2024. 8. 3. 18:24ㆍUnreal Engine
UClass : 이 클래스에 메타데이터를 추가적으로 붙여서 새롭게 만들어진 것. 객체 지향에서 Reflection을 사용할 수 있게 해줌.
CDO : 초기값을 미리 설정해놓고 가지고 있다가 복사해서 사용함.
적 생성 위한 C++ 만들기
Actor로 "CEnemy" 이름으로 생성
바로 블루프린트로도 만들기
이전에 블루프린트로 만들었던 BP_Enemy의 속성들을 참고하여 C++로 만들어본다.
CEnemy.h 수정
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "CEnemy.generated.h"
UCLASS()
class SHOOTING_API ACEnemy : public AActor
{
GENERATED_BODY()
public:
// Sets default values for this actor's properties
ACEnemy();
protected:
// Called when the game starts or when spawned
virtual void BeginPlay() override;
public:
// Called every frame
virtual void Tick(float DeltaTime) override;
public:
UPROPERTY(VisibleAnywhere)
class UBoxComponent* BoxComp;
UPROPERTY(VisibleAnywhere)
class UStaticMeshComponent* BodyMesh;
};
CEnemy.cpp 수정
// Fill out your copyright notice in the Description page of Project Settings.
#include "CEnemy.h"
#include "Components/BoxComponent.h"
// Sets default values
ACEnemy::ACEnemy()
{
// Set this actor to call Tick() every frame. You can turn this off to improve performance if you don't need it.
PrimaryActorTick.bCanEverTick = true;
BoxComp = CreateDefaultSubobject<UBoxComponent>(TEXT("BoxComp"));
//BoxComp를 Root로 등록
RootComponent = BoxComp;
//BodyMesh 그릇에 StaticMeshComponent를 만들어서 담으려고 한다.
BodyMesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("BodyMesh"));
BodyMesh->SetupAttachment(BoxComp);
}
// Called when the game starts or when spawned
void ACEnemy::BeginPlay()
{
Super::BeginPlay();
}
// Called every frame
void ACEnemy::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
}
잘 설정되었다. 에디터를 껐다 켜는게 가장 좋은 방법인 것 같다.
회전값, 위치값, 모델링 설정
블루프린트에서 설정되어있는 설정 값들을 C++로 만든다.
CEnemy.cpp 코드 추가
//사용할 Static Mesh 데이터를 읽어서 컴포넌트에 할당하기
ConstructorHelpers::FObjectFinder<UStaticMesh> TempMesh(TEXT("/Script/Engine.StaticMesh'/Game/Drone/Drone_low.Drone_low'"));
//로딩 성공하면 BodyMesh에 사용할 Static Mesh로 TempMesh를 넣는다.
if (TempMesh.Succeeded())
{
BodyMesh->SetStaticMesh(TempMesh.Object);
BodyMesh->SetRelativeLocation(FVector(50.0f, 0, 0));
BodyMesh->SetRelativeRotation(FRotator(0, -90.0f, -90.0f));
}
전체 코드
// Fill out your copyright notice in the Description page of Project Settings.
#include "CEnemy.h"
#include "Components/BoxComponent.h"
// Sets default values
ACEnemy::ACEnemy()
{
// Set this actor to call Tick() every frame. You can turn this off to improve performance if you don't need it.
PrimaryActorTick.bCanEverTick = true;
BoxComp = CreateDefaultSubobject<UBoxComponent>(TEXT("BoxComp"));
//BoxComp를 Root로 등록
RootComponent = BoxComp;
//BodyMesh 그릇에 StaticMeshComponent를 만들어서 담으려고 한다.
BodyMesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("BodyMesh"));
BodyMesh->SetupAttachment(BoxComp);
//사용할 Static Mesh 데이터를 읽어서 컴포넌트에 할당하기
ConstructorHelpers::FObjectFinder<UStaticMesh> TempMesh(TEXT("/Script/Engine.StaticMesh'/Game/Drone/Drone_low.Drone_low'"));
//로딩 성공하면 BodyMesh에 사용할 Static Mesh로 TempMesh를 넣는다.
if (TempMesh.Succeeded())
{
BodyMesh->SetStaticMesh(TempMesh.Object);
BodyMesh->SetRelativeLocation(FVector(50.0f, 0, 0));
BodyMesh->SetRelativeRotation(FRotator(0, -90.0f, -90.0f));
}
}
// Called when the game starts or when spawned
void ACEnemy::BeginPlay()
{
Super::BeginPlay();
}
// Called every frame
void ACEnemy::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
}
빌드 후 에디터를 껐다 켜면 잘 적용된 것을 볼 수 있다.
콜라이더 설정하기
콜라이더는 EnemyProfile, BodyMesh는 NoCollision 설정
CEnemy.cpp 코드 추가
//Collision Profile 설정하기
BoxComp->SetCollisionProfileName(TEXT("EnemyProfile"));
BodyMesh->SetCollisionEnabled(ECollisionEnabled::NoCollision);
전체 코드
// Fill out your copyright notice in the Description page of Project Settings.
#include "CEnemy.h"
#include "Components/BoxComponent.h"
// Sets default values
ACEnemy::ACEnemy()
{
// Set this actor to call Tick() every frame. You can turn this off to improve performance if you don't need it.
PrimaryActorTick.bCanEverTick = true;
BoxComp = CreateDefaultSubobject<UBoxComponent>(TEXT("BoxComp"));
//BoxComp를 Root로 등록
RootComponent = BoxComp;
//Collision Profile 설정하기
BoxComp->SetCollisionProfileName(TEXT("EnemyProfile"));
//BodyMesh 그릇에 StaticMeshComponent를 만들어서 담으려고 한다.
BodyMesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("BodyMesh"));
BodyMesh->SetupAttachment(BoxComp);
BodyMesh->SetCollisionEnabled(ECollisionEnabled::NoCollision);
//사용할 Static Mesh 데이터를 읽어서 컴포넌트에 할당하기
ConstructorHelpers::FObjectFinder<UStaticMesh> TempMesh(TEXT("/Script/Engine.StaticMesh'/Game/Drone/Drone_low.Drone_low'"));
//로딩 성공하면 BodyMesh에 사용할 Static Mesh로 TempMesh를 넣는다.
if (TempMesh.Succeeded())
{
BodyMesh->SetStaticMesh(TempMesh.Object);
BodyMesh->SetRelativeLocation(FVector(50.0f, 0, 0));
BodyMesh->SetRelativeRotation(FRotator(0, -90.0f, -90.0f));
}
}
// Called when the game starts or when spawned
void ACEnemy::BeginPlay()
{
Super::BeginPlay();
}
// Called every frame
void ACEnemy::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
}
잘 설정되었다.
적 이동
Target에 Actor를 담을 수 있도록 설정
CEnemy.h 코드 추가
UPROPERTY()
AActor* target;
전체 코드
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "CEnemy.generated.h"
UCLASS()
class SHOOTING_API ACEnemy : public AActor
{
GENERATED_BODY()
public:
// Sets default values for this actor's properties
ACEnemy();
protected:
// Called when the game starts or when spawned
virtual void BeginPlay() override;
public:
// Called every frame
virtual void Tick(float DeltaTime) override;
public:
UPROPERTY(VisibleAnywhere)
class UBoxComponent* BoxComp;
UPROPERTY(VisibleAnywhere)
class UStaticMeshComponent* BodyMesh;
public:
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "MySettings")
float speed = 500;
UPROPERTY()
AActor* target;
};
CEnemy.cpp 코드 추가
#include <Kismet/GameplayStatics.h>
#include "CPlayer.h"
//타겟 찾기
target = UGameplayStatics::GetActorOfClass(GetWorld(), ACPlayer::StaticClass());
UGameplayStatics는 유틸리티 클래스로써 사용하기 편하다.
전체 코드
// Fill out your copyright notice in the Description page of Project Settings.
#include "CEnemy.h"
#include "Components/BoxComponent.h"
#include <Kismet/GameplayStatics.h>
#include "CPlayer.h"
// Sets default values
ACEnemy::ACEnemy()
{
// Set this actor to call Tick() every frame. You can turn this off to improve performance if you don't need it.
PrimaryActorTick.bCanEverTick = true;
BoxComp = CreateDefaultSubobject<UBoxComponent>(TEXT("BoxComp"));
//BoxComp를 Root로 등록
RootComponent = BoxComp;
//Collision Profile 설정하기
BoxComp->SetCollisionProfileName(TEXT("EnemyProfile"));
//BodyMesh 그릇에 StaticMeshComponent를 만들어서 담으려고 한다.
BodyMesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("BodyMesh"));
BodyMesh->SetupAttachment(BoxComp);
BodyMesh->SetCollisionEnabled(ECollisionEnabled::NoCollision);
//사용할 Static Mesh 데이터를 읽어서 컴포넌트에 할당하기
ConstructorHelpers::FObjectFinder<UStaticMesh> TempMesh(TEXT("/Script/Engine.StaticMesh'/Game/Drone/Drone_low.Drone_low'"));
//로딩 성공하면 BodyMesh에 사용할 Static Mesh로 TempMesh를 넣는다.
if (TempMesh.Succeeded())
{
BodyMesh->SetStaticMesh(TempMesh.Object);
BodyMesh->SetRelativeLocation(FVector(50.0f, 0, 0));
BodyMesh->SetRelativeRotation(FRotator(0, -90.0f, -90.0f));
}
}
// Called when the game starts or when spawned
void ACEnemy::BeginPlay()
{
Super::BeginPlay();
//타겟 찾기
target = UGameplayStatics::GetActorOfClass(GetWorld(), ACPlayer::StaticClass());
}
// Called every frame
void ACEnemy::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
//이동
FVector dir(0, 0, 1);
FVector P0 = GetActorLocation(); //현재 위치 설정
FVector vt = dir * speed * DeltaTime;
FVector P = P0 + vt;
SetActorLocation(P);
}
적의 방향을 아래로 설정
CEnemy.h 코드 추가
- dir을 전역 변수로 설정
FVector dir;
전체 코드
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "CEnemy.generated.h"
UCLASS()
class SHOOTING_API ACEnemy : public AActor
{
GENERATED_BODY()
public:
// Sets default values for this actor's properties
ACEnemy();
protected:
// Called when the game starts or when spawned
virtual void BeginPlay() override;
public:
// Called every frame
virtual void Tick(float DeltaTime) override;
public:
UPROPERTY(VisibleAnywhere)
class UBoxComponent* BoxComp;
UPROPERTY(VisibleAnywhere)
class UStaticMeshComponent* BodyMesh;
public:
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "MySettings")
float speed = 500;
UPROPERTY()
AActor* target;
FVector dir;
};
CEnemy.cpp 코드 변경
- 전역 변수를 받아오도록 변경
void ACEnemy::BeginPlay()
{
Super::BeginPlay();
//타겟 찾기
target = UGameplayStatics::GetActorOfClass(GetWorld(), ACPlayer::StaticClass());
//아래로 방향 설정
dir = FVector(0, 0, -1);
}
// Called every frame
void ACEnemy::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
//이동
FVector P0 = GetActorLocation(); //현재 위치 설정
FVector vt = dir * speed * DeltaTime;
FVector P = P0 + vt;
SetActorLocation(P);
}
전체 코드
// Fill out your copyright notice in the Description page of Project Settings.
#include "CEnemy.h"
#include "Components/BoxComponent.h"
#include <Kismet/GameplayStatics.h>
#include "CPlayer.h"
// Sets default values
ACEnemy::ACEnemy()
{
// Set this actor to call Tick() every frame. You can turn this off to improve performance if you don't need it.
PrimaryActorTick.bCanEverTick = true;
BoxComp = CreateDefaultSubobject<UBoxComponent>(TEXT("BoxComp"));
//BoxComp를 Root로 등록
RootComponent = BoxComp;
//Collision Profile 설정하기
BoxComp->SetCollisionProfileName(TEXT("EnemyProfile"));
//BodyMesh 그릇에 StaticMeshComponent를 만들어서 담으려고 한다.
BodyMesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("BodyMesh"));
BodyMesh->SetupAttachment(BoxComp);
BodyMesh->SetCollisionEnabled(ECollisionEnabled::NoCollision);
//사용할 Static Mesh 데이터를 읽어서 컴포넌트에 할당하기
ConstructorHelpers::FObjectFinder<UStaticMesh> TempMesh(TEXT("/Script/Engine.StaticMesh'/Game/Drone/Drone_low.Drone_low'"));
//로딩 성공하면 BodyMesh에 사용할 Static Mesh로 TempMesh를 넣는다.
if (TempMesh.Succeeded())
{
BodyMesh->SetStaticMesh(TempMesh.Object);
BodyMesh->SetRelativeLocation(FVector(50.0f, 0, 0));
BodyMesh->SetRelativeRotation(FRotator(0, -90.0f, -90.0f));
}
}
// Called when the game starts or when spawned
void ACEnemy::BeginPlay()
{
Super::BeginPlay();
//타겟 찾기
target = UGameplayStatics::GetActorOfClass(GetWorld(), ACPlayer::StaticClass());
//아래로 방향 설정
dir = FVector(0, 0, -1);
}
// Called every frame
void ACEnemy::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
//이동
FVector P0 = GetActorLocation(); //현재 위치 설정
FVector vt = dir * speed * DeltaTime;
FVector P = P0 + vt;
SetActorLocation(P);
}
빌드 후 BP_CEnemy를 끌어다 놓고 Transform 설정하고 실행하면 아래로 움직이는 것을 볼 수 있다.
적이 Target쪽으로 움직이게 하기
CEnemy.cpp 코드 추가
//타겟 쪽으로 이동하도록 설정
dir = target->GetActorLocation() - GetActorLocation();
dir.Normalize();
전체 코드
// Fill out your copyright notice in the Description page of Project Settings.
#include "CEnemy.h"
#include "Components/BoxComponent.h"
#include <Kismet/GameplayStatics.h>
#include "CPlayer.h"
// Sets default values
ACEnemy::ACEnemy()
{
// Set this actor to call Tick() every frame. You can turn this off to improve performance if you don't need it.
PrimaryActorTick.bCanEverTick = true;
BoxComp = CreateDefaultSubobject<UBoxComponent>(TEXT("BoxComp"));
//BoxComp를 Root로 등록
RootComponent = BoxComp;
//Collision Profile 설정하기
BoxComp->SetCollisionProfileName(TEXT("EnemyProfile"));
//BodyMesh 그릇에 StaticMeshComponent를 만들어서 담으려고 한다.
BodyMesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("BodyMesh"));
BodyMesh->SetupAttachment(BoxComp);
BodyMesh->SetCollisionEnabled(ECollisionEnabled::NoCollision);
//사용할 Static Mesh 데이터를 읽어서 컴포넌트에 할당하기
ConstructorHelpers::FObjectFinder<UStaticMesh> TempMesh(TEXT("/Script/Engine.StaticMesh'/Game/Drone/Drone_low.Drone_low'"));
//로딩 성공하면 BodyMesh에 사용할 Static Mesh로 TempMesh를 넣는다.
if (TempMesh.Succeeded())
{
BodyMesh->SetStaticMesh(TempMesh.Object);
BodyMesh->SetRelativeLocation(FVector(50.0f, 0, 0));
BodyMesh->SetRelativeRotation(FRotator(0, -90.0f, -90.0f));
}
}
// Called when the game starts or when spawned
void ACEnemy::BeginPlay()
{
Super::BeginPlay();
//타겟 찾기
target = UGameplayStatics::GetActorOfClass(GetWorld(), ACPlayer::StaticClass());
//아래로 방향 설정
//dir = FVector(0, 0, -1);
//타겟 쪽으로 이동하도록 설정
dir = target->GetActorLocation() - GetActorLocation();
dir.Normalize();
}
// Called every frame
void ACEnemy::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
//이동
FVector P0 = GetActorLocation(); //현재 위치 설정
FVector vt = dir * speed * DeltaTime;
FVector P = P0 + vt;
SetActorLocation(P);
}
빌드 후 실행하면 첫 방향 그대로 쭉 이동한다.
플레이어가 죽었을 때는 아래쪽으로 움직이기
CEnemy.cpp 코드 추가 및 수정
//아래로 방향 설정
dir = FVector(0, 0, -1);
//타겟이 있을 때는 타겟쪽으로
if (IsValid(target))
{
dir = target->GetActorLocation() - GetActorLocation();
dir.Normalize();
}
전체 코드
// Fill out your copyright notice in the Description page of Project Settings.
#include "CEnemy.h"
#include "Components/BoxComponent.h"
#include <Kismet/GameplayStatics.h>
#include "CPlayer.h"
// Sets default values
ACEnemy::ACEnemy()
{
// Set this actor to call Tick() every frame. You can turn this off to improve performance if you don't need it.
PrimaryActorTick.bCanEverTick = true;
BoxComp = CreateDefaultSubobject<UBoxComponent>(TEXT("BoxComp"));
//BoxComp를 Root로 등록
RootComponent = BoxComp;
//Collision Profile 설정하기
BoxComp->SetCollisionProfileName(TEXT("EnemyProfile"));
//BodyMesh 그릇에 StaticMeshComponent를 만들어서 담으려고 한다.
BodyMesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("BodyMesh"));
BodyMesh->SetupAttachment(BoxComp);
BodyMesh->SetCollisionEnabled(ECollisionEnabled::NoCollision);
//사용할 Static Mesh 데이터를 읽어서 컴포넌트에 할당하기
ConstructorHelpers::FObjectFinder<UStaticMesh> TempMesh(TEXT("/Script/Engine.StaticMesh'/Game/Drone/Drone_low.Drone_low'"));
//로딩 성공하면 BodyMesh에 사용할 Static Mesh로 TempMesh를 넣는다.
if (TempMesh.Succeeded())
{
BodyMesh->SetStaticMesh(TempMesh.Object);
BodyMesh->SetRelativeLocation(FVector(50.0f, 0, 0));
BodyMesh->SetRelativeRotation(FRotator(0, -90.0f, -90.0f));
}
}
// Called when the game starts or when spawned
void ACEnemy::BeginPlay()
{
Super::BeginPlay();
//타겟 찾기
target = UGameplayStatics::GetActorOfClass(GetWorld(), ACPlayer::StaticClass());
//아래로 방향 설정
dir = FVector(0, 0, -1);
//타겟이 있을 때는 타겟쪽으로
if (IsValid(target))
{
dir = target->GetActorLocation() - GetActorLocation();
dir.Normalize();
}
}
// Called every frame
void ACEnemy::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
//이동
FVector P0 = GetActorLocation(); //현재 위치 설정
FVector vt = dir * speed * DeltaTime;
FVector P = P0 + vt;
SetActorLocation(P);
}
30% 확률로 아래로 향하기
CEnemy.cpp 코드 추가 및 수정
//타겟이 있고 30%의 확률로 타겟쪽으로
int percent = FMath::RandRange(1, 10);
if (IsValid(target) && percent <= 3)
{
dir = target->GetActorLocation() - GetActorLocation();
dir.Normalize();
}
전체 코드
// Fill out your copyright notice in the Description page of Project Settings.
#include "CEnemy.h"
#include "Components/BoxComponent.h"
#include <Kismet/GameplayStatics.h>
#include "CPlayer.h"
// Sets default values
ACEnemy::ACEnemy()
{
// Set this actor to call Tick() every frame. You can turn this off to improve performance if you don't need it.
PrimaryActorTick.bCanEverTick = true;
BoxComp = CreateDefaultSubobject<UBoxComponent>(TEXT("BoxComp"));
//BoxComp를 Root로 등록
RootComponent = BoxComp;
//Collision Profile 설정하기
BoxComp->SetCollisionProfileName(TEXT("EnemyProfile"));
//BodyMesh 그릇에 StaticMeshComponent를 만들어서 담으려고 한다.
BodyMesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("BodyMesh"));
BodyMesh->SetupAttachment(BoxComp);
BodyMesh->SetCollisionEnabled(ECollisionEnabled::NoCollision);
//사용할 Static Mesh 데이터를 읽어서 컴포넌트에 할당하기
ConstructorHelpers::FObjectFinder<UStaticMesh> TempMesh(TEXT("/Script/Engine.StaticMesh'/Game/Drone/Drone_low.Drone_low'"));
//로딩 성공하면 BodyMesh에 사용할 Static Mesh로 TempMesh를 넣는다.
if (TempMesh.Succeeded())
{
BodyMesh->SetStaticMesh(TempMesh.Object);
BodyMesh->SetRelativeLocation(FVector(50.0f, 0, 0));
BodyMesh->SetRelativeRotation(FRotator(0, -90.0f, -90.0f));
}
}
// Called when the game starts or when spawned
void ACEnemy::BeginPlay()
{
Super::BeginPlay();
//타겟 찾기
target = UGameplayStatics::GetActorOfClass(GetWorld(), ACPlayer::StaticClass());
//아래로 방향 설정
dir = FVector(0, 0, -1);
//타겟이 있고 30%의 확률로 타겟쪽으로
int percent = FMath::RandRange(1, 10);
if (IsValid(target) && percent <= 3)
{
dir = target->GetActorLocation() - GetActorLocation();
dir.Normalize();
}
}
// Called every frame
void ACEnemy::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
//이동
FVector P0 = GetActorLocation(); //현재 위치 설정
FVector vt = dir * speed * DeltaTime;
FVector P = P0 + vt;
SetActorLocation(P);
}
플레이어 방향을 보면서 이동하기
CEnemy.cpp 코드 추가
#include <Kismet/KismetMathLibrary.h>
//타겟 방향으로 회전하기
FRotator rot = UKismetMathLibrary::MakeRotFromXZ(GetActorForwardVector(), dir);
SetActorRotation(rot);
전체 코드
// Fill out your copyright notice in the Description page of Project Settings.
#include "CEnemy.h"
#include "Components/BoxComponent.h"
#include <Kismet/GameplayStatics.h>
#include "CPlayer.h"
#include <Kismet/KismetMathLibrary.h>
// Sets default values
ACEnemy::ACEnemy()
{
// Set this actor to call Tick() every frame. You can turn this off to improve performance if you don't need it.
PrimaryActorTick.bCanEverTick = true;
BoxComp = CreateDefaultSubobject<UBoxComponent>(TEXT("BoxComp"));
//BoxComp를 Root로 등록
RootComponent = BoxComp;
//Collision Profile 설정하기
BoxComp->SetCollisionProfileName(TEXT("EnemyProfile"));
//BodyMesh 그릇에 StaticMeshComponent를 만들어서 담으려고 한다.
BodyMesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("BodyMesh"));
BodyMesh->SetupAttachment(BoxComp);
BodyMesh->SetCollisionEnabled(ECollisionEnabled::NoCollision);
//사용할 Static Mesh 데이터를 읽어서 컴포넌트에 할당하기
ConstructorHelpers::FObjectFinder<UStaticMesh> TempMesh(TEXT("/Script/Engine.StaticMesh'/Game/Drone/Drone_low.Drone_low'"));
//로딩 성공하면 BodyMesh에 사용할 Static Mesh로 TempMesh를 넣는다.
if (TempMesh.Succeeded())
{
BodyMesh->SetStaticMesh(TempMesh.Object);
BodyMesh->SetRelativeLocation(FVector(50.0f, 0, 0));
BodyMesh->SetRelativeRotation(FRotator(0, -90.0f, -90.0f));
}
}
// Called when the game starts or when spawned
void ACEnemy::BeginPlay()
{
Super::BeginPlay();
//타겟 찾기
target = UGameplayStatics::GetActorOfClass(GetWorld(), ACPlayer::StaticClass());
//아래로 방향 설정
dir = FVector(0, 0, -1);
//타겟이 있고 30%의 확률로 타겟쪽으로
int percent = FMath::RandRange(1, 10);
if (IsValid(target) && percent <= 3)
{
dir = target->GetActorLocation() - GetActorLocation();
dir.Normalize();
}
//타겟 방향으로 회전하기
FRotator rot = UKismetMathLibrary::MakeRotFromXZ(GetActorForwardVector(), dir);
SetActorRotation(rot);
}
// Called every frame
void ACEnemy::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
//이동
FVector P0 = GetActorLocation(); //현재 위치 설정
FVector vt = dir * speed * DeltaTime;
FVector P = P0 + vt;
SetActorLocation(P);
}
플레이어 방향으로 돌려서 오는 것을 볼 수 있다.
충돌 처리 하기
Enemy가 Player나 Bullet과 충돌하도록 설정
CEnemy.h 코드 추가
void OnComponentBeginOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult);
OnComponentBeginOverlap에서 F12 눌러서 나온 코드 줄을 수정했다.
그리고 Ctrl + . 을 눌러서 cpp에 정의를 생성했다.
전체 코드
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "CEnemy.generated.h"
UCLASS()
class SHOOTING_API ACEnemy : public AActor
{
GENERATED_BODY()
public:
// Sets default values for this actor's properties
ACEnemy();
protected:
// Called when the game starts or when spawned
virtual void BeginPlay() override;
public:
// Called every frame
virtual void Tick(float DeltaTime) override;
public:
UPROPERTY(VisibleAnywhere)
class UBoxComponent* BoxComp;
UPROPERTY(VisibleAnywhere)
class UStaticMeshComponent* BodyMesh;
public:
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "MySettings")
float speed = 500;
UPROPERTY()
AActor* target;
FVector dir;
void OnComponentBeginOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult);
};
CEnemy.cpp 코드 추가
//충돌 overlap 처리 이벤트 등록
BoxComp->OnComponentBeginOverlap.AddDynamic(this, &ACEnemy::OnComponentBeginOverlap);
void ACEnemy::OnComponentBeginOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult)
{
//상대편 파괴
OtherActor->Destroy();
//나 자신 파괴
Destroy();
}
전체 코드
// Fill out your copyright notice in the Description page of Project Settings.
#include "CEnemy.h"
#include "Components/BoxComponent.h"
#include <Kismet/GameplayStatics.h>
#include "CPlayer.h"
#include <Kismet/KismetMathLibrary.h>
// Sets default values
ACEnemy::ACEnemy()
{
// Set this actor to call Tick() every frame. You can turn this off to improve performance if you don't need it.
PrimaryActorTick.bCanEverTick = true;
BoxComp = CreateDefaultSubobject<UBoxComponent>(TEXT("BoxComp"));
//BoxComp를 Root로 등록
RootComponent = BoxComp;
//Collision Profile 설정하기
BoxComp->SetCollisionProfileName(TEXT("EnemyProfile"));
//충돌 overlap 처리 이벤트 등록
BoxComp->OnComponentBeginOverlap.AddDynamic(this, &ACEnemy::OnComponentBeginOverlap);
//BodyMesh 그릇에 StaticMeshComponent를 만들어서 담으려고 한다.
BodyMesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("BodyMesh"));
BodyMesh->SetupAttachment(BoxComp);
BodyMesh->SetCollisionEnabled(ECollisionEnabled::NoCollision);
//사용할 Static Mesh 데이터를 읽어서 컴포넌트에 할당하기
ConstructorHelpers::FObjectFinder<UStaticMesh> TempMesh(TEXT("/Script/Engine.StaticMesh'/Game/Drone/Drone_low.Drone_low'"));
//로딩 성공하면 BodyMesh에 사용할 Static Mesh로 TempMesh를 넣는다.
if (TempMesh.Succeeded())
{
BodyMesh->SetStaticMesh(TempMesh.Object);
BodyMesh->SetRelativeLocation(FVector(50.0f, 0, 0));
BodyMesh->SetRelativeRotation(FRotator(0, -90.0f, -90.0f));
}
}
// Called when the game starts or when spawned
void ACEnemy::BeginPlay()
{
Super::BeginPlay();
//타겟 찾기
target = UGameplayStatics::GetActorOfClass(GetWorld(), ACPlayer::StaticClass());
//아래로 방향 설정
dir = FVector(0, 0, -1);
//타겟이 있고 30%의 확률로 타겟쪽으로
int percent = FMath::RandRange(1, 10);
if (IsValid(target) && percent <= 3)
{
dir = target->GetActorLocation() - GetActorLocation();
dir.Normalize();
}
//타겟 방향으로 회전하기
FRotator rot = UKismetMathLibrary::MakeRotFromXZ(GetActorForwardVector(), dir);
SetActorRotation(rot);
}
// Called every frame
void ACEnemy::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
//이동
FVector P0 = GetActorLocation(); //현재 위치 설정
FVector vt = dir * speed * DeltaTime;
FVector P = P0 + vt;
SetActorLocation(P);
}
void ACEnemy::OnComponentBeginOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult)
{
//상대편 파괴
OtherActor->Destroy();
//나 자신 파괴
Destroy();
}
빌드 후 실행해도 파괴가 되지 않는다.
블루프린트에서는 우리가 만든 함수를 읽을 수 없기 때문에
CEnemy.h 헤더 파일에서 UFUNCTION()을 추가한다.
UFUNCTION()
void OnComponentBeginOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult);
빌드 후 에디터 껐다 켜고 실행하니 잘 된다.
'Unreal Engine' 카테고리의 다른 글
[Unreal] 18일차 - Game Mode Class 만들기, 3인칭 카메라 생성과 회전, IMC 생성 및 적용, 플레이어 이동과 점프 (0) | 2024.08.08 |
---|---|
[Unreal] 17일차 - 폭발 이펙트 추가, 적 생성, 프로젝트 빌드, TPS 프로젝트 생성 (0) | 2024.08.07 |
[Unreal] 15일차 - C++ 플레이어 이동, 총알 생성 및 발사하기 (0) | 2024.08.03 |
[Unreal] 14일차 - 블루프린트로 만들어진 것을 C++로 만들기 (StaticMeshComponent, Details, SubObject, RootComponent, 위치값) (0) | 2024.08.02 |
[Unreal] 13일차 - C++ 시작, Hello World 출력, 자료형 (0) | 2024.08.01 |