我正在为空间入侵者克隆学习目的。当入侵者被枪杀时,我坚持这个问题。我不确定当子弹与入侵者的一部分(谁是位置列表)发生碰撞时如何擦除它并继续游戏。有没有人有想法?
这是代码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace SpaceInvader
{
class Program
{
static void Main()
{
Settings.ScreenSettings();
ArmyOfInvaders.InitializeArmyOfInvaders();
Player.InitializePlayer();
int stepCount = 0;
int armyOfInvadersSpeed = 50;
while (true)
{
stepCount++;
if (stepCount % armyOfInvadersSpeed == 0)
{
Draw.EraseItem(ArmyOfInvaders.armyOfInvaders);
Invader.invader.Clear();
ArmyOfInvaders.armyOfInvaders.Clear();
ArmyOfInvaders.InitializeArmyOfInvaders(Movement.moveY, Movement.moveX);
Movement.MovementArmyOfInvaders();
stepCount = 0;
}
Console.CursorVisible = false;
Draw.DrawItem(ArmyOfInvaders.armyOfInvaders);
Draw.EraseItem(Player.player);
Shoot.GenerateShot();
Movement.MovementPlayer();
Draw.DrawItem(Player.player);
Draw.DrawShoot();
Draw.EraseShoot();
//Collision.InvaderGotShot();
Thread.Sleep(Common.gameSpeed);
}
}
}
public class Settings
{
static public int maxRows = 50;
static public int maxCols = 180;
public static void ScreenSettings()
{
Console.CursorVisible = false;
Console.BufferHeight = Console.WindowHeight = maxRows;
Console.BufferWidth = Console.WindowWidth = maxCols;
}
}
public struct Position
{
public int Row { get; set; }
public int Col { get; set; }
public char Symbol { get; set; }
public Position(int row, int col, char symbol)
{
this.Row = row;
this.Col = col;
this.Symbol = symbol;
}
}
public class Player
{
public static List<Position> player = new List<Position>();
public static int playerWide = 9;
public static int playerLong = player.Count;
public static List<Position> InitializePlayer(int row = 0, int col = 0)
{
int startrow = Settings.maxRows - 5 - playerLong;//start position row
int startcol = (Settings.maxCols / 2) - (playerWide / 2);// start position col
player.Add(new Position(startrow + row, startcol + col, 'A'));
player.Add(new Position(startrow + 1 + row, startcol + col, 'o'));
player.Add(new Position(startrow + 2 + row, startcol - 2 + col, '|'));
player.Add(new Position(startrow + 2 + row, startcol + col, 'o'));
player.Add(new Position(startrow + 2 + row, startcol + 2 + col, '|'));
player.Add(new Position(startrow + 3 + row, startcol - 4 + col, '/'));
player.Add(new Position(startrow + 3 + row, startcol - 3 + col, '\\'));
player.Add(new Position(startrow + 3 + row, startcol - 2 + col, '\\'));
player.Add(new Position(startrow + 3 + row, startcol - 1 + col, '\\'));
player.Add(new Position(startrow + 3 + row, startcol + col, 'o'));
player.Add(new Position(startrow + 3 + row, startcol + 1 + col, '/'));
player.Add(new Position(startrow + 3 + row, startcol + 2 + col, '/'));
player.Add(new Position(startrow + 3 + row, startcol + 3 + col, '/'));
player.Add(new Position(startrow + 3 + row, startcol + 4 + col, '\\'));
player.Add(new Position(startrow + 4 + row, startcol - 2 + col, '<'));
player.Add(new Position(startrow + 4 + row, startcol - 1 + col, '/'));
player.Add(new Position(startrow + 4 + row, startcol - 0 + col, 'o'));
player.Add(new Position(startrow + 4 + row, startcol + 1 + col, '\\'));
player.Add(new Position(startrow + 4 + row, startcol + 2 + col, '>'));
return player;
}
}
public class Movement
{
public static bool isRight = true;
public static int moveX = 0;
public static int moveY = 0;
public static int left = -1;
public static int right = 1;
public static int armyOfInvaderJump = 5;
public static void MovementArmyOfInvaders()
{
if (isRight)
{
moveX += armyOfInvaderJump;
if (ArmyOfInvaders.armyOfInvaders[ArmyOfInvaders.armyOfInvaders.Count - 1][Invader.invader.Count - 1].Col >= Settings.maxCols - 20)
{
isRight = false;
moveY += 2;
}
}
else
{
moveX -= armyOfInvaderJump;
if (ArmyOfInvaders.armyOfInvaders[0][0].Col <= 20)
{
isRight = true;
moveY += 2;
}
}
}
public static void MovementPlayer()
{
while (Console.KeyAvailable)
{
ConsoleKeyInfo key = Console.ReadKey(true);
while (Console.KeyAvailable)
{
Console.ReadKey(true);
}
if (Player.player[0].Col - 6 >= 0)
{
if (key.Key == ConsoleKey.LeftArrow)
{
for (int i = 0; i < Player.player.Count; i++)
{
Player.player[i] = new Position(Player.player[i].Row, Player.player[i].Col + left, Player.player[i].Symbol);
}
}
}
if (Player.player[0].Col + 7 < Settings.maxCols)
{
if (key.Key == ConsoleKey.RightArrow)
{
for (int i = 0; i < Player.player.Count; i++)
{
Player.player[i] = new Position(Player.player[i].Row, Player.player[i].Col + right, Player.player[i].Symbol);
}
}
}
if (key.Key == ConsoleKey.Spacebar)
{
Shoot.shoot[Player.player[0].Row - 1, Player.player[0].Col] = 1;
}
}
}
}
class Shoot
{
public static int[,] shoot = new int[Settings.maxRows, Settings.maxCols];
public static void GenerateShot()
{
for (int Row = 0; Row < Shoot.shoot.GetLength(0); Row++)
{
for (int Col = 0; Col < Shoot.shoot.GetLength(1); Col++)
{
if (Shoot.shoot[Row, Col] == 1 && (Row == 0))
{
Shoot.shoot[Row, Col] = 0;
}
if (Shoot.shoot[Row, Col] == 1)
{
Shoot.shoot[Row, Col] = 0;
Shoot.shoot[Row - 1, Col] = 1;
}
}
}
}
}
static public class Invader
{
public static List<Position> invader = new List<Position>();
public static List<Position> InitializeInvader(int row, int col)
{
int startrow = 5;//start position row
int startcol = ArmyOfInvaders.startArmyOfInvadersPosition;// start position col
invader.Add(new Position(startrow + row, startcol + col, '/'));
invader.Add(new Position(startrow + row, startcol + 1 + col, '{'));
invader.Add(new Position(startrow + row, startcol + 2 + col, 'O'));
invader.Add(new Position(startrow + row, startcol + 3 + col, '}'));
invader.Add(new Position(startrow + row, startcol + 4 + col, '\\'));
invader.Add(new Position(startrow + 1 + row, startcol + col, '\\'));
invader.Add(new Position(startrow + 1 + row, startcol + 1 + col, '~'));
invader.Add(new Position(startrow + 1 + row, startcol + 2 + col, '$'));
invader.Add(new Position(startrow + 1 + row, startcol + 3 + col, '~'));
invader.Add(new Position(startrow + 1 + row, startcol + 4 + col, '/'));
return invader;
}
}
public class Draw
{
public static void DrawItem(List<Position> invader)
{
;
foreach (Position part in invader)
{
Console.SetCursorPosition(part.Col, part.Row);
Console.Write((char)part.Symbol);
}
}
public static void DrawItem(List<List<Position>> armyOfInvaders)
{
foreach (List<Position> invader in armyOfInvaders)
{
Draw.DrawItem(invader);
}
}
public static void EraseItem(List<List<Position>> armyOfInvaders)
{
foreach (List<Position> invader in armyOfInvaders)
{
foreach (Position part in invader)
{
Console.SetCursorPosition(part.Col, part.Row);
Console.Write(' ');
}
}
}
public static void EraseItem(List<Position> invader)
{
foreach (Position part in invader)
{
Console.SetCursorPosition(part.Col, part.Row);
Console.Write(' ');
}
}
public static void DrawShoot()
{
for (int Row = 0; Row < Shoot.shoot.GetLength(0); Row++)
{
for (int Col = 0; Col < Shoot.shoot.GetLength(1); Col++)
{
if (Shoot.shoot[Row, Col] == 1)
{
Console.SetCursorPosition(Col, Row);
Console.Write("|");
}
}
}
}
public static void EraseShoot()
{
for (int Row = 0; Row < Shoot.shoot.GetLength(0); Row++)
{
for (int Col = 0; Col < Shoot.shoot.GetLength(1); Col++)
{
if (Row == 0)
{
Console.SetCursorPosition(Col, Row);
Console.Write(" ");
}
if (Shoot.shoot[Row, Col] == 1)
{
Console.SetCursorPosition(Col, Row + 1);
Console.Write(" ");
}
}
}
}
}
public class Collision
{
public static void InvaderGotShot()
{
for (int i = 0; i < ArmyOfInvaders.armyOfInvaders.Count; i++)
{
for (int j = 0; j < Invader.invader.Count; j++)
{
if (Shoot.shoot[ArmyOfInvaders.armyOfInvaders[i][j].Row, ArmyOfInvaders.armyOfInvaders[i][j].Col] == 1)
{
ArmyOfInvaders.armyOfInvaders[i].Clear();
for (int k = 0; k < Invader.invader.Count; k++)
{
ArmyOfInvaders.armyOfInvaders[i].Add(new Position(ArmyOfInvaders.armyOfInvaders[i][k].Row, ArmyOfInvaders.armyOfInvaders[i][k].Col, ' '));
}
}
}
}
}
}
public class ArmyOfInvaders
{
public static int invadersColDistance = 9;
public static int invadersColsCount = 10;
public static int invadersRowDistance = 4;
public static int invadersRowsCount = 4;
public static int startArmyOfInvadersPosition = (Settings.maxCols - (ArmyOfInvaders.invadersColDistance * ArmyOfInvaders.invadersColsCount)) / 2 + 5;//5 e shiranata na edin invader
public static List<List<Position>> armyOfInvaders = new List<List<Position>>();
public static void InitializeArmyOfInvaders(int moveY = 0, int moveX = 0)
{
for (int row = 0; row < invadersRowDistance * invadersRowsCount; row += invadersRowDistance)
{
for (int col = 0; col < invadersColDistance * invadersColsCount; col += invadersColDistance)
{
Invader.InitializeInvader(row + moveY, col + moveX);
}
}
armyOfInvaders.Add(Invader.invader);
}
}
public class Common
{
public static int gameSpeed = 1;
}
}
提前致谢!
在没有声称重新设计你的设计的情况下,我添加了死亡入侵者(ArmyOfInvaders.deadInvader
)的集合来存储已经射击的那些人,并且改变了InvaderGotShot
和DrawItem
方法。我摆脱了Invader.invader
集合并在Invader.InitializeInvader
中引入了局部变量而不是它以防止错误分配。请看一下:
class Program
{
static void Main()
{
Settings.ScreenSettings();
ArmyOfInvaders.InitializeArmyOfInvaders();
Player.InitializePlayer();
int stepCount = 0;
int armyOfInvadersSpeed = 50;
while (true)
{
stepCount++;
if (stepCount % armyOfInvadersSpeed == 0)
{
Draw.EraseItem(ArmyOfInvaders.armyOfInvaders);
ArmyOfInvaders.armyOfInvaders.Clear();
ArmyOfInvaders.InitializeArmyOfInvaders(Movement.moveY, Movement.moveX);
Movement.MovementArmyOfInvaders();
stepCount = 0;
}
Console.CursorVisible = false;
Draw.DrawItem(ArmyOfInvaders.armyOfInvaders);
Draw.EraseItem(Player.player);
Shoot.GenerateShot();
Movement.MovementPlayer();
Draw.DrawItem(Player.player);
Draw.DrawShoot();
Draw.EraseShoot();
Collision.InvaderGotShot();
Thread.Sleep(Common.gameSpeed);
}
}
}
public class Settings
{
static public int maxRows = 50;
static public int maxCols = 180;
public static void ScreenSettings()
{
Console.CursorVisible = false;
Console.BufferHeight = Console.WindowHeight = maxRows;
Console.BufferWidth = Console.WindowWidth = maxCols;
}
}
public struct Position
{
public int Row { get; set; }
public int Col { get; set; }
public char Symbol { get; set; }
public Position(int row, int col, char symbol)
{
this.Row = row;
this.Col = col;
this.Symbol = symbol;
}
}
public class Player
{
public static List<Position> player = new List<Position>();
public static int playerWide = 9;
public static int playerLong = player.Count;
public static List<Position> InitializePlayer(int row = 0, int col = 0)
{
int startrow = Settings.maxRows - 5 - playerLong;//start position row
int startcol = (Settings.maxCols / 2) - (playerWide / 2);// start position col
player.Add(new Position(startrow + row, startcol + col, 'A'));
player.Add(new Position(startrow + 1 + row, startcol + col, 'o'));
player.Add(new Position(startrow + 2 + row, startcol - 2 + col, '|'));
player.Add(new Position(startrow + 2 + row, startcol + col, 'o'));
player.Add(new Position(startrow + 2 + row, startcol + 2 + col, '|'));
player.Add(new Position(startrow + 3 + row, startcol - 4 + col, '/'));
player.Add(new Position(startrow + 3 + row, startcol - 3 + col, '\\'));
player.Add(new Position(startrow + 3 + row, startcol - 2 + col, '\\'));
player.Add(new Position(startrow + 3 + row, startcol - 1 + col, '\\'));
player.Add(new Position(startrow + 3 + row, startcol + col, 'o'));
player.Add(new Position(startrow + 3 + row, startcol + 1 + col, '/'));
player.Add(new Position(startrow + 3 + row, startcol + 2 + col, '/'));
player.Add(new Position(startrow + 3 + row, startcol + 3 + col, '/'));
player.Add(new Position(startrow + 3 + row, startcol + 4 + col, '\\'));
player.Add(new Position(startrow + 4 + row, startcol - 2 + col, '<'));
player.Add(new Position(startrow + 4 + row, startcol - 1 + col, '/'));
player.Add(new Position(startrow + 4 + row, startcol - 0 + col, 'o'));
player.Add(new Position(startrow + 4 + row, startcol + 1 + col, '\\'));
player.Add(new Position(startrow + 4 + row, startcol + 2 + col, '>'));
return player;
}
}
public class Movement
{
public static bool isRight = true;
public static int moveX = 0;
public static int moveY = 0;
public static int left = -1;
public static int right = 1;
public static int armyOfInvaderJump = 5;
public static void MovementArmyOfInvaders()
{
if (isRight)
{
moveX += armyOfInvaderJump;
if (ArmyOfInvaders.armyOfInvaders[ArmyOfInvaders.armyOfInvaders.Count - 1][9].Col >= Settings.maxCols - 20)
{
isRight = false;
moveY += 2;
}
}
else
{
moveX -= armyOfInvaderJump;
if (ArmyOfInvaders.armyOfInvaders[0][0].Col <= 20)
{
isRight = true;
moveY += 2;
}
}
}
public static void MovementPlayer()
{
while (Console.KeyAvailable)
{
ConsoleKeyInfo key = Console.ReadKey(true);
while (Console.KeyAvailable)
{
Console.ReadKey(true);
}
if (Player.player[0].Col - 6 >= 0)
{
if (key.Key == ConsoleKey.LeftArrow)
{
for (int i = 0; i < Player.player.Count; i++)
{
Player.player[i] = new Position(Player.player[i].Row, Player.player[i].Col + left, Player.player[i].Symbol);
}
}
}
if (Player.player[0].Col + 7 < Settings.maxCols)
{
if (key.Key == ConsoleKey.RightArrow)
{
for (int i = 0; i < Player.player.Count; i++)
{
Player.player[i] = new Position(Player.player[i].Row, Player.player[i].Col + right, Player.player[i].Symbol);
}
}
}
if (key.Key == ConsoleKey.Spacebar)
{
Shoot.shoot[Player.player[0].Row - 1, Player.player[0].Col] = 1;
}
}
}
}
class Shoot
{
public static int[,] shoot = new int[Settings.maxRows, Settings.maxCols];
public static void GenerateShot()
{
for (int Row = 0; Row < Shoot.shoot.GetLength(0); Row++)
{
for (int Col = 0; Col < Shoot.shoot.GetLength(1); Col++)
{
if (Shoot.shoot[Row, Col] == 1 && (Row == 0))
{
Shoot.shoot[Row, Col] = 0;
}
if (Shoot.shoot[Row, Col] == 1)
{
Shoot.shoot[Row, Col] = 0;
Shoot.shoot[Row - 1, Col] = 1;
}
}
}
}
}
static public class Invader
{
public static List<Position> InitializeInvader(int row, int col)
{
int startrow = 5;//start position row
int startcol = ArmyOfInvaders.startArmyOfInvadersPosition;// start position col
List<Position> invader = new List<Position>();
invader.Add(new Position(startrow + row, startcol + col, '/'));
invader.Add(new Position(startrow + row, startcol + 1 + col, '{'));
invader.Add(new Position(startrow + row, startcol + 2 + col, 'O'));
invader.Add(new Position(startrow + row, startcol + 3 + col, '}'));
invader.Add(new Position(startrow + row, startcol + 4 + col, '\\'));
invader.Add(new Position(startrow + 1 + row, startcol + col, '\\'));
invader.Add(new Position(startrow + 1 + row, startcol + 1 + col, '~'));
invader.Add(new Position(startrow + 1 + row, startcol + 2 + col, '$'));
invader.Add(new Position(startrow + 1 + row, startcol + 3 + col, '~'));
invader.Add(new Position(startrow + 1 + row, startcol + 4 + col, '/'));
return invader;
}
}
public class Draw
{
public static void DrawItem(List<Position> invader)
{
;
foreach (Position part in invader)
{
Console.SetCursorPosition(part.Col, part.Row);
Console.Write((char)part.Symbol);
}
}
public static void DrawItem(List<List<Position>> armyOfInvaders)
{
for (var i = 0; i < armyOfInvaders.Count; i++)
{
if (!ArmyOfInvaders.deadInvaders.Contains(i))
{
Draw.DrawItem(armyOfInvaders[i]);
}
}
}
public static void EraseItem(List<List<Position>> armyOfInvaders)
{
foreach (List<Position> invader in armyOfInvaders)
{
foreach (Position part in invader)
{
Console.SetCursorPosition(part.Col, part.Row);
Console.Write(' ');
}
}
}
public static void EraseItem(List<Position> invader)
{
foreach (Position part in invader)
{
Console.SetCursorPosition(part.Col, part.Row);
Console.Write(' ');
}
}
public static void DrawShoot()
{
for (int Row = 0; Row < Shoot.shoot.GetLength(0); Row++)
{
for (int Col = 0; Col < Shoot.shoot.GetLength(1); Col++)
{
if (Shoot.shoot[Row, Col] == 1)
{
Console.SetCursorPosition(Col, Row);
Console.Write("|");
}
}
}
}
public static void EraseShoot()
{
for (int Row = 0; Row < Shoot.shoot.GetLength(0); Row++)
{
for (int Col = 0; Col < Shoot.shoot.GetLength(1); Col++)
{
if (Row == 0)
{
Console.SetCursorPosition(Col, Row);
Console.Write(" ");
}
if (Shoot.shoot[Row, Col] == 1)
{
Console.SetCursorPosition(Col, Row + 1);
Console.Write(" ");
}
}
}
}
}
public class Collision
{
public static void InvaderGotShot()
{
for (int i = 0; i < ArmyOfInvaders.armyOfInvaders.Count; i++)
{
for (int j = 0; j < ArmyOfInvaders.armyOfInvaders[i].Count; j++)
{
if (Shoot.shoot[ArmyOfInvaders.armyOfInvaders[i][j].Row, ArmyOfInvaders.armyOfInvaders[i][j].Col] == 1)
{
if (!ArmyOfInvaders.deadInvaders.Contains(i))
{
Shoot.shoot[ArmyOfInvaders.armyOfInvaders[i][j].Row,
ArmyOfInvaders.armyOfInvaders[i][j].Col] = 0;
ArmyOfInvaders.deadInvaders.Add(i);
return;
}
}
}
}
}
}
public class ArmyOfInvaders
{
public static int invadersColDistance = 9;
public static int invadersColsCount = 10;
public static int invadersRowDistance = 4;
public static int invadersRowsCount = 4;
public static List<int> deadInvaders = new List<int>();
public static int startArmyOfInvadersPosition = (Settings.maxCols - (ArmyOfInvaders.invadersColDistance * ArmyOfInvaders.invadersColsCount)) / 2 + 5;//5 e shiranata na edin invader
public static List<List<Position>> armyOfInvaders = new List<List<Position>>();
public static void InitializeArmyOfInvaders(int moveY = 0, int moveX = 0)
{
for (int row = 0; row < invadersRowDistance * invadersRowsCount; row += invadersRowDistance)
{
for (int col = 0; col < invadersColDistance * invadersColsCount; col += invadersColDistance)
{
var invader = Invader.InitializeInvader(row + moveY, col + moveX);
armyOfInvaders.Add(invader);
}
}
}
}
public class Common
{
public static int gameSpeed = 1;
}
重点是隐藏死亡的外星人,但不要将他们排除在收集之外。你的实现试图清除外星人的位置,但在下一次迭代中它再次初始化了所有入侵者。
还要注意我被迫在9
中引入文字Movement.MovementArmyOfInvaders
而不是调用Invader.invader.Length
。
希望能帮助到你。
关于存储入侵者的正确方法的问题的附加答案。我不知道是否适合创建另一个答案,但代码片段相当大。这是一个设计的例子。它只是理解这个想法的原型。我没有尝试提出完整的解决方案,您可以随意修改它。我为您留下了大部分实施细节,并试图在评论中提供完整的解释。主要思想是避免静态并将其替换为对象中的封装状态:
/// <summary>
/// Invaders, that can move and be shot
/// </summary>
public class ArmyOfInvaders
{
/// <summary>
/// Alive invaders
/// </summary>
private readonly List<Invader> _invaders = new List<Invader>();
/// <summary>
/// Initializes all invaders once on start of the game
/// Provide them initial coordinates and add them to <see cref="_invaders"/>
/// </summary>
public void Initialize()
{
}
/// <summary>
/// Moves all invaders somewhere
/// Erases invaders, moves them and draw again
/// </summary>
public void Move()
{
int xMove = 0;
int yMove = 0;
// Here some logic around moving of entire cloud of invaders
// computing of xMove and yMove
foreach (var invader in _invaders)
{
invader.Erase();
invader.Move(xMove, yMove);
invader.Draw();
}
}
/// <summary>
/// Handles shoot to invaders
/// </summary>
/// <param name="shootX">X coordinate of the bullet</param>
/// <param name="shootY">Y coordinate of the bullet</param>
public void HandleShoot(int shootX, int shootY)
{
var victim = _invaders.FirstOrDefault(i => i.IsShot(shootX, shootY));
if (victim != null)
{
_invaders.Remove(victim);
}
}
}
/// <summary>
/// Single invader
/// </summary>
/// <remarks>
/// Invader really needs only one postion(x,y), let say top-left point
/// All symbols, which it consists of, can be printed relatively of this point.
/// </remarks>
public class Invader
{
/// <summary>
/// X coordinate of invader
/// </summary>
private int _x;
/// <summary>
/// Y coordinate of invader
/// </summary>
private int _y;
/// <summary>
/// Ctor
/// </summary>
/// <param name="x">Initial x coordinate</param>
/// <param name="y">Initial y coordinate</param>
public Invader(int x, int y)
{
Move(x, y);
}
/// <summary>
/// Draws the invader by current coordinates
/// Invader really needs only one postion(x,y), let say top-left point
/// All symbols, which it consists of, can be printed relatively of this point.
/// </summary>
public void Draw()
{
// here printing of symbols
}
/// <summary>
/// Changes the coordinates of invader
/// </summary>
public void Move(int xMove, int yMove)
{
_x += xMove;
_y += yMove;
}
/// <summary>
/// Erases the invader by current coordinates
/// </summary>
public void Erase()
{
// here erasing of symbols
}
/// <summary>
/// Returns true if some part of invaders is crushed by bullet
/// </summary>
/// <param name="shootX">X coordinate of bullet</param>
/// <param name="shootY">Y coordinate of bullet</param>
public bool IsShot(int shootX, int shootY)
{
return // here logic of crushing
}
}
希望能帮助到你。