박하의 나날

[07]BatteryCollector_아이템습득

프로그래밍/Unreal

 

09. Extending the Character Class / 10.Collecting Pickups 

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
// Fill out your copyright notice in the Description page of Project Settings.
 
#pragma once
 
#include "GameFramework/Actor.h"
#include "Pickup.generated.h"
UCLASS()
class BATTERYCOLLECTOR_API APickup : public AActor
{
    GENERATED_BODY()
    
public:    
    // Sets default values for this actor's properties
    APickup();
    // Called when the game starts or when spawned
    virtual void BeginPlay() override;
    // Called every frame
    virtual void Tick( float DeltaSeconds ) override;
 
    /**Return the mesh for the pickup*/
    FORCEINLINE class UStaticMeshComponent* GetMesh() const{ return PickupMesh; }
 
    UFUNCTION(BlueprintPure, Category = "Pickup")
    bool IsActive(); //값을 반환해줄 함수
 
    //Allows other classes to saftely change whether or not pickup is active
    UFUNCTION(BluePrintCallable, Category = "Pickup")
    void SetActive(bool NewPickupState);
    
    
    //Function to call when the pickup is collected
    UFUNCTION(BlueprintNativeEvent)
    void WasCollected();//배터리 아이템을 먹고 일어나야할일?
    virtual void WasCollected_Implementation();
 
protected: 
    /**True when the pickup can be used, and false when pickup is deactivated*/
    bool blsActive;
    
private:
    //static mesh to represent the pickup in the level
    UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Pickup", meta = (AllowPrivateAccess = "true"))
    class UStaticMeshComponent* PickupMesh; 
};
 
 
cs
아이템을 먹는 Collection 코드: 아이템에서 일어나는 부분,

캐릭터에서 블루프린트 네이티브 이벤트는 이벤트 발생시 코드에서 설정한 부분을 실행한다.

블루프린트에서는 설정불가.

임플멘테이션(Implementation): virtual 함수, 자식클래스에서 오버라이딩이 가능해야한다.

34)자식 클래스에서 오버라이딩 할 수 있다.
 하지만 하나의 함수호출로 wascollected를 코드 임플멘테이션과 블루프린트 임플멘테이션이  

 호출하는 방법 대로만 실행된다.  그래서 둘을 같이 놓거나 둘다 만들어놓거나 하지 않는다.

 

pickup.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
// Fill out your copyright notice in the Description page of Project Settings.
 
#include "BatteryCollector.h"
#include "Pickup.h"
 
// Sets default values
APickup::APickup()
{
     // Set this actor to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
    PrimaryActorTick.bCanEverTick = false; 
 
    //all pickups start activate
    blsActive = true;
    
    PickupMesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("PickupMesh"));
    RootComponent = PickupMesh; 
}
 
// Called when the game starts or when spawned
void APickup::BeginPlay()
{
    Super::BeginPlay();
}
 
void APickup::Tick(float DeltaTime){
    Super::Tick(DeltaTime);
}
//return active state
bool APickup::IsActive(){
    return blsActive;
}
//change active state
void APickup::SetActive(bool NewPickupState){
    blsActive = NewPickupState;
}
 
void APickup::WasCollected_Implementation(){
    //log a debug message
    FString PickupDebugString = GetName();
    UE_LOG(LogClass, Log, TEXT("You have collected &s"), *PickupDebugString);
}
cs

40)LogClass는 기본 임플멘테이션에 사용된다.

 

BatteryPickup.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// Fill out your copyright notice in the Description page of Project Settings.
 
#pragma once
 
#include "Pickup.h"
#include "BatteryPickup.generated.h"
 
UCLASS()
class BATTERYCOLLECTOR_API ABatteryPickup : public APickup
{
    GENERATED_BODY()
 
    // Sets default values for this actor's properties
public:
    ABatteryPickup();
    // Called when the game starts or when spawned
    virtual void BeginPlay() override;
 
    /**Override the WasCollected function_us Implementation
    because it's a Bluepirnt Native Event*/
    void WasCollected_Implementation() override;
};
 
cs

21) WasCollected 함수 오버라이드. 블루프린트 네이티브 이벤트이기 때문에 임플멘테이션 사용.

 

BatteryPickup.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// Fill out your copyright notice in the Description page of Project Settings.
 
#include "BatteryCollector.h"
#include "BatteryPickup.h"
 
//Set Default values
ABatteryPickup::ABatteryPickup(){
    //GetMesh()->SetSimulatePhysics(true);
//생성되자마자 자유낙하(물리적용)
}
void ABatteryPickup::BeginPlay()
{
    Super::BeginPlay();
    GetMesh()->SetSimulatePhysics(true);
}
 
void ABatteryPickup::WasCollected_Implementation(){
    //Use the base pickup behavior
    Super::WasCollected_Implementation();
    //Destroy the battery
    Destroy();
}
 
cs
임플멘테이션 키워드는 서버, 클라이언트나 매크로 키워드로 코드 내에서 정의된 특정한 경우에 해당한다.

 

 

BatteryCollectorCharacter.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// Copyright 1998-2015 Epic Games, Inc. All Rights Reserved.
#pragma once
#include "GameFramework/Character.h"
#include "BatteryCollectorCharacter.generated.h"
 
UCLASS(config=Game)
class ABatteryCollectorCharacter : public ACharacter
{
    GENERATED_BODY()
 
    /** Camera boom positioning the camera behind the character */
    UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Camera, meta = (AllowPrivateAccess = "true"))
    class USpringArmComponent* CameraBoom;
 
    /** Follow camera */
    UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Camera, meta = (AllowPrivateAccess = "true"))
    class UCameraComponent* FollowCamera;
 
    /** Collection sphere */
    UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Camera, meta = (AllowPrivateAccess = "true"))
    class USphereComponent* CollectionSphere;
cs

19~21) 캐릭터에 아이템 인식을 위한 원 추가.


BatteryCollectorCharacter.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
// Copyright 1998-2015 Epic Games, Inc. All Rights Reserved.
 
#include "BatteryCollector.h"
#include "BatteryCollectorCharacter.h"
#include "Pickup.h"
//////////////////////////////////////////////////////////////////////////
// ABatteryCollectorCharacter
 
ABatteryCollectorCharacter::ABatteryCollectorCharacter()
{
    // Set size for collision capsule
    GetCapsuleComponent()->InitCapsuleSize(42.f, 96.0f);
 
    // set our turn rates for input
    BaseTurnRate = 45.f;
    BaseLookUpRate = 45.f;
 
    // Don't rotate when the controller rotates. Let that just affect the camera.
    bUseControllerRotationPitch = false;
    bUseControllerRotationYaw = false;
    bUseControllerRotationRoll = false;
 
    // Configure character movement
    GetCharacterMovement()->bOrientRotationToMovement = true; // Character moves in the direction of input...    
    GetCharacterMovement()->RotationRate = FRotator(0.0f, 540.0f, 0.0f); // ...at this rotation rate
    GetCharacterMovement()->JumpZVelocity = 600.f;
    GetCharacterMovement()->AirControl = 0.2f;
 
    // Create a camera boom (pulls in towards the player if there is a collision)
    CameraBoom = CreateDefaultSubobject<USpringArmComponent>(TEXT("CameraBoom"));
    CameraBoom->AttachTo(RootComponent);
    CameraBoom->TargetArmLength = 300.0f; // The camera follows at this distance behind the character    
    CameraBoom->bUsePawnControlRotation = true; // Rotate the arm based on the controller
 
    // Create a follow camera
    FollowCamera = CreateDefaultSubobject<UCameraComponent>(TEXT("FollowCamera"));
    FollowCamera->AttachTo(CameraBoom, USpringArmComponent::SocketName); // Attach the camera to the end of the boom and let the boom adjust to match the controller orientation
    FollowCamera->bUsePawnControlRotation = false; // Camera does not rotate relative to arm
 
    //create the collection sphere
    CollectionSphere = CreateDefaultSubobject<USphereComponent>(TEXT("CollectionSphere"));
    CollectionSphere->AttachTo(RootComponent);
    CollectionSphere->SetSphereRadius(300.0f);
 
    // Note: The skeletal mesh and anim blueprint references on the Mesh component (inherited from Character) 
    // are set in the derived blueprint asset named MyCharacter (to avoid direct content references in C++)
}
//////////////////////////////////////////////////////////////////////////
// Input
 
void ABatteryCollectorCharacter::SetupPlayerInputComponent(class UInputComponent* InputComponent)
{
    // Set up gameplay key bindings
    check(InputComponent);
    InputComponent->BindAction("Jump", IE_Pressed, this, &ACharacter::Jump);
    InputComponent->BindAction("Jump", IE_Released, this, &ACharacter::StopJumping);
 
    InputComponent->BindAction("Collect", IE_Pressed, this, &ABatteryCollectorCharacter::CollectPickups);
 
    InputComponent->BindAxis("MoveForward", this, &ABatteryCollectorCharacter::MoveForward);
    InputComponent->BindAxis("MoveRight", this, &ABatteryCollectorCharacter::MoveRight);
 
    // We have 2 versions of the rotation bindings to handle different kinds of devices differently
    // "turn" handles devices that provide an absolute delta, such as a mouse.
    // "turnrate" is for devices that we choose to treat as a rate of change, such as an analog joystick
    InputComponent->BindAxis("Turn", this, &APawn::AddControllerYawInput);
    InputComponent->BindAxis("TurnRate", this, &ABatteryCollectorCharacter::TurnAtRate);
    InputComponent->BindAxis("LookUp", this, &APawn::AddControllerPitchInput);
    InputComponent->BindAxis("LookUpRate", this, &ABatteryCollectorCharacter::LookUpAtRate);
 
    // handle touch devices
    InputComponent->BindTouch(IE_Pressed, this, &ABatteryCollectorCharacter::TouchStarted);
    InputComponent->BindTouch(IE_Released, this, &ABatteryCollectorCharacter::TouchStopped);
}
 
void ABatteryCollectorCharacter::CollectPickups(){
    //Get all overlapping actors and store them in an array
    TArray < AActor* > CollectedActors;
    CollectionSphere->GetOverlappingActors(CollectedActors);
    //For each Actor we collected
    for (int32 iCollected = 0; iCollected < CollectedActors.Num(); ++iCollected){
        // Cast the actor to APickup
        APickup* const TestPickup = Cast<APickup>(CollectedActors[iCollected]);
            //If the cast is successful and the pickup is valid and active
        if (TestPickup && !TestPickup->IsPendingKill() && TestPickup->IsActive()){
            //call the pickup's wascollected function
            TestPickup->WasCollected();
            //deactivate the pickup
            TestPickup->SetActive(false);
        }
    }        
}
 
 
cs

 

44~46)원 추가.

60,61)BindAction 점프와 같이 일회성 이벤트를 발생시키는 것
BindAxis 회전 등 두 말단 사이의 값이 지속적으로 전달되는 이벤트를 발생시킨다.

76~96)추가

79, 80) CollectionSphere와 오버랩되는 모든 액터를 배열로 받아옴

82~)월드에 놓이게되면 자동으로 오버랩 시작/끝,  이벤트가 시작되서 일어나는 모든 액터를 기록하게 된다.

85) 오버랩되는 액터중 연관있는 액터만 형변환으로 걸러낸다.

89~91) 해당아이템의 wasCollected 함수를 호출한다

 

BatteryCollectorCharacter.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
64
65
66
67
68
69
70
71
72
73
74
75
76
// Copyright 1998-2015 Epic Games, Inc. All Rights Reserved.
#pragma once
#include "GameFramework/Character.h"
#include "BatteryCollectorCharacter.generated.h"
 
UCLASS(config=Game)
class ABatteryCollectorCharacter : public ACharacter
{
    GENERATED_BODY()
 
    /** Camera boom positioning the camera behind the character */
    UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Camera, meta = (AllowPrivateAccess = "true"))
    class USpringArmComponent* CameraBoom;
 
    /** Follow camera */
    UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Camera, meta = (AllowPrivateAccess = "true"))
    class UCameraComponent* FollowCamera;
 
    /** Collection sphere */
    UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Camera, meta = (AllowPrivateAccess = "true"))
    class USphereComponent* CollectionSphere;
public:
    ABatteryCollectorCharacter();
 
    /** Base turn rate, in deg/sec. Other scaling may affect final turn rate. */
    UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category=Camera)
    float BaseTurnRate;
 
    /** Base look up/down rate, in deg/sec. Other scaling may affect final rate. */
    UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category=Camera)
    float BaseLookUpRate;
 
protected:
 
    /** Called for forwards/backward input */
    void MoveForward(float Value);
 
    /** Called for side to side input */
    void MoveRight(float Value);
 
    /** 
     * Called via input to turn at a given rate. 
     * @param Rate    This is a normalized rate, i.e. 1.0 means 100% of desired turn rate
     */
    void TurnAtRate(float Rate);
 
    /**
     * Called via input to turn look up/down at a given rate. 
     * @param Rate    This is a normalized rate, i.e. 1.0 means 100% of desired turn rate
     */
    void LookUpAtRate(float Rate);
 
    /** Handler for when a touch input begins. */
    void TouchStarted(ETouchIndex::Type FingerIndex, FVector Location);
 
    /** Handler for when a touch input stops. */
    void TouchStopped(ETouchIndex::Type FingerIndex, FVector Location);
 
protected:
    // APawn interface
    virtual void SetupPlayerInputComponent(class UInputComponent* InputComponent) override;
    // End of APawn interface
    /*CAlled when we press a key to collect any pickups inside the CollectionSphere*/
    UFUNCTION(BlueprintCallable, Category = "Pickups")
    void CollectPickups();
 
public:
    /** Returns CameraBoom subobject **/
    FORCEINLINE class USpringArmComponent* GetCameraBoom() const { return CameraBoom; }
    /** Returns FollowCamera subobject **/
    FORCEINLINE class UCameraComponent* GetFollowCamera() const { return FollowCamera; }
    /**return collectionsphere subobject*/
    FORCEINLINE class USphereComponent* GetCollectionSphere() const { return CollectionSphere; }
};
 
 
cs