繁体   English   中英

如何最好地为C#monogame Visual Studio创建经过的计时器和暂停状态

[英]How best to create an elapsed time timer and pause state for C# monogame visual studio

我有一个用VS制作的C#单机游戏(下面的代码),想要添加一个计时器,以便游戏记录经过的时间,当您用角色击中敌人时重置计时器,如果按P则暂停时间。

当游戏暂停时,我想要一个带有“游戏暂停”的蓝色窗口,您可以在其中再次按P来返回游戏状态,并从上次中断的位置继续。

我已经为GamePause状态添加了枚举器

码:

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,
            GamePause = 3,
        }
        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 menuClose = "Press ESC To Quit Game.";
        string GameOverText = "Game Over";
        string GameOverClose = "Press A To Start New Game";
        string GameMainMenu = "Press X To Return To Main Menu";
        string GameHowToPause = "Press P To Pause 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");

            // create the song
            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
                    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 / 6,
                        30), Color.DarkRed);
                    spriteBatch.DrawString(scoreFont, menuHowToPlay,
                        new Vector2((float)safeBounds.Right / 2 - scoreFont.MeasureString(menuHowToPlay).X / 6,
                        50), Color.DarkRed);
                    spriteBatch.DrawString(scoreFont, menuClose,
                        new Vector2((float)safeBounds.Right / 2 - scoreFont.MeasureString(menuClose).X / 6,
                        70), Color.DarkRed);
                    spriteBatch.End();
                    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 / 2,
                        10), Color.DarkRed);
                    spriteBatch.DrawString(scoreFont, GameOverClose,
                        new Vector2((float)safeBounds.Right / 2 - scoreFont.MeasureString(GameOverClose).X / 2,
                        30), Color.DarkRed);
                    spriteBatch.DrawString(scoreFont, highScoreText,
                        new Vector2((float)safeBounds.Right - scoreFont.MeasureString(highScoreText).X / 1,
                        30), Color.Black);
                    spriteBatch.End();
                    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 / 1,
                        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);
                    spriteBatch.DrawString(scoreFont, GameHowToPause,
                        new Vector2((float)safeBounds.Right / 2 - scoreFont.MeasureString(gameName).X / 1,
                        80), Color.Black);
                    spriteBatch.DrawString(scoreFont, menuClose,
                        new Vector2((float)safeBounds.Right / 2 - scoreFont.MeasureString(gameName).X / 1,
                        100), Color.Black);
                    spriteBatch.DrawString(scoreFont, GameMainMenu,
                        new Vector2((float)safeBounds.Right / 2 - scoreFont.MeasureString(gameName).X / 1,
                        120), Color.Black);

                    // "Close" the sprite batch
                    spriteBatch.End();
                    break;
            }
            base.Draw(gameTime);
        }
    }
}

那是很多代码。 但是,为了笼统地回答您的问题,在将时间存储为变量然后在update方法中对其进行检查时,在游戏框架(如MonoGame)中维护计时器通常是最容易的。

例如(未测试):

DateTime _timeElapsed;
TimeSpan _timePaused;
DateTime? _pauseStart;

protected override void Update(GameTime gameTime)
{
    ...
           if (keyboard.IsKeyDown(Keys.P))
           {
              if (_isPaused)
              {
                  _timePaused += DateTime.Now - _pauseStart;
                  _pauseStart = null;
              }
              else
              {
                  _pauseStart = DateTime.Now;
              }
           }

pm_2已经掩盖了大多数答案,但是我想提供一个使用gameTime参数的替代解决方案:

int timeElapsed = 0;

protected override void Update(GameTime gameTime)
{
    //...
    if (keyboard.IsKeyDown(Keys.P))
    {
       isPaused = !isPaused;
    }
    if (!isPaused)
    {
        timeElapsed += gameTime.ElapsedGameTime.Milliseconds;
        //code when the game isn't paused.
    }
    else
    {
        //code when the game is paused.
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM