티스토리 뷰
2D게임이나 3D 탑뷰에서 시야 범위를 표현 하기 위하여 구현하게 된 컴포넌트 입니다.
ProceduralMeshComponent 를 이용하였으며 실시간으로 Mesh를 생성하여 시야를 표현합니다.
간단히 범위, 각도, 트레이스될 장애물 값을 설정 하면 됩니다.
<Line of sight 설정 값>
<Line of sight 사용>
<LineOfSightComponent.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 | // Fill out your copyright notice in the Description page of Project Settings. #pragma once #include "CoreMinimal.h" #include "ProceduralMeshComponent.h" #include "Components/SceneComponent.h" #include "LineOfSightComponent.generated.h" struct FSightTraceInfo { bool Hit; FVector Point; float Dst; float Angle; FSightTraceInfo() {} FSightTraceInfo(bool InHit, FVector InPoint, float InDst, float InAngle) :Hit(InHit), Point(InPoint), Dst(InDst), Angle(InAngle) {} }; class UMaterialInterface; UCLASS( ClassGroup=(LineOfSight), meta=(BlueprintSpawnableComponent) ) class PROJECTA_API ULineOfSightComponent : public UProceduralMeshComponent { GENERATED_BODY() public: /** 디버그 유무 */ UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "LineOfSight") bool bDebugIsEnabled; /** 시야범위 */ UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "LineOfSight") float SightRadius; /** 시야각도 ( 0 ~ 360 ) */ UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "LineOfSight", meta = (UIMax = 360, UIMin = 0)) float SightAngle; /** 장애물 타겟 채널 */ UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "LineOfSight") TEnumAsByte<ETraceTypeQuery> ObstacleTraceType; /** 생성 Mesh 퀄리티 ( 버텍스 갯수 ) */ UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "LineOfSight|MeshInfo") float MeshQuality; UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "LineOfSight|MeshInfo") UMaterialInterface* Material; public: ULineOfSightComponent(); virtual void BeginPlay() override; virtual void TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override; private: UPROPERTY() TArray<FVector> Vertices; UPROPERTY() TArray<int32> Triangles; UPROPERTY() TArray<FVector> normals; UPROPERTY() TArray<FVector2D> UV0; UPROPERTY() TArray<FLinearColor> vertexColors; UPROPERTY() TArray<FProcMeshTangent> tangents; void DrawLineOfSight(); FSightTraceInfo GetSightTraceInfoInfo(float Angle); FVector DirectionFromAngle(float AngleInDegrees); }; | cs |
<LineOfSightComponent.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 | // Fill out your copyright notice in the Description page of Project Settings. #include "LineOfSightComponent.h" #include "ProceduralMeshComponent.h" #include "Kismet/KismetSystemLibrary.h" ULineOfSightComponent::ULineOfSightComponent() { PrimaryComponentTick.bCanEverTick = true; SightRadius = 500.0f; SightAngle = 90.0f; MeshQuality = 5.0f; CastShadow = false; } void ULineOfSightComponent::BeginPlay() { Super::BeginPlay(); if ( Material ) { SetMaterial(0, Material); } } void ULineOfSightComponent::TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) { Super::TickComponent(DeltaTime, TickType, ThisTickFunction); DrawLineOfSight(); } void ULineOfSightComponent::DrawLineOfSight() { /** * MeshQuality 값이 클수록 많이 폴리곤을 그리기 위하여 SightAngle값에 MeshQuality를 곱한 값을 * SightAngle값으로 나누어 최소 AngleSize 를 구한다. * 현재 컴포넌트의 Yaw(Z축) 값을 기준으로 좌측 부터 우측 까지 최소 AngleSize 만큼 더해가면서 장애물을 Trace 하여 * 버텍스 위치값을 설정한다 */ int32 AnglePieceCount = FMath::RoundToInt(SightAngle * MeshQuality); float DivideAngleSize = SightAngle / AnglePieceCount; TArray<FVector> ViewPoints; for (int32 index = 0; index <= AnglePieceCount; ++index) { FRotator ViewRotation = GetComponentRotation(); float Angle = ViewRotation.Yaw - (SightAngle / 2.0f) + (DivideAngleSize * index); FSightTraceInfo SightTraceInfo = GetSightTraceInfoInfo(Angle); ViewPoints.Add(SightTraceInfo.Point); } int32 VertextCount = ViewPoints.Num() + 1; Vertices.SetNum(VertextCount); int32 TriangleCount = (VertextCount - 2) * 3; Triangles.SetNum(TriangleCount); Vertices[0] = FVector::ZeroVector; for (int32 index = 0; index < VertextCount - 1; ++index) { //버텍스 월드좌표를 컴포넌트의 로컬좌표로 변경 Vertices[index + 1] = GetComponentTransform().InverseTransformPosition(ViewPoints[index]); //인덱스 버퍼 설정 if (index < VertextCount - 2) { Triangles[index * 3 + 2] = 0; Triangles[index * 3 + 1] = index + 1; Triangles[index * 3 ] = index + 2; } } CreateMeshSection_LinearColor(0, Vertices, Triangles,normals, UV0, vertexColors, tangents, false); } FSightTraceInfo ULineOfSightComponent::GetSightTraceInfoInfo(float Angle) { EDrawDebugTrace::Type DrawDebugType = bDebugIsEnabled ? EDrawDebugTrace::ForDuration : EDrawDebugTrace::None; //Angle 값으로 x축 y축 방향을 구한다 FVector Dir = DirectionFromAngle(Angle); FHitResult OutHit; FVector Start = GetComponentLocation(); FVector End = (Dir*SightRadius) + Start; TArray<AActor*> ActorsToIgnore; if(UKismetSystemLibrary::LineTraceSingle(this,Start,End, ObstacleTraceType,false, ActorsToIgnore, DrawDebugType, OutHit, true)) { return FSightTraceInfo(true, OutHit.ImpactPoint, OutHit.Distance, Angle); } else { return FSightTraceInfo(false, End, SightRadius, Angle); } } FVector ULineOfSightComponent::DirectionFromAngle(float AngleInDegrees) { return FVector(FMath::Cos(FMath::DegreesToRadians(AngleInDegrees)), FMath::Sin(FMath::DegreesToRadians(AngleInDegrees)), 0.0f); } | cs |
'프로그래밍 > Unreal Engine4' 카테고리의 다른 글
고스트 트레일 효과 (c++ /애님블루프린트) (0) | 2019.01.28 |
---|---|
파라곤 Anim Distance Matching (0) | 2018.10.22 |
VIVE (SteamVR) Load Streaming Level 문제 (0) | 2018.10.22 |
GENERATED_BODY , GENERATED_UCLASS_BODY 매크로 (0) | 2018.07.10 |
파라곤 이동 중지,시작거리 예측 (0) | 2018.05.16 |