所以,我正在努力用Java制作2D游戏,而且我真的没有太多的Java经验。我目前使用一个非常简单的循环,使用一个每10毫秒运行一次的swing计时器,看起来像是:
public void actionPerformed(ActionEvent e) {
update();
repaint();
}
然而,出于显而易见的原因,我需要一些更实用的东西。这些原因包括更多滞后意味着更少的FPS和更慢的移动/其他更新。 我在3D Java游戏here的教程中找到了以下代码。它会在程序启动时开始运行,我完全理解它会起作用。但是,我不完全理解它:( 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++;
}
这个代码没有在我找到的教程中解释。有人可以打破这个并解释一下吗? 我还查看了here的想法,并且该页面上的最后一段代码带有渲染线程和更新线程对我来说很有意义。 我应该使用哪种方法?上面的一个,或者完全不同的东西?另外,你可以告诉我这是我在stackoverflow上的第一个问题。 提前致谢, 约什
答案 0 :(得分:1)
tick()可能更新了游戏对象的物理属性(位置,速度等)。每次更新都会多次调用tick()因为某些模拟无法处理太大的时间步而不会变得不稳定。
网上有一篇很受欢迎的文章解释了为什么会出现这种情况,以及为什么使用固定的时间步长是正确的程序。 Check it out.
每次更新游戏都会在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++;
}
祝你好运Josh。
编辑:
我没有使用一个线程进行更新的游戏经验,还有一个用于渲染的游戏。由于这个原因,我无法就这些提出建议。如果您对多线程很少或没有经验,我会避免它,因为只有复杂的游戏可能需要这种方法,而多线程会增加您可能不想处理的大量问题。
多线程游戏引擎在渲染和更新之间比单线程游戏消耗更多内存,或者无论如何都会依赖于彼此。这是因为两个线程不能同时操作相同的数据。因此,两个线程操作的唯一方法是在这些数据结构上进行同步,或者通过更新线程为渲染线程提供不可变数据进行渲染。
编写多线程游戏引擎将是对线程的一个很好的介绍。它可以教你很多。取决于你想要摆脱的东西。
如果您正在制作2D游戏,我会更加确信您不需要一个线程进行更新,而另一个线程需要渲染。
如果你真的想追求这个,here's the approach I'd take.
您不需要多个while循环来控制渲染。
答案 1 :(得分: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)"并以此方式解决它) 我希望这至少有一点帮助(两年后,大声笑),并帮助你得到多线程的基础(如果你还没有)。