19.Toggling the Spawn Volumes
SpawnVolume.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
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63 |
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "GameFramework/Actor.h"
#include "SpawnVolume.generated.h"
UCLASS()
class BATTERYCOLLECTOR_API ASpawnVolume : public AActor
{
GENERATED_BODY()
public:
// Sets default values for this actor's properties
ASpawnVolume();
// Called when the game starts or when spawned
virtual void BeginPlay() override;
// Called every frame
virtual void Tick( float DeltaSeconds ) override;
/*Returns the WhereToSpawn subobject*/
FORCEINLINE class UBoxComponent* GetWhereToSpawn() const { return WhereToSpawn; }
/*Find a random point within the Boxcomponent*/
UFUNCTION(BlueprintPure, Category = "Spawning")
FVector GetRandomPointInVolume();
/**This function toggles whether or not the spawn volume spawns pickups*/
UFUNCTION(BlueprintCallable, Category = "Spawning")
void SetSpawningActive(bool bShouldSpawn);
protected:
/**The pickup to spawn*/
UPROPERTY(EditAnywhere, Category = "spawn")
TSubclassOf<class APickup> WhatToSpawn;
FTimerHandle SpawnTimer;
//Minimum spawn delay
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Spawning")
float SpawnDelayRangeLow;
//Maximum spawn delay
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Spawning")
float SpawnDelayRangeHigh;
private:
/*Box Component to specify where pickups should be spawned*/
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Spawning", meta = (AllowPrivateAccess = "true"))
class UBoxComponent* WhereToSpawn;
//Handle spawning a new pickup
void SpawnPickup();
/*The current spawn delay*/
float SpawnDelay;
};
|
cs |
33)Blueprint의 기능을 이용하면 spawn volume으로 하여금 언제 spawn을 하고 말지 호출하도록 만들 수 있다.
34)volume spawn 의 pickupspawn 작동을 조정하는 함수
파라미터로 Bool bShouldSpawn을 받아서 Spawn Volme의 활성화 여부를 결정하게 한다.
SpawnVolume.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
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78 |
// Fill out your copyright notice in the Description page of Project Settings.
#include "BatteryCollector.h"
#include "SpawnVolume.h"
#include "Kismet/KismetMathLibrary.h"
#include "Pickup.h"
// Sets default values
ASpawnVolume::ASpawnVolume()
{
// Set this actor to call Tick() every frame.
PrimaryActorTick.bCanEverTick = false;
//Create the Box Component to represent the spawn volume
WhereToSpawn = CreateDefaultSubobject<UBoxComponent>(TEXT("WhereToSpawn"));
RootComponent = WhereToSpawn;
//Set the spawn delay range
SpawnDelayRangeLow = 1.0f;
SpawnDelayRangeHigh = 4.5f;
}
// Called when the game starts or when spawned
void ASpawnVolume::BeginPlay()
{
Super::BeginPlay();
}
// Called every frame
void ASpawnVolume::Tick( float DeltaTime )
{
Super::Tick( DeltaTime );
}
FVector ASpawnVolume::GetRandomPointInVolume(){
FVector SpawnOrigin = WhereToSpawn->Bounds.Origin;
FVector SpawnExtent = WhereToSpawn->Bounds.BoxExtent;
return UKismetMathLibrary::RandomPointInBoundingBox(SpawnOrigin, SpawnExtent);
}
void ASpawnVolume::SetSpawningActive(bool bShouldSpawn){
if (bShouldSpawn){
//Set the timer on Spawn Pickup
SpawnDelay = FMath::FRandRange(SpawnDelayRangeLow, SpawnDelayRangeHigh);
GetWorldTimerManager().SetTimer(SpawnTimer, this, &ASpawnVolume::SpawnPickup, SpawnDelay, false);
}
else{
//clear the timer on spawn pickup
GetWorldTimerManager().ClearTimer(SpawnTimer);
}
}
void ASpawnVolume::SpawnPickup(){
//1.If we have set something to spawn:
if (WhatToSpawn != NULL){
//2.Check for a valid world:
UWorld* const World = GetWorld();
if (World){
//3.Set the spawn parameters
FActorSpawnParameters SpawnParams;
SpawnParams.Owner = this;
SpawnParams.Instigator = Instigator;
/**Get a random location to spawn at*/
FVector SpawnLocation = GetRandomPointInVolume();
//Get a random rotation for the spawned item
FRotator SpawnRotation;
SpawnRotation.Yaw = FMath::FRand()*360.0f;
SpawnRotation.Pitch = FMath::FRand()*360.0f;
SpawnRotation.Roll = FMath::FRand()*360.0f;
//4.spawn the pickup
APickup* const SpawnedPickup = World->SpawnActor<APickup>(WhatToSpawn, SpawnLocation, SpawnRotation, SpawnParams);
SpawnDelay = FMath::FRandRange(SpawnDelayRangeLow, SpawnDelayRangeHigh);
GetWorldTimerManager().SetTimer(SpawnTimer, this, &ASpawnVolume::SpawnPickup, SpawnDelay, false);
}
}
} |
cs |
41)활성화 여부는 bShouldSpawn의 값을 따른다.
43,44)Beginplay에 타이머두고 기준으로 spawnpickup함수를 호출할지 말지 결정했었음.
spawn volume은 setspawningActive함수가 호출되고 나서 spawning을 시작해야 하므로 BeginPlay에 있던 타이머를 여기로 옮겨옴.
44)게임속 실행중인 모든 타이머를 추적한다.
48)spawn pickup함수가 tick에서 더이상 호출되지 않는다.
BatteryCollectorGameMode.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
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62 |
// Copyright 1998-2015 Epic Games, Inc. All Rights Reserved.
#pragma once
#include "GameFramework/GameMode.h"
#include "BatteryCollectorGameMode.generated.h"
//enum to store the current state of gameplay
UENUM(BlueprintType)
enum class EBatteryPlayState{
EPlaying,
EGameOver,
EWon,
EUnknown
};
UCLASS(minimalapi)
class ABatteryCollectorGameMode : public AGameMode
{
GENERATED_BODY()
public:
ABatteryCollectorGameMode();
virtual void Tick(float DeltaTime) override;
//Returns power needed to win - needed for the HUD
UFUNCTION(BlueprintPure, Category = "Power")
float GetPowerToWin() const;
virtual void BeginPlay() override;
/**Returns the current playing state*/
UFUNCTION(Blueprintpure, Category = "Power")
EBatteryPlayState GetCurrentState() const;
//Sets a new playing state
void SetCurrentState(EBatteryPlayState NewState);
protected:
/**The rate at which the character loses power */
UPROPERTY(EditDefaultsOnly, BlueprintReadWrite, Category = "Power", Meta = (BlueprintProtected = "true"))
float DecayRate;
/**The power needed to win the game*/
UPROPERTY(EditDefaultsOnly, BlueprintReadWrite, Category = "Power", Meta = (BlueprintProtected = "true"))
float PowerToWin;
/**The widget class to use for our HUD screen*/
UPROPERTY(EditDefaultsOnly, BlueprintReadWrite, Category = "Power", Meta = (BlueprintProtected = "true"))
TSubclassOf<class UUserWidget> HUDWidgetClass;
//The instance of the HUD
/***/
UPROPERTY()
class UUserWidget* CurrentWidget;
private:
/** Keeps track of the current playing state*/
EBatteryPlayState CurrentState;
TArray<class ASpawnVolume*> SpawnVolumeActors;
/** Handle any function calls that rely upon changing the playing state of our game*/
void HandleNewState(EBatteryPlayState NewState);
}; |
cs |
57)모든 spawn volume을 배열에 저장할 것.
61)게임 플레이 상태에 영향을 주는 모든 함수의 호출을 담당
BatteryCollectorGameMode.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
49
50
51
52
53
54
55
56 |
// Copyright 1998-2015 Epic Games, Inc. All Rights Reserved.
#include "BatteryCollector.h"
#include "BatteryCollectorGameMode.h"
#include "BatteryCollectorCharacter.h"
#include "Kismet/GameplayStatics.h"
#include "Blueprint/UserWidget.h"
#include "SpawnVolume.h"
ABatteryCollectorGameMode::ABatteryCollectorGameMode()
{
// set default pawn class to our Blueprinted character
static ConstructorHelpers::FClassFinder<APawn> PlayerPawnBPClass(TEXT("/Game/ThirdPersonCPP/Blueprints/ThirdPersonCharacter"));
if (PlayerPawnBPClass.Class != NULL)
{
DefaultPawnClass = PlayerPawnBPClass.Class;
}
//base decay rate
DecayRate = 0.01f;
}
void ABatteryCollectorGameMode::BeginPlay()
{
Super::BeginPlay();
TArray<AActor*> FoundActors;
UGameplayStatics::GetAllActorsOfClass(GetWorld(), ASpawnVolume::StaticClass(), FoundActors);
for (auto Actor : FoundActors)
{
ASpawnVolume* SpawnVolumeActor = Cast<ASpawnVolume>(Actor);
if (SpawnVolumeActor)
{
SpawnVolumeActors.AddUnique(SpawnVolumeActor);
}
}
SetCurrentState(EBatteryPlayState::EPlaying);
// set the score to beat
ABatteryCollectorCharacter* MyCharacter = Cast<ABatteryCollectorCharacter> (UGameplayStatics::GetPlayerPawn(this, 0));
if (MyCharacter)
{
PowerToWin = (MyCharacter->GetInitialPower())*1.25f;
}
if (HUDWidgetClass != nullptr)
{
CurrentWidget = CreateWidget<UUserWidget>(GetWorld(), HUDWidgetClass);
if (CurrentWidget != nullptr)
{
CurrentWidget->AddToViewport();
}
}
} |
cs |
23~37)게임이 시작하면 GetAllActorsOfClass를 사용해서 모든 spawnvolume 액터를 검색함->
찾아낸 Actor를 저장하기 위해 배열 내 엑터를 형변환 하고-> spawn volume엑터로 확인되면 spawnvolumeActor배열에 저장한다.
27)레벨에서 모든 엑터 찾기 ->spawn Volume찾으면 spawnvolumeActor배열에 저장.
28)GetAllActorsOfClass : 레벨전체를 검색하기때문에 레벨의 크기가 아주크면 퍼포먼스에 신경써야함.
27,8)또 다른 Gameplay Statics함수와 또 다른 배열을 이용해 초기화된 엑터를 담을것.
엑터의 베이스 클래스로 배열을 설정한 이유는 GetAllActorsOfClass가 이 클래스 형으로 반환하기 때문이다.
20.Handling New Play States
BatteryCollectorGameMode.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 |
// Copyright 1998-2015 Epic Games, Inc. All Rights Reserved.
#pragma once
#include "GameFramework/GameMode.h"
#include "BatteryCollectorGameMode.generated.h"
//enum to store the current state of gameplay
UENUM(BlueprintType)
enum class EBatteryPlayState{
EPlaying,
EGameOver,
EWon,
EUnknown
};
UCLASS(minimalapi)
class ABatteryCollectorGameMode : public AGameMode
{
private:
/** Keeps track of the current playing state*/
EBatteryPlayState CurrentState;
TArray<class ASpawnVolume*> SpawnVolumeActors;
/** Handle any function calls that rely upon changing the playing state of our game */
void HandleNewState(EBatteryPlayState NewState);
}; |
cs |
24) 게임 플레이 상태에 영향을 주는 모든 함수의 호출을 담당 .
handler를 gamemode내에서만 호출할 수 있게 하기 위해서 private.
BatteryCollectorGameMode.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
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157 |
// Copyright 1998-2015 Epic Games, Inc. All Rights Reserved.
#include "BatteryCollector.h"
#include "BatteryCollectorGameMode.h"
#include "BatteryCollectorCharacter.h"
#include "Kismet/GameplayStatics.h"
#include "Blueprint/UserWidget.h"
#include "SpawnVolume.h"
ABatteryCollectorGameMode::ABatteryCollectorGameMode()
{
// set default pawn class to our Blueprinted character
static ConstructorHelpers::FClassFinder<APawn> PlayerPawnBPClass(TEXT("/Game/ThirdPersonCPP/Blueprints/ThirdPersonCharacter"));
if (PlayerPawnBPClass.Class != NULL)
{
DefaultPawnClass = PlayerPawnBPClass.Class;
}
//base decay rate
DecayRate = 0.01f;
}
void ABatteryCollectorGameMode::BeginPlay()
{
Super::BeginPlay();
// find all spawn volume Actors
TArray<AActor*> FoundActors;
UGameplayStatics::GetAllActorsOfClass(GetWorld(), ASpawnVolume::StaticClass(), FoundActors);
for (auto Actor : FoundActors)
{
ASpawnVolume* SpawnVolumeActor = Cast<ASpawnVolume>(Actor);
if (SpawnVolumeActor)
{
SpawnVolumeActors.AddUnique(SpawnVolumeActor);
}
}
SetCurrentState(EBatteryPlayState::EPlaying);
// set the score to beat
ABatteryCollectorCharacter* MyCharacter = Cast<ABatteryCollectorCharacter>(UGameplayStatics::GetPlayerPawn(this, 0));
if (MyCharacter)
{
PowerToWin = (MyCharacter->GetInitialPower())*1.25f;
}
if (HUDWidgetClass != nullptr)
{
CurrentWidget = CreateWidget<UUserWidget>(GetWorld(), HUDWidgetClass);
if (CurrentWidget != nullptr)
{
CurrentWidget->AddToViewport();
}
}
}
void ABatteryCollectorGameMode::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
// Check that we are using the battery collector character
ABatteryCollectorCharacter* MyCharacter = Cast<ABatteryCollectorCharacter>(UGameplayStatics::GetPlayerPawn(this, 0));
if (MyCharacter)
{
// If our power is greater than needed to win, set the game's state to Won
if (MyCharacter->GetCurrentPower() > PowerToWin)
{
SetCurrentState(EBatteryPlayState::EWon);
}
// if the character's power is positive
else if (MyCharacter->GetCurrentPower() > 0)
{
// decrease the character's power using the decay rate
MyCharacter->UpdatePower(-DeltaTime*DecayRate*(MyCharacter->GetInitialPower()));
}
else
{
SetCurrentState(EBatteryPlayState::EGameOver);
}
}
}
float ABatteryCollectorGameMode::GetPowerToWin() const
{
return PowerToWin;
}
EBatteryPlayState ABatteryCollectorGameMode::GetCurrentState() const
{
return CurrentState;
}
void ABatteryCollectorGameMode::SetCurrentState(EBatteryPlayState NewState)
{
//set current state
CurrentState = NewState;
// handle the new current state
HandleNewState(CurrentState);
}
void ABatteryCollectorGameMode::HandleNewState(EBatteryPlayState NewState)
{
switch (NewState)
{
// If the game is playing
case EBatteryPlayState::EPlaying:
{
// spawn volumes active
for (ASpawnVolume* Volume : SpawnVolumeActors)
{
Volume->SetSpawningActive(true);
}
}
break;
// If we've won the game
case EBatteryPlayState::EWon:
{
// spawn volumes inactive
for (ASpawnVolume* Volume : SpawnVolumeActors)
{
Volume->SetSpawningActive(false);
}
}
break;
// If we've lost the game
case EBatteryPlayState::EGameOver:
{
// spawn volumes inactive
for (ASpawnVolume* Volume : SpawnVolumeActors)
{
Volume->SetSpawningActive(false);
}
// block player input : cinematic mode
APlayerController* PlayerController = UGameplayStatics::GetPlayerController(this, 0);
if (PlayerController){
PlayerController->SetCinematicMode(true, false, false, true, true);
}
// ragdoll the character
ACharacter* MyCharacter = UGameplayStatics::GetPlayerCharacter(this, 0);
if (MyCharacter){
MyCharacter->GetMesh()->SetSimulatePhysics(true);
MyCharacter->GetMovementComponent()->MovementState.bCanJump = false;
}
}
break;
// Unknown/default state
default:
case EBatteryPlayState::EUnknown:
{
// do nothing
}
break;
}
}
|
cs |
148,149)HandleCurrentState의 호출을 잊어서 EPlaying, EWon, EGameOVer등의 상태가 나타나지
않을때 도움이 될것. 이 switch문에 떨어질때를 대비해 디버그스트링을 삽입할 수도 있다
110~)for문: 배열 내 모든엑터들을 돌면서 SetSpawningActive을 false 또는 true로.
134)cinematic mode:플레이어 입력 차단
139~144)mesh를 가져와서 게임에서 패배하면 캐릭터가 ragdoll을 일으켜 쓰러지도록함.
현재 include되어있는 기본캐릭터로 작업중이기 때문에 커스텀한 캐릭터로 형변환 하지 않는다.
movement등이 기본으로 들어가있는 클래스.
폰이 아니라 반드시 캐릭터를 사용해야한다. 캐릭터 클래스에는 추가적인 이동셋과 스켈레탈 메시까지 붙어있기 때문이다.
140)뒤에 GetPlayerCharacter를 써서 형변환이 더이상 필요없도록.
*ragdoll은 skeletal mesh에서 create - physics asset추가. 그리고 캐릭터 블루프린트 collision변경.
게임오바되면 ragdoll적용되서 와르르 무너지고 입력안된당.
'프로그래밍 > Unreal' 카테고리의 다른 글
[17]액터 (0) | 2017.05.15 |
---|---|
[16] UE4 C++ 프로그래밍 입문_0 (0) | 2017.05.15 |
[14]Battery Collector_player 상태 설정 (0) | 2017.05.13 |
[13]Battery Collector_HUD 블루프린트 만들기 (0) | 2017.05.12 |
[12]Battery Collector_UMG 활성화 (0) | 2017.05.11 |