ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 컴포넌트와 콜리전
    게임/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

    댓글

Designed by Tistory.