简体   繁体   English

Java 2D游戏由repaint()提供支持; 以一种奇怪的方式落后

[英]Java 2D game “powered” by repaint(); lags in a strange way

I used my recent days to program a little 2D game in Java. 最近几天,我用Java编写了一个2D游戏。 I wanted to use nothing but the normal Java SDK. 我只想使用普通的Java SDK。 So far so good. 到现在为止还挺好。 I now finshed it, there's just one little problem: I used the Thread.sleep method to create something like a gameloop/tick. 现在完成它,只有一个小问题:我使用Thread.sleep方法创建了类似gameloop / tick的东西。 Since I'm not too familiar with object oriented programming, I'm not quite sure whether I use the right expressions, so please ignore wrong ones. 由于我不太熟悉面向对象的编程,因此我不确定是否使用正确的表达式,因此请忽略错误的表达式。

The strange thing is, that if I switch my waiting-time (I called it "Takt") to 100 or above, everything works perfectly fine. 奇怪的是,如果我将等待时间(我称其为“ Takt”)设置为100或更高,则一切正常。 I want to change it to 50, but as soon as I get it lower than 100, the game starts lagging extremly (the bouncing red ball which this easy ping-pong-game is about starts flickering heavily. 我想将其更改为50,但是当我将其设置为低于100时,游戏开始极端滞后(此简单的乒乓球游戏即将开始的弹跳红球开始大量闪烁。

Here's a piece of code of my Display class, it includes the paint(); 这是我的Display类的一部分代码,其中包括paint(); method. 方法。 If you need other code parts, just let me know! 如果您需要其他代码部分,请告诉我! And please pardon my variable names, I'm from germany. 请原谅我的变量名,我来自德国。 So here's the code: 所以这是代码:

import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JFrame;
import javax.swing.JOptionPane;

@SuppressWarnings("serial")

public class Output extends JFrame implements Runnable{

public static int W = 400;
public static int H = 700;

public static int Playerx;
public static int Playery = H-30;
public static int Punkte;

public static int Trash;

public static long Takt = 100;

public static boolean DrawGameOver;
public static boolean finished;

public static void main(String[] args) throws InterruptedException {
    JOptionPane.showMessageDialog(null, "Das Spiel startet, sobald Sie auf OK drücken. Das Ziel ist es, möglichst viele Punkte zu erzielen.", "Ping-Pong-Solo", JOptionPane.NO_OPTION);
    JOptionPane.showMessageDialog(null, "Mindstanforderungen: 1. Dual-Core Prozessor 2. Bildschirmauflösung mit mindestens 400*700p", "Systemanforderungen", JOptionPane.NO_OPTION);

    Output Fenster = new Output();
    Fenster.setSize(W, H);
    Fenster.setResizable(false);
    Fenster.setLocationRelativeTo(null);
    Fenster.setVisible(true);
    Fenster.setTitle("Ping Pong Release 1.0");
    Fenster.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    Fenster.addKeyListener(new MyKeyListener());
    new Physics();
    new Thread(new Output()).start();
    while(true){
        if(DrawGameOver == false && finished){
            Fenster.repaint();
        }else{
            GameOver();
        }
        try {
            Thread.sleep(Takt);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        if(!DrawGameOver){
            Physics.Bewegung();
        }
    }
}       

public static void GameOver(){
    JOptionPane.showMessageDialog(null, "Sie erreichten "+Punkte+" Punkte. ", "Spiel beendet.", JOptionPane.NO_OPTION);
    JOptionPane.showMessageDialog(null, "(c) Joel Krimmel", "Der Boss", JOptionPane.NO_OPTION);
    System.exit(0);
}
    public void paint(Graphics g){
        finished = false;

        g.setColor(Color.BLACK);
        g.fillRect(0, 0, W, H);
        g.setColor(Color.BLUE);
        g.fillRect(Playerx, Playery, 100, 20);
        g.setColor(Color.RED);
        g.fillRoundRect(Physics.x, Physics.y, Physics.W, Physics.H, 500, 500);
        g.setColor(Color.YELLOW);
        g.drawString("Punkte: "+Punkte, W-100, 50);

        finished = true;
    }
    @Override
    public void run() {
        // TODO Auto-generated method stub
        while(true){
            MyKeyListener.Verarbeitung();
        }
    }
} 

So there could be multiple reasons why your game is flickering. 因此,您的游戏闪烁可能有多种原因。 I think the most likely one is that you are using no buffering. 我认为最可能的原因是您没有使用缓冲。 That means that you are drawing the screen while it's beeing displayed. 这意味着您正在蜂鸣显示屏幕时对其进行绘制。 So stange things like half drawn pictures will be displayed sometimes. 因此有时会显示像半张图画之类的粗糙东西。 Instead you can write the content to an image first and then draw the whole image at once. 相反,您可以先将内容写入图像,然后立即绘制整个图像。
In the code it would look something like this: 在代码中,它看起来像这样:

public void paint(Graphics g){
    finished = false;
    // the buffer image
    BufferedImage bufferImage = new BufferedImage(getWidth(),getHeight(),BufferedImage.TYPE_INT_RGB);
    // I used Graphics2D instead of Graphics here, because its more flexible and lets you do more things.
    Graphics2D g2 = (Graphics2D)bufferImage.getGraphics();
    g2.setColor(Color.BLACK);
    g2.fillRect(0, 0, W, H);
    // ...
    g2.drawString("Punkte: "+Punkte, W-100, 50);
    // now draw the buffer image on the screen.
    g.drawImage(bufferImage, 0, 0, null);
    finished = true;
}

(That code is not ideal, but it's a quick way to do it. If you want to know how to do it better look up "double buffering".) (该代码不是理想的代码,但这是一种快速的方法。如果您想知道如何更好地执行此操作,请查找“双重缓冲”。)

Another (unlikely) reason could be that the rendering takes different amounts of time each rendering process. 另一个(不太可能)的原因可能是,每个渲染过程需要花费不同的时间。 You could fix that by measuring the time the rendering takes with System.currentTimeMillis() and adjust the sleeping time. 您可以通过使用System.currentTimeMillis()测量渲染所花费的时间并调整休眠时间来解决此问题。

And also: Don't name variables in german. 并且:不要用德语命名变量。 I'm german too (Hallo aus Bremen) and I don't do it either. 我也是德国人(不来梅哈洛),我也不这样做。 I's bad. 不好。 :-) :-)
But more importantly don't start variable name with an upper-case letter, they can easily be confused with clases otherwise. 但更重要的是,不要以大写字母开头变量名,否则它们很容易与句号混淆。
You should take a look at the java naming conventions . 您应该看一下Java命名约定

I've noticed that you're using JFrame, which means that each time you repaint, you're repainting the entire window. 我注意到您正在使用JFrame,这意味着每次重新绘制时,都将重新绘制整个窗口。 The solution is to use a JPanel, which is much faster, and to put that into your JFrame as to not have any more flickering. 解决方案是使用速度更快的JPanel,并将其放入JFrame中,以免闪烁。 Also, thread.sleep essentially freezes your entire program, so please use the swing timer. 另外,thread.sleep实际上会冻结整个程序,因此请使用swing计时器。

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

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