-
컴포넌트와 콜리전게임/UnReal_MakeMyGameStudy 2021. 5. 2. 19:02
컴포넌트를 만들어 계층구조에 넣고 게임플레이 도중 제어하는 법과, 컴포넌트를 사용하여 폰이 입체 오브젝트로 된 월드를 돌아다니도록 만드는 법
-> 플레이어가 캐릭터를 움직이고, 특정 키를 누르면, 어떤 액션을 취할 수 있다.
그러기 위해서는 필요한 것:
- 캐릭터
- 캐릭터의 물리 함수성질
캐릭터
CoreMinimal
CoreMinimal.h
// Fill out your copyright notice in the Description page of Project Settings. #pragma once #include "CoreMinimal.h" #include "GameFramework/Pawn.h" #include "CollidingPawn.generated.h" UCLASS() class HOWTO_AUTOCAMERA_API ACollidingPawn : public APawn { GENERATED_BODY() public: // Sets default values for this pawn's properties ACollidingPawn(); // Particle System 컴포넌트의 기록을 유지하도록 한다. // 코드에서 그 컴포넌트 를 사용하려면, 이렇게 클래스 멤버 변수에 저장해야 합니다. UParticleSystemComponent* OurParticleSystem; //우리 커스텀 Pawn Movement Component 를 사용하기 위해서는 먼저 //그에 대한 기록을 유지할 변수를 Pawn 클래스에 추가해 줘야 합니다. class UCollidingPawnMovementComponent* OurMovementComponent; // Pawn 에는 "GetMovementComponent" 라는 함수가 있는데, // 엔진의 다른 클래스가 현재 Pawn 이 사용중인 Pawn Movement Component 에 접근할 수 있도록 하는 데 사용됩니다. virtual UPawnMovementComponent* GetMovementComponent() const override; protected: // Called when the game starts or when spawned virtual void BeginPlay() override; public: // Called every frame virtual void Tick(float DeltaTime) override; // Called to bind functionality to input virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override; // 새로운 Pawn Movement Component 구성이 완료되었으니, 우리 Pawn 이 받을 입력 처리를 위한 코드를 만들면 되겠습니다. void MoveForward(float AxisValue); void MoveRight(float AxisValue); void Turn(float AxisValue); void ParticleToggle(); };
CollidingPawn.cpp
// Fill out your copyright notice in the Description page of Project Settings. /* 물리 월드와의 상호작용을 위한 Sphere 컴포넌트, 콜리전 모양을 시각적으로 나타내 줄 Static Mesh 컴포넌트, 마음대로 켜고 끌 수 있는 Particle System 컴포넌트, 게임내 시점 제어를 위해 Camera 컴포넌트에 붙일 Spring Arm 컴포넌트를 만들겠습니다. */ //액터 에는 계층구조 내 다수의 물리 기반 컴포넌트 가 있을 수 있다. //But. 여기서는 하나면 된다. #include "CollidingPawn.h" #include "Components/SphereComponent.h" #include "Particles/ParticleSystemComponent.h" #include "GameFramework/SpringArmComponent.h" #include "CollidingPawnMovementComponent.h" #include "camera/CameraComponent.h" // Sets default values //여러가지 유용한 컴포넌트 를 스폰시킬 코드를 추가하고, 계층구조로 배치합니다. ACollidingPawn::ACollidingPawn() { // Set this pawn to call Tick() every frame. You can turn this off to improve performance if you don't need it. PrimaryActorTick.bCanEverTick = true; //Share 컴포포넌트 //물리적 실존이 있고 게임 월드와의 상호작용 및 충돌이 가능하다. //루트 컴포넌트는 물리에 반응하는 구체가 됩니다. //->InitSphereRadius(): 렌더 또는 물리학 업데이트를 트리거하지 않고 구 반지름을 설정합니다. USphereComponent* SphereComponent = CreateDefaultSubobject<USphereComponent>(TEXT("RootComponent")); RootComponent = SphereComponent; SphereComponent->InitSphereRadius(40.0f); SphereComponent->SetCollisionProfileName(TEXT("Pawn")); // 구체가 어딨는지 확인할 수 있도록 메시 컴포넌트 생성 및 위치 조정 // 반경이 50 인 스태틱 메시 애셋에서 눈에 보이는 구체를 만들어 붙여줍니다. // 방금 만든 반경 40 의 Sphere 컴포넌트와 완전히 맞아떨어지지 않으므로, 스케일을 80% 로 줄여줍니다. // 중심도 맞춰주려면 40 유닛 아래로 내려주기도 해야 합니다. UStaticMeshComponent* SphereVisual = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("VisualRepresentation")); SphereVisual->SetupAttachment(RootComponent); static ConstructorHelpers::FObjectFinder<UStaticMesh> SphereVisualAsset(TEXT("/Game/StarterContent/Shapes/Shape_Sphere.Shape_Sphere")); if (SphereVisualAsset.Succeeded()) { SphereVisual->SetStaticMesh(SphereVisualAsset.Object); SphereVisual->SetRelativeLocation(FVector(0.0f, 0.0f, -40.0f)); SphereVisual->SetWorldScale3D(FVector(0.8f)); } // 계층구조에 비활성 Particle System 컴포넌트를 붙일 수 있다. // 이 컴포넌트는 코드로 조작할 수 있으며, 나중에 켜고 끄는 입력 구성을 할것이다. // Particle System 컴포넌트는 루트가 아닌 Static Mesh 컴포넌트에 붙어 있다. // 활성화 또는 비활성화시킬 수 있는 파티클 시스템 생성 OurParticleSystem = CreateDefaultSubobject<UParticleSystemComponent>(TEXT("MovementParticles")); OurParticleSystem->SetupAttachment(SphereVisual); OurParticleSystem->bAutoActivate = false; OurParticleSystem->SetRelativeLocation(FVector(-20.0f, 0.0f, 20.0f)); static ConstructorHelpers::FObjectFinder<UParticleSystem> ParticleAsset(TEXT("/Game/StarterContent/Particles/P_Fire.P_Fire")); if (ParticleAsset.Succeeded()) { OurParticleSystem->SetTemplate(ParticleAsset.Object); } // Spring Arm 컴포넌트는 폰 보다 느린 가속 / 감속을 따라다니는 카메라에 적용시킬 수 있다 // 카메라의 부드러운 부착점이 됩니다. // 스프링 암을 사용하여 카메라에 부드럽고 자연스러운 모션을 적용합니다. USpringArmComponent* SpringArm = CreateDefaultSubobject<USpringArmComponent>(TEXT("CameraAttachmentArm")); SpringArm->SetupAttachment(RootComponent); SpringArm->SetRelativeRotation(FRotator(-45.0f, 0.0f, 0.0f)); SpringArm->TargetArmLength = 400.0f; SpringArm->bEnableCameraLag = true; SpringArm->CameraLagSpeed = 3.0f; // 카메라를 만들어 스프링 암에 붙입니다. UCameraComponent* Camera = CreateDefaultSubobject<UCameraComponent>(TEXT("ActualCamera")); Camera->SetupAttachment(SpringArm, USpringArmComponent::SocketName); AutoPossessPlayer = EAutoReceiveInput::Player0; // 무브먼트 컴포넌트 인스턴스를 생성하고, 루트를 업데이트하라 이릅니다. OurMovementComponent = CreateDefaultSubobject<UCollidingPawnMovementComponent>(TEXT("CustomMovementComponent")); OurMovementComponent->UpdatedComponent = RootComponent; } // Called when the game starts or when spawned void ACollidingPawn::BeginPlay() { Super::BeginPlay(); } // Called every frame void ACollidingPawn::Tick(float DeltaTime) { Super::Tick(DeltaTime); } // Called to bind functionality to input void ACollidingPawn::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent) { Super::SetupPlayerInputComponent(PlayerInputComponent); //우리 함수를 입력 이벤트에 묶는 것 뿐입니다. InputComponent->BindAction("ParticleToggle", IE_Pressed, this, &ACollidingPawn::ParticleToggle); InputComponent->BindAxis("MoveForward", this, &ACollidingPawn::MoveForward); InputComponent->BindAxis("MoveRight", this, &ACollidingPawn::MoveRight); InputComponent->BindAxis("Turn", this, &ACollidingPawn::Turn); } UPawnMovementComponent* ACollidingPawn::GetMovementComponent() const { return OurMovementComponent; } void ACollidingPawn::MoveForward(float AxisValue) { if (OurMovementComponent && (OurMovementComponent->UpdatedComponent == RootComponent)) { OurMovementComponent->AddInputVector(GetActorForwardVector() * AxisValue); } } void ACollidingPawn::MoveRight(float AxisValue) { if (OurMovementComponent && (OurMovementComponent->UpdatedComponent == RootComponent)) { OurMovementComponent->AddInputVector(GetActorRightVector() * AxisValue); } } void ACollidingPawn::Turn(float AxisValue) { FRotator NewRotation = GetActorRotation(); NewRotation.Yaw += AxisValue; SetActorRotation(NewRotation); } void ACollidingPawn::ParticleToggle() { if (OurParticleSystem && OurParticleSystem->Template) { OurParticleSystem->ToggleActive(); } }
CollidingPawnMovementComponent
CollidingPawnMovementComponent.h
// Fill out your copyright notice in the Description page of Project Settings. #pragma once #include "CoreMinimal.h" #include "GameFramework/PawnMovementComponent.h" #include "CollidingPawnMovementComponent.generated.h" /** * */ UCLASS() class HOWTO_AUTOCAMERA_API UCollidingPawnMovementComponent : public UPawnMovementComponent { GENERATED_BODY() // TickComponent 함수로 각 프레임 어떻게 이동할지를 알려줘야 한다. public: virtual void TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override; };
CollidingPawnMovementComponent.cpp
// Fill out your copyright notice in the Description page of Project Settings. #include "CollidingPawnMovementComponent.h" /* 적합한 면을 미끄러져 다니며 월드를 부드럽게 움직이도록 폰 을 이동시킵니다. 폰 에는 중력이 적용되지 않으며, 최대 속력은 초당 150 언리얼 유닛 으로 하드코딩되어 있습니다. */ //이 TickComponent 함수는 UPawnMovementComponent 클래스에 제공되는 강력한 기능을 몇 가지 활용하고 있습니다. void UCollidingPawnMovementComponent::TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) { Super::TickComponent(DeltaTime, TickType, ThisTickFunction); // 모든 것이 아직 유효한지, 이동 가능한지 확인합니다. if (!PawnOwner || !UpdatedComponent || ShouldSkipUpdate(DeltaTime)) { return; } /* Pawn Movement Components 에는 설명할 만한 기능이 더 있지만, 이 튜토리얼 범위에는 필요치 않습니다. Floating Pawn Movement, Spectator Pawn Movement, Character Movement Component 같은 다른 클래스를 살펴보면 추가적인 용례나 개념을 찾아볼 수 있습니다. */ // ACollidingPawn::Tick 에 설정한 무브먼트 벡터를 구(한 뒤 소거)합니다. // ConsumeInputVector 는 미동 입력을 저장하는 데 사용할 내장 변수 값을 보고 및 소거합니다. FVector DesiredMovementThisFrame = ConsumeInputVector().GetClampedToMaxSize(1.0f) * DeltaTime * 150.0f; if (!DesiredMovementThisFrame.IsNearlyZero()) { FHitResult Hit; // SafeMoveUpdatedComponent 는 언리얼 엔진 피직스를 사용하여 입체 장애물을 피해 Pawn Movement Component 를 이동시킵니다. SafeMoveUpdatedComponent(DesiredMovementThisFrame, UpdatedComponent->GetComponentRotation(), true, Hit); // 무언가에 부딛혔으면, 돌아가 봅니다. if (Hit.IsValidBlockingHit()) { // SlideAlongSurface는 이동하다가 충돌 발생시 그냥 제자리에 멈춰 벽이나 경사로에 "달라붙기" 보다는, // 그 표면을 타고 부드럽게 미끄러지도록 하는 데 관련된 물리 계산 처리를 합니다. SlideAlongSurface(DesiredMovementThisFrame, 1.f - Hit.Time, Hit.Normal, Hit); } } };
응용
-> 플레이어 조작을 통해서 대쉬, 이동 점프를 할 수 있다.
'게임 > UnReal_MakeMyGameStudy' 카테고리의 다른 글
일인칭 슈팅 C++ 튜토리얼 (0) 2021.05.07 게임 조종 카메라 (0) 2021.05.01 출발!! (0) 2021.05.01