2014-10-02 18 views
0

我對XNA相對較新且缺乏經驗,我一直遵循Jamie McMahon的指南在C#中創建基本的突破遊戲(http://xnagpa.net/xna4beginner.php)。最近,我偶然發現了微軟的遊戲狀態管理代碼示例(http://xbox.create.msdn.com/en-US/education/catalog/sample/game_state_management),並一直試圖移動我的Breakout代碼,以便我可以使用代碼示例爲我提供的菜單。然而,每當我試圖啓動遊戲,我在spriteBatch.Begin得到一個NullReferenceException下面的代碼:spriteBatch.Begin正在獲取NullReferenceException

#region File Description 
//----------------------------------------------------------------------------- 
// GameplayScreen.cs 
// 
// Microsoft XNA Community Game Platform 
// Copyright (C) Microsoft Corporation. All rights reserved. 
//----------------------------------------------------------------------------- 
#endregion 

#region Using Statements 
using System; 
using System.Threading; 
using Microsoft.Xna.Framework; 
using Microsoft.Xna.Framework.Content; 
using Microsoft.Xna.Framework.Graphics; 
using Microsoft.Xna.Framework.Input; 
using GameStateManagement; 
using System.Collections.Generic; 
using System.Linq; 
using Microsoft.Xna.Framework.Audio; 
using Microsoft.Xna.Framework.GamerServices; 
using Microsoft.Xna.Framework.Media; 
#endregion 

namespace Rebound 
{ 
    /// <summary> 
    /// This screen implements the actual game logic. It is just a 
    /// placeholder to get the idea across: you'll probably want to 
    /// put some more interesting gameplay in here! 
    /// </summary> 
    public class GameplayScreen : GameScreen 
    { 
     #region Fields 

     ContentManager content; 
     SpriteFont gameFont; 
     GraphicsDeviceManager graphics; 
     SpriteBatch spriteBatch; 

     Ball ball; 
     Paddle paddle; 
     Rectangle screenRectangle; 

     int bricksWide = 10; 
     int bricksHigh = 5; 
     Texture2D brickImage; 
     Brick[,] bricks; 

     float pauseAlpha; 

     InputAction pauseAction; 

     #endregion 

     #region Initialization 


     /// <summary> 
     /// Constructor. 
     /// </summary> 

     public GameplayScreen() 
     { 
      graphics = new GraphicsDeviceManager(this); 
      Content.RootDirectory = "Content"; 

      graphics.PreferredBackBufferWidth = 800; 
      graphics.PreferredBackBufferHeight = 480; 

      screenRectangle = new Rectangle(
       0, 
       0, 
       graphics.PreferredBackBufferWidth, 
       graphics.PreferredBackBufferHeight); 

      TransitionOnTime = TimeSpan.FromSeconds(1.5); 
      TransitionOffTime = TimeSpan.FromSeconds(0.5); 

      pauseAction = new InputAction(
       new Buttons[] { Buttons.Start, Buttons.Back }, 
       new Keys[] { Keys.Escape }, 
       true); 
     } 

     protected override void Initialize() 
     { 
      // TODO: Add your initialization logic here 
      base.Initialize(); 
     } 

     /// <summary> 
     /// Load graphics content for the game. 
     /// </summary> 
     /// 
     protected override void LoadContent() 
     { 
      spriteBatch = new SpriteBatch(GraphicsDevice); 

       gameFont = Content.Load<SpriteFont>("gamefont"); 

       Texture2D tempTexture = Content.Load<Texture2D>("paddle"); 
       paddle = new Paddle(tempTexture, screenRectangle); 

       tempTexture = Content.Load<Texture2D>("ball"); 
       ball = new Ball(tempTexture, screenRectangle); 

       brickImage = Content.Load<Texture2D>("brick"); 

       StartGame(); 

       // once the load has finished, we use ResetElapsedTime to tell the game's 
       // timing mechanism that we have just finished a very long frame, and that 
       // it should not try to catch up. 
       ScreenManager.Game.ResetElapsedTime(); 
      base.LoadContent(); 
     } 

     private void StartGame() 
     { 
      paddle.SetInStartPosition(); 
      ball.SetInStartPosition(paddle.GetBounds()); 

      bricks = new Brick[bricksWide, bricksHigh]; 

      for (int y = 0; y < bricksHigh; y++) 
      { 
       Color tint = Color.White; 

       switch (y) 
       { 
        case 0: 
         tint = Color.Blue; 
         break; 
        case 1: 
         tint = Color.Red; 
         break; 
        case 2: 
         tint = Color.Green; 
         break; 
        case 3: 
         tint = Color.Yellow; 
         break; 
        case 4: 
         tint = Color.Purple; 
         break; 
       } 

       for (int x = 0; x < bricksWide; x++) 
       { 
        bricks[x, y] = new Brick(
         brickImage, 
         new Rectangle(
          x * brickImage.Width, 
          y * brickImage.Height, 
          brickImage.Width, 
          brickImage.Height), 
         tint); 
       } 
      } 
     } 

     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> 


     #endregion 

     #region Update and Draw 


     /// <summary> 
     /// Updates the state of the game. This method checks the GameScreen.IsActive 
     /// property, so the game will stop updating when the pause menu is active, 
     /// or if you tab away to a different application. 
     /// </summary> 
     public override void Update(GameTime gameTime, bool otherScreenHasFocus, 
                 bool coveredByOtherScreen) 
     { 
      base.Update(gameTime, otherScreenHasFocus, false); 

      // Gradually fade in or out depending on whether we are covered by the pause screen. 
      if (coveredByOtherScreen) 
       pauseAlpha = Math.Min(pauseAlpha + 1f/32, 1); 
      else 
       pauseAlpha = Math.Max(pauseAlpha - 1f/32, 0); 

      if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed) 

       this.Exit(); 

      paddle.Update(); 
      ball.Update(); 

      foreach (Brick brick in bricks) 
      { 
       brick.CheckCollision(ball); 
      } 

      ball.PaddleCollision(paddle.GetBounds()); 

      if (ball.OffBottom()) 
       StartGame(); 

      base.Update(gameTime, otherScreenHasFocus, coveredByOtherScreen); 
     } 

     /// <summary> 
     /// Draws the gameplay screen. 
     /// </summary> 
     public override void Draw(GameTime gameTime) 
     { 
      // This game has a blue background. Why? Because! 
      ScreenManager.GraphicsDevice.Clear(ClearOptions.Target, 
               Color.CornflowerBlue, 0, 0); 
      spriteBatch.Begin(); 

      foreach (Brick brick in bricks) 
       brick.Draw(spriteBatch); 

      paddle.Draw(spriteBatch); 
      ball.Draw(spriteBatch); 

      spriteBatch.End(); 

      base.Draw(gameTime); 

      // If the game is transitioning on or off, fade it out to black. 
      if (TransitionPosition > 0 || pauseAlpha > 0) 
      { 
       float alpha = MathHelper.Lerp(1f - TransitionAlpha, 1f, pauseAlpha/2); 

       ScreenManager.FadeBackBufferToBlack(alpha); 
      } 
     } 


     #endregion 
    } 
} 

所以我要去哪裏錯了嗎?我對這個錯誤做了一些研究,沒有任何解決方案幫助我解決問題。隨意指出我的代碼中的任何其他冗餘/錯誤,因爲我對這類事情極其缺乏經驗。謝謝!

編輯:從微軟的GameStateManagement代碼示例中添加原始的GameplayScreen.cs和我試圖與它合併的Breakout遊戲代碼。如果有人知道這樣做的簡單方法,我很樂意聽取他們的建議。

突圍遊戲代碼:從微軟的代碼示例

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

namespace Rebound 
{ 
    /// <summary> 
    /// This is the main type for your game 
    /// </summary> 
    public class Game1 : Microsoft.Xna.Framework.Game 
    { 
     GraphicsDeviceManager graphics; 
     SpriteBatch spriteBatch; 

     Ball ball; 
     Paddle paddle; 
     Rectangle screenRectangle; 

     int bricksWide = 10; 
     int bricksHigh = 5; 
     Texture2D brickImage; 
     Brick[,] bricks; 

     public Game1() 
     { 
      graphics = new GraphicsDeviceManager(this); 
      Content.RootDirectory = "Content"; 

      graphics.PreferredBackBufferWidth = 750; 
      graphics.PreferredBackBufferHeight = 600; 

      screenRectangle = new Rectangle(
       0, 
       0, 
       graphics.PreferredBackBufferWidth, 
       graphics.PreferredBackBufferHeight); 
     } 

     /// <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 

      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); 

      Texture2D tempTexture = Content.Load<Texture2D>("paddle"); 
      paddle = new Paddle(tempTexture, screenRectangle); 

      tempTexture = Content.Load<Texture2D>("ball"); 
      ball = new Ball(tempTexture, screenRectangle); 

      brickImage = Content.Load<Texture2D>("brick"); 

      StartGame(); 
     } 

     private void StartGame() 
     { 
      paddle.SetInStartPosition(); 
      ball.SetInStartPosition(paddle.GetBounds()); 

      bricks = new Brick[bricksWide, bricksHigh]; 

      for (int y = 0; y < bricksHigh; y++) 
      { 
       Color tint = Color.White; 

       switch (y) 
       { 
        case 0: 
         tint = Color.Blue; 
         break; 
        case 1: 
         tint = Color.Red; 
         break; 
        case 2: 
         tint = Color.Green; 
         break; 
        case 3: 
         tint = Color.Yellow; 
         break; 
        case 4: 
         tint = Color.Purple; 
         break; 
       } 

       for (int x = 0; x < bricksWide; x++) 
       { 
        bricks[x, y] = new Brick(
         brickImage, 
         new Rectangle(
          x * brickImage.Width, 
          y * brickImage.Height, 
          brickImage.Width, 
          brickImage.Height), 
         tint); 
       } 
      } 
     } 

     /// <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(); 

      paddle.Update(); 
      ball.Update(); 

      foreach (Brick brick in bricks) 
      { 
       brick.CheckCollision(ball); 
      } 

      ball.PaddleCollision(paddle.GetBounds()); 

      if (ball.OffBottom()) 
       StartGame(); 

      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.Clear(Color.CornflowerBlue); 

      spriteBatch.Begin(); 

      foreach (Brick brick in bricks) 
       brick.Draw(spriteBatch); 

      paddle.Draw(spriteBatch); 
      ball.Draw(spriteBatch); 

      spriteBatch.End(); 

      base.Draw(gameTime); 
     } 
    } 
} 

原始GameplayScreen.cs:

#region File Description 
//----------------------------------------------------------------------------- 
// GameplayScreen.cs 
// 
// Microsoft XNA Community Game Platform 
// Copyright (C) Microsoft Corporation. All rights reserved. 
//----------------------------------------------------------------------------- 
#endregion 

#region Using Statements 
using System; 
using System.Threading; 
using Microsoft.Xna.Framework; 
using Microsoft.Xna.Framework.Content; 
using Microsoft.Xna.Framework.Graphics; 
using Microsoft.Xna.Framework.Input; 
using GameStateManagement; 
#endregion 

namespace GameStateManagementSample 
{ 
    /// <summary> 
    /// This screen implements the actual game logic. It is just a 
    /// placeholder to get the idea across: you'll probably want to 
    /// put some more interesting gameplay in here! 
    /// </summary> 
    class GameplayScreen : GameScreen 
    { 
     #region Fields 

     ContentManager content; 
     SpriteFont gameFont; 

     Vector2 playerPosition = new Vector2(100, 100); 
     Vector2 enemyPosition = new Vector2(100, 100); 

     Random random = new Random(); 

     float pauseAlpha; 

     InputAction pauseAction; 

     #endregion 

     #region Initialization 


     /// <summary> 
     /// Constructor. 
     /// </summary> 
     public GameplayScreen() 
     { 
      TransitionOnTime = TimeSpan.FromSeconds(1.5); 
      TransitionOffTime = TimeSpan.FromSeconds(0.5); 

      pauseAction = new InputAction(
       new Buttons[] { Buttons.Start, Buttons.Back }, 
       new Keys[] { Keys.Escape }, 
       true); 
     } 


     /// <summary> 
     /// Load graphics content for the game. 
     /// </summary> 
     public override void Activate(bool instancePreserved) 
     { 
      if (!instancePreserved) 
      { 
       if (content == null) 
        content = new ContentManager(ScreenManager.Game.Services, "Content"); 

       gameFont = content.Load<SpriteFont>("gamefont"); 

       // A real game would probably have more content than this sample, so 
       // it would take longer to load. We simulate that by delaying for a 
       // while, giving you a chance to admire the beautiful loading screen. 
       Thread.Sleep(1000); 

       // once the load has finished, we use ResetElapsedTime to tell the game's 
       // timing mechanism that we have just finished a very long frame, and that 
       // it should not try to catch up. 
       ScreenManager.Game.ResetElapsedTime(); 
      } 

#if WINDOWS_PHONE 
      if (Microsoft.Phone.Shell.PhoneApplicationService.Current.State.ContainsKey("PlayerPosition")) 
      { 
       playerPosition = (Vector2)Microsoft.Phone.Shell.PhoneApplicationService.Current.State["PlayerPosition"]; 
       enemyPosition = (Vector2)Microsoft.Phone.Shell.PhoneApplicationService.Current.State["EnemyPosition"]; 
      } 
#endif 
     } 


     public override void Deactivate() 
     { 
#if WINDOWS_PHONE 
      Microsoft.Phone.Shell.PhoneApplicationService.Current.State["PlayerPosition"] = playerPosition; 
      Microsoft.Phone.Shell.PhoneApplicationService.Current.State["EnemyPosition"] = enemyPosition; 
#endif 

      base.Deactivate(); 
     } 


     /// <summary> 
     /// Unload graphics content used by the game. 
     /// </summary> 
     public override void Unload() 
     { 
      content.Unload(); 

#if WINDOWS_PHONE 
      Microsoft.Phone.Shell.PhoneApplicationService.Current.State.Remove("PlayerPosition"); 
      Microsoft.Phone.Shell.PhoneApplicationService.Current.State.Remove("EnemyPosition"); 
#endif 
     } 


     #endregion 

     #region Update and Draw 


     /// <summary> 
     /// Updates the state of the game. This method checks the GameScreen.IsActive 
     /// property, so the game will stop updating when the pause menu is active, 
     /// or if you tab away to a different application. 
     /// </summary> 
     public override void Update(GameTime gameTime, bool otherScreenHasFocus, 
                 bool coveredByOtherScreen) 
     { 
      base.Update(gameTime, otherScreenHasFocus, false); 

      // Gradually fade in or out depending on whether we are covered by the pause screen. 
      if (coveredByOtherScreen) 
       pauseAlpha = Math.Min(pauseAlpha + 1f/32, 1); 
      else 
       pauseAlpha = Math.Max(pauseAlpha - 1f/32, 0); 

      if (IsActive) 
      { 
       // Apply some random jitter to make the enemy move around. 
       const float randomization = 10; 

       enemyPosition.X += (float)(random.NextDouble() - 0.5) * randomization; 
       enemyPosition.Y += (float)(random.NextDouble() - 0.5) * randomization; 

       // Apply a stabilizing force to stop the enemy moving off the screen. 
       Vector2 targetPosition = new Vector2(
        ScreenManager.GraphicsDevice.Viewport.Width/2 - gameFont.MeasureString("Insert Gameplay Here").X/2, 
        200); 

       enemyPosition = Vector2.Lerp(enemyPosition, targetPosition, 0.05f); 

       // TODO: this game isn't very fun! You could probably improve 
       // it by inserting something more interesting in this space :-) 
      } 
     } 


     /// <summary> 
     /// Lets the game respond to player input. Unlike the Update method, 
     /// this will only be called when the gameplay screen is active. 
     /// </summary> 
     public override void HandleInput(GameTime gameTime, InputState input) 
     { 
      if (input == null) 
       throw new ArgumentNullException("input"); 

      // Look up inputs for the active player profile. 
      int playerIndex = (int)ControllingPlayer.Value; 

      KeyboardState keyboardState = input.CurrentKeyboardStates[playerIndex]; 
      GamePadState gamePadState = input.CurrentGamePadStates[playerIndex]; 

      // The game pauses either if the user presses the pause button, or if 
      // they unplug the active gamepad. This requires us to keep track of 
      // whether a gamepad was ever plugged in, because we don't want to pause 
      // on PC if they are playing with a keyboard and have no gamepad at all! 
      bool gamePadDisconnected = !gamePadState.IsConnected && 
             input.GamePadWasConnected[playerIndex]; 

      PlayerIndex player; 
      if (pauseAction.Evaluate(input, ControllingPlayer, out player) || gamePadDisconnected) 
      { 
#if WINDOWS_PHONE 
       ScreenManager.AddScreen(new PhonePauseScreen(), ControllingPlayer); 
#else 
       ScreenManager.AddScreen(new PauseMenuScreen(), ControllingPlayer); 
#endif 
      } 
      else 
      { 
       // Otherwise move the player position. 
       Vector2 movement = Vector2.Zero; 

       if (keyboardState.IsKeyDown(Keys.Left)) 
        movement.X--; 

       if (keyboardState.IsKeyDown(Keys.Right)) 
        movement.X++; 

       if (keyboardState.IsKeyDown(Keys.Up)) 
        movement.Y--; 

       if (keyboardState.IsKeyDown(Keys.Down)) 
        movement.Y++; 

       Vector2 thumbstick = gamePadState.ThumbSticks.Left; 

       movement.X += thumbstick.X; 
       movement.Y -= thumbstick.Y; 

       if (input.TouchState.Count > 0) 
       { 
        Vector2 touchPosition = input.TouchState[0].Position; 
        Vector2 direction = touchPosition - playerPosition; 
        direction.Normalize(); 
        movement += direction; 
       } 

       if (movement.Length() > 1) 
        movement.Normalize(); 

       playerPosition += movement * 8f; 
      } 
     } 


     /// <summary> 
     /// Draws the gameplay screen. 
     /// </summary> 
     public override void Draw(GameTime gameTime) 
     { 
      // This game has a blue background. Why? Because! 
      ScreenManager.GraphicsDevice.Clear(ClearOptions.Target, 
               Color.CornflowerBlue, 0, 0); 

      // Our player and enemy are both actually just text strings. 
      SpriteBatch spriteBatch = ScreenManager.SpriteBatch; 

      spriteBatch.Begin(); 

      spriteBatch.DrawString(gameFont, "// TODO", playerPosition, Color.Green); 

      spriteBatch.DrawString(gameFont, "Insert Gameplay Here", 
            enemyPosition, Color.DarkRed); 

      spriteBatch.End(); 

      // If the game is transitioning on or off, fade it out to black. 
      if (TransitionPosition > 0 || pauseAlpha > 0) 
      { 
       float alpha = MathHelper.Lerp(1f - TransitionAlpha, 1f, pauseAlpha/2); 

       ScreenManager.FadeBackBufferToBlack(alpha); 
      } 
     } 


     #endregion 
    } 
} 
+0

[什麼是NullReferenceException,我該如何解決它?](http://stackoverflow.com/questions/4660142/what-is-a-nullreferenceexception-and-how-do-i-fix-it) – 2014-10-02 08:32:11

+0

我相當肯定我已經初始化了spriteBatch,但我完全不知道它是如何變爲null的。 – 2014-10-02 09:00:11

+0

噢,我想知道是否通過顯示上面的代碼來打破_Microsoft許可許可(Ms-PL)_? – MickyD 2014-10-02 11:17:12

回答

0

您在LoadContent初始化spriteBatch。在你做任何事情之前,你確定你正在運行GamePlayScreen.Loadcontent()嗎?也許你可以向我們展示你使用這個GameScreen對象的類。另一方面,您可以將主類中的SpriteBatch對象傳遞給GameScreen的繪製方法。

public void Draw(GameTime gameTime, SpriteBatch spritebatch) 
{ 
} 

//In the main class (Game1) you can use draw like this: 

gameScreen.Draw(gameTime, spritebatch); 

此外,我從未在我的繪製方法中使用GameTime。 GameTime afaik用於更新邏輯,在Update方法中。我感覺你正在創造一些混亂。剛開始,也許是一個更簡單的教程開始。 gameScreen需要基本的繼承知識。當你想了解更多關於遊戲屏幕管理的信息時,我建議先了解一些關於繼承的內容。

+0

作者:GameScreen你的意思是GameplayScreen?另外,Breakout教程說要將GameTime添加到Draw方法中。 我已經能夠按照教程創建一個成功的突破遊戲,並且我正在嘗試將遊戲代碼與Microsoft的Game State Management代碼示例合併,以便我可以擁有漂亮的菜單。我將使用原始的Breakout遊戲代碼和Microsoft代碼示例中的原始GameplayScreen.cs更新OP。我真的只需要合併這兩個,所以如果你知道一個更流暢的方式來做到這一點,我將非常感激,如果你能幫助我。 – 2014-10-02 12:49:06

0

你似乎沒有在你的代碼中的激活方法(除非我只是錯過了它)。 從內存中,這是從屏幕管理器實際調用的方法。覆蓋此方法,並從那裏調用您的loadcontent方法。 此外 - 你不應該需要重新創建你的spritebatch。我相當確定屏幕管理器有一個引用它 - 所以相反,你應該沿着this.spritebatch = ScreenManager.Spritebatch行;

再一次 - 這是從記憶中,我可以稍後再次更新,一旦我回家,可以引用我自己的項目。

0

您是否先添加紋理文件?因爲如果沒有,那就是爲什麼它會給出一個空例外......因爲它無法找到並加載紋理文件。

相關問題