https://github.com/onPlex/SesacVR.git
BP_GrabItem Actor를 부모로 블루프린트 만듬. 인터페이스붙여줌
이벤트추가후 노드 작성
C++ 재구성
Charater 상속해서 AVRCharacter 작성
Character.h
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Character.h"
#include "VRCharacter.generated.h"
UCLASS()
class SESACVR_API AVRCharacter : public ACharacter
{
GENERATED_BODY()
public:
// Sets default values for this character's properties
AVRCharacter();
protected:
// Called when the game starts or when spawned
virtual void BeginPlay() override;
UPROPERTY(EditAnywhere, Category = "Controller")
class UMotionControllerComponent* LeftController;
UPROPERTY(EditAnywhere, Category = "Controller")
class UMotionControllerComponent* RightController;
public:
// Called every frame
virtual void Tick(float DeltaTime) override;
// Called to bind functionality to input
virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override;
};
Character.cpp
// Fill out your copyright notice in the Description page of Project Settings.
#include "VRCharacter.h"
#include <Components/CapsuleComponent.h>
#include "MotionControllerComponent.h"
#include "Components/InputComponent.h"
// Sets default values
AVRCharacter::AVRCharacter()
{
// 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;
LeftController = CreateDefaultSubobject<UMotionControllerComponent>(TEXT("LeftCon"));
LeftController->MotionSource = FName("Left");
RightController = CreateDefaultSubobject<UMotionControllerComponent>(TEXT("RightCon"));
RightController->MotionSource = FName("Left");
GetCapsuleComponent()->SetCapsuleSize(1.0f, 1.0f);
}
// Called when the game starts or when spawned
void AVRCharacter::BeginPlay()
{
Super::BeginPlay();
}
// Called every frame
void AVRCharacter::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
}
// Called to bind functionality to input
void AVRCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
Super::SetupPlayerInputComponent(PlayerInputComponent);
}
Build.cs에 EnhanceInput, HeadMountedDisplay 추가하고 VS ProjectFile 재생성하고 리빌드
// Fill out your copyright notice in the Description page of Project Settings.
using UnrealBuildTool;
public class SesacVR : ModuleRules
{
public SesacVR(ReadOnlyTargetRules Target) : base(Target)
{
PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs;
PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine",
"InputCore" , "EnhancedInput", "HeadMountedDisplay"});
PrivateDependencyModuleNames.AddRange(new string[] { });
일단은 이것저것 짜집기해서 움직이게는 만들었다.
VRCharacter.h
// 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 "VRCharacter.generated.h"
UCLASS()
class SESACVR_API AVRCharacter : public ACharacter
{
GENERATED_BODY()
public:
// Sets default values for this character's properties
AVRCharacter();
public:
UPROPERTY(VisibleAnywhere, Category = Camera)
class USpringArmComponent* springArmComp;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Camera)
class UCameraComponent* tpsCamComp;
protected:
// Called when the game starts or when spawned
virtual void BeginPlay() override;
// 좌측 모션 컨트롤러
UPROPERTY(EditAnywhere, Category = "VR")
class UMotionControllerComponent* LeftController;
// 우측 모션 컨트롤러
UPROPERTY(EditAnywhere, Category = "VR")
class UMotionControllerComponent* RightController;
// 좌측 모션 컨트롤러 메쉬
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "VR")
class USkeletalMeshComponent * LeftHand;
// 우측 모션 컨트롤러 메쉬
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "VR")
class USkeletalMeshComponent* RightHand;
public:
UPROPERTY(EditAnywhere, Category = "Input")
UInputMappingContext* PlayerMappingContext;
UPROPERTY(EditAnywhere, Category = "Input")
UInputAction* MoveIA;
UPROPERTY(EditAnywhere, Category = "Input")
UInputAction* LookUpIA;
UPROPERTY(EditAnywhere, Category = "Input")
UInputAction* JumpIA;
UPROPERTY(EditAnywhere, Category = "Input")
UInputAction* FireIA;
UPROPERTY(EditAnywhere, Category = "Input")
UInputAction* IA_1;
UPROPERTY(EditAnywhere, Category = "Input")
UInputAction* IA_2;
UPROPERTY(EditAnywhere, Category = "Input")
UInputAction* IA_Aim;
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); // 총알 발사 처리 함수
UFUNCTION(BlueprintCallable, Category = "Pawn")
virtual void MoveForward(float Val);
UFUNCTION(BlueprintCallable, Category = "Pawn")
virtual void MoveRight(float Val);
UFUNCTION(BlueprintCallable, Category = "Pawn")
virtual void MoveUp_World(float Val);
UFUNCTION(BlueprintCallable, Category = "Pawn")
virtual void TurnAtRate(float Rate);
UFUNCTION(BlueprintCallable, Category = "Pawn")
virtual void LookUpAtRate(float Rate);
/** Base turn rate, in deg/sec. Other scaling may affect final turn rate. */
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Pawn")
float BaseTurnRate;
/** Base lookup rate, in deg/sec. Other scaling may affect final lookup rate. */
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Pawn")
float BaseLookUpRate;
public:
// Called every frame
virtual void Tick(float DeltaTime) override;
// Called to bind functionality to input
virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override;
/** If true, adds default input bindings for movement and camera look. */
UPROPERTY(Category = Pawn, EditAnywhere, BlueprintReadOnly)
uint32 bAddDefaultMovementBindings : 1;
private:
void Locomotion();
FVector moveDirection;
bool fireReady;
float fireTimerTime;
};
VRCharacter.cpp
// Fill out your copyright notice in the Description page of Project Settings.
#include "VRCharacter.h"
#include "Components/InputComponent.h"
#include <Camera/CameraComponent.h>
#include <GameFramework/SpringArmComponent.h>
#include "EnhancedInputSubsystems.h"
#include "EnhancedInputComponent.h"
#include "MotionControllerComponent.h"
#include "Components/CapsuleComponent.h"
#include "Components/StaticMeshComponent.h"
#include "Components/SkeletalMeshComponent.h"
#include <Kismet/GameplayStatics.h>
#include "UObject/ConstructorHelpers.h"
// Sets default values
AVRCharacter::AVRCharacter()
{
// 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;
// 씬 루트 컴포넌트
//RootComponent = CreateDefaultSubobject<USceneComponent>(TEXT("RootComponent"));
// 좌측 모션 컨트롤러 초기화
LeftController = CreateDefaultSubobject<UMotionControllerComponent>(TEXT("LeftCon"));
LeftController->MotionSource = FName("Left");
//LeftController->Hand = EControllerHand::Left;
LeftController->SetupAttachment(RootComponent);
// 우측 모션 컨트롤러 초기화
RightController = CreateDefaultSubobject<UMotionControllerComponent>(TEXT("RightCon"));
LeftController->MotionSource = FName("Right");
//RightController->Hand = EControllerHand::Right;
RightController->SetupAttachment(RootComponent);
GetCapsuleComponent()->SetCapsuleSize(1.f, 1.f);
// 좌측 모션 컨트롤러 메쉬 초기화
LeftHand = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("LeftHand"));
LeftHand->SetupAttachment(LeftController);
static ConstructorHelpers::FObjectFinder<USkeletalMesh> LeftHandMesh(TEXT("/Game/Characters/MannequinsXR/Meshes/SKM_MannyXR_left.SKM_MannyXR_left"));
if (LeftHandMesh.Succeeded())
{
if(GEngine)
GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Yellow, TEXT("LeftHandMesh.Succedded"));
LeftHand->SetSkeletalMesh(LeftHandMesh.Object);
}
else {
if (GEngine)
GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Yellow, TEXT("LeftHandMesh.Succedded"));
}
//// 우측 모션 컨트롤러 메쉬 초기화
RightHand = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("RightHand"));
RightHand->SetupAttachment(RightController);
static ConstructorHelpers::FObjectFinder<USkeletalMesh> RightHandMesh(TEXT("/Game/Characters/MannequinsXR/Meshes/SKM_MannyXR_right.SKM_MannyXR_right"));
if (RightHandMesh.Succeeded())
{
if (GEngine)
GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Yellow, TEXT("RightHandMesh.Succedded()"));
RightHand->SetSkeletalMesh(RightHandMesh.Object);
}
else {
if (GEngine)
GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Yellow, TEXT("LeftHandMesh.Succedded"));
}
LeftHand->SetRelativeLocationAndRotation(FVector(0, -50, 0), FRotator(0, -90, 0));
RightHand->SetRelativeLocationAndRotation(FVector(0, 50, 0), FRotator(0, -90, 0));
// 3-1. SpringArm 컴포넌트 붙이기
springArmComp = CreateDefaultSubobject<USpringArmComponent>(TEXT("SpringArmComp"));
springArmComp->SetupAttachment(RootComponent);
springArmComp->SetRelativeLocation(FVector(0, 70, 90));
springArmComp->TargetArmLength = 400;
springArmComp->bUsePawnControlRotation = true;
// 3-2. Camera 컴포넌트 붙이기
tpsCamComp = CreateDefaultSubobject<UCameraComponent>(TEXT("TpsCamComp"));
tpsCamComp->SetupAttachment(springArmComp);
tpsCamComp->bUsePawnControlRotation = false;
bUseControllerRotationYaw = true;
// 2단 점프
JumpMaxCount = 2;
// 플레이어 빙의
AutoPossessPlayer = EAutoReceiveInput::Player0;
}
// Called when the game starts or when spawned
void AVRCharacter::BeginPlay()
{
Super::BeginPlay();
Super::BeginPlay();
if (APlayerController* PlayerController = Cast<APlayerController>(GetController()))
{
if (UEnhancedInputLocalPlayerSubsystem* Subsystem
= ULocalPlayer::GetSubsystem<UEnhancedInputLocalPlayerSubsystem>(PlayerController->GetLocalPlayer()))
{
Subsystem->AddMappingContext(PlayerMappingContext, 0);
}
}
}
// Called every frame
void AVRCharacter::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
Locomotion();
}
void InitializeDefaultPawnInputBindings()
{
static bool bBindingsAdded = false;
if (!bBindingsAdded)
{
if (GEngine)
GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Yellow, TEXT("InputBindings"));
bBindingsAdded = true;
UPlayerInput::AddEngineDefinedAxisMapping(FInputAxisKeyMapping("DefaultPawn_MoveForward", EKeys::W, 1.f));
UPlayerInput::AddEngineDefinedAxisMapping(FInputAxisKeyMapping("DefaultPawn_MoveForward", EKeys::S, -1.f));
UPlayerInput::AddEngineDefinedAxisMapping(FInputAxisKeyMapping("DefaultPawn_MoveForward", EKeys::Up, 1.f));
UPlayerInput::AddEngineDefinedAxisMapping(FInputAxisKeyMapping("DefaultPawn_MoveForward", EKeys::Down, -1.f));
UPlayerInput::AddEngineDefinedAxisMapping(FInputAxisKeyMapping("DefaultPawn_MoveForward", EKeys::Gamepad_LeftY, 1.f));
UPlayerInput::AddEngineDefinedAxisMapping(FInputAxisKeyMapping("DefaultPawn_MoveRight", EKeys::A, -1.f));
UPlayerInput::AddEngineDefinedAxisMapping(FInputAxisKeyMapping("DefaultPawn_MoveRight", EKeys::D, 1.f));
UPlayerInput::AddEngineDefinedAxisMapping(FInputAxisKeyMapping("DefaultPawn_MoveRight", EKeys::Gamepad_LeftX, 1.f));
// HACK: Android controller bindings in ini files seem to not work
// Direct overrides here some to work
#if !PLATFORM_ANDROID
UPlayerInput::AddEngineDefinedAxisMapping(FInputAxisKeyMapping("DefaultPawn_MoveUp", EKeys::Gamepad_LeftThumbstick, 1.f));
UPlayerInput::AddEngineDefinedAxisMapping(FInputAxisKeyMapping("DefaultPawn_MoveUp", EKeys::Gamepad_RightThumbstick, -1.f));
UPlayerInput::AddEngineDefinedAxisMapping(FInputAxisKeyMapping("DefaultPawn_MoveUp", EKeys::Gamepad_FaceButton_Bottom, 1.f));
UPlayerInput::AddEngineDefinedAxisMapping(FInputAxisKeyMapping("DefaultPawn_MoveUp", EKeys::LeftControl, -1.f));
UPlayerInput::AddEngineDefinedAxisMapping(FInputAxisKeyMapping("DefaultPawn_MoveUp", EKeys::SpaceBar, 1.f));
UPlayerInput::AddEngineDefinedAxisMapping(FInputAxisKeyMapping("DefaultPawn_MoveUp", EKeys::C, -1.f));
UPlayerInput::AddEngineDefinedAxisMapping(FInputAxisKeyMapping("DefaultPawn_MoveUp", EKeys::E, 1.f));
UPlayerInput::AddEngineDefinedAxisMapping(FInputAxisKeyMapping("DefaultPawn_MoveUp", EKeys::Q, -1.f));
#else
UPlayerInput::AddEngineDefinedAxisMapping(FInputAxisKeyMapping("DefaultPawn_MoveUp", EKeys::Gamepad_LeftTriggerAxis, -0.5f));
UPlayerInput::AddEngineDefinedAxisMapping(FInputAxisKeyMapping("DefaultPawn_MoveUp", EKeys::Gamepad_RightTriggerAxis, 0.5f));
#endif
UPlayerInput::AddEngineDefinedAxisMapping(FInputAxisKeyMapping("DefaultPawn_TurnRate", EKeys::Gamepad_RightX, 1.f));
UPlayerInput::AddEngineDefinedAxisMapping(FInputAxisKeyMapping("DefaultPawn_TurnRate", EKeys::Left, -1.f));
UPlayerInput::AddEngineDefinedAxisMapping(FInputAxisKeyMapping("DefaultPawn_TurnRate", EKeys::Right, 1.f));
UPlayerInput::AddEngineDefinedAxisMapping(FInputAxisKeyMapping("DefaultPawn_Turn", EKeys::MouseX, 1.f));
UPlayerInput::AddEngineDefinedAxisMapping(FInputAxisKeyMapping("DefaultPawn_LookUpRate", EKeys::Gamepad_RightY, 1.f));
UPlayerInput::AddEngineDefinedAxisMapping(FInputAxisKeyMapping("DefaultPawn_LookUp", EKeys::MouseY, -1.f));
}
}
// Called to bind functionality to input
void AVRCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
Super::SetupPlayerInputComponent(PlayerInputComponent);
check(PlayerInputComponent);
if (GEngine)
GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Yellow, TEXT("SetupInputComponent"));
if (UEnhancedInputComponent* EnhancedInputComponent = CastChecked<UEnhancedInputComponent>(PlayerInputComponent))
{
EnhancedInputComponent->BindAction(MoveIA, ETriggerEvent::Triggered, this, &AVRCharacter::Move);
EnhancedInputComponent->BindAction(LookUpIA, ETriggerEvent::Triggered, this, &AVRCharacter::LookUp);
EnhancedInputComponent->BindAction(JumpIA, ETriggerEvent::Triggered, this, &AVRCharacter::InputJump);
EnhancedInputComponent->BindAction(FireIA, ETriggerEvent::Triggered, this, &AVRCharacter::InputFire);
//EnhancedInputComponent->BindAction(IA_1, ETriggerEvent::Triggered, this, &AVRCharacter::ChangeToGrenadeGun);
//EnhancedInputComponent->BindAction(IA_2, ETriggerEvent::Triggered, this, &AVRCharacter::ChangeToSniperGun);
//EnhancedInputComponent->BindAction(IA_Aim, ETriggerEvent::Started, this, &AVRCharacter::SniperAim);
//EnhancedInputComponent->BindAction(IA_Aim, ETriggerEvent::Completed, this, &AVRCharacter::SniperAim);
}
//if (bAddDefaultMovementBindings)
//{
// InitializeDefaultPawnInputBindings();
// if (GEngine)
// GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Yellow, TEXT("SetupInputComponent"));
// PlayerInputComponent->BindAxis("DefaultPawn_MoveForward", this, &AVRCharacter::MoveForward);
// PlayerInputComponent->BindAxis("DefaultPawn_MoveRight", this, &AVRCharacter::MoveRight);
// PlayerInputComponent->BindAxis("DefaultPawn_MoveUp", this, &AVRCharacter::MoveUp_World);
// PlayerInputComponent->BindAxis("DefaultPawn_Turn", this, &AVRCharacter::AddControllerYawInput);
// PlayerInputComponent->BindAxis("DefaultPawn_TurnRate", this, &AVRCharacter::TurnAtRate);
// PlayerInputComponent->BindAxis("DefaultPawn_LookUp", this, &AVRCharacter::AddControllerPitchInput);
// PlayerInputComponent->BindAxis("DefaultPawn_LookUpRate", this, &AVRCharacter::LookUpAtRate);
//}
}
//void AVRCharacter::UpdateNavigationRelevance()
//{
// if (CollisionComponent)
// {
// CollisionComponent->SetCanEverAffectNavigation(bCanAffectNavigationGeneration);
// }
//}
void AVRCharacter::Locomotion()
{
moveDirection = FTransform(GetControlRotation()).TransformVector(moveDirection);
AddMovementInput(moveDirection);
moveDirection = FVector::ZeroVector; //ZeroVector; == FVector(0,0,0)
}
void AVRCharacter::Move(const FInputActionValue& Value)
{
const FVector _currentValue = Value.Get<FVector>();
//PRINT_LOG(TEXT("%f %f %f"), _currentValue.X, _currentValue.Y, _currentValue.Z);
if (GEngine)
GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Yellow, TEXT("Move"));
if (Controller)
{
moveDirection.Y = _currentValue.X;
moveDirection.X = _currentValue.Y;
}
}
void AVRCharacter::LookUp(const FInputActionValue& Value)
{
const FVector _currentValue = Value.Get<FVector>();
//PRINT_LOG(TEXT("%f %f %f"), _currentValue.X, _currentValue.Y, _currentValue.Z);
AddControllerPitchInput(_currentValue.Y);
AddControllerYawInput(_currentValue.X);
}
void AVRCharacter::InputJump(const FInputActionValue& Value)
{
Jump();
}
void AVRCharacter::InputFire(const FInputActionValue& Value)
{
}
void AVRCharacter::MoveRight(float Val)
{
if (Val != 0.f)
{
if (Controller)
{
FRotator const ControlSpaceRot = Controller->GetControlRotation();
// transform to world space and add it
AddMovementInput(FRotationMatrix(ControlSpaceRot).GetScaledAxis(EAxis::Y), Val);
}
}
}
void AVRCharacter::MoveForward(float Val)
{
if(GEngine)
GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Yellow, FString::Printf(TEXT("%f"),Val));
if (Val != 0.f)
{
if (Controller)
{
FRotator const ControlSpaceRot = Controller->GetControlRotation();
// transform to world space and add it
AddMovementInput(FRotationMatrix(ControlSpaceRot).GetScaledAxis(EAxis::X), Val);
}
}
}
void AVRCharacter::MoveUp_World(float Val)
{
if (Val != 0.f)
{
AddMovementInput(FVector::UpVector, Val);
}
}
void AVRCharacter::TurnAtRate(float Rate)
{
// calculate delta for this frame from the rate information
AddControllerYawInput(Rate * BaseTurnRate * GetWorld()->GetDeltaSeconds() * CustomTimeDilation);
}
void AVRCharacter::LookUpAtRate(float Rate)
{
// calculate delta for this frame from the rate information
AddControllerPitchInput(Rate * BaseLookUpRate * GetWorld()->GetDeltaSeconds() * CustomTimeDilation);
}
VRCharacter.h
'언리얼수업 > 언리얼' 카테고리의 다른 글
231218 Unreal VR Site (1) | 2023.12.18 |
---|---|
C++ Oculus Touch(Motion Controller)를 포함한 Pawn 생성하기 (0) | 2023.12.18 |
OPENXR (0) | 2023.12.15 |
231214 VR First (0) | 2023.12.14 |
프로그래밍패턴 (0) | 2023.12.13 |