我正在制作一个简单的游戏项目,当我尝试创建一个在屏幕上移动的矩形时,我遇到了问题。 这是主要的课程:
`public class Main extends Canvas实现了Runnable {
private static final long serialVersionUID = 1L;
private JFrame frame;
boolean running = false;
Graphics g;
static int HEIGHT = 500;
static int WIDTH = HEIGHT * 16 / 9;
SoundHandler sh = new SoundHandler();
//Game state manager
private GameStateManager gsm;
public Main()
{
//window
frame = new JFrame("Game");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(this, BorderLayout.CENTER);
frame.pack();
frame.setSize(WIDTH, HEIGHT);
frame.setResizable(false);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
init();
}
void init()
{
gsm = new GameStateManager();
sh.playMusic("Undertale.wav", 1);
}
public synchronized void start(){
running = true;
new Thread(this).start();
}
public synchronized void stop(){
running = false;
}
//game loop
public void run()
{
//init time loop variables
long lastLoopTime = System.nanoTime();
final int TARGET_FPS = 60;
final long OPTIMAL_TIME = 1000000000 / TARGET_FPS;
double lastFpsTime = 0;
int fps = 0;
while(running)
{
//work out how long its been since last update
//will be used to calculate how entities should
//move this loop
long now = System.nanoTime();
long updateLength = now - lastLoopTime;
lastLoopTime = now;
double delta = updateLength / ((double)OPTIMAL_TIME);
//update frame counter
lastFpsTime += updateLength;
fps++;
//update FPS counter
if(lastFpsTime >= 1000000000)
{
System.out.println("FPS " + fps);
lastFpsTime = 0;
fps = 0;
}
//game updates
update(delta);
//draw
draw(g);
try{
Thread.sleep((lastLoopTime - System.nanoTime() + OPTIMAL_TIME)/1000000 );
}catch(InterruptedException e){
System.out.println("Error in sleep");
}
}
}
private void update(double delta)
{
//updates game state code
gsm.update(delta);
}
public void draw(Graphics g)
{
gsm.draw(g);
}`
这是我想用
绘制矩形的类package me.mangodragon.gamestate;
import java.awt.Graphics;
公共类MainState扩展了GameState {
int x;
public MainState(GameStateManager gsm){
this.gsm = gsm;
}
public void init() {
}
public void update(double delta) {
x += 2 * delta;
}
public void draw(Graphics g) {
g.drawRect(x, 0, 50, 50);
g.dispose();
}
public void keyPressed(int k) {
}
public void keyReleased(int k) {
}
} 我一直收到这个错误:
Exception in thread "Thread-4" java.lang.NullPointerException
at me.mangodragon.gamestate.MainState.draw(MainState.java:22)
at me.mangodragon.gamestate.GameStateManager.draw(GameStateManager.java:37)
at me.mangodragon.main.Main.draw(Main.java:118)
at me.mangodragon.main.Main.run(Main.java:100)
at java.lang.Thread.run(Unknown Source)
我试图解决它,但我找不到问题。
谢谢!
答案 0 :(得分:1)
您永远不会向g
(Graphics
)分配任何内容。现在,在你跑掉并尝试弄清楚如何做到这一点之前,我强烈建议你摆脱这个变量,它会给你带来太多问题。
通常情况下,当系统需要绘制组件时,它会调用您的paint
方法并将您想要绘制的Graphics
上下文传递给它。这种方法被称为被动绘画,因为绘画请求是随机出现的,这并不是你想要的。另一个问题是java.awt.Canvas
不是双缓冲的,这会在组件更新时导致闪烁。
您可能需要查看Painting in AWT and Swing和Performing Custom Painting了解详情
您可以使用JPanel
代替双缓冲,但使用java.awt.Canvas
的主要原因是您可以使用BufferStrategy
API。这不仅提供双重缓冲,还为您提供了一种方法,您可以通过它直接控制绘画过程(或主动绘画)。
有关详细信息,请参阅BufferStrategy
和BufferStrategy and BufferCapabilities
答案 1 :(得分:0)
您定义了g
:
Graphics g;
但从来没有给它一个价值。
这不是你应该如何绘制形状,反正。而是覆盖类Main
中的paint方法(继承自Canvas):
@Override
public void paint(Graphics2D g) {
//Drawing code goes in here. This runs whenever the Canvas is rendered.
}
然后,当您想要更新它时,例如在while
循环中,运行
this.repaint(); //note that this doesn't take arguments
如果您想在其他课程中使用draw(Graphics g)
方法,请在paint()
中进行调用。
public void paint(Graphics2D g) {
gsm.draw(g);
}
答案 2 :(得分:0)
问题是你没有定义g
,所以它是null。在大多数情况下,你永远不应该创建一个新的Graphics
对象,而是从某个地方获取它。
由于您继承了Canvas
,因此可以轻松完成此任务。
首先,您应该将draw
方法更改为此类。
private void draw() {
BufferStrategy bs = this.getBufferStrategy();
if (bs == null) {
this.createBufferStrategy(3);
return;
}
Graphics g = bs.getDrawGraphics();
// Draw your game here, using the g declared above
g.dispose();
bs.show();
}
前几行创建了一个名为BufferStrategy
的东西,您可以阅读更多关于here的内容,但它实质上允许Java提前渲染下一对帧,这样您就不会看到任何闪烁。
从BufferStrategy
,您可以获取Graphics
对象。
最后,您必须处理Graphics
对象,然后显示Buffer
,以便您在屏幕上显示所有内容。