Init
This commit is contained in:
371
Source/FireworkDuels/FireworksPawn.cpp
Normal file
371
Source/FireworkDuels/FireworksPawn.cpp
Normal file
@@ -0,0 +1,371 @@
|
||||
// Fill out your copyright notice in the Description page of Project Settings.
|
||||
|
||||
|
||||
#include "FireworksPawn.h"
|
||||
|
||||
// Sets default values
|
||||
AFireworksPawn::AFireworksPawn()
|
||||
{
|
||||
// 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;
|
||||
|
||||
PawnRoot = CreateDefaultSubobject<USceneComponent>(TEXT("Root"));
|
||||
RootComponent = PawnRoot;
|
||||
CameraRoot = CreateDefaultSubobject<USceneComponent>(TEXT("Camera Root"));
|
||||
CameraRoot->SetupAttachment(PawnRoot);
|
||||
VRCamera = CreateDefaultSubobject<UCameraComponent>(TEXT("VR Camera"));
|
||||
VRCamera->SetupAttachment(CameraRoot);
|
||||
|
||||
MotionControllerR = CreateDefaultSubobject<UMotionControllerComponent>(TEXT("MotionControllerR"));
|
||||
MotionControllerR->SetupAttachment(PawnRoot);
|
||||
MotionControllerR->MotionSource = FName(TEXT("Right"));
|
||||
MotionControllerL = CreateDefaultSubobject<UMotionControllerComponent>(TEXT("MotionControllerL"));
|
||||
MotionControllerL->SetupAttachment(PawnRoot);
|
||||
MotionControllerL->MotionSource = FName(TEXT("Left"));
|
||||
|
||||
LeftHandMesh = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("LeftHandMesh"));
|
||||
LeftHandMesh->SetupAttachment(MotionControllerL);
|
||||
RightHandMesh = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("RightHandMesh"));
|
||||
RightHandMesh->SetupAttachment(MotionControllerR);
|
||||
|
||||
RightHandCollision = CreateDefaultSubobject<USphereComponent>(TEXT("RightHandCollision"));
|
||||
RightHandCollision->SetupAttachment(RightHandMesh);
|
||||
RightHandCollision->SetSphereRadius(10.0f, false);
|
||||
LeftHandCollision = CreateDefaultSubobject<USphereComponent>(TEXT("LeftHandCollision"));
|
||||
LeftHandCollision->SetupAttachment(LeftHandMesh);
|
||||
LeftHandCollision->SetSphereRadius(10.0f, false);
|
||||
|
||||
WidgetInteractionL = CreateDefaultSubobject<UWidgetInteractionComponent>(TEXT("WidgetInteraction_L"));
|
||||
WidgetInteractionL->SetupAttachment(LeftHandMesh);
|
||||
WidgetInteractionR = CreateDefaultSubobject<UWidgetInteractionComponent>(TEXT("WidgetInteraction_R"));
|
||||
WidgetInteractionR->SetupAttachment(RightHandMesh);
|
||||
|
||||
LaserL = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("LaserL"));
|
||||
LaserL->SetupAttachment(WidgetInteractionL);
|
||||
LaserR = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("LaserR"));
|
||||
LaserR->SetupAttachment(WidgetInteractionR);
|
||||
|
||||
}
|
||||
|
||||
// Sample Hand Velocities for throw approximation
|
||||
void AFireworksPawn::SampleHandVelocities()
|
||||
{
|
||||
// Left hand
|
||||
if (IsGrabbingL)
|
||||
{
|
||||
VelocitySamples_L.Add(LeftHandCollision->GetPhysicsLinearVelocity());
|
||||
if (VelocitySamples_L.Num() > VelocitySamples)
|
||||
{
|
||||
VelocitySamples_L.RemoveAt(0, 1, true);
|
||||
}
|
||||
}
|
||||
|
||||
// Right hand
|
||||
if (IsGrabbingR)
|
||||
{
|
||||
VelocitySamples_R.Add(RightHandCollision->GetPhysicsLinearVelocity());
|
||||
if (VelocitySamples_R.Num() > VelocitySamples)
|
||||
{
|
||||
VelocitySamples_R.RemoveAt(0, 1, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Called when the game starts or when spawned
|
||||
void AFireworksPawn::BeginPlay()
|
||||
{
|
||||
Super::BeginPlay();
|
||||
|
||||
CameraRoot->AttachToComponent(PawnRoot, FAttachmentTransformRules::KeepRelativeTransform);
|
||||
VRCamera->AttachToComponent(CameraRoot, FAttachmentTransformRules::KeepRelativeTransform);
|
||||
MotionControllerR->AttachToComponent(PawnRoot, FAttachmentTransformRules::KeepRelativeTransform);
|
||||
MotionControllerL->AttachToComponent(PawnRoot, FAttachmentTransformRules::KeepRelativeTransform);
|
||||
LeftHandMesh->AttachToComponent(MotionControllerL, FAttachmentTransformRules::KeepRelativeTransform);
|
||||
RightHandMesh->AttachToComponent(MotionControllerR, FAttachmentTransformRules::KeepRelativeTransform);
|
||||
RightHandCollision->AttachToComponent(RightHandMesh, FAttachmentTransformRules::SnapToTargetNotIncludingScale);
|
||||
LeftHandCollision->AttachToComponent(LeftHandMesh, FAttachmentTransformRules::SnapToTargetNotIncludingScale);
|
||||
WidgetInteractionL->AttachToComponent(LeftHandMesh, FAttachmentTransformRules::KeepRelativeTransform);
|
||||
WidgetInteractionR->AttachToComponent(RightHandMesh, FAttachmentTransformRules::KeepRelativeTransform);
|
||||
LaserL->AttachToComponent(WidgetInteractionL, FAttachmentTransformRules::SnapToTargetNotIncludingScale);
|
||||
LaserR->AttachToComponent(WidgetInteractionR, FAttachmentTransformRules::SnapToTargetNotIncludingScale);
|
||||
}
|
||||
|
||||
// Called every frame
|
||||
void AFireworksPawn::Tick(float DeltaTime)
|
||||
{
|
||||
Super::Tick(DeltaTime);
|
||||
SampleHandVelocities();
|
||||
TryUpdateLasers();
|
||||
TryUpdateTeleportVisual();
|
||||
}
|
||||
|
||||
// Called to bind functionality to input
|
||||
void AFireworksPawn::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
|
||||
{
|
||||
Super::SetupPlayerInputComponent(PlayerInputComponent);
|
||||
|
||||
}
|
||||
|
||||
// Setup grab attachment
|
||||
void AFireworksPawn::SetupGrabAttachment(EControllerHand Hand) {
|
||||
FName Socket = Hand == EControllerHand::Left ? TEXT("SocketL") : TEXT("SocketR");
|
||||
APickableObject* HeldObject = Hand == EControllerHand::Left ? HeldObject_L : HeldObject_R;
|
||||
|
||||
FTransform HeldObjectTransformLocal = HeldObject->StaticMesh->GetSocketTransform(Socket, ERelativeTransformSpace::RTS_Actor);
|
||||
|
||||
// Set new values
|
||||
FTransform NewTransform;
|
||||
NewTransform.SetScale3D(FVector(1.f, 1.f, 1.f));
|
||||
NewTransform.SetLocation(FVector(0.f, 0.f, 0.f));
|
||||
NewTransform.SetRotation(HeldObjectTransformLocal.GetRotation().Inverse());
|
||||
|
||||
// Set new transform
|
||||
HeldObject->SetActorRelativeTransform(NewTransform);
|
||||
HeldObject->AddActorLocalOffset(HeldObjectTransformLocal.GetLocation() * -1.f);
|
||||
}
|
||||
|
||||
// Try grab
|
||||
bool AFireworksPawn::TryGrab(EControllerHand Hand)
|
||||
{
|
||||
if (Hand == EControllerHand::Left) {
|
||||
// Left hand
|
||||
if (IsValid(HeldObject_L)) {
|
||||
return false;
|
||||
}
|
||||
if (!IsValid(HoveredActorL)) {
|
||||
return false;
|
||||
}
|
||||
HoveredActorL->StaticMesh->SetSimulatePhysics(false);
|
||||
HoveredActorL->StaticMesh->SetRenderCustomDepth(false);
|
||||
HeldObject_L = HoveredActorL;
|
||||
HeldObject_L->AttachToComponent(MotionControllerL, FAttachmentTransformRules::KeepRelativeTransform);
|
||||
SetupGrabAttachment(EControllerHand::Left);
|
||||
HeldObject_L->SetInstigator(this);
|
||||
IsGrabbingL = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
// Right hand
|
||||
if (IsValid(HeldObject_R)) {
|
||||
return false;
|
||||
}
|
||||
if (!IsValid(HoveredActorR)) {
|
||||
return false;
|
||||
}
|
||||
HoveredActorR->StaticMesh->SetSimulatePhysics(false);
|
||||
HoveredActorR->StaticMesh->SetRenderCustomDepth(false);
|
||||
HeldObject_R = HoveredActorR;
|
||||
HeldObject_R->StaticMesh->AttachToComponent(MotionControllerR, FAttachmentTransformRules::KeepRelativeTransform);
|
||||
SetupGrabAttachment(EControllerHand::Right);
|
||||
HeldObject_R->SetInstigator(this);
|
||||
IsGrabbingR = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Approximate Throw Velocity
|
||||
FVector AFireworksPawn::ApproximateThrowVelocity(EControllerHand Hand)
|
||||
{
|
||||
TArray<FVector> SampledVelocities = Hand == EControllerHand::Left ? VelocitySamples_L : VelocitySamples_R;
|
||||
FVector ApproximatedVelocity;
|
||||
|
||||
if (!SampledVelocities.IsEmpty()) {
|
||||
// TODO: discard shortest and longest vector, but first check if average works
|
||||
|
||||
// Calculate arithmetic average of Sampled Velocities
|
||||
for (int32 i = 0; i < SampledVelocities.Num(); i++)
|
||||
{
|
||||
ApproximatedVelocity += SampledVelocities[i];
|
||||
|
||||
// Draw debug lines
|
||||
if (DrawApproximationDebug)
|
||||
{
|
||||
FVector StartLoc = Hand == EControllerHand::Left ? LeftHandMesh->GetComponentLocation() : RightHandMesh->GetComponentLocation();
|
||||
DrawDebugLine(GetWorld(), StartLoc, StartLoc + SampledVelocities[i], FColor::Magenta, false, 2.f);
|
||||
}
|
||||
}
|
||||
ApproximatedVelocity = ApproximatedVelocity / SampledVelocities.Num();
|
||||
}
|
||||
|
||||
// Draw final result debug
|
||||
if (DrawApproximationDebug)
|
||||
{
|
||||
FVector StartLoc = Hand == EControllerHand::Left ? LeftHandMesh->GetComponentLocation() : RightHandMesh->GetComponentLocation();
|
||||
DrawDebugLine(GetWorld(), StartLoc, StartLoc + ApproximatedVelocity, FColor::Green, false, 2.f);
|
||||
}
|
||||
|
||||
return ApproximatedVelocity;
|
||||
}
|
||||
|
||||
// Throw object
|
||||
void AFireworksPawn::ThrowObject(APickableObject* Object, EControllerHand Hand)
|
||||
{
|
||||
Object->DetachFromActor(FDetachmentTransformRules::KeepWorldTransform);
|
||||
Object->StaticMesh->SetSimulatePhysics(true);
|
||||
Object->StaticMesh->SetPhysicsLinearVelocity(ApproximateThrowVelocity(Hand) * ThrowVelocityMultiplier);
|
||||
Object->ThrowEffects();
|
||||
}
|
||||
|
||||
// Drop
|
||||
bool AFireworksPawn::Drop(EControllerHand Hand)
|
||||
{
|
||||
if (Hand == EControllerHand::Left) {
|
||||
// Left hand
|
||||
if (IsValid(HeldObject_L)) {
|
||||
ThrowObject(HeldObject_L, Hand);
|
||||
|
||||
HeldObject_L = nullptr;
|
||||
IsGrabbingL = false;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Right hand
|
||||
if (IsValid(HeldObject_R)) {
|
||||
ThrowObject(HeldObject_R, Hand);
|
||||
|
||||
HeldObject_R = nullptr;
|
||||
IsGrabbingR = false;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Add firecracker to inventory
|
||||
void AFireworksPawn::AddToInventory(const FFireworkEntry& Entry)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
// Remove firecracker from inventory
|
||||
void AFireworksPawn::RemoveFromInventory(const FFireworkData& Item)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
// Enable laser on specific hand
|
||||
void AFireworksPawn::EnableLaserOnHand(EControllerHand Hand)
|
||||
{
|
||||
if (Hand == EControllerHand::Left)
|
||||
{
|
||||
TryShowLaserL = true;
|
||||
}
|
||||
else {
|
||||
TryShowLaserR = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Disable laser on hand
|
||||
void AFireworksPawn::DisableLaserOnHand(EControllerHand Hand)
|
||||
{
|
||||
if (Hand == EControllerHand::Left)
|
||||
{
|
||||
TryShowLaserL = false;
|
||||
}
|
||||
else {
|
||||
TryShowLaserR = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Update laser visuals and trace
|
||||
void AFireworksPawn::TryUpdateLasers()
|
||||
{
|
||||
// --- Left Hand ---
|
||||
|
||||
// Check if this hand is grabbing anything, if not - continue
|
||||
if (!IsGrabbingL) {
|
||||
|
||||
// Check if is pointing at any widget - if yes, omit trace and show laser
|
||||
if (WidgetInteractionL->IsOverHitTestVisibleWidget()) {
|
||||
LaserL->SetHiddenInGame(false);
|
||||
LaserL->SetRelativeScale3D(FVector(WidgetInteractionL->GetLastHitResult().Distance, LaserL->GetRelativeScale3D().Y, LaserL->GetRelativeScale3D().Z));
|
||||
} // If not pointing widget, check if Laser (teleport) button is pressed - if yes, show laser
|
||||
else if (TryShowLaserL)
|
||||
{
|
||||
FVector StartLocation = LaserL->GetComponentLocation();
|
||||
FVector EndLocation = StartLocation + (WidgetInteractionL->GetForwardVector() * WidgetInteractionL->InteractionDistance);
|
||||
GetWorld()->LineTraceSingleByChannel(CurrentLaserHitL, StartLocation, EndLocation, ECollisionChannel::ECC_Visibility);
|
||||
|
||||
LaserL->SetHiddenInGame(false);
|
||||
LaserL->SetRelativeScale3D(FVector(CurrentLaserHitL.Distance, LaserL->GetRelativeScale3D().Y, LaserL->GetRelativeScale3D().Z));
|
||||
} // If the laser is visible, and should not - hide it
|
||||
else if(!LaserL->bHiddenInGame)
|
||||
{
|
||||
LaserL->SetHiddenInGame(true);
|
||||
}
|
||||
}
|
||||
|
||||
// --- Right Hand ---
|
||||
|
||||
// Check if this hand is grabbing anything, if not - continue
|
||||
if (!IsGrabbingR) {
|
||||
|
||||
// Check if is pointing at any widget - if yes, omit trace and show laser
|
||||
if (WidgetInteractionR->IsOverHitTestVisibleWidget()) {
|
||||
LaserR->SetHiddenInGame(false);
|
||||
LaserR->SetRelativeScale3D(FVector(WidgetInteractionR->GetLastHitResult().Distance, LaserR->GetRelativeScale3D().Y, LaserR->GetRelativeScale3D().Z));
|
||||
} // If not pointing widget, check if Laser (teleport) button is pressed - if yes, show laser
|
||||
else if (TryShowLaserR)
|
||||
{
|
||||
FVector StartLocation = LaserR->GetComponentLocation();
|
||||
FVector EndLocation = StartLocation + (WidgetInteractionR->GetForwardVector() * WidgetInteractionR->InteractionDistance);
|
||||
GetWorld()->LineTraceSingleByChannel(CurrentLaserHitR, StartLocation, EndLocation, ECollisionChannel::ECC_Visibility);
|
||||
|
||||
LaserR->SetHiddenInGame(false);
|
||||
LaserR->SetRelativeScale3D(FVector(CurrentLaserHitR.Distance, LaserR->GetRelativeScale3D().Y, LaserR->GetRelativeScale3D().Z));
|
||||
} // If the laser is visible, and should not - hide it
|
||||
else if (!LaserR->bHiddenInGame)
|
||||
{
|
||||
LaserR->SetHiddenInGame(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Try update teleport visual
|
||||
void AFireworksPawn::TryUpdateTeleportVisual()
|
||||
{
|
||||
bool RightLaserCanTeleport = !LaserR->bHiddenInGame && (IsValid(CurrentLaserHitR.GetActor()) ? CurrentLaserHitR.GetActor()->ActorHasTag(TEXT("Ground")) : false);
|
||||
bool LeftLaserCanTeleport = !LaserL->bHiddenInGame && (IsValid(CurrentLaserHitL.GetActor()) ? CurrentLaserHitL.GetActor()->ActorHasTag(TEXT("Ground")) : false);
|
||||
|
||||
// Firstly cover the case of both hands pointing at ground with laser
|
||||
if (RightLaserCanTeleport && LeftLaserCanTeleport)
|
||||
{
|
||||
if (DominatingHand == EControllerHand::Left)
|
||||
{
|
||||
TeleportVisual->SetActorHiddenInGame(false);
|
||||
TeleportVisual->SetActorLocation(CurrentLaserHitL.Location);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
TeleportVisual->SetActorHiddenInGame(false);
|
||||
TeleportVisual->SetActorLocation(CurrentLaserHitR.Location);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Check if any hand is pointing laser at the ground
|
||||
if (LeftLaserCanTeleport)
|
||||
{
|
||||
TeleportVisual->SetActorHiddenInGame(false);
|
||||
TeleportVisual->SetActorLocation(CurrentLaserHitL.Location);
|
||||
return;
|
||||
}
|
||||
else if (RightLaserCanTeleport)
|
||||
{
|
||||
TeleportVisual->SetActorHiddenInGame(false);
|
||||
TeleportVisual->SetActorLocation(CurrentLaserHitR.Location);
|
||||
return;
|
||||
}
|
||||
else {
|
||||
TeleportVisual->SetActorHiddenInGame(true);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user