可移动的 Unity C# 中的网格

huangapple go评论204阅读模式
英文:

Moveable grid in Unity C#

问题

I am working on a moveable grid system for my voxel game, I implemented most of it, but I keep getting stuck at making the actual Move function. This is the code without the Move function implemented:

我正在为我的体素游戏开发一个可移动的网格系统,我已经实现了大部分功能,但是在编写实际的Move函数时遇到了困难。以下是没有实现Move函数的代码:

  1. using UnityEngine;
  2. using System;
  3. public class Grid<T>
  4. {
  5. // ... (其他代码部分未翻译)
  6. }
  7. // ... (其他代码部分未翻译)

This is the code Im using to test it:

这是我用来测试的代码:

  1. using System.Collections;
  2. using System.Collections.Generic;
  3. using UnityEngine;
  4. public class Tester : MonoBehaviour
  5. {
  6. // ... (其他代码部分未翻译)
  7. }

The example shifts the grid in the left.

这个示例将网格向左移动。

First time it logs the matrix correctly:

第一次记录矩阵时正确的输出:

1 5 9 13

2 6 10 14

3 7 11 15

4 8 12 16

However the second time its incorrect.

但是第二次输出是不正确的。

What it prints with the current move function:

使用当前的移动函数时输出的内容:

What it's supposed to print:

它应该输出的内容:

0 1 5 9

0 2 6 10

0 3 7 11

0 4 8 12

What it prints:

实际输出的内容:

2 6 10 14

3 7 11 15

4 8 12 16

0 9 13 0

I've tried this Move function, but its not working, I could not figure out how to get good startPosition and endPosition.

我尝试了这个Move函数,但它不起作用,我无法弄清楚如何获得正确的startPosition和endPosition。

  1. public void Move(Vector3Int position)
  2. {
  3. // ... (其他代码部分未翻译)
  4. }

How it should look like

应该是什么样子

The first grid with position 0, 0, 0 shows how a 2x2 part of it would look like, and the second grid with position -1, 0, 0 shows how a 2x2 part of it should look shifted, and under them are the small 2x2 grids shown. THe one which is 0 6 0 7 is how it should look in code, 0 because the code cannot guess that its supposed to be 2 and 3.

第一个位置为0, 0, 0的网格显示了它的一部分是什么样子,而第二个位置为-1, 0, 0的网格显示了它的一部分应该如何移动,下面是显示的小型2x2网格。0 6 0 7 的网格是代码中应该的样子,0 是因为代码无法猜测它应该是2和3。

英文:

I am working on a moveable grid system for my voxel game, I implemented most of it, but I keep getting stuck at making the actual Move function. This is the code without the Move function implemented:

  1. using UnityEngine;
  2. using System;
  3. public class Grid<T>
  4. {
  5. private T[] data;
  6. public Vector3Int position;
  7. public Vector3Int size;
  8. public int iSize;
  9. public Grid(Vector3Int size)
  10. {
  11. this.position = new Vector3Int(0, 0, 0);
  12. this.size = size;
  13. this.iSize = size.x * size.y * size.z;
  14. this.data = new T[size.x * size.y * size.z];
  15. }
  16. public T this[int x, int y, int z]
  17. {
  18. get
  19. {
  20. Vector3Int position = new Vector3Int(x, y, z);
  21. if (!IsValidIndex(position - this.position))
  22. {
  23. throw new IndexOutOfRangeException("Invalid position");
  24. }
  25. Vector3Int positionRelative = PositionToRelative(position);
  26. return this.data[VectorToIndex(positionRelative)];
  27. }
  28. set
  29. {
  30. Vector3Int position = new Vector3Int(x, y, z);
  31. if (!IsValidIndex(position - this.position))
  32. {
  33. throw new IndexOutOfRangeException("Invalid position");
  34. }
  35. Vector3Int positionRelative = PositionToRelative(position);
  36. this.data[VectorToIndex(positionRelative)] = value;
  37. }
  38. }
  39. public void Move(Vector3Int newPosition)
  40. {
  41. Vector3Int offset = PositionToRelative(newPosition);
  42. T[] newData = new T[data.Length];
  43. this.data = newData;
  44. this.position = newPosition;
  45. }
  46. private bool IsPositionInRange(Vector3Int position, Vector3Int start, Vector3Int end)
  47. {
  48. int minX = Mathf.Min(start.x, end.x);
  49. int maxX = Mathf.Max(start.x, end.x);
  50. int minY = Mathf.Min(start.y, end.y);
  51. int maxY = Mathf.Max(start.y, end.y);
  52. int minZ = Mathf.Min(start.z, end.z);
  53. int maxZ = Mathf.Max(start.z, end.z);
  54. return position.x >= minX
  55. && position.x <= maxX
  56. && position.y >= minY
  57. && position.y <= maxY
  58. && position.z >= minZ
  59. && position.z <= maxZ;
  60. }
  61. private Vector3Int PositionToRelative(Vector3Int position)
  62. {
  63. return position - this.position;
  64. }
  65. private bool IsValidIndex(Vector3Int position)
  66. {
  67. int index = VectorToIndex(position);
  68. return index >= 0 && index < this.iSize;
  69. }
  70. private bool IsValidIndex(int index)
  71. {
  72. return index >= 0 && index < this.iSize;
  73. }
  74. private int VectorToIndex(Vector3Int position)
  75. {
  76. return position.x + this.size.x * (position.y + this.size.y * position.z);
  77. }
  78. }

This is the code Im using to test it:

  1. using System.Collections;
  2. using System.Collections.Generic;
  3. using UnityEngine;
  4. public class Tester : MonoBehaviour
  5. {
  6. void PrintMatrix<T>(Grid<T> grid)
  7. {
  8. for (int x = 0; x < grid.size.x; x++)
  9. {
  10. string output = "\n";
  11. for (int y = 0; y < grid.size.y; y++)
  12. {
  13. Vector3Int position = new Vector3Int(x, y, 0) + grid.position;
  14. output += grid[position.x, position.y, position.z];
  15. if (y < grid.size.y - 1)
  16. {
  17. output += " ";
  18. }
  19. }
  20. Debug.Log(output);
  21. }
  22. }
  23. void Start()
  24. {
  25. Vector3Int size = new Vector3Int(4, 4, 1);
  26. Grid<int> grid = new Grid<int>(size);
  27. for (int x = 0; x < size.x; x++)
  28. {
  29. for (int y = 0; y < size.y; y++)
  30. {
  31. grid[x, y, 0] = x + size.y * y + 1;
  32. }
  33. }
  34. PrintMatrix<int>(grid);
  35. Debug.Log("-------- Amogus ------------");
  36. grid.Move(new Vector3Int(-1, 0, 0));
  37. PrintMatrix<int>(grid);
  38. }
  39. void Update() { }
  40. }

The example shifts the grid in the left.

First time it logs the matrix correctly:

1 5 9 13

2 6 10 14

3 7 11 15

4 8 12 16

However the second time its incorrect.
What it prints with the current move function:

What it's supposed to print:

0 1 5 9

0 2 6 10

0 3 7 11

0 4 8 12

What it prints:

2 6 10 14

3 7 11 15

4 8 12 16

0 9 13 0

I've tried this Move function, but its not working, I could not figure out how to get good startPosition and endPosition.

  1. public void Move(Vector3Int position)
  2. {
  3. T[] newData = new T[data.Length];
  4. Vector3Int positionRelative = PositionToRelative(position);
  5. Vector3Int startPosition = new Vector3Int(
  6. positionRelative.x >= 0 ? positionRelative.x : this.size.x + positionRelative.x,
  7. positionRelative.y >= 0 ? positionRelative.y : this.size.y + positionRelative.y,
  8. positionRelative.z >= 0 ? positionRelative.z : this.size.z + positionRelative.z
  9. );
  10. Vector3Int endPosition = new Vector3Int(
  11. positionRelative.x < 0 ? this.size.x : positionRelative.x,
  12. positionRelative.y < 0 ? this.size.y : positionRelative.y,
  13. positionRelative.z < 0 ? this.size.z : positionRelative.z
  14. );
  15. Debug.Log(positionRelative + " " + startPosition + " " + endPosition);
  16. for (int x = 0; x < size.x; x++)
  17. {
  18. for (int y = 0; y < size.y; y++)
  19. {
  20. for (int z = 0; z < size.z; z++)
  21. {
  22. Vector3Int currentPosition = new Vector3Int(x, y, z);
  23. int index = VectorToIndex(currentPosition);
  24. int translationIndex = VectorToIndex(currentPosition - positionRelative);
  25. if (
  26. IsPositionInRange(currentPosition, startPosition, endPosition)
  27. || !IsValidIndex(translationIndex)
  28. )
  29. {
  30. newData[index] = default(T);
  31. continue;
  32. }
  33. newData[index] = data[translationIndex];
  34. }
  35. }
  36. }
  37. this.position = position;
  38. data = newData;
  39. }

How it should look like

The first grid with position 0, 0, 0 shows how a 2x2 part of it would look like, and the second grid with position -1, 0, 0 shows how a 2x2 part of it should look shifted, and under them are the small 2x2 grids shown. THe one which is 0 6 0 7 is how it should look in code, 0 because the code cannot guess that its supposed to be 2 and 3.

答案1

得分: 0

最大的问题似乎出在你的PrintMatrix函数上。

它以以下方式打印值:

  • 对于每个X,打印一行

    => X 从上到下

  • 在每行中打印4个连续的Y值

    => Y 从左到右

基本上你的打印内容更接近我所期望的,因为它正确地将所有内容向上移动了一步(负X方向)。

可能更好的方式应该是:

  1. public void PrintMatrix(Grid<T> grid)
  2. {
  3. var output = new StringBuilder();
  4. for (var y = 0; y < grid.size.y; y++)
  5. {
  6. for (var x = 0; x < grid.size.x; x++)
  7. {
  8. var value = grid[x, y, 0];
  9. if (value < 10) output.Append(' ');
  10. output.Append(value);
  11. output.Append(' ');
  12. }
  13. output.Append('\n');
  14. }
  15. Debug.Log(output.ToString());
  16. }

这将为每个Y打印一行(=> 从上到下),然后在每行内为X打印(=> 从左到右)。

实际上,我可能会选择对索引进行环绕处理,例如:

  1. private int VectorToIndex(Vector3Int index) => VectorToIndex(index.x, index.y, index.z);
  2. private int VectorToIndex(int x, int y, int z)
  3. {
  4. x = x.WrapAround(size.x);
  5. y = y.WrapAround(size.y);
  6. z = z.WrapAround(size.z);
  7. return x + size.x * (y + size.y * z);
  8. }

使用扩展方法:

  1. public static class IntExtensions
  2. {
  3. public static int WrapAround(this int value, int maxValue)
  4. {
  5. return ((value % maxValue) + maxValue) % maxValue;
  6. }
  7. }

以处理索引在边界处的情况。

首先打印:

  1. 1 2 3 4
  2. 5 6 7 8
  3. 9 10 11 12
  4. 13 14 15 16

在移动后(-1, 0, 0)的打印结果:

  1. 2 3 4 1
  2. 6 7 8 5
  3. 10 11 12 9
  4. 14 15 16 13

=> 所有值向左移动了一个位置(负X方向)

还有一个小提示,你知道你也可以直接使用矢量作为索引器,并进行如下操作:

  1. public T this[Vector3Int index]
  2. {
  3. get
  4. {
  5. var positionRelative = PositionToRelative(position);
  6. return data[VectorToIndex(positionRelative)];
  7. }
  8. set
  9. {
  10. var positionRelative = PositionToRelative(position);
  11. data[VectorToIndex(positionRelative)] = value;
  12. }
  13. }

和/或者甚至为方便起见保留两者:

  1. public T this[int x, int y, int z]
  2. {
  3. get => this[new Vector3Int(x, y, z)];
  4. set => this[new Vector3Int(x, y, z)] = value;
  5. }
英文:

The biggest issue seems to be your PrintMatrix.

It prints the values the following way

  • For each X prints a line

    => X goes top to bottom

  • In each line prints 4 consecutive Y values

    => Y goes left to right

Basically your What it prints is closer to what I would expect as it correctl shifts everything one step upwards (negative X direction)

It should probably rather be e.g.

  1. public void PrintMatrix(Grid&lt;T&gt; grid)
  2. {
  3. var output = new StringBuilder();
  4. for (var y = 0; y &lt; grid.size.y; y++)
  5. {
  6. for (var x = 0; x &lt; grid.size.x; x++)
  7. {
  8. var value = grid[x, y, 0];
  9. if(value &lt; 10) output.Append(&#39; &#39;)
  10. output.Append(value);
  11. output.Append(&#39; &#39;);
  12. }
  13. output.Append(&#39;\n&#39;);
  14. }
  15. Debug.Log(output.ToString());
  16. }

which would print out a line for each Y (=> top to bottom) and then within the line X (=> left to right).


Actually I would probably go for a wrap-around of the indices and have something like e.g.

  1. private int VectorToIndex(Vector3Int index) =&gt; VectorToIndex(index.x, index.y, index.z);
  2. private int VectorToIndex(int x, int y, int z)
  3. {
  4. x = x.WrapAround(size.x);
  5. y = y.WrapAround(size.y);
  6. z = z.WrapAround(size.z);
  7. return x + size.x * (y + size.y * z);
  8. }

with extension method

  1. public static class IntExtensions
  2. {
  3. public static int WrapAround(this int value, int maxValue)
  4. {
  5. return ((value % maxValue) + maxValue) % maxValue;
  6. }
  7. }

for wrapping the index at the borders

=>

first print

  1. 1 2 3 4
  2. 5 6 7 8
  3. 9 10 11 12
  4. 13 14 15 16

print after moving (-1 ,0 ,0)

  1. 2 3 4 1
  2. 6 7 8 5
  3. 10 11 12 9
  4. 14 15 16 13

=> all values shifted one to the left (= negative X direction)


And just a sidenote you know you can also directly use the vector as indexer and do

  1. public T this[Vector3Int index]
  2. {
  3. get
  4. {
  5. var positionRelative = PositionToRelative(position);
  6. return data[VectorToIndex(positionRelative)];
  7. }
  8. set
  9. {
  10. var positionRelative = PositionToRelative(position);
  11. data[VectorToIndex(positionRelative)] = value;
  12. }
  13. }

and/or even keep both for convenience

  1. public T this[int x, int y, int z]
  2. {
  3. get =&gt; this[new Vector3Int(x, y, z)];
  4. set =&gt; this[new Vector3Int(x, y, z)] = value;
  5. }

huangapple
  • 本文由 发表于 2023年7月3日 16:20:57
  • 转载请务必保留本文链接:https://go.coder-hub.com/76603008.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定