即使我使用变量,也会出现空错误

时间:2016-02-12 07:20:41

标签: c# nullpointerexception xna monogame

我正在尝试学习MonoGame而我正在尝试做基本的事情,而且我已经自己想出了大部分内容但是我得到了一个空指针而且我&# 39;我不知道为什么。我试图让MainMenuScene只绘制一个纹理,但在SceneManager中,currentScene一直给我空指针,我不明白为什么。发布我的SceneManager代码,但其余的将在github上。它的代码不多,所以如果你不看它就不应该花很长时间。我非常困惑,我不知道该怎么去谷歌试图弄清楚自己。

info here

using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Tutorial.Scenes;

class SceneManager
{
    private static SceneManager instance = new SceneManager();
    Scene currentScene, newScene;

    Dictionary<string, Scene> sceneDirectory =new Dictionary<string, Scene>();

    public static SceneManager getInstance()
    {
        return instance;
    }

    public static Scene getCurrentScene()
    {
        return instance.currentScene;
    }

    public static void changeScene(Scene scene)
    {

    }

    public static void addScene(string sceneName)
    {
        instance.newScene = instance.sceneDirectory[sceneName];
    }

    public void update() { currentScene.Update(); }
    public void draw(SpriteBatch spriteBatch) { currentScene.Draw(spriteBatch); }

    public void Initialize()
    {
        instance.sceneDirectory["MainMenuScene"] = new MainMenuScene();

        instance.currentScene = instance.sceneDirectory["MainMenuScene"];
    }

    public void LoadContent(ContentManager content)
    {
        instance.currentScene.LoadContent(content);
    }

    public void UnloadContent()
    {
        instance.currentScene.UnloadContent();
    }
}

2 个答案:

答案 0 :(得分:0)

您已将Scene声明为抽象类,因此您不能像以前一样使用它:Scene currentScene, newScene。 (有关抽象类的更多详细信息,请参阅this参考)。

要么使场景成为非抽象类类型,要么创建另一个继承自抽象类的类,查看代码就像:

public class myScene : Scene
  {
      public override void Update()
     {
         //do something
     }

     // etc.

   }

答案 1 :(得分:0)

您收到NullReferenceException,因为您在代码中混合了静态和实例字段:

有几个问题:

  1. 您的SceneManager公开构造函数,但其​​实例方法都访问相同的静态(单例)实例。

  2. 您的SceneManager.Draw方法访问静态实例。

  3. 您的Game类实例化了一个单独的 ScreenManager实例,这意味着单例已初始化,但Game的实例并非如此。由于1,这是允许的。

  4. 有几种解决方法:

    首选方式:从SceneManager中移除静态内容。无论如何,你的游戏将在Game类中拥有一个实例,你可以简单地将实例传递给任何场景。没问题。

    但是,如果你想让这个班级成为一个单身人士,你需要改变一些事情。人们通常想要这个,因为他们懒得将SceneManager传递给每个场景实例。所以,单身人士很糟糕,你无法对任何事情进行单元测试,但我相信大多数独立游戏开发者都不太关心单元测试,如果一切都是静态的,并且可以从任何地方访问,那将是最快乐的。

    1. 创建构造函数private,这样其他类(如Game)就无法实例化它。如果有人想要访问该实例,他们应该通过getInstance()方法来实现。哪个,顺便说一句,可能更适合作为财产:

      public class SceneManager
      {
           // private constructor means other classes cannot instantiate this
           private SceneManager() { }
      
           private static readonly SceneManager _instance = new SceneManager();
           public static SceneManager Instance
           { 
               get { return _instance; }
           }
      }
      

      如果您现在尝试在Game课程中解决此问题:

      var sceneManager = new SceneManager();
      

      你的编译器会告诉你它不会那样工作。

    2. 您的SceneManager应该只有单个静态方法/属性:getInstance()Instance属性,如上所示。所有其他方法应该是该唯一实例的实例方法,而根本不访问instance字段。无论如何,他们正在访问该实例。让实例方法访问静态字段是个坏主意:

      错误

      public void Initialize()
      {
           var mainScene = = new MainMenuScene();
           instance.sceneDirectory["MainMenuScene"] = mainScene;
           instance.currentScene = mainScene;
      }
      

      但这很好(当然this关键字是多余的):

      public void Initialize()
      {
           var mainScene = = new MainMenuScene();
           this.sceneDirectory["MainMenuScene"] = mainScene;
           this.currentScene = mainScene;
      }
      

      因为无论如何你都会这样使用它:

      // you're basically doing the same thing, but
      // it's immediately clear what's going on, and there
      // is no room for errors:
      
      var manager = SceneManager.Instance;
      manager.Initialize();
      

      确保您正确删除instance类内SceneManager所有引用的最简单方法。