入门RPG有效的ASCII映射和移动系统

时间:2018-10-11 10:36:08

标签: c# ascii

自您对我的第一期杂志的帮助以来,我在教育和娱乐目的RPG方面取得了长足进步。谢谢大家!

在这篇文章中,我将要求解决我遇到的2个问题:第一个问题如下:

现在运动系统工作正常,我决定开始为游戏绘制地图。创建此地图非常耗时,但是确保我的程序以彩色打印该地图会更糟。

到目前为止,这是我的方法:

Console.ForegroundColor = ConsoleColor.DarkGreen;
Console.Write(@"^/\/\^^^   ^ /\/\ /\^^/\^/\^^^ ^   ^/\/\^/\/\ /\^^/\ ");
Console.ForegroundColor = ConsoleColor.DarkCyan;
Console.Write("ooo~o~o~oo~o~~o~oo~");
Console.ForegroundColor = ConsoleColor.DarkGreen;
Console.Write(@"^^/\^/\^/\^^/\ ^/\^^^^ /\ /\/\ /\  ^^  ^/\^/\/\^/\^ ^^");
Console.Write(@"^^/\^/\/\/\^/\^/\^/\/\^ /\   ^ ^  ^^ /\^/\^^/\^^^^^/\ ");
Console.ForegroundColor = ConsoleColor.DarkCyan;
Console.Write("oo~~~~~oooo~oo~~o~o");
Console.ForegroundColor = ConsoleColor.Green;
Console.Write("....|....|||....|.|.|.|.|..|.....||..|..||.|.|.");
Console.ForegroundColor = ConsoleColor.DarkGreen;
Console.Write(@"^/\/\ ^");

由于我的控制台的宽度为128,所以这段相当大且重复的代码块是只在32行地图中创建两行(我需要创建其中的两行才能创建更大的游戏)。

像这样制作整个地图会非常耗时(令人讨厌)。是否有更好,更有效的方法来为RPG(或任何类型的ASCII游戏)创建地图,像我这样的初学者将能够理解和创建? >

第二个问题是玩家角色。我还没有找到一种方法来使“ @”符号出现在光标上,以及如何在按下按钮时使@与光标一起移动。这是我为运动系统准备的代码:

while (true)
{
    ConsoleKeyInfo input = Console.ReadKey(true);
    PosX = Console.CursorLeft;
    PosY = Console.CursorTop;
    switch (input.KeyChar)
        {

        case 'w':
            if (PosY > 1)
            {
                Console.SetCursorPosition(PosX + 0, PosY - 1);
                PosX = Console.CursorLeft;
                PosY = Console.CursorTop;
            }
                break;

        case 'a':
            if (PosX > 1)
            {
                Console.SetCursorPosition(PosX - 1, PosY + 0);
            }
                break;

        case 's':
            if (PosY < 31 )
            {
                Console.SetCursorPosition(PosX + 0, PosY + 1);
            }
                break;

        case 'd':
            if (PosX < 127)
            {
                Console.SetCursorPosition(PosX + 1, PosY + 0);
            }
                break;
    }
}

如您所见:这是一个循环,不断检查是否按下了按钮,并相应地移动了光标。
我如何确定光标上始终有一个@符号,而又没有摆脱@符号移动时的地图字符?

2 个答案:

答案 0 :(得分:4)

我查看了您之前的问题,以查看用于创建地图的代码,而且我也不是游戏程序员,所以我的方法可能不是最好的方法,但希望我能帮助您学习如果您不愿意阅读全部内容,请稍加注意。

我强烈建议将您的系统更改为以下概述的系统,如果继续使用当前创建地图的方式,则可能会难以正确执行某些操作

因此,您当前显示地图的方式效率很低,您目前无法保存地图及其当前显示。因此,让我们从这里开始。

您可以创建一个二维数组,在地图上存储图块,这样就可以将所有地图图块和玩家位置保存到该数组中,而不是当前的方法中。这将允许您在播放器移动或其他类似操作之后更新控制台以显示地图。

您还可以创建一个MapTile对象,该对象指定图块的字符和颜色。下面,我展示了如何创建地图和地图图块。

    // 32 rows and 128 columns
    public static MapTile[,] map = new MapTile[32, 128];

    // Holds the character to be displayed and the colour to display it in
    public class MapTile
    {
        public char character {get; set;}

        public ConsoleColor colour { get; set; }
    }

现在您已经有了一张由字符和颜色组成的地图。但是,地图上什么都没有,我们还没有放入任何MapTiles,所以让我们创建一个方法来填充它。

    // Fills the map with the tile passed in
    public static void FillMap(MapTile tile)
    {
        // For all rows
        for (int row = 0; row < 32; row++)
        {
            // For all columns
            for (int col = 0; col < 128; col++)
            {

                // Make that position the same as the tile passed in
                map[row, col] = tile;
            }

        }
    }

我们可能已经创建了这些方法,但是我们尚未调用它,所以从您的角度来看,类似这样的东西会很好。

    static void Main(string[] args)
    {
        // Setup our default map tile
        MapTile defaultTile = new MapTile();
        defaultTile.character = 'o';
        defaultTile.colour = ConsoleColor.Green;

        // Fill our map with the default tile
        FillMap(defaultTile);

        ...
    }

因此,现在我们有了一个带有默认图块的地图,但是没有简单的方法向用户显示该地图。因此,让我们找到一种方法。

    // Displays the map to the player
    public static void DisplayMap()
    {
        // Clear the console so we can redisplay the map
        Console.Clear();
        // For all rows
        for (int row = 0; row < 32; row++)
        {
            // For all columns
            for (int col = 0; col < 128; col++)
            {
                // Get the right colour
                Console.ForegroundColor = map[row, col].colour;
                // Write the character
                Console.Write(map[row, col].character);
            }
            Console.WriteLine();
        }
    }

现在,每次调用“ DisplayMap()”方法时,都可以在发生任何事情(例如敌人移动或发生其他事情)时重新绘制地图。

这将使我们现在轻松移动玩家。更改后,这是完整的main方法:

    static void Main(string[] args)
    {

        // Setup our default map tile
        MapTile defaultTile = new MapTile();
        defaultTile.character = 'o';
        defaultTile.colour = ConsoleColor.Green;

        // Fill our map with the default tile
        FillMap(defaultTile);

        // Display our map to the user
        DisplayMap();

        // Create a player tile that shows the player on the map
        MapTile playerTile = new MapTile();
        playerTile.colour = ConsoleColor.Red;
        playerTile.character = 'P';

        // Create a Player location, instead of using mouse
        // May require using 'System.Drawing;' at the top as Point is from System.Drawing
        Point playerLocation = new Point(5, 5);

        while (true)
        {
            // Get user input
            ConsoleKeyInfo input = Console.ReadKey(true);

            // Update the current player position to the default tile
            map[playerLocation.Y, playerLocation.X] = defaultTile;
            switch (input.KeyChar)
            {
                case 'w':
                    playerLocation = new Point(playerLocation.X + 0, playerLocation.Y - 1);
                    // Change the players new position to the player tile
                    map[playerLocation.Y, playerLocation.X] = playerTile;
                    break;
                case 'a':
                    playerLocation = new Point(playerLocation.X - 1, playerLocation.Y + 0);
                    // Change the players new position to the player tile
                    map[playerLocation.Y, playerLocation.X] = playerTile;
                    break;
                case 's':
                    playerLocation = new Point(playerLocation.X + 0, playerLocation.Y + 1);
                    // Change the players new position to the player tile
                    map[playerLocation.Y, playerLocation.X] = playerTile;
                    break;
                case 'd':
                    playerLocation = new Point(playerLocation.X + 1, playerLocation.Y + 0);
                    // Change the players new position to the player tile
                    map[playerLocation.Y, playerLocation.X] = playerTile;
                    break;
            }

            DisplayMap();
        }
    }

现在这应该允许您的玩家移动,并且您已经成功创建了可以更新的地图(虽然速度很慢,但是我们只是初学者),我感到特别慷慨,所以我给您提供另一种方法< / p>

    // Create rectangle on the map with the maptile
    public static void CreateRectangle(Point startPoint, int width, int height, MapTile tile)
    {
        // Starting from the point we specified, create a rectangle of the given map tile
        for (int row = startPoint.X; row < startPoint.X + width; row++)
        {
            // For all columns
            for (int col = startPoint.Y; col < startPoint.Y + height; col++)
            {
                // Make that position the same as the tile passed in
                map[row, col] = tile;
            }
        }
    }

这使您可以在地图上创建其他内容,例如河流,小路,建筑物等。

例如,将其放在我们的“ FillMap()”方法之后将在玩家开始的地方创建一个湖泊。

        // Set up our water tile
        MapTile waterTile = new MapTile();
        waterTile.character = '~';
        waterTile.colour = ConsoleColor.Blue;

        // Create a little lake
        CreateRectangle(new Point(10, 10), 4, 3, waterTile);

这里有很多内容可能对您来说并不新鲜,尤其是第一部分。我所做的基本上是创建一个数组,该数组在某种程度上类似于数据库表,并且它将容纳某些对象。我还创建了一个名为MapTile的新对象,您可以执行任何操作,因此可以创建诸如播放器之类的东西,其中包括名称,年龄,发色等,这是制作过程中很大的一部分游戏。 显然,如果您知道这些知识,那么我所做的就是侮辱您的智力,但是否则,我希望您已经学到了一些知识。

此外,对不起,这在任何情况下都不是完美的,控制台需要一段时间来更新其当前状态。缩小地图是一种解决办法,但不是一个很好的解决办法,您必须进行一些研究以快速向用户显示内容,但是如果您不介意稍等片刻,则可以将其保留。 >

答案 1 :(得分:3)

首先,我不是游戏程序员,所以我的解决方案可能不是最佳解决方案。阅读我的评论以获取解释。

using System;

namespace ConsoleApp1RPG
{
    class Program
    {
        private static int PosX;
        private static int PosY;
        private static char LastCharMap; // used to store the last background and needed when we redraw the map when the @ moved

        private static char[][] Map = new[] // map object, might store it in a text file
        {
            new [] { '^', '/', '\\', '/', '\\', '^', '^', '^', ' ', ' ', ' ', '^', ' ', '/', '\\', '/', '\\', ' ', '/', '\\', '^', '^', '/', '\\', '^', '/', '\\', '^', '^', '^', ' ', '^', ' ', ' ', ' ', '^', '/', '\\', '/', '\\', '^', '/', '\\', '/', '\\', ' ', '/', '\\', '^', '^', '/', '\\', ' ' },
            new [] { 'o', 'o', 'o', '~', 'o', '~', 'o', '~', 'o', 'o', '~', 'o', '~', '~', 'o', '~', 'o', 'o', '~' },
            new [] { '^', '^', '/', '\\', '^', '/', '\\', '^', '/', '\\', '^', '^', '/', '\\', ' ', '^', '/', '\\', '^', '^', '^', '^', ' ', '/', '\\', ' ', '/', '\\', '/', '\\', ' ', '/', '\\', ' ', ' ', '^', '^', ' ', ' ', '^', '/', '\\', '^', '/', '\\', ' ', '/', '\\', '^', '/', '\\', '^', ' ', '^', '^' },
            new [] { '^', '^', '/', '\\', '^', '/', '\\', '/', '\\', '/', '\\', '^', '/', '\\', '^', '/', '\\', '^', '/', '\\', '/', '\\', '^', ' ', '/', '\\', ' ', ' ', ' ', '^', ' ', '^', ' ', ' ', '^', '^', ' ', '/', '\\', '^', '/', '\\', '^', '^', '/', '\\', '^', '^', '^', '^', '^', '/', '\\', ' ' },
            new [] { 'o', 'o', '~', '~', '~', '~', '~', 'o', 'o', 'o', 'o', '~', 'o', 'o', '~', '~', 'o', '~', 'o' },
            new [] { ' ', '.', '.', '.', '.', '|', '.', '.', '.', '.', '|', '|', '|', '.', '.', '.', '.', '|', '.', '|', '.', '|', '.', '|', '.', '|', '.', '.', '|', '.', '.', '.', '.', '.', '|', '|', '.', '.', '|', '.', '.', '|', '|', '.', '|', '.', '|', '.' },
            new [] { '^', '/', '\\', '/', '\\', ' ', '^' }
        };

        static void Main(string[] args)
        {
            drawMap(); // draw the map
            runGame(); // game loop, press Escape to stop playing
            Console.Write("Press any key...");
            Console.ReadKey(true);
        }

        // this method draw the @ char and store the background it's entering in
        static void drawChar()
        {
            Console.SetCursorPosition(PosX, PosY); // move cursor position to new position
            if ((PosY < Map.Length) && (PosX < Map[PosY].Length)) // check map object if a background exist
                LastCharMap = Map[PosY][PosX]; // store it
            else
                LastCharMap = ' '; // background is not defined in map, use a space
            Console.Write("@"); // draw the @ character
            Console.SetCursorPosition(PosX, PosY); // move cursor position back because printing @ move it
        }

        static void runGame()
        {
            PosX = 0; // starting point
            PosY = 0; // starting point
            drawChar(); // draw @ char

            ConsoleKey key = ConsoleKey.Enter; // initial value
            do
            {
                if (Console.KeyAvailable) // if some key is pressed
                {
                    key = Console.ReadKey(true).Key; // get that key pressed
                    Console.Write(LastCharMap); // draw last background because @ will move to another location
                    switch (key) // modify the new location of @
                    {
                        case ConsoleKey.W: // press W
                            if (PosY > 0)
                                PosY--;
                            break;
                        case ConsoleKey.S: // press S
                            if (PosY < Console.WindowHeight - 1) // better use this because screen height might be different
                                PosY++;
                            break;
                        case ConsoleKey.A: // press A
                            if (PosX > 0)
                                PosX--;
                            break;
                        case ConsoleKey.D: // press X
                            if (PosX < Console.WindowWidth - 1) // better use this because screen width might be different
                                PosX++;
                            break;
                    }
                    drawChar(); // draw @ char
                }
            } while (key != ConsoleKey.Escape); // stop game loop if Escape is pressed
        }

        // this method draws the map
        static void drawMap()
        {
            Console.SetCursorPosition(0, 0); // start from top left corner
            foreach (var arr in Map)
            {
                foreach (var c in arr)
                    Console.Write(c); // draw background
                Console.WriteLine(); // move to new line
            }
        }
    }
}