我正在创建一个太空入侵者类型的游戏并遇到错误。
错误发生在Update
函数内,两个for循环内。一个用于检查有多少外星人活着,一个用于检查外星人是否到达屏幕底部。
这是代码中的主要错误
if (rectShipBullet.Y + rectShipBullet.Height < 0)// Adding this will allow the player to fire a new bullet each time the player misses. If a minus symbol was used then the bullet would go off the screen far too early and not look realistic so the plus symbol is used instead.
ShipBulletVisible = "No";
int CountAliensAlive = 0;//Keeps track of how many aliens are alive.
for (int i = 0; i < rectSpaceInvader.Length; i++)
{
if (AlienAlive[i].Equals("Yes"))
CountAliensAlive = CountAliensAlive + 1;
}
//If half of the aliens are gone (25/50) aliens are dead then.
if (50 * 1 / 2 == CountAliensAlive)
SpaceInvaderSpeed = 15; // So when most of the aliens are dead the speed of the aliens coming down will double making it more difficult.
//Now we will check to see if the aliens reach the bottom of the screen and hit our ship which would cause a game over.
for (int i = 0; i < rectSpaceInvader.Length; i++)
{
{
if (AlienAlive[i].Equals("Yes")) //Checks to see if the space invader is visible.
if (rectSpaceInvader[i].Y + rectSpaceInvader[i].Height > rectSpaceShip.Y)
this.Exit();
}
}
完整的代码仅供参考
namespace Space_Invaders
{
/// <summary>
/// This is the main type for your game
/// </summary>
///
public class Game1 : Microsoft.Xna.Framework.Game
{
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
SpriteFont Start;
string Screen = "START";
bool GameOver = false, restart = true;
SpriteFont Label;
string txt = ".";
Keys PrevKey;
string[] HighScores = new string[5];
int count = 0;
Texture2D SpaceShip, ShipBullet;
Rectangle rectShipBullet;//Implementing the ship's bullet and again no need for multiple arrays since we are only going to use one bullet.
Rectangle rectSpaceShip; //No need for the multidimensonal array with the spaceship since there is only going to be on visible on the screen.
Texture2D[] SpaceInvader = new Texture2D[50];
Rectangle[] rectSpaceInvader = new Rectangle[50]; //This will be a multidimensional array which will be used for the space invaders. For rows and columns.
String[] AlienAlive= new String[50]; //Creating another multidimensional array for keeping track of what aliens are alive or dead. At the beginning of the game we want all aliens to be alive at the start so we would begin by saying that aliens alive = "Yes".
SpriteFont scoreBoard;
int Score = 0;
int SpaceInvaderX=10, SpaceInvaderY=5;
int SpaceInvaderSpeed = 10;//Creating a variable for the speed of the aliens.
String Direction = "Right";
String ShipBulletVisible = "No"; //Need to know when the bullet is going to be visible within the game so we create a string and immediately upon declaring we say no so we can add an if statement saying otherwise.
public Game1()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
}
/// <summary>
/// Allows the game to perform any initialization it needs to before starting to run.
/// This is where it can query for any required services and load any non-graphic
/// related content. Calling base.Initialize will enumerate through any components
/// and initialize them as well.
/// </summary>
protected override void Initialize()
{
// TODO: Add your initialization logic here
for (int i = 0; i < rectSpaceInvader.Length; i++)
{
if (i % 5 == 0 && i!=0)
{
SpaceInvaderY += 30;
SpaceInvaderX = 5;
}
rectSpaceInvader[i] = new Rectangle(SpaceInvaderX, SpaceInvaderY, 100, 25);
SpaceInvaderX = SpaceInvaderX+ rectSpaceInvader[i].Width + 2;
AlienAlive[i] = "Yes";
}
base.Initialize();
}
/// <summary>
/// LoadContent will be called once per game and is the place to load
///
/// all of your content.
/// </summary>
protected override void LoadContent()
{
// Create a new SpriteBatch, which can be used to draw textures.
spriteBatch = new SpriteBatch(GraphicsDevice);
// TODO: use this.Content to load your game content here
Start = Content.Load<SpriteFont>("StartScreen");
scoreBoard = Content.Load<SpriteFont>("Score");
for (int i = 0; i < rectSpaceInvader.Length; i++)
{
SpaceInvader[i] = Content.Load<Texture2D>("Invader");
}
// rectSpaceInvader = new Rectangle[50]; //Adding Rows & Columns to the space invaders so when the game is loaded there will be 5 rows of space invaders with 10 in each row.
// AlienAlive = new String[50];// Must declare the multidimensional array here also in order for it to detect what aliens are alive or not.
/*
for (int i = 0; i < rectSpaceInvader.Length; i++) // This is used for the columns, so when the program runs the loop will go through and say 0 times 50, then 1 times 50 and so on.
{
rectSpaceInvader[i].Width = SpaceInvader[i].Width;
rectSpaceInvader[i].Height = SpaceInvader[i].Height;
rectSpaceInvader[i].X = 50 ; //X corresponds to my collumns and will space the space invaders out according to what value was added to multiply by the columns.
rectSpaceInvader[i].Y = 50 ; //Y corresponds to my rows and will space the space invaders out according to what value was added to multiply by the rows.
AlienAlive[i] = "Yes";
}
*/
SpaceShip = Content.Load<Texture2D>("SpaceShip");//Loading in the spaceship into the LoadContent function.
rectSpaceShip.Width = SpaceShip.Width;//Setting the width of the rectangle the same width as the spaceship image that is being loaded in.
rectSpaceShip.Height = SpaceShip.Height; //Setting the height of the rectangle the same height as the spaceship image that is being loaded in.
rectSpaceShip.X = 0;//Setting the X position of the spaceship to be in the far bottom left corner of the game screen.
rectSpaceShip.Y = 440; //Setting the Y position of the spaceship.
ShipBullet = Content.Load<Texture2D>("Bullet3");
rectShipBullet.Width = ShipBullet.Width;//Setting the width of the bullet to be the same width as the bullet image that was loaded in.
rectShipBullet.Height = ShipBullet.Height;//Setting the heigh of the buller to be the same heigh as the bullet image that was loaded in.
rectShipBullet.X = 0;
rectShipBullet.Y = 0;
}
/// <summary>
/// UnloadContent will be called once per game and is the place to unload
/// all content.
/// </summary>
protected override void UnloadContent()
{
// TODO: Unload any non ContentManager content here
}
/// <summary>
/// Allows the game to run logic such as updating the world,
/// checking for collisions, gathering input, and playing audio.
/// </summary>
/// <param name="gameTime">Provides a snapshot of timing values.</param>
protected override void Update(GameTime gameTime)
{
// Allows the game to exit
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
this.Exit();
// TODO: Add your update logic here
// Alien Movement
if (!GameOver && !restart)
{
int RightEdge = graphics.GraphicsDevice.Viewport.Width;
int LeftEdge = 0;
for (int i = 0; i < rectSpaceInvader.Length; i++)
{
if (Direction.Equals("Right"))// ".Equals" is used in place of "==" and is used throughout the entire code".
rectSpaceInvader[i].X = rectSpaceInvader[i].X + SpaceInvaderSpeed; //If the direction is equal to right then the space invaders will move along the X axis towards the right edge of the screen.
if (Direction.Equals("Left"))
rectSpaceInvader[i].X = rectSpaceInvader[i].X - SpaceInvaderSpeed; //Almost same code as the one above except instead of going to the right we are moving the aliens to the left edge of the screen.
}
//Checks to see if any aliens have gone passed the edge of the right side of the screen.
String ChangeDirection = "No"; //Declaring a string variable inside the update function.
for (int i = 0; i < rectSpaceInvader.Length; i++)
{
if (AlienAlive[i].Equals("Yes"))//This code stops an error. The error is that without this line of code the aliens that the player has already shot are shown as invisible and dead on the screen but are still there while the game runs so if the player eliminated the first two rows of aliens, once the aliens reached the far left of the screen, the aliens would not go to the very edge of the screen, since the game still thinks the dead aliens are still in the game and the check that is running is causing them to collide with the left wall so with this line of code, that bypasses that.
{
if (rectSpaceInvader[i].X + rectSpaceInvader[i].Width > RightEdge)
{
Direction = "Left"; //This will not switch the aliens around and have them move to the left edge but the if statement above will do that.
ChangeDirection = "Yes";
}
if (rectSpaceInvader[i].X < LeftEdge)
{
Direction = "Right"; //Checks to see if the aliens have gone passed the left edge of the screen and if so then the direction will turn them back towards the right edge of the screen.
ChangeDirection = "Yes";
}
}
}
if (ChangeDirection.Equals("Yes"))
{
for (int i = 0; i < rectSpaceInvader.Length; i++)
rectSpaceInvader[i].Y = rectSpaceInvader[i].Y + 8;//Here we set and change the Y value for the aliens. When the aliens reach either the left or right edge of the game screen they will move down by 3 and continue moving down until the bottom.
}
}
//Ship Movement
KeyboardState kb = Keyboard.GetState();
if (kb.IsKeyDown(Keys.S))
restart = false;
if (kb.IsKeyDown(Keys.Left))
rectSpaceShip.X = rectSpaceShip.X - 4;//Allows user to use the left arrow key in order to move the space ship to the left and the ship will move twice as fast as normal since the speed has been set to 2
if (kb.IsKeyDown(Keys.Right))
rectSpaceShip.X = rectSpaceShip.X + 4;//Allows user to use the right arrow key in order to move the space ship to the right.
if (kb.IsKeyDown(Keys.Space) && ShipBulletVisible.Equals("No"))
{
ShipBulletVisible = "Yes";//Since we have set the spacebar as the trigger to show the bullet on the screen.
rectShipBullet.X = rectSpaceShip.X + (rectSpaceShip.Width / 2) - (rectShipBullet.Width / 2) - 1; //In order to set the position of the bullet to be in the middle of the ship, I had to take the width of the ship divide it by 2 which would make it to be in the middle of the ship since when the game ran previously the bullet would appear to the left edge of the ships rectangle. I then took that away from the width of the ship's bullet rectangle and divided that by 2. Was still slightly off so I had to subtract one from the entire line of code in order to get it dead centre. So when the spacebar is triggered the bullet will appear in the middle of the ship, also when moving the bullet will appear in the same position.
rectShipBullet.Y = rectSpaceShip.Y - rectShipBullet.Height + 2; //Since the Y values are increasing as you are moving down the screen I use "+2" and not minus 2 so that the very bottom of the bullet is on the tip of the spaceship.
}
if (ShipBulletVisible.Equals("Yes")) //Could use a boolean to check.
rectShipBullet.Y = rectShipBullet.Y - 5; //Making the bullet move when the spacebar is pressed and giving it an initial speed.
//Now I am checking to see if a bullet has hit an alien. Use of the For loop again.
if (ShipBulletVisible.Equals("Yes"))
{
for (int i = 0; i < rectSpaceInvader.Length; i++)
{
if (AlienAlive[i].Equals("Yes"))
{//This piece of code is crucial for the game to function right. If this is not in, when the game loads and the player takes out the first row of aliens. The player would not be able to advance since when the player would fire it the bullet would still hit aliens that are supposed to be dead but they are still loaded on the screen and are causing the bullet the to detect them as alive aliens. So with this piece of code, saying if the aliens are alive and that equals yes then it would run the check and bypass the invisible alive aliens and allow the player to continue playing the game.
if (rectShipBullet.Intersects(rectSpaceInvader[i])) //This means that if the bullet intersects/ has hit one of the aliens then the bullet would have to become invisible after hitting the alien to act like it has realistcly hit the alien and has disappeared.
{
ShipBulletVisible = "No";
AlienAlive[i] = "No";
Score++;
rectShipBullet.X = rectSpaceShip.X + (rectSpaceShip.Width / 2) - (rectShipBullet.Width / 2) - 1; //In order to set the position of the bullet to be in the middle of the ship, I had to take the width of the ship divide it by 2 which would make it to be in the middle of the ship since when the game ran previously the bullet would appear to the left edge of the ships rectangle. I then took that away from the width of the ship's bullet rectangle and divided that by 2. Was still slightly off so I had to subtract one from the entire line of code in order to get it dead centre. So when the spacebar is triggered the bullet will appear in the middle of the ship, also when moving the bullet will appear in the same position.
rectShipBullet.Y = rectSpaceShip.Y - rectShipBullet.Height + 2;
rectSpaceInvader[i].Width = 0;
rectSpaceInvader[i].Height = 0;
if (Score == 50)
{
this.Exit();
}
}
//Checks to see if the bullet has missed any aliens and has gone off of the screen, before this code is added the game would not allow you to fire anymore new bullets.
if (rectShipBullet.Y + rectShipBullet.Height < 0)// Adding this will allow the player to fire a new bullet each time the player misses. If a minus symbol was used then the bullet would go off the screen far too early and not look realistic so the plus symbol is used instead.
ShipBulletVisible = "No";
***int CountAliensAlive = 0;//Keeps track of how many aliens are alive.
for (int i = 0; i < rectSpaceInvader.Length; i++)
{
if (AlienAlive[i].Equals("Yes"))
CountAliensAlive = CountAliensAlive + 1;
}
//If half of the aliens are gone (25/50) aliens are dead then.
if (50 * 1 / 2 == CountAliensAlive)
SpaceInvaderSpeed = 15; // So when most of the aliens are dead the speed of the aliens coming down will double making it more difficult.
//Now we will check to see if the aliens reach the bottom of the screen and hit our ship which would cause a game over.
for (int i = 0; i < rectSpaceInvader.Length; i++)
{
{
if (AlienAlive[i].Equals("Yes")) //Checks to see if the space invader is visible.
if (rectSpaceInvader[i].Y + rectSpaceInvader[i].Height > rectSpaceShip.Y)
this.Exit();*
}
}**
/*
for (int i = 0; i < rectSpaceInvader.Length; i++)
{
if (rectShipBullet.Intersects(rectSpaceInvader[i]))
{
Score++;
rectShipBullet.X = rectSpaceShip.X + (rectSpaceShip.Width / 2) - (rectShipBullet.Width / 2) - 1; //In order to set the position of the bullet to be in the middle of the ship, I had to take the width of the ship divide it by 2 which would make it to be in the middle of the ship since when the game ran previously the bullet would appear to the left edge of the ships rectangle. I then took that away from the width of the ship's bullet rectangle and divided that by 2. Was still slightly off so I had to subtract one from the entire line of code in order to get it dead centre. So when the spacebar is triggered the bullet will appear in the middle of the ship, also when moving the bullet will appear in the same position.
rectShipBullet.Y = rectSpaceShip.Y - rectShipBullet.Height + 2;
}
}
*/
if (restart)
Screen = "START";
if (GameOver)
Screen = "Game Over";
KeyboardState ks = Keyboard.GetState();
Keys[] k = ks.GetPressedKeys();
Keys tempKey = Keys.None;
string keyChar = "";
foreach (Keys q in k)
{
Keys currentKey = q;
if (ks.IsKeyUp(PrevKey))
{
if (!(q == Keys.None))
{
switch (q)
{
case Keys.Space:
keyChar = " ";
break;
case Keys.Delete:
txt = "";
break;
case Keys.Back:
txt = txt.Remove(txt.Length - 1);
break;
case Keys.Enter:
HighScores[count] = txt;
count++;
txt = "";
if (count == 5)
count = 0;
break;
case Keys.End:
WriteScores();
break;
case Keys.Home:
ReadScores();
break;
default:
keyChar = q.ToString();
break;
}
txt += keyChar;
}
}
if (currentKey != Keys.None && ks.IsKeyDown(currentKey))
{
tempKey = currentKey;
}
}
PrevKey = tempKey;
base.Update(gameTime);
}
}
}
}
public void WriteScores()
{
StreamWriter Rite = new StreamWriter(@"C:\TheScores.txt");
for (int i = 0; i < HighScores.Length; i++)
{
Rite.WriteLine(HighScores[i]);
}
Rite.Close();
}
public void ReadScores()
{
if (File.Exists(@"C:\TheHighScores.txt"))
{
StreamReader Reed = new StreamReader(@"C:\TheScores.txt");
for (int i = 0; i < HighScores.Length; i++)
{
txt += Reed.ReadLine() + "\n";
}
Reed.Close();
}
}
/// <summary>
/// This is called when the game should draw itself.
/// </summary>
/// <param name="gameTime">Provides a snapshot of timing values.</param>
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
// TODO: Add your drawing code here
spriteBatch.Begin();
if (!restart && !GameOver)
{
for (int i = 0; i < rectSpaceInvader.Length; i++)
{
if (AlienAlive[i].Equals("Yes"))
spriteBatch.Draw(SpaceInvader[i], rectSpaceInvader[i], Color.White); //This will run the loop within the spritebatch and create 5 columns of space invaders and 10 space invaders in each of the rows using the spritebatch.draw method.
}
spriteBatch.Draw(SpaceShip, rectSpaceShip, Color.White);//Loading in the spaceship and loading it in outside the for loop because if it was drawn inside the for loop then it would create multiple spaceships when we only need one.
if (ShipBulletVisible.Equals("Yes"))//If the bullet is visible then this will trigger and draw the bullet onto the screen.
spriteBatch.Draw(ShipBullet, rectShipBullet, Color.White);
spriteBatch.DrawString(scoreBoard, Convert.ToString(Score) + " " + AlienAlive[49], new Vector2(10, 10), Color.Black);
}
else
{
if (GameOver)
Screen = "GAME OVER";
spriteBatch.DrawString(Start, Screen, new Vector2(100, 100), Color.Black);
spriteBatch.DrawString(Label, txt, new Vector2(200, 100), Color.Black);
}
spriteBatch.End();
base.Draw(gameTime);
}
}
}
答案 0 :(得分:8)
对于具有嵌套for
循环的迭代器,您需要具有不同的名称。
示例:强>
for(int i = 0; i < 10; i++)
{
for(int x = 0; x < 10; x++)
{
//some code
}
}
注意i
和x
。两者都不能在同一范围内i
。
另一方面,这是有效的,因为每个都存在于不同的范围内。
for(int i = 0; i < 10; i++)
{
//some code
}
for(int i = 0; i < 10; i++)
{
//some code
}
<强>修正:强>
以下是有问题的循环。在声明中,将i
的所有实例更改为x
(或其他),如上所示。
for (int i = 0; i < rectSpaceInvader.Length; i++)
{
if (AlienAlive[i].Equals("Yes"))
CountAliensAlive = CountAliensAlive + 1;
}
for (int i = 0; i < rectSpaceInvader.Length; i++)
{
{
if (AlienAlive[i].Equals("Yes"))
if (rectSpaceInvader[i].Y + rectSpaceInvader[i].Height > rectSpaceShip.Y)
this.Exit();*
}
}
它们都包含在此内容中(显示if
以供参考)。
if (ShipBulletVisible.Equals("Yes"))
{
for (int i = 0; i < rectSpaceInvader.Length; i++)
{
//code
}
}
答案 1 :(得分:2)
正如@ aw04(+1)指出的那样,你有使用相互嵌套的相同变量的循环。你在这里(在你的update
方法中):
//Now I am checking to see if a bullet has hit an alien. Use of the For loop again.
if (ShipBulletVisible.Equals("Yes"))
{
for (int i = 0; i < rectSpaceInvader.Length; i++)
{
if (AlienAlive[i].Equals("Yes"))
{
if (...)
for (int i = 0; i < rectSpaceInvader.Length; i++)<-- this is causing the error. Change the variable to x or j like was suggested, or change the outer loops variable
{...}
//Now we will check to see if the aliens reach the bottom of the screen and hit our ship which would cause a game over.
for (int i = 0; i < rectSpaceInvader.Length; i++)<-- same thing here
{...}
}
}
}
作为旁注,如果为外星人上课,你的代码会更易于管理。