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 |
Tags
- 백준 c++ 2870번
- 수학숙제
- 2870번 수학숙제 c++
- 2870번 c++
- 2468 c++
- c++
- Unity
- 백준 1103번 게임
- 백준 17070번 c++
- 플레이어 이동
- Lv.3
- dfs
- 프로그래머스
- Algorithm
- 2870번 수학숙제
- 백준 2870번
- 백준 17070번
- 백준 1103번
- Lv2
- 백준 c++ 2468번
- C#
- 코테
- 17070번
- 백준 1103번 c++
- 2870번
- 오브젝트 풀링
- 유니티
- 코딩테스트
- Beakjoon
- 백준
Archives
- Today
- Total
주녘공부일지
[마법사의 길] 캐릭터, 몬스터 AI 상태 관리 본문
게임 소개 영상
https://github.com/godgjwnsgur7/Project_IH
GitHub - godgjwnsgur7/Project_IH
Contribute to godgjwnsgur7/Project_IH development by creating an account on GitHub.
github.com
유한 상태 기계 (FSM)을 기반으로 한 플레이어, 몬스터 AI 상태 관리
1) 플레이어 상태 관리 ( Condition, Exit, Enter )
protected EPlayerState _playerState = EPlayerState.None;
public virtual EPlayerState PlayerState
{
get { return _playerState; }
protected set
{
if (_playerState == value)
return;
bool isChangeState = true;
switch (value)
{
case EPlayerState.Idle: isChangeState = IdleStateCondition(); break;
case EPlayerState.Move: isChangeState = MoveStateCondition(); break;
case EPlayerState.Jump: isChangeState = JumpStateCondition(); break;
case EPlayerState.Fall: isChangeState = FallStateCondition(); break;
case EPlayerState.Land: isChangeState = LandStateCondition(); break;
case EPlayerState.Dash: isChangeState = DashStateCondition(); break;
case EPlayerState.Attack: isChangeState = AttackStateCondition(); break;
case EPlayerState.Skill1:
case EPlayerState.Skill2:
case EPlayerState.Skill3:
case EPlayerState.Skill4: isChangeState = SkillStateCondition(); break;
case EPlayerState.Hit: isChangeState = HitStateCondition(); break;
case EPlayerState.Down: isChangeState = DownStateCondition(); break;
case EPlayerState.DownLand: isChangeState = DownLandStateCondition(); break;
case EPlayerState.GetUp: isChangeState = GetUpStateCondition(); break;
case EPlayerState.Dead: isChangeState = DeadStateCondition(); break;
}
if (isChangeState == false)
return;
switch (_playerState)
{
case EPlayerState.Idle: IdleStateExit(); break;
case EPlayerState.Move: MoveStateExit(); break;
case EPlayerState.Jump: JumpStateExit(); break;
case EPlayerState.Fall: FallStateExit(); break;
case EPlayerState.Land: LandStateExit(); break;
case EPlayerState.Dash: DashStateExit(); break;
case EPlayerState.Attack: AttackStateExit(); break;
case EPlayerState.Skill1:
case EPlayerState.Skill2:
case EPlayerState.Skill3:
case EPlayerState.Skill4: SkillStateExit(); break;
case EPlayerState.Guard: GuardStateExit(); break;
case EPlayerState.Block: BlockStateExit(); break;
case EPlayerState.Hit: HitStateExit(); break;
case EPlayerState.Down: DownStateExit(); break;
case EPlayerState.DownLand: DownLandStateExit(); break;
case EPlayerState.GetUp: GetUpStateExit(); break;
case EPlayerState.Dead: DeadStateExit(); break;
}
_playerState = value;
PlayAnimation(value);
switch (value)
{
case EPlayerState.Idle: IdleStateEnter(); break;
case EPlayerState.Move: MoveStateEnter(); break;
case EPlayerState.Jump: JumpStateEnter(); break;
case EPlayerState.Fall: FallStateEnter(); break;
case EPlayerState.Land: LandStateEnter(); break;
case EPlayerState.Dash: DashStateEnter(); break;
case EPlayerState.Attack: AttackStateEnter(); break;
case EPlayerState.Skill1:
case EPlayerState.Skill2:
case EPlayerState.Skill3:
case EPlayerState.Skill4: SkillStateEnter(); break;
case EPlayerState.Guard: GuardStateEnter(); break;
case EPlayerState.Block: BlockStateEnter(); break;
case EPlayerState.Hit: HitStateEnter(); break;
case EPlayerState.Down: DownStateEnter(); break;
case EPlayerState.DownLand: DownLandStateEnter(); break;
case EPlayerState.GetUp: GetUpStateEnter(); break;
case EPlayerState.Dead: DeadStateEnter(); break;
}
}
}
2) 플레이어 인풋 컨트롤러 ( Update )
- 플레이어가 입력 값을 받아 동작이 가능한 상태를 나타내며, 상태가 변경됨에 따른 동작을 수행
private _isPlayerInputControll;
public bool IsPlayerInputControll
{
get { return _isPlayerInputControll; }
protected set
{
if (_isPlayerInputControll == value)
return;
_isPlayerInputControll = value;
ConnectInputActions(value);
if (_isPlayerInputControll)
{
// 강제 모션 변환
PlayAnimation(EPlayerState.Idle);
IdleStateEnter();
if (coPlayerStateController == null)
coPlayerStateController = StartCoroutine(CoPlayerStateController());
}
}
}
Coroutine coPlayerStateController = null;
protected IEnumerator CoPlayerStateController()
{
while (IsPlayerInputControll)
{
switch (PlayerState)
{
case EPlayerState.Idle: UpdateIdleState(); break;
case EPlayerState.Move: UpdateMoveState(); break;
case EPlayerState.Jump: UpdateJumpState(); break;
case EPlayerState.Fall: UpdateFallState(); break;
case EPlayerState.Land: UpdateLandState(); break;
case EPlayerState.Dash: UpdateDashState(); break;
case EPlayerState.Attack: UpdateAttackState(); break;
case EPlayerState.Skill1:
case EPlayerState.Skill2:
case EPlayerState.Skill3:
case EPlayerState.Skill4: UpdateSkillState(); break;
case EPlayerState.Guard: UpdateGuardState(); break;
case EPlayerState.Block: UpdateBlockState(); break;
case EPlayerState.Hit: UpdateHitState(); break;
case EPlayerState.Down: UpdateDownState(); break;
case EPlayerState.DownLand: UpdateDownLandState(); break;
case EPlayerState.GetUp: UpdateGetUpState(); break;
}
yield return null;
}
coPlayerStateController = null;
}
Ex) Attack State
- Condition : Attack 모션은 착지 상태에서만 가능
- Enter : Attack 상태에서는 플레이어 조작을 할 수 없음
- Update : Attack 모션이 종료되면 입력되고 있는 값에 따라 상태를 전이 ( Idle, Move )
protected virtual bool AttackStateCondition()
{
if (CreatureFoot.IsLandingGround == false)
return false;
return true;
}
protected virtual void AttackStateEnter()
{
isPlayerStateLock = true;
InitRigidVelocityX();
}
protected virtual void UpdateAttackState()
{
if(IsEndCurrentState(EPlayerState.Attack))
{
isPlayerStateLock = false;
PlayerState = EPlayerState.Move;
PlayerState = EPlayerState.Idle;
}
}
protected virtual void AttackStateExit()
{
}
public void OnAttackTarget(IHitEvent attackTarget)
{
attackTarget.OnHit(new AttackParam(PlayerInfo.Damage));
}
2) 몬스터 상태 관리, AI
- 각 상태에 따라 코루틴으로 실행되는 Update문에서 상태 전이에 대한 정의를 함
public float UpdateAITick { get; protected set; } = 0.0f;
[SerializeField, ReadOnly] BaseObject ChaseTarget;
[SerializeField, ReadOnly] BaseObject AttackTarget;
protected IEnumerator CoUpdateAI()
{
while (true)
{
switch (MonsterState)
{
case ENormalMonsterState.None:
MonsterState = ENormalMonsterState.Idle;
break;
case ENormalMonsterState.Idle: UpdateIdleState(); break;
case ENormalMonsterState.Patrol: UpdatePatrolState(); break;
case ENormalMonsterState.Chase: UpdateChaseState(); break;
case ENormalMonsterState.Attack: UpdateAttackState(); break;
case ENormalMonsterState.Hit: UpdateHitState(); break;
case ENormalMonsterState.Dead: UpdateDeadState(); break;
}
if (UpdateAITick > 0)
yield return new WaitForSeconds(UpdateAITick);
else
yield return null;
}
}
3) 현재 애니메이션의 상태 제어를 위한 로직
- 애니메이션 상태 확인, 특정 모션이 끝났는지 확인 등
protected void PlayAnimation(EPlayerState state)
{
if (animator == null)
return;
animator.Play(state.ToString());
}
public bool IsState(EPlayerState state)
{
if (animator == null)
return false;
return IsState(animator.GetCurrentAnimatorStateInfo(0), state);
}
protected bool IsState(AnimatorStateInfo stateInfo, EPlayerState state)
{
return stateInfo.IsName(state.ToString());
}
public bool IsEndCurrentState(EPlayerState state)
{
if (animator == null)
{
Debug.LogWarning("animator is Null");
return false;
}
// 다른 애니메이션 재생 중
if (!IsState(state))
return false;
return IsEndState(animator.GetCurrentAnimatorStateInfo(0));
}
protected bool IsEndState(AnimatorStateInfo stateInfo)
{
return stateInfo.normalizedTime >= 1.0f;
}
'GameDevelopment > [Unity] Project' 카테고리의 다른 글
[해피스케치] 스테이지 관리 및 제어 (0) | 2024.12.10 |
---|---|
[해피스케치] 에디터 인스펙터 툴 (카메라, 스테이지) (1) | 2024.12.04 |
[더 챌린저스] 동기화(RPC) & 네트워크(Photon) (1) | 2024.09.09 |
[더 챌린저스] 캐릭터 (0) | 2024.09.09 |
[더 챌린저스] 게임 플레이 영상 (2) | 2024.09.04 |