Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
Tags
- 파이썬서버
- 레베카
- Ajax
- 으
- 언리얼뮤지컬
- Unseen
- 정글사관학교
- Bootstrap4
- 프메
- 데이터베이스
- 알고풀자
- 카렌
- R
- 스마일게이트
- 언리얼
- JWT
- VUE
- 마인크래프트뮤지컬
- 스터디
- 프린세스메이커
- Enhanced Input System
- 언리얼프로그래머
- Express
- 디자드
- 게임개발
- node
- EnhancedInput
- Jinja2
- flask
- 미니프로젝트
Archives
- Today
- Total
Showing
[Unreal] Line Trace를 이용하여 3D Player에서 NPC로의 시점 전환 본문
3D 게임 상에서 플레이어가 NPC 혹은 상점에 닿으면 NPC의 시점으로 전환되는 연출을 종종 본 적이 있을 것이다.
Npc 혹은 상점에 다다가면, 화면이 전환되는 연출.
key point
-NPC도 카메라 소유
-NPC에게 트리거 박스 설치
-트리거 박스에 닿으면 플레이어 컨트롤러의 view를 NPC의 view로 switch
따라서 NPC를 따로 제작해주면 아래와 같다.
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Character.h"
#include "NPC.generated.h"
class UboxComponent;
UCLASS()
class THIRDPERSONTEMPLATE_API ANPC : public ACharacter
{
GENERATED_BODY()
public:
// Sets default values for this character's properties
ANPC();
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;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Camera")
class UCameraComponent* CameraComp;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Interaction")
class UBoxComponent* triggerBox;
UFUNCTION()
void OnOverlapBeginTB(class UPrimitiveComponent* OverlappedComponent, class AActor* OtherActor, class UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult);
};
// Fill out your copyright notice in the Description page of Project Settings.
#include "NPC.h"
#include "Camera/CameraComponent.h"
#include "Components/BoxComponent.h"
#include <Kismet/GameplayStatics.h>
// Sets default values
ANPC::ANPC()
{
// Set this character to call Tick() every frame. You can turn this off to improve performance if you don't need it.
PrimaryActorTick.bCanEverTick = true;
CameraComp = CreateDefaultSubobject<UCameraComponent>(TEXT("ZoomCamera"));
CameraComp->SetupAttachment(GetRootComponent());
triggerBox = CreateDefaultSubobject<UBoxComponent>(TEXT("trigger Box"));
triggerBox->SetupAttachment(GetRootComponent());
}
// Called when the game starts or when spawned
void ANPC::BeginPlay()
{
Super::BeginPlay();
triggerBox->OnComponentBeginOverlap.AddDynamic(this, &ANPC::OnOverlapBeginTB);
}
// Called every frame
void ANPC::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
}
// Called to bind functionality to input
void ANPC::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
Super::SetupPlayerInputComponent(PlayerInputComponent);
}
void ANPC::OnOverlapBeginTB(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult)
{
if (GEngine) {
GEngine->AddOnScreenDebugMessage(-1, 0.5f, FColor::Yellow, TEXT("Debug"));
}
APlayerController* OurPlayerController = UGameplayStatics::GetPlayerController(this, 0);
OurPlayerController->SetViewTargetWithBlend(this, 1.f);
OurPlayerController->SetInputMode(FInputModeUIOnly());
OurPlayerController->SetShowMouseCursor(true);
}
BP에서 콜리전 세팅
bp_에서 카메라 rot값을 적절히 변경해준다.
기존 3D Player의 코드는 아래와 같다
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Character.h"
#include "InputAction.h"
#include "NiagaraComponent.h"
#include "NiagaraFunctionLibrary.h"
#include "MyPlayer.generated.h"
class UInputMappingContext;
class UInputAction;
class UNiagaraComponent;
UCLASS()
class THIRDPERSONTEMPLATE_API AMyPlayer : public ACharacter
{
GENERATED_BODY()
public:
// Sets default values for this character's properties
AMyPlayer();
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;
UPROPERTY(EditAnywhere, Category = "Anim")
UAnimMontage* attackMontage;
public:
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Camera")
class USpringArmComponent* springArmComp;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Camera")
class UCameraComponent* cameraComp;
UPROPERTY(EditAnywhere, Category = "Input")
UInputMappingContext* PlayerMappingContext;
UPROPERTY(VisibleAnywhere, Category = "Weapon")
class UStaticMeshComponent* staffMesh;
UPROPERTY(EditAnywhere, Category = "FX")
class UNiagaraComponent* jumpNiagara;
UPROPERTY(EditAnywhere, Category = "Input")
UInputAction* MoveIA;
UPROPERTY(EditAnywhere, Category = "Input")
UInputAction* LookUpIA;
UPROPERTY(EditAnywhere, Category = "Input")
UInputAction* TurnIA;
UPROPERTY(EditAnywhere, Category = "Input")
UInputAction* JumpIA;
UPROPERTY(EditAnywhere, Category = "Input")
UInputAction* FireIA;
UPROPERTY(EditAnywhere, Category = "Input")
UInputAction* InteractionIA;
public:
void Move(const FInputActionValue& Value);
void LookUp(const FInputActionValue& Value);
void Turn(const FInputActionValue& Value);
void InputJump(const FInputActionValue& Value);
void InputFire(const FInputActionValue& Value);
void InteractionPositive(const FInputActionValue& Value);
void Fire();
float fireTimerTime; // 타이머의 시간
bool fireReady; // 타이머 도달 여부
public:
UPROPERTY(EditAnywhere,BlueprintReadOnly, Category = "Status")
float maxHp;
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Status")
float currentHp;
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Status")
float maxMp;
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Status")
float currentMp;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Interaction")
float interactionDistance;
UPROPERTY(EditAnywhere, Category = "Move")
float moveSpeed;
UPROPERTY(EditAnywhere)
TSubclassOf<class APBullet> bulletFactory;
UPROPERTY(EditAnyWhere)
float fireCoolTime = 2.0f;
bool isJump = false;
private:
FVector moveDirection;
protected:
void FireCoolTimer(float cooltime, float deltaTime);
public:
void ShowFX(bool show);
};
// Fill out your copyright notice in the Description page of Project Settings.
#include "MyPlayer.h"
#include "Components/ArrowComponent.h"
#include "GameFramework/SpringArmComponent.h"
#include "Camera/CameraComponent.h"
#include "EnhancedInputSubsystems.h" //https://docs.unrealengine.com/5.0/en-US/enhanced-input-in-unreal-engine/
#include "EnhancedInputComponent.h" //https://docs.unrealengine.com/4.26/en-US/InteractiveExperiences/Input/EnhancedInput/
#include "PBullet.h"
#include "NiagaraComponent.h"
#include "NiagaraFunctionLibrary.h"
#include "GameFramework/CharacterMovementComponent.h"
#include "DrawDebugHelpers.h"
// Sets default values
AMyPlayer::AMyPlayer()
{
// Set this character to call Tick() every frame. You can turn this off to improve performance if you don't need it.
PrimaryActorTick.bCanEverTick = true;
//ConstructorHelpers 라는 유틸리티로 에셋 가져오기(찾기)
// InitMesh 굳이 이렇게 하기는 했으나 콘텐츠 브라우저에서 선택하는게 사실 더 좋음
ConstructorHelpers::FObjectFinder<USkeletalMesh> InitMesh(TEXT("/Script/Engine.SkeletalMesh'/Game/MyResouce/unitychan.unitychan'"));
if (InitMesh.Succeeded()) { // 제대로 오브젝트를 가져왔다면~
// GetMesh는 actor(근본)의 상속자인 character에서 제공!
GetMesh()->SetSkeletalMesh(InitMesh.Object);
GetMesh()->SetRelativeLocationAndRotation(
FVector(0, 0, -88)
, FRotator(0, -90, 0));
}
springArmComp = CreateDefaultSubobject<USpringArmComponent>(TEXT("SpringArmComp"));
springArmComp->SetupAttachment(RootComponent);
springArmComp->SetRelativeLocationAndRotation(FVector(0, 0, 50), FRotator(-20,0,0));
springArmComp->TargetArmLength = 530;
springArmComp->bUsePawnControlRotation = true;
//카메라도 생성 초기화
cameraComp = CreateDefaultSubobject<UCameraComponent>(TEXT("CameraComponent"));
cameraComp->SetupAttachment(springArmComp);
cameraComp->bUsePawnControlRotation = false;
//staff mesh
staffMesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("staff meshComp"));// 스태프 외관 컴포넌트 등록
// 두번째 인자 캐릭터 메쉬에 부착, FName이 문자열 속도가 빠름
staffMesh->SetupAttachment(GetMesh(), FName("Character1_RightHandSocket"));
//staffMesh->SetRelativeLocationAndRotation
//pawn이 들고 있음
bUseControllerRotationYaw = true;
moveSpeed = 100.0f;
maxHp = 100;
maxMp = 100;
currentHp = 50;
currentMp = 50;
fireTimerTime = 0;
fireCoolTime = 1.85f;
fireReady = true; // 발사 준비 On
}
// Called when the game starts or when spawned
void AMyPlayer::BeginPlay()
{
Super::BeginPlay();
if (APlayerController* PlayerController = Cast<APlayerController>(GetController()))
{
if (UEnhancedInputLocalPlayerSubsystem* Subsystem
= ULocalPlayer::GetSubsystem<UEnhancedInputLocalPlayerSubsystem>(PlayerController->GetLocalPlayer())) {
Subsystem->AddMappingContext(PlayerMappingContext, 0);
}
}
jumpNiagara = GetComponentByClass<UNiagaraComponent>();
jumpNiagara->SetVisibility(false);
}
// Called every frame
void AMyPlayer::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
if (fireReady == false) {
FireCoolTimer(fireCoolTime, DeltaTime);
}
const TArray<USceneComponent*>& AttachChildren = GetRootComponent()->GetAttachChildren();
const int32 Count = AttachChildren.Num();
// 이동방향을 컨트롤 방향 기준으로 변환
moveDirection = FTransform(GetControlRotation()).TransformVector(moveDirection);
/*
// 플레이어 이동 - 등속운동
FVector P0 = GetActorLocation();//현재 위치
FVector vt = moveDirection * moveSpeed * DeltaTime; //이동거리
FVector P = P0 + vt;
SetActorLocation(P);
*/
AddMovementInput(moveDirection);
// 방향 초기화
// 방향이 누적되지 않게
moveDirection = FVector::ZeroVector;
}
// Called to bind functionality to input
void AMyPlayer::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
Super::SetupPlayerInputComponent(PlayerInputComponent);
if (UEnhancedInputComponent* EnhancedInputComponent = CastChecked<UEnhancedInputComponent>(PlayerInputComponent)) {
EnhancedInputComponent->BindAction(MoveIA, ETriggerEvent::Triggered, this, &AMyPlayer::Move);
EnhancedInputComponent->BindAction(LookUpIA, ETriggerEvent::Triggered, this, &AMyPlayer::LookUp);
EnhancedInputComponent->BindAction(TurnIA, ETriggerEvent::Triggered, this, &AMyPlayer::Turn);
EnhancedInputComponent->BindAction(JumpIA, ETriggerEvent::Triggered, this, &AMyPlayer::InputJump);
EnhancedInputComponent->BindAction(FireIA, ETriggerEvent::Triggered, this, &AMyPlayer::InputFire);
EnhancedInputComponent->BindAction(InteractionIA, ETriggerEvent::Started, this, &AMyPlayer::InteractionPositive);
}
}
void AMyPlayer::Move(const FInputActionValue& Value)
{
UE_LOG(LogTemp, Log, TEXT("Log Message %f"), moveSpeed);
const FVector _currentValue = Value.Get<FVector>();
if (Controller) {
moveDirection.Y = _currentValue.X;
moveDirection.X = _currentValue.Y;
}
//FVector newLocation = GetActorLocation() + _currentValue;
//SetActorLocation(newLocation);
}
void AMyPlayer::LookUp(const FInputActionValue& Value)
{
// mouse y - 한 축의 값(float)
const float _currentValue = Value.Get<float>();
APawn::AddControllerPitchInput(_currentValue);
}
void AMyPlayer::Turn(const FInputActionValue& Value)
{
// mouse x - 한 축의 값(float)
const float _currentValue = Value.Get<float>();
APawn::AddControllerYawInput(_currentValue);
}
void AMyPlayer::InputJump(const FInputActionValue& Value)
{
Jump();
}
void AMyPlayer::InputFire(const FInputActionValue& Value)
{
if (fireReady == true) {
UAnimInstance* AnimInstance = GetMesh()->GetAnimInstance();
if (AnimInstance) {
AnimInstance->Montage_Play(attackMontage);
}
fireReady = false;
}
}
void AMyPlayer::InteractionPositive(const FInputActionValue& Value)
{
/*
//start와 end 가 중요
FVector _Location;
FRotator _Rotation;
FHitResult _HitOut;
//카메라가 보고 있는 위치
GetController()->GetPlayerViewPoint(_Location, _Rotation);
FVector _Start = _Location;
int ViewDis = 2000;
FVector _End = (_Rotation.Vector() * ViewDis); // 2000은 무작위 거리
FCollisionQueryParams _traceParams; //trace의 params들
GetWorld()->LineTraceSingleByChannel(_HitOut, _Start, _End, ECC_Visibility, _traceParams); // 충돌 결과, 시작점, 결과, 콜리전채널, params(안넣으면 디폴트)
DrawDebugLine(GetWorld(), _Start, _End, FColor::Green, false, 2.0f);
*/
FHitResult _HitOut;
FVector _Start = GetActorLocation();
FVector _End = GetActorLocation() + (GetActorForwardVector() * interactionDistance);
FCollisionQueryParams _TraceParams;
GetWorld()->LineTraceSingleByChannel(_HitOut, _Start, _End, ECC_Visibility, _TraceParams);
DrawDebugLine(GetWorld(), _Start, _End, FColor::Magenta, false, 3.0f);
}
void AMyPlayer::FireCoolTimer(float cooltime, float deltaTime)
{
if (fireTimerTime < cooltime) {
fireTimerTime += deltaTime;
}
else
{
fireTimerTime = 0;
fireReady = true;
}
}
void AMyPlayer::ShowFX(bool show)
{
if (nullptr == jumpNiagara) {
jumpNiagara = GetComponentByClass<UNiagaraComponent>();
}
jumpNiagara->SetVisibility(show);
}
void AMyPlayer::Fire()
{
FTransform firePosition = staffMesh->GetSocketTransform(TEXT("FirePosition"));
GetWorld()->SpawnActor<APBullet>(bulletFactory, firePosition);
}
'Unreal' 카테고리의 다른 글
[Unreal, VR] Custom VR Pawn Blueprint (1) | 2023.12.21 |
---|---|
[Unreal, VR] VR에서 Item grab(Hold) and Release를 위한 블루프린트 설정 (1) | 2023.12.18 |
[Unreal] Pawn과 Character, EnhancedInput vs InputSystem (0) | 2023.11.24 |
[Unreal] 플레이어 폰 세팅과 이동 애니메이션 (0) | 2023.11.24 |
[Unreal] 액터 C++ 클래스와 블루프린트 호환 및 컴포넌트의 이해 (1) | 2023.11.24 |