ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 블루아카이브 루트슈터 팬게임 프로젝트(7) - 사격 매커니즘, 반동
    루트슈터 프로젝트 2024. 1. 3. 23:16

    더 디비전2

     

    안녕하세요. 오늘 설명할 기능은 사격 매커니즘입니다. FPS, TPS는 모두 크로스헤어(조준점)가 카메라 정중앙에 있습니다. 하지만 캐릭터가 장비한 총기는 항상 중앙이 아닌 오른쪽이나 왼쪽에 있기 때문에 무작정 총구에 총알이 발사되게 설정한다면 왜곡이 생깁니다. 이렇기 때문에 총알 발사체를 설정하지 않고 레이캐스트 기능을 이용하여 사격 기능을 구현하는 경우가 많습니다. 하지만 저는 어떻게든 발사체로 구현하고 싶었고 한가지 방법을 생각했습니다. 

     

     

     

     

    발퀄 죄송합니다.

     

    바로 카메라에서 조준점 방향으로 레이캐스트를 쏘고 충돌지점으로 총알을 발사하게 하는 방법입니다. 이렇게 하면 발사체로 사격을 구현하면서 조준점으로 총알이 가도록 만들 수 있습니다. 바로 코드 설명 하겠습니다. 

     

    Gun.cpp

    void AGun::Fire(FVector startPoint, FVector endPoint)
    {
        FHitResult hitResult;
        if (GetWorld())
        {
            //DrawDebugLine(GetWorld(), startPoint, endPoint, FColor::Red, true, -1.f, 0, 2.f);

            if (GetWorld()->LineTraceSingleByChannel(hitResult, startPoint, endPoint, ECollisionChannel::ECC_Visibility))
            {   
                SpawnBullet(FVector(hitResult.ImpactPoint - projectileSpawnPoint->GetComponentLocation()).GetSafeNormal());
            }
        }
    }

     

    총의 발사 함수입니다. 먼저 Visibility 채널로 라인트레이싱을 해서 충돌하는 포인트가 어딘지 감지합니다. 어딘가에 충돌했다면 충돌지점에 총구 위치를 뺄셈하여 총구에서 충돌지점으로 향하는 벡터를 만들고 normalize까지 하여 총알을 스폰합니다. 

     

     

    Gun.cpp

    void AGun::SpawnBullet(FVector direction)
    {
        AProjectile* proj = (GetWorld()->SpawnActor<AProjectile>(
            projectileClass ,
            projectileSpawnPoint->GetComponentLocation(),
            projectileSpawnPoint->GetComponentRotation()
        ));
        if(proj)
        {
            proj->SetDamage(gunStat.weaponDamage); //투사체 스폰 및 데미지 랜덤설정
            proj->SetOwner(this); //이 총알의 주인 = 총
            proj->SetVelocity(direction);
        }
    }

     

    총알 액터를 스폰하고 총알의 데미지나 Owner를 설정한 후 총알의 Velocity를 설정합니다. 

     

    Projectile.cpp

    void AProjectile::SetVelocity(FVector direction)
    {
        projMovementComp->Velocity = direction * projMovementComp->InitialSpeed;
    }

     

    총알의 direction(방향)에 원하는 총알의 속도를 곱하여 Velocity를 지정해주면 됩니다. 

     

    PlayerCharacter.cpp

    void APlayerCharacter::Fire()
    {
        if(gun && gun->nowMag !=0 ){
            UAnimInstance* animIn = GetMesh()->GetAnimInstance();
            if(animIn && FireMont){
                animIn->Montage_Play(FireMont);
            } else UE_LOG(LogTemp, Display, TEXT("Fire animation failed"));

            FVector startPoint = cameraComp->GetComponentLocation() + cameraComp->GetForwardVector() * 150;
            FVector endPoint = startPoint + cameraComp->GetForwardVector() * 10000;
            gun->Fire(startPoint, endPoint);
            Recoil(0.3);
        } else if(gun && gun->nowMag == 0) StartReload();
    }

     

    캐릭터가 발사 함수를 실행할때 라인 트레이싱의 시작, 끝 지점을 만드는 방법입니다. TPS는 카메라가 뒤에 있기 때문에 카메라의 위치를 받아오고 앞쪽으로 조금 당겨놓은 지점을 스타트 포인트로 지정합니다. 그리고 끝 지점으로는 스타트 포인트로부터 카메라가 앞으로 향하는 벡터에 총의 사거리만큼 곱하시면 되는데, 저는 사거리를 정하지 않아서 임의의 값을 곱했습니다.

     

     

    void APlayerCharacter::Recoil(float weaponRecoil) //캐릭터에게 반동 흔들림 부여
    {
        this->AddControllerPitchInput(-weaponRecoil);
        this->AddControllerYawInput(FMath::RandRange(-weaponRecoil, weaponRecoil));
    }

    Recoil 함수는 반동에 대한 함수입니다. 무기마다 각각 다른 값의 반동 변수를 부여해놓고 그 값이 큰만큼 큰 반동을 부여할 것입니다. AddControllerPitchInput 함수는 카메가라 위, 아래로 움직이게 하는 함수이고, AddControllerYawInput은 좌,우로 움직이게 하는 함수입니다. 위 방향으로는 무기의 반동만큼 정직하게 움직이도록 설정하였고, 좌우 반동은 RandRange 함수로 랜덤하게 좌우로 움직이도록 설정하였습니다. 

     

     

     

     

    결과물입니다. 조준점에 제대로 총알이 날라가고 반동 또한 좌우로 잘 튀고 있습니다. 생각보다는 총알 궤적이 그렇게 부자연스럽지 않네요. 이정도면 만족입니다. 

     

    이만 줄이겠습니다. 읽어주신 분들 모두 감사합니다. 

Designed by Tistory.