找不到默认构造函数
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 是我的最爱之一)通常是更干净的解决方案。
我正在为我的游戏制作一个有限状态机:
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 是我的最爱之一)通常是更干净的解决方案。