unity3d 我应该如何使用Unity 2020.3.14f编写益智游戏的机械设计?

w6lpcovy  于 2022-11-15  发布在  其他
关注(0)|答案(1)|浏览(193)

我正在编写一个益智游戏,你可以在一个3x3的网格Map中水平或垂直滑动瓷砖。
如果您选择了一个区块,当您按向上或向下箭头键时,所选区块所在的列将垂直向上或向下移动1个单位。同样适用于水平移动。
这将导致块超过3x3边界。这就是为什么我有另一个规则:当一个区块超过3x3的边界时,它会被传送到空的位置,填充网格Map。方块的水平顺序可以是(1,2,3)。将这一行方块向左滑动1格后,顺序变成(3,1,2)。再做一次吗?它是(2,3,1)。下面是该级别的屏幕截图:

我认为这是一个非常简单的逻辑编码,但它已经证明我错了。它实际上是相当棘手的。
我最初给每个块分配了一个与键盘完全相同的顺序号,所以左下角的块是1,然后是右下角的2,右下角的3 ......每当我按下键盘上的数字键1并按下向上箭头时,我就硬编码它,并将块的垂直顺序(1,4,7)设置为(7,1,4)。
它根本不起作用,因为如果我不将位置重置回正常位置,并开始改变另一个给定的行或列,Map的布局就会变得混乱。这是因为即使我改变了块的物理位置,它们的分配顺序也不会改变,这意味着如果要移动的块不在正常位置,它们可能会重叠到其他块上。
无论如何,这里是一个设计机制的例子:
一、正常位置:

II.将行(1,2,3)向右滑动1个单位

三、立柱(2、5、8)向下滑动1个单位

有人能给予我一些建议吗?它不一定是在实际的代码。我只是需要一些方向去...我现在没有主意了。

tcomlyy6

tcomlyy61#

正如所指出的,你的图像并不十分准确^^
无论如何,可能会有更有效和可扩展的方法,但这里是我将做的第一次迭代-平原直接前进:

  • 有一个网格组件,它包含一个3x 3网格并处理所有的移位操作

此外,我还将通过此Grid组件来路由所有移动,以便轻松地将磁贴移动到一起(整行或整列)并保持整洁
我希望评论足够清楚

public class Grid : MonoBehaviour
 {
     // To make things simple for the demo I simply have 9 "GridElement" objects and place them later based on their index
     [SerializeField]
     private GridElement[] elements = new GridElement[9];

     // stores the current grid state
     private readonly GridElement[,] _grid = new GridElement[3, 3];

     private void Awake()
     {
         // go through the grid and assign initial elements to their positions and initialize them
         for (var column = 0; column < 3; column++)
         {
             for (var row = 0; row < 3; row++)
             {
                 _grid[column, row] = elements[row * 3 + column];

                 _grid[column, row].Initialize(this);
             }
         }

         RefreshIndices();
     }

     // Shifts the given column one step up with wrap around
     // => top element becomes new bottom
     public void ShiftColumnUp(int column)
     {
         var temp = _grid[column, 2];
         _grid[column, 2] = _grid[column, 1];
         _grid[column, 1] = _grid[column, 0];
         _grid[column, 0] = temp;

         RefreshIndices();
     }

     // Shifts the given column one step down with wrap around
     // => bottom element becomes new top
     public void ShiftColumnDown(int column)
     {
         var temp = _grid[column, 0];
         _grid[column, 0] = _grid[column, 1];
         _grid[column, 1] = _grid[column, 2];
         _grid[column, 2] = temp;

         RefreshIndices();
     }

     // Shifts the given row one step right with wrap around
     // => right element becomes new left
     public void ShiftRowRight(int row)
     {
         var temp = _grid[2, row];
         _grid[2, row] = _grid[1, row];
         _grid[1, row] = _grid[0, row];
         _grid[0, row] = temp;

         RefreshIndices();
     }

     // Shifts the given row one step left with wrap around
     // => left element becomes new right
     public void ShiftRowLeft(int row)
     {
         var temp = _grid[0, row];
         _grid[0, row] = _grid[1, row];
         _grid[1, row] = _grid[2, row];
         _grid[2, row] = temp;

         RefreshIndices();
     }

     // Iterates through all grid elements and updates their current row and column indices
     // and applies according positions
     public void RefreshIndices()
     {
         for (var column = 0; column < 3; column++)
         {
             for (var row = 0; row < 3; row++)
             {
                 _grid[column, row].UpdateIndices(row, column);
                 _grid[column, row].transform.position = new Vector3(column - 1, 0, row - 1);
             }
         }
     }

     // Called while dragging an element
     // Moves the entire row according to given delta (+/- 1)
     public void MoveRow(int targetRow, float delta)
     {
         for (var column = 0; column < 3; column++)
         {
             for (var row = 0; row < 3; row++)
             {
                 _grid[column, row].transform.position = new Vector3(column - 1 + (row == targetRow ? delta : 0), 0, row - 1);
             }
         }
     }

     // Called while dragging an element
     // Moves the entire column according to given delta (+/- 1)
     public void MoveColumn(int targetColumn, float delta)
     {
         for (var column = 0; column < 3; column++)
         {
             for (var row = 0; row < 3; row++)
             {
                 _grid[column, row].transform.position = new Vector3(column - 1, 0, row - 1 + (column == targetColumn ? delta : 0));
             }
         }
     }
 }
  • 然后相应地在每个网格元素上有一个GridElement组件来处理拖动并通过Grid路由移动
public class GridElement : MonoBehaviour, IBeginDragHandler, IEndDragHandler, IDragHandler
 {
     // on indices within the grid so we can forward thm to method calls later
     private int _currentRow;
     private int _currentColumn;

     // a mathematical XZ plane we will use for the dragging input
     // you could as well just use physics raycasts 
     // but for now just wanted to keep it simple
     private static Plane _dragPlane = new Plane(Vector3.up, 1f);

     // reference to the grid to forward invoke methods
     private Grid _grid;

     // the world position where the current draggin was started
     private Vector3 _startDragPoint;

     // camera used to convert screenspace mouse position to ray
     [SerializeField]
     private Camera _camera;

     public void Initialize(Grid grid)
     {
         // assign the camera 
         if(!_camera)_camera = Camera.main;

         // store the grid reference to later forward the input calls
         _grid = grid;
     }

     // plain set the indices to the new values
     public void UpdateIndices(int currentRow, int currentColumn)
     {
         _currentRow = currentRow;
         _currentColumn = currentColumn;
     }

     // called by the EventSystem when starting to drag this object
     public void OnBeginDrag(PointerEventData eventData)
     {
         // get a ray for the current mouse position
         var ray = _camera.ScreenPointToRay(eventData.position);

         // shoot a raycast against the mathemtical XZ plane
         // You could as well use Physics.Raycast and get the exact hit point on the collider etc 
         // but this should be close enough especially in top-down views
         if (_dragPlane.Raycast(ray, out var distance))
         {
             // store the world space position of the cursor hit point
             _startDragPoint = ray.GetPoint(distance);
         }
     }

     // Called by the EventSystem while dragging this object
     public void OnDrag(PointerEventData eventData)
     {
         var ray = _camera.ScreenPointToRay(eventData.position);

         if (_dragPlane.Raycast(ray, out var distance))
         {
             // get the dragged delta against the start position
             var currentDragPoint = ray.GetPoint(distance);
             var delta = currentDragPoint - _startDragPoint;

             // we either only drag vertically or horizontally
             if (Mathf.Abs(delta.x) > Mathf.Abs(delta.z))
             {
                 // clamp the delta between -1 and 1
                 delta.x = Mathf.Clamp(delta.x, -1f, 1f);

                 // and tell the grid to move this entire row
                 _grid.MoveRow(_currentRow, delta.x);
             }
             else
             {
                 delta.z = Mathf.Clamp(delta.z, -1f, 1f);

                 // accordingly tell the grid to move this entire column
                 _grid.MoveColumn(_currentColumn,delta.z);
             }
         }
     }

     // Called by the EventSystem when stop dragging this object
     public void OnEndDrag(PointerEventData eventData)
     {
         var ray = _camera.ScreenPointToRay(eventData.position);

         if (_dragPlane.Raycast(ray, out var distance))
         {
             // as before get the final delta
             var currentDragPoint = ray.GetPoint(distance);
             var delta = currentDragPoint - _startDragPoint;

             // Check against a threashold - if simply went with more then the half of one step
             // and shift the grid into the according direction
             if (delta.x > 0.5f)
             {
                 _grid.ShiftRowRight(_currentRow);
             }else if (delta.x < -0.5f)
             {
                 _grid.ShiftRowLeft(_currentRow);
             }
             else if (delta.z > 0.5f)
             {
                 _grid.ShiftColumnUp(_currentColumn);
             }
             else if(delta.z < -0.5f)
             {
                 _grid.ShiftColumnDown(_currentColumn);
             }
             else
             {
                 // if no direction matched at all just make sure to reset the positions
                 _grid.RefreshIndices();
             }
         }
     }
 }
  • 最后,为了使此设置正常工作,您需要
  • 场景中任意位置的EventSystem组件
  • Camera上的PhysicsRaycaster组件

小演示

相关问题