Convidamos futuros alunos do curso " Unity Game Developer. Professional " a assistir à aula aberta sobre o tema "Inteligência artificial avançada de inimigos em atiradores".
E agora estamos compartilhando a tradução tradicional de material útil.
Neste tutorial, vamos dominar o padrão de design Command e implementá-lo no Unity como parte de um sistema de movimento de objetos de jogo.
Apresentando o padrão de comando
Pedidos, ordens e comandos : todos estamos familiarizados com eles na vida real; uma pessoa envia uma solicitação (ou ordem ou comando) a outra pessoa para realizar (ou não) algumas das tarefas atribuídas a ela. Em design e desenvolvimento de software, isso funciona de maneira semelhante: uma solicitação de um componente é passada para outro para executar tarefas específicas dentro do padrão Equipe.
: — , , () , . , / .
. , ( ). — : (GUI), , (logic handler), -.
GUI , . , GUI -.
UML . , , .
        Command
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    ,   (ConcreteCommandN
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    )   Invoker
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    , Client
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      Receiver
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    .
Command
Command (Execute) (Undo) . Execute , , Undo.
public interface ICommand      
{ 
    void Execute();
    void ExecuteUndo();       
}
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    
            Invoker
 Invoker
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     (   Sender
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    )    .  ,   .     ,          .        .  ,         .          .
Client
(Client) . , (Receiver), . . , .
Receiver ( )
Receiver () — , -. . , , .
Command . , - ( ). .
, , . (immutable), .
Unity
, Unity . . (Undo), .
, !
3D Unity
    3D  Unity.   CommandDesignPattern
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    .
Plane, . Hierarchy Plane. «Ground» 20 X 20 z. , .
     Player
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    .           Capsule
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    .       Hierarchy      Capsule
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    .    Player
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    .
GameManager.cs
   Ground
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
         .   GameManager.cs
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    .
     Player
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    .
    public GameObject
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
        player
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    .
public GameObject mPlayer;
    Player
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      Hierarchy
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       Player
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       .
(Up, Down, Left Right).
      .       Update
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    .       1        .
void Update()
{
    Vector3 dir = Vector3.zero;
    if (Input.GetKeyDown(KeyCode.UpArrow))
        dir.z = 1.0f;
    else if (Input.GetKeyDown(KeyCode.DownArrow))
        dir.z = -1.0f;
    else if (Input.GetKeyDown(KeyCode.LeftArrow))
        dir.x = -1.0f;
    else if (Input.GetKeyDown(KeyCode.RightArrow))
        dir.x = 1.0f;
    if (dir != Vector3.zero)
    {
        _player.transform.position += dir;
    }
}
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    
              Play
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      ,  .     (Up, Down, Left  Right),    .
         — Player
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
           Ground
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    ,     .     ?
 ,      Ground
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    ,        .
public Vector3? GetClickPosition()
{
    if(Input.GetMouseButtonDown(1))
    {
        RaycastHit hitInfo;
        Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
        if(Physics.Raycast(ray, out hitInfo))
        {
            //Debug.Log("Tag = " + hitInfo.collider.gameObject.tag);
            return hitInfo.point;
        }
    }
    return null;
}
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    
            Vector3?
  ?
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
         C#, 
public int? myProperty { get; set; }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    
            , nullable
Nullable
,System.Nullable
. ,NULL
,NULL
. ,Nullable<Int32>
,«Nullable of Int32»
, -2147483648 2147483647,null
.Nullable<bool>
true
,false
null
.null
, , , . ,true
false
, .
,     ,      MoveTo
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    .   MoveTo
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
        .          .
public IEnumerator MoveToInSeconds(GameObject objectToMove, Vector3 end, float seconds)
{
    float elapsedTime = 0;
    Vector3 startingPos = objectToMove.transform.position;
    end.y = startingPos.y;
    while (elapsedTime < seconds)
    {
        objectToMove.transform.position = Vector3.Lerp(startingPos, end, (elapsedTime / seconds));
        elapsedTime += Time.deltaTime;
        yield return null;
    }
    objectToMove.transform.position = end;
}
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    
            , , , .
  Update
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    ,    .
****
    var clickPoint = GetClickPosition();
    if (clickPoint != null)
    {
        IEnumerator moveto = MoveToInSeconds(_player, clickPoint.Value, 0.5f);
        StartCoroutine(moveto);
    }
****
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    
              Play
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      ,  .     (Up, Down, Left  Right)       Ground
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    ,     Player
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    .
    (Undo
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    )?    ?   .
Unity
    Undo
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
        ,         ,      .
     Undo
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     —    ,    Unity.
          .     Command
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    .
Command
public interface ICommand { void Execute(); void ExecuteUndo(); }
  Command
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       .  —    Execute
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    ,   —  ExecuteUndo
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    ,   .            (  ,    ).
.
CommandMove
public class CommandMove : ICommand
{
    public CommandMove(GameObject obj, Vector3 direction)
    {
        mGameObject = obj;
        mDirection = direction;
    }
    public void Execute()
    {
        mGameObject.transform.position += mDirection;
    }
    public void ExecuteUndo()
    {
        mGameObject.transform.position -= mDirection;
    }
    GameObject mGameObject;
    Vector3 mDirection;
}
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    
            CommandMoveTo
public class CommandMoveTo : ICommand
{
    public CommandMoveTo(GameManager manager, Vector3 startPos, Vector3 destPos)
    {
        mGameManager = manager;
        mDestination = destPos;
        mStartPosition = startPos;
    }
    public void Execute()
    {
        mGameManager.MoveTo(mDestination);
    }
    public void ExecuteUndo()
    {
        mGameManager.MoveTo(mStartPosition);
    }
    GameManager mGameManager;
    Vector3 mDestination;
    Vector3 mStartPosition;
}
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    
             ,    ExecuteUndo
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    .     ,    Execute
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    .
Invoker
     Invoker
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    . ,  Invoker
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     —  ,    .  ,    Undo
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
            Last In First Out (LIFO)
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    .
  LIFO?     LIFO?     Stack
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    .
C#    ,       LIFO (Last In First Out).          .    Push()
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          (  ),  Pop()
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
        ( )    Peek()
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
        .
    Invoker
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    ,     .
public class Invoker
{
    public Invoker()
    {
        mCommands = new Stack<ICommand>();
    }
    public void Execute(ICommand command)
    {
        if (command != null)
        {
            mCommands.Push(command);
            mCommands.Peek().Execute();
        }
    }
    public void Undo()
    {
        if(mCommands.Count > 0)
        {
            mCommands.Peek().ExecuteUndo();
            mCommands.Pop();
        }
    }
    Stack<ICommand> mCommands;
}
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    
             ,   Execute
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      Undo
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      .    Execute
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
         ,   Push
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
         Execute
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     .        Peek
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    .      
Undo    ExecuteUndo
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
     ,      (  Peek
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    ).   Invoker
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       ,    Pop
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    .
     Invoker
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       .          Invoker
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
        GameManager
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    .
private Invoker mInvoker;
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    
                 mInvoker
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       Start
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
       GameManager.
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    
mInvoker = new Invoker();
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    
            Undo
      U
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    .      Update
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    .
// Undo 
    if (Input.GetKeyDown(KeyCode.U))
    {
        mInvoker.Undo();
    }
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    
                Update
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
          
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    .
void Update()
{
    Vector3 dir = Vector3.zero;
    if (Input.GetKeyDown(KeyCode.UpArrow))
        dir.z = 1.0f;
    else if (Input.GetKeyDown(KeyCode.DownArrow))
        dir.z = -1.0f;
    else if (Input.GetKeyDown(KeyCode.LeftArrow))
        dir.x = -1.0f;
    else if (Input.GetKeyDown(KeyCode.RightArrow))
        dir.x = 1.0f;
    if (dir != Vector3.zero)
    {
        //Using command pattern implementation.
        ICommand move = new CommandMove(mPlayer, dir);
        mInvoker.Execute(move);
    }
    var clickPoint = GetClickPosition();
    //Using command pattern right click moveto.
    if (clickPoint != null)
    {
        CommandMoveTo moveto = new CommandMoveTo(
            this, 
            mPlayer.transform.position, 
            clickPoint.Value);
        mInvoker.Execute(moveto);
    }
    // Undo 
    if (Input.GetKeyDown(KeyCode.U))
    {
        mInvoker.Undo();
    }
}
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    
              Play
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
      ,  .     (Up, Down, Left  Right),    ,   «u»     . 
— GoF, , - , , , , , .
Unity
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class GameManager : MonoBehaviour
{
    public interface ICommand
    {
        void Execute();
        void ExecuteUndo();
    }
    public class CommandMove : ICommand
    {
        public CommandMove(GameObject obj, Vector3 direction)
        {
            mGameObject = obj;
            mDirection = direction;
        }
        public void Execute()
        {
            mGameObject.transform.position += mDirection;
        }
        public void ExecuteUndo()
        {
            mGameObject.transform.position -= mDirection;
        }
        GameObject mGameObject;
        Vector3 mDirection;
    }
    public class Invoker
    {
        public Invoker()
        {
            mCommands = new Stack<ICommand>();
        }
        public void Execute(ICommand command)
        {
            if (command != null)
            {
                mCommands.Push(command);
                mCommands.Peek().Execute();
            }
        }
        public void Undo()
        {
            if (mCommands.Count > 0)
            {
                mCommands.Peek().ExecuteUndo();
                mCommands.Pop();
            }
        }
        Stack<ICommand> mCommands;
    }
    public GameObject mPlayer;
    private Invoker mInvoker;
    public class CommandMoveTo : ICommand
    {
        public CommandMoveTo(GameManager manager, Vector3 startPos, Vector3 destPos)
        {
            mGameManager = manager;
            mDestination = destPos;
            mStartPosition = startPos;
        }
        public void Execute()
        {
            mGameManager.MoveTo(mDestination);
        }
        public void ExecuteUndo()
        {
            mGameManager.MoveTo(mStartPosition);
        }
        GameManager mGameManager;
        Vector3 mDestination;
        Vector3 mStartPosition;
    }
    public IEnumerator MoveToInSeconds(GameObject objectToMove, Vector3 end, float seconds)
    {
        float elapsedTime = 0;
        Vector3 startingPos = objectToMove.transform.position;
        end.y = startingPos.y;
        while (elapsedTime < seconds)
        {
            objectToMove.transform.position = Vector3.Lerp(startingPos, end, (elapsedTime / seconds));
            elapsedTime += Time.deltaTime;
            yield return null;
        }
        objectToMove.transform.position = end;
    }
    public Vector3? GetClickPosition()
    {
        if (Input.GetMouseButtonDown(1))
        {
            RaycastHit hitInfo;
            Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
            if (Physics.Raycast(ray, out hitInfo))
            {
                //Debug.Log("Tag = " + hitInfo.collider.gameObject.tag);
                return hitInfo.point;
            }
        }
        return null;
    }
    // Start is called before the first frame update
    void Start()
    {
        mInvoker = new Invoker();
    }
    // Update is called once per frame
    void Update()
    {
        Vector3 dir = Vector3.zero;
        if (Input.GetKeyDown(KeyCode.UpArrow))
            dir.z = 1.0f;
        else if (Input.GetKeyDown(KeyCode.DownArrow))
            dir.z = -1.0f;
        else if (Input.GetKeyDown(KeyCode.LeftArrow))
            dir.x = -1.0f;
        else if (Input.GetKeyDown(KeyCode.RightArrow))
            dir.x = 1.0f;
        if (dir != Vector3.zero)
        {
            //----------------------------------------------------//
            //Using normal implementation.
            //mPlayer.transform.position += dir;
            //----------------------------------------------------//
            //----------------------------------------------------//
            //Using command pattern implementation.
            ICommand move = new CommandMove(mPlayer, dir);
            mInvoker.Execute(move);
            //----------------------------------------------------//
        }
        var clickPoint = GetClickPosition();
        //----------------------------------------------------//
        //Using normal implementation for right click moveto.
        //if (clickPoint != null)
        //{
        //    IEnumerator moveto = MoveToInSeconds(mPlayer, clickPoint.Value, 0.5f);
        //    StartCoroutine(moveto);
        //}
        //----------------------------------------------------//
        //----------------------------------------------------//
        //Using command pattern right click moveto.
        if (clickPoint != null)
        {
            CommandMoveTo moveto = new CommandMoveTo(this, mPlayer.transform.position, clickPoint.Value);
            mInvoker.Execute(moveto);
        }
        //----------------------------------------------------//
        //----------------------------------------------------//
        // Undo 
        if (Input.GetKeyDown(KeyCode.U))
        {
            mInvoker.Undo();
        }
        //----------------------------------------------------//
    }
    public void MoveTo(Vector3 pt)
    {
        IEnumerator moveto = MoveToInSeconds(mPlayer, pt, 0.5f);
        StartCoroutine(moveto);
    }
}
      
      
        
        
        
      
    
        
        
        
      
      
        
        
        
      
    
    
            
            Wikidepia Design Patterns
Wikipedia Command Design Pattern
Refactoring Guru
Game Programming Patterns
Design Patterns in Game Programming
"Unity Game Developer. Professional".
" ".