可移动的 Unity C# 中的网格

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

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)
    {
        // ... (其他代码部分未翻译)
    }

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:

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;
    }

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方向)。

可能更好的方式应该是:

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&lt;T&gt; grid)
{
var output = new StringBuilder();
for (var y = 0; y &lt; grid.size.y; y++)
{
for (var x = 0; x &lt; grid.size.x; x++)
{
var value = grid[x, y, 0];
if(value &lt; 10) output.Append(&#39; &#39;)
output.Append(value);
output.Append(&#39; &#39;);
}
output.Append(&#39;\n&#39;);
}
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) =&gt; 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 =&gt; this[new Vector3Int(x, y, z)];
set =&gt; this[new Vector3Int(x, y, z)] = value;
}

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:

确定