Chapter 3. 전략 패턴(Strategy Pattern)
카테고리: Design Pattern
인프런에 있는 이재환님의 강의 게임 디자인 패턴 with Unity 를 듣고 정리한 필기입니다. 😀
Chapter 3. Strategy Pattern
🔔 Strategy Pattern이란?
인터페이스 & 다형성과 관련있다.
- 여러 알고리즘을 하나의 추상적인 접근점(
인터페이스
)을 만들어 접근점에서 알고리즘이 서로 교환 가능하도록 하는 패턴- 동일 목적 알고리즘의 선택 적용
인터페이스
- 기능에 대한 선언
- 구현과의 분리
- 기능들을 구현하진 않고 프로토타입만 명시한다.
- 구현과의 분리
- 여러가지 기능을 사용하기 위한 단일 통로
- 예시
- 워드 문서에서 프린터, 폰트 사용
- ‘프린트’ 버튼만 누르면 어떤 종류의 프린터든간에 알아서 각자에 맞게 프린트함
- 똑같은 문장을 써도 폰트에 따라 모양은 다르게 나타남
- 정수 배열에 대해 사용하는 정렬 알고리즘
- 게임 캐릭터의 무기 사용
- 워드 문서에서 프린터, 폰트 사용
인터페이스에 무기에 대한 추상적인 기능 이름들만 명시해주면 각 무기들은 이 인터페이스를 상속받아 각자 무기 특성에 맞게 알아서 기능들을 구현하면 된다.
또한 부모인 인터페이스 이름 하나로 한방에 그 아래 자식들을 관리할 수 있다.
다형성
인터페이스 클래스 구현 in C#
public interface 뫄뫄 {
void func();
}
- 클래스 이름 앞엔 대문자
I
를 붙여주어야 한다. - 멤버 변수를 가질 수 없다.
- 멤버 함수들은 전부 프로토타입만 명시해주며 구현하지 않는다.
- 자식 클래스들은 인터페이스에 있는 모든 함수들은 무조건 다 오버라이딩 해야 한다.
🔔 예제 1 : 텍스트로 무기 교체
무기를 교체할때마다 콘솔창에 출력
구조
- 📜IWeapon.cs 인터페이스
Shoot()
- 📜Arrow.cs 상속
Shoot()
오버라이딩
- 📜Bullet.cs 상속
Shoot()
오버라이딩
- 📜Missile.cs 상속
Shoot()
오버라이딩
- 📜MyWeapon.cs
- private IWeapon weapon
SetWeapon
무기를 교체하고weapon.Shoot();
발사- 다형성
IWeapon weapon = Arrow arrow; IWeapon weapon = Bullet bullet; IWeapon weapon = Missile missile;
- 👉 📜MyWeapon 입장에선 여러 무기들에 대한 정보를 알지 못하지만 IWeapon타입으로 받은 무기는 각자 무기 타입에 따라 각자 오버라이딩 한대로 다른 내용의
Shoot()
을 실행한다. - 👉 📜MyWeapon 입장에선 그저
Shoot()
만 실행해도 각자 무기에 따라 알아서 다른 내용으로 실행되는 셈.
- 👉 📜MyWeapon 입장에선 여러 무기들에 대한 정보를 알지 못하지만 IWeapon타입으로 받은 무기는 각자 무기 타입에 따라 각자 오버라이딩 한대로 다른 내용의
- 다형성
- 📜WeaponManager.cs
- 무기 교체
📜IWeapon.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public interface IWeapon{
void Shoot(GameObject obj);
}
📜Arrow.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Arrow : IWeapon {
public void Shoot () {
Debug.Log ("화살 공격");
}
}
📜Bullet.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Bullet : IWeapon {
public void Shoot () {
Debug.Log ("총알 공격");
}
}
📜Missile.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Missile : IWeapon {
public void Shoot () {
Debug.Log ("미사일 공격");
}
}
📜MyWeapon.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MyWeapon {
// 접근점
private IWeapon weapon;
// 무기 교환 가능하게...
public void setWeapon (IWeapon weapon) {
this.weapon = weapon;
}
public void Shoot() {
// Function Delegage
weapon.Shoot();
}
}
📜WeaponManager.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class WeaponManager : MonoBehaviour {
MyWeapon myweapon;
void Start(){
myweapon = new MyWeapon ();
myweapon.setWeapon(new Bullet());
}
public void ChangeBullet() {
myweapon.setWeapon(new Bullet());
}
public void ChangeMissile() {
myweapon.setWeapon(new Missile());
}
public void ChangeArrow() {
myweapon.setWeapon(new Arrow());
}
public void Fire() {
myweapon.Shoot();
}
}
🔔 예제 2 : 직접 무기 교체
- 가운데 있는 오브젝트는 총알 or 화살 or 미사일을 쏘는 오브젝트인
BattleShip
오브젝트다. - 총알 or 화살 or 미사일 버튼을 누르고 Fire 버튼을 누르면 발사한다.
- 총알 or 화살 or 미사일 버튼을 누를때마다
BattleShip
오브젝트에 붙어있는 C# 스크립트 컴포넌트가 바뀐다.
- 총알 or 화살 or 미사일 버튼을 누를때마다
- 총알 or 화살 or 미사일은 실시간으로 게임 도중 프리팹을 복사아여 오브젝트로 생성된다.
- Instantiate
- 오브젝트의 사본을 실시간으로 게임 도움에 생성한다.
- Instantiate
구조
- 📜IWeapon.cs 인터페이스
- Shoot(GameObject obj)
Arrow
프리팹- 📜Arrow.cs 상속
- Shoot(GameObject obj) 오버라이딩
- 📜BulletMove.cs
- 총알 이동
- update 함수
- 📜Arrow.cs 상속
Bullet
프리팹- 📜Bullet.cs 상속
- Shoot(GameObject obj) 오버라이딩
- 📜BulletMove.cs
- 총알 이동
- update 함수
- 📜Bullet.cs 상속
Missile
프리팹- 📜Missile.cs 상속
- Shoot(GameObject obj) 오버라이딩
- 📜BulletMove.cs
- 총알 이동
- update 함수
- 📜Missile.cs 상속
BattleShip
오브젝트- 📜WeaponManager.cs
- 무기 교체
- 슬롯에 각각
Arrow
프리팹,Bullet
프리팹,Missile
프리팹 연결
- 게임이 실행되면
- 버튼에 따라 📜Arrow.cs, 📜Bullet.cs, 📜Missile.cs 중 하나씩 붙는다.
- 게임 시작시엔 📜Bullet.cs가 기본적으로 붙어있다.
- 📜WeaponManager.cs
📜IWeapon.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public interface IWeapon{
void Shoot(GameObject obj);
}
📜Arrow.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Arrow : MonoBehaviour, IWeapon {
void Start () {
}
public void Shoot(GameObject obj)
{
Vector3 initialPosition = new Vector3 (transform.position.x, transform.position.y, 0);
GameObject bullet = Instantiate(obj) as GameObject;
bullet.transform.position = initialPosition;
}
}
Arrow
프리팹에 붙는다.- 게임 실행 중 Arrow 버튼을 누르면
BattleShip
오브젝트에 붙는다. - public void Shoot(GameObject obj)
- 인터페이스 오버라이딩
- 인수로 들어온 프리팹
obj
를 Instantiate 하여 GameObject 타입으로 생성한다.- 이
obj
는 날아갈 화살이 된다.
- 이
obj
의 초기 위치를BattleShip
오브젝트의 위치로 설정
📜Bullet.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Bullet : MonoBehaviour, IWeapon {
void Start () {
}
public void Shoot(GameObject obj)
{
Vector3 initialPosition = new Vector3 (transform.position.x, transform.position.y, 0);
GameObject bullet = Instantiate(obj) as GameObject;
bullet.transform.position = initialPosition;
}
}
Bullet
프리팹에 붙는다.- 게임 실행 중 Bullet 버튼을 누르면
BattleShip
오브젝트에 붙는다. - public void Shoot(GameObject obj)
- 인터페이스 오버라이딩
- 인수로 들어온 프리팹
obj
를 Instantiate 하여 GameObject 타입으로 생성한다.- 이
obj
는 날아갈 총알이 된다.
- 이
obj
의 초기 위치를BattleShip
오브젝트의 위치로 설정
📜Missile.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Missile : MonoBehaviour, IWeapon {
void Start () {
}
public void Shoot(GameObject obj) {
Vector3 initialPosition = new Vector3 (transform.position.x, transform.position.y, 0);
GameObject bullet = Instantiate(obj) as GameObject;
bullet.transform.position = initialPosition;
}
}
Missile
프리팹에 붙는다.- 게임 실행 중 Missile 버튼을 누르면
BattleShip
오브젝트에 붙는다. - public void Shoot(GameObject obj)
- 인터페이스 오버라이딩
- 인수로 들어온 프리팹
obj
를 Instantiate 하여 GameObject 타입으로 생성한다.- 이
obj
는 날아갈 미사일이 된다.
- 이
obj
의 초기 위치를BattleShip
오브젝트의 위치로 설정
📜BulletMove.cs
using UnityEngine;
using System.Collections;
public class BulletMove : MonoBehaviour
{
float Speed = 10.0f;
void Update ()
{
this.transform.Translate(Vector3.up * Speed * Time.deltaTime);
if (this.transform.position.y > 10.0f)
{
Destroy(this.gameObject);
}
}
}
Arrow
,Bullet
,Missile
에 붙는다.- update 함수
- 시간, 속도에 따라 총알을 계속해서 이동시킴
- y 방향으로 위로 이동시킴 Vector3.up * Speed * Time.deltaTime
- y방향으로 10을 벗어나면 스스로를 파괴
📜WeaponManager.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public enum WeaponType {
Bullet,
Missile,
Arrow
}
public class WeaponManager : MonoBehaviour {
public GameObject _arrow;
public GameObject _bullet;
public GameObject _missile;
private GameObject myWeapon;
// 접근점
private IWeapon weapon;
private void setWeaponType (WeaponType weaponType) {
Component c = gameObject.GetComponent<IWeapon>() as Component; // 현재 게임 오브젝트의 IWeapon 타입의 컴포넌트를 가져온다.
if (c != null) {
Destroy(c);
}
switch (weaponType)
{
case WeaponType.Bullet:
weapon = gameObject.AddComponent<Bullet>();
myWeapon = _bullet;
break;
case WeaponType.Missile:
weapon = gameObject.AddComponent<Missile>();
myWeapon = _missile;
break;
case WeaponType.Arrow:
weapon = gameObject.AddComponent<Arrow>();
myWeapon = _arrow;
break;
default:
weapon = gameObject.AddComponent<Bullet>();
myWeapon = _bullet;
break;
}
}
void Start(){
setWeaponType(WeaponType.Bullet);
}
public void ChangeBullet () {
setWeaponType(WeaponType.Bullet);
}
public void ChangeMissile () {
setWeaponType(WeaponType.Missile);
}
public void ChangeArrow () {
setWeaponType(WeaponType.Arrow);
}
public void Fire() {
weapon.Shoot(myWeapon);
}
}
BattleShip
오브젝트에 붙는다.- _arrow, _missile, bullet 에 각 프리팹을 드래그 앤 드롭하여 넣어준다.
- private void setWeaponType (WeaponType weaponType)
- Component c = gameObject.GetComponent<IWeapon>() as Component;
BattleShip
오브젝트에 현재 붙어있는 IWeapon 타입의 컴포넌트를 컴포넌트 타입으로 형변환하여 리턴한다. (최상위 부모타입인 Component로)- 현재 미사일 모드였었다면 미사일(📜Missile)이 리턴될 것이고 이를 컴포넌트로 추상화하여 형변환해 리턴
- if (c != null) Destroy(c)
- 게임을 처음 싲작한 경우엔 c 가 null로 나올테니 이땐 파괴 안해도 되지만
- c가 null이 아니라는건 이미
BattleShip
오브젝트에 붙어있었던 무기가 있었다는거다. 원래 무기를 파괴해주기.- 미사일모드였었는데 화살 버튼을 눌렀다면 기존
BattleShip
오브젝트에 붙어있었던 미사일 컴포넌트를 실시간으로 삭제함
- 미사일모드였었는데 화살 버튼을 눌렀다면 기존
- Component c = gameObject.GetComponent<IWeapon>() as Component;
- switch문
- 인수로 총알, 화살, 미사일 enum을 받았을때 각각 처리
- weapon = gameObject.AddComponent<Arrow>();
BattleShip
오브젝트에 📜Arrow.cs 를 붙여준다.- 인터페이스이자 부모타입인 weapon으로 이를 참조하게 되었다. 2. myWeapon = _arrow;
- 화살 프리팹을 myWeapon이 참조하게끔
- 인수로 총알, 화살, 미사일 enum을 받았을때 각각 처리
- 각 Change 무기 교체 함수들은 위 setWeaponType 함수를 호출한다.
- Fire()
- weapon.Shoot(myWeapon);
-
bullet의 종류가 화살이던 미사일이던 총알이던 간에 알 필요없이 그냥 weapon 하나로 퉁쳐서 무기에 따라 다른 내용으로 오버라이딩 된 Shoot 멤버 함수를 호출할 수 있다.
다형성
-
- weapon.Shoot(myWeapon);
🌜 개인 공부 기록용 블로그입니다. 오류나 틀린 부분이 있을 경우
언제든지 댓글 혹은 메일로 지적해주시면 감사하겠습니다! 😄
댓글남기기