如何在这样的结构中访问列表位置的C#Dictionary的List <class>值,这是一个类?

时间:2016-10-21 15:39:58

标签: c# class dictionary unity3d state-machine

我还是一个新的程序员,学习如何做到。必须承认我尝试了很多方法,但仍然没有前进。这段代码可能有点复杂,所以试图告诉你它是如何构造的。 我想访问我在状态机状态中为状态创建的字典,这是一个类的实例。 我设计了它,所以我在课堂上有一个状态(玩家可以切换状态),每个州都持有州名,描述,bool是否有敌人,敌人字典(数字和种族列表),以及bool是否有非 - 玩家角色。

添加了一些代码,以便您可以了解它的运行方式/结构。

在添加怪物之前机器工作得很好,现在我按下播放后我得到错误:“NullReferenceException:对象引用未设置为对象的实例 StateController.GetTransitionsAndActions()(在Assets / _Scripts / GameRPG / StateMachines / StateController.cs:169) StateController.Start()(在Assets / _Scripts / GameRPG / StateMachines / StateController.cs:131)“ ......威尔指着国家控制员:Monobehaviour剧本中的那一行:

Debug.Log ("monster.name: " + monster.name);

请记住,我只向您展示我的部分脚本,但应该足以在Unity控制台中调试输出。

public class FunMachine : IStateMachine
{

    List<FunMachineState> mStates;
    FunMachineState mCurrent;
    FunMachineState mExit;
    List <Monster> monsterList = new List<Monster> ();

    public FunMachine()
    {       
        List <Monster> monsterList = new List<Monster> ();
        MonsterManualVol1 monsterManualVol1 = new MonsterManualVol1 (monsterList);

        FunMachineState entryHall = new FunMachineState("Grand Entrance", "You are standing in a grand enterance of a castle.\nThere are tables and chairs, but nothing you can interact with.", "Enter the Grand Entrance", true, new Dictionary<int, Monster> (){{7, monsterList.Find(x => x.name.Contains("orc"))}}, false);
        // (...) many other similar states here
    }

    // Hook up doors.
    entryHall.Neighbors.Add(staircase);
    entryHall.Neighbors.Add(mExit);
    // Add them to the collection
    mStates = new List<FunMachineState>();
    mStates.Add(entryHall);
    // Finally set my starting point
    mCurrent = entryHall;

    #region IStateMachine Overrides
    public override IState CurrentState
    {
        get { return mCurrent; }
    }

    public override List<FunMachineState> PossibleTransitions()
    {
        List<FunMachineState> transitionResult = mCurrent.Neighbors;
        return transitionResult = mCurrent.Neighbors;
    }

    public override Dictionary<int, Monster> GetStateMonsters ()
{
    Dictionary<int, Monster> result = new Dictionary<int, Monster> ();
    List <Monster> monsterList = new List<Monster> ();
    MonsterManualVol1 monsterManualVol1 = new MonsterManualVol1 (monsterList);

    result = mCurrent.Monsters;
    return result;
    }

    // (...) more code
}

FunMachineState:

public class FunMachineState : IState
{
    string mName;
    string mDescription;
    string mPlayerChoiceButtonText;
    bool mEnemies;
    bool mNpcs;
    Dictionary<int, Monster> mEnemyDictionary;

    List<FunMachineState> mNeighbors = new List<FunMachineState>();
    public List<FunMachineState> Neighbors { get { return mNeighbors; } }

    public Dictionary <int, Monster> Monsters { get { return mEnemyDictionary; } }

    public FunMachineState(string mName, string mDescription, string mPlayerChoiceButtonText, bool mEnemies, Dictionary<int, Monster> mEnemyDictionary, bool mNpcs)
    {
        this.mName = mName;
        this.mDescription = mDescription;
        this.mPlayerChoiceButtonText = mPlayerChoiceButtonText;
        this.mEnemies = mEnemies;
        this.mEnemyDictionary = mEnemyDictionary;
        this.mNpcs = mNpcs;
    }

    #region IState Overrides
    public override string GetName()
    {
        Debug.Log ("Here mName runs!");
        return mName;   
    }

   public override string GetStateDescriptionText()
   {
        return mDescription;
   }

    public override Dictionary<int, Monster> GetStateMonsters()
    {
        return Monsters;
    }
    // (...) more code
}

IStateMachine:

public abstract class IStateMachine
{
    // List of all possible transitions we can make from this current state.
    public abstract List<FunMachineState> PossibleTransitions();
    // Get those monsters.
    public abstract Dictionary<int, Monster> GetStateMonsters ();
    // (...) more code
}

即将状态置:

public abstract class IState
{
    public abstract Dictionary<int, Monster> GetStateMonsters ();
    // Do something
    public abstract void Run();
    // (...) more code
}

现在运行它:

public class StateController : MonoBehaviour
{
    public StateController stateController;
    IStateMachine machine = GetMachine();

    private static IStateMachine GetMachine()
    {
        IStateMachine machine = null;
        machine = new FunMachine();
        return machine;
    }

    void Start()
    {

        if (!machine.IsComplete())
        {
            Debug.Log("Currently in " + machine.CurrentState);
            machine.CurrentState.Run();
            Text_main_game_content.text = machine.CurrentState.GetStateDescriptionText();
        GetTransitionsAndActions ();
        }

        public void GetTransitionsAndActions(){
        Dictionary<int, Monster> monsterlisting = machine.CurrentState.GetStateMonsters();

            if (monsterlisting.Values.Count > 0)
            foreach (var monster in monsterlisting.Values) {
            Debug.Log ("monster.name: " + monster.name);
            }
        }
    }
    // (...) more code
}

我的怪物收藏:

public class Monster
{
    public string name, description;
    public bool hostile;
    public int hitPoints;
    public int damage;
    public int loot;
    public string coin_type;

    public Monster (string c_name, string c_description, bool c_hostile, int c_hitPoints, int c_damage, int c_loot, string c_coin_type)
    {
        name = c_name;
        description = c_description;
        hostile = c_hostile;
        loot = c_loot;
        hitPoints = c_hitPoints;
        coin_type = c_coin_type;
        damage = c_damage;          
    }
}

public class MonsterManualVol1 
{

    public MonsterManualVol1 (List <Monster> c_monsterList) 
    {
        List <Monster> monsterList = new List<Monster> ();
        monsterList = c_monsterList;
        monsterList.Add (goblin);
        monsterList.Add (orc);
    }
    Monster goblin = new Monster("Goblin", "Cute goblin", true, 7, 5, 28, "sz");
    Monster orc = new Monster("Orc", "Pretty orc", true, 6, 6, 20, "sz");
}

我真的不知道发生了什么事。试图将该字典转换为列表,但也没有用。

哦,这可以在状态机启动时正确调试。除了公共类FunMachine:IStateMachine:

public class FunMachine : IStateMachine
{       

    public override List<Monster> MonsterListDebug () {
        monsterList = new List<Monster> ();
        MonsterManualVol1 monsterManualVol1 = new MonsterManualVol1 (monsterList);
        Debug.Log ("monsterList.Count: " + monsterList.Count);

        for (int i = 0; i < monsterList.Count; i++)
        {
            Debug.Log ("Monster name: " + monsterList [i].name +
                " Monster description: " + monsterList [i].description +
                " Monster hostility: " + monsterList [i].hostile +
                " Monster hit points: " + monsterList [i].hitPoints + 
                " Monster hit damage: " + monsterList [i].damage + 
                " Monster hit loot: " + monsterList [i].loot + " " + monsterList [i].coin_type);
        }
        return monsterList;
    }

   public FunMachine()
   {
   // (...)
   //MonsterListDebug (monsterList);    
    MonsterListDebug ();    
   // (...)
   }
// (...)
}

我无法从StateController中的实际CurrentState调试它,它正确地运行游戏。调试仅适用于FunMachine类,如上所示。 StateController中的Foreach循环会删除空引用,这是唯一的问题。 Monodevelop没有显示错误。

2 个答案:

答案 0 :(得分:2)

修改

  

好的伙计......我解决了这个问题。 ......我寻找“兽人”,而它只是“兽人”......就是这样。

呃,不太好。你找到了一种诱导bug的方法。你还没有解决问题。

解决方案不是:

  • 只需输入正确的字符串
  • 即可
  • 实施不区分大小写的名称搜索

我应该可以搜索“Yabadabadoo”而不是NullReferenceException

KMussa的答案得到了解决。 Dictionary<int, Monster>应该处理空值。修复分为两部分:

  • 第1部分
    • 不要实例化类级别和局部变量。
    • 我认为您在该方法中的意图是:monsterlist.Clear()
  • 第2部分

执行第2部分的最佳方法是编写自定义的“MonsterCollection”或“MonsterDictionary”类。然后最简单的修复方法是拒绝空值的Add()方法。

如果两个部分都没有完成,问题就无法解决。

结束修改

更简单,更清洁的调试。

移动这个......

"Monster name: " + monsterList [i].name +
            " Monster description: " + monsterList [i].description +
            " Monster hostility: " + monsterList [i].hostile +
            " Monster hit points: " + monsterList [i].hitDice + 
            " Monster hit damage: " + monsterList [i].damage + 
            " Monster hit loot: " + monsterList [i].loot + " " + monsterList 

...转到Monster并覆盖ToString。然后:

for (int i = 0; i < monsterList.Count; i++)
    {
        Debug.Log (monsterList[i].ToString());
    }
    return monsterList;

......甚至更好,也会覆盖ToString中的MonsterManualVol1,然后for循环就消失了,你就离开了:

Debug.Log(monsterList.ToString());

ToString写一个StateController。当然,这还包括为其属性调用ToString

实际上,为所有类编写ToString并真正清理日志代码。

不需要在构造函数中初始化和设置属性:

public class FunMachine : IStateMachine
{
  List <Monster> monsterList = new List<Monster> ();

  public FunMachine()
  {       
    List <Monster> monsterList = new List<Monster> ();        
  }

测试null的字符串参数:

public Monster (string c_name, ...)
{
    name = c_name; // could be null
    // so:
    name = c_name ?? string.Empty;

在Visual Studio中,您是否有Debug |例外......设置?

答案 1 :(得分:2)

很难遵循确切的流程,但我的猜测是问题出在这一部分:

List <Monster> monsterList = new List<Monster> ();

public FunMachine()
{       
    List <Monster> monsterList = new List<Monster> ();

    FunMachineState entryHall = new FunMachineState("...", "...", "...", true, 
       new Dictionary<int, Monster> (){{7, monsterList.Find(x => x.name.Contains("orc"))}}, false);
//...
}

具体来说,您在构造函数中声明了一个名为monsterList类变量和另一个具有相同名称的局部变量 - 在该阶段,两个列表都将是空,所以当你致电monsterList.Find(x => x.name.Contains("orc"))时,你会回来NULL;然后你的字典有一个key = 7和value = null

的项目

您稍后尝试遍历字典条目并打印怪物名称并获得NullReferenceException