ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

Java游戏开发:图形

2019-11-23 04:14:00  阅读:308  来源: 互联网

标签:animation swing jpanel jframe java


我是新来的.希望您能提供帮助.

问题:
在JFrame上显示动画时出现问题.似乎我想念/不太了解Java的图形如何工作.

全球思路:
假设我要制作游戏/电影/剪辑.为此,我需要这个(不是)简单的动画开始工作.

这个问题的一个例子:
我得到了Screen类,它具有屏幕内容-JFrame的声明,设置其配置(大小,关闭操作等),然后创建Box类的对象,以显示在框架上.请检查以下图像/类的图表(希望我以正确的方式写出):ClassesDiagram

现在,Box类扩展了JPanel.我从JPanel继承了Paint()方法并重写了它,即绘制框.

在Screen类中,在创建两个Box之后,我将它们添加到JFrame.接下来,启动一个while(true)循环,并通过使线程休眠该数量每200毫秒更新一次盒子的位置.
(在这种情况下,简单的x或y取决于哪个box,box1或box2).

主要问题1):程序运行并显示JFrame,但在JFrame上仅显示最后添加的对象/组件Box.它没有显示另一个.为什么?

我找到了一个主题How to add multiple components to a JFrame?,并尝试了jjnguy 2010年11月15日17:02投票次数最多的技巧.
由于某种奇怪的原因,第一个技巧或第二个技巧都不适合我.

主要问题2):据我了解,我需要布局管理器.如果我只想在框架上特定的X,Y处绘制(),为什么需要它?

找到了其他帖子(不能再次找到它)Oracle有关布局的指南,建议我需要考虑使用setLayout(null);.我试图这样做,但是又有一个问题.

主要问题3):JFrame出现,它只显示1个框(绿色将不显示,无论您要做什么.不知道为什么),当它移动时,它将从另一侧擦除.
此处:Box Movement

预先感谢您的帮助,提示和解释!希望帖子清晰,井井有条,外观漂亮.

public class Screen {

public static void main(String[] args) {
    new Screen();
}

private JFrame window;

public Screen() {
    window = new JFrame("Multiply components panel");
    //window.setLayout(null);
    window.setSize(200, 200);

    window.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);

    Box b1 = new Box(10,10, "box1");
    //b1.setBounds(10, 10, 50, 50);

    Box b2 = new Box(100,100, "box2");
    //b2.setBounds(100, 100, 50, 50);


    window.add(b1);
    //window.add(b2);


    window.setVisible(true);

    while (true){

        b1.update();
        b2.update();

        try {
            Thread.sleep(200);
        } catch (Exception e) {
            // TODO: handle exception
        }
    }

}
}
public class Box extends JPanel{

int x, y, w, h;
private String name;

public Box(int x, int y, String name) {
    this.x = x;
    this.y = y;
    this.w = 100;
    this.h = 100;
    this.name=name;
}


public void paint(Graphics g){
    System.out.println(this.name.equalsIgnoreCase("box1"));
    if(this.name.equalsIgnoreCase("box1")){
        g.setColor(Color.BLACK);
        g.fillRect(x, y, w, h);
    }else{
        g.setColor(Color.GREEN);
        g.fillRect(x, y, w, h);
    }


}


public void update() {
    if(this.name.equalsIgnoreCase("box1"))
        x++;
    else
        y++;
    //this.setBounds(x, y, w, h);
    System.out.println("Current "+name+": X: "+x+", Y: "+y+", W: "+w+", H: "+h);
    repaint();
}

}

解决方法:

Main Problem 1): The program runs, and shows the JFrame, but on the
JFrame it shows only the last added object/component- Box. It doesn’t
show the other one. Why?

你做
window.add(b1);
window.add(b2);,
默认情况下,JFrame具有BorderLayout,因此您在执行add(..)时将替换上一个添加的框.

Main Problem 2): As far as I understand, i need layout manager. Why do
I need it, if I just want to paint() at specific X,Y on the frame?

如果您将JPanels用作游戏中的对象,则这将是唯一一次使用setLayout(null)的时间,因为我们希望完全控制JPanels的放置.

Main Problem 3): The JFrame shows up, it shows only 1 box(the green
one wont show up, whatever you will do. Don’t know why) and when it
DOES move- it gets erased from the other side. Here: Box Movement

因为您要执行g.fillRect(x,y,w,h),所以它应该是g.fillRect(0,0,w,h)

其他问题:

1)我认为您遇到的主要问题是:

public class Box extends JPanel{

    ...

    public void paint(Graphics g){

       ...
    }

}

您应该重写JPanel的paintComponent,并记住在覆盖的方法中首先调用super.paintComponent(g).

3)您应该重写JPanel的getPreferredSize并返回与JPanel的图像或内容匹配的正确尺寸

4)不要在JFrame上调用setSize使用正确的Layoutmanager和/或重写必需容器的getPreferredSize,而不是在将JFrame设置为可见之前简单地在JFrame上调用pack().

5)如@MadProgrammer所说,读Concurrency in Swing,但基本上所有Swing组件都应通过SwingUtilities.inokeXXX块在EDT上创建/操作.

6)这样做绝对是不好的:

while (true){

    b1.update();
    b2.update();

    try {
        Thread.sleep(200);
    } catch (Exception e) {
        // TODO: handle exception
    }
}

因为您不仅要创建连续循环,而且还要在创建GUI的线程上调用Thread.sleep,所以似乎冻结了.看看How to use Swing Timers,也看到关于以上主题的this类似的question.answer.

这是实现上述修复的代码:

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import javax.swing.AbstractAction;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;

public class Screen {

    private JFrame window;

    public static void main(String[] args) {

        //creat UI on EDT
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                new Screen();
            }
        });
    }

    public Screen() {
        window = new JFrame("Multiply components panel") {
            @Override
            public Dimension getPreferredSize() {
                return new Dimension(600, 400);
            }
        };

        window.setLayout(null);//only reason this is warrented is because its a gmae using JPanels as game objects thus we need full control over its placing
        window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//changed from DISPOSE to EXIT so Timers  will be exited too

        final Box b1 = new Box(10, 10, 50, 50, "box1");

        final Box b2 = new Box(100, 100, 50, 50, "box2");

        window.add(b1);
        window.add(b2);

        window.pack();
        window.setVisible(true);

        Timer timer = new Timer(200, new AbstractAction() {
            @Override
            public void actionPerformed(ActionEvent e) {
                b1.update();
                b2.update();
            }
        });
        timer.setInitialDelay(0);
        timer.start();

    }
}

class Box extends JPanel {

    int x, y, w, h;
    private String name;

    public Box(int x, int y, int w, int h, String name) {
        this.x = x;
        this.y = y;
        this.w = w;
        this.h = h;
        this.name = name;
        setBounds(x, y, w, h);//let the Box class handle setting the bounds more elegant OOP
    }

    @Override
    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        System.out.println(this.name.equalsIgnoreCase("box1"));
        if (this.name.equalsIgnoreCase("box1")) {
            g.setColor(Color.BLACK);
            g.fillRect(0, 0, w, h);
        } else {
            g.setColor(Color.GREEN);
            g.fillRect(0, 0, w, h);
        }
    }

    @Override
    public Dimension getPreferredSize() {
        return new Dimension(w, h);
    }

    public void update() {
        if (this.name.equalsIgnoreCase("box1")) {
            x++;
        } else {
            y++;
        }
        this.setBounds(x, y, w, h);//set the new bounds so box may be updated
        System.out.println("Current " + name + ": X: " + x + ", Y: " + y + ", W: " + w + ", H: " + h);
        revalidate();
        repaint();
    }
}

最后看看我的教程/代码段Game Development Loop, Logic and Collision detection Java Swing 2D.

它具有启动简单的2D游戏所需的全部功能,如游戏循环,逻辑,像素碰撞检测,动画(即,在多个精灵之间进行交换以创建精灵集的动画),以及更多的基本区​​别在于,它使用对象作为对象游戏实体,即一个类将保存绘制对象的所有必需信息,IMO这就是游戏的完成方式,事情可能会变得图形化,许多JPanels怀疑屏幕肯定会降低整体FPS

标签:animation,swing,jpanel,jframe,java
来源: https://codeday.me/bug/20191123/2065018.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有