让 Snake 移动更流畅,看起来像 Google Snake 一样

问题描述 投票:0回答:1

尝试制作一款小吃游戏,就像大多数游戏开发人员所做的那样,但我的版本有点复杂,因为我没有为蛇使用单个绿色或黑色盒子,我为蛇头、尾巴、身体和身体使用不同的精灵角落像这样。我的最终目标是做类似 Google Snake 游戏。

我已经完成了一款贪吃蛇游戏的大部分机制:移动、生长、改变移动方向引起的角点。蛇的移动是基于一张抽象的二维网格图。我认为蛇是由一系列snake节点组成的,一条蛇可能是这样的:

头<- body <- corner <- ... <- tail.

这些节点继承关系是:

class BaseNode; // BaseNode just handler the four direcion sprites
class SnakeNode: BaseNode;
class SnakeCorner: SnakeNode;
class SnakeHead: SnakeNode; // Singleton
class SnakeTail: SnakeNode; // Singleton
public class SnakeNode : BaseNode
{
    public SnakeNode prev;
    public SnakeNode next;
    public Vector2Int gridPos; // The pos in the abstract two-dimensional grid map.
    // every snake node have its direction
    protected Vector2Int _direction;

    // SnakeCorner will override this property
    public virtual Vector2Int Direction
    {
        get => _direction;
        set
        {
         // ...
         // some code auto set spriterender.sprite when change the direction
        }
    }
}

我定义了一个函数来将网格位置映射到世界位置,这就是我所做的。

    public Vector2 Grid2WorldPosition(int row, int col){
        var offset = new Vector2(setting.cols, setting.rows) / 2;

        return (new Vector2(col ,row) - offset) * setting.scale;
    }

以及我如何移动蛇:

    private BaseNode[,] gridMap;

    private void MoveSnack(){
        var tail = SnackTail.Instance;
        var newTailPos = tail.prev.gridPos;
        var newTailDir = tail.prev.Direction;

        var head = SnackHead.Instance;
        var oldPos = head.gridPos;
        var newPos = head.gridPos + new Vector2Int(head.Direction.y, head.Direction.x);
        if (CheckOutOfBounds(newPos.x, newPos.y)){
          // some code limit bounds
        }

        if (gridMap[newPos.x, newPos.y] != null){
          // some code handle eat apple or collision.
        }

        GameObject gameObj;
        if (head.Direction != head.next.Direction)
        {
           // some code create SnakeCorner obj
        }
        else
        {
           // some code create common SnakeNode obj
        }
        var body = gameObj.GetComponent<SnackNode>();
        body.Direction = head.Direction;
        body.gridPos = oldPos;

        SnackListHandler.Insert(head, body);

        head.gridPos = newPos;

        // here is what I do to update postion on the abstract map.
        gridMap[newPos.x, newPos.y] = head;
        gridMap[oldPos.x, oldPos.y] = body;
        gridMap[tail.gridPos.x, tail.gridPos.y] = null;
        gridMap[newTailPos.x, newTailPos.y] = tail; 

        tail.Direction = newTailDir;
        tail.gridPos = newTailPos;

        // just update head and tail positon is enough
        var nodes = new SnackNode[]{head, tail};
        foreach (var node in nodes){
            node.transform.position = Grid2WorldPosition(node.gridPos.x, node.gridPos.y);
        }

        if (tail.prev != head)
            SnackListHandler.Remove(tail.prev);
    }

SnakeListHanler 将 Snake Nodes prev、next 关系处理为链表,我认为没有必要将其代码放在这里,也许......

问题是,当我运行 MoveSnack 函数时,头部和尾部位置就像“跳转”到新的世界位置,导致感觉卡住了。我尝试过 lerp 方式,但没有按照我喜欢的方式行事,也许 lerp 能够让我的蛇像 Google Snake 一样移动,但我不知道该怎么做。

欢迎提出任何建议、想法,以重新创建 Google 贪吃蛇游戏。

蛇动

c# unity-game-engine animation move lerp
1个回答
0
投票

它按设计工作,仅此而已。您使用离散网格移动蛇,并且各部分根据该网格改变位置。

你可以做什么来让它更顺利:

  • 分割逻辑位置和视图位置
  • 在代码中保留当前工作的逻辑(使用离散网格)
  • 实现视图移动逻辑,使用 Lerp 将蛇部分移动到目标(逻辑上当前)位置。
  • 确保您只允许在“到达逻辑点”(即您的逻辑标记)上应用输入。
  • 考虑到您的视图移动取决于视图更新,因此您还必须预测蛇在更新过程中改变方向时的情况。
© www.soinside.com 2019 - 2024. All rights reserved.