Dev7 npc 무기 장착, Mixamo 애니메이션 적용 성공, 플레이어 공격 애니메이션
오버랩 범위 안에서 시작하면 오버랩 안 먹힘, 오버랩 범위 바깥에서 오버랩 범위로 들어가면 잘 됨
그래서 weapon 블루프린트 클래스에서 BeginPlay()에서 타이머 놓고 이벤트 실행
특정 액터가 본인(npc 무기 블루프린트)과 오버랩핑 중인지 확인 후 오버랩핑 중이면 npc 무기 장착 함수 실행
Weapon.cpp
플레이어의 무기 장착 함수와 거의 비슷함. 필요없는 걸 뺌.
void AWeapon::Equip_NPC(AYaroCharacter* Char)
{
if (Char)
{
SkeletalMesh->SetCollisionResponseToChannel(ECollisionChannel::ECC_Camera, ECollisionResponse::ECR_Ignore);
SkeletalMesh->SetCollisionResponseToChannel(ECollisionChannel::ECC_Pawn, ECollisionResponse::ECR_Ignore);
SkeletalMesh->SetSimulatePhysics(false);
const USkeletalMeshSocket* RightHandSocket = Char->GetMesh()->GetSocketByName("RightHandSocket");
if (RightHandSocket)
{
RightHandSocket->AttachActor(this, Char->GetMesh());
bRotate = false;
}
}
}
뭐가 많이 바껴서 포스팅 쓰기 어렵다...
몬스터 공격 관련
Enemy.h 에 추가됨
CombatCollision은 몬스터의 무기(혹은 공격을 가하는 몸..?신체 일부)에 붙인 콜리전
ActiveCollision - CombatCollision 활성화
DeactiveCollision - CombatCollision 비활성화
UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category = "AI")
bool bOverlappingCombatSphere;
UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category = "AI")
AMain* CombatTarget;
UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category = "Combat")
class UBoxComponent* CombatCollision;
UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category = "Combat")
class UBoxComponent* CombatCollision2;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Combat")
class UAnimMontage* CombatMontage;
UFUNCTION()
void CombatOnOverlapBegin(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult);
UFUNCTION()
void CombatOnOverlapEnd(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex);
UFUNCTION(BlueprintCallable)
void ActivateCollision();
UFUNCTION(BlueprintCallable)
void DeactivateCollision();
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Combat")
bool bAttacking;
void Attack();
UFUNCTION(BlueprintCallable)
void AttackEnd();
Enemy.cpp에 추가됨
in 생성자, 저 부모 소켓(EnemySocket은 스켈레톤에서 무기나 신체 일부에 붙여둔 거)
CombatCollision = CreateDefaultSubobject<UBoxComponent>(TEXT("CombatCollision"));
CombatCollision->AttachToComponent(GetMesh(), FAttachmentTransformRules::SnapToTargetIncludingScale, FName("EnemySocket_1"));
CombatCollision2 = CreateDefaultSubobject<UBoxComponent>(TEXT("CombatCollision2"));
CombatCollision2->AttachToComponent(GetMesh(), FAttachmentTransformRules::SnapToTargetIncludingScale, FName("EnemySocket_2"));
몽둥이 두 개에 컴뱃 콜리전 확인 가능
in BeginPlay(), 이해 필요..
CombatCollision->OnComponentBeginOverlap.AddDynamic(this, &AEnemy::CombatOnOverlapBegin);
CombatCollision->OnComponentEndOverlap.AddDynamic(this, &AEnemy::CombatOnOverlapEnd);
CombatCollision2->OnComponentBeginOverlap.AddDynamic(this, &AEnemy::CombatOnOverlapBegin);
CombatCollision2->OnComponentEndOverlap.AddDynamic(this, &AEnemy::CombatOnOverlapEnd);
CombatCollision->SetCollisionEnabled(ECollisionEnabled::NoCollision);
CombatCollision->SetCollisionObjectType(ECollisionChannel::ECC_WorldDynamic);
CombatCollision->SetCollisionResponseToAllChannels(ECollisionResponse::ECR_Ignore);
CombatCollision->SetCollisionResponseToChannel(ECollisionChannel::ECC_Pawn, ECollisionResponse::ECR_Overlap);
CombatCollision2->SetCollisionEnabled(ECollisionEnabled::NoCollision);
CombatCollision2->SetCollisionObjectType(ECollisionChannel::ECC_WorldDynamic);
CombatCollision2->SetCollisionResponseToAllChannels(ECollisionResponse::ECR_Ignore);
CombatCollision2->SetCollisionResponseToChannel(ECollisionChannel::ECC_Pawn, ECollisionResponse::ECR_Overlap);
}
전투 범위에 오버랩되면 전투 대상을 플레이어로 지정하고 불 변수 true하고 공격 함수 실행
오버랩 해제되면 불 변수 false하고 공격 상태였으면 MoveToTarget(Main);하고
전투 대상을 널로 지정
void AEnemy::CombatSphereOnOverlapBegin(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult)
{
if (OtherActor)
{
AMain* Main = Cast<AMain>(OtherActor);
if (Main)
{
CombatTarget = Main;
bOverlappingCombatSphere = true;
Attack();
}
}
}
void AEnemy::CombatSphereOnOverlapEnd(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex)
{
if (OtherActor)
{
AMain* Main = Cast<AMain>(OtherActor);
if (Main)
{
bOverlappingCombatSphere = false;
if (EnemyMovementStatus == EEnemyMovementStatus::EMS_Attacking)
{
MoveToTarget(Main);
CombatTarget = nullptr;
}
}
}
}
CombatCollision에 플레이어가 오버랩되면
일단 간단한 테스트 겸 체력 10씩 깎기로. (생성자에서 Damage = 10.f)
void AEnemy::CombatOnOverlapBegin(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult)
{
if (OtherActor)
{
AMain* Main = Cast<AMain>(OtherActor);
if (Main)
{
Main->HP -= Damage;
}
}
}
Grux의 CombatMontage에서 플레이어를 때리기 직전(일 거 같을 때) 프레임에 노티파이 ActiveCollision추가
플레이어를 때리고 난 뒤로 추정될 때 프레임에 노티파이 DeactiveCollision추가
NoCollision은 알겠는데 쿼리온리는 뭘까..
void AEnemy::ActivateCollision()
{
CombatCollision->SetCollisionEnabled(ECollisionEnabled::QueryOnly);
CombatCollision2->SetCollisionEnabled(ECollisionEnabled::QueryOnly);
}
void AEnemy::DeactivateCollision()
{
CombatCollision->SetCollisionEnabled(ECollisionEnabled::NoCollision);
CombatCollision2->SetCollisionEnabled(ECollisionEnabled::NoCollision);
}
bAttacking이 false면 (=공격 중이 아니면) true로 바꾸고
AnimInstance가져와서 컴뱃몽타주 재생, 근데 Attack 섹션으로 점프해서 재생
AttackEnd가 호출되었으면 불 변수 false하고
근데 아직 전투 범위 안에 있다? 다시 Attack() 실행
void AEnemy::Attack()
{
if (AIController)
{
AIController->StopMovement();
SetEnemyMovementStatus(EEnemyMovementStatus::EMS_Attacking);
}
if (!bAttacking)
{
bAttacking = true;
UAnimInstance* AnimInstance = GetMesh()->GetAnimInstance();
if (AnimInstance)
{
AnimInstance->Montage_Play(CombatMontage);
AnimInstance->Montage_JumpToSection(FName("Attack"), CombatMontage);
}
}
}
void AEnemy::AttackEnd()
{
bAttacking = false;
if (bOverlappingCombatSphere)
{
Attack();
}
}
GruxAnim_BP 변화
Grux 컴뱃몽타주, Notify와 Section을 볼 수 있음
플레이어 공격 모션 관련
Main.h
Enemy와 유사
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Items)
class AWeapon* EquippedWeapon;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Anims")
bool bAttacking;
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Anims")
class UAnimMontage* CombatMontage;
void Attack();
UFUNCTION(BlueprintCallable)
void AttackEnd();
Main.cpp
in SetupPlayerInputComponent(), 액션 매핑에 숫자키 1 -> Attack
PlayerInputComponent->BindAction("Attack", IE_Pressed, this, &AMain::Attack);
공격 도중에는 이동 불가, 이동함수 조건에 && (!bAttacking) 추가
void AMain::MoveForward(float Value)
{
if ((Controller != nullptr) && (Value != 0.0f) && (!bAttacking))
{
// find out which way is forward
const FRotator Rotation = Controller->GetControlRotation(); // 회전자 반환 함수
const FRotator YawRotation(0.f, Rotation.Yaw, 0.f);
const FVector Direction = FRotationMatrix(YawRotation).GetUnitAxis(EAxis::X);
AddMovementInput(Direction, Value);
}
}
void AMain::MoveRight(float Value)
{
if ((Controller != nullptr) && (Value != 0.0f) && (!bAttacking))
{
// find out which way is forward
const FRotator Rotation = Controller->GetControlRotation(); // 회전자 반환 함수
const FRotator YawRotation(0.f, Rotation.Yaw, 0.f);
const FVector Direction = FRotationMatrix(YawRotation).GetUnitAxis(EAxis::Y);
AddMovementInput(Direction, Value);
}
}
장착한 무기가 있으면
불 변수 true, AnimInstance 불러와서 컴뱃몽타주 실행하는데 이제 Attack 섹션부터 시작
void AMain::Attack()
{
if (EquippedWeapon)
{
bAttacking = true;
UAnimInstance* AnimInstance = GetMesh()->GetAnimInstance();
if (AnimInstance && CombatMontage)
{
AnimInstance->Montage_Play(CombatMontage);
AnimInstance->Montage_JumpToSection(FName("Attack"), CombatMontage);
}
}
}
void AMain::AttackEnd()
{
bAttacking = false;
}
발표 때 테스트 영상으로 보여준 거라 프리뷰로 처음부터 시작
다음에 할 것 : 마법 이펙트 적용!!!!!!!!!!!!!!!!! 해서 플레이어가 마법 공격하게 하기