找不到默认构造函数

Default constructor not found

我正在为我的游戏制作一个有限状态机:

using UnityEngine;
using System;
public class StateMachine : MonoBehaviour {

    private State currentState;

    public void ChangeState<T>() where T : State {
        if (currentState != null) {
            currentState.Exit ();
        }
        currentState = (T)Activator.CreateInstance (typeof(T), this.gameObject);
        currentState.Enter();
    }

    void Update() {
        if (currentState != null) {
            currentState.Execute ();
        }
    }

    void OnCollisionEnter2D (Collision2D col)
    {
        currentState.ResolveCollision (col);
    }
}

州摘要 class:

using UnityEngine;
public abstract class State  {
    protected GameObject parent;

    public State(GameObject parent) {
        this.parent = parent;
    }

    abstract public void Enter();
    abstract public void Execute();
    abstract public void Exit();
    abstract public void ResolveCollision(Collision2D col);
}

运行 状态的简短示例:

using UnityEngine;
public class Running : State {

    public Running(GameObject parent) : base(parent) {}

    public override void Enter ()
    {
        return;
    }

    public override void Execute ()
    {
        if (Input.GetMouseButtonDown (0)) {
            parent.GetComponent<StateMachine> ().ChangeState<Jumping> ();
        }
    }

    public override void Exit ()
    {
        return;
    }

    public override void ResolveCollision (Collision2D col)
    {
        switch (col.gameObject.tag) {
        case "Obstacle":
            break;
        case "Pickupable":
            break;
        case "Enemy":
            break;
        }
        return;
    }
}

跳跃:

using UnityEngine;
public class Jumping : State {


    public override void Enter ()
    {
        return;
    }

    public override void Execute ()
    {
        return;
    }

    public override void Exit ()
    {
        return;
    }

    public override void ResolveCollision (Collision2D col)
    {
        switch (col.gameObject.tag) {
        case "Obstacle":
            break;
        case "Pickupable":
            break;
        case "Enemy":
            break;
        }
    }
}

我们的想法是,您将 StateMachine 附加到任何游戏对象,并且很容易更改该对象的状态。

每个状态都需要父对象进行操作,例如更改其位置。

每个状态还需要能够更改当前状态。传递父游戏对象(状态机附加到的游戏对象)将允许状态访问状态机并对游戏对象进行操作。

当更改状态时,我总是知道要操作的游戏对象(这显然是状态机所附加的游戏对象)所以要求是我不会在每次更改状态时手动传递游戏对象。

为了实现这一点,我想到了使用 (T)Activator.CreateInstance (typeof(T), this.gameObject);

在 start 方法中调用 ChangeState<Running> (); 时,我得到:

MissingMethodException: Method not found: 'Default constructor not found...ctor() of Running'.

如果我删除参数 this.gameobject(并删除 state 和 运行 中的构造函数),游戏将正常运行。问题是什么,我该如何解决? (仍在使用激活方法)...任何帮助都值得赞赏!

编辑:

让用户创建 class 的对象并在以后分配游戏对象符合我的需要,但根据我的说法,这不是一个优雅的解决方案:

public void ChangeState(State state) {
    state.parent = this.gameObject;
    if (currentState != null) {
        currentState.Exit ();
    }
    //currentState = (T)Activator.CreateInstance (typeof(T), this.gameObject);
    currentState.Enter ();
}

除了使用 Activator.CreateInstance,您还可以使用反射来实例化您的状态。这有两个好处:

  • 你可以实现一些逻辑来根据参数类型找到正确的构造函数(如果你搞砸了,你会得到更多的描述性错误)
  • 性能稍微好一点

您可以这样做:

var ctor = typeof(T).GetConstructor(new []{typeof(GameObject)})
currentState = ctor.Invoke(new object[]{this.gameObject}) as T;

或者如果您有一组已知且有限的状态,您可以简单地创建一个工厂 class 来封装不同状态的实例化。您可以根据泛型类型参数重定向到正确的私有方法,并在这些私有方法中直接调用构造函数。那表现得更好。

不过,如果您想要干净,使用依赖注入框架(Autofac 是我的最爱之一)通常是更干净的解决方案。