Java 2D Game:repaint();使窗口变灰 [英] Java 2D Game: repaint(); makes window grey

查看:141
本文介绍了Java 2D Game:repaint();使窗口变灰的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用Java制作2D游戏,但是当我在一个线程中调用repaint()方法时,会出现一个奇怪的灰色窗口。

I'm trying to make a 2D game in Java, but when I call the repaint() method in a thread there's an odd grey-only window.

这是我到目前为止的源代码:

Here's the source code I have so far:


  1. Spaceshooter.java

  1. Spaceshooter.java

package spaceshooter;

import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
public class Spaceshooter extends JFrame implements KeyListener, Runnable {

private Player player = new Player(5, 186, this);
private boolean up, down;

public Spaceshooter(String title) {
    super(title);
    this.setFocusable(true);
    this.addKeyListener(this);
}

@Override
public void paint(Graphics gr) {
    super.paint(gr);

    gr.setColor(Color.BLACK);
    gr.fillRect(0, 0, 800, 500);

    player.paintPlayer(gr);
}

public static void main(String[] args) {
    Spaceshooter shooter = new Spaceshooter("Spaceshooter");
    new Thread(shooter).start();
    shooter.setSize(800,500);
    shooter.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    shooter.setVisible(true);
}

@Override
public void keyTyped(KeyEvent e) {
}

@Override
public void keyPressed(KeyEvent e) {
    if (e.getKeyCode() == 38) {
        up = true;
        down = false;
    } else if (e.getKeyCode() == 40) {
        down = true;
        up = false;
    }
}

@Override
public void keyReleased(KeyEvent e) {
    down = false;
    up = false;
}

@Override
public void run() {
    while(true) {
        if (up) {
            player.moveUp();
        } else if (down) {
            player.moveDown();
        }
        repaint();
    try {
        Thread.sleep(20);
    } catch (InterruptedException ex) {
        Logger.getLogger(Spaceshooter.class.getName()).log(Level.SEVERE, null, ex);
    }
    }
}
}


  • Player.java

  • Player.java

     package spaceshooter;
    
     import java.awt.Component;
     import java.awt.Graphics;
     import java.awt.Toolkit;
    
     public class Player {
    
    private int x, y;
    private Component comp;
    
    public Player(int x, int y, Component comp) {
        this.x = x;
        this.y = y;
        this.comp = comp;
    }
    
    public void moveUp() {
        y -= 5;
    }
    
    public void moveDown() {
        y += 5;
    }
    
    public void paintPlayer(Graphics gr) {
        gr.drawImage(Toolkit.getDefaultToolkit().getImage("images/player.png"), x, y, comp);
    }
    
    }
    


  • 提前感谢您的回答!

    推荐答案

    什么是EDT?

    Swing事件处理代码在称为事件派发线程的特殊线程上运行。大多数调用Swing方法的代码也在这个线程上运行。这是必要的,因为大多数Swing对象方法都不是线程安全的。所有与GUI相关的任务,都应该对GUI进行任何更新,而绘制过程必须在EDT上进行,这涉及将请求包装在一个事件中并将其处理到 EventQueue 。然后,事件将从一个接一个的队列中按顺序分派,即FIRST IN FIRST OUT。也就是说,如果是,如果事件A 事件B之前排队到 EventQueue 然后在事件A之前不会调度事件B.

    Swing event handling code runs on a special thread known as the event dispatch thread. Most code that invokes Swing methods also runs on this thread. This is necessary because most Swing object methods are not "thread safe". All GUI related task, any update should be made to GUI while painting process must happen on the EDT, which involves wrapping the request in an event and processing it onto the EventQueue. Then the event are dispatched from the same queue in the one by one in order they en-queued, FIRST IN FIRST OUT. That is, if That is, if Event A is enqueued to the EventQueue before Event B then event B will not be dispatched before event A.

    您执行的任何可能需要一段时间的任务,可能会阻止EDT,否调度将发生,不会进行更新,因此您的应用程序将冻结。你将不得不杀死它以摆脱这种冰冻状态。

    Any task you perform which may take a while, likely to block the EDT, no dispatching will happen, no update will be made and hence your application FREEZES. You will have to kill it to get rid of this freezing state.

    在你的程序中,除了创建 JFrame 并使其从主线程(我们也可以看到)中可见不应该这样做):

    In your program, aside from creating your JFrame and making it to visible from the main thread (which we also should not do):

        while(true) {
            if (up) {
                player.moveUp();
            } else if (down) {
                player.moveDown();
            }
            repaint();
        try {
            Thread.sleep(20);
        } catch (InterruptedException ex) {
            Logger.getLogger(Spaceshooter.class.getName()).log(Level.SEVERE, null, ex);
        }
        }
    

    您要发布重绘( )请求来自您之后立即发送的线程的请求。

    you are posting repaint() request from the thread which you sent to sleep right immediately after that.

    SwingUtilities.invokeLater():

    Swing提供了一个很好的功能 SwingUtilities.invokeLater(new Runnable(){})用于向EDT发送重绘请求。你所要做的就是写:

    Swing provides a nice function SwingUtilities.invokeLater(new Runnable(){}) for posting repaint request to the EDT. All you have to do is to write:

        SwingUtilities.invokeLater(new Runnable()
           {
             public void run()
             {
                   repaint();
             }
       });
    

    现在还有一件事需要提及:


    1. 我们不应该使用 Runnable 实现GUI组件。创建另一个实现 Runnable 的类,在其中进行计算,然后使用 SwingUtilities 发布组件更新请求。

    2. 我们不应该直接在 JFrame 上进行自定义绘画。 JFrame是一个顶级组件。它更像是一个包含整个应用程序的容器。如果你想自定义绘画使用自定义组件 MyCanvas扩展JComponent

    3. 我们不应该覆盖 paint() 功能。相反, paintComponent(g)将很好地服务于我们的自定义绘画目的。

    4. 学习使用Swing Timer类及时重复GUI渲染任务。

    1. We should not implements a GUI component with Runnable. Make another class implementing Runnable, make your computation inside that then use SwingUtilities to post the component update request.
    2. we should not made custom painting on JFrame directly. JFrame is a top level component. It is more like a container which contains your whole app. If you want custom painting use a custom component MyCanvas extends JComponent.
    3. we should not override paint() function. Instead paintComponent(g) will serve our custom painting purposes nicely.
    4. Learn to use Swing Timer class for timely repeated GUI rendering task.

    教程资源和参考:


    1. 事件派遣线程

    2. EventQueue

    3. 如何使用摇摆计时器

    4. 课程:执行自定义绘画

    1. The Event Dispatch Thread
    2. EventQueue
    3. How to Use Swing Timers
    4. Lesson: Performing Custom Painting

    这篇关于Java 2D Game:repaint();使窗口变灰的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

    查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆