Unreal Engine and C++ (1)

개요


Class 마법사(Unreal Engine에서 새로운 Class 만들기)

File > New C++ Class >
Class 지정

이름과 경로 지정
생성 완료

MyActor.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "MyActor.generated.h"

UCLASS()
class CPPTEST_API AMyActor : public AActor
{
GENERATED_BODY()

public:
// Sets default values for this actor's properties
AMyActor();

protected:
// Called when the game starts or when spawned
virtual void BeginPlay() override;

public:
// Called every frame
virtual void Tick(float DeltaTime) override;

};
  • BeingPalay()는 액터가 플레이 가능한 상태로 게임에 들어왔음을 알려주는 이벤트
  • Tick()는 지난번 들여온 이후의 경과된 시간만큼 프레임당 한 번씩 호출된다

MyActor.Cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// Fill out your copyright notice in the Description page of Project Settings.

#include "MyActor.h"

// Sets default values
AMyActor::AMyActor()
{
// 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;

}

// Called when the game starts or when spawned
void AMyActor::BeginPlay()
{
Super::BeginPlay();

}

// Called every frame
void AMyActor::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);

}
  • PrimaryActorTick.bCanEverTick = true를 제거함으로써 필요치 않은 반복 로직을 제거할 수 있다

컴파일

그림의 컴파일 버튼으로 컴파일을 빠르게 할 수 있다


Class

접두사

  • A : 스폰가능한 게임플레이 오브젝트의 베이스 클래스에서 확장(Actor, 월드에서 바로 스폰 가능)
  • U : 모든 게임플레이 오브젝트의 베이스 클래스에서 확장(월드에서 바로 인스턴싱 불가, 엑터에 속해야함, 컴포넌트와 같은 오브젝트)

선언

1
2
3
4
5
UCLASS([specifier, specifier, ...], [meta(key = value, key = value, ...)])
class ClassName : public ParentName // 클래스의 상속
{
GENERATED_BODY()
}
  • UCLASS매크로에 클래스 지정자나 메타데이터와 같은 지시어가 전달됨
  • GENERATED_BODY()매크로는 본문 제일 처음에 와야함
  • 아래의 Class Specifier를 위의 specifier란에 용도에 맞게 적어서 쓸 수 있다

Class Specifier


프로퍼티가 에디터에 보이도록 만들기

MyActor.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "MyActor.generated.h"

UCLASS()
class CPPTEST_API AMyActor : public AActor
{
GENERATED_BODY()

public:
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Damage")
int32 TotalDamge;

public:
// Sets default values for this actor's properties
AMyActor();

protected:
// Called when the game starts or when spawned
virtual void BeginPlay() override;

public:
// Called every frame
virtual void Tick(float DeltaTime) override;

};
  • GENERATED_BODY()UPROPERTY()뒤에는 ;을 붙이지 않는다
  • 아래의 프로퍼티 지정자UPROPERTY()에 적절히 사용함으로써 위의 상황에선 다음과 같은 설정을 할 수 있다

프로퍼티 부여

MyActor.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "MyActor.generated.h"

UCLASS()
class CPPTEST_API AMyActor : public AActor
{
GENERATED_BODY()

public:
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Damage")
int32 TotalDamage;

UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Damage")
float DamageTimeInSeconds;

UPROPERTY(BlueprintReadOnly, VisibleAnywhere, Transient, Category = "Damage")
float DamagePerSecond;

public:
// Sets default values for this actor's properties
AMyActor();

protected:
// Called when the game starts or when spawned
virtual void BeginPlay() override;

public:
// Called every frame
virtual void Tick(float DeltaTime) override;

};

더 많은 프로퍼티 부여

MyActor.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// Fill out your copyright notice in the Description page of Project Settings.

#include "MyActor.h"

// Sets default values
AMyActor::AMyActor()
{
// 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;
TotalDamage = 200;
DamageTimeInSeconds = 1.f;

}

// Called when the game starts or when spawned
void AMyActor::BeginPlay()
{
Super::BeginPlay();

}

// Called every frame
void AMyActor::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);

}

프로퍼티에 초기값 부여


종속적인 프로퍼티 계산 시키기

1
2
3
4
5
void AMyActor::PostInitProperties()
{
Super::PostInitProperties();
DamagePerSecond = TotalDamage / DamageTimeInSeconds;
}

위와 같이 선언해주면 초기값만 계산한다

MyActor.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "MyActor.generated.h"

UCLASS()
class CPPTEST_API AMyActor : public AActor
{
GENERATED_BODY()

public:
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Damage")
int32 TotalDamage;

UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Damage")
float DamageTimeInSeconds;

UPROPERTY(BlueprintReadOnly, VisibleAnywhere, Transient, Category = "Damage")
float DamagePerSecond;

public:
// Sets default values for this actor's properties
AMyActor();

protected:
// Called when the game starts or when spawned
virtual void BeginPlay() override;

public:
// Called every frame
virtual void Tick(float DeltaTime) override;
void PostInitProperties();
void CalculateValues();
void PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent);
};

MyActor.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
// Fill out your copyright notice in the Description page of Project Settings.

#include "MyActor.h"

// Sets default values
AMyActor::AMyActor()
{
// 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;
TotalDamage = 200;
DamageTimeInSeconds = 1.f;

}

// Called when the game starts or when spawned
void AMyActor::BeginPlay()
{
Super::BeginPlay();

}

// Called every frame
void AMyActor::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);

}

void AMyActor::PostInitProperties()
{
Super::PostInitProperties();

CalculateValues();
}

void AMyActor::CalculateValues()
{
DamagePerSecond = TotalDamage / DamageTimeInSeconds;
}

#if WITH_EDITOR
void AMyActor::PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent)
{
CalculateValues();

Super::PostEditChangeProperty(PropertyChangedEvent);
}
#endif

계산이 되는 모습


여러가지 프로퍼티 지정자

프로퍼티 지정자