• Unity实现设计模式——命令模式


    Unity实现设计模式——命令模式

    推荐一个Unity学习设计模式很好的GitHub地址:https://github.com/QianMo/Unity-Design-Pattern 有非常多的Star

    一、介绍

    命令模式使得请求的发送者与请求的执行者之间消除耦合,让对象之间的调用关系更加灵活。在命令模式中,会将一个命令封装成一个对象,同时命令模式也支持可撤销的操作。
    在这里插入图片描述
    命令里面通常聚合接收者,初始化命令时传入接收者,调用者直接调用命令即可

    二、实现

    这里使用Unity上下左右控制物体移动同时记录移动信息方便撤回为例子演示命令模式

    1.ICommand

    命令接口基类

    public interface ICommand
    {
        void Execute();
        void UnExecute();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    2.MoveCommand

    具体的移动命令

    class MoveCommand : ICommand
    {
        private MoveDirection _direction;
        private MoveCommandReceiver _receiver;
        private float _distance;
        private GameObject _gameObject;
    
    
        //Constructor
        public MoveCommand(MoveCommandReceiver reciever, MoveDirection direction, float distance,
            GameObject gameObjectToMove)
        {
            this._receiver = reciever;
            this._direction = direction;
            this._distance = distance;
            this._gameObject = gameObjectToMove;
        }
    
    
        //Execute new command
        public void Execute()
        {
            _receiver.MoveOperation(_gameObject, _direction, _distance);
        }
    
    
        //Undo last command
        public void UnExecute()
        {
            _receiver.MoveOperation(_gameObject, InverseDirection(_direction), _distance);
        }
    
    
        //invert the direction for undo
        private MoveDirection InverseDirection(MoveDirection direction)
        {
            switch (direction)
            {
                case MoveDirection.up:
                    return MoveDirection.down;
                case MoveDirection.down:
                    return MoveDirection.up;
                case MoveDirection.left:
                    return MoveDirection.right;
                case MoveDirection.right:
                    return MoveDirection.left;
                default:
                    Debug.LogError("Unknown MoveDirection");
                    return MoveDirection.up;
            }
        }
    
    
        //So we can show this command in debug output easily
        public override string ToString()
        {
            return _gameObject.name + " : " + MoveDirectionString(_direction) + " : " + _distance.ToString();
        }
    
    
        //Convert the MoveDirection enum to a string for debug
        public string MoveDirectionString(MoveDirection direction)
        {
            switch (direction)
            {
                case MoveDirection.up:
                    return "up";
                case MoveDirection.down:
                    return "down";
                case MoveDirection.left:
                    return "left";
                case MoveDirection.right:
                    return "right";
                default:
                    return "unkown";
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78

    3.MoveCommandReceiver

    命令接收者

    class MoveCommandReceiver
        {
            public void MoveOperation(GameObject gameObjectToMove, MoveDirection direction, float distance)
            {
                switch (direction)
                {
                    case MoveDirection.up:
                        MoveY(gameObjectToMove, distance);
                        break;
                    case MoveDirection.down:
                        MoveY(gameObjectToMove, -distance);
                        break;
                    case MoveDirection.left:
                        MoveX(gameObjectToMove, -distance);
                        break;
                    case MoveDirection.right:
                        MoveX(gameObjectToMove, distance);
                        break;
                }
            }
    
            private void MoveY(GameObject gameObjectToMove, float distance)
            {
                Vector3 newPos = gameObjectToMove.transform.position;
                newPos.y += distance;
                gameObjectToMove.transform.position = newPos;
            }
    
            private void MoveX(GameObject gameObjectToMove, float distance)
            {
                Vector3 newPos = gameObjectToMove.transform.position;
                newPos.x += distance;
                gameObjectToMove.transform.position = newPos;
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35

    4.命令的发出者(或者说是图中Clinet)

    这里将命令发出者和Client放到了一起

    public class InputHandler : MonoBehaviour
    {
        public float moveDistance = 10f;
        public GameObject objectToMove;
    
        private MoveCommandReceiver moveCommandReciever;
        private Stack<MoveCommand> commandStack1 = new Stack<MoveCommand>();
        private Stack<MoveCommand> commandStack2 = new Stack<MoveCommand>();
    
        void Start()
        {
            moveCommandReciever = new MoveCommandReceiver();
    
            if (objectToMove == null)
            {
                Debug.LogError("objectToMove must be assigned via inspector");
                this.enabled = false;
            }
        }
    
    
        public void Undo()
        {
            if (commandStack1.Count > 0)
            {
                MoveCommand moveCommand = commandStack1.Pop();
                moveCommand.UnExecute();
                commandStack2.Push(moveCommand);
            }
        }
    
        public void Redo()
        {
            if (commandStack2.Count > 0)
            {
                MoveCommand moveCommand = commandStack2.Pop();
                moveCommand.Execute();
                commandStack1.Push(moveCommand);
            }
        }
    
        private void Move(MoveDirection direction)
        {
            MoveCommand moveCommand = new MoveCommand(moveCommandReciever, direction, moveDistance, objectToMove);
            moveCommand.Execute();
            commandStack1.Push(moveCommand);
        }
    
    
        //Simple move commands to attach to UI buttons
        public void MoveUp() { Move(MoveDirection.up); }
        public void MoveDown() { Move(MoveDirection.down); }
        public void MoveLeft() { Move(MoveDirection.left); }
        public void MoveRight() { Move(MoveDirection.right); }
    
        void Update()
        {
            if (Input.GetKeyDown(KeyCode.UpArrow))
            {
                MoveUp();
            }
            if (Input.GetKeyDown(KeyCode.DownArrow))
            {
                MoveDown();
            }
            if (Input.GetKeyDown(KeyCode.LeftArrow))
            {
                MoveLeft();
            }
            if (Input.GetKeyDown(KeyCode.RightArrow))
            {
                MoveRight();
            }
            if (Input.GetKeyDown(KeyCode.R))
            {
                Redo();
            }
            if (Input.GetKeyDown(KeyCode.U))
            {
                Undo();
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
  • 相关阅读:
    面试官: AMS在Android起到什么作用,简单的分析下Android的源码
    小型企业团队的理想项目管理软件解决方案
    Spring Boot中整合WebSocket
    深剖数商云B2B电商交易系统营销应用场景,赋能医疗器械企业实现精细化运营
    黔院长 | 黄帝内经:脏气法时论!
    海藻酸钠-聚乙二醇-反式环辛烯|TCO-PEG-alginate|海藻酸钠-聚乙二醇-PEG-TCO
    async&await函数
    VsCode中搭建TypeScript调试环境
    windows 安装cuda 11.2过程记录
    Unity记录5.6-地图-天空地面及地底的地形
  • 原文地址:https://blog.csdn.net/zzzsss123333/article/details/133298683