C#关于roguelike引擎的简单瓷砖地图的问题

时间:2017-04-24 14:26:00

标签: c# console tile

好吧,首先,这是我在这里的第一篇文章,通常我可以过去并简单地搜索答案,但是,因为这有点具体,我无法找到答案之一。

我在某种程度上是编码的初学者(我基本上了解基础知识并观看了很多视频并阅读了很多关于C#的教程)并且正在尝试编写ASCII控制台"游戏" 。一段时间一切都很顺利,但现在我已经陷入了映射部分。起初,我以为我会手动输入墙壁的所有坐标。但是我在这里发现了一篇文章,解释说更多以对象为导向的方法就是创建一个像这样的Tile类。

public class Tile
{
    public int X { get; set; }
    public int Y { get; set; }
    public bool IsWall { get; set; }
}

然后通过执行此操作填充列表

private static void PopulateTiles()
    {
        for (int x = 1; x < 159; x++)
            for (int y = 3; y < 45; y++)
                Tiles.Add(new Tile { X = x, Y = y });
    }

奇数启动x和y值的原因是因为我将tile限制为控制台的某个部分,其余部分用于GUI。

在任何情况下,除非有更好的方法(并且必须有一个,我只是不知道它可能是什么),我试图只检索该列表的一部分来改变ISWALL属性将其设置为TRUE然后使用此

    static void DrawObstacles()
    {
        foreach (Tile tile in World.Tiles)
        {
            if (tile.IsWall)
            {
                Console.SetCursorPosition(tile.X, tile.Y);
                Console.Write("#");
            }
        }
    }

到目前为止,我尝试了几种不同的解决方案,但很明显,我遇到了每个问题的问题(如果可能的话,我也试图避免减慢程序的速度,并且避免使用另外1000次迭代的循环)。

    //Tried this
    private static void SetWalls()
    {
        int[] walls = new int[] { };
        walls += Tiles.GetRange(0, 7); //Fails because I cannot use tiles in an int[]... of course
    }

    //This
    List<Tile> walls = new List<Tile>();
    List<Tile> walls = Tiles.GetRange(0, 7);
    List<Tile> walls = Tiles.GetRange(19, 7; //Doesn't work either but I've no idea why here

    //And finally
    List<Tile> walls = new List<Tile>();
    walls.Add(Tiles[Tiles.GetRange(0, 7)]); //Gives me an error saying that System.Collections.Generic.List<Engine.Tile> cannot be converted to int

所以现在,我有点迷失,因为我真的更喜欢迭代列表,而不是在2D数组中手动​​输入每个坐标......然后迭代到#34 ;建立&#34;墙壁。

我的问题是:是否可以只检索列表的某些部分(如索引0 - 7,19 - 26,29,31,35 - 46),然后遍历主要的切片列表以使用这个新的&#34;索引列表&#34;在那些索引处更改tile的ISWALL属性......如果这是有道理的。

提前致谢,请随时告诉我,如果我在帖子中犯了一些错误。

1 个答案:

答案 0 :(得分:0)

有很多不必要的信息,所以这个问题很难理解。但是,看起来你不想遍历每个游戏对象来简单地找到一些。这是你在游戏中遇到的一个问题,主要是碰撞。我假设您正在控制台上构建此游戏,因此任何游戏引擎功能都可能无法使用。

所以,我建议您根据其重要性或功能将对象分解为列表。这样做,您只需要在启动时循环遍历每个游戏对象,然后在运行时避免耗尽处理。

例如,您可以像这样初始化所有内容:

    List<GameObject> GameObjects { get; set; }
    List<GameObject> Walls { get; set; }
    List<GameObject> Items { get; set; }

    public Map()
    {
        PopulateTiles();
        StructureCollections();
    }

    //Small processing loop
    private void DrawObstacles()
    {
        foreach(var wall in Walls)
        {
            Console.SetCursorPosition(tile.X, tile.Y);
            Console.Write("#");
        }
    }

    //Called only on startup
    private  void PopulateTiles()
    {
        for (int x = 1; x < 159; x++)
            for (int y = 3; y < 45; y++)
                GameObjects.Add(new GameObject() { X = x, Y = y });
    }

    //Called only on starup
    private void StructureCollections()
    {
        foreach(GameObject gameObj in GameObjects)
        {
            if (gameObj.IsWall)
                Walls.Add(gameObj);

            if (gameObj.IsItem)
                Items.Add(gameObj);
        }
    }

这不是一个完美的解决方案,而且所有这些都取决于您计划如何运行游戏。但我认为这是一个好主意。

更新:如果你想找到一种更好的方法来协调游戏对象的创建,而不是手动完成它们,你可以将对象分成更多的类。例如:

public class GameObject
{
    public int X { get; set; }
    public int Y { get; set; }
    public bool IsWall { get; set; }

    public GameObject(int x, int y)
    {
        X = x;
        Y = y;
    }

}

public class Wall : GameObject
{
    public Wall(int x, int y) : base(x,y)
    {
        IsWall = true;
    }
}

现在在这种情况下,您只需要调用一个新的new Wall(x, y);,它将处理作为墙操作所需的一切,而不需要更多参数。

更新:由于这被接受作为答案,我觉得有必要指出这个答案是针对一个小而具体的问题。如果你将要有许多需要自己的类的对象,这不是最好的方法(其中“Wall”是它自己的类)。如果我们要有更多的对象,这种设计可能会导致类爆炸。