为什么我的 java 制作的 pacMan 克隆有时会很慢?

发布于 2024-12-07 00:34:11 字数 3469 浏览 0 评论 0原文

我正在使用 eclipse 在 java 中进行 pacman 克隆,有​​时它看起来很滞后,更具体地说,pacman/ghosts 的移动很慢,有时它很好。一旦它在我运行它时发生,所以它不是在我添加代码之后发生的,而且它似乎也不是在游戏中的任何特定事件之后发生的。我找不到任何触发器或故意产生延迟

资源管理器显示相同的 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;
            }

        }

edit 2 -感谢大家的帮助。我现在使用系统时间进行运动,它似乎已经解决了这个问题,因为我一开始只为 pacman 实现了它,而幽灵仍然很慢。现在存在一个问题,向右和向下移动比向左或向上移动要慢得多。我看到的唯一区别是向右和向下都是加法,向左和向上都是减法。对此我能做什么?

更新后的代码如下。

//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);
        }
    }

I'm working on a pacman clone in java using eclipse and sometimes it appears laggy more specifically the movement of pacman/ghosts is slow, sometimes its fine. Once it has happened while I was running it so it wasn't after I added code and it doesn't seem to be after any specific event in game. I can't find any trigger or produce the lag on purpose

The resource manager shows the same cpu usage(only around 50%)/memory usage . Aswell the FPS seems to be around 200 consistently through lag and during the periods where it is working well.

Does anyone know what this could be?

Is there any information I left out that could be of use?

edit - I am basing movement on a timer is that bad? I will post the movement relevant code below is there a good way of posting the whole code on here?

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;
    }

in the main class in public void keyPressed:

if(keyCode == KeyEvent.VK_W)
        {
            if(pacMan.isUpHittingWall == false)
            {
                pacMan.setDirUp();

                pacMan.isDownHittingWall = false;
                pacMan.isRightHittingWall = false;
                pacMan.isLeftHittingWall = false;
            }

        }

edit 2 -Thanks for the help guys. I have the movement using System time now and it seems to have fixed the issue because I implemented it only for pacman at first and the ghosts were still slow. Now there is an issue where moving right and down are much slower than moving left or up The only difference I see is that right and down are both adding and left and up are subtracting. What can I do about this?

The updated code is below.

//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);
        }
    }

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

余生共白头 2024-12-14 00:34:11

而不是每次计时器运行时都将 pacman 移动恒定距离(看起来为 1 像素)

  1. 您应该:将计时器设置为尽可能快地运行(例如,每毫秒或更短一次), 。 编辑:如果你设置得太快,游戏最终可能会运行得更慢,你必须进行试验。
  2. 使用系统时钟计算每帧之间经过了多少时间 并将 pacman 移动与其成比例的量。

执行上述操作意味着如果系统“滞后”,它只会显示每秒更少的帧,而不是实际上使所有内容移动得更慢。

Rather than always moving the pacman by a constant distance (1 pixel, it appears) each time the timer runs, you should:

  1. Set the timer to run as fast as possible (e.g. once every millisecond or less). Edit: if you set it too fast, the game may end up actually running slower, you'll have to experiment.
  2. Calculate how much time has passed between each frame using the system clock and move the pacman by an amount proportional to that.

Doing the above will mean that if the system is "laggy," it will simply show fewer frames per second, rather than actually moving everything slower.

ぃ弥猫深巷。 2024-12-14 00:34:11

正如我担心的那样,您所移动的距离是基于计时器的时间块。您不应该这样做,因为所有计时器都可能是可变的且不可靠,尤其是对于小时间块。最好根据系统时间的差异进行移动。所以,是的,使用计时器或其他东西来运行你的“游戏循环”,但使用双精度知道精灵的位置和速度,并根据速度向量(数学向量而不是Java向量)*系统时间差来计算移动距离。这样,如果计时器因垃圾收集而延迟,使时间块变大,则移动的距离将相应更大并且看起来更平滑。

As I feared, you're basing the distance moved on the time chunk from the Timer. You shouldn't do this as all timers can be variable and unreliable, especially with small time chunks. Better to base movement on difference in system time. So yes, use a Timer or something to run your "game loop", but know the sprite's position and velocity using doubles, and calculate the distance to move based on velocity vector (math vector not Java Vector) * difference in system time. That way if the timer is delayed by say garbage collection, making the time chunk larger, the distance moved will be correspondingly greater and will look smoother.

扎心 2024-12-14 00:34:11

您应该考虑创建一个适当的“主循环”或“游戏循环”,正如某些人所说的那样。查看这篇维基百科文章的游戏结构部分。基本上,这些输入事件是从与主线程不同的单独线程发生\调用的,并且它们直接修改游戏对象中的几何形状。相反,对于主循环,请考虑这样的事情:

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;
    }

}

基本上,您在“额外”线程(输入线程)中所做的处理是最少的,因此不会干扰你的主线程。此外,此方法的优点是可以轻松同时支持多个方向(即:UP+RIGHT = 对角线)。

只有超高端游戏才会有多个线程(如果他们甚至需要的话)。在游戏中处理同步并不利于性能。

You should look into creating a proper "main loop" or "game loop" as some call it. Take a look at the game structure part of this wikipedia article.. Basically those input events are happening\invoked from a separate thread than the main thread and they are directly modifying geometry of in game objects. Instead consider something like this for a main loop:

loop:
    process collision detection
    process animation (alters geometry of game objects)
    process input (more on this later)
    any other game specific logic
    render screen

your process input could be something like this

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;
}

and your input handler would look something like this:

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;
    }

}

Basically the processing that you're doing in your "extra" threads (input thread) is minimal and therefore doesn't interfere with your main thread. Also, this method has the benefied of easily supporting multiple directions simultaneously (ie: UP+RIGHT = diagonal).

Only super high end games have more than a single thread (if they even need it at all). Dealing with synchronisation in a game is not good for performance.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文