일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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
- Multiplay
- DSP
- ability task
- CTF
- Security
- gas
- boss monster
- MLFQ
- Replication
- 메카님
- unity
- Race condition
- 게임개발
- 운영체제
- animation
- 유니티
- MAC
- 언리얼 엔진
- dirty cow
- stride
- Unreal Engine
- 유스케이스
- photon fusion2
- Rr
- Delegate
- gameplay ability system
- ret2libc
- 언리얼엔진
- 게임 개발
- DP
Archives
- Today
- Total
다양한 기록
[Fortress Craft] Boss Monster - Frost Lizard AI 본문
Monster_FrostLizardMain
Monster_FrostLizardController
두 가지 클래스를 통해 AI가 작동
Main : 다음에 어떤 행동을 할 지 정하는 클래스
Controller : 실제 해당 행동에 대한 구체적인 구현
Main에서 다음 스테이트 결정하는 건 코루틴으로 구현
Controller에서 AI 설정은 FIxedUpdateNetwork에서 구현됨
이유: 컨트롤러의 경우 해당 행동에서 속도 설정 같은 게 필요한 경우가 있음
⇒ 한 번 스테이트 정하고 끝나지 않는 행동이 있어서 컨트롤러에서는 코루틴으로 구현 X
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Fusion;
namespace Agit.FortressCraft
{
public class Monster_FrostLizardMain : NetworkBehaviour
{
[SerializeField] private Monster_FrostLizardController monsterCtrl;
[SerializeField] private int idle = 20;
[SerializeField] private int walk = 20;
[SerializeField] private int breath = 20;
[SerializeField] private int tailAttack = 20;
[SerializeField] private int slam = 20;
private int sum;
private int num;
private int burstActualValue = 0;
private Dictionary<Monster_FrostLizardState, float> delayDict;
private Monster_FrostLizardState prevState = Monster_FrostLizardState.IDLE;
private Monster_FrostLizardState nextState = Monster_FrostLizardState.IDLE;
public override void Spawned()
{
delayDict = new Dictionary<Monster_FrostLizardState, float>();
delayDict.Add(Monster_FrostLizardState.IDLE, 2.0f);
delayDict.Add(Monster_FrostLizardState.WALK, 2.0f);
delayDict.Add(Monster_FrostLizardState.BREATH, 3.0f);
delayDict.Add(Monster_FrostLizardState.TAILATTACK, 2.0f);
delayDict.Add(Monster_FrostLizardState.SLAM, 3.0f);
sum = idle + walk + breath + tailAttack + slam;
StartCoroutine(SetMonsterState());
}
public IEnumerator SetMonsterState()
{
while( true )
{
prevState = nextState;
nextState = Monster_FrostLizardState.NON;
/*
// 스테이트 강제 설정 ----------------------------------------------------
if (nextState != Monster_FrostLizardState.NON)
{
monsterCtrl.setState(nextState, delayDict[nextState]);
return;
}
*/
// 스테이트 일반 설정 ----------------------------------------------------
num = Random.Range(0, sum);
int currentSum = idle;
if (num < currentSum)
{
//Debug.Log("Monster - Idle");
nextState = Monster_FrostLizardState.IDLE;
}
else if (num < (currentSum += walk)) // 걷기
{
//Debug.Log("Monster - Walk");
nextState = Monster_FrostLizardState.WALK;
}
else if (num < (currentSum += breath))
{
//Debug.Log("Monster - Breath");
nextState = Monster_FrostLizardState.BREATH;
}
else if( num < (currentSum += tailAttack) )
{
nextState = Monster_FrostLizardState.TAILATTACK;
}
else if( num < (currentSum += slam) )
{
nextState = Monster_FrostLizardState.SLAM;
}
if( prevState == nextState && nextState == Monster_FrostLizardState.BREATH )
{
continue;
}
monsterCtrl.SetState(nextState, delayDict[nextState]);
yield return new WaitForSeconds(delayDict[nextState]);
}
}
}
}
Main에서 코루틴으로 관리하는 형태
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Fusion;
namespace Agit.FortressCraft
{
public enum Monster_FrostLizardState
{
IDLE,
WALK,
BREATH,
TAILATTACK,
SLAM,
NON
}
public class Monster_FrostLizardController : MonsterController
{
private Monster_FrostLizardState state = Monster_FrostLizardState.NON;
private MonsterAttackCollider attackCollider;
public override void Spawned()
{
base.Spawned();
HP = hpMax;
attackCollider = GetComponentInChildren<MonsterAttackCollider>();
}
// FixedUpdateNetwork는 Athority 있는 거에서만 돌아서 FixedUpdate에서 처리 필요
private void FixedUpdate()
{
if(Runner.IsSharedModeMasterClient)
{
rb.velocity = Vector2.zero;
MonsterAI();
}
}
public void SetState(Monster_FrostLizardState state, float nextDelay)
{
if (!timeCheck()) return;
acted = false;
startTime = Time.fixedTime;
this.state = state;
this.nextDelay = nextDelay;
}
public override void MonsterAI()
{
if (HP <= 0.0f) return;
switch (state)
{
case Monster_FrostLizardState.IDLE:
ActionIdle();
break;
case Monster_FrostLizardState.WALK:
ActionWalk();
break;
case Monster_FrostLizardState.BREATH:
ActionBreath();
break;
case Monster_FrostLizardState.TAILATTACK:
ActionTailAttack();
break;
case Monster_FrostLizardState.SLAM:
ActionSlam();
break;
}
}
private void ActionIdle()
{
if (acted) return;
animator.SetTrigger("Idle");
acted = true;
}
private void ActionWalk()
{
if (!acted)
{
dir = Vector2.zero;
Transform Target = null;
Collider2D[] cols = Physics2D.OverlapCircleAll(new Vector2(transform.position.x, transform.position.y), 4.0f);
// 적 탐색
foreach (Collider2D col in cols)
{
if (col.tag.StartsWith("Unit") && !col.CompareTag("Unit_Monster"))
{
Target = col.transform;
break;
}
}
if( Target != null )
{
dir = (Target.position - transform.position).normalized;
}
else
{
// 타겟이 없을 시 랜덤 단위 벡터
float angle = Random.Range(0f, Mathf.PI * 2);
dir = new Vector2(Mathf.Cos(angle), Mathf.Sin(angle));
}
animator.SetTrigger("Walk");
acted = true;
}
if( dir.x > 0.001f || dir.y > 0.001f )
{
rb.velocity = dir * movingWeight;
}
if( rb.velocity.x > 0 )
{
rb.transform.localScale = new Vector3( Mathf.Abs( transform.localScale.x) * -1.0f,
transform.localScale.y, transform.localScale.z);
}
else
{
rb.transform.localScale = new Vector3(Mathf.Abs(transform.localScale.x),
transform.localScale.y, transform.localScale.z);
}
}
private void ActionBreath()
{
if (acted) return;
attackCollider.Damage = damage * 3.0f;
animator.SetTrigger("Breath");
acted = true;
}
private void ActionTailAttack()
{
if (acted) return;
attackCollider.Damage = damage;
animator.SetTrigger("TailAttack");
acted = true;
}
private void ActionSlam()
{
if (acted) return;
attackCollider.Damage = damage;
animator.SetTrigger("Slam");
acted = true;
}
}
}
그밖에 자세한 구현은 Controller에서 진행
플레이 예시 영상
'유니티 엔진 > Fortress Craft' 카테고리의 다른 글
[Fortress Craft] 맵 확장 (0) | 2025.02.06 |
---|---|
[Fortress Craft] Normal Monster With Scriptable Object (0) | 2025.02.06 |
[Fortress Craft] BossMonster - Frost Lizard 일러스트, 애니메이션 (0) | 2025.02.06 |
[Fortress Craft] Commander_Magician - 기본 공격, 스킬1, 스킬2 (0) | 2025.02.05 |
[Fortress Craft] Commander_Magician - 기본 외형 및 컨셉 기획 (0) | 2025.02.05 |