슈팅 게임에서 조준점의 간격은 항상 고정되어있지 않고 캐릭터의 움직임이나 점프, 사격, 조준사격 등의 요인에 의해 벌어지거나 좁혀지는게 일반적이다.

 

조준점의 간격에 영향을 주는 요인들을 하나씩 계산해서 하나의 변수로 만들어주면 생각보다 어렵지 않게 구현할 수 있다.

 

/* 조준점의 최종 확산 계수 */
float CrosshairSpreadMultiplier;

/* 속력에 의한 확산 계수 */
float CrosshairVelocityFactor;

/* 점프에 의한 확산 계수 */
float CrosshairInAirFactor;

/* 조준에 의한 확산 계수 */
float CrosshairAimFactor;

/* 사격에 의한 확산 계수 */
float CrosshairShootingFactor;

 

우선은 이동, 점프, 조준, 사격 총 4가지 요인으로 정해서 구현해본다.

 

 

 

이동에 의한 확산값은 현재 이동속도를 최대 이동속도에 대한 비율을 구하면 된다.

 

Vector Velocity = GetVelocity();
Velocity.Z = 0.f // Z값은 필요하지 않다
CrosshairVelocityFactor = Velocity.Size() / GetCharacterMovement()->MaxWalkSpeed;

/* 또는 */
FVector2D WalkSpeedRange = FVector2D(0.f, GetCharacterMovement()->MaxWalkSpeed);
FVector2D VelocityMultiplierRange = FVector2D(0.f, 1.f);
FVector Velocity = GetVelocity();
Velocity.Z = 0.f;

CrosshairVelocityFactor = FMath::GetMappedRangeValueClamped(WalkSpeedRange, VelocityMultiplierRange, Velocity.Size());

 

구한 값을 최종 값에 더해주면 이동에 의한 계산은 끝난다.

 

CrosshairSpreadMultiplier = 0.5f + CrosshairVelocityFactor; // 0.5는 기본 계수

 

 

나머지 값들을 구하기 전에 HUD를 우선 만들어둔다.

 

조준점은 하나로 합쳐진것을 사용하면 확산시킬수 없기 때문에 각 방향으로 나눠진것을 총 4개 사용한다.

 

Crosshair Spread Max의 값을 고정시켜놓고(위의 그래프에서는 16으로 지정) C++에서 계산한 값인 Crosshair Spread Multiplier를 곱해서 사용하게 된다. 조준점을 4개로 분할했으므로 위와 같지만 계산식만 조금 다른 노드들을 4개 사용한다.

 

HUD 블루프린트 작성이 완료되었다면 이제 각 확산 값만 구해주면 잘 적용될 것이다.

 

이동에 의한 확산만 적용한 상태

 

점프에 의한 확산값은 현재 캐릭터가 점프중인지를 판별해서 값을 보간해준다.

 

if (GetCharacterMovement()->IsFalling())
{
	// 점프중에는 천천히 확산되고
    CrosshairInAirFactor = FMath::FInterpTo(CrosshairInAirFactor, 2.25f, DeltaTime, 2.25f);
}
else
{
	// 착지하면 빠르게 회복한다
    CrosshairInAirFactor = FMath::FInterpTo(CrosshairInAirFactor, 0.f, DeltaTime, 30.f);
}

CrosshairSpreadMultiplier = 0.5f + CrosshairVelocityFactor + CrosshairInAirFactor;

 

이동+점프 확산 동시 적용

 

조준도 점프와 마찬가지로 값을 보간해준다. 단, 조준은 확산이 아니라 좁혀지기 때문에 값을 빼주어야 한다.

 

if (bAiming)
{
    CrosshairAimFactor = FMath::FInterpTo(CrosshairAimFactor, 0.3f, DeltaTime, 30.f);
}
else
{
    CrosshairAimFactor = FMath::FInterpTo(CrosshairAimFactor, 0.f, DeltaTime, 30.f);
}

CrosshairSpreadMultiplier = 0.5f + CrosshairVelocityFactor + 
                            CrosshairInAirFactor - CrosshairAimFactor;

 

조준 적용

 

 

사격에 의한 확산값은 단순하게 구현한다면 사격에 의한 확산값을 항상 0으로 보간하고 사격하는 순간만 상수값을 대입하는 방법이 있다.

 

// 사격하는 순간
CrosshairShootingFactor = 1.5f;

/* */

// 항상 0으로 보간
CrosshairShootingFactor = FMath::FInterpTo(CrosshairShootingFactor, 0.f, DeltaTime, 30.f);

 

단순하게 구현

 

사격시 조준점이 즉시 회복되지 않고 일정시간 뒤에 회복되길 원한다면 bool값과 타이머 매니저를 이용해서 구현해주면 된다.

 

 

CrosshairSpreadMultiplier = 
    0.5f + // 기본 계수
    CrosshairVelocityFactor +
    CrosshairInAirFactor -
    CrosshairAimFactor + 
    CrosshairShootingFactor;

 

최종적으로 위의 수식이 만들어진다.

https://dev-sbee.tistory.com/84?category=1219843 

'언리얼 엔진 > 정보' 카테고리의 다른 글

조준점 HUD 구현  (0) 2022.11.05
AI, Behavior Tree, Blackboard  (0) 2022.10.19
파생 데이터 캐시 경로(DDC) 바꾸기  (0) 2022.10.13
Mixamo의 루트모션 애니메이션 사용  (0) 2022.10.12
커스텀 CharacterMovement  (0) 2022.10.12

AI는 AIController에 의해 제어된다.

흔히 생각하는 몬스터의 패턴 등은 Behavior Tree(행동 트리)로 작성하게 된다.

Blackboard(블랙 보드)는 행동 트리에서 관리하는 데이터라고 보면 된다.

 

행동 트리와 블랙 보드는 블루프린트와는 개념이 다르다. 에디터에 존재할 뿐이다.

 

프로젝트 빌드 파일의 공개 종속성 모듈에 "AIModule", "GameplayTasks" (BTTaskNode 사용시 필요) 를 추가해주어야 한다.

 

AAIController::RunBehaviorTree(UBehaviorTree* BTAsset);

 

AIController에서 RunBehaviorTree 호출시 행동 트리에 포함된 블랙 보드까지 AIController에 자동으로 등록된다.

이후 GetBlackboardComponent 호출로 블랙보드에 접근할 수 있다.

 

GetBlackboardComponent()->SetValueAsVector(KeyName, VectorValue); // key-value 등록
GetBlackboardComponent()->ClearValue(KeyName); // key-value 초기화

 

블랙 보드는 <key, value> 형식으로써 c++의 map과 유사하다고 보면 될 것 같다.

 

노드는 크게 Composites, Decorator, Service, Tasks로 총 4종류가 있다. 

 

Composites 노드

 

높은 우선순위의 자식 노드부터 순차적으로 실행된다.

  • Selector: 자식 노드 중 하나라도 실행 성공시 성공한 것으로 본다. 옆의 노드들은 더 이상 실행되지 않는다.
  • Sequence: 자식 노드 중 하나라도 실행 실패시 실패한 것으로 본다. 옆의 노드들은 더 이상 실행되지 않는다.
  • Simple Parallel: 이름 그대로 단순 병렬 노드이다. 전체 노드 트리와 동시에 하나의 태스크를 실행시킨다.

 

Decorators 노드

 

조건절이라고도 한다. if의 개념과 같다. 컴포짓이나 태스크노드에 붙여서 실행 여부를 정의할 수 있다.

 

Services 노드

 

 

 

Tasks 노드

 

AI의 이동이나 블랙보드의 값 조정등의 작업을 한다.

Tasks 노드를 C++ 커스텀으로 만들시에는 공개 종속성 모듈에 "GameplayTasks"를 포함시켜 주어야 한다.

 

커스텀 노드를 만들었다면 ExecuteTask를 구현하면 된다.

매개변수 OwnerComp를 통해 블랙보드와 AIController에 접근할 수 있다.

 

EBTNodeResult::Type을 반환함으로써 성공/실패 유무를 반환한다.

 

'언리얼 엔진 > 정보' 카테고리의 다른 글

조준점 HUD 구현  (0) 2022.11.05
에이밍 시스템 구현  (0) 2022.10.27
파생 데이터 캐시 경로(DDC) 바꾸기  (0) 2022.10.13
Mixamo의 루트모션 애니메이션 사용  (0) 2022.10.12
커스텀 CharacterMovement  (0) 2022.10.12

 

https://blog.naver.com/ryumr/221334719805

 

'언리얼 엔진 > 정보' 카테고리의 다른 글

에이밍 시스템 구현  (0) 2022.10.27
AI, Behavior Tree, Blackboard  (0) 2022.10.19
Mixamo의 루트모션 애니메이션 사용  (0) 2022.10.12
커스텀 CharacterMovement  (0) 2022.10.12
FTimerDelegate에 관련된 내용  (0) 2022.10.11

 

https://youtu.be/f32fzAuJyZU

 

 

'언리얼 엔진 > 정보' 카테고리의 다른 글

AI, Behavior Tree, Blackboard  (0) 2022.10.19
파생 데이터 캐시 경로(DDC) 바꾸기  (0) 2022.10.13
커스텀 CharacterMovement  (0) 2022.10.12
FTimerDelegate에 관련된 내용  (0) 2022.10.11
ApplyDamage, TakeDamage  (0) 2022.10.11

+ Recent posts