【问题标题】:Java 2D programming: Rendering techniquesJava 2D 编程:渲染技术
【发布时间】:2024-01-12 22:04:02
【问题描述】:

我已经用 java 编程有一段时间了,我刚刚开始 2D 图形(游戏开发)。在编写我的游戏时,我注意到我的游戏出现了渲染问题。当我的播放器在屏幕上运行时,像素会出现故障。这就像多人游戏的延迟,但几乎不引人注意。在研究了这个问题之后,我没有想出任何解决方案,所以我请求你的帮助。

我的问题:我的游戏渲染很差,我想知道我的渲染方式是否很差。如果是这样,你能指出我的任何资源吗?

我的渲染类

public class Render extends JPanel implements Runnable{
    int SCREEN_WIDTH,SCREEN_HEIGHT;
    Game game;
    Thread t;

    public Render(int w,int h,Game g){
        this.SCREEN_WIDTH = w;
        this.SCREEN_HEIGHT = h;
        this.game = g;
        this.setDoubleBuffered(true);

    }

    public void run(){
        while(true){
            repaint();
        }
    }

    public void paint(Graphics g){
        super.paintComponent(g);
        Graphics2D g2d = (Graphics2D) g;
        g2d.translate(-this.game.getCamera().getX(), -game.getCamera().getY());


        g2d.setColor(Color.black);
        //fill the screen with black
        g2d.fillRect(0, 0, game.getLevelHandler().getLevel().getWidth() * 32, game.getLevelHandler().getLevel().getHeight() * 32);

        /**for(Entity E: game.getObjects()){
            E.draw(g2d);
        }*/
        //send the graphics object to my player...IS THIS OKAY TO DO?
        game.getPlayer().draw(g2d);

    }

    public void start(){
        t = new Thread(this);
        t.start();
    }

}




public class Player extends Entity{
    float dx,dy,moveSpeed;
    boolean jumping, canJump;

    float terminalVelocity,acceleration = 0;
    int GravityCounter,jumps,maxJumps,jumpheight = 0;


    public Player(float x, float y, float w, float h, ObjectID id, Game g) {
        super(x, y, w, h, id, g);
        //gravity
        terminalVelocity += 7;
        acceleration += 0.2;
        moveSpeed += 2.5;

        //jumping
        jumpheight = 40;        
        maxJumps = 2;
        jumps = maxJumps;
    }

    public void tick() {
        dx = 0;
        dy = 0;

        collisions();
        move();

        x += dx;
        y += dy;
    }

    public void collisions(){
    }

        public void move(){
        }
        //the drawing
        public void draw(Graphics2D g) {
            g.setColor(Color.green);
            g.drawRect((int)x, (int)y, (int)w, (int)h);
        }

    }

编辑:可下载链接here , 如果需要任何更改,我会尝试更正它。另外,内存泄漏时是否会出现这种故障?

由于建议,我修改了我的代码,这就是我现在所拥有的。

渲染器:

public class Render extends JPanel implements Runnable{
    int SCREEN_WIDTH,SCREEN_HEIGHT;
    Game game;
    Thread t;

    public Render(int w,int h,Game g){
        this.SCREEN_WIDTH = w;
        this.SCREEN_HEIGHT = h;
        this.game = g;
        this.setDoubleBuffered(true);

    }

    public void run(){
        while(true){
            repaint();
            try {
                Thread.sleep(16);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public synchronized void paint(Graphics g){
        Graphics2D g2d = (Graphics2D) g;
        g2d.translate(-this.game.getCamera().getX(), -game.getCamera().getY());


        g2d.setColor(Color.black);
        g2d.fillRect(0, 0, game.getLevelHandler().getLevel().getWidth() * 32,                 game.getLevelHandler().getLevel().getHeight() * 32);

        for(Entity E: game.getObjects()){
            synchronized(E){E.draw(g2d);}
        }

        synchronized(game.getPlayer()){game.getPlayer().draw(g2d);}

     }

    public void start(){
        t = new Thread(this);
        t.start();
    }

}

播放器类没有改变

源代码:here

【问题讨论】:

  • 您已覆盖 paint,但正在调用 super.paintComponent,开始出现问题。请记住,Swing 不是线程安全的,您需要采取措施将线程更新与屏幕更新同步,以确保在绘制游戏实体时不会修改它们的状态...
  • while(true) { repaint(); }...我想你可能想给 EDT 一些喘息的空间,尝试在repaint 之后添加Thread.sleep(16)...
  • 考虑提供一个runnable example 来证明您的问题。这将导致更少的混乱和更好的响应
  • @MadProgrammer 看看我上面的修改。
  • 覆盖paintComponent,调用super.paintComponent。除非您可以为演示您的问题的可运行示例提供源代码,否则我们将无法提供进一步帮助...

标签: java swing rendering


【解决方案1】:

我知道这里发生了什么,因为我在编写的游戏中遇到了完全相同的问题。这肯定是一件很难找到的事情。您的问题正在发生,因为您在绘制时正在舍入您的 xy 变量。

g.drawRect((int)x, (int)y, (int)w, (int)h);

这会导致您的矩形稍微跳动。因为看起来你的矩形可以有十进制坐标,所以你需要能够在十进制坐标处绘制矩形。有一种非常简单的方法可以做到这一点,但是让我们使用一种不管你在画什么都可以工作的方法。

您将需要使用一些转换,我个人喜欢AffineTransform's。有很多关于这些的教程,但这是谷歌搜索https://docs.oracle.com/javase/tutorial/2d/advanced/transforming.html 的第一个(非文档)结果。我知道您已经在进行一些转换,但这是您添加它们后绘制方法的样子。

public void draw(Graphics2D g) {
        AffineTransform original = g.getTransform(); // keep a copy of the original so that we can restore it
        AffineTransform transform = (AffineTransform)original.clone();
        transform.translate((double)x, (double)y); // translate the transform to the player location, note that x and y can be non-integers here.
        g.transform(transform); // apply the transformation.
        g.setColor(Color.green);
        g.drawRect(0, 0, (int)w, (int)h);
        g.setTransform(original); // restore the original transformation
    }

对于其余的墙壁和其他东西,您可以使用完全相同的方法。请记住,对象的“屏幕”位置是对象的游戏位置减去相机的游戏位置。祝你游戏好运。

【讨论】:

  • 感谢您的回复。但这似乎并不能解决问题。我什至把我所有的浮点数都改成了整数,但故障仍在发生。
  • @Nichos 您不必使用整数。您应该改用double,它们的范围更大,而且(在我看来)更容易使用。
  • 好的,谢谢。我遇到了另一个问题。我正在翻译我的播放器周围的屏幕,当我添加 AffineTransform 时,一切都开始出现问题。 (对不起,这是多么模糊,很难解释)
  • 另外,我的“g”​​对象不能识别gettransform(); (抱歉重复发帖)
  • @Nichos 没有看到你的代码很难说清楚。您可以编辑您的问题并更新其中的代码吗?