본문 바로가기

강동새싹언리얼수업/언리얼

231226 AI수업

레벨에  volumes>NavMeshBounds volume을 추가한다.

영역을 설정한다. P를 누르면 영역이 표시된다.

BP_EnemyBase 이벤트그래프에 AIMoveTo를 추가해 TargetActor를 따라가게 만드는 이벤트 ChasePlayer를 만든다.

공격을 하는 이벤트 Attack도 만든다. PlayMontage에는 어택 몽타지를 하나 만들어 적용한다.

Behavior Tree : 게임 AI의 동작을 조직하고 관리하는 시스템

Black Board : AI의 상태, 정보, 데이터를 저장하고 공유하는 중앙 데이터 저장소

AI폴더를 하나 만들고 BB_Enemy_Base, BT_Enemy_Base를 만든다.

 

 

  • 트리 구조 ~~~ >> 탐색
                            >> (빠른 속도) 원하는 데이터 구하기 
  • 큰 데이터를 빠르게 Read 에 적합

BT를 열어 추가할수 있는 노드 종류 Tasks가 제일 작은 단위

 

 

Selector

  • 자식 노드를 왼쪽에서 오른쪽으로 진행
  • 자식 노드 중에 성공 시, 중단 함 
  • 모든 자식 노드가 실패면 실패

Sequence

  • 자식 노드를 왼쪽에서 오른쪽으로 진행
  • 자식 노드 중에 실패 시, 중단 함 
  • 모든 자식 노드가 성공이면 성공

Simple Parallel

단일 기본 작업 노드를 전체 트리와 함께 실행

기본 작업이 완료되면 마침 모드 의 설정 에 따라 노드가 즉시 완료되어 보조 트리가 중단되어야 하는지, 아니면 보조 트리가 완료될 때까지 지연되어야 하는지가 지정

 

Behavior Tree에 MoveTo 추가

Blackboard에 Object타입의 TargetActor Key를 추가한다. Detail에서 KeyType Base Class를 Actor로 설정한다.

Behavior Tree의 Sequence아래 MoveTo의 Blackboard Key를TargetActor로 변경한다

Radius범위와 노드이름을 변경한다.

AI 컨트롤러 [AIController] 

AI 컨트롤러는 사람 플레이어의 입력 없이 주변 월드를 관찰하고 의사를 결정한 뒤 알맞게 반응합니다.

블루프린트를 만든다 AIController를 부모로 하고 이름을 AIC_Enemy_Base로 한다.

이벤트그래프에서 Event On Possess를 추가한다.

AI 컨트롤러가 특정 AI 캐릭터를 제어하기 시작할 때 호출되는 이벤트
AI 컨트롤러가 AI 캐릭터를 "Possess(지배)"하거나 제어하려 할 때 해당 캐릭터를 설정하고 초기화하는 데 사용
예를 들어, 게임에서 특정 상황에 AI 캐릭터를 생성하고, 해당 AI 캐릭터를 AI 컨트롤러가 제어해야 할 때 OnPossess 이벤트를 사용하여 AI 컨트롤러와 AI 캐릭터를 연결하고 초기 설정을 수행 가능

BehaviorTree를 Run시킨다. BTASset을 지정한다.

톱니바퀴에서 Show Inherited Variables를 켠다 AI트리를 연다.

블랙보드컴포넌트키를 설정하기 위해 Set Value as Object를 추가하고 Key Name변수로 승격하고 컴파일후 Default를 BlackBoard의 키중 하나인 TargetActor로 설정한다.

Blackboard변수도 끌어다 연결해준다.

BP_EnemyBase에 AIC_Enemy_Base를 지정해준다.

기존 Event Graph 내용이 없어도 따라와 짐 단 플레이어가 추적가능한 Nav영역에 있어야 한다

BT_에 Wait추가 2초로 설정

NewTask>BTT_Attack추가 BTTask_BlueprintBase을 클릭해 이름을 변경한다  이후는 클릭해 상속받는다.

TASK에는 다음과 같이 함수옆  오버라이드 메뉴에서  이벤트를 추가할 수 있다.

 함수옆  오버라이드 메뉴에서  Receive Execute AI를 눌러 이벤트를 추가할 수 있다.

Cast To BP_TP_EnemyBase해서 Attack애니메이션을 실행시켜주는  BP_EnemyBase의 Attack이벤트 추가한다. 

컨텍스트메뉴를 열어 >Tasks에서 방금만든 BTT_Attack추가

플레이 해보면 에너미가 wait하지 않고 계속 공격하고 도망가면 미끄러지듯이 따라옴

BP_Enemy_Base에서 Event Dispachers + 를 눌러 OnAttackEnd를 생성해서 이벤트그래프에 Call On Attack End를 추가한다.

다시 BTT_Attack으로 돌아와

OnAttackEnd는 BP_Enemy_Base에서 정의했으므로 ControlledPawn을 BP_EnemyBase로 Cast후 Attack을 추가한다 그럼 공격 애니메이션이 실행되고 애니메이션이 끝날때 OnAttackEnd Dispatch가 실행되므로  AsBP TP Enemy Base에서 끌어 우클릭후  Assign On Attack End검색해 추가해준다. 그럼 BindEvent+OnattackEnd_Event가 추가된다.

Task의 마지막은 Finish Execue를 노드를 추가한다. 이 노드는 애니메이션이 끝나는 OnAttackEnd_Event수신후 진행된다.

 

다시 BlackTree로 돌아가 Wait를 와 ATTACK를 교체해준다 공격후 2초 기다리게 해준다.

BTT_FocusTarget을 만든다.

Function override에서 ReceiveExecuteAI를 추가해주고 OwnerController에 SetFocus를 주고 Finish를 연결해준다. Success를 체크해준다

SetFocus에 GetBlackboardValueasActor를 붙여주고 Key입력을 변수로 승격시켜 AttackTargetKey로 변경한다.  Default는 없다. AttackTargetKey는 눈을 켜주고 public으로 만든다. 전체흐름은 블랙보드에서 TargetActor 키를 얻어와 SetFocus해준다

AttackTargetKey는 눈을 켜주고 public으로 만든다.

방금만든 BTT_FocusTarget을 추가한다.Default를 TargetActor로 설정해준다. 

스플라인 베지에 곡선을 이용해 AI를 걸을 패스를 만들어 보겠다 BP_Patrol을 액터로 만들어 PatrolSPline을 컴포넌트로 추가해준다.

CustomEvent를 추가해주고 IncrementPatrol이름으로 바꿔준다.

변수 2개를 추가해주고 Index는 점의 위치 Direction은 진행방향을 의미한다 끝까지 갔다가 돌아올때 -1 이 된다.

IncrementPatrol이벤트가 불릴때마다 다음 인덱스를 1씩 변화시켜준다. 패트롤 포인트 0~마지막이라면 다시 0으로 반복하게 만들어준다.

이벤트그래프

인덱스의 위치를 스플라인포인터에서 얻어오는 getsplinepointworld변수를 만든다.

함수만들기

Patrol Index를 받아와 해당되는 점의 Location을 리턴한다. CoordinateSpace를 World로 한다

BP_EnemyBase로 이동해서. PatrolSpline(BP_Patrol)변수 만들것 눈동자를 켜줘 퍼블릭으로 만든다

찾기쉽게 카테고리는 BT로 한다.

 

컴파일후  레벨 아웃라이너 디테일에서 BP_Patrol연결해줄것 

BP_Enemy_Base에 BP_Patrol타입 변수 지정

BT_Enemy_Base에서 BTT_MovePatrol Task생성 BTT_Task_BlueprintBase에서 상속받는다

BP_Enemy_base의 함수를 사용할때 마다 다음과 같이 캐스팅하면 적이 많아지면 로드가 걸리므로

이벤트가 불릴 때 마다, 캐스팅 비 경제적

BPI_EnemyAI 인터페이스를 만듬 

Functions GetPatrolSpline를 만들고 Output을 BP_Patrol타입의 PatrolSpline변수를 만듬

   BP_Enemy_Base로가 ClassSettings를 선택하고 디테일  Interface카테고리에  BPI_EnemyAI를 추가해주고 컴파일하면 MyBlueprint에 GetPatrolSpline인터페이스가 보임

GetPatrolSpline를 더블클릭해  PatrolSPline변수를 출력으로 연결

BTT_MovePatrol로 돌아와 방금만든 Interface를 추가 캐스팅없이 콜할수 있다. 목적은 BP_Enemy_Base의 PatrolSpline리퍼런스를 받아오는것

GetPlinePointWorld로 점을 받아와 AIMoveTo함수를 이용 적을 이동시킨다. 이동후에는 BP_Patrol-> IncrementPatrol 이벤트를 이용해 인데스를 증가시켜주고 끝낸다

새로운 BTT_FocusClear를 만든다.

위에서 만든 BTT_MovePatrol을 추가해준다. BP_Patrol의 월드 포인트로 이동하고 인덱스를 하나증가해준다. 테스트를 위해 다음과 같이 테스트해본다.

232023 . 12 . 26 이동시켜보면 급브레이트 현상이 있다.

BP_Enemy_Base의 CharacterMovement의 UserFixedDistancePaths를 체크해제한다.

 

부드럽게 따라가기 BPI_EnemyAI 인터페이스를 열어

GetPatrolSpline밑에, SetMovementSpeed함수를 추가한다.  값은 Float가 아니라 Enum을 만들어 변경할 예정이다.

E_MovementSpeed Enum을 만든다. Idle, Walk, Sprint 상태를 만든다.

BPI_EnemyAI로 와 Input변수 Speed타입을  E_MovementSpeed를 지정해준다.

Output변수로 SpeedValue변수를 Float타입으로 만든다. 리턴노드가 자동으로 추가된다.

BP_EnemyBase로 돌아가면 SetMovementSpeed 인터페이스가 보인다. 더블클릭해 내용을 구현해준다. Select노드를 이용해 Speed 상태에 따라 값을 선택해 CharactgerMovement의 Max Walk Speed를 설정해준다. ReturnNode를 추가해준다. 인터페이스의 출력변수값이 있기때문이다.

BTT_SetMovementSpeed Task를 만들어준다. SetMovementSpeed인터페이스를 콜해 Idle로 설정해주고 끝낸다. 

Speed를 변수로 승격해서 이름을 MovementSpeed로 한다. 눈동자를 뜨게해줘 퍼블릭으로 만든다.

BT_Enemy_Base로 돌아가 BTT_SetMovementSpeed를 추가해주고 MovemetSpeed 상태를 Walk로 바꿔준다. 조금전에 퍼블릭으로 만들었던 변수다. CharacterMovement의 MaxWalkSpeed가 300으로 변경된다

ChasePlayer 시퀀스아래에도 BTT_SetMovementSpeed를 넣어주고 Sprint로 설정해준다.

Root아래 BTT_movePatrol와 Btt_SetMovementSpeed 노드를 바꿔가면서 테스트해본다.

 

Decorator는 자식 노드의 실행 여부를 조건에 따라 변경하거나 조절하는 역할

if문과 유사 BTDecorator_BlueprintBase로 상속받아 만든다.

목표 : Patrol(Spline) 경로 여부에 따라서, 순찰 여부 결정 

TASK와 비슷하게 펀셩옆 Override에서 이벤트를 고를 수 있다. PerformConditionCheckAI

Perform Condition Check: 데코레이터의 조건을 검사하고, 조건이 충족되면 true를 반환하여 자식 노드를 실행하거나, 그렇지 않으면 false를 반환하여 실행을 건너뜁니다.

Receive Execution Start: 자식 노드의 실행이 시작될 때 호출되는 함수로, 데코레이터가 실행되기 전에 이벤트를 처리하고자 할 때 사용합니다.

Receive Execution Finish: 자식 노드의 실행이 완료된 후 호출되는 함수로, 데코레이터가 실행된 후 추가적인 처리를 하고자 할 때 사용합니다.

Receive Observer Activated: 데코레이터가 감시자(observer)로 활성화될 때 호출되는 함수로, 특정 상황에서 데코레이터의 동작을 시작하고자 할 때 사용합니다.

~= Deactivated - 비활성화

Receive Tick: 데코레이터가 갱신될 때마다 호출되는 함수로, 주기적으로 데코레이터의 상태를 업데이트하고자 할 때 사용합니다.

 

AI가 함수명 뒤에 붙으면 해당 함수가 AI 관련 작업에 특화되어 AI 컨트롤러, Pawn 등과 직접적으로 상호작용하고 AI 상태를 감지하거나 제어하는 데 사용

 

AAIController* OwnerController 및 APawn* ControlledPawn을 인자로 받습니다. 이는 AI 관련 조건을 검사할 때 사용되며, AI 컨트롤러와 그에 연결된 Pawn에 대한 더 직접적인 접근을 제공

간소화

 

GetPatrolSpline이 있는지를 검사해서 결과를 리턴합니다.

Spline없는 애들은 대기하게 만든다.

Patrol시퀀스 위를 우클릭후 Add decorator를 선택해 추가할 수 있다. BTD Patrol Check를 추가해준다.

추가된 모습

Slector를 추가하고 Wait를 추가한다.

BT_Enemy_Base를 관찰해보면 BP_Patrol이 없을때 5초  waiting한다.

BP_Enemy_Base의 Patrol Spline을 관찰하면 None, BP_Patrol로 달라진다.

AI의 상태를 구분하고자 함 FSM

E_AIState 이넘을 생성

 

BB_enemy_base에 State:Enum변수를 추가 디테일에서 E_AIState설정

AIC_Enemy_Base Set ValueAsObject뒤에 SetValueasEnum을 추가해줘 상태를 설정해준다. KeyName은 변수로 승격해주고 컴파일후 디폴트로 State를 적어준다.

나중에 이걸 SetStatePatrol 함수로 만들고 사이의 SetValueasObject는 지우는듯

데코레이터를 하나만든다 .맨위 Blackboard를 누르면 된다.

 

BT_Enemy_Base ChasePlayer노드위에 blackboard 데코레이션 추가

Observer를 OnResultChange로 하고BlackBoard Key 를 State로 변경하고 IsEqualTo,  Attack로 변경한다. if(State=="Attack")와 같다.

오른쪽은 Selector를 추가하고 IsEqualTo Patrol로 변경한다.  상태가 Attack일때 왼쪽 상태가 Patrol일때 오른쪽이 실행된다.

E_AIState값을 Patrol로 변경해보면

AIC_Enemy_Base에 SetStatePatrol함수를 만들어 다음과 같이 정리한다. 블랙보드의 State를 Enum Patrol로 설정해준다.

BT_Enemy_Base의

ChasePlayer의 데코레이터의 NotifyObserver를 OnResultChange로 바꾼다.

On Result Change : Attack -> Attack (같은 상태의 새 변화로 간주)

On Value Change : Attack -> Attack (같은 것으로 간주, 변화 X)

중단 당했을 때 Observer aborts를 self로 해주어 시퀀스 실패시 중간에 멈추게 해준다

None:

이 옵션이 선택된 경우, 데코레이터가 감시 중에 자식 노드의 실행을 중단시키지 않습니다. 따라서 데코레이터가 조건을 검사하고 있는 동안에는 자식 노드가 계속 실행됩니다.

 

Self:

이 옵션이 선택된 경우, 데코레이터 자체가 감시하고 있는 조건이 충족되면 자식 노드의 실행을 중단합니다. 즉, 데코레이터의 조건이 충족되면 자식 노드의 실행을 중단하고 다른 노드로 이동하게 됩니다.

 

Lower Priority:

이 옵션이 선택된 경우, 데코레이터보다 낮은 우선 순위를 가진 다른 데코레이터가 감시하고 있는 조건이 충족되면 자식 노드의 실행을 중단합니다. 다른 데코레이터의 조건이 충족되면 해당 데코레이터로 인해 실행이 중단됩니다.

 

Both:

이 옵션이 선택된 경우, 데코레이터 자체가 감시하고 있는 조건과 데코레이터보다 낮은 우선 순위를 가진 다른 데코레이터의 조건 둘 다 충족되면 자식 노드의 실행을 중단합니다. 두 가지 조건 중 하나만 충족되어도 실행이 중단됩니다.

취소 되었을때  BTT_MovePatrol Task의  AIMoveTo실행을 즉시 멈추게 한다. EventReceiveAbortAI 로 가게 한다.

Function Override EventReceiveAbortAI를 추가하고 StopMovement롤 멈추게 한다. 아래부분을 구현한다.

새로운 시퀀스를 추가한다.  포커스를 클리어해주고 Wait해준다

 

 

 

AIC_Enemy_Base에 AIPerception을 추가해준다. 여러가지 감각기능을 추가해준다.

DominantSense(주도적인 감각)로 여러가지를 고를수 있다.

AISense_Sight를 선택하고 시감각 범위를 설정한다. MaxAge를 10으로 놓으면 범위를 벗어나면 10초후 망각한다.

  • Sight Radius (시야 반경)
  • Lose Sight Radius (시야 손실 반경)
  • Peripheral Vision Angle (주시 시야 각도)
  • Peripheral Vision Angle Degrees (주시 시야 각도, 도 단위)
  • Detection by Affiliation (소속에 따른 감지)
  • Auto Success Range From Last Seen Location (마지막으로 본 위치로부터의 자동 성공 범위)
  • Max Age (최대 나이)
  •  '(아포스트로피, apostrophe)를 눌러 AI정보를 모니터링할수 있다 NumKey 1 2 3 4를 눌러 추가해보자
  • 검색대상을 전부 체크합니다
  •  

체크되면 구체가 표시됩니다.

청각을 추가합니다.

 

BP_ThirdPersonCharacter에 Jump후 Maker Noise를 추가합니다.

AIC_Enemy_Base의 AIPerception을 선택후 디테일에서 OnPerceptionUpdated + 를 클릭해 이벤트를 추가해줍니다.

 

작성전 E_AISense를 작성합니다 . Sight, Hearing뿐입니다.

AIC_Enemy_Base로 돌아와서

CanSenseActor함수를 만들고 Input Outptus를 설정합니다.

EventGraph에서

EventOnPossess뒤의 Dealy를 없애주고 다음같이 정리합니다.

이벤트그래프에서 Branch를 추가하고

CanSenseActor를 구현합니다. BreakActorPerception에서 자극을 받아 ReturnNode에서 자각결과값을 리턴합니다.

AIPerception에서 GetActorsPerception 리턴값은 배열인데 하나씩 풀어 visual인지 hearing인지 검사후 결과를 리턴합니다.

SetStateAttack함수를 구현합니다.

HandleSensedSight함수를 구현합니다. AttackTarget을 설정해 공격하게 만듭니다.

 

이벤트그래프에서 OnPerceptionUpdate(AIPerception)을 구현합니다. 자극에 반응한 액터들을 찾아냅니다. 

이벤트그래프에서 맨뒤에 놔주고 Actor를 연결해줍니다.

GetCurrentState함수를 만듭니다.

HandleSensedSight함수에 GetCurrentState를 넣어줍니다.

AIC_Enemy_Base>SetStateDetect함수를 만들고

BB_Enemy_Base에 LocationOfDetect New키를 만들고 SetValueasVector를 추가합니다.

AIC_Enemy_Base에 HandleSensedHearing함수를 만들어 현재상태가 Patrol이나 Detect일대 Location을 리턴합니다.

실습 벽너머에서 점프해서 소리를 내면 해당 위치로 오게합니다.

AIC_Enemy_Base에 Hearing처리 부분을 추가합니다.

완성된 OnPerceptionUpdate입니다.

실습문제입니다. 소리로 Detect되면 처리할 걸 만듭니다.

BTT_SetStatePatrol을 만듭니다.

Wait뒤에 추가해줍니다.

추가후 BlackboardBasedCondition 데코레이션의 설정을 해줍니다. State상태가 Detect되면 실행되게 해줍니다.

 

 

 

'강동새싹언리얼수업 > 언리얼' 카테고리의 다른 글

231227 수업 EQS (Environment Query System)  (1) 2023.12.28
Retarget  (0) 2023.12.22
SketchFab OpenBrush  (0) 2023.12.22
231221 수업.  (0) 2023.12.21
VR 다트게임 위젯 만들기  (0) 2023.12.21