Sunday, 31 October 2021

Unity Implementing Command Pattern

To Implement a Command Pattern you need Two Classes first


"ICommand" as "Interface" And CommandList to hold all commands


ICommand Interface;

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public interface  ICommand 
{
    void Execute();
    void Undo();
}


CommandList Class (No monoBehaviour inheritance**)

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Linq;
public class CommandList
{
    private const int MAXCOMMAND = 100;
    private Stack<ICommand> commandList = new Stack<ICommand>();

    public void Execute(ICommand command)
    {
        command.Execute();
        if (commandList.Count < MAXCOMMAND)
            commandList.Push(command);
    }

    public void Undo()
    {
        if (commandList.Count <= 0)
            return;
        commandList.Pop().Undo();
    }

  
}




 those two classes is main implementation  after that you can use those classes based on your sceneraio;

For example you scale your cube based on your imput
 and you move your cube based on your mouse movement
So command will be seperated  like "MoveCommand" and "ScaleCommand"


Move Command (Inherites from ICommand);


public class MoveCommand : ICommand
{

    private Transform movingObject;
    private Vector3 direction;
    private float moveSpeed;
    public MoveCommand(Transform transform,Vector3 direction,float moveSpeed)
    {
        this.movingObject = transform;
        this.direction = direction;
        this.moveSpeed = moveSpeed;
    }
     public void Execute()
    {
        this.movingObject.transform.position += this.direction* moveSpeed;
    }

    public void Undo()
    {
        this.movingObject.transform.position -= this.direction* moveSpeed;
    }

}

Scale Command(Inherites from ICommand);

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class ScaleCommand : ICommand
{
    private float scalefactor;
    private Transform transform;
    public ScaleCommand(float scalefactor,Transform transform)
    {
        this.scalefactor = scalefactor;
        this.transform = transform;
    }

    public void Execute()
    {
        this.transform.localScale += Vector3.one * scalefactor;
    }

    public void Undo()
    {
        this.transform.localScale -= Vector3.one * scalefactor;
    }

 
}
 
To Finalize every thing and combine mechanics togeter you have to call those classes 

let's say "CubeController" to our Main Class

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class CubeController : MonoBehaviour
{
    // Start is called before the first frame update
    [SerializeField]
    float moveSpeed;
    [SerializeField]
    float scaleUpMultiplyer;
    Vector3 lastPos;
    Vector3 deltaPos;
    // Update is called once per frame
    CommandList commands = new CommandList();
    void Update()
    {

        MovingInputs();
        ScaleInputs();
        UndoInput();
    }

    void ScaleInputs()
    {
        if (Input.GetKeyDown(KeyCode.A))
        {
            commands.Execute(new ScaleCommand(scaleUpMultiplyer, this.transform));
        }

    }
    void UndoInput()
    {
        if (Input.GetKey(KeyCode.Q))
        {
            commands.Undo();
        }
        if (Input.GetKeyDown(KeyCode.Z))
        {
            commands.Undo();
        }
    }
    void MovingInputs()
    {
        if (Input.GetMouseButtonDown(0))
        {
            lastPos = Input.mousePosition;
        }
        else if (Input.GetMouseButton(0))
        {
            deltaPos = Input.mousePosition - lastPos;

            commands.Execute(new MoveCommand(this.transform, deltaPos, moveSpeed));
        }
       
    }
}



you can  do commands and undo commands with this system  every new mechanic will be Inherited from ICommand   like  Coloring Cube,RotatingCube and  can be Undo  using CommandList
Feel Free to ask any questions :)

Happy Coding :)

No comments:

Post a Comment