[70. Console Controller Input]

 

콘솔 컨트롤러 입력을 적용시켜 볼 것이다.

 

[프로젝트 세팅 - 입력] 에서 게임패드에 대응되는 액션이나 축을 매핑 시켜주면 된다.

 

게임패드의 경우 0과 1의 값만 대응되는 키보드 이동과는 다르게 아날로그 스틱의 조작에 따라 값이 다양하게 들어간다.

그것 때문에 아주 천천히 이동시 애니메이션이 너무 느리게 재생되어서 마치 캐릭터가 떠다니는 듯한 느낌을 받게된다.

 

 

이 문제는 블렌드 스페이스가 정교하게 설정되어있지 않아서 그렇다.

 

 

그리드 분할을 4개에서 8개로 늘리고 Walk 애니메이션을 Idle쪽에 가깝게 붙이면 이동속도가 느리더라도 걷는 모션이 충분히 재생 되어서 이제는 자연스럽게 된다.

 

별다른 작업을 하지 않아도 입력 매핑만 하면 되는 간단한 작업이다.

 

[71. Combat Mechanics #1]

 

검을 휘두를 때 적이 명중할 때를 감지할 수 있어야 하고 명중시 피해를 입혀야 한다.

기존에 있던 구체 콜리전 볼륨은 무기 습득을 위한 충돌 판정이므로 공격을 위한 새로운 콜리전 볼륨을 추가해야 한다.

 

 

// Weapon.h
public:
    UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category="Item | Combat")
    class UBoxComponent* CombatCollision;

// Weapon.cpp
AWeapon::AWeapon()
{
    CombatCollision = CreateDefaultSubobject<UBoxComponent>(TEXT("CombatCollision"));
    CombatCollision->SetupAttachment(GetRootComponent());
}

 

박스 콜리전을 만들고 적당한 크기와 위치를 조정한다.

 

Weapon은 Item을 상속받는 클래스이고 Item에 습득을 위한 OnOverlapBegin/End 함수가 바인딩 되어있다.

무기는 공격을 위한 콜리전 볼륨이 하나 더 추가되었고 해당 무기와 겹침 판정이 일어나면 공격이 이루어졌다는걸 의미하므로 또다른 OnOverlapBegin/End 함수가 필요하다.

또한 Item 클래스에서 BeginPlay 함수 내에서 바인딩 되었으므로 Weapon에서도 BeginPlay시 바인딩 해주기 위해 BeginPlay를 오버라이드 해준다.

 

 

// Weapon.h
public:
    // 상속받은 것이 아니므로 virtual과 override가 붙지 않는다
    // 차후 무기의 종류가 많아진다면 virtual정도는 붙을 수 있을 것이다
    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);
protected:
	virtual void BeginPlay() override;
    
// Weapon.cpp
void AWeapon::BeginPlay()
{
    Super::BeginPlay();

    CombatCollision->OnComponentBeginOverlap.AddDynamic(this, &AWeapon::CombatOnOverlapBegin);
    CombatCollision->OnComponentEndOverlap.AddDynamic(this, &AWeapon::CombatOnOverlapEnd);
}

 

박스 콜리전에 대한 겹침 이벤트 발생에 대한 구조도 만들었으니 실제 내용을 구현할 차례이다.

 

 

내가 피해를 입는 것 외에 적이 공격을 당했을 시, 피를 뿜어내는 것과 같은 파티클 시스템이 필요하다.

적마다 다른 피격 효과를 가질 수 있으므로 파티클은 Enemy가 직접 가지도록 한다.

해당 파티클을 재생시키는 것은 Weapon에서 담당하도록 한다.

 

// Enemy.h
public:
    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "AI")
    float Health;
    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "AI")
    float MaxHealth;
    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "AI")
    float Damage;

    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "AI")
    class UParticleSystem* HitParticles;
    
// Enemy.cpp
AEnemy::AEnemy()
{
    // 지금은 안쓰지만 다음 구현을 위해 미리 추가
    Health = 75.f;
    MaxHealth = 100.f;
    Damage = 10.f;
}

 

// Weapon.h
public:
    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Item | Combat")
    float Damage;
    
// Weapon.cpp
AWeapon::AWeapon()
{
    // 지금은 안씀
    Damage = 25.f;
}

void AWeapon::CombatOnOverlapBegin(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult)
{
    if (OtherActor)
    {
        AEnemy* Enemy = Cast<AEnemy>(OtherActor);
        if (Enemy)
        {
            if (Enemy->HitParticles)
            {
                // 월드에, 파티클을, 어느 위치에, 어느 방향으로, 재생이 끝나면 자동 파괴여부
                UGameplayStatics::SpawnEmitterAtLocation(GetWorld(), Enemy->HitParticles, GetActorLocation(), FRotator(0.f), true);
            }
        }
    }
}

 

Enemy_BP에서 파티클을 설정 후 겹침 이벤트 발생시 파티클이 재생된다.

의도하는 사항은 공격 적중시에만 파티클이 재생되길 원하지만 지금은 공격을 하지 않아도 적과 겹치기만 하면 파티클이 재생된다.

 

우선은 여기까지만 구현하고 다음에 해당 사항을 수정하도록 한다.

 

[72. Combat Mechanics #2]

 

공격 적중시 재생되는 파티클의 위치가 정확하지 않다는 문제점이 있다.

GetActorLocation 함수를 통해 위치를 가져왔는데 이 위치가 무기의 중심점이기 때문이다. 사실상 손잡이에서 파티클이 튀는 것과 같다.

 

무기의 스켈레탈 메시에서 소켓을 추가하고 파티클이 재생되길 원하는 위치로 조절한다.

 

void AWeapon::CombatOnOverlapBegin(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult)
{
    if (OtherActor)
    {
        AEnemy* Enemy = Cast<AEnemy>(OtherActor);
        if (Enemy)
        {
            if (Enemy->HitParticles)
            {
                const USkeletalMeshSocket* WeaponSocket = SkeletalMesh->GetSocketByName("WeaponSocket");
                if (WeaponSocket)
                {
                    FVector SocketLocation = WeaponSocket->GetSocketLocation(SkeletalMesh);
                    // 월드에, 파티클을, 어느 위치에, 어느 방향으로, 재생이 끝나면 자동 파괴여부
                    UGameplayStatics::SpawnEmitterAtLocation(GetWorld(), Enemy->HitParticles, SocketLocation, FRotator(0.f), true);
                }
            }
        }
    }
}

 

소켓의 위치를 받아와서 해당 위치로 재생하게끔 변경하면 쉽게 해결된다.

 

이제 공격하지 않아도 상시 적용되는 공격 판정을 수정할 차례이다.

 

우선 애니메이션 몽타주에 공격 시작과 끝에 해당하는 부분에 노티파이를 설정한다.

 

// Weapon.h
public:
    UFUNCTION(BlueprintCallable)
    void ActivateCollision();
    UFUNCTION(BlueprintCallable)
    void DeActivateCollision();

// Weapon.cpp
void AWeapon::BeginPlay()
{
    CombatCollision->SetCollisionEnabled(ECollisionEnabled::NoCollision); // 충돌시 쿼리만(물리x)
    CombatCollision->SetCollisionObjectType(ECollisionChannel::ECC_WorldDynamic); // WorldDynamic에 대해서만 충돌판정
    CombatCollision->SetCollisionResponseToAllChannels(ECollisionResponse::ECR_Ignore); // 모든 채널에 대한 반응을 무시함
    CombatCollision->SetCollisionResponseToChannel(ECollisionChannel::ECC_Pawn, ECollisionResponse::ECR_Overlap); // Pawn에 대한 충돌만 겹침으로 허용
}

void AWeapon::ActivateCollision()
{
    CombatCollision->SetCollisionEnabled(ECollisionEnabled::QueryOnly); // 쿼리만 처리
}

void AWeapon::DeActivateCollision()
{
    CombatCollision->SetCollisionEnabled(ECollisionEnabled::NoCollision); // 충돌처리 X
}

 

어떤 채널과 충돌할지는 모두 설정 되어있지만 초기에는 NoCollision 속성을 통해 충돌이 발생하지 않게 막았다.

노티파이를 통해 충돌 여부를 On/Off하는 방식으로 구현 되어있다.

 

마지막으로 MainAnim_BP에서 노티파이에 대한 처리를 해주면 공격 시 특정 구간에서만 판정이 발생하도록 변경이 가능해진다.

 

[정리]

 

  • 콘솔 컨트롤러 조작을 고려한다면 블렌드 스페이스를 잘 설정해야 한다.
  • 공격을 위한 콜리전 볼륨이 추가로 필요하다.
  • 적의 타입별로 피격 이펙트가 다를 수 있으므로 파티클만 들고있다가 공격 적중 시 무기에서 해당 파티클을 재생하도록 한다.
  • 노티파이를 통해 공격 판정을 On/Off하여 제어할 수 있다.
  • 스켈레탈 메시에 추가한 소켓의 위치로 파티클을 재생시킬 수 있다.

'언리얼 엔진 > UE4 C++' 카테고리의 다른 글

[UE C++] Combat #7  (0) 2022.09.13
[UE C++] Combat #6  (0) 2022.09.13
[UE C++] Combat #4  (0) 2022.09.11
[UE C++] Combat #3  (0) 2022.09.11
[UE C++] Combat #2  (0) 2022.09.11

+ Recent posts