简体   繁体   English

如何减少我的Java 2D Platformer的滞后?

[英]How to reduce lag in my java 2d platformer?

I am making a 2d platformer in Swing java, and I am wondering how to reduce the lag I get from it. 我正在使用Swing Java开发2D平台游戏,我想知道如何减少从它获得的延迟。 I mean, it doesnt lag too bad but it is noticable that it slows down sometimes. 我的意思是,它并不会太落后,但值得注意的是它有时会变慢。 I have a Swing timer ticking at 12 milliseconds, a cycle function, and a paint function. 我有一个在12毫秒处滴答作响的Swing计时器,一个循环功能和一个绘画功能。

public void cycle() {
    if (guy.getJumpState() == false) {
        if (canExecuteMovement(0, 4)) {
            onGround = false;
            if (guy.getY() > 300) {
                // if you are in the middle, move the platforms.
                for (int i = 0; i < platformCount; i++) {
                    platform[i].setY(platform[i].getY() - 4);
                }
            } else {
                // or just move the guy if not.
                guy.moveY(4);
            }
        } else {
            onGround = true;
        }
    } else {
        if (canExecuteMovement(0, -8)) {
            if (guy.getY() < 300) {
                // if you are in the middle, move the platforms.
                for (int i = 0; i < platformCount; i++) {
                    platform[i].setY(platform[i].getY() + 8);
                }
            } else {
                // or just move the guy if not.
                guy.moveY(-8);
            }
            jumpCount++;
            if (jumpCount >= 15) {
                jumpCount = 0;
                guy.setJumpState(false);
            }
        } else {
            jumpCount = 0;
            guy.setJumpState(false);
        }
    }

    if (guy.getDirection() == "left") {
        if (canExecuteMovement(-3, 0)) {
            if (guy.getX() < 450) {
                // if you are in the middle, move the platforms.
                for (int i = 0; i < platformCount; i++) {
                    platform[i].setX(platform[i].getX() + 3);
                }
            } else {
                // or just move the guy if not.
                guy.moveX(-3);
            }
        }
    } else if (guy.getDirection() == "right") {
        if (canExecuteMovement(3, 0)) {
            if (guy.getX() > 450) {
                // if you are in the middle, move the platforms.
                for (int i = 0; i < platformCount; i++) {
                    platform[i].setX(platform[i].getX() - 3);
                }
            } else {
                // or just move the guy if not.
                guy.moveX(3);
            }
        }
    }
}


public void paint(Graphics g) {
    super.paint(g); // something important
    Graphics2D g2d = (Graphics2D) g;

    // draw platforms
    for (int i = 0; i < platformCount; i++) {
        if (platform[i].getX() > -50 && platform[i].getX() < 950 && platform[i].getY() > -50 && platform[i].getY() < 650) {
            g2d.drawImage(platform[i].getImage(), platform[i].getX(), platform[i].getY(), this);
        }
    }

    // draw guy
    g2d.drawImage(guy.getImage(), guy.getX(), guy.getY(), this);

    // destroy unneeded processes
    Toolkit.getDefaultToolkit().sync();
    g.dispose();
}

What can I do to optimize this and cause less lag? 我该怎么做才能优化这一点并减少延迟? When I make a thread for the cycle function itself, the platforms sometimes seperate for a split second. 当我为循环功能本身创建线程时,平台有时会瞬间分开。 I assume because since the thread is asynchronous, half of it is done while the paint function goes on. 我假设是因为线程是异步的,所以它的一半是在paint函数打开时完成的。

Some loose thoughts (it's been years since I did some animation in Swing), and you didn't posted some compilable code. 一些松散的想法(自从我在Swing中制作动画以来已经有好几年了),并且您没有发布一些可编译的代码。

  • Have you tried do paintComponent() --- paint does a lot of other stuff. 您是否尝试过paintComponent()--- paint还有很多其他功能。 And then maybe you need to add repaint() to tick function. 然后也许您需要将repaint()添加到tick函数。 Every time I reloaded paint it enden in a mess. 每次我重新装油漆时,它都会变得一团糟。
  • Also try increasing tick time --- youll waste less time repaiting. 也可以尝试增加刻度时间---您浪费的时间更少。
  • Also I assume you are doing ticks by Timers. 我还假设您正在按计时器进行滴答作响。
  • I have no idea why you dispose graphics object 我不知道为什么要放置图形对象
  • Also try just dropping sync (Ive done animations that work on many oeses without it) Toolkit.getDefaultToolkit().sync() 也可以尝试仅删除同步(没有它,我就已经完成了可以在许多类中工作的动画) Toolkit.getDefaultToolkit().sync()

If it doesn't help use profiler to find a bottleneck. 如果这样做没有帮助,请使用探查器查找瓶颈。 Visual VM is quite nice. Visual VM非常不错。 Also Visual VM is part of the jdk for some time --- just go into bin folder and launch jvisualvm. 另外,Visual VM在一段时间内还是jdk的一部分-只需进入bin文件夹并启动jvisualvm。

EDIT: (thread issues) 编辑:(线程问题)

  • Some people suggested using threads --- which I diasgree. 有人建议使用线程---我不同意。 If you want do some work outside EDT please use SwingWorker 如果要在EDT之外进行一些工作,请使用SwingWorker
  • I assume you are not calling paint() but just call repeaint() . 我假设您不是在调用paint()而是在调用repeaint() If you do call paint() (whatever black magic you also make to make it work) please just call repaint() that will schedule repaing on appropriate time. 如果您确实调用了paint() (无论您使用什么黑魔法都可以使它起作用),请仅调用repaint()即可在适当的时间安排修复。

I would create your variables outside the method so that it is not being created every time you call that method. 我会在方法之外创建变量,以免每次调用该方法时都不会创建该变量。 The best way to program games is to re-use things instead of destroying and creating because destroying & creating cost a lot of computing power. 编写游戏程序的最佳方法是重用事物而不是破坏和创造,因为破坏和创造会消耗大量的计算能力。

Graphics2D g2d = (Graphics2D) g; <---declare it outside your method.

And also try to find redundant conditionals. 并尝试查找多余的条件。 I saw one where you say (if direction right then ..., else if direction left ...); 我在您说的地方看到了一个(如果向右的方向是...,否则向左的方向...); just say (if direction right then ... else ...). 只是说(如果方向正确,则...否则...)。 Conditionals do not cost much but when you're calling that conditional 1000 times a second I think it adds up. 有条件的花费不多,但是当您每秒调用该有条件的1000次时,我认为它加起来了。 (idk though, but I do it just in case and for making things fluid) (虽然idk,但我这样做是为了以防万一,并使事情变得流畅)

Where you say setjumpstate(false) it's redundant because no matter what, it is executed - just move it outside the conditional. 在说setjumpstate(false)的地方,这是多余的,因为无论执行什么操作,都将其执行-只需将其移至条件setjumpstate(false)之外即可。

First of all, this bit here is a problem: 首先,这是一个问题:

// destroy unneeded processes
Toolkit.getDefaultToolkit().sync();
g.dispose();

In general, disposing a resource you did not create is probably a bad idea. 通常,处置未创建的资源可能是个坏主意。 In this specific case, the Graphics passed into paint() is probably used by all other components in the hierarchy, so this could cause really odd results. 在这种特定情况下,传递给paint()Graphics可能会被层次结构中的所有其他组件使用,因此这可能会导致非常奇怪的结果。

Calling Toolkit.sync() here is I think your attempt to eliminate the tearing you were seeing when moving things in the background. 我认为在这里调用Toolkit.sync()是您尝试消除在后台移动事物时看到的撕裂感的尝试。 But all that it does is to flush any pending draw instructions. 但是,它所做的只是刷新所有未决的绘制指令。 That has no effect here because you are probably drawing to a back-buffered Swing component that will be drawn fully later. 这在这里没有效果,因为您可能正在绘制一个将在以后完全绘制的后缓冲Swing组件。

The correct way to eliminate tearing is to perform any updates on the event thread, so that you are not changing the screen data while drawing it. 消除撕裂的正确方法是在事件线程上执行任何更新,以便在绘制时不会更改屏幕数据。 One simple way to implement this would be to have your timer just call repaint() , and have the paint() method call cycle() before doing anything. 一种简单的实现方法是让您的计时器只调用repaint() ,并在执行任何操作之前让paint()方法调用cycle()。

For dealing with lag, one solution might be to allow a variable frame rate. 为了处理延迟,一种解决方案可能是允许使用可变帧速率。 Instead of moving everything a fixed distance each frame, calculate the time since the last frame and move everything accordingly. 不必将所有内容每帧移动固定距离,而是计算自上一帧以来的时间并相应地移动所有内容。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM