卡在了制作2D游戏移动引擎的过程中

3
我正在为我的俯视2D游戏制作移动引擎,但我在尝试解决以下问题时遇到了困难:
  • 玩家可以使用箭头键移动,这将使您在各自方向上加速。有摩擦力,所以释放键后您会停止移动,但不会立即停止。
  • 当您按住两个垂直的键时,您以45°的方向加速,速度与在一个轴上相同
  • 有一个最大速度,超过这个速度您不能通过步行来加速,这也限制了您的最大步行速度。然而,如果您被撞飞,就可能超过这个速度。
  • 如果您移动得比最大步行速度快,如果您按反方向的键,您可以更快地减速
第一点的伪代码(无摩擦力):
gameTick(){

  tempX += LeftKeyHeld ? -1 : 0;
  tempX += RightKeyHeld ? 1 : 0;
  tempY += UpKeyHeld ? -1 : 0;
  tempY += DownKeyHeld ? 1 : 0;
  ratio = 0.71;

  if( |tempX| == |tempY| ) {
    tempX =tempX* ratio;
    tempY =tempY* ratio;
  }
  player.x += tempX;
  player.y += tempY;
}

我可以解决摩擦问题(获取移动向量的长度,减少它的摩擦力,以相同的x:y比例进行投影),但我无法理解如何实现最大速度。我尝试了一种解决方案,即当玩家超过最大速度时根本不允许行走,但这违反了第4点。而且,它还有一个不好的副作用,当你向左以最大速度移动并开始按下时,移动方向几乎没有改变。然后,我开始思考各种向量之间的差异和其他问题,但我大多数情况下已经无法跟上或遇到早期问题。因此,总之,有人能解释一下如何实现满足以上所有要求的系统,或者指出一篇解释如何实现这样的系统的文章吗?不用担心建议某些复杂的东西,只要给我一些时间,我就能掌握甚至困难的概念。感谢您的帮助!
3个回答

1

很抱歉让你没有多余的时间思考这个问题,但是我已经解决了,并且它不是两行代码的问题。(尽管还是要感谢每个人提供的思路)

因为我懒惰又疲倦,所以我不会将它改成伪代码,除了以下两个方法:

updateGame(){
  player.walk();
  player.move();
}
player.move(){
  player.x += player.speedX
  player.y += player.speedY
}  

代码如下(Java):

public void walk() {
    float tempX = 0;
    float tempY = 0;
    float accelX;
    float accelY;
    float nextSpeedX;
    float nextSpeedY;
    float nextSpeed;
    float speed;
    tempX += walkLeft ? -1 : 0;
    tempX += walkRight ? 1 : 0;
    tempY += walkUp ? -1 : 0;
    tempY += walkDown ? 1 : 0;

    if (Math.abs(tempX) == Math.abs(tempY)) {
        tempX = (float) tempX * rat;
        tempY = (float) tempY * rat;
    }

    accelX = tempX * (float) runSpeed;
    accelY = tempY * (float) runSpeed;
    speed = (float) Math.sqrt(speedX * speedX + speedY * speedY);
    nextSpeedX = speedX + accelX;
    nextSpeedY = speedY + accelY;
    nextSpeed = (float) Math.sqrt(nextSpeedX * nextSpeedX + nextSpeedY * nextSpeedY);

    if (nextSpeed > maxSpeed) { //can't accelerate by running
        if (nextSpeed > speed) {  //wants to accelerate
            if (speed > maxSpeed) {  //the current speed is larger than maximum.
                float diff = (float)(speed / nextSpeed);
                float greenX = nextSpeedX*diff;
                float greenY = nextSpeedY*diff;
                accelX = greenX-speedX;
                accelY = greenY-speedY;
            } else { //speed <= maxspeed
                float diff = (float)(maxSpeed / nextSpeed);
                float greenX = nextSpeedX*diff;
                float greenY = nextSpeedY*diff;
                accelX = greenX-speedX;
                accelY = greenY-speedY;
            }
        } else { //wants to slow! allow it!
            //acceleration doesn't need to be changed
        }
    } else { //no problem, allow it!
        //acceleration doesn't need to be changed
    }
    speedX += accelX;
    speedY += accelY;
}

代码可能可以更短,也可以更优化,但它能够正常工作。我希望这能帮助未来遇到这个问题的人。


0

添加到底部:

 If (|tempX|>maxSpeed)
   tempX=maxSpeed*sign(tempX);

 If (|tempY|>maxSpeed)
   tempY=maxSpeed*sign(tempX);

其中 int sign(x) { if x<0 返回 -1; }


2
@Szoltomi:类似这样的代码 If (|tempX, tempY| > maxSpeed) { tempX = sign(tempX)*maxSpeed*ratio; tempY=sign(tempY)*maxSpeed*ratio; } 应该可以解决这个问题。 - JAB
当(x>=0)时,sign(x)返回什么?另外,存在一些错误:玩家以天文速度被发射出去。我还有其他变量需要整合进去,所以插入代码并不是非常简单:P此外:我的动态世界生成器速度极快。 - Szoltomi
@Szoltomi 可能是1,我猜代码应该是: int sign(x) { return x < 0 ? -1 : 1; } - Gustavo Muenz
@Edison:是的,我只是使用sign(x)来指出需要考虑tempX/tempY的符号。 - JAB
抱歉,我无法实现您的解决方案。您能否解释一下您的思路?另一方面,我制作了一个不同的解决方案,似乎可以工作。我写了一个详细的自我回答,但在发布之前决定进行最后一次测试。结果发现它违反了第三部分的第二部分。啊!拔头发。只能重新开始了... - Szoltomi
显示剩余2条评论

0
我建议除了位置之外,与玩家相关联的是特定的速度,并且仅在按下箭头键时检查该速度是否超过最大速度。
如果速度确实超过了最大速度,但是来自相反方向的箭头键正在被按下,则您将保持当前速度高于最大速度,并简单地应用负加速度。

伪代码被大大简化了,实际上我有一个单独的speedX和Y变量,但是已经将其编辑掉了。然而,根据您的建议,我遇到了我已经写过的问题:如果您向左移动,并开始按住左+下,则不会加速。 - Szoltomi
@Szoltomi:在这种情况下,您应该减缓向左的运动,同时加速向下的运动。这与您的第二个条件非常契合。 - JAB

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接