我正在使用eclipse在java中制作一个《吃豆人》克隆版本,有时它会出现延迟,更具体地说,是吃豆人/鬼的移动缓慢,有时它很好。一旦它发生了,而我正在运行它,所以它不是在我添加代码之后,它似乎不是在游戏中的任何特定事件之后。我找不到任何触发器或故意产生延迟
资源管理器显示相同的cpu使用情况(仅约50%)/内存使用情况。此外,在延迟和正常运行期间,FPS似乎一直在200左右。
有人知道这可能是什么吗?
有没有我遗漏的有用的信息?
编辑-我基于一个计时器的运动是坏的吗?我会把运动相关的代码贴在下面,有没有好的方法把整个代码贴在这里?
Timer movement = new Timer(20, new ActionListener()//500 is time in milliseconds between
//calls to actionPerformed as far as I know.
{
public void actionPerformed(ActionEvent arg0)
{
if(movingUp == true)
{
moveUp();
}
else if(movingDown == true)
{
moveDown();
}
else if(movingRight == true)
{
moveRight();
}
else if(movingLeft == true)
{
moveLeft();
}
}
});
public void moveUp()
{
yPos -= 1;
this.rect.y -= 1;
}
public void setDirUp()
{
movingUp = true;
movingDown = false;
movingRight = false;
movingLeft = false;
}
在主类中的public void keyPressed:
if(keyCode == KeyEvent.VK_W)
{
if(pacMan.isUpHittingWall == false)
{
pacMan.setDirUp();
pacMan.isDownHittingWall = false;
pacMan.isRightHittingWall = false;
pacMan.isLeftHittingWall = false;
}
}
谢谢你们的帮助。我现在使用系统时间移动,这似乎已经解决了这个问题,因为我最初只在吃豆人中执行了它,幽灵仍然很慢。现在有一个问题,向右和向下移动比向左或向上移动慢得多,我看到的唯一区别是向右和向下都是加法,向左和向上是减法。我该怎么办呢?更新后的代码如下:
//updated movement code
public void moveUp(long timePassed)
{
yPos -= vy * timePassed;
this.rect.y -= vy * timePassed;
}
public void moveDown(long timePassed)
{
yPos += vy * timePassed;
this.rect.y += vy * timePassed;
}
public void moveRight(long timePassed)
{
xPos += vx * timePassed;
this.rect.x += vx * timePassed;
}
public void moveLeft(long timePassed)
{
xPos -= vx * timePassed;
this.rect.x -= vx * timePassed;
}
//I passed timePassed through a globalInputObject because my input is handled in public //void keyPressed(KeyEvent e) and I didnt know how else to get timePassed in to the //movement method
//Here is the code in gameLoop()
globalInputObject.isPacManMovingUp(timePassed);
globalInputObject.isPacManMovingDown(timePassed);
globalInputObject.isPacManMovingRight(timePassed);
globalInputObject.isPacManMovingLeft(timePassed);
//This is inside the GlobalInputObject
public void isPacManMovingUp(long timePassed)
{
if(pacMan.movingUp == true)
{
pacMan.moveUp(timePassed);
}
}
public void isPacManMovingDown(long timePassed)
{
if(pacMan.movingDown == true)
{
pacMan.moveDown(timePassed);
}
}
public void isPacManMovingRight(long timePassed)
{
if(pacMan.movingRight == true)
{
pacMan.moveRight(timePassed);
}
}
public void isPacManMovingLeft(long timePassed)
{
if(pacMan.movingLeft == true)
{
pacMan.moveLeft(timePassed);
}
}
与其总是在每次计时器运行时移动吃豆人一个固定的距离(看起来是1个像素),你应该:
- 设置定时器尽可能快地运行(例如每毫秒或更少一次)。编辑:如果你设置得太快,游戏可能最终会运行得更慢,你必须尝试。
- 使用系统时钟计算每帧之间经过的时间,并按此比例移动吃豆人。
这样做将意味着如果系统是"滞后的",它只会显示每秒更少的帧数,而不是实际移动更慢。
正如我所担心的那样,您是基于来自计时器的时间块移动的距离。您不应该这样做,因为所有计时器都可能是可变的且不可靠的,特别是对于小时间块。最好基于系统时间的差异进行移动。所以,是的,使用计时器或其他东西来运行你的"游戏循环",但要知道精灵的位置和速度,并根据速度矢量(数学矢量,而不是Java矢量)*系统时间的差异来计算移动距离。这样,如果计时器被垃圾收集延迟,使时间块变大,移动的距离将相应变大,并且看起来更平滑。
你应该考虑创造一个合适的"主循环"或"游戏循环"。看看这篇维基百科文章的游戏结构部分。基本上,这些输入事件是从一个独立的线程中调用的,而不是主线程,它们直接修改游戏对象的几何形状。对于主循环,可以考虑这样做:
loop:
process collision detection
process animation (alters geometry of game objects)
process input (more on this later)
any other game specific logic
render screen
你的流程输入可以是这样的
if (globalInputObject.movingUp==true) {
hero.y -= 10;
}
if (globalInputObject.movingDown==true) {
hero.y += 10;
}
if (globalInputObject.movingLeft==true) {
hero.x -= 10;
}
if (globalInputObject.movingRight==true) {
hero.x += 10;
}
和你的输入处理器看起来像这样:
public void actionPerformed(ActionEvent evt) {
if (evt.button==UP_BUTTON) {
globalInputObject.movingUp=true;
}
if (evt.button==DOWN_BUTTON) {
globalInputObject.movingDown=true;
}
if (evt.button==LEFT_BUTTON) {
globalInputObject.movingLeft=true;
}
if (evt.button==RIGHT_BUTTON) {
globalInputObject.movingRight=true;
}
}
基本上,你在"额外"线程(输入线程)中所做的处理是最小的,因此不会干扰主线程。此外,这种方法的好处是容易支持多个方向同时(即:向上+右=对角线)。
只有超级高端游戏才会拥有不止一个线程(如果它们真的需要的话)。在游戏中处理同步并不利于性能。