캐릭터 구성을 마쳤으니, 이제 발사체 무기를 구현하여 발사하면 단순한 수류탄같은 발사체가 화면 중앙에서 발사되어 월드에 충돌할 때까지 날아가도록 만들겠습니다. 이번 단계에서는 프로젝타일에 쓸 입력을 추가하고 새 코드 클래스를 만들도록 하겠습니다.
발사 액션 매핑 추가
-
편집 메뉴에서, 프로젝트 세팅 에 클릭합니다.
-
프로젝트 세팅 탭 왼편의 엔진 제목줄 아래 입력 을 클릭합니다.
-
바인딩 아래, 액션 매핑 옆의 더하기 부호를 클릭합니다.
-
액션 매핑 왼쪽의 화살표를 클릭합니다.
-
뜨는 글상자에 Fire 라 입력하고, 글상자 왼쪽의 화살표를 클릭하여 액션 바인딩 옵션을 펼칩니다.
-
드롭다운 메뉴의 마우스 드롭다운 목록에서 왼쪽 마우스 버튼 을 선택합니다.
-
입력 세팅이 이제 다음과 같을 것입니다:
-
프로젝트 세팅 메뉴를 닫습니다.
프로젝타일 클래스 추가
-
파일 메뉴에서 새 C++ 클래스... 를 선택하고 새 부모 클래스를 선택합니다.
-
부모 클래스 선택 메뉴가 열립니다. 스크롤해 내려가, Acotr 를 부모 클래스로 선택하고 다음 을 클릭합니다.
-
새 클래스 이름을 "FPSProjectile" 이라 하고 생성 을 클릭합니다.
USphere Component 추가
-
Solution Explorer 에서
FPSProjectile.h를 열고FPSProjectile클래스 헤더를 찾습니다. -
FPSProjectile인터페이스에USphereComponent로의 레퍼런스를 추가합니다.
// 구체 콜리전 컴포넌트
UPROPERTY(VisibleDefaultsOnly, Category = Projectile)
USphereComponent* CollisionComponent;
FPSProjectile.h는 이제 다음과 같을 것입니다:
// 프로젝트 세팅의 설명 페이지에 저작권 문구를 채우세요.
#pragma once
#include "GameFramework/Actor.h"
#include "FPSProjectile.generated.h"
UCLASS()
class FPSPROJECT_API AFPSProjectile : public AActor
{
GENERATED_BODY()
public:
// 이 액터 프로퍼티의 기본값을 설정합니다.
AFPSProjectile();
protected:
// 게임 시작 또는 스폰시 호출됩니다.
virtual void BeginPlay() override;
public:
// 매 프레임 호출됩니다.
virtual void Tick( float DeltaSeconds ) override;
// 구체 콜리전 컴포넌트입니다.
UPROPERTY(VisibleDefaultsOnly, Category = Projectile)
USphereComponent* CollisionComponent;
};
-
Solution Explorer 에서
FPSProjectile클래스 CPP 파일을 찾아FPSProjectile.cpp를 엽니다. -
FPSProjectile.cpp의AFPSProjectile생성자에 다음 코드를 추가합니다:
// 구체를 단순 콜리전 표현으로 사용합니다.
CollisionComponent = CreateDefaultSubobject<USphereComponent>(TEXT("SphereComponent"));
// 구체의 콜리전 반경을 설정합니다.
CollisionComponent->InitSphereRadius(15.0f);
// 루트 컴포넌트를 콜리전 컴포넌트로 설정합니다.
RootComponent = CollisionComponent;
시뮬레이션으로 구동시켜줄 것이므로 CollisionComponent 를 RootComponent 로 만듭니다.
-
FPSProjectile.cpp는 이제 다음과 같을 것입니다:// 프로젝트 세팅의 설명 페이지에 저작권 문구를 채우세요. #include "FPSProject.h" #include "FPSProjectile.h" // Sets default values AFPSProjectile::AFPSProjectile() { // 이 액터가 매 프레임 Tick() 을 호출하도록 설정합니다. 필요치 않은 경우 끄면 퍼포먼스가 향상됩니다. PrimaryActorTick.bCanEverTick = true; // 구체를 단순 콜리전 표현으로 사용합니다. CollisionComponent = CreateDefaultSubobject<USphereComponent>(TEXT("SphereComponent")); // 구체의 콜리전 반경을 설정합니다. CollisionComponent->InitSphereRadius(15.0f); // 루트 컴포넌트를 콜리전 컴포넌트로 설정합니다. RootComponent = CollisionComponent; } // 게임 시작시 또는 스폰시 호출됩니다. void AFPSProjectile::BeginPlay() { Super::BeginPlay(); } // 매 프레임 호출됩니다. void AFPSProjectile::Tick( float DeltaTime ) { Super::Tick( DeltaTime ); }
프로젝타일 무브먼트 컴포넌트 추가
-
Solution Explorer 에서
FPSProjectile클래스 헤더 파일을 찾아FPSProjectile.h를 엽니다. -
FPSProjectile.h에 다음 코드를 추가합니다:
// 프로젝타일 무브먼트 컴포넌트
UPROPERTY(VisibleAnywhere, Category = Movement)
UProjectileMovementComponent* ProjectileMovementComponent;
FPSProjectile.h는 이제 다음과 같을 것입니다:
// 프로젝트 세팅의 설명 페이지에 저작권 문구를 채우세요.
#pragma once
#include "GameFramework/Actor.h"
#include "FPSProjectile.generated.h"
UCLASS()
class FPSPROJECT_API AFPSProjectile : public AActor
{
GENERATED_BODY()
public:
// 이 액터 프로퍼티의 기본값을 설정합니다.
AFPSProjectile();
protected:
// 게임 시작 또는 스폰시 호출됩니다.
virtual void BeginPlay() override;
public:
// 매 프레임 호출됩니다.
virtual void Tick( float DeltaSeconds ) override;
// 구체 콜리전 컴포넌트입니다.
UPROPERTY(VisibleDefaultsOnly, Category = Projectile)
USphereComponent* CollisionComponent;
// 프로젝타일 무브먼트 컴포넌트
UPROPERTY(VisibleAnywhere, Category = Movement)
UProjectileMovementComponent* ProjectileMovementComponent;
};
-
Solution Explorer 에서
FPSProjectileCPP 파일을 찾아FPSProjectile.cpp파일을 엽니다. -
FPSProjectile.cpp의FPSProjectile생성자에 다음 코드 줄을 추가합니다:
// ProjectileMovementComponent 를 사용하여 이 발사체의 운동을 관장합니다.
ProjectileMovementComponent = CreateDefaultSubobject<UProjectileMovementComponent>(TEXT("ProjectileMovementComponent"));
ProjectileMovementComponent->SetUpdatedComponent(CollisionComponent);
ProjectileMovementComponent->InitialSpeed = 3000.0f;
ProjectileMovementComponent->MaxSpeed = 3000.0f;
ProjectileMovementComponent->bRotationFollowsVelocity = true;
ProjectileMovementComponent->bShouldBounce = true;
ProjectileMovementComponent->Bounciness = 0.3f;
FPSProjectile.cpp는 이제 다음과 같을 것입니다:
// 프로젝트 세팅의 설명 페이지에 저작권 문구를 채우세요.
#include "FPSProject.h"
#include "FPSProjectile.h"
// Sets default values
AFPSProjectile::AFPSProjectile()
{
// 이 액터가 매 프레임 Tick() 을 호출하도록 설정합니다. 필요치 않은 경우 끄면 퍼포먼스가 향상됩니다.
PrimaryActorTick.bCanEverTick = true;
// 구체를 단순 콜리전 표현으로 사용합니다.
CollisionComponent = CreateDefaultSubobject<USphereComponent>(TEXT("SphereComponent"));
// 구체의 콜리전 반경을 설정합니다.
CollisionComponent->InitSphereRadius(15.0f);
// 루트 컴포넌트를 콜리전 컴포넌트로 설정합니다.
RootComponent = CollisionComponent;
// 이 컴포넌트를 사용하여 이 프로젝타일의 무브먼트를 구동시킵니다.
ProjectileMovementComponent = CreateDefaultSubobject<UProjectileMovementComponent>(TEXT("ProjectileMovementComponent"));
ProjectileMovementComponent->SetUpdatedComponent(CollisionComponent);
ProjectileMovementComponent->InitialSpeed = 3000.0f;
ProjectileMovementComponent->MaxSpeed = 3000.0f;
ProjectileMovementComponent->bRotationFollowsVelocity = true;
ProjectileMovementComponent->bShouldBounce = true;
ProjectileMovementComponent->Bounciness = 0.3f;
}
// 게임 시작시 또는 스폰시 호출됩니다.
void AFPSProjectile::BeginPlay()
{
Super::BeginPlay();
}
// 매 프레임 호출됩니다.
void AFPSProjectile::Tick( float DeltaTime )
{
Super::Tick( DeltaTime );
}
발사체 초기 속도 설정
-
Solution Explorer 에서
FPSProjectile클래스 헤더 파일을 찾아FPSProjectile.h를 엽니다. -
FPSProjectile.h에 다음 함수 선언을 추가합니다:
// 발사체의 속도를 발사 방향으로 초기화시킵니다.
void FireInDirection(const FVector& ShootDirection);
이 함수가 발사체의 발사를 담당합니다.
FPSProjectile.h는 이제 다음과 같은 모습일 것입니다:
// 프로젝트 세팅의 설명 페이지에 저작권 문구를 채우세요.
#pragma once
#include "GameFramework/Actor.h"
#include "FPSProjectile.generated.h"
UCLASS()
class FPSPROJECT_API AFPSProjectile : public AActor
{
GENERATED_BODY()
public:
// 이 액터 프로퍼티의 기본값을 설정합니다.
AFPSProjectile();
protected:
// 게임 시작 또는 스폰시 호출됩니다.
virtual void BeginPlay() override;
public:
// 매 프레임 호출됩니다.
virtual void Tick( float DeltaSeconds ) override;
// 구체 콜리전 컴포넌트입니다.
UPROPERTY(VisibleDefaultsOnly, Category = Projectile)
USphereComponent* CollisionComponent;
// 프로젝타일 무브먼트 컴포넌트입니다.
UPROPERTY(VisibleAnywhere, Category = Movement)
UProjectileMovementComponent* ProjectileMovementComponent;
// 프로젝타일의 속도를 발사 방향으로 초기화시키는 함수입니다.
void FireInDirection(const FVector& ShootDirection);
};
-
Solution Explorer 에서
FPSProjectileCPP 파일을 찾아FPSProjectile.cpp를 엽니다. -
FPSProjectile.cpp에 다음 함수 정의부를 추가합니다:
// 프로젝타일의 속도를 발사 방향으로 초기화시키는 함수입니다.
void AFPSProjectile::FireInDirection(const FVector& ShootDirection)
{
ProjectileMovementComponent->Velocity = ShootDirection * ProjectileMovementComponent->InitialSpeed;
}
참고로 발사체의 속력은 ProjectileMovementComponent 에 의해 정의되므로 발사 방향만 제공해 주면 됩니다.
FPSProjectile.cpp는 이제 다음과 같을 것입니다:
// 프로젝트 세팅의 설명 페이지에 저작권 문구를 채우세요.
#include "FPSProject.h"
#include "FPSProjectile.h"
// Sets default values
AFPSProjectile::AFPSProjectile()
{
// 이 액터가 매 프레임 Tick() 을 호출하도록 설정합니다. 필요치 않은 경우 끄면 퍼포먼스가 향상됩니다.
PrimaryActorTick.bCanEverTick = true;
// 구체를 단순 콜리전 표현으로 사용합니다.
CollisionComponent = CreateDefaultSubobject<USphereComponent>(TEXT("SphereComponent"));
// 구체의 콜리전 반경을 설정합니다.
CollisionComponent->InitSphereRadius(15.0f);
// 루트 컴포넌트를 콜리전 컴포넌트로 설정합니다.
RootComponent = CollisionComponent;
// 이 컴포넌트를 사용하여 프로젝타일의 무브먼트를 구동시킵니다.
ProjectileMovementComponent = CreateDefaultSubobject<UProjectileMovementComponent>(TEXT("ProjectileMovementComponent"));
ProjectileMovementComponent->SetUpdatedComponent(CollisionComponent);
ProjectileMovementComponent->InitialSpeed = 3000.0f;
ProjectileMovementComponent->MaxSpeed = 3000.0f;
ProjectileMovementComponent->bRotationFollowsVelocity = true;
ProjectileMovementComponent->bShouldBounce = true;
ProjectileMovementComponent->Bounciness = 0.3f;
}
// 게임 시작시 또는 스폰시 호출됩니다.
void AFPSProjectile::BeginPlay()
{
Super::BeginPlay();
}
// 매 프레임 호출됩니다.
void AFPSProjectile::Tick( float DeltaTime )
{
Super::Tick( DeltaTime );
}
// 프로젝타일의 속도를 발사 방향으로 초기화시키는 함수입니다.
void AFPSProjectile::FireInDirection(const FVector& ShootDirection)
{
ProjectileMovementComponent->Velocity = ShootDirection * ProjectileMovementComponent->InitialSpeed;
}
발사 입력 액션 바인딩
-
Solution Explorer 에서
FPSCharacter클래스 헤더 파일을 찾아FPSCharacter.h를 엽니다. -
FPSCharacter.h에 다음 함수 선언을 추가합니다:
// 발사 처리
UFUNCTION()
void Fire();
FPSCharacter.h는 이 제 다음과 비슷할 것입니다:
// 프로젝트 세팅의 설명 페이지에 저작권 문구를 채우세요.
#pragma once
#include "GameFramework/Character.h"
#include "FPSCharacter.generated.h"
UCLASS()
class FPSPROJECT_API AFPSCharacter : public ACharacter
{
GENERATED_BODY()
public:
// 이 캐릭터 프로퍼티에 대한 기본값을 설정합니다.
AFPSCharacter();
protected:
// 게임 시작 또는 스폰시 호출됩니다.
virtual void BeginPlay() override;
public:
// 매 프레임 호출됩니다.
virtual void Tick( float DeltaSeconds ) override;
// 입력에 함수성을 바인딩하기 위해 호출됩니다.
virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override;
// 전후 이동을 처리합니다.
UFUNCTION()
void MoveForward(float Value);
// 좌우 이동을 처리합니다.
UFUNCTION()
void MoveRight(float Value);
// 키를 누르면 점프 플래그를 설정합니다.
UFUNCTION()
void StartJump();
// 키를 떼면 점프 플래그를 지웁니다.
UFUNCTION()
void StopJump();
// 프로젝타일 발사를 처리하는 함수입니다.
UFUNCTION()
void Fire();
// FPS 카메라입니다.
UPROPERTY(VisibleAnywhere)
UCameraComponent* FPSCameraComponent;
// 폰 메시: 일인칭 시점 (자신에게만 보이는 팔)
UPROPERTY(VisibleDefaultsOnly, Category = Mesh)
USkeletalMeshComponent* FPSMesh;
};
-
Solution Explorer 에서
FPSCharacterCPP 파일을 찾고FPSCharacter.cpp를 엽니다. -
FPSCharacter.cpp에서,OnFire함수 바인딩을 위해SetupPlayerInputComponent에 다음 코드를 추가합니다:
PlayerInputComponent->BindAction("Fire", IE_Pressed, this, &AFPSCharacter::Fire);
- 이제,
FPSCharacter.cpp에 다음 함수 정의부를 추가합니다:
void AFPSCharacter::Fire()
{
}
FPSCharacter.cpp는 이제 다음과 같아 보일 것입니다:
// 프로젝트 세팅의 설명 페이지에 저작권 문구를 채우세요.
#include "FPSProject.h"
#include "FPSCharacter.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);
// 게임플레이 키 바인딩을 구성합니다.
PlayerInputComponent->BindAxis("MoveForward", this, &AFPSCharacter::MoveForward);
PlayerInputComponent->BindAxis("MoveRight", this, &AFPSCharacter::MoveRight);
// 게임플레이 마우스 바인딩을 구성합니다.
PlayerInputComponent->BindAxis("Turn", this, &AFPSCharacter::AddControllerYawInput);
PlayerInputComponent->BindAxis("LookUp", this, &AFPSCharacter::AddControllerPitchInput);
// 점프 동작 바인딩을 구성합니다.
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()
{
}
발사체의 스폰 위치 정의
FPSProjectile액터 스폰시OnFire함수 구현에 있어 두 가지 고려할 점이 있습니다. 이를테면:
- 발사체 스폰 위치
- 프로젝타일 클래스 (
FPSCharacter와 그 파생 블루프린트가 스폰할 발사체를 알도록 하기 위함입니다).
카메라 스페이스 오프셋 벡터를 사용하여 프로젝타일의 스폰 위치를 결정하게 됩니다. 이 파라미터를 편집가능하게 만들어야 BP_FPSCharacter 블루프린트에서 설정 및 조정할 수 있습니다. 궁극적으로 이 데이터를 토대로 발사체에 대한 초기 위치를 계산할 수 있을 것입니다.
-
Solution Explorer 에서
FPSCharacter클래스 헤더 파일을 찾고FPSCharacter.h를 엽니다. -
FPSCharacter.h에 다음 코드를 추가합니다:
// 카메라 위치에서의 총구 오프셋
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Gameplay)
FVector MuzzleOffset;
EditAnywhere 지정자를 통해 총구 오프셋 값을 블루프린트 에디터의 디폴트 모드나 캐릭터의 아무 인스턴스에 대한 디테일 탭에서 변경할 수 있습니다. BlueprintReadWrite 지정자를 통해서는 블루프린트 안에서 총구 오프셋의 값을 구하고 설정할 수 있습니다.
FPSCharacter.h에 다음 코드를 추가합니다:
// 스폰시킬 프로젝타일 클래스
UPROPERTY(EditDefaultsOnly, Category = Projectile)
TSubclassOf<class AFPSProjectile> ProjectileClass;
EditDefaultsOnly 지정자는 프로젝타일 클래스를 블루프린트의 각 인스턴스 상에서가 아니라 블루프린트의 디폴트로만 설정할 수 있다는 뜻입니다.
FPSCharacter.h의 모습은 다음과 같을 것입니다:
// 프로젝트 세팅의 설명 페이지에 저작권 문구를 채우세요.
#pragma once
#include "GameFramework/Character.h"
#include "FPSCharacter.generated.h"
UCLASS()
class FPSPROJECT_API AFPSCharacter : public ACharacter
{
GENERATED_BODY()
public:
// 이 캐릭터 프로퍼티에 대한 기본값을 설정합니다.
AFPSCharacter();
protected:
// 게임 시작 또는 스폰시 호출됩니다.
virtual void BeginPlay() override;
public:
// 매 프레임 호출됩니다.
virtual void Tick( float DeltaSeconds ) override;
// 입력에 함수성을 바인딩하기 위해 호출됩니다.
virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override;
// 전후 이동을 처리합니다.
UFUNCTION()
void MoveForward(float Value);
// 좌우 이동을 처리합니다.
UFUNCTION()
void MoveRight(float Value);
// 키를 누르면 점프 플래그를 설정합니다.
UFUNCTION()
void StartJump();
// 키를 떼면 점프 플래그를 지웁니다.
UFUNCTION()
void StopJump();
// 프로젝타일 발사를 처리하는 함수입니다.
UFUNCTION()
void Fire();
// FPS 카메라입니다.
UPROPERTY(VisibleAnywhere)
UCameraComponent* FPSCameraComponent;
// 폰 메시: 일인칭 시점 (자신에게만 보이는 팔)
UPROPERTY(VisibleDefaultsOnly, Category = Mesh)
USkeletalMeshComponent* FPSMesh;
// 카메라 위치에서의 총구 오프셋
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Gameplay)
FVector MuzzleOffset;
// 스폰시킬 프로젝타일 클래스
UPROPERTY(EditDefaultsOnly, Category = Projectile)
TSubclassOf<class AFPSProjectile> ProjectileClass;
};
코드 컴파일 및 검사
이제 새로 구현된 발사체 코드를 컴파일하고 검사할 차례입니다.
-
Visual Studio 에서 모든 헤더 및 구현 파일을 저장합니다.
-
Solution Explorer 에서 FPSProject 를 찾습니다.
-
FPSProject 에 우클릭한 다음 Build 를 선택하여 프로젝트를 컴파일합니다.
이 단계의 목적은 다음 단계로 넘어가기 전 빌드 오류를 잡아내기 위함입니다.