float UGameplayStatics::ApplyDamage(
AActor* DamagedActor, // 피해를 입은 대상
float BaseDamage, // 피해량
AController* EventInstigator, // 피해를 입힌 대상
AActor* DamageCauser, // 피해를 준 액터 (수류탄, 칼 등등)
TSubclassOf<UDamageType> DamageTypeClass) // 피해의 종류 (범위공격, 헤드샷 등)
ApplyDamage 호출 시, DamagedActor의 TakeDamage가 호출이 된다.
ApplyDamage 호출 시 OnTakeAnyDamage에 등록된 메소드가 호출된다.
TakeDamage 함수는 오버라이딩이 가능하므로 여러가지 커스텀 대미지 이벤트를 사용할 수 있을것이다.
Any, Point, Radial 3가지 타입이 있는데 3브랜치가 아닌 Point, Radial 브랜치를 수행해서 데미지를 계산한 다음 Any를 처리하는 방식이다.
예를 들어 Point 타입인 경우 헤드샷이면 데미지의 배율을 2배로 늘리고 Any를 수행한다거나 Radial 타입인 경우 범위 거리에 따른 데미지 편차를 계산 후 Any를 수행하는 방식이다.
타이머 핸들에 함수를 바인딩 시켜서 일정 시간 뒤에 실행시키거나 일정 시간마다 반복 실행 시킬 수 있다.
[132. Spawning The Projectile]
SpawnActor는 새로운 액터를 월드에 생성시켜준다. 템플릿에는 어떤 클래스를 만들어 줄 것인지를 지정하고 첫 번째 인자인 UClass에는 블루프린트도 들어갈 수 있기때문에 의미가 다르다.
예를 들어 C++ 클래스를 블루프린트로 파생시켜서 만들고 코드상에서는 스태틱 메시를 따로 지정하지 않는다면 C++ 클래스를 SpawnActor 하게될 시 보이지 않는 액터가 생성이 될 것이다. 하지만 스태틱 메시를 포함한 다른 값들이 지정된 블루프린트를 SpawnActor 한다면 정상적으로 잘 보일것이다.
[133. Projectile Movement Component]
발사체를 이동시키는 방법은 크게 3가지가 있다.
매 틱마다 Transform을 변화시키는 것 (Set Location & Rotation)
물리를 적용시켜서 운동량을 변화시키는 것 (Add Impulse)
발사체 전용 Movement Component 사용
언리얼에는 발사체를 위한 Movement 컴포넌트가 따로 존재한다.
발사체에 컴포넌트를 붙여주고 속도 설정만 해주면 된다.
[134. Hit Events]
어떤 Primitive Component와 충돌 이벤트(Hit, OnOverlap)가 발생했을 때 바인딩 시킨 메소드들을 호출할 수 있다.
단순히 액터를 숨긴다고 실제로 월드에서 비활성화 되는것은 아니다. 눈에 안보일뿐이지 타워는 계속 플레이어를 인지한다.
추가로 콜리전까지 꺼주면 콜리전 이벤트에서 검출되지 않을것이다.
다만 이 실습에서는 콜리전 이벤트를 통한 공격이 이루어지는것이 아닌 타겟(플레이어)를 처음부터 설정해놓고 매 틱마다 추적하는 방식이기때문에 플레이어에게 생존여부를 알수있는 bool값을 추가해서 죽은 상태라면 타워가 플레이어를 추적하거나 발사하지 않는 방식을 사용해야한다.
OnComponentBeginOverlap같은 이벤트라면 콜리전을 없애는것 만으로도 해결이 될 것이라고 생각된다.
폰의 이동은 MovementComponent, 제어는 Controller에 의해 이뤄진다.
컨트롤러가 폰에 빙의해서 제어하는 방식이다.
플레이어가 폰을 제어할 때 PlayerController를 사용하고 AI가 폰을 제어할 때는 AIController를 사용하면 된다.
Controller는 따로 설정하지 않으면 게임모드에 의해 기본 컨트롤러(PlayerController)가 설정된다.
MovementComponent는 따로 추가해주지 않으면 컴포넌트가 붙지 않는다.
Pawn에서 MovementComponent를 반환받을 수 있는 GetMovementComponent가 구현되어 있지만 해당 컴포넌트를 폰에서 관리하고 있지 않기 때문에 AddMovementInput등의 기능이 작동하지 않는다.
만약 MovementComponent를 붙여준다면 MovementComponent::UpdatedComponent = RootComponent 를 반드시 추가해서 RootComponent에 접근할 수 있게 해야한다.
Character는 Pawn을 확장한것인데 조금 더 복잡한 행동이나 애니메이션을 처리하는것이 추가되었다.
CharacterMovementComponent가 기본적으로 포함되어있다.
// Character 코드 일부
TObjectPtr<UCharacterMovementComponent> CharacterMovement;
Character::Character()
{
CharacterMovement = CreateDefaultSubobject<UCharacterMovementComponent>(ACharacter::CharacterMovementComponentName);
if (CharacterMovement)
{
CharacterMovement->UpdatedComponent = CapsuleComponent;
}
}
Pawn에는 없는 내용이 Character에는 기본적으로 포함이 되어 있는 것을 확인할 수 있다.
위에서 언급한대로 CharacterMovement가 CapsuleComponent(=RootComponent)를 관리하도록 설정한다.
걷기 최대속도, 가속도, 점프 등 이동에 관련된 다양한 내용과 애니메이션에 관한 내용들이 추가로 구현이 되어있다.
추가로 액터와 폰에는 기본적으로 메시가 존재하지 않지만 캐릭터는 스켈레탈 메시가 붙어있다.