Java游戏开发:图形 [英] Java Game Development: Graphics

查看:60
本文介绍了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.它没有显示另一个.为什么?

我找到了一个主题,如何向JFrame添加多个组件吗?,并尝试了投票最多的帖子,发表时间是 jjnguy,2010年11月15日,17:02 . 出于某种奇怪的原因,第一个技巧或第二个技巧都不适合我.

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

找到了其他帖子(不能再次找到它)+ Oracle的布局指南,建议我需要考虑使用setLayout(null);我曾尝试这样做,但随后又出现了问题.

主要问题3): JFrame出现,它只显示1个框(绿色将不显示,无论您做什么,都不知道为什么),并且它何时移动-它从另一面被擦除. 此处:盒子运动

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


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();
}

}

解决方案

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

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

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

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

主要问题3):显示JFrame,它仅显示1个框(绿色 一个人不会出现,无论您做什么.不知道为什么),什么时候 会移动吗?它会从另一面擦除.此处:方块运动

因为您执行了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)您应该覆盖JPanelgetPreferredSize,并返回与JPanel

的图像或内容匹配的正确尺寸

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

5),如@MadProgrammer所说,请阅读 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,因此似乎冻结了.看看如何使用Swing计时器,另请参见关于上述主题的类似问题. >

以下是实现了上述修复的代码:

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();
    }
}

最后看看我的教程/代码段ClassesDiagram

Now, class Box extends JPanel. I inherit from JPanel the method Paint() and override it, painting boxes.

In the Screen class, after I created the two Boxes, i .add() them to the JFrame. Next, starts a loop while(true), and updates the box's position every 200 milisec by making the thread sleep that amount. (in this case, just simple x++ or y++ depends on which box, box1 or box2).

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?

I found a topic, How to add multiple components to a JFrame?, and tried the tips the most voted post gave, by jjnguy Nov 15 '10 at 17:02. For some odd reason, not the first, nor the second tip worked for me.

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?

Found other post(cant find it again)+Oracle's guidelines about layouts, suggested that I need consider using setLayout(null); I tried to do so, but then there's a problem once again.

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

Thank you in advance for any help, tips, and explanation! Hope the post is clear, organised, and nice looking.


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?

You do window.add(b1); window.add(b2);, by default JFrame has BorderLayout thus you are replacing the last added box when you do 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?

If you are using JPanels as objects in the game than, this would be the only time to use setLayout(null) as we want full control over the JPanels placing.

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

because you you do this g.fillRect(x,y,w,h), it should be g.fillRect(0,0,w,h)

Other problems:

1) I think a major problem you have is here:

public class Box extends JPanel{

    ...

    public void paint(Graphics g){

       ...
    }

}

You should override paintComponent of JPanel, and remember to call super.paintComponent(g) as first call in overridden method.

3) you should override getPreferredSize of JPanel and return correct dimensions which match the image or contents of the JPanel

4) dont call setSize on JFrame use correct Layoutmanager and/or override getPreferredSize of necessary containers than simply call pack() on JFrame before setting it visible.

5) as said by @MadProgrammer have a read on Concurrency in Swing but basically all Swing components should be created/manipulated on EDT via SwingUtilities.inokeXXX block.

6) doing this is definetly bad:

while (true){

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

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

as you are not only creating a continuous loop but also calling Thread.sleep on the Thread which you created you GUI, thus is will seem to freeze. Have a look at How to use Swing Timers, also see this similar question.answer on the above topic.

Here is code with above fixes implemented:

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();
    }
}

Lastly have a look at my tutorial/code snippet Game Development Loop, Logic and Collision detection Java Swing 2D.

It has all you need to start a simple 2D game, like game loop, logic, pixel collision detection, animation ( ie swapping between multiple sprites to create animation of the sprite set), and more, the fundamental difference though is it uses objects as the game entities, i.e a class will hold all the needed information for an object to be drawn, IMO this is how games should be done, a things might get graphically intense and have many JPanels wondering the screen will definitely drop overall FPS

这篇关于Java游戏开发:图形的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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