在 Unity 中围绕瓷砖平台移动对象

Move Object around a platform of tiles in Unity

我想制作一个旋转的尖刺,以便在由瓷砖制成的平台周围移动,如下所示

我已经写下了当平台砖挡住钉子的方式时移动到哪里的所有可能状态。它看起来像这样

     for (int i = 0; i < platformTileMap.Length; i++)
     {
         if (platformTileMap[i].HasTile(cellPosition + new Vector3Int(0, -1, 0))) // BOTTOM
         {
             moveX = moveDir;
         }
         else if (platformTileMap[i].HasTile(cellPosition + new Vector3Int(0, 1, 0))) // TOP
         {
             moveX = -moveDir;
         }
         else if (platformTileMap[i].HasTile(cellPosition + new Vector3Int(-1, -1, 0))) //BOT LEFT
         {
             if (moveDir == 1)
             {
                 moveY = -1;
             }
             else moveX = moveDir;
         }
         else if (platformTileMap[i].HasTile(cellPosition + new Vector3Int(1, 1, 0))) //TOP RIGHT
         {
             if (moveDir == 1)
             {
                 moveY = 1;
             }
             else moveX = -moveDir;
         }
         else if (platformTileMap[i].HasTile(cellPosition + new Vector3Int(1, -1, 0))) // BOT RIGHT
         {
             if (moveDir == 1)
             {
                 moveX = moveDir;
             }
             else
             {
                 moveY = -1;
             }
         }
         else if (platformTileMap[i].HasTile(cellPosition + new Vector3Int(-1, 1, 0))) // TOP LEFT
         {
             if (moveDir == -1)
             {
                 moveY = 1;
             }
             else
             {
                 moveX = -moveDir;
             }
         }

我觉得必须有更有效的方法来解决这个问题。我真的必须在 if 语句中写出所有可能性吗?我可以通过寻路实现吗?

这个怎么样

  1. 使用光线投射

  1. 放置空游戏对象并在它到达时旋转尖刺

您可以创建一个要移动到的点数组。

public Vector3[] movePoints;

您可以在检查器或代码(例如 Start 函数)用户选择中设置 movePoints

在update loop lerp to the next point in sequence, pull the next point, unless we are at the end of the array then pull the first point in the array, rinse and repeat forever.

https://docs.unity3d.com/ScriptReference/Vector3.Lerp.html

正确设置一次,当你制作更多的刀片和不同的配置或想要改变速度时,它将是 ez pz。

任何感兴趣的人。这是我解决它的方法:

GridLayout platformGridLayout;
Grid platformGrid;
Tilemap[] platformTileMap;


[SerializeField] float rotationSpeed;
[SerializeField] float moveSpeed;
[SerializeField] private LayerMask platformLayerMask;

Vector3Int startPos;
Vector3Int currentCellPosition;

Vector3 raycastPlatformDir;
Vector3 raycastMoveDir;

float platformRaycastDist;

// Start is called before the first frame update
void Start()
{
    movePoints = new List<Vector3Int>();
    platformGridLayout = transform.parent.GetComponentInParent<GridLayout>();
    platformGrid = transform.parent.GetComponentInParent<Grid>();

    startPos = platformGridLayout.WorldToCell(transform.position);
    Debug.Log("Cell Startposition: " + startPos);

    PlatformToMoveOn();

    GetStartRaycastDir();

    platformRaycastDist = platformGridLayout.cellSize.x;
    Debug.Log("CellCenterToWorld of Startposition: " + platformGrid.GetCellCenterWorld(startPos));
    Debug.Log(platformGrid.GetCellCenterLocal(currentCellPosition + Vector3Int.FloorToInt(raycastPlatformDir) + Vector3Int.FloorToInt(raycastMoveDir)));
}

private void PlatformToMoveOn()
{
    platformTileMap = new Tilemap[2];
    platformTileMap[0] = GameObject.Find("Platform").GetComponent<Tilemap>();
    platformTileMap[1] = GameObject.Find("MovingPlatform").GetComponent<Tilemap>();
}

private void GetStartRaycastDir()
{
    for (int i = 0; i < platformTileMap.Length; i++)
    {
        if (platformTileMap[i].HasTile(startPos + new Vector3Int(0, -1, 0))) // BOTTOM
        {
            raycastPlatformDir = Vector3.down;
        }
        else if (platformTileMap[i].HasTile(startPos + new Vector3Int(0, 1, 0))) // TOP
        {
            raycastPlatformDir = Vector3.up;
        }
        else if (platformTileMap[i].HasTile(startPos + new Vector3Int(1, 0, 0))) // RIGHT
        {
            raycastPlatformDir = Vector3.right;
        }
        else if (platformTileMap[i].HasTile(startPos + new Vector3Int(-1, 0, 0))) // LEFT
        {
            raycastPlatformDir = Vector3.left;
        }
    }
    raycastMoveDir = Quaternion.Euler(0, 0, 90) * raycastPlatformDir * Mathf.Sign(moveSpeed);
    //raycastMoveDir = new Vector3(raycastPlatformDir.y, raycastPlatformDir.x) * Mathf.Sign(moveSpeed);
}

// Update is called once per frame
void Update()
{
    MoveSpike();
}

private void MoveSpike() 
{

    currentCellPosition = platformGridLayout.WorldToCell(transform.position); // + raycastPlatformDir * platformGridLayout.cellSize.y / 2;
    // Debug.Log(cellPosition);
    //Debug.Log(raycastMoveDir);
    transform.Rotate(0, 0, 300 * rotationSpeed * Time.deltaTime);

    RaycastHit2D raycastMove = Physics2D.Raycast(platformGrid.GetCellCenterLocal(currentCellPosition),raycastMoveDir,0.01f,platformLayerMask);
    RaycastHit2D raycastPlatform = Physics2D.Raycast(platformGrid.GetCellCenterLocal(currentCellPosition), raycastPlatformDir, platformRaycastDist, platformLayerMask);

    Debug.DrawRay(transform.position, raycastMoveDir * 0.01f, Color.red);
    Debug.DrawRay(transform.position, raycastPlatformDir * platformRaycastDist, Color.green);



    if (currentCellPosition != startPos) { // Check on Platform corners
        Debug.Log("Checking");
        if (raycastMove.collider != null)
        {
            // reassign raycastsdirections            
            RotateRaycastDirections(1);
            Debug.Log("Spike Collision");
        }
        else if (raycastPlatform.collider == null)
        {
            RotateRaycastDirections(-1);
            Debug.Log("Spike on Platform");
        }

        startPos = currentCellPosition;
    }
        /*transform.position = Vector3.MoveTowards(transform.position,
        platformGrid.GetCellCenterLocal(currentCellPosition + Vector3Int.FloorToInt(raycastPlatformDir) + Vector3Int.FloorToInt(raycastMoveDir)), moveSpeed * Time.deltaTime); */

    transform.Translate(raycastMoveDir.x * Mathf.Abs(moveSpeed) * Time.deltaTime, raycastMoveDir.y * Mathf.Abs(moveSpeed) * Time.deltaTime, 0, Space.World);
}
private void RotateRaycastDirections(int angle)
{
    raycastPlatformDir = Quaternion.Euler(0, 0, 90) * raycastPlatformDir * angle * Mathf.Sign(moveSpeed);
    raycastMoveDir = Quaternion.Euler(0, 0, 90) * raycastMoveDir * angle * Mathf.Sign(moveSpeed);



    // raycastPlatformDir = new Vector3(raycastPlatformDir.y, raycastPlatformDir.x) * angle;
    //raycastMoveDir = new Vector3(raycastMoveDir.y, raycastMoveDir.x) * -angle;
}

编辑:

但这不适用于移动平台。我有什么办法可以解决这个问题吗?我尝试将光线投射位置更改为 tilemapscentercell 位置,但它不起作用。