워낙 중요하고 알아두어야할 것이 많아서 til 3개로 정리하게 됐다.
명령(행동) 하나하나를 객체로 만든다.
구현 목적에 따라서 방법이 달라짐.
using System.Collections.Generic;
using UnityEngine;
// 명령 객체를 위한 인터페이스
public interface ICommand
{
void Execute();
string GetCommandLog(); // 로깅을 위한 구현
}
public class BuildCommand : ICommand
{
GameObject building;
Vector3 position;
public BuildCommand(GameObject objectToBuild, Vector3 buildPoint)
{
building = objectToBuild;
position = buildPoint;
}
public void Execute()
{
// 예시용 : 무리한 사용방법
GameObject.Instantiate(building, position, Quaternion.identity);
}
public string GetCommandLog()
{
return $"BuildCommand: {building.name} 생성. 생성 위치 : {position}";
}
}
public class RemoveCommand : ICommand
{
GameObject building;
public RemoveCommand(GameObject objectToBuild)
{
building = objectToBuild;
}
public void Execute()
{
// 예시용 : 무리한 사용방법
GameObject.Destroy(building);
}
public string GetCommandLog()
{
return $"RemoveCommand: {building.name} 파괴";
}
}
public class CommandLogger
{
List<string> logs = new List<string>();
public void LogCommand(ICommand command)
{
command.Execute();
logs.Add(command.GetCommandLog());
}
void PringLog()
{
foreach (var log in logs)
{
Debug.Log(log);
}
}
}
// 명령 객체를 위한 인터페이스
using System.Collections.Generic;
using UnityEngine;
public interface ICommand
{
Vector3 Execute();
Vector3 Redo(); // 되돌리기를 위한 구현
}
public class MoveCommand : ICommand
{
Vector3 _direction;
float _distance;
public MoveCommand(Vector3 direction, float distance)
{
_direction = direction;
_distance = distance;
}
public Vector3 Execute()
{
return _direction * _distance;
}
public Vector3 Redo()
{
return -_direction * _distance;
}
}
// 파사드 패턴
// 내부 로직 구성이 많거나 복잡한 경우
// 외부에서 쉽게 접근할 수 있도록하기 위한 창구 역할
// 주로 api 등등에서 사용하는 방법
public class PlayerFacade : MonoBehaviour
{
PlayerInput input;
PlayerMovement movement;
void Awake()
{
input = GetComponent<PlayerInput>();
movement = GetComponent<PlayerMovement>();
}
void Update()
{
// 이동 명령 입력 시, 처리
Vector3? move = input.ProcessInput();
if(move.HasValue)
{
movement.Move(move.Value);
}
// 명령 취소
if(input.ShouldRewind())
{
Vector3? redoMovement = input.Rewind();
if(redoMovement.HasValue)
{
movement.Move(redoMovement.Value);
}
}
}
}
public class PlayerMovement : MonoBehaviour
{
public void Move(Vector3 movement)
{
transform.position += movement;
}
}
public class PlayerInput : MonoBehaviour
{
public float moveDistance = 1f;
Stack<ICommand> history = new Stack<ICommand>();
public Vector3? ProcessInput()
{
float h = Input.GetAxisRaw("Horizontal");
float v = Input.GetAxisRaw("Vertical");
Vector3 dir = new Vector3(h, 0, v);
if(dir != Vector3.zero)
{
// 이동 명령
ICommand moveCommand = new MoveCommand(dir.normalized, moveDistance);
history.Push(moveCommand);
return moveCommand.Execute();
}
return null;
}
public bool ShouldRewind()
{
return Input.GetKeyDown(KeyCode.Escape) && history.Count > 0;
}
public Vector3? Rewind()
{
if(history.Count > 0)
{
ICommand lastCommand = history.Pop();
return lastCommand.Redo();
}
return null;
}
}
#내일배움캠프 #스파르타내일배움캠프 #스파르타내일배움캠프TIL