0

所以,我正在用 Java 制作一个 2D 游戏,我真的没有太多的 Java 经验。我目前使用一个非常简单的循环,使用每 10 毫秒左右运行一次的摆动计时器,看起来像:

public void actionPerformed(ActionEvent e) {
update();
repaint();
}

但是,出于显而易见的原因,我需要一些更实用的东西。这些原因包括更多的延迟意味着更少的 FPS 和更慢的移动/其他更新。我在此处的 3D Java 游戏教程中找到了以下代码。它会在程序启动时开始运行,我知道它会起作用。但是,我并不完全理解它:(tick() 是更新程序,render() 渲染屏幕)

    long currenttime;
    long previoustime = System.nanoTime();
    long passedtime;
    int frames = 0;
    double unprocessedseconds = 0;
    double secondspertick = 1 / 60.0;
    int tickcount = 0;
    boolean ticked = false;     

    while (gameIsRunning) {
        currenttime = System.nanoTime();
        passedtime = currenttime - previoustime;
        previoustime = currenttime;
        unprocessedseconds += passedtime / 1000000000.0;

        while (unprocessedseconds > secondspertick) {
            tick();
            unprocessedseconds -= secondspertick;
            ticked = true;
            tickcount++;
            System.out.println(tickcount);
            if (tickcount % 60 == 0) {
                System.out.println(frames + " FPS");
                previoustime += 1000;
                frames = 0;
            }
        }
        if (ticked) {
            render();
            frames++;
        }
        render();           
        frames++;
    }

我发现它的教程中没有解释这个代码。有人可以把它分解并解释一下吗?我也在这里寻找想法,该页面上带有渲染线程和更新线程的最后一段代码对我来说很有意义。我应该使用哪种方法?以上之一,还是完全不同的东西?此外,您可能会说这是我在 stackoverflow 上的第一个问题。在此先感谢,乔希

4

2 回答 2

1

tick() 可能正在更新游戏对象的物理属性(位置、速度等)。 tick() 每次更新都会被调用多次,因为某些模拟无法处理太大的时间步长而不会变得不稳定。

网上有一篇热门文章解释了为什么会这样,以及为什么使用固定时间步长是正确的程序。 一探究竟。

每次更新游戏都会以 1/60 秒(即每秒 60 帧)为增量进行升级。重复此操作,直到总共剩余不到 1/60 秒。聚合只是总和的一个花哨的词。

然后将游戏当前状态的快照呈现到屏幕上。

我不会深入研究它,但实际上这段代码应该在 render() 期间将每个对象的位置插入聚合中的剩余时间。

long currenttime;
long previoustime = System.nanoTime();
long passedtime;
int frames = 0;
//this is an aggregate, games usually step in fixed units of time.
//this is usually because physics simulations can't handle too large of time steps.
double unprocessedseconds = 0;
double secondspertick = 1 / 60.0;
int tickcount = 0;
boolean ticked = false;     

while (gameIsRunning) {
    //get elapsed nano seconds from the epoch (january 1st, 1970)
    currenttime = System.nanoTime();
    //take difference of current time in nanos and previous time in nanos
    passedtime = currenttime - previoustime;
    previoustime = currenttime;
    //divide to get the elapsed time in seconds.
    unprocessedseconds += passedtime / 1000000000.0;

    while (unprocessedseconds > secondspertick) {
        tick();
        unprocessedseconds -= secondspertick;
        ticked = true;
        tickcount++;
        System.out.println(tickcount);
        if (tickcount % 60 == 0) {
            System.out.println(frames + " FPS");
            previoustime += 1000;
            frames = 0;
        }
    }
    if (ticked) {
        render();
        frames++;
    }
    render();           
    frames++;
}

祝乔什好运。

编辑:

我没有使用一个线程进行更新和一个线程进行渲染的游戏经验。出于这个原因,我无法就这些提供建议。如果您对多线程几乎没有经验,我会避免使用它,因为只有复杂的游戏可能需要这种方法,而多线程会增加许多您可能不想处理的问题。

多线程游戏引擎在渲染和更新之间会比单线程游戏消耗更多的内存,或者最终会相互依赖。这是因为两个线程不能同时操作相同的数据。因此,两个线程操作的唯一方法是在这些数据结构上进行同步,或者通过更新线程为渲染线程提供不可变数据以进行渲染。

编写多线程游戏引擎将是对线程的一个很好的介绍。它可以教给你很多东西。取决于你想从中得到什么。

如果您正在制作 2D 游戏,我会更加确信您不需要一个线程进行更新和一个线程进行渲染。

如果你真的想追求这个,这就是我要采取的方法。

您只需要一个 while 循环来控制渲染。

于 2013-07-19T22:43:50.750 回答
0

我做引擎的方式和前面解释的一样,我是多线程的。基本上,如果你将处理和绘制游戏的工作分成两个部分,它会变得更快,但会消耗更多的资源。我做了一些这样的事情:

public class Engine implements Runnable {

    //Sets classes
    Engine tick = new Engine(true);
    Engine render = new Engine(false);
    Thread tickThread = new Thread(tick);
    Thread renderThread = new Thread(render);

    boolean job;
    boolean isRunning = false;

    long sleepTime = 5L;

    public Engine(boolean job) {
         //Sets what the thread does
         this.job = job;
    }

    public static void startEngine() {
         //Starts Engine
         isRunning = true;
         tickThread.start();
         renderThread.start();
    }

    public void tick() {
         //Process things
    }

    public void render() {
         //Draw things
    }

    public void run() {
         //Do engine base things
         while(isRunning) {
              if(job) {
                   tick();
              } else {
                   render();
              }
              Thread.sleep(sleepTime);
         }
    }

}

这一点都不先进。这只是一个简单的多线程游戏引擎的示例。老实说,当我开始制作游戏时,我使用了这个确切的代码。这可以使用,但应根据您的用途进行一些调整。我的意思是,假设您有一个正在移动的对象,并且它同时被渲染。如果对象的位置是 50 并且增加并且渲染方法正在绘制它,那么对象可以在再次渲染之前转到 51 然后 52。通常,处理比绘图快。另一个例子:假设您有一个 ArrayList 并且不断地向其中删除和添加对象。有时您可以在渲染方法即将绘制对象时移除对象并导致空指针异常,因为它正在尝试绘制不存在的东西' 不存在。(我使用了“if(object.get(i)!= null)”并以这种方式解决了它)我希望这至少有一点帮助(两年后,大声笑)并帮助您获得多线程的基础就像(如果你还没有)。

于 2015-07-21T05:53:23.213 回答