Canvas 双缓冲图形不工作
Canvas double buffered graphics not working
我试图为我的 canvas 制作双缓冲图形,但它总是在渲染后立即消失,有时甚至不渲染,这是代码:
package initilizer;
import java.awt.AWTException;
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Cursor;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.MouseInfo;
import java.awt.Point;
import java.awt.Robot;
import java.awt.Toolkit;
import java.awt.image.BufferedImage;
import javax.swing.JFrame;
import input.Keyboard;
public class Main extends Canvas{
static int width = 800;
static int height = 600;
int cx = width/2;
int cy = height/2;
boolean initilized = false;
double FOV = 0.5 * Math.PI;
Camera cam = new Camera(1.0, 5.0, 3.0);
Camera cam1 = new Camera(10.0, 50.0, 30.0);
long lastFpsCheck = System.currentTimeMillis();
public static JFrame frame = new JFrame("3D Engine");
Robot robot;
static Keyboard keyboard = new Keyboard();
Image img;
public static void main(String[] args) {
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Canvas canvas = new Main();
canvas.setSize(width, height);
canvas.addKeyListener(keyboard);
canvas.setFocusable(true);
canvas.setBackground(Color.black);
frame.add(canvas);
frame.pack();
frame.setVisible(true);
BufferedImage cursorImg = new BufferedImage(16, 16, BufferedImage.TYPE_INT_ARGB);
// Create a new blank cursor.
Cursor blankCursor = Toolkit.getDefaultToolkit().createCustomCursor(
cursorImg, new Point(0, 0), "blank cursor");
// Set the blank cursor to the JFrame.
canvas.setCursor(blankCursor);
}
void init() {
try {
robot = new Robot();
} catch (AWTException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
double[] rotate2D(double[] pos,double[] rot) {
double x = pos[0];
double y = pos[1];
double s = rot[0];
double c = rot[1];
double[] result = {(x * c) - (y * s), (y * c) + (x * s)};
return result;
}
public void paint(Graphics MainGraphics) {
Point startMousePos = MouseInfo.getPointerInfo().getLocation();
double startMouseX = startMousePos.getX();
double startMouseY = startMousePos.getY();
if(img == null)
{
img = createImage(width, height);
}
Graphics g = img.getGraphics();;
// First run initialization
if (initilized == false) {
initilized = true;
init();
}
// Storing start time for FPS Counting
long startTime = System.currentTimeMillis();
// Clearing Last Frame
//g.clearRect(0, 0, width, height);
// Drawing Crosshair
g.setColor(Color.white);
g.fillRect(cx - 8, cy - 1, 16, 2);
g.fillRect(cx - 1, cy - 8, 2, 16);
// Drawing Debugger Menu
g.drawString("HI WASSUp", 0, 16);
g.dispose();
if (frame.isFocused() == true) {
robot.mouseMove(cx, cy);
Point endMousePos = MouseInfo.getPointerInfo().getLocation();
double endMouseX = endMousePos.getX();
double endMouseY = endMousePos.getY();
double[] rel = {startMouseX - endMouseX, startMouseY - endMouseY};
cam.mouseMotion(rel);
}
// Limiting FPS
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// Calculating FPS
long endTime = System.currentTimeMillis();
double delta_time = (endTime - startTime);
if ((lastFpsCheck + 1000) < endTime) {
lastFpsCheck = endTime;
frame.setTitle("3D Engine - FPS: " + (int) (1000/delta_time));
}
// Controlling camera movement
if (keyboard.getW() == true) {
cam.update(delta_time, "W");
}
if (keyboard.getA() == true) {
cam.update(delta_time, "A");
}
if (keyboard.getS() == true) {
cam.update(delta_time, "S");
}
if (keyboard.getD() == true) {
cam.update(delta_time, "D");
}
if (keyboard.getE() == true) {
cam.update(delta_time, "E");
}
if (keyboard.getQ() == true) {
cam.update(delta_time, "Q");
}
// Draw rendered frame
MainGraphics.drawImage(img, 0,0, null);
// Draw next frame
repaint();
}
}
我最近 post 提出了一个关于这段代码的问题,如果你愿意的话,你可以检查最后一个 post 的键盘 java,但是请帮我解决这个问题java 编程新手(不过我还有一些编程经验),谢谢
你的问题的答案很复杂。
- Java Swing
JPanel
(或JComponent
)默认双缓冲
- Swing 已经具有您无法控制的绘画机制,因此您需要在其功能范围内工作。
- 您使用
java.awt.Canvas
的唯一真正原因是您想要完全控制绘画过程
我建议您做的第一件事是看一下 Performing Custom Painting and Painting in AWT and Swing 以更好地了解 Swing/AWT 中的绘画工作原理。这将使您更好地了解 API 以及您是想使用它还是定义您自己的。
其他一些值得关注的领域:
- 不要在
paint
方法中执行 Thread.sleep(1000);
,在 paint
方法 returns 之前不会呈现任何内容。您想要将 "update pass" 与 "paint pass" 分开。绘画对颜料没有任何作用。你所有的决策都应该作为你的 "main loop" 的 "update pass" 的一部分来完成,它应该在事件调度线程之外执行(在这种情况下),以防止可能的问题,但随后会引发一堆其他问题
MouseInfo.getPointerInfo().getLocation()
不是您跟踪鼠标位置的方式。 Swing 已经提供了许多用于跟踪鼠标事件的机制。有关详细信息,请参阅 How to write a Mouse Listener and How to Write a Mouse-Motion Listener。
- 基于每一件事,我也很关心您如何跟踪键盘输入,并强烈建议您查看 How to Use Key Bindings 以了解管理键盘输入的最常用推荐方法来自用户。
以下示例仅使用 JPanel
作为主要渲染表面。它利用预先存在的绘画过程并使用 Swing Timer
作为 "main loop" 机制,负责处理用户输入并在安排新的绘画过程之前更新状态。
请记住,Swing 不是线程安全的,您不应该从事件调度线程的上下文之外更新 UI 或 UI 可能依赖的任何内容。
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.time.Duration;
import java.time.Instant;
import java.util.HashSet;
import java.util.Set;
import java.util.StringJoiner;
import javax.swing.AbstractAction;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
import javax.swing.Timer;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
JFrame frame = new JFrame();
Main main = new Main();
frame.add(main);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
main.start();
}
});
}
// Decouple the input from the implementation
enum Input {
UP, DOWN, LEFT, RIGHT
}
public class Main extends JPanel {
boolean initilized = false;
double FOV = 0.5 * Math.PI;
private Instant lastFpsCheck = Instant.now();
private Point mousePosition;
private Timer timer;
private Set<Input> input = new HashSet<>();
public Main() {
MouseAdapter mouseHandler = new MouseAdapter() {
@Override
public void mouseMoved(MouseEvent e) {
// This is within the components coordinate space
mousePosition = e.getPoint();
}
@Override
public void mouseEntered(MouseEvent e) {
mousePosition = e.getPoint();
}
@Override
public void mouseExited(MouseEvent e) {
mousePosition = null;
}
};
addMouseMotionListener(mouseHandler);
addMouseListener(mouseHandler);
InputMap inputMap = getInputMap(WHEN_IN_FOCUSED_WINDOW);
ActionMap actionMap = getActionMap();
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_W, 0, false), "Pressed.up");
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_W, 0, true), "Released.up");
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_S, 0, false), "Pressed.down");
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_S, 0, true), "Released.down");
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_A, 0, false), "Pressed.left");
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_A, 0, true), "Released.left");
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_D, 0, false), "Pressed.right");
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_D, 0, true), "Released.right");
actionMap.put("Pressed.up", new InputAction(input, Input.UP, true));
actionMap.put("Released.up", new InputAction(input, Input.UP, false));
actionMap.put("Pressed.down", new InputAction(input, Input.DOWN, true));
actionMap.put("Released.down", new InputAction(input, Input.DOWN, false));
actionMap.put("Pressed.left", new InputAction(input, Input.LEFT, true));
actionMap.put("Released.left", new InputAction(input, Input.LEFT, false));
actionMap.put("Pressed.right", new InputAction(input, Input.RIGHT, true));
actionMap.put("Released.right", new InputAction(input, Input.RIGHT, false));
timer = new Timer(15, new ActionListener() {
@Override
public void actionPerformed(ActionEvent evt) {
update();
}
});
}
public void start() {
startTime = Instant.now();
timer.start();
}
public void stop() {
timer.stop();
}
// The start time of a given cycle
private Instant startTime;
// The estimated number of frames per second
private double fps = 0;
// The number of acutal updates performed
// within a given cycle
private int updates = 0;
protected void update() {
if (startTime == null) {
startTime = Instant.now();
}
if (input.contains(Input.UP)) {
//cam.update(delta_time, "W");
}
if (input.contains(Input.LEFT)) {
//cam.update(delta_time, "A");
}
if (input.contains(Input.DOWN)) {
//cam.update(delta_time, "S");
}
if (input.contains(Input.RIGHT)) {
//cam.update(delta_time, "D");
}
// Don't know what these do, so you will need to devices
// your own action
//if (input.contains(Input.UP)) {
//cam.update(delta_time, "E");
//}
//if (input.contains(Input.UP)) {
//cam.update(delta_time, "Q");
//}
Instant endTime = Instant.now();
Duration deltaTime = Duration.between(startTime, endTime);
if (lastFpsCheck.plusSeconds(1).isBefore(endTime)) {
System.out.println(deltaTime.toMillis());
lastFpsCheck = endTime;
fps = updates;
updates = 0;
startTime = Instant.now();
}
updates++;
repaint();
}
@Override
public Dimension getPreferredSize() {
return new Dimension(800, 600);
}
double[] rotate2D(double[] pos, double[] rot) {
double x = pos[0];
double y = pos[1];
double s = rot[0];
double c = rot[1];
double[] result = {(x * c) - (y * s), (y * c) + (x * s)};
return result;
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
//Point startMousePos = MouseInfo.getPointerInfo().getLocation();
//double startMouseX = startMousePos.getX();
//double startMouseY = startMousePos.getY();
Graphics2D g2d = (Graphics2D) g.create();
// Drawing Debugger Menu
g2d.drawString("HI WASSUp", 0, 20);
if (mousePosition != null) {
g2d.drawString(mousePosition.x + "x" + mousePosition.y, 0, 40);
// Your old code is broken, because MouseInfo.getPointerInfo
// doesn't give you the position of the mouse from within
// the components coordinate space, but in the screen space
// instead
//robot.mouseMove(cx, cy);
//Point endMousePos = MouseInfo.getPointerInfo().getLocation();
//double endMouseX = endMousePos.getX();
//double endMouseY = endMousePos.getY();
//double[] rel = {startMouseX - endMouseX, startMouseY - endMouseY};
//cam.mouseMotion(rel);
}
g2d.drawString(Double.toString(fps), 0, 60);
StringJoiner sj = new StringJoiner(", ");
for (Input item : input) {
switch (item) {
case DOWN:
sj.add("down");
break;
case UP:
sj.add("up");
break;
case LEFT:
sj.add("left");
break;
case RIGHT:
sj.add("right");
break;
}
}
g2d.drawString(sj.toString(), 0, 80);
g2d.dispose();
}
public class InputAction extends AbstractAction {
private final Set<Input> input;
private final Input direction;
private final boolean add;
public InputAction(Set<Input> input, Input direction, boolean add) {
this.input = input;
this.direction = direction;
this.add = add;
}
@Override
public void actionPerformed(ActionEvent evt) {
if (add) {
input.add(direction);
} else {
input.remove(direction);
}
}
}
}
}
现在,由于 Swing 的绘制过程的工作方式,FPS 充其量是 "guesstimate",我个人不会过分依赖它。我可能会考虑将 Timer
设置为使用 5 毫秒的延迟,并尽可能快地进行。
现在,如果您绝对肯定必须毫无疑问地完全控制绘画过程,那么您将需要从 java.awt.Canvas
开始并利用 BufferStrategy
API.
这将使您能够完全控制绘画过程。它更复杂,需要您考虑更多的边缘情况,但可以让您在绘制过程发生时完全控制调度,从而更好地控制 FPS。
我建议看一下 JavaDocs,因为示例更好。
I used the Thread.sleep(1000); to limit FPS only, It was 1000/60 but I changed it to this because I thought the problem may be in the speed of rendering
坦率地说,这是一种天真的方法,表明对绘画过程的工作原理缺乏了解 - 没有冒犯,你必须从某个地方开始。但更好的起点是阅读我在上面提供的可用文档,这样您就可以更好地了解 API 的实际工作原理,并就是否要使用它做出更好的决定(即JPanel
) 或自己滚动(即 Canvas
)
我试图为我的 canvas 制作双缓冲图形,但它总是在渲染后立即消失,有时甚至不渲染,这是代码:
package initilizer;
import java.awt.AWTException;
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Cursor;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.MouseInfo;
import java.awt.Point;
import java.awt.Robot;
import java.awt.Toolkit;
import java.awt.image.BufferedImage;
import javax.swing.JFrame;
import input.Keyboard;
public class Main extends Canvas{
static int width = 800;
static int height = 600;
int cx = width/2;
int cy = height/2;
boolean initilized = false;
double FOV = 0.5 * Math.PI;
Camera cam = new Camera(1.0, 5.0, 3.0);
Camera cam1 = new Camera(10.0, 50.0, 30.0);
long lastFpsCheck = System.currentTimeMillis();
public static JFrame frame = new JFrame("3D Engine");
Robot robot;
static Keyboard keyboard = new Keyboard();
Image img;
public static void main(String[] args) {
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Canvas canvas = new Main();
canvas.setSize(width, height);
canvas.addKeyListener(keyboard);
canvas.setFocusable(true);
canvas.setBackground(Color.black);
frame.add(canvas);
frame.pack();
frame.setVisible(true);
BufferedImage cursorImg = new BufferedImage(16, 16, BufferedImage.TYPE_INT_ARGB);
// Create a new blank cursor.
Cursor blankCursor = Toolkit.getDefaultToolkit().createCustomCursor(
cursorImg, new Point(0, 0), "blank cursor");
// Set the blank cursor to the JFrame.
canvas.setCursor(blankCursor);
}
void init() {
try {
robot = new Robot();
} catch (AWTException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
double[] rotate2D(double[] pos,double[] rot) {
double x = pos[0];
double y = pos[1];
double s = rot[0];
double c = rot[1];
double[] result = {(x * c) - (y * s), (y * c) + (x * s)};
return result;
}
public void paint(Graphics MainGraphics) {
Point startMousePos = MouseInfo.getPointerInfo().getLocation();
double startMouseX = startMousePos.getX();
double startMouseY = startMousePos.getY();
if(img == null)
{
img = createImage(width, height);
}
Graphics g = img.getGraphics();;
// First run initialization
if (initilized == false) {
initilized = true;
init();
}
// Storing start time for FPS Counting
long startTime = System.currentTimeMillis();
// Clearing Last Frame
//g.clearRect(0, 0, width, height);
// Drawing Crosshair
g.setColor(Color.white);
g.fillRect(cx - 8, cy - 1, 16, 2);
g.fillRect(cx - 1, cy - 8, 2, 16);
// Drawing Debugger Menu
g.drawString("HI WASSUp", 0, 16);
g.dispose();
if (frame.isFocused() == true) {
robot.mouseMove(cx, cy);
Point endMousePos = MouseInfo.getPointerInfo().getLocation();
double endMouseX = endMousePos.getX();
double endMouseY = endMousePos.getY();
double[] rel = {startMouseX - endMouseX, startMouseY - endMouseY};
cam.mouseMotion(rel);
}
// Limiting FPS
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// Calculating FPS
long endTime = System.currentTimeMillis();
double delta_time = (endTime - startTime);
if ((lastFpsCheck + 1000) < endTime) {
lastFpsCheck = endTime;
frame.setTitle("3D Engine - FPS: " + (int) (1000/delta_time));
}
// Controlling camera movement
if (keyboard.getW() == true) {
cam.update(delta_time, "W");
}
if (keyboard.getA() == true) {
cam.update(delta_time, "A");
}
if (keyboard.getS() == true) {
cam.update(delta_time, "S");
}
if (keyboard.getD() == true) {
cam.update(delta_time, "D");
}
if (keyboard.getE() == true) {
cam.update(delta_time, "E");
}
if (keyboard.getQ() == true) {
cam.update(delta_time, "Q");
}
// Draw rendered frame
MainGraphics.drawImage(img, 0,0, null);
// Draw next frame
repaint();
}
}
我最近 post 提出了一个关于这段代码的问题,如果你愿意的话,你可以检查最后一个 post 的键盘 java,但是请帮我解决这个问题java 编程新手(不过我还有一些编程经验),谢谢
你的问题的答案很复杂。
- Java Swing
JPanel
(或JComponent
)默认双缓冲 - Swing 已经具有您无法控制的绘画机制,因此您需要在其功能范围内工作。
- 您使用
java.awt.Canvas
的唯一真正原因是您想要完全控制绘画过程
我建议您做的第一件事是看一下 Performing Custom Painting and Painting in AWT and Swing 以更好地了解 Swing/AWT 中的绘画工作原理。这将使您更好地了解 API 以及您是想使用它还是定义您自己的。
其他一些值得关注的领域:
- 不要在
paint
方法中执行Thread.sleep(1000);
,在paint
方法 returns 之前不会呈现任何内容。您想要将 "update pass" 与 "paint pass" 分开。绘画对颜料没有任何作用。你所有的决策都应该作为你的 "main loop" 的 "update pass" 的一部分来完成,它应该在事件调度线程之外执行(在这种情况下),以防止可能的问题,但随后会引发一堆其他问题 MouseInfo.getPointerInfo().getLocation()
不是您跟踪鼠标位置的方式。 Swing 已经提供了许多用于跟踪鼠标事件的机制。有关详细信息,请参阅 How to write a Mouse Listener and How to Write a Mouse-Motion Listener。- 基于每一件事,我也很关心您如何跟踪键盘输入,并强烈建议您查看 How to Use Key Bindings 以了解管理键盘输入的最常用推荐方法来自用户。
以下示例仅使用 JPanel
作为主要渲染表面。它利用预先存在的绘画过程并使用 Swing Timer
作为 "main loop" 机制,负责处理用户输入并在安排新的绘画过程之前更新状态。
请记住,Swing 不是线程安全的,您不应该从事件调度线程的上下文之外更新 UI 或 UI 可能依赖的任何内容。
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.time.Duration;
import java.time.Instant;
import java.util.HashSet;
import java.util.Set;
import java.util.StringJoiner;
import javax.swing.AbstractAction;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
import javax.swing.Timer;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
JFrame frame = new JFrame();
Main main = new Main();
frame.add(main);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
main.start();
}
});
}
// Decouple the input from the implementation
enum Input {
UP, DOWN, LEFT, RIGHT
}
public class Main extends JPanel {
boolean initilized = false;
double FOV = 0.5 * Math.PI;
private Instant lastFpsCheck = Instant.now();
private Point mousePosition;
private Timer timer;
private Set<Input> input = new HashSet<>();
public Main() {
MouseAdapter mouseHandler = new MouseAdapter() {
@Override
public void mouseMoved(MouseEvent e) {
// This is within the components coordinate space
mousePosition = e.getPoint();
}
@Override
public void mouseEntered(MouseEvent e) {
mousePosition = e.getPoint();
}
@Override
public void mouseExited(MouseEvent e) {
mousePosition = null;
}
};
addMouseMotionListener(mouseHandler);
addMouseListener(mouseHandler);
InputMap inputMap = getInputMap(WHEN_IN_FOCUSED_WINDOW);
ActionMap actionMap = getActionMap();
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_W, 0, false), "Pressed.up");
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_W, 0, true), "Released.up");
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_S, 0, false), "Pressed.down");
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_S, 0, true), "Released.down");
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_A, 0, false), "Pressed.left");
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_A, 0, true), "Released.left");
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_D, 0, false), "Pressed.right");
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_D, 0, true), "Released.right");
actionMap.put("Pressed.up", new InputAction(input, Input.UP, true));
actionMap.put("Released.up", new InputAction(input, Input.UP, false));
actionMap.put("Pressed.down", new InputAction(input, Input.DOWN, true));
actionMap.put("Released.down", new InputAction(input, Input.DOWN, false));
actionMap.put("Pressed.left", new InputAction(input, Input.LEFT, true));
actionMap.put("Released.left", new InputAction(input, Input.LEFT, false));
actionMap.put("Pressed.right", new InputAction(input, Input.RIGHT, true));
actionMap.put("Released.right", new InputAction(input, Input.RIGHT, false));
timer = new Timer(15, new ActionListener() {
@Override
public void actionPerformed(ActionEvent evt) {
update();
}
});
}
public void start() {
startTime = Instant.now();
timer.start();
}
public void stop() {
timer.stop();
}
// The start time of a given cycle
private Instant startTime;
// The estimated number of frames per second
private double fps = 0;
// The number of acutal updates performed
// within a given cycle
private int updates = 0;
protected void update() {
if (startTime == null) {
startTime = Instant.now();
}
if (input.contains(Input.UP)) {
//cam.update(delta_time, "W");
}
if (input.contains(Input.LEFT)) {
//cam.update(delta_time, "A");
}
if (input.contains(Input.DOWN)) {
//cam.update(delta_time, "S");
}
if (input.contains(Input.RIGHT)) {
//cam.update(delta_time, "D");
}
// Don't know what these do, so you will need to devices
// your own action
//if (input.contains(Input.UP)) {
//cam.update(delta_time, "E");
//}
//if (input.contains(Input.UP)) {
//cam.update(delta_time, "Q");
//}
Instant endTime = Instant.now();
Duration deltaTime = Duration.between(startTime, endTime);
if (lastFpsCheck.plusSeconds(1).isBefore(endTime)) {
System.out.println(deltaTime.toMillis());
lastFpsCheck = endTime;
fps = updates;
updates = 0;
startTime = Instant.now();
}
updates++;
repaint();
}
@Override
public Dimension getPreferredSize() {
return new Dimension(800, 600);
}
double[] rotate2D(double[] pos, double[] rot) {
double x = pos[0];
double y = pos[1];
double s = rot[0];
double c = rot[1];
double[] result = {(x * c) - (y * s), (y * c) + (x * s)};
return result;
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
//Point startMousePos = MouseInfo.getPointerInfo().getLocation();
//double startMouseX = startMousePos.getX();
//double startMouseY = startMousePos.getY();
Graphics2D g2d = (Graphics2D) g.create();
// Drawing Debugger Menu
g2d.drawString("HI WASSUp", 0, 20);
if (mousePosition != null) {
g2d.drawString(mousePosition.x + "x" + mousePosition.y, 0, 40);
// Your old code is broken, because MouseInfo.getPointerInfo
// doesn't give you the position of the mouse from within
// the components coordinate space, but in the screen space
// instead
//robot.mouseMove(cx, cy);
//Point endMousePos = MouseInfo.getPointerInfo().getLocation();
//double endMouseX = endMousePos.getX();
//double endMouseY = endMousePos.getY();
//double[] rel = {startMouseX - endMouseX, startMouseY - endMouseY};
//cam.mouseMotion(rel);
}
g2d.drawString(Double.toString(fps), 0, 60);
StringJoiner sj = new StringJoiner(", ");
for (Input item : input) {
switch (item) {
case DOWN:
sj.add("down");
break;
case UP:
sj.add("up");
break;
case LEFT:
sj.add("left");
break;
case RIGHT:
sj.add("right");
break;
}
}
g2d.drawString(sj.toString(), 0, 80);
g2d.dispose();
}
public class InputAction extends AbstractAction {
private final Set<Input> input;
private final Input direction;
private final boolean add;
public InputAction(Set<Input> input, Input direction, boolean add) {
this.input = input;
this.direction = direction;
this.add = add;
}
@Override
public void actionPerformed(ActionEvent evt) {
if (add) {
input.add(direction);
} else {
input.remove(direction);
}
}
}
}
}
现在,由于 Swing 的绘制过程的工作方式,FPS 充其量是 "guesstimate",我个人不会过分依赖它。我可能会考虑将 Timer
设置为使用 5 毫秒的延迟,并尽可能快地进行。
现在,如果您绝对肯定必须毫无疑问地完全控制绘画过程,那么您将需要从 java.awt.Canvas
开始并利用 BufferStrategy
API.
这将使您能够完全控制绘画过程。它更复杂,需要您考虑更多的边缘情况,但可以让您在绘制过程发生时完全控制调度,从而更好地控制 FPS。
我建议看一下 JavaDocs,因为示例更好。
I used the Thread.sleep(1000); to limit FPS only, It was 1000/60 but I changed it to this because I thought the problem may be in the speed of rendering
坦率地说,这是一种天真的方法,表明对绘画过程的工作原理缺乏了解 - 没有冒犯,你必须从某个地方开始。但更好的起点是阅读我在上面提供的可用文档,这样您就可以更好地了解 API 的实际工作原理,并就是否要使用它做出更好的决定(即JPanel
) 或自己滚动(即 Canvas
)