【问题标题】:Appropriate way to draw to a JPanel for 2D Game development?为 2D 游戏开发绘制到 JPanel 的适当方法?
【发布时间】:2012-06-13 13:46:35
【问题描述】:

我想要制作一个 2D 游戏,但我无法找到使用 BufferStrategy 绘制到 2D Surface/Canvas 的最佳和最有效的方法。我将使用 JFrame 作为主窗口,并希望在其表面上进行绘制。我很想看到一些关于如何完成的示例代码(如果这是一个很好的方法)以及其他示例。如果有人也能解释这样做的一些优点和缺点,那就太好了。

我目前正在使用“frame.add(new Painter());”将我的绘图类添加到我的 JFrame然后覆盖paintComponent 方法。我发现的唯一问题是它似乎只调用了一次这个方法。

这是我的 Painter 课程:

public class Painter extends JPanel{

    public static Player player;

    public Painter() {
        player = new Player(300, 300);

    }

    public void paint(Graphics g) {
        player.x++;
        g.setColor(Color.white);
        g.fillRect(player.x, player.y, 32, 32);
    }

}

【问题讨论】:

  • 为什么它会调用它多次?如果你想要一个动画,你需要有一个线程来移动你的玩家并要求摇摆在循环中重新绘制画家。
  • 因为我希望能够不断地在屏幕上绘制,以便显示更新的玩家位置等。
  • 1) 您在文本中提到了paintComponent(正确),但该代码覆盖了paint(错误)。 2) 除非还在渲染顶部添加组件,否则请考虑使用BufferedImage。在标签中显示它并在需要时重新绘制(图像和)标签(根据 Swing Timer)。

标签: java graphics drawing 2d


【解决方案1】:

在最简单的情况下,您的游戏只需要根据用户操作更新屏幕,您需要在更新时调用repaint()(例如在 JFrame 上)。

在其他情况下,您需要构建一个所谓的游戏循环,在其中更新游戏状态并及时呈现更新的游戏状态。可以在此处找到有关使用 Java 代码的简单游戏循环的精彩教程:http://obviam.net/index.php/the-android-game-loop/

如果您开发一款严肃的游戏,您应该坚持使用游戏引擎来管理游戏循环和其他常规游戏开发方面。一个好的 Java 游戏引擎可以在这里找到:http://code.google.com/p/playn/

【讨论】:

  • 虽然是一个老问题,但我只是想澄清一下“严肃游戏”是一个术语,用于指以教育或营销等娱乐以外的目的创建的游戏。我想你的意思可能是“真正的游戏”或“完整的游戏”。
【解决方案2】:

对于游戏循环和将游戏对象和其他内容(图像、爆炸等)打印到屏幕上的有效方式,您需要一个计时机制和一个 JFrame 来一遍又一遍地打印,同时,从玩家和游戏状态本身获取更新。

首先,你需要一个 main 方法,我猜你对 java 中的这种类型的字段很陌生,所以我会尽可能快和清楚地为你分解它。

public static main(String[] args)
{
  yourClassName game = new yourClassName();
  game.run();
  System.exit(0);
}

这个 main 方法首先做了两件事,为你的 run 方法创建一个对象(因为不建议在游戏循环中使用静态引用),然后用你新创建的对象调用该方法。当该运行方法完成后,系统将退出程序。

现在我不会在这里详细介绍,但是一旦你运行了 run 方法,你需要一个只运行一次的 init 方法。在此方法中,您将创建要渲染到的 JFrame。这样做相当简单,所以我不会再进一步​​创建 JFrame 类。但是,您的 Run 方法应该看起来像这样......

void Run()
{
   init();
   while(isRunning)
   {
     update();
     draw();

     time = (1000 / fps) - (System.currentTimeMillis() - time);

            if (time > 0) 
            {
                try 
                { 
                        Thread.sleep(time); 
                } 
                catch(Exception e){} 
            }

   }
}

此方法会将计算速度减慢到您想要的某个 fps(在这种情况下,fps 变量被命名为 fps 用于显示)。

现在在您的更新方法中,您将拥有 keyBinding 和其他东西来查找键盘或鼠标的更改(在我的情况下,目前是服务器)。大多数人不知道如何在不接收 Repaint 方法所需的参数的情况下打印或绘制到 JFrame,因此我们将通过添加双缓冲来覆盖它。

BufferedImage backBuffer;

在你将添加的初始化方法中

backBuffer = new BufferedImage(getWidth(),getHeight(),
                            BufferedImage.TYPE_INT_RGB)

在draw方法中你将拥有...

Graphics g = getGraphics();

Graphics bbg = backBuffer.getGraphics();

并且您可以绘制到由 init 类创建的 JFrame(此外,通过这样做,您可以从任何类或线程中绘制以减少处理负载)。

要查看它是否有效,请继续使用bbg.fillRect(updateX,updateY,5,5)

updateX 和 updateY 表示用于更新矩形位置的变量。将它们保存为全局变量或保存在字符类中的公共变量。

如果一切都失败了,这里是我用来创建自己的游戏引擎的示例代码...

import input.InputHandler; 

import java.awt.*; 
import java.awt.event.KeyEvent; 
import java.awt.image.BufferedImage; 
import javax.swing.JFrame; 

/** 
 * Main class for the game 
 */ 
public class GameTutorial extends JFrame 
{        
    boolean isRunning = true; 
    int fps = 30; 
    int windowWidth = 500; 
    int windowHeight = 500; 

    BufferedImage backBuffer; 
    Insets insets; 
    InputHandler input; 

    int x = 0; 

    public static void main(String[] args) 
    { 
            GameTutorial game = new GameTutorial(); 
            game.run(); 
            System.exit(0); 
    } 

    /** 
     * This method starts the game and runs it in a loop 
     */ 
    public void run() 
    { 
            initialize(); 

            while(isRunning) 
            { 
                    long time = System.currentTimeMillis(); 

                    update(); 
                    draw(); 

                    //  delay for each frame  -   time it took for one frame 
                    time = (1000 / fps) - (System.currentTimeMillis()-          time); 

                    if (time > 0) 
                    { 
                            try 
                            { 
                                    Thread.sleep(time); 
                            } 
                            catch(Exception e){} 
                    } 
            } 

            setVisible(false); 
    } 

    /** 
     * This method will set up everything need for the game to run 
     */ 
    void initialize() 
    { 
            setTitle("Game Tutorial"); 
            setSize(windowWidth, windowHeight); 
            setResizable(false); 
            setDefaultCloseOperation(EXIT_ON_CLOSE); 
            setVisible(true); 

            insets = getInsets(); 
            setSize(insets.left + windowWidth + insets.right, 
                            insets.top + windowHeight + insets.bottom); 

        backBuffer = new BufferedImage(windowWidth, windowHeight,   BufferedImage.TYPE_INT_RGB); 
            input = new InputHandler(this); 
    } 

    /** 
     * This method will check for input, move things 
     * around and check for win conditions, etc 
     */ 
    void update() 
    { 
            if (input.isKeyDown(KeyEvent.VK_RIGHT)) 
            { 
                    x += 5; 
            } 
            if (input.isKeyDown(KeyEvent.VK_LEFT)) 
            { 
                    x -= 5; 
            } 
    } 

    /** 
     * This method will draw everything 
     */ 
    void draw() 
    {               
            Graphics g = getGraphics(); 

            Graphics bbg = backBuffer.getGraphics(); 

            bbg.setColor(Color.WHITE); 
            bbg.fillRect(0, 0, windowWidth, windowHeight); 

            bbg.setColor(Color.BLACK); 
            bbg.drawOval(x, 10, 20, 20); 

            g.drawImage(backBuffer, insets.left, insets.top, this); 
    } 
} 

我希望这会有所帮助,并且我知道这可能是一个非常晚的答案,但我还没有看到一个体面的 Java 游戏引擎,它易于理解和使用并且使用起来很有趣。希望你坚持下去,祝你编程愉快!!!

【讨论】:

    猜你喜欢
    • 2020-07-14
    • 2012-03-15
    • 1970-01-01
    • 1970-01-01
    • 2011-03-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多