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 |
Tags
- 행동트리
- 최소신장트리 mst
- 깊이탐색
- Unity
- readonly
- 오블완
- GetComponent
- 유니티 sparkmain(clone)
- unity sparkmain(clone)
- 유니티
- list clear
- removeAll
- sparkmain(clone) 무한생성
- 티스토리챌린지
- 트리구조
- Simulation
- C#
- 너비탐색
- articulation body
- unity korea
- raycast
- 디지털트윈
- dropdown
- 크루스칼
- BFS
- 최단거리 알고리즘
- dfs
- 드롭다운
- sparkmain(clone)
- navisworks api
Archives
- Today
- Total
낑깡의 게임 프로그래밍 도전기
C# 상태머신 상태패턴 본문
반응형
SMALL
상태머신
현재상태를 저장할수 있어야하며 전이가 될수 있어야한다.
현재 상태는 하나만 가져야한다.
상태패턴
상태머신을 객체지향적 패턴으로 만든것
고로 상태머신이라고 상태패턴은 아니며 상태패턴은 곧 상태머신이 된다
상태패턴은 다 다르지만
전략패턴은 행위의 파생느낌이다. 공격내 여러가지 공격이 있는것 처럼
using System.Collections;
using System.Collections.Generic;
using Unity.VisualScripting;
using UnityEngine;
using UnityEngine.AI;
using static Unity.VisualScripting.Dependencies.Sqlite.SQLite3;
public enum ENEMY_STATE_TYPE
{
IDLE,
TRACE,
ATTACK
}
public class State
{
public Enemy enemy;
public State(Enemy enemy)
{
this.enemy = enemy;
}
public virtual void Update()
{
}
}
public class IdleState : State
{
public IdleState(Enemy enemy) : base(enemy)
{
}
public override void Update()
{
if (enemy.isDetectiveTarget)
enemy.curState = new TraceState(enemy);
}
}
public class TraceState : State
{
public TraceState(Enemy enemy) : base(enemy)
{
}
public override void Update()
{
if (enemy.isDetectiveTarget == false)
enemy.curState = new IdleState(enemy);
if (enemy.isAttackable)
enemy.curState = enemy.attackStrategy;
enemy.SetTarget();
}
}
public class AttackState : State
{
public AttackState(Enemy enemy) : base(enemy)
{
}
public override void Update()
{
if (enemy.isAttackable == false)
enemy.curState = new TraceState(enemy);
Debug.Log("공격!");
}
}
public class MeleeAttackState : AttackState
{
public MeleeAttackState(Enemy enemy) : base(enemy)
{
}
public override void Update()
{
if (enemy.isAttackable == false)
enemy.curState = new TraceState(enemy);
Debug.Log("근거리 공격!");
}
}
public class RanageAttackState : AttackState
{
public RanageAttackState(Enemy enemy) : base(enemy)
{
}
public override void Update()
{
if (enemy.isAttackable == false)
enemy.curState = new TraceState(enemy);
Debug.Log("원거리 공격!");
}
}
public enum ATTACK_TYPE
{
Melee,
Range
}
public class Enemy : MonoBehaviour
{
// public ENEMY_STATE_TYPE curType;
public State curState;
public ATTACK_TYPE atkType;
public LayerMask targetMask;
public float detectiveRange;
public float attackableRange;
public AttackState attackStrategy = null;
public Transform target;
public NavMeshAgent agent;
// Start is called before the first frame update
void Start()
{
if (atkType == ATTACK_TYPE.Melee)
{
attackStrategy = new MeleeAttackState(this);
}
else
{
attackStrategy = new RanageAttackState(this);
}
curState = new IdleState(this);
agent = GetComponent<NavMeshAgent>();
}
public bool isDetectiveTarget;
public bool isAttackable;
private void Update()
{
isDetectiveTarget = Physics.OverlapSphere(transform.position, detectiveRange, targetMask).Length > 0;
isAttackable = Physics.OverlapSphere(transform.position, attackableRange, targetMask).Length > 0;
curState.Update();
}
public void SetTarget()
{
agent.SetDestination(target.position);
}
public void OnDrawGizmos()
{
Gizmos.color = Color.blue;
Gizmos.DrawWireSphere(transform.position, detectiveRange);
Gizmos.color = Color.red;
Gizmos.DrawWireSphere(transform.position, attackableRange);
}
}
using System.Collections;
using System.Collections.Generic;
using System.Data;
using UnityEditor.Build;
using UnityEngine;
using static UnityEditor.Experimental.GraphView.Port;
using System;
namespace CustomCollections
{
public class List
{
const int defaultCapacity = 4;//기존꺼는 바뀌면안되서 콘스트로 ㄷ만든다
int[] items;
int size = 0;
public int this[int index]//디스라는 것은 객체하나 이것을 쓰면 At을 안쓰고 출력가능
{
get { return items[index]; }
set { items[index] = value; }
}
public List()
{
items = new int[defaultCapacity];
}
public void Add(int item)
{
if (size >= items.Length)
Grow();
items[size] = item;
size++;
}
/*
public int At(int index)
{ return items[index]; }*/
public void Grow()
{
//Capacity를 2배늘려주고
//새로운 배열 Capacity만큼 할당하고
//기존 배열속 원소들은 새로운 배열에 복사해서 넣는 과정
int newCapacity = items.Length*2;
int[] newItems = new int[newCapacity];
Array.Copy(items,0, newItems, 0, size);//(복사위치, 위치의 어디부터, 복사대상, ,복사대상의 시작점, 끝점)
/*
for(int i = 0; i < items.Length; i++)
{
newItems[i] = items[i];
}*/
items = newItems;
}
}
public class GameManager : MonoBehaviour
{
//List<T> 가변배열 : 크기가 변할 수 있는 배열
//Array 정적배열 : 크기가 변하지 않는 배열
int[] array;
int capacity = 5;
List list;
void Start()
{
list = new List();
list.Add(10);
/*
int[] array = new int[capacity];
array[0] = 10;
array[1] = 20;
array[2] = 30;
array[3] = 40;
array[4] = 50;
capacity = capacity * 2;
int[] temp = array;//얕은 복사가 일어남
Debug.Log(temp[0]);//10나옴
array = new int[capacity];
//array = new int[30]; //위의 배열이 삭제후 30개로 새로 생성
for (int i = 0; i < capacity; i++)
{
array[i] = temp[i];
}
Debug.Log(temp[0]);//10나옴
Debug.Log(array[0]); //새로 만들면서 주소가 달라져서 0번이 출력이 안된다.*/
Debug.Log(list[1]);
}
}
}
using System.Collections;
using System.Collections.Generic;
using System.Data;
using UnityEditor.Build;
using UnityEngine;
using static UnityEditor.Experimental.GraphView.Port;
using System;
using System.Runtime.ExceptionServices;
namespace CustomCollections
{
public class List
{
const int defaultCapacity = 4;//기존꺼는 바뀌면안되서 콘스트로 ㄷ만든다
int[] items;
int size = 0;
public int Capacity { get { return items.Length; } }//전체길이
public int Count { get { return size; } }//안에 몇개가 있는지 세는거
public int this[int index]//디스라는 것은 객체하나 이것을 쓰면 At을 안쓰고 출력가능
{
get { return items[index]; }
set { items[index] = value; }
}
public List()
{
items = new int[defaultCapacity];
}
public void Add(int item)
{
if (size >= items.Length)
Grow();
items[size] = item;
size++;
}
public void RemoveAt(int index)// 그 번째를 지움
{
for (int i = index; i < items.Length - 1; i++)
{
items[i] = items[i + 1];
}
size--;
}
public int indexOf(int item)
{
return Array.IndexOf(items, item, 0, size);
}
public void Remove(int item)//그값을 지우는거고
{
int index = indexOf(item);
if (index >= 0)
{
RemoveAt(index);
}
}
public void Clear() //배열 초기화
{
items = new int[defaultCapacity];
size = 0;
}
/*
public int At(int index)
{ return items[index]; }*/
public void Grow()
{
//Capacity를 2배늘려주고
//새로운 배열 Capacity만큼 할당하고
//기존 배열속 원소들은 새로운 배열에 복사해서 넣는 과정
int newCapacity = items.Length * 2;
int[] newItems = new int[newCapacity];
Array.Copy(items, 0, newItems, 0, size);//(복사위치, 위치의 어디부터, 복사대상, ,복사대상의 시작점, 끝점)
/*
for(int i = 0; i < items.Length; i++)
{
newItems[i] = items[i];
}*/
items = newItems;
}
}
public class GameManager : MonoBehaviour
{
//List<T> 가변배열 : 크기가 변할 수 있는 배열
//Array 정적배열 : 크기가 변하지 않는 배열
int[] array;
int capacity = 5;
List list;
void Start()
{
list = new List();
list.Add(10);
/*
int[] array = new int[capacity];
array[0] = 10;
array[1] = 20;
array[2] = 30;
array[3] = 40;
array[4] = 50;
capacity = capacity * 2;
int[] temp = array;//얕은 복사가 일어남
Debug.Log(temp[0]);//10나옴
array = new int[capacity];
//array = new int[30]; //위의 배열이 삭제후 30개로 새로 생성
for (int i = 0; i < capacity; i++)
{
array[i] = temp[i];
}
Debug.Log(temp[0]);//10나옴
Debug.Log(array[0]); //새로 만들면서 주소가 달라져서 0번이 출력이 안된다.*/
Debug.Log(list[1]);
}
}
}
구조는 같고 데이터 타입만 다른 것에 제네릭화 하기 좋다 <T>
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices.WindowsRuntime;
public delegate void CustomDel();
public delegate bool BoolDel(int x);
namespace CustomCollections
{
public class List<T>
{
const int defaultCapacity = 4;
T[] items;
int size = 0;
public int Capacity { get { return items.Length; } }
public int Count { get { return size; } }
public T this[int index]
{
get
{
return items[index];
}
set
{
items[index] = value;
}
}
public List()
{
items = new T[defaultCapacity];
}
public int FindIndex(Predicate<T> match)
{
for(int i=0;i<items.Length; i++)
{
if (match(items[i]))
{
return i;
}
}
return -1;
//특정한 조건에 만족하는 원소의 인덱스를
//가져오는 함수.
}
public void Add(T item)
{
if (size >= items.Length)
Grow();
items[size] = item;
size++;
}
public int indexOf(T item)
{
return Array.IndexOf(items, item, 0, size);
}
//+)
public void RemoveAt(int index)
{
for(int i=index;i<items.Length-1; i++)
{
items[i] = items[i + 1];
}
size--;
}
//++)
public void Remove(T item)
{
int index = indexOf(item);
if(index >= 0)
{
RemoveAt(index);
}
}
public void Clear()
{
items = new T[defaultCapacity];
size = 0;
}
public void Grow()
{
int newCapacity = items.Length * 2;
T[] newItems = new T[newCapacity];
Array.Copy(items, 0, newItems, 0, size);
/*
for(int i=0;i<items.Length;i++)
{
newItems[i] = items[i];
}
*/
items = newItems;
}
}
public class GameManager : MonoBehaviour
{
//List<T> 가변배열 : 크기가변할 수 있는 배열
//Array 정적배열 : 크기가 변하지 않는 배열
List<int> list;
public bool IsUpperThanTen(int value)
{
return value > 10;
}
void Start()
{
list = new List<int>();
list.Add(10);
list.Add(20);
list.Add(30);
list.Add(40);
list.Add(50);
list.Add(60);
for(int i=0;i<list.Count;i++)
{
Debug.Log(list[i]);
}
Debug.Log(list.FindIndex((int value) => { return value == 50; }))
}
}
}
유니티는 throw를 던져주기만 해도 알아서 잡는다.
public class Stack
{
const int defaultCapacity = 4;
int[] array;
int size = 0;
public Stack()
{
array = new int[defaultCapacity];
}
public void Clear()
{
array = new int[defaultCapacity];
size = 0;
}
public void Push(int item)
{
if (size >= array.Length)
Grow();
array[size] = item;
size++;
}
public int Pop()
{
size--;
return array[size-- -1];
}
public bool IsEmpty()
{
return size == 0;
}
public bool IsFull()
{
return size == array.Length;
}
public int Peek()
{
return array[size];
}
public bool TryPop(out int result)
{
if (IsEmpty())
{
result = default(int);
return false;
}
else
{
result = array[size];
return true;
}
}
public void Grow()
{
int newCapacity = array.Length * 2;
int[] newArray = new int[newCapacity];
Array.Copy(array, 0, newArray, 0, size);
array = newArray;
}
}
처음에 클래스에 where T : ICompareble을 해주면 애초에 비교대상만 들어갈 수 있게되고 주석의 것을 안쓰고 아래 처럼 쓸 수 있다.
반응형
LIST