再次,非常感谢您对我之前的问题的帮助。
我为娱乐和教育而制作的RPG取得了更大的进步。现在,我可以从.txt文件(彩色!)中显示地图了,因此我很高兴一切正常。
我接下来要实现的是碰撞检测系统。例如:如果我的玩家角色尝试踩到'〜'角色,则该程序不会移动玩家角色,因为'〜'是水,无法行走。
我为运动系统和加载地图提供的代码如下:
using System;
using System.IO;
namespace TextFileReaderTest
{
class Program
{
public static int PosX;
public static int PosY;
static void DisplayMap()
{
string line;
//Pass the file path and file name to the StreamReader constructor
StreamReader sr = new StreamReader(@"D:\personal\tests\Tests\ascii map tools\map1.txt");
//Read the first line of text
line = sr.ReadLine();
//Continue to read until you reach end of file
while (line != null)
{
Char[] MapArray = line.ToCharArray();
foreach (Char c in MapArray)
{
if (c == '/')
{
Console.ForegroundColor = ConsoleColor.DarkGreen;
Console.Write('/');
}
else if (c == '^')
{
Console.ForegroundColor = ConsoleColor.DarkGreen;
Console.Write('^');
}
else if (c == '|')
{
Console.ForegroundColor = ConsoleColor.Green;
Console.Write('|');
}
else if (c == '.')
{
Console.ForegroundColor = ConsoleColor.Green;
Console.Write('.');
}
else if (c == 'o')
{
Console.ForegroundColor = ConsoleColor.DarkCyan;
Console.Write('o');
}
else if (c == '~')
{
Console.ForegroundColor = ConsoleColor.DarkCyan;
Console.Write('~');
}
else
{
Console.Write(c);
Console.ForegroundColor = System.ConsoleColor.White;
}
}
//Read the next line
line = sr.ReadLine();
}
//close the file
sr.Close();
}
static void Main(string[] args)
{
Console.WindowWidth = 128;
Console.WindowHeight = 32;
DisplayMap();
Console.SetCursorPosition(10, 10); //the cursor will be set at x = 10 and y = 10
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;
//if (PosX == 11 && PosY == 11 ) //this is a portal
//{
// Console.SetCursorPosition(20, 20); // clear console, teleport player, load new map
//}
}
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;
}
}
}
}
}
许多“ if else”语句是针对地图中的颜色的。请不要介意我的代码中有很多注释。每当有想法时,我通常会在可能实现的地方写评论。另外,它是其他程序员的解释,我认为这很有用。我仍然还是一个初学者,因此,如果您能解释您的解决方案,将不胜感激。
提前谢谢!
答案 0 :(得分:2)
为特定事物提供特定类是一个好习惯。即Map
类用于处理地图,Player
类用于处理播放器,等等。
现在,要处理碰撞,我将有两个Map
,一个用于存储和显示播放器图标等,还有一个用于瓷砖的参考Map
(检查起来会更容易播放器在什么位置上并正在朝此方向移动。
Map
应该有一个private char[][]
字段来存储图块,以便可以快速调用所述图块。
将字符的当前位置存储在Player
类的X
和Y
中的两个字段中,然后将 next 位置存储到另外两个位置中字段NewX
和NewY
。在移动Player
之前,请将当前坐标存储到PrevX
和PrevY
中。
如果玩家不应该移动TileMap[Player.NewX][Player.NewY]
上的图块,请不要更改Player.X
和Player.Y
。否则,将Player.NewX
存储到Player.X
中,将Player.NewY
存储到Player.Y
中。
TL; DR:
Player
类的示例:
public class Player{
public int X, Y;
private int NewX, NewY;
private int PrevX, PrevY;
public Player(){
X = 10;
Y = 10;
NewX = 0;
NewY = 0;
PrevX = 0;
PrevY = 0;
}
//Add other constructors to initialize the coordinates
public void Update(){
//Call this method in `Main()` in a loop. Make sure to add a delay between each call!
PrevX = X;
PrevY = Y;
ConsoleKeyInfo input = Console.ReadKey(true);
switch(input.KeyChar){
case 'w':
NewX = X;
NewY = Y - 1;
break;
case 'a':
NewX = X - 1;
NewY = Y;
break;
case 's':
NewX = X;
NewY = Y + 1;
break;
case 'd':
NewX = X + 1;
NewY = Y;
}
//Add code to restrict the player to the window
if(RPG.ReferenceMap[NewX][NewY] == '~'){ //Water tile
NewX = X;
NewY = Y;
}
//Check for other tiles the player should not walk on
X = NewX;
Y = NewY;
}
}
Map
类的示例:
public class Map{
public char[][] TileMap;
public int Height, Width;
public Map(){
TileMap = new char[16][16]; //Default to a 16x16 map
Height = 16;
Width = 16;
}
public Map(string file){
//Load the map like you did above, but store the chars read into the TileMap array
//Give the 'Height' and 'Width' fields the height and width of the map
}
public void Update(){
//Call this AFTER Player.Update()
//Use the reference map to add the correct tile to the previous position
//and then update the Player's icon
TileMap[Player.PrevX][Player.PrevY] = RPG.ReferenceMap.TileMap[Player.PrevX][Player.PrevY];
TileMap[Player.X][Player.Y] = 'O'; //Assuming that 'O' is your player icon
}
public void Draw(){
//Use the "TileMap" field to refresh the map
Console.Clear(); //Clear the console
foreach(char[] array in TileMap){
foreach(char tile in array){
//Use the logic you used in your "foreach" loop to draw the tiles.
}
}
}
}
在主类中应称为RPG
的示例:
public class RPG{
Player player;
Map ReferenceMap, ActualMap;
public static void Main(){
player = new Player(); //Use the default constructor or another constructor
//to set the starting coords of the player
ActualMap = new Map(); //Load the data into the map
ReferenceMap = ActualMap; //Since they are the same for now, just store
//the data already there
while(true){
//Add a delay using Stopwatch, preferably 1/60th of a second
Update();
}
}
public void Update(){
Player.Update();
ActualMap.Update();
ActualMap.Draw();
}
}
答案 1 :(得分:1)
虽然我认为另一个答案比这个答案更好,并且更接近实际游戏开发,但对于初学者而言可能很难掌握。这样做的目的是为了更简单,并且理论上更少。
代码使用函数和参数以及switch语句,但应更接近OP的级别。代码中的注释应说明其作用。
示例文件:
^^^^^^^^^^^^^^^
|||||||||||||||
~~~
~~~~~
~~~
...............
...............
...............
...............
代码:
using System;
using System.IO;
namespace TextFileReaderTest
{
class Program
{
static char GetTerrainAt(string[] map, int x, int y)
{
return map[y][x];
}
static void PrintCharacter(int x, int y)
{
Console.SetCursorPosition(x, y);
Console.ForegroundColor = ConsoleColor.Magenta;
Console.Write('X');
}
static void PrintTerrainAt(string[] map, int x, int y)
{
char terrain = GetTerrainAt(map, x, y);
switch (terrain)
{
case '/':
Console.ForegroundColor = ConsoleColor.DarkGreen;
break;
case '^':
Console.ForegroundColor = ConsoleColor.DarkGreen;
break;
case '|':
Console.ForegroundColor = ConsoleColor.Green;
break;
case '.':
Console.ForegroundColor = ConsoleColor.Green;
break;
case 'o':
Console.ForegroundColor = ConsoleColor.DarkCyan;
break;
case '~':
Console.ForegroundColor = ConsoleColor.DarkCyan;
break;
default:
Console.ForegroundColor = ConsoleColor.White;
break;
}
Console.SetCursorPosition(x, y);
Console.Write(terrain);
}
static void Main()
{
// initialize (once)
var map = File.ReadAllLines(@"D:\personal\tests\Tests\ascii map tools\map1.txt");
var posX = 10;
var posY = 10;
Console.WindowWidth = map[0].Length; // length of first line, make sure all lines in the file are of same length
Console.WindowHeight = map.Length; // number of lines
Console.CursorVisible = false;
// print whole map once
for (int x = 0; x < Console.WindowWidth; x++)
{
for (int y = 0; y < Console.WindowHeight; y++)
{
PrintTerrainAt(map, x, y);
}
}
// print character starting pos
PrintCharacter(posX, posY);
// start
while (true)
{
var input = Console.ReadKey(true);
// next move for now: stay in the same place
var nextX = posX;
var nextY = posY;
// find out where the next move will take us
switch (input.KeyChar)
{
case 'w':
nextY--;
break;
case 'a':
nextX--;
break;
case 's':
nextY++;
break;
case 'd':
nextX++;
break;
}
// make sure it's a legal move
if (nextY >= Console.WindowHeight || nextY < 0 || nextX >= Console.WindowWidth || nextX < 0)
{
// illegal move, beep and continue the while loop from the top without moving the character
Console.Beep();
continue;
}
char terrainToMoveTo = GetTerrainAt(map, nextX, nextY);
// this should probably be moved into a function "IsTerrainPassable(terrainToMoveTo)"
if (terrainToMoveTo == '~')
{
// illegal move, beep and continue the while loop from the top without moving the character
Console.Beep();
continue;
}
// okay, legal move, move our character:
// clean up old position (if you comment this out, you will see a "snake")
PrintTerrainAt(map, posX, posY);
// move character
posX = nextX;
posY = nextY;
// print character at new position
PrintCharacter(posX, posY);
}
}
}
}