渲染具有多个类的矩形

时间:2016-02-11 02:04:24

标签: java graphics

我正在制作一个简单的游戏项目,当我尝试创建一个在屏幕上移动的矩形时,我遇到了问题。 这是主要的课程:

`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)

我试图解决它,但我找不到问题。

谢谢!

3 个答案:

答案 0 :(得分:1)

您永远不会向gGraphics)分配任何内容。现在,在你跑掉并尝试弄清楚如何做到这一点之前,我强烈建议你摆脱这个变量,它会给你带来太多问题。

通常情况下,当系统需要绘制组件时,它会调用您的paint方法并将您想要绘制的Graphics上下文传递给它。这种方法被称为被动绘画,因为绘画请求是随机出现的,这并不是你想要的。另一个问题是java.awt.Canvas不是双缓冲的,这会在组件更新时导致闪烁。

您可能需要查看Painting in AWT and SwingPerforming Custom Painting了解详情

您可以使用JPanel代替双缓冲,但使用java.awt.Canvas的主要原因是您可以使用BufferStrategy API。这不仅提供双重缓冲,还为您提供了一种方法,您可以通过它直接控制绘画过程(或主动绘画)。

有关详细信息,请参阅BufferStrategyBufferStrategy 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,以便您在屏幕上显示所有内容。