C#单游戏菜单不起作用,敌人击中时游戏屏幕不起作用



我正在使用C#和monogame框架在Visual Studio中构建这个游戏。游戏的目的是使用埃里克来躲避掉落的敌人,随着时间的推移,敌人会变得更快,如果你击中了一个敌人,那么游戏就结束了。

有一个主菜单在游戏前加载,要求您按回车键开始游戏,如果您按下此键,游戏将加载,如果您击中敌人,将出现游戏结束屏幕,您可以通过按 A 返回主菜单。

但是,目前,我的游戏没有先打开主菜单或在屏幕上显示游戏。这些屏幕使用与主游戏本身相同的背景图像,但文本具有深红色字体,以便于区分状态。

这是我的代码,请有人建议

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using System.Collections.Generic;
using System;
using System.Media;
using Microsoft.Xna.Framework.Audio;

namespace AttackOfTheUnknown
{
/// <summary>
/// Constructor for Game.
/// This is called when the Game object is created.
/// </summary>
public class SuperAlianorRescue : Game
{
// --- GAME STATE ---
enum GameState
{
GameMenu = 0,
GamePlay = 1,
GameOver = 2,
}
GameState currentGameState;
// --- GRAPHICS ---
// Manages the graphics
GraphicsDeviceManager graphics;
// Used to draw sprite images (textures)
SpriteBatch spriteBatch;
// Area which should be visible on all TVs (OK to draw inside)
Rectangle safeBounds;
// Percentage of the screen on every side is the safe area
const float safeAreaPortion = 0.05f;
// --- CHARACTER ---
// Used for character sprite
Texture2D characterTexture;
// Used to store current character position
Vector2 characterPosition;
// Used to calculate next position of character given user input
const int characterSpeed = 10;
// Used to state character has collided with enemy
bool characterHit = false;
//--- ENEMIES ---
// Used for enemy sprite
Texture2D enemyTexture;
// The list of enemies currently in the game
List<Vector2> enemyPositions = new List<Vector2>();
// Probability that an enemy will be spawned
float enemySpawnProbability = 0.05f;
// Speed of enemy
public float speedIncrement = 0.01f;
public float enemySpeed = 0.005f;
public float speed = 0;
// Used to generate random colours
Random random = new Random();
// Current enemy colour
Color enemyColor = Color.White;
// IMPORT GAME BACKGROUND
Texture2D backgroundTexture;
// SOUND
// enemy spawn sound
SoundEffect enemySpawnSound;
SoundEffectInstance enemySpawnSoundInstance;
// --- IN_GAME INFORMATION ---
// Player score
long score;
// Highest score
long highScore;
// Font used to display score
SpriteFont scoreFont;
// Used to hold current on-screen information
string scoreText = "SCORE: 0";
string highScoreText = "HI: 0";
string gameName = "Super Alianor Rescue";
string aimText = "Aim: Move Eric with WASD keys to dodge the enemies.";
string menuWelcome = "Welcome to Super Alianor Rescue.";
string menuHowToPlay = "Press ENTER To Start New Game.";
string GameOverText = "Game Over";
string GameOverClose = "Press Escape To Quit Game";
Song theSong;
public SuperAlianorRescue()
{
graphics = new GraphicsDeviceManager(this);
graphics.PreferredBackBufferHeight = 600;
graphics.PreferredBackBufferWidth = 650;
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()
{
base.Initialize();
// Calculate safe bounds based on current resolution
Viewport viewport = graphics.GraphicsDevice.Viewport;
safeBounds = new Rectangle(
(int)(viewport.Width * safeAreaPortion),
(int)(viewport.Height * safeAreaPortion),
(int)(viewport.Width * (1 - 2 * safeAreaPortion)),
(int)(viewport.Height * (1 - 2 * safeAreaPortion)));
// Start the player in the centre along the bottom of the screen
characterPosition.X = (safeBounds.Width - characterTexture.Width) / 2;
characterPosition.Y = safeBounds.Height - characterTexture.Height;
// Reset score
score = 0;
highScore = 0;
MediaPlayer.IsRepeating = true;
MediaPlayer.Play(theSong);
MediaPlayer.Volume = 0.01f;
// Set the initial game state
currentGameState = GameState.GameMenu;
// Reset score
score = 0;
highScore = 0;
}
/// <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);
// Load textures
enemyTexture = Content.Load<Texture2D>("enemy");
characterTexture = Content.Load<Texture2D>("eric2");
backgroundTexture = Content.Load<Texture2D>("gameback");
// create the font
scoreFont = Content.Load<SpriteFont>("GameFont");
theSong = Content.Load<Song>("Komiku_-_63_-_The_Zone");

// create the sound effect
enemySpawnSound = Content.Load<SoundEffect>("Zombie Demon");
enemySpawnSoundInstance = enemySpawnSound.CreateInstance();
enemySpawnSoundInstance.Volume = 1.0f;
enemySpawnSoundInstance.Pitch = 1.0f;
}
/// <summary>
/// UnloadContent will be called once per game and is the place to unload
/// game-specific 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)
{
// Get input
KeyboardState keyboard = Keyboard.GetState();
GamePadState gamePad = GamePad.GetState(PlayerIndex.One);
// use game state
switch (currentGameState)
{
case GameState.GameMenu:
// Allows the game to exit
if (gamePad.Buttons.Back == ButtonState.Pressed ||
keyboard.IsKeyDown(Keys.Escape))
{
this.Exit();
}
if (gamePad.Buttons.Start == ButtonState.Pressed ||
keyboard.IsKeyDown(Keys.Enter))
{
// Start the player in the center along the bottom of the screen
characterPosition.X = (safeBounds.Width - characterTexture.Width) / 2;
characterPosition.Y = (safeBounds.Height - characterTexture.Height);
// Set the game state to play
currentGameState = GameState.GamePlay;
// Reset score
score = 0;
}
break;
case GameState.GameOver:
// If game is over, the game allows return to main menu if key A is pressed 
if (gamePad.Buttons.A == ButtonState.Pressed ||
keyboard.IsKeyDown(Keys.A))
{
currentGameState = GameState.GameMenu;
}
break;
case GameState.GamePlay:
// Press X during game play to return to main menu
if (gamePad.Buttons.X == ButtonState.Pressed ||
keyboard.IsKeyDown(Keys.X))
{
currentGameState = GameState.GameMenu;
}
// Press ESC to quit game during game play
if (gamePad.Buttons.Back == ButtonState.Pressed ||
keyboard.IsKeyDown(Keys.Escape))
{
this.Exit();
}
//Move the player left and right with arrow keys or d-pad
if (keyboard.IsKeyDown(Keys.Left) || gamePad.DPad.Left == ButtonState.Pressed)
{
characterPosition.X -= characterSpeed;
}
if (keyboard.IsKeyDown(Keys.Right) || gamePad.DPad.Right == ButtonState.Pressed)
{
characterPosition.X += characterSpeed;
}
// Prevent the character from moving off of the screen
characterPosition.X = MathHelper.Clamp(characterPosition.X,
safeBounds.Left, safeBounds.Right - characterTexture.Width);
// Get the bounding rectangle of the character
Rectangle characterRectangle =
new Rectangle((int)characterPosition.X, (int)characterPosition.Y,
characterTexture.Width, characterTexture.Height);
// Spawn new enemy
if (random.NextDouble() < enemySpawnProbability)
{
float x = (float)random.NextDouble() *
(Window.ClientBounds.Width - enemyTexture.Width);
enemyPositions.Add(new Vector2(x, -enemyTexture.Height));
// play the enemy spawn sound
enemySpawnSoundInstance.Play();
}
// Increase enemy speed as game progresses
enemySpeed += speedIncrement;
if (speed >= speedIncrement) speed = enemySpeed;
// Update each enemy
characterHit = false;
for (int i = 0; i < enemyPositions.Count; i++)
{
// Animate this enemy
enemyPositions[i] =
new Vector2(enemyPositions[i].X,
enemyPositions[i].Y + enemySpeed);
// Get the bounding rectangle of this enemy
Rectangle enemyRectangle =
new Rectangle((int)enemyPositions[i].X, (int)enemyPositions[i].Y,
enemyTexture.Width, enemyTexture.Height);
// Check collision with character
if (characterRectangle.Intersects(enemyRectangle))
characterHit = true;
// Remove this enemy if it has fallen off the screen
if (enemyPositions[i].Y > Window.ClientBounds.Height)
{
enemyPositions.RemoveAt(i);
// When removing an enemy, the next enemy will have the same index 
// as the current enemy. Decrement i to prevent skipping an enemy.
i--;
}
}
// Reset game if character has been hit
if (characterHit)
{
// check for highscore
if (score > highScore)
highScore = score;
// reset score to zero
score = 0;
// empty the enemies list
enemyPositions = new List<Vector2>();
// change color of enemies to indicate a new game
enemyColor = new Color(random.Next(0, 255), random.Next(0, 255), random.Next(0, 255));
// finish game by loading gameover screen
currentGameState = GameState.GameOver;
}
else
{
// update score (character has been hit)
score = score + 1;
}
// update on-screen information variables
scoreText = "SCORE: " + score.ToString();
highScoreText = "HIGH SCORE: " + highScore.ToString();
break;
}
base.Update(gameTime);
}
/// <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 device = graphics.GraphicsDevice;
// use game state
switch (currentGameState)
{
case GameState.GameMenu:                              // load game menu and clear once enter key is pressed
spriteBatch.Begin();
spriteBatch.Draw(backgroundTexture, Vector2.Zero, Color.White);
spriteBatch.DrawString(scoreFont, menuWelcome,
new Vector2((float)safeBounds.Right / 2 - scoreFont.MeasureString(menuWelcome).X / 3,
30), Color.DarkRed);
spriteBatch.DrawString(scoreFont, menuHowToPlay,
new Vector2((float)safeBounds.Right / 2 - scoreFont.MeasureString(menuHowToPlay).X / 4,
30), Color.DarkRed);
spriteBatch.End();
device.Clear(Color.DarkBlue);
break;
case GameState.GameOver:                          // load game menu and clear once escape is pressed
spriteBatch.Begin();
spriteBatch.Draw(backgroundTexture, Vector2.Zero, Color.White);
spriteBatch.DrawString(scoreFont, GameOverText,
new Vector2((float)safeBounds.Right / 2 - scoreFont.MeasureString(GameOverText).X / 3,
30), Color.DarkRed);
spriteBatch.DrawString(scoreFont, GameOverClose,
new Vector2((float)safeBounds.Right / 2 - scoreFont.MeasureString(GameOverClose).X / 4,
30), Color.DarkRed);
spriteBatch.End();
device.Clear(Color.DarkBlue);
break;
case GameState.GamePlay:                // load the sprite batch for main game play
// Open sprite batch
spriteBatch.Begin();
spriteBatch.End();
break;
}
device.Clear(Color.CornflowerBlue);
// "Open" the sprite batch
spriteBatch.Begin();
// Clear game screen with background colour
device.Clear(Color.DarkBlue);
// Draw background
spriteBatch.Draw(backgroundTexture, Vector2.Zero, Color.White);
// Draw character
spriteBatch.Draw(characterTexture, characterPosition, Color.White);
// Draw enemies
foreach (Vector2 enemyPosition in enemyPositions)
spriteBatch.Draw(enemyTexture, enemyPosition, enemyColor);
// Draw on-screen game information
spriteBatch.DrawString(scoreFont, scoreText, new Vector2(30, 30), Color.Black);
spriteBatch.DrawString(scoreFont, highScoreText,
new Vector2((float)safeBounds.Right - scoreFont.MeasureString(highScoreText).X,
30), Color.Black);
spriteBatch.DrawString(scoreFont, gameName,
new Vector2((float)safeBounds.Right / 2 - scoreFont.MeasureString(gameName).X / 2,
30), Color.Black);
spriteBatch.DrawString(scoreFont, aimText,
new Vector2((float)safeBounds.Right / 2 - scoreFont.MeasureString(gameName).X / 1,
60), Color.Black);
// "Close" the sprite batch
spriteBatch.End();
break;
base.Draw(gameTime);
}
}
}

游戏状态的绘制代码位于 switch 语句之外,因此会清空绘制的任何菜单或游戏精灵,并将游戏精灵绘制在顶部。这是由这段代码引起的:

case GameState.GamePlay:                // load the sprite batch for main game play
// Open sprite batch
spriteBatch.Begin();
spriteBatch.End();
break;
}

要解决此问题,您需要将游戏状态绘制代码移动到 switch 语句中,如下所示:

protected override void Draw(GameTime gameTime)
{
GraphicsDevice device = graphics.GraphicsDevice;
// use game state
switch (currentGameState)
{
case GameState.GameMenu:                              // load game menu and clear once enter key is pressed
device.Clear(Color.DarkBlue);
spriteBatch.Begin();
spriteBatch.Draw(backgroundTexture, Vector2.Zero, Color.White);
spriteBatch.DrawString(scoreFont, menuWelcome,
new Vector2((float)safeBounds.Right / 2 - scoreFont.MeasureString(menuWelcome).X / 3,
30), Color.DarkRed);
spriteBatch.DrawString(scoreFont, menuHowToPlay,
new Vector2((float)safeBounds.Right / 2 - scoreFont.MeasureString(menuHowToPlay).X / 4,
30), Color.DarkRed);
spriteBatch.End();
break;
case GameState.GameOver:                          // load game menu and clear once escape is pressed
device.Clear(Color.DarkBlue);
spriteBatch.Begin();
spriteBatch.Draw(backgroundTexture, Vector2.Zero, Color.White);
spriteBatch.DrawString(scoreFont, GameOverText,
new Vector2((float)safeBounds.Right / 2 - scoreFont.MeasureString(GameOverText).X / 3,
30), Color.DarkRed);
spriteBatch.DrawString(scoreFont, GameOverClose,
new Vector2((float)safeBounds.Right / 2 - scoreFont.MeasureString(GameOverClose).X / 4,
30), Color.DarkRed);
spriteBatch.End();
device.Clear(Color.DarkBlue);
break;
case GameState.GamePlay:                // load the sprite batch for main game play
device.Clear(Color.CornflowerBlue);
// Open sprite batch
spriteBatch.Begin();
// Draw background
spriteBatch.Draw(backgroundTexture, Vector2.Zero, Color.White);
// Draw character
spriteBatch.Draw(characterTexture, characterPosition, Color.White);
// Draw enemies
foreach (Vector2 enemyPosition in enemyPositions)
spriteBatch.Draw(enemyTexture, enemyPosition, enemyColor);
// Draw on-screen game information
spriteBatch.DrawString(scoreFont, scoreText, new Vector2(30, 30), Color.Black);
spriteBatch.DrawString(scoreFont, highScoreText,
new Vector2((float)safeBounds.Right - scoreFont.MeasureString(highScoreText).X,
30), Color.Black);
spriteBatch.DrawString(scoreFont, gameName,
new Vector2((float)safeBounds.Right / 2 - scoreFont.MeasureString(gameName).X / 2,
30), Color.Black);
spriteBatch.DrawString(scoreFont, aimText,
new Vector2((float)safeBounds.Right / 2 - scoreFont.MeasureString(gameName).X / 1,
60), Color.Black);
// "Close" the sprite batch
spriteBatch.End();
break;
}
base.Draw(gameTime);
}

以前,switch 语句中的游戏状态会创建一个空的精灵批处理并关闭 switch 语句,然后是游戏绘制代码。

在上面,我已将您的游戏绘制代码移至 switch 语句中(并将device.clear()语句移动到每个开关块的顶部以清楚起见(

最新更新