3.2 - 발사 구현

일인칭 슈팅 캐릭터의 발사 방법을 배워봅니다.

Windows
MacOS
Linux

이번 단계에서는 캐릭터가 발사체 발사를 시작할 수 있도록 Fire 함수를 구현해 보겠습니다.

Fire 함수 구현

  1. Solution Explorer 에서 FPSCharacter 클래스 CPP 파일을 찾고 FPSCharacter.cpp 를 엽니다.

  2. FPSCharacter.cpp 상단에 다음 #include 를 추가합니다.

    #include "FPSProjectile.h"
  3. FPSCharacter.cpp 에 다음 Fire 함수 정의를 추가합니다:

    void AFPSCharacter::Fire()
    {
        // 프로젝타일 발사를 시도합니다.
        if (ProjectileClass)
        {
            // 카메라 트랜스폼을 구합니다.
            FVector CameraLocation;
            FRotator CameraRotation;
            GetActorEyesViewPoint(CameraLocation, CameraRotation);
    
            // MuzzleOffset 을 카메라 스페이스에서 월드 스페이스로 변환합니다.
            FVector MuzzleLocation = CameraLocation + FTransform(CameraRotation).TransformVector(MuzzleOffset);
            FRotator MuzzleRotation = CameraRotation;
            // 조준을 약간 윗쪽으로 올려줍니다.
            MuzzleRotation.Pitch += 10.0f;
            UWorld* World = GetWorld();
            if (World)
            {
                FActorSpawnParameters SpawnParams;
                SpawnParams.Owner = this;
                SpawnParams.Instigator = Instigator;
                // 총구 위치에 발사체를 스폰시킵니다.
                AFPSProjectile* Projectile = World->SpawnActor<AFPSProjectile>(ProjectileClass, MuzzleLocation, MuzzleRotation, SpawnParams);
                if (Projectile)
                {
                    // 발사 방향을 알아냅니다.
                    FVector LaunchDirection = MuzzleRotation.Vector();
                    Projectile->FireInDirection(LaunchDirection);
                }
            }
        }
    }
  4. FPSCharacter.cpp 는 이제 다음과 같을 것입니다:

    // 프로젝트 세팅의 설명 페이지에 저작권 문구를 채우세요.
    
    #include "FPSProject.h"
    #include "FPSCharacter.h"
    #include "FPSProjectile.h"
    
    // 기본값을 설정합니다.
    AFPSCharacter::AFPSCharacter()
    {
        // 이 캐릭터가 TIck() 을 매 프레임 호출하도록 설정합니다. 필요치 않은 경우 끄면 퍼포먼스가 향상됩니다.
        PrimaryActorTick.bCanEverTick = true;
    
        // 일인칭 카메라 컴포넌트를 생성합니다.
        FPSCameraComponent = CreateDefaultSubobject<UCameraComponent>(TEXT("FirstPersonCamera"));
        // 카메라 컴포넌트를 캡슐 컴포넌트에 붙입니다.
        FPSCameraComponent->SetupAttachment(GetCapsuleComponent());
        // 카메라 위치를 눈 살짝 위로 잡습니다.
        FPSCameraComponent->SetRelativeLocation(FVector(0.0f, 0.0f, 50.0f + BaseEyeHeight));
        // 폰의 로테이션 제어를 허가합니다.
        FPSCameraComponent->bUsePawnControlRotation = true;
    
        // 일인칭 메시 컴포넌트를 생성합니다.
        FPSMesh = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("FirstPersonMesh"));
        // 이 메시는 소유 플레이어게만 보입니다.
        FPSMesh->SetOnlyOwnerSee(true);
        // FPS 카메라에 FPS 메시를 붙입니다.
        FPSMesh->SetupAttachment(FPSCameraComponent);
        // 일부 환경 섀도잉을 꺼서 메시가 하나처럼 보이는 느낌을 보존합니다.
        FPSMesh->bCastDynamicShadow = false;
        FPSMesh->CastShadow = false;
    
        // 소유 플레이어는 일반 (삼인칭) 바디 메시를 보지 못합니다.
        GetMesh()->SetOwnerNoSee(true);
    }
    
    // 게임 시작시 또는 스폰시 호출됩니다.
    void AFPSCharacter::BeginPlay()
    {
        Super::BeginPlay();
    
        if (GEngine)
        {
            // 5 초간 디버그 메시지를 표시합니다. (첫 인수인) -1 Key 값은 이 메시지를 업데이트 또는 새로고칠 필요가 없음을 나타냅니다.
            GEngine->AddOnScreenDebugMessage(-1, 5.0f, FColor::Red, TEXT("We are using FPSCharacter."));
        }
    }
    
    // 매 프레임 호출됩니다.
    void AFPSCharacter::Tick( float DeltaTime )
    {
        Super::Tick( DeltaTime );
    
    }
    
    // 입력에 함수성을 바인딩하기 위해 호출됩니다.
    void AFPSCharacter::SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent)
    {
        Super::SetupPlayerInputComponent(PlayerInputComponent);
    
        // "movement" 바인딩을 구성합니다.
        PlayerInputComponent->BindAxis("MoveForward", this, &AFPSCharacter::MoveForward);
        PlayerInputComponent->BindAxis("MoveRight", this, &AFPSCharacter::MoveRight);
    
        // "look" 바인딩을 구성합니다.
        PlayerInputComponent->BindAxis("Turn", this, &AFPSCharacter::AddControllerYawInput);
        PlayerInputComponent->BindAxis("LookUp", this, &AFPSCharacter::AddControllerPitchInput);
    
        // "action" 바인딩을 구성합니다.
        PlayerInputComponent->BindAction("Jump", IE_Pressed, this, &AFPSCharacter::StartJump);
        PlayerInputComponent->BindAction("Jump", IE_Released, this, &AFPSCharacter::StopJump);
        PlayerInputComponent->BindAction("Fire", IE_Pressed, this, &AFPSCharacter::Fire);
    }
    
    void AFPSCharacter::MoveForward(float Value)
    {
        // 어느 쪽이 전방인지 알아내어 플레이어가 그 방향으로 이동하고자 한다고 기록합니다.
        FVector Direction = FRotationMatrix(Controller->GetControlRotation()).GetScaledAxis(EAxis::X);
        AddMovementInput(Direction, Value);
    }
    
    void AFPSCharacter::MoveRight(float Value)
    {
        // 어느 쪽이 오른쪽인지 알아내어 플레이어가 그 방향으로 이동하고자 한다고 기록합니다.
        FVector Direction = FRotationMatrix(Controller->GetControlRotation()).GetScaledAxis(EAxis::Y);
        AddMovementInput(Direction, Value);
    }
    
    void AFPSCharacter::StartJump()
    {
        bPressedJump = true;
    }
    
    void AFPSCharacter::StopJump()
    {
        bPressedJump = false;
    }
    
    void AFPSCharacter::Fire()
    {
        // 프로젝타일 발사를 시도합니다.
        if (ProjectileClass)
        {
            // 카메라 트랜스폼을 구합니다.
            FVector CameraLocation;
            FRotator CameraRotation;
            GetActorEyesViewPoint(CameraLocation, CameraRotation);
    
            // MuzzleOffset 을 카메라 스페이스에서 월드 스페이스로 변환합니다.
            FVector MuzzleLocation = CameraLocation + FTransform(CameraRotation).TransformVector(MuzzleOffset);
            FRotator MuzzleRotation = CameraRotation;
            // 조준선을 약간 윗쪽으로 조준합니다.
            MuzzleRotation.Pitch += 10.0f;
            UWorld* World = GetWorld();
            if (World)
            {
                FActorSpawnParameters SpawnParams;
                SpawnParams.Owner = this;
                SpawnParams.Instigator = Instigator;
                // 총구 위치에 발사체를 스폰시킵니다.
                AFPSProjectile* Projectile = World->SpawnActor<AFPSProjectile>(ProjectileClass, MuzzleLocation, MuzzleRotation, SpawnParams);
                if (Projectile)
                {
                    // 발사 방향을 알아냅니다.
                    FVector LaunchDirection = MuzzleRotation.Vector();
                    Projectile->FireInDirection(LaunchDirection);
                }
            }
        }
    }
  5. Visual Studio 에서 FPSCharacter.cpp 를 저장합니다.

  6. Solution Explorer 에서 FPSProject 를 찾습니다.

  7. FPSProject 에 우클릭하고 Build 를 선택하여 프로젝트를 컴파일합니다.

    BuildFPSProject.png

프로젝타일 블루프린트 빌드하기

계속하기 전, 다음 링크에서 샘플 메시를 다운로드하고 압축을 풉니다: "프로젝타일 메시"

  1. 콘텐츠 브라우저의 파일 박스 안에서 우클릭하여 애셋 임포트 대화창을 엽니다.

  2. /Game... 에 임포트 를 클릭하여 임포트 대화창을 엽니다.

    RightClickImport.png

  3. Sphere.fbx 메시 파일을 찾아 선택합니다.

  4. 열기 를 클릭하여 프로젝트에 메시 임포트를 시작합니다.

  5. 콘텐츠 브라우저 에서 FBX 임포트 옵션 대화창이 뜹니다. 임포트 를 클릭하면 프로젝트에 메시가 추가됩니다.

    다음 스무딩 그룹 관련 오류는 무시합니다:

    FBXWarning.png

    이 메시는 여전히 일인칭 메시 구성을 나타내며, 나중의 섹션에서 애니메이션 작업시 사용할 것입니다.

  6. 저장 버튼을 클릭하여 임포트된 스태틱 메시를 저장합니다.

  7. 콘텐츠 브라우저 에서 Blueprints 폴더로 돌아갑니다.

  8. 신규 추가 버튼을 클릭하고 블루프린트 클래스 를 선택합니다.

  9. 모든 클래스 드롭다운 메뉴를 펼친 다음 검색창에 FPSProjectile 이라 입력합니다.

    AddNewBPClass.png

  10. FPSProjectile 를 클릭한 다음 선택 을 누릅니다.

  11. 새 블루프린트 이름을 BP_FPSProjectile 라 합니다.

    NameBP_FPSProjectile.png

  12. BP_FPSCharacter 아이콘을 더블클릭하여 블루프린트 에디터 에서 엽니다.

  13. 컴포넌트 탭에서 CollisionComponent 에 클릭합니다.

  14. 컴포넌트 추가 드롭다운 목록에 클릭한 다음 스태틱 메시 를 선택합니다.

    AddStaticMeshComponent.png

  15. 새 컴포넌트 이름을 ProjectileMeshComponent 라 합니다.

    NameProjectileMeshComponent.png

  16. 디테일 탭의 Mesh 섹션으로 스크롤해 내려간 다음 '없음'이라 되어있는 드롭다운 메뉴를 클릭합니다.

  17. Sphere 스태틱 메시를 선택합니다.

    SelectSphereMesh.png

    참고로 멀티플레이어 게임을 만드는 경우, MovementComp 컴포넌트의 Initial Velocity in Local Space (로컬 스페이스의 초기 속도) 옵션 체크를 해제해 줘야 이 발사체가 서버에 제대로 리플리케이트됩니다.

  18. X, Y, Z 스케일 값을 0.09 로 설정합니다.

    Set_XYZ_ScaleValues.png

    자물쇠 아이콘을 클릭하면 세 축 모두 고정시켜 상대 비율이 유지됩니다.

  19. ProjectileMeshComponent콜리전 프리셋 값을 NoCollision 으로 설정합니다 (콜리전에 이 스태틱 메시가 아닌 SphereComponent 를 사용하기 때문입니다).

    SetCollisionPresets.png

  20. 블루프린트를 컴파일, 저장블루프린트 에디터 를 닫습니다.

  21. BP_FPSCharacter 에 더블클릭하여 캐릭터 블루프린트를 편집용으로 엽니다.

  22. 클래스 디폴트 모드 를 엽니다.

    SelectProjectileClass.png

  23. Projectile Class 프로퍼티를 찾은 다음 BP_FPSProjectile 로 설정합니다+.

  24. MuzzleOffset 프로퍼티를 {100, 0, 00} 로 설정하여 발사체를 카메라 약간 앞에 스폰시킵니다.

    CharacterProjectileClass.png

  25. 블루프린트를 컴파일, 저장블루프린트 에디터 를 닫습니다.

게임내 발사체 발사

  1. 레벨 에디터 툴바플레이 버튼을 클릭하여 게임내에서 발사체를 발사해 봅니다.

  2. 좌클릭 하면 발사체가 월드로 발사됩니다.

    FiringProjectiles.png

  3. Esc 키를 누르거나 레벨 에디터의 중지 버튼을 클릭하여 에디터에서 플레이 (PIE) 모드를 빠져나갑니다.

Select Skin
Light
Dark

새로운 언리얼 엔진 4 문서 사이트에 오신 것을 환영합니다!

문서 사이트에 대한 의견을 모을 수 있는 피드백 시스템을 포함해서 여러가지 새로운 기능을 준비하고 있습니다. 아래 Documentation Feedback 포럼(영문) 또는 언리얼 엔진 네이버 공식 카페(한글) 중 편하신 곳에 의견이나 문제점을 알려 주세요.

새 시스템이 준비되면 알려 드리겠습니다.

네이버 카페
공식 포럼