【问题标题】:Move Object around a platform of tiles in Unity在 Unity 中围绕瓷砖平台移动对象
【发布时间】:2020-05-16 23:38:21
【问题描述】:

我想制作一个旋转的尖刺,在一个由瓷砖制成的平台上移动,如下面的

我已经写了所有可能的状态,说明当平台图块挡住尖峰时应该移动到哪里。它看起来像这样

     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 语句中写下所有可能性吗?我可以通过寻路实现这一目标吗?

【问题讨论】:

    标签: unity3d path-finding tile


    【解决方案1】:

    这个怎么样

    1. 使用光线投射

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

    【讨论】:

      【解决方案2】:

      你可以创建一个点数组来移动。

      public Vector3[] movePoints;
      

      你可以在inspector或者代码(比如Start函数)用户选择中设置movePoints

      在更新循环中按顺序移动到下一个点,当到达时拉下一个点,除非我们在数组的末尾然后拉出数组中的第一个点,冲洗并永远重复。

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

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

      【讨论】:

      • 这样做的目的是为了节省资源吗?这样它只会在开始时计算一次,而不是在每次更新调用中不断计算。
      • 它应该节省一点,因为它没有做太多的 if 检查,但它使您的代码更具可读性和可扩展性
      【解决方案3】:

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

      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 位置,但它不起作用。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-10-28
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-11-19
        • 1970-01-01
        相关资源
        最近更新 更多