목차

     
     


     
     

    Line Trace

     

    01_Spawn
      C01_Properties.h .cpp
    C02_Mesh
    C02_Mesh_Sphere
    C02_Mesh_Cone
    C03_Spawner.h .cpp
    02_Profiler
      C01_Log.h .cpp
    C02_DrawDebug.h .cpp
    03_Collision
      C01_ActorOverlap.h .cpp
    C02_ComponentOverlap.h .cpp
    C03_OverlapAndHit.h .cpp 
    C04_Trigger.h .cpp
    C04_Light.h .cpp 
    C05_MultiTrigger.h .cpp 
    C05_FallingBox.h .cpp 
    C05_SpotLight.h .cpp 
    C06_EventTrigger.h .cpp 
    C06_Explosion.h .cpp 
    C07_Override.h .cpp 
    04_Trace
      C01_Trigger.h .cpp 
    C01_SphereTrace.h .cpp 
    C02_Cylinder.h .cpp
    C02_LineTrace.h .cpp
    C03_MultiTrace.h .cpp
    Utilities
      CHelpers.h
     
    CAnimInstance.h .cpp
    CGameMode.h .cpp
    CPlayer.h .cpp

     
    Actor 안에 Camera가 있으면 조정가능?
     
     
     


     
     

    Trace

     

    Line vs. Sweep
     
    Line
     
    Sweep

    • 충돌체의 모양 정의: Box, Sphere, Capsule 

     
    Multi일 때 Channel, Objects 차이가 생긴다 (Line과 Sweep 둘 다 해당).

    • Object는 블락(Block)만 체크한다.
    • Chanel은 첫번째 블락(Block)까지 체크한다. ex. 유리창 깨트리고 벽에 박힌다.

     


     

    Line Trace

     
    C02_LineTrace.h

    더보기
    #pragma once
    #include "CoreMinimal.h"
    #include "GameFramework/Actor.h"
    #include "C02_LineTrace.generated.h"
    
    DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FLineTraceResult, class AActor*, InActor, FLinearColor, InColor);
    
    UCLASS()
    class U2212_03_API AC02_LineTrace : public AActor
    {
    	GENERATED_BODY()
    	
    public:	
    	AC02_LineTrace();
    
    protected:
    	virtual void BeginPlay() override;
    
    public:	
    	virtual void Tick(float DeltaTime) override;
    
    private:
    	UFUNCTION()
    		void StartLaunch(class AActor* InActor, FLinearColor InColor);//Dynamic은 매개변수 이름이 똑같아야 한다.
    
    public:
    	UPROPERTY(BlueprintAssignable)
    		FLineTraceResult OnLineTraceResult;
    
    private:
    	TArray<class AC02_Cylinder*> Cylinders;
    };

     
     
    C02_LineTrace.cpp

    더보기
    #include "04_Trace/C02_LineTrace.h"
    #include "Global.h"
    #include "C02_Cylinder.h"
    #include "GameFramework/Character.h" //실제적으로 실행시켜주는 역할
    
    AC02_LineTrace::AC02_LineTrace()
    {
    	PrimaryActorTick.bCanEverTick = true;
    
    }
    
    void AC02_LineTrace::BeginPlay()
    {
    	Super::BeginPlay();
    
    	CHelpers::FindActors<AC02_Cylinder>(GetWorld(), Cylinders);
    
    	//Delegate 사용
    	OnLineTraceResult.AddDynamic(this, &AC02_LineTrace::StartLaunch);
    }
    
    void AC02_LineTrace::Tick(float DeltaTime)
    {
    	Super::Tick(DeltaTime);
    
    	FVector start = Cylinders[0]->GetActorLocation();
    	FVector end = Cylinders[1]->GetActorLocation();
    
    	//DrawDebugLIne
    	{
    		start.Z -= 20;
    		end.Z -= 20;
    
    		DrawDebugLine(GetWorld(), start, end, FColor::Blue);
    	}
    
    	//LineTrace
    	{
    		start.Z += 40;
    		end.Z += 40;
    
    		TArray<AActor*> ignores;
    		ignores.Add(Cylinders[0]);
    		ignores.Add(Cylinders[1]);
    
    		FHitResult hitResult;
    
    		UKismetSystemLibrary::LineTraceSingleByProfile(GetWorld(), start, end, "Pawn", false, ignores, EDrawDebugTrace::ForOneFrame, hitResult, true);
    
    		if(hitResult.bBlockingHit)
    		{
    			if (OnLineTraceResult.IsBound())
    				OnLineTraceResult.Broadcast(hitResult.GetActor(), FLinearColor::MakeRandomColor());
    		}
    
    	}
    }
    
    void AC02_LineTrace::StartLaunch(AActor* InActor, FLinearColor InColor)
    {
    	ACharacter* character = Cast<ACharacter>(InActor); //InActor를 Character로 캐스팅
    	CheckNull(character);//character==nullptr이면 return
    
    	character->LaunchCharacter(FVector(0, 0, 50), true, false);//Launch 오버라이드
    
    }

    ※ 참고 - LaunchCharcter 함수

    더보기
    void ACharacter::LaunchCharacter(FVector LaunchVelocity, bool bXYOverride, bool bZOverride)
    {
    	UE_LOG(LogCharacter, Verbose, TEXT("ACharacter::LaunchCharacter '%s' (%f,%f,%f)"), *GetName(), LaunchVelocity.X, LaunchVelocity.Y, LaunchVelocity.Z);
    
    	if (CharacterMovement)
    	{
    		FVector FinalVel = LaunchVelocity;
    		const FVector Velocity = GetVelocity();
    
    		if (!bXYOverride)
    		{
    			FinalVel.X += Velocity.X;
    			FinalVel.Y += Velocity.Y;
    		}
    		if (!bZOverride)
    		{
    			FinalVel.Z += Velocity.Z;
    		}
    
    		CharacterMovement->Launch(FinalVel);
    
    		OnLaunched(LaunchVelocity, bXYOverride, bZOverride);
    	}
    }

     
     
     
     
    BP_C02_LineTrace

    UPROPERTY(BlueprintAssignable)
    	FLineTraceResult OnLineTraceResult;

    UPROPERTY(BlueprintAssignable)는 Event Dispatcher를 만든다.
     
     
    https://docs.unrealengine.com/4.27/ko/ProgrammingAndScripting/Blueprints/TechnicalGuide/ExtendingBlueprints/

     

    블루프린트에 게임플레이 요소 노출시키기

    게임플레이 요소를 블루프린트에 노출시키는 게임플레이 프로그래머를 위한 기술 안내서입니다.

    docs.unrealengine.com

     


     

    실행화면

     

    • DrawDebugLine 선과 Capsule이 충돌하여 Launch가 발동한다.
    • 충돌 시 BP에서 만든 ChangePlayerColor가 실행되어 Player의 색이 바뀐다.  

     
     
     


     
     

    MultiTrace

     


     

     

    중요!!) Channel Trace와 Object Trace의 차이

     

    C=Channel, O=Object

    Channel첫 번째 블락까지 겹친 애들 다 체크한다.
    Object는 오브젝트 무시하고 블락(Block)만 체크한다.
     
    예시 상황) 총알이 날라와 유리창을 깨고 방 안의 벽에 박혔다.

    • Overlap - 유리창이 깨지는 효과를 구현할 수 있다.
    • Block - 총알이 벽에 박히는 것을 구현할 수 있다. 

     
    LineTraceMulti vs. LineTraceMultiForObjects

    //Channel
    UKismetSystemLibrary::LineTraceMulti(GetWorld(), start1, end1, ETraceTypeQuery::TraceTypeQuery1, false, ignores, EDrawDebugTrace::ForOneFrame, hitResults1, true);
    //Object
    UKismetSystemLibrary::LineTraceMultiForObjects(GetWorld(), start2, end2, types, false, ignores, EDrawDebugTrace::ForOneFrame, hitResults2, true);

     


     

     

    벽 배치

     

    겹친 연산(=Overlap 연산)
    블록 연산

     


     

    Multi Trace

     
    C03_MultiTrace.h

    더보기
    #pragma once
    #include "CoreMinimal.h"
    #include "GameFramework/Actor.h"
    #include "C03_MultiTrace.generated.h"
    
    UCLASS()
    class U2212_03_API AC03_MultiTrace : public AActor
    {
    	GENERATED_BODY()
    
    private:
    	UPROPERTY(VisibleAnywhere)
    		class USceneComponent* Root;
    
    	UPROPERTY(VisibleAnywhere)
    		class UTextRenderComponent* Text;
    	
    public:	
    	AC03_MultiTrace();
    
    protected:
    	virtual void BeginPlay() override;
    
    public:	
    	virtual void Tick(float DeltaTime) override;
    
    private:
    	float TotalTime;
    };

     
     
    C03_MultiTrace.cpp

    더보기
    #include "04_Trace/C03_MultiTrace.h"
    #include "Global.h"
    #include "Components/TextRenderComponent.h"
    
    AC03_MultiTrace::AC03_MultiTrace()
    {
    	PrimaryActorTick.bCanEverTick = true;
    
    	CHelpers::CreateComponent<USceneComponent>(this, &Root, "Root");
    
    	CreateTextRender();
    }
    
    void AC03_MultiTrace::BeginPlay()
    {
    	Super::BeginPlay();
    
    }
    
    void AC03_MultiTrace::Tick(float DeltaTime)
    {
    	Super::Tick(DeltaTime);
    
    	FVector start = GetActorLocation();
    	FVector start1 = FVector(start.X + 50, start.Y, start.Z);
    	FVector start2 = FVector(start.X - 50, start.Y, start.Z);
    
    	FVector end1 = start1 + GetActorForwardVector() * 600;
    	FVector end2 = start2 + GetActorForwardVector() * 600;
    
    	TArray<AActor*> ignores;
    	//Multi로 쏘니 hitResult가 여러개여서 배열로 만들어준다.
    	TArray<FHitResult> hitResults1; 
    	TArray<FHitResult> hitResults2;
    
    	//Channel
    	UKismetSystemLibrary::LineTraceMulti(GetWorld(), start1, end1, ETraceTypeQuery::TraceTypeQuery1, false, ignores, EDrawDebugTrace::ForOneFrame, hitResults1, true);
    
    	//Objects
    	TArray<TEnumAsByte<EObjectTypeQuery>> types;
    	types.Add(EObjectTypeQuery::ObjectTypeQuery1);
    
    	UKismetSystemLibrary::LineTraceMultiForObjects(GetWorld(), start2, end2, types, false, ignores, EDrawDebugTrace::ForOneFrame, hitResults2, true);
    
    	TotalTime += DeltaTime;
    	if(TotalTime >= 2.0f)
    	{
    		TotalTime = 0.0f;
    
    		CLog::Log(FString::Printf(L"-- Channel : %d", hitResults1.Num()));
    		for (const FHitResult& hitResult : hitResults1)
    		{
    			FString str = FString::Printf(L"Block : %d, %s", hitResult.bBlockingHit, *hitResult.GetActor()->GetName());
    			CLog::Log(str);
    		}
    
    		CLog::Log(FString::Printf(L"-- Objects : %d", hitResults2.Num()));
    		for (const FHitResult& hitResult : hitResults2)
    			CLog::Log(hitResult.GetActor()->GetName());
    	}
    
    }

     
     


     

    실행화면

     

     

    • Channel의 경우 맨 앞의 Overlap을 체크하고 뒤에 있는 Block을 연산한다. 하지만 그 뒤의 Block들은 연산하지 않는다.
    • 반면에 Object의 경우 맨 앞의 Overlap을 통과하고 뒤에 있는 Block은 모두 연산한다.  

     
     
     
     

    TPS 기본세팅

     

     
    Characters
      CAnimInstance.h .cpp
    CPlayer.h .cpp
    Utilities
      CHelpers.h
    CLog.h .cpp
    CGameMode.h .cpp
    Global.h

     
     


     

    프로젝트 세팅

     

     
     
     
     
    U2212_04.Build.cs

    using UnrealBuildTool;
    
    public class U2212_04 : ModuleRules
    {
    	public U2212_04(ReadOnlyTargetRules Target) : base(Target)
    	{
    		PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs;
    	
            PublicIncludePaths.Add(ModuleDirectory); //경로찾기!!
    
    		PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore" });
    
    		PrivateDependencyModuleNames.AddRange(new string[] {  });
    	}
    }

    PublicIncludePaths.Add(ModuleDirectory); 추가

    • 경로를 찾는데 필요한 코드이다.