英文:
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函数的代码:
using UnityEngine;
using System;
public class Grid<T>
{
// ... (其他代码部分未翻译)
}
// ... (其他代码部分未翻译)
This is the code Im using to test it:
这是我用来测试的代码:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Tester : MonoBehaviour
{
// ... (其他代码部分未翻译)
}
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。
public void Move(Vector3Int position)
{
// ... (其他代码部分未翻译)
}
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:
using UnityEngine;
using System;
public class Grid<T>
{
private T[] data;
public Vector3Int position;
public Vector3Int size;
public int iSize;
public Grid(Vector3Int size)
{
this.position = new Vector3Int(0, 0, 0);
this.size = size;
this.iSize = size.x * size.y * size.z;
this.data = new T[size.x * size.y * size.z];
}
public T this[int x, int y, int z]
{
get
{
Vector3Int position = new Vector3Int(x, y, z);
if (!IsValidIndex(position - this.position))
{
throw new IndexOutOfRangeException("Invalid position");
}
Vector3Int positionRelative = PositionToRelative(position);
return this.data[VectorToIndex(positionRelative)];
}
set
{
Vector3Int position = new Vector3Int(x, y, z);
if (!IsValidIndex(position - this.position))
{
throw new IndexOutOfRangeException("Invalid position");
}
Vector3Int positionRelative = PositionToRelative(position);
this.data[VectorToIndex(positionRelative)] = value;
}
}
public void Move(Vector3Int newPosition)
{
Vector3Int offset = PositionToRelative(newPosition);
T[] newData = new T[data.Length];
this.data = newData;
this.position = newPosition;
}
private bool IsPositionInRange(Vector3Int position, Vector3Int start, Vector3Int end)
{
int minX = Mathf.Min(start.x, end.x);
int maxX = Mathf.Max(start.x, end.x);
int minY = Mathf.Min(start.y, end.y);
int maxY = Mathf.Max(start.y, end.y);
int minZ = Mathf.Min(start.z, end.z);
int maxZ = Mathf.Max(start.z, end.z);
return position.x >= minX
&& position.x <= maxX
&& position.y >= minY
&& position.y <= maxY
&& position.z >= minZ
&& position.z <= maxZ;
}
private Vector3Int PositionToRelative(Vector3Int position)
{
return position - this.position;
}
private bool IsValidIndex(Vector3Int position)
{
int index = VectorToIndex(position);
return index >= 0 && index < this.iSize;
}
private bool IsValidIndex(int index)
{
return index >= 0 && index < this.iSize;
}
private int VectorToIndex(Vector3Int position)
{
return position.x + this.size.x * (position.y + this.size.y * position.z);
}
}
This is the code Im using to test it:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Tester : MonoBehaviour
{
void PrintMatrix<T>(Grid<T> grid)
{
for (int x = 0; x < grid.size.x; x++)
{
string output = "\n";
for (int y = 0; y < grid.size.y; y++)
{
Vector3Int position = new Vector3Int(x, y, 0) + grid.position;
output += grid[position.x, position.y, position.z];
if (y < grid.size.y - 1)
{
output += " ";
}
}
Debug.Log(output);
}
}
void Start()
{
Vector3Int size = new Vector3Int(4, 4, 1);
Grid<int> grid = new Grid<int>(size);
for (int x = 0; x < size.x; x++)
{
for (int y = 0; y < size.y; y++)
{
grid[x, y, 0] = x + size.y * y + 1;
}
}
PrintMatrix<int>(grid);
Debug.Log("-------- Amogus ------------");
grid.Move(new Vector3Int(-1, 0, 0));
PrintMatrix<int>(grid);
}
void Update() { }
}
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.
public void Move(Vector3Int position)
{
T[] newData = new T[data.Length];
Vector3Int positionRelative = PositionToRelative(position);
Vector3Int startPosition = new Vector3Int(
positionRelative.x >= 0 ? positionRelative.x : this.size.x + positionRelative.x,
positionRelative.y >= 0 ? positionRelative.y : this.size.y + positionRelative.y,
positionRelative.z >= 0 ? positionRelative.z : this.size.z + positionRelative.z
);
Vector3Int endPosition = new Vector3Int(
positionRelative.x < 0 ? this.size.x : positionRelative.x,
positionRelative.y < 0 ? this.size.y : positionRelative.y,
positionRelative.z < 0 ? this.size.z : positionRelative.z
);
Debug.Log(positionRelative + " " + startPosition + " " + endPosition);
for (int x = 0; x < size.x; x++)
{
for (int y = 0; y < size.y; y++)
{
for (int z = 0; z < size.z; z++)
{
Vector3Int currentPosition = new Vector3Int(x, y, z);
int index = VectorToIndex(currentPosition);
int translationIndex = VectorToIndex(currentPosition - positionRelative);
if (
IsPositionInRange(currentPosition, startPosition, endPosition)
|| !IsValidIndex(translationIndex)
)
{
newData[index] = default(T);
continue;
}
newData[index] = data[translationIndex];
}
}
}
this.position = position;
data = newData;
}
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方向)。
可能更好的方式应该是:
public void PrintMatrix(Grid<T> grid)
{
var output = new StringBuilder();
for (var y = 0; y < grid.size.y; y++)
{
for (var x = 0; x < grid.size.x; x++)
{
var value = grid[x, y, 0];
if (value < 10) output.Append(' ');
output.Append(value);
output.Append(' ');
}
output.Append('\n');
}
Debug.Log(output.ToString());
}
这将为每个Y打印一行(=> 从上到下),然后在每行内为X打印(=> 从左到右)。
实际上,我可能会选择对索引进行环绕处理,例如:
private int VectorToIndex(Vector3Int index) => VectorToIndex(index.x, index.y, index.z);
private int VectorToIndex(int x, int y, int z)
{
x = x.WrapAround(size.x);
y = y.WrapAround(size.y);
z = z.WrapAround(size.z);
return x + size.x * (y + size.y * z);
}
使用扩展方法:
public static class IntExtensions
{
public static int WrapAround(this int value, int maxValue)
{
return ((value % maxValue) + maxValue) % maxValue;
}
}
以处理索引在边界处的情况。
首先打印:
1 2 3 4
5 6 7 8
9 10 11 12
13 14 15 16
在移动后(-1, 0, 0)的打印结果:
2 3 4 1
6 7 8 5
10 11 12 9
14 15 16 13
=> 所有值向左移动了一个位置(负X方向)
还有一个小提示,你知道你也可以直接使用矢量作为索引器,并进行如下操作:
public T this[Vector3Int index]
{
get
{
var positionRelative = PositionToRelative(position);
return data[VectorToIndex(positionRelative)];
}
set
{
var positionRelative = PositionToRelative(position);
data[VectorToIndex(positionRelative)] = value;
}
}
和/或者甚至为方便起见保留两者:
public T this[int x, int y, int z]
{
get => this[new Vector3Int(x, y, z)];
set => this[new Vector3Int(x, y, z)] = value;
}
英文:
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.
public void PrintMatrix(Grid<T> grid)
{
var output = new StringBuilder();
for (var y = 0; y < grid.size.y; y++)
{
for (var x = 0; x < grid.size.x; x++)
{
var value = grid[x, y, 0];
if(value < 10) output.Append(' ')
output.Append(value);
output.Append(' ');
}
output.Append('\n');
}
Debug.Log(output.ToString());
}
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.
private int VectorToIndex(Vector3Int index) => VectorToIndex(index.x, index.y, index.z);
private int VectorToIndex(int x, int y, int z)
{
x = x.WrapAround(size.x);
y = y.WrapAround(size.y);
z = z.WrapAround(size.z);
return x + size.x * (y + size.y * z);
}
with extension method
public static class IntExtensions
{
public static int WrapAround(this int value, int maxValue)
{
return ((value % maxValue) + maxValue) % maxValue;
}
}
for wrapping the index at the borders
=>
first print
1 2 3 4
5 6 7 8
9 10 11 12
13 14 15 16
print after moving (-1 ,0 ,0)
2 3 4 1
6 7 8 5
10 11 12 9
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
public T this[Vector3Int index]
{
get
{
var positionRelative = PositionToRelative(position);
return data[VectorToIndex(positionRelative)];
}
set
{
var positionRelative = PositionToRelative(position);
data[VectorToIndex(positionRelative)] = value;
}
}
and/or even keep both for convenience
public T this[int x, int y, int z]
{
get => this[new Vector3Int(x, y, z)];
set => this[new Vector3Int(x, y, z)] = value;
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论