All is well

[UE5/TPS/Proto04] Bullet 구현 본문

UE/TPS

[UE5/TPS/Proto04] Bullet 구현

D0YUN 2025. 2. 12. 12:24

01) Bullet - class 생성

  1. UE 실행 → Bullet 클래스 생성
  2. UE 종료 후 VS로 이동

02) Bullet - Collision Component 생성

  1. `Bullet.h` 에 Collision component 변수 선언 - `USphereComponent`
  2. `Bullet.cpp`의 생성자에서 컴포넌트 생성
    1. Collision component 등록하기
    2. Collision Profile(== Collision Preset) 설정
    3. Collision component 크기 설정
    4. Root로 등록
      1. 방법1 : `SetRootComponent()` 이용
      2. 방법2 : `RootComponent = ~~~` 이용
// Bullet.h

(...)

UCLASS()
class TPSPROJECT_API ABullet : public AActor
{
	GENERATED_BODY()
	
public:	
	ABullet();

protected:
	virtual void BeginPlay() override;

public:	
	virtual void Tick(float DeltaTime) override;

	/***** 이동 - 250205 *****/
public:
	// 충돌 컴포넌트
	UPROPERTY( VisibleAnywhere , Category = "Collision" )
	class USphereComponent* CollisionComp;
};

 

// Bullet.cpp

ABullet::ABullet()
{
	PrimaryActorTick.bCanEverTick = true;

	/***** Collision 컴포넌트 생성 - 250205 *****/
	// 1. Collision component 등록하기
	CollisionComp = CreateDefaultSubobject<USphereComponent>( L"CollisionComp" );
	// 2. Collision Profile(== Collision Preset) 설정
	CollisionComp->SetCollisionProfileName( L"BlockAll" );
	// 3. Collision component 크기 설정
	CollisionComp->SetSphereRadius(20.f);
	// 4. Root로 등록
	// SetRootComponent( CollisionComp );		// 방법1
	RootComponent = CollisionComp;				// 방법2
	
	(...)
}

03) Bullet - 외관 Component 생성

  1. `Bullet.h`에 외관 component 관련 변수 선언 - `UStaticMeshComponent`
  2. `Bullet.cpp`의 생성자에서 컴포넌트 생성
    1. Static Mesh component 등록
    2. 부모 컴포넌트 지정
    3. 충돌 비활성화
      • 충돌 비활성화를 하는 이유 : 이미 root node에서 충돌 처리를 하고 있다. 따라서 Mesh component도 충돌 처리를 하게 되면 충돌 처리를 두 번 하게 되기 때문에 Mesh Component의 충돌은 비활성화 한다.
    4. Static Mesh 크기 설정
// Bullet.h

(...)

UCLASS()
class TPSPROJECT_API ABullet : public AActor
{
	GENERATED_BODY()
	
public:	
	ABullet();

protected:
	virtual void BeginPlay() override;

public:	
	virtual void Tick(float DeltaTime) override;

	/***** 이동 - 250205 *****/
public:
	// 충돌 컴포넌트
	UPROPERTY( VisibleAnywhere , Category = "Collision" )
	class USphereComponent* CollisionComp;
	
	// 외관 컴포넌트
	UPROPERTY( VisibleAnywhere , Category = "BodyMesh" )
	class UStaticMeshComponent* MeshComp;
};
// Bullet.cpp

ABullet::ABullet()
{
	PrimaryActorTick.bCanEverTick = true;
	(...)
	
	/***** 외관 Component 생성 - 250205 *****/
	// 1. Static Mesh component 등록
	MeshComp = CreateDefaultSubobject<UStaticMeshComponent>( L"MeshComp" );
	// 2. 부모 컴포넌트 지정
	MeshComp->SetupAttachment( RootComponent );
	// 3. 충돌 비활성화
	MeshComp->SetCollisionEnabled( ECollisionEnabled::NoCollision );
	// 4. Static Mesh 크기 설정
	MeshComp->SetRelativeScale3D( FVector(0.5f) );
	
	(...)
}

04) Bullet - 발사체 Component 생성

  • Projectile의 갱신을 위해 사용
  1. `Bullet.h`에 Movement component 관련 변수 선언 - UProjectileMovementComponent
  2. `Bullet.cpp`의 생성자에서 컴포넌트 생성
    1. Projectile Movement component component 등록
    2. Projectile Movement component가 갱신시킬 component 지정
    3. 발사체의 초기 속도 세팅
    4. 발사체의 최대 속도 세팅
    5. 발사체의 반동 여부 지정
    6. 발사체의 반동값 지정
      • 0에 가까울수록 반동이 작고, 1에 가까울수록 반동이 크다
// Bullet.h

(...)

UCLASS()
class TPSPROJECT_API ABullet : public AActor
{
	GENERATED_BODY()
	
public:	
	ABullet();

protected:
	virtual void BeginPlay() override;

public:	
	virtual void Tick(float DeltaTime) override;

	/***** 이동 - 250205 *****/
public:
	// 충돌 컴포넌트
	UPROPERTY( VisibleAnywhere , Category = "Collision" )
	class USphereComponent* CollisionComp;
	
	// 외관 컴포넌트
	UPROPERTY( VisibleAnywhere , Category = "BodyMesh" )
	class UStaticMeshComponent* MeshComp;
	
	// 발사체(Projectile)의 이동을 담당할 컴포넌트
	UPROPERTY( VisibleAnywhere , Category = "Movement" )
	class UProjectileMovementComponent* MovementComp;	
};
// Bullet.cpp

ABullet::ABullet()
{
	(...)
	
	/***** 발사체(Projectile) Component 생성 - 250205 *****/
	// 1. Projectile Movement component component 등록
	MovementComp = CreateDefaultSubobject<UProjectileMovementComponent>( L"MovementComp" );
	// 2. Projectile Movement component가 갱신시킬 component 지정
	MovementComp->SetUpdatedComponent( CollisionComp );
	// 3. 발사체의 초기 속도 세팅
	MovementComp->InitialSpeed = 5000.f;
	// 4. 발사체의 최대 속도 세팅
	MovementComp->MaxSpeed = 5000.f;
	// 5. 발사체의 반동 여부 지정
	MovementComp->bShouldBounce = true;
	// 6. 발사체의 반동값 지정
	MovementComp->Bounciness = 0.3f;
	
	(...)
}

 

https://alizwldyl.tistory.com/26

 

[UE5] UProjectileMovementComponent 란?

UProjectileMovementComponent는 tick 동안 발사체(Projectile)의 위치를 업데이트하는 component로, 주로 총알, 로켓, 화살 등의 발사체(Projectile)를 구현할 때 사용됩니다. 이 component는 기본적으로 중력, 반사,

alizwldyl.tistory.com

 


05) Bullt - 생성한 Bullet 테스트

  1. UE로 이동 → BP_Bullet 생성
  2. Details에서 static mesh 추가
  3. Coliision Comp의 Sphere radius, Mesh Comp의 Location. Scale 조정
  4. Map에 올려두고 잘 날아가는지 확인

Details에서 static mesh 추가

 


06) Bullet - Enhanced Input 방식을 이용한 Fire Input 관련 세팅

  1. Unreal Editor 실행
  2. IA 추가
  1. RMB 클릭 → Input Action 추가 → IA_Fire 으로 이름 변경
  2. Value Type을 Digital로 설정 후 저장
  3. IMC_TPS에 IA_Fire 추가
Value type : input이 들어왔을때 어떤 데이터 타입으로 결과를 받을 것인지 선택하는 것

IMC_TPS에 IA_Fire 추가


07) Bullet - Bullet 제거

<방법1 : InitialLifeSpan 변수 이용 >

  1. `Bullet.cpp`의 생성자에서 생명 시간 주기 2초로 지정
// Bullet.cpp

ABullet::ABullet()
{
	PrimaryActorTick.bCanEverTick = true;
	
	(...)
	
	/***** Bullet 제거 - 250205 *****/
	/* 방법1: 생명 시간 주기 변수 이용 */
	InitialLifeSpan = 2.f;
}

 

<방법2 : timer 이용 >

  1. `Bullet.h`에 총알 제거 함수 선언 - `Die()`
  2. `Bullet.cpp`에 함수 구현
  3. `BeginPlay()` 에서 사망 타이머 설정 : 타이머 끝나면 `Die()` 함수 실행되도록
// Bullet.h

UCLASS()
class TPSPROJECT_API ABullet : public AActor
{
	GENERATED_BODY()
	
public:	
	ABullet();

protected:a
	virtual void BeginPlay() override;

public:	
	virtual void Tick(float DeltaTime) override;
	
	(...)

	/***** Bullet 제거 - 250205 *****/
public:
	void Die();
};
// Bullet.cpp

void ABullet::BeginPlay()
{
	Super::BeginPlay();

	/***** Bullet 제거 - 250205 *****/
	// 사망 타이머 설정
	FTimerHandle deathTimer;

	/* 방법2 : Timer */
	GetWorld()->GetTimerManager().SetTimer(deathTimer, this, &ABullet::Die, 2.f, false);		
}

(...)

void ABullet::Die()
{
	Destroy();
}

 

<방법3 : 람다식>

  1. `BeginPlay()` 에서 사망 타이머 설정 : 타이머 끝나면 `lambdaFunction`이 실행되도록
// Bullet.cpp

void ABullet::BeginPlay()
{
	Super::BeginPlay();

	/***** Bullet 제거 - 250205 *****/
	// 사망 타이머 설정
	FTimerHandle deathTimer;

	/* 방법3-1: 람다식 */
	//GetWorld()->GetTimerManager().SetTimer(deathTimer, 
	//FTimerDelegate::CreateLambda( [this]()->void
	//							  {
	//								Destroy();
	//							  } )
	//							  ,2.f , false );

	/* 방법3-2: 람다식 */
	auto lambdaFunction = FTimerDelegate::CreateLambda([this]()->void
		{
			Destroy();
		}) ;

	GetWorld()->GetTimerManager().SetTimer( deathTimer , lambdaFunction, 2.f , false );
}

 

람다 설명

  • `[this]` : 캡쳐
    • cf) 캡쳐 : 람다 외부에서 선언된 변수나 상수를 함수 몸체 안에서 사용하기 위한 것
  • `()` : 매개변수
  • `→void` : 반환 자료형
  • `{ ~~~ }` : 구현부