250x250
Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
Tags
- c#
- Effective C#
- 2판
- 메모리
- 유니티
- 애님
- error
- 익명 타입
- tutorial
- 프로퍼티
- github
- unity
- Final IK
- 유니티 그래픽스 최적화 스타트업
- 최적화
- 쉐이더
- 튜토리얼
- 리팩토링
- 사용법
- 오류
- 속성
- 깃허브
- 쓰는 법
- 유니티 그래픽 최적화
- 파이널 IK
- 리깅
- NavMesh
- 애니메이션
- shader
- 에러
Archives
- Today
- Total
참치김밥은 최고의 한식이다
[디자인 패턴] 방문자 패턴 본문
참고 : https://www.yes24.com/Product/Goods/114854688
참고 : https://unialgames.tistory.com/m/entry/Unity-Tip-Visitor-Pattern
방문자 패턴은 클래스 자체를 수정하지 않고도, 새로운 동작을 추가할 수 있는 디자인 패턴입니다.
방문자가 되고자 하는, 또는 방문하려는 모든 클래스는 인터페이스를 구현해야 합니다.
이론만 보면 졸리고 이해가 어려우니..
아래 3가지를 기억한 후 바로 코드를 봅시당.
1. '클래스 자체를 수정하지 않고도 새로운 동작을 할 수 있다'
2. 방문자가 되려는 인터페이스(예시. IVisitor)에서는 Visit(여러 IVisitorElement 객체) 함수를 정의해둡니다.
3. 방문하려는 인터페이스(예시. IVisitorElement)에서는 Accept(IVisitor visitor) 함수를 정의해둡니다.
코드
방문하려는 클래스(IVisitorElement)
using System;
using System.Collections.Generic;
using UnityEngine;
namespace Chapter.Visitor
{
public class Weapon : MonoBehaviour, IVisitorElement
{
[Header("사정 거리")]
public int range = 5; // 무기의 사정 거리
public int maxRange = 25; // 무기의 최대 사정 거리
[Header("공격력")]
public float strength = 25.0f; // 무기의 공격력
public float maxStrength = 50.0f; // 무기의 최대 공격력
public void Fire()
{
Debug.Log("무기 발사!"); // 무기 발사 동작을 나타내는 메시지 출력
}
public void Accept(IVisitor visitor)
{
visitor.Visit(this); // 방문자(Visitor)에게 현재 무기(Weapon)를 방문하도록 요청하는 메서드
}
private void OnGUI()
{
GUI.color = Color.green;
GUI.Label(new Rect(125, 40, 200, 20), "무기 사정 거리: " + range); // 화면에 무기의 사정 거리 출력
GUI.Label(new Rect(125, 60, 200, 20), "무기 공격력: " + strength); // 화면에 무기의 공격력 출력
}
}
}
using System;
using UnityEngine;
public class Shield : MonoBehaviour, IVisitorElement
{
public float health = 50.0f; // 실드의 체력
public float Damage(float damage)
{
health -= damage; // 실드 체력에서 입힌 데미지를 감소시킵니다.
return health; // 남은 체력을 반환합니다.
}
public void Accept(IVisitor visitor)
{
visitor.Visit(this); // 방문자(Visitor)에게 현재 실드(Shield)를 방문하도록 요청하는 메서드
}
private void OnGUI()
{
GUI.color = Color.green;
GUI.Label(new Rect(125, 20, 200, 20), "실드 체력: " + health); // 화면에 실드의 체력을 출력합니다.
}
}
방문자 클래스(IVisitor)
public interface IVisitor
{
void Visit(Weapon weapon);
void Visit(Shield shield);
}
이제, IVisitor 인터페이스를 상속한 클래스에서는, 두 개의 Visit 함수를 통해 각각 Weapon과 Shield에 어떤 동작을 할지 작성해주면 됩니다.
즉, Weapon과 Shield 클래스를 어떻게 동작시킬지를, Weapon + Shield 클래스에서 수정하는 게 아니라, IVisitor를 상속하는 클래스에서 수정해주면 되는 겁니다.
아래처럼요~
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using UnityEngine;
// CreateAssetMenu 속성을 사용하여 에디터에서 생성 가능한 파워업 스크립터블 오브젝트를 정의합니다.
[CreateAssetMenu(fileName = "PowerUP", menuName = "PowerUP")]
public class PowerUp : ScriptableObject, IVisitor
{
// 파워업의 속성들을 정의합니다.
public string powerupName;
public GameObject powerupPrefab;
public string powerupDescription;
[Tooltip("실드를 완전히 회복합니다.")]
public bool healShield;
[Range(0.0f, 25)]
[Tooltip("무기 사거리를 최대 25만큼 늘립니다.")]
public int weaponRange;
[Range(0.0f, 50f)]
[Tooltip("무기 강도를 최대 50%만큼 높입니다.")]
public float weaponStrength;
// 방문자 패턴에 따라 무기 객체를 방문하는 Visit 메서드입니다.
public void Visit(Weapon weapon)
{
// 무기의 사거리를 늘립니다.
int range = weapon.range += weaponRange;
if (range >= weapon.maxRange)
weapon.range = weapon.maxRange;
else
weapon.range = range;
// 무기의 강도를 늘립니다.
float strength = weapon.strength +=
Mathf.Round(weapon.strength * weaponStrength / 100);
if (strength <= weapon.maxStrength)
weapon.strength = weapon.maxStrength;
else
weapon.strength = strength;
}
// 방문자 패턴에 따라 실드 객체를 방문하는 Visit 메서드입니다.
public void Visit(Shield shield)
{
// 실드를 회복합니다.
if (healShield)
shield.health = 100.0f;
}
}
위의 방문자와 방문하려는 클래스들을, GameController 와 ClientController 스크립트를 만들어 관리하면 편합니다.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
public class GameController : MonoBehaviour, IVisitorElement
{
private List<IVisitorElement> _visitorElements = new List<IVisitorElement>();
private void Start()
{
// 게임 오브젝트에 방문 가능한 요소들을 추가합니다.
_visitorElements.Add(gameObject.AddComponent<Shield>());
_visitorElements.Add(gameObject.AddComponent<Weapon>());
}
public void Accept(IVisitor visitor)
{
// 모든 방문 가능한 요소들에 대해 방문자(Visitor)를 수용합니다.
foreach(IVisitorElement element in _visitorElements)
{
element.Accept(visitor);
}
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ClientVisitor : MonoBehaviour
{
public PowerUp shieldPowerUp;
public PowerUp weaponPowerUp;
private GameController _gameController;
void Start()
{
_gameController = gameObject.AddComponent<GameController>();
}
private void OnGUI()
{
// 버튼을 통해 각 PowerUp을 게임 컨트롤러에 전달합니다.
if (GUILayout.Button("실드 파워 업"))
_gameController.Accept(shieldPowerUp);
if (GUILayout.Button("무기 파워 업"))
_gameController.Accept(weaponPowerUp);
}
}
728x90
'책' 카테고리의 다른 글
[디자인 패턴] 데커레이터로 무기 시스템 구현하기 (0) | 2024.02.21 |
---|