类图:
理解:
一条命令的周期为发布和接受(执行)。在Unity3D中,
调用者(Invoker)一般为控制器或者角色本身,得到客户端输入,调用具体的命令发布出去。
接受者(Receiver)(说成执行者可能更好理解),一般为角色本身,提供一些命令的具体执行方法。
在传统的Unity3D中,通过按键控制物体,一般是以
if(Input.GetKey(KeyCode.W)){
//向前移动的具体逻辑
}
上面的代码看似非常正常,但是这里的调用模块和执行模块高耦合,调用者需要关心者接受者的逻辑实现,执行者需要根据具体的调用来实现逻辑,两者过于相互依赖。如果那天需要修改向前移动的逻辑,或者更换向前移动的按键,需要直接修改上面的代码具体逻辑。违反了开闭原则。或者需要更换控制角色,则就需要更换脚本绑定。
命令模式主要的特点是把调用者和接受者之间的连接——命令——类化,把命令(Command)独立出来一个,成为一个单独的层用来连接调用者和接受者。然后调用者(Invoker)调用命令,命令通知接受者(Receiver)具体的执行逻辑
实际使用:
这里通过WSAD键控制Cube的前后左右移动的例子实现命令模式在Unity3D中的使用
ICommand.cs:
using UnityEngine;
using System.Collections;
public interface ICommand {
void Execute(Receiver receiver);
}
命令接口(由于会存在多个不同的命令,这里将命令的公共部分写成接口),其中Receiver是接受者(执行者),用于调用接受者的具体执行方法
——————————————————————————————————————————————————————
MoveCommand.cs
using UnityEngine;
using System.Collections;
public class MoveForwardCommand : ICommand {
public void Execute(Receiver receiver){
receiver.MoveForward();
}
}
public class MoveBackCommand : ICommand {
public void Execute(Receiver receiver){
receiver.MoveBack();
}
}
public class MoveLeftCommand : ICommand {
public void Execute(Receiver receiver){
receiver.MoveLeft();
}
}
public class MoveRightCommand : ICommand {
public void Execute(Receiver receiver){
receiver.MoveRight();
}
}
4个具体的命令类,实现了ICommand接口。
——————————————————————————————————————————————————————
Receiver.cs:
using UnityEngine;
using System.Collections;
public class Receiver : MonoBehaviour {
public float speed = 6f;
CharacterController characterController;
Vector3 moveDir = Vector3.zero;
void Awake(){
characterController = GetComponent<CharacterController>();
}
public void MoveForward(){
moveDir = transform.TransformDirection(Vector3.forward) * speed; //将世界的正前方向量转化为物体的正前方向量
characterController.Move(moveDir * Time.deltaTime);
}
public void MoveBack(){
moveDir = transform.TransformDirection(Vector3.back) * speed;
characterController.Move(moveDir * Time.deltaTime);
}
public void MoveRight(){
moveDir = transform.TransformDirection(Vector3.right) * speed;
characterController.Move(moveDir * Time.deltaTime);
}
public void MoveLeft(){
moveDir = transform.TransformDirection(Vector3.left) * speed;
characterController.Move(moveDir * Time.deltaTime);
}
}
这里提供了具体的移动逻辑方法,这里通过CharacterController进行移动
——————————————————————————————————————————————————————
在Unity3D项目中创建一个Plane做背景,创建一个Cube和Sphere作为被控制移动的对象,GameController是一个空物体,用作控制移动脚本的载体。
给Cube和Sphere添加CharacterController组件和Receiver脚本
给GameController添加Invoker脚本
分别将Cube和Sphere拖给Invoker脚本的Receiver,分别运行,Receiver为Cube时,可以控制Cube移动,Receiver是Sphere时,可以控制Sphere移动。
总结
命令模式将调用模块和接受模块进行了很大程度的解耦,利于扩展。
学疏才浅,理解有限,欢迎指正不对之处,共同交流