找不到默认构造函数

时间:2018-04-17 23:26:16

标签: c# generics unity3d types createinstance

我为团结游戏制作了一个有限状态机:

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

州的抽象类:

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:找不到方法:'默认构造函数不是   发现... ctor()的跑步'。

如果我删除参数this.gameobject(并删除状态中的构造函数并运行)游戏运行没有错误。有什么问题,我该如何解决? (仍然使用激活方法)......任何帮助都是有意义的!

编辑:

让用户创建一个类的对象,然后分配游戏对象以后会满足我的需求但是根据我并不是那么优雅的解决方案:

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

1 个答案:

答案 0 :(得分:2)

您也可以使用反射来实例化您的状态,而不是使用Activator.CreateInstance。这有两个好处:

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

以下是您的表现方式:

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

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

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