move modificator physics

This commit is contained in:
Oleg Petruny 2025-01-16 13:28:36 +01:00
parent 80e3091f85
commit ab3e1dd9fd
16 changed files with 196 additions and 46 deletions

View File

@ -122,26 +122,31 @@ ManualIPAddress=
-Profiles=(Name="UI",CollisionEnabled=QueryOnly,ObjectTypeName="WorldDynamic",CustomResponses=((Channel="WorldStatic",Response=ECR_Overlap),(Channel="Pawn",Response=ECR_Overlap),(Channel="Visibility",Response=ECR_Block),(Channel="WorldDynamic",Response=ECR_Overlap),(Channel="Camera",Response=ECR_Overlap),(Channel="PhysicsBody",Response=ECR_Overlap),(Channel="Vehicle",Response=ECR_Overlap),(Channel="Destructible",Response=ECR_Overlap)),HelpMessage="WorldStatic object that overlaps all actors by default. All new custom channels will use its own default response. ",bCanModify=False)
+Profiles=(Name="NoCollision",CollisionEnabled=NoCollision,bCanModify=False,ObjectTypeName="WorldStatic",CustomResponses=((Channel="Visibility",Response=ECR_Ignore),(Channel="Camera",Response=ECR_Ignore)),HelpMessage="No collision")
+Profiles=(Name="BlockAll",CollisionEnabled=QueryAndPhysics,bCanModify=False,ObjectTypeName="WorldStatic",CustomResponses=,HelpMessage="WorldStatic object that blocks all actors by default. All new custom channels will use its own default response. ")
+Profiles=(Name="OverlapAll",CollisionEnabled=QueryOnly,bCanModify=False,ObjectTypeName="WorldStatic",CustomResponses=((Channel="WorldStatic",Response=ECR_Overlap),(Channel="Pawn",Response=ECR_Overlap),(Channel="Visibility",Response=ECR_Overlap),(Channel="WorldDynamic",Response=ECR_Overlap),(Channel="Camera",Response=ECR_Overlap),(Channel="PhysicsBody",Response=ECR_Overlap),(Channel="Vehicle",Response=ECR_Overlap),(Channel="Destructible",Response=ECR_Overlap)),HelpMessage="WorldStatic object that overlaps all actors by default. All new custom channels will use its own default response. ")
+Profiles=(Name="OverlapAll",CollisionEnabled=QueryOnly,bCanModify=False,ObjectTypeName="WorldStatic",CustomResponses=((Channel="WorldStatic",Response=ECR_Overlap),(Channel="WorldDynamic",Response=ECR_Overlap),(Channel="Pawn",Response=ECR_Overlap),(Channel="Visibility",Response=ECR_Overlap),(Channel="Camera",Response=ECR_Overlap),(Channel="PhysicsBody",Response=ECR_Overlap),(Channel="Vehicle",Response=ECR_Overlap),(Channel="Destructible",Response=ECR_Overlap)),HelpMessage="WorldStatic object that overlaps all actors by default. All new custom channels will use its own default response. ")
+Profiles=(Name="BlockAllDynamic",CollisionEnabled=QueryAndPhysics,bCanModify=False,ObjectTypeName="WorldDynamic",CustomResponses=,HelpMessage="WorldDynamic object that blocks all actors by default. All new custom channels will use its own default response. ")
+Profiles=(Name="OverlapAllDynamic",CollisionEnabled=QueryOnly,bCanModify=False,ObjectTypeName="WorldDynamic",CustomResponses=((Channel="WorldStatic",Response=ECR_Overlap),(Channel="Pawn",Response=ECR_Overlap),(Channel="Visibility",Response=ECR_Overlap),(Channel="WorldDynamic",Response=ECR_Overlap),(Channel="Camera",Response=ECR_Overlap),(Channel="PhysicsBody",Response=ECR_Overlap),(Channel="Vehicle",Response=ECR_Overlap),(Channel="Destructible",Response=ECR_Overlap)),HelpMessage="WorldDynamic object that overlaps all actors by default. All new custom channels will use its own default response. ")
+Profiles=(Name="OverlapAllDynamic",CollisionEnabled=QueryOnly,bCanModify=False,ObjectTypeName="WorldDynamic",CustomResponses=((Channel="WorldStatic",Response=ECR_Overlap),(Channel="WorldDynamic",Response=ECR_Overlap),(Channel="Pawn",Response=ECR_Overlap),(Channel="Visibility",Response=ECR_Overlap),(Channel="Camera",Response=ECR_Overlap),(Channel="PhysicsBody",Response=ECR_Overlap),(Channel="Vehicle",Response=ECR_Overlap),(Channel="Destructible",Response=ECR_Overlap),(Channel="InteractableTrace",Response=ECR_Overlap)),HelpMessage="WorldDynamic object that overlaps all actors by default. All new custom channels will use its own default response. ")
+Profiles=(Name="IgnoreOnlyPawn",CollisionEnabled=QueryOnly,bCanModify=False,ObjectTypeName="WorldDynamic",CustomResponses=((Channel="Pawn",Response=ECR_Ignore),(Channel="Vehicle",Response=ECR_Ignore)),HelpMessage="WorldDynamic object that ignores Pawn and Vehicle. All other channels will be set to default.")
+Profiles=(Name="OverlapOnlyPawn",CollisionEnabled=QueryOnly,bCanModify=False,ObjectTypeName="WorldDynamic",CustomResponses=((Channel="Pawn",Response=ECR_Overlap),(Channel="Vehicle",Response=ECR_Overlap),(Channel="Camera",Response=ECR_Ignore)),HelpMessage="WorldDynamic object that overlaps Pawn, Camera, and Vehicle. All other channels will be set to default. ")
+Profiles=(Name="Pawn",CollisionEnabled=QueryAndPhysics,bCanModify=False,ObjectTypeName="Pawn",CustomResponses=((Channel="Visibility",Response=ECR_Ignore)),HelpMessage="Pawn object. Can be used for capsule of any playerable character or AI. ")
+Profiles=(Name="Spectator",CollisionEnabled=QueryOnly,bCanModify=False,ObjectTypeName="Pawn",CustomResponses=((Channel="WorldStatic"),(Channel="Pawn",Response=ECR_Ignore),(Channel="Visibility",Response=ECR_Ignore),(Channel="WorldDynamic",Response=ECR_Ignore),(Channel="Camera",Response=ECR_Ignore),(Channel="PhysicsBody",Response=ECR_Ignore),(Channel="Vehicle",Response=ECR_Ignore),(Channel="Destructible",Response=ECR_Ignore)),HelpMessage="Pawn object that ignores all other actors except WorldStatic.")
+Profiles=(Name="CharacterMesh",CollisionEnabled=QueryOnly,bCanModify=False,ObjectTypeName="Pawn",CustomResponses=((Channel="Pawn",Response=ECR_Ignore),(Channel="Vehicle",Response=ECR_Ignore),(Channel="Visibility",Response=ECR_Ignore)),HelpMessage="Pawn object that is used for Character Mesh. All other channels will be set to default.")
+Profiles=(Name="OverlapOnlyPawn",CollisionEnabled=QueryOnly,bCanModify=False,ObjectTypeName="WorldDynamic",CustomResponses=((Channel="Pawn",Response=ECR_Overlap),(Channel="Camera",Response=ECR_Ignore),(Channel="Vehicle",Response=ECR_Overlap)),HelpMessage="WorldDynamic object that overlaps Pawn, Camera, and Vehicle. All other channels will be set to default. ")
+Profiles=(Name="Pawn",CollisionEnabled=QueryAndPhysics,bCanModify=False,ObjectTypeName="Pawn",CustomResponses=((Channel="Visibility",Response=ECR_Ignore),(Channel="InteractableTrace")),HelpMessage="Pawn object. Can be used for capsule of any playerable character or AI. ")
+Profiles=(Name="Spectator",CollisionEnabled=QueryOnly,bCanModify=False,ObjectTypeName="Pawn",CustomResponses=((Channel="WorldDynamic",Response=ECR_Ignore),(Channel="Pawn",Response=ECR_Ignore),(Channel="Visibility",Response=ECR_Ignore),(Channel="Camera",Response=ECR_Ignore),(Channel="PhysicsBody",Response=ECR_Ignore),(Channel="Vehicle",Response=ECR_Ignore),(Channel="Destructible",Response=ECR_Ignore)),HelpMessage="Pawn object that ignores all other actors except WorldStatic.")
+Profiles=(Name="CharacterMesh",CollisionEnabled=QueryOnly,bCanModify=False,ObjectTypeName="Pawn",CustomResponses=((Channel="Pawn",Response=ECR_Ignore),(Channel="Visibility",Response=ECR_Ignore),(Channel="Vehicle",Response=ECR_Ignore)),HelpMessage="Pawn object that is used for Character Mesh. All other channels will be set to default.")
+Profiles=(Name="PhysicsActor",CollisionEnabled=QueryAndPhysics,bCanModify=False,ObjectTypeName="PhysicsBody",CustomResponses=,HelpMessage="Simulating actors")
+Profiles=(Name="Destructible",CollisionEnabled=QueryAndPhysics,bCanModify=False,ObjectTypeName="Destructible",CustomResponses=,HelpMessage="Destructible actors")
+Profiles=(Name="InvisibleWall",CollisionEnabled=QueryAndPhysics,bCanModify=False,ObjectTypeName="WorldStatic",CustomResponses=((Channel="Visibility",Response=ECR_Ignore)),HelpMessage="WorldStatic object that is invisible.")
+Profiles=(Name="InvisibleWallDynamic",CollisionEnabled=QueryAndPhysics,bCanModify=False,ObjectTypeName="WorldDynamic",CustomResponses=((Channel="Visibility",Response=ECR_Ignore)),HelpMessage="WorldDynamic object that is invisible.")
+Profiles=(Name="Trigger",CollisionEnabled=QueryOnly,bCanModify=False,ObjectTypeName="WorldDynamic",CustomResponses=((Channel="WorldStatic",Response=ECR_Overlap),(Channel="Pawn",Response=ECR_Overlap),(Channel="Visibility",Response=ECR_Ignore),(Channel="WorldDynamic",Response=ECR_Overlap),(Channel="Camera",Response=ECR_Overlap),(Channel="PhysicsBody",Response=ECR_Overlap),(Channel="Vehicle",Response=ECR_Overlap),(Channel="Destructible",Response=ECR_Overlap)),HelpMessage="WorldDynamic object that is used for trigger. All other channels will be set to default.")
+Profiles=(Name="Trigger",CollisionEnabled=QueryOnly,bCanModify=False,ObjectTypeName="WorldDynamic",CustomResponses=((Channel="WorldStatic",Response=ECR_Overlap),(Channel="WorldDynamic",Response=ECR_Overlap),(Channel="Pawn",Response=ECR_Overlap),(Channel="Visibility",Response=ECR_Ignore),(Channel="Camera",Response=ECR_Overlap),(Channel="PhysicsBody",Response=ECR_Overlap),(Channel="Vehicle",Response=ECR_Overlap),(Channel="Destructible",Response=ECR_Overlap)),HelpMessage="WorldDynamic object that is used for trigger. All other channels will be set to default.")
+Profiles=(Name="Ragdoll",CollisionEnabled=QueryAndPhysics,bCanModify=False,ObjectTypeName="PhysicsBody",CustomResponses=((Channel="Pawn",Response=ECR_Ignore),(Channel="Visibility",Response=ECR_Ignore)),HelpMessage="Simulating Skeletal Mesh Component. All other channels will be set to default.")
+Profiles=(Name="Vehicle",CollisionEnabled=QueryAndPhysics,bCanModify=False,ObjectTypeName="Vehicle",CustomResponses=,HelpMessage="Vehicle object that blocks Vehicle, WorldStatic, and WorldDynamic. All other channels will be set to default.")
+Profiles=(Name="UI",CollisionEnabled=QueryOnly,bCanModify=False,ObjectTypeName="WorldDynamic",CustomResponses=((Channel="WorldStatic",Response=ECR_Overlap),(Channel="Pawn",Response=ECR_Overlap),(Channel="Visibility"),(Channel="WorldDynamic",Response=ECR_Overlap),(Channel="Camera",Response=ECR_Overlap),(Channel="PhysicsBody",Response=ECR_Overlap),(Channel="Vehicle",Response=ECR_Overlap),(Channel="Destructible",Response=ECR_Overlap)),HelpMessage="WorldStatic object that overlaps all actors by default. All new custom channels will use its own default response. ")
+Profiles=(Name="Interactable",CollisionEnabled=QueryAndPhysics,bCanModify=True,ObjectTypeName="WorldDynamic",CustomResponses=((Channel="Interactable")),HelpMessage="WorldDynamic objects derived from AInteractable.")
+Profiles=(Name="AgeOfWarUnitPlayer",CollisionEnabled=QueryOnly,bCanModify=True,ObjectTypeName="Vehicle",CustomResponses=((Channel="WorldStatic",Response=ECR_Ignore),(Channel="WorldDynamic",Response=ECR_Ignore),(Channel="Pawn",Response=ECR_Ignore),(Channel="Visibility",Response=ECR_Ignore),(Channel="Camera",Response=ECR_Ignore),(Channel="PhysicsBody",Response=ECR_Ignore),(Channel="Vehicle",Response=ECR_Ignore),(Channel="Interactable")),HelpMessage="Minigame object")
+Profiles=(Name="AgeOfWarUnitComputer",CollisionEnabled=QueryOnly,bCanModify=True,ObjectTypeName="Destructible",CustomResponses=((Channel="WorldStatic",Response=ECR_Ignore),(Channel="WorldDynamic",Response=ECR_Ignore),(Channel="Pawn",Response=ECR_Ignore),(Channel="Visibility",Response=ECR_Ignore),(Channel="Camera",Response=ECR_Ignore),(Channel="PhysicsBody",Response=ECR_Ignore),(Channel="Destructible",Response=ECR_Ignore),(Channel="Interactable")),HelpMessage="Minigame object")
+DefaultChannelResponses=(Channel=ECC_GameTraceChannel1,DefaultResponse=ECR_Ignore,bTraceType=True,bStaticObject=False,Name="Interactable")
+Profiles=(Name="UI",CollisionEnabled=QueryOnly,bCanModify=False,ObjectTypeName="WorldDynamic",CustomResponses=((Channel="WorldStatic",Response=ECR_Overlap),(Channel="WorldDynamic",Response=ECR_Overlap),(Channel="Pawn",Response=ECR_Overlap),(Channel="Camera",Response=ECR_Overlap),(Channel="PhysicsBody",Response=ECR_Overlap),(Channel="Vehicle",Response=ECR_Overlap),(Channel="Destructible",Response=ECR_Overlap)),HelpMessage="WorldStatic object that overlaps all actors by default. All new custom channels will use its own default response. ")
+Profiles=(Name="Interactable",CollisionEnabled=QueryAndPhysics,bCanModify=True,ObjectTypeName="WorldDynamic",CustomResponses=((Channel="InteractableTrace")),HelpMessage="WorldDynamic objects derived from AInteractable.")
+Profiles=(Name="AgeOfWarUnitPlayer",CollisionEnabled=QueryOnly,bCanModify=True,ObjectTypeName="Vehicle",CustomResponses=((Channel="WorldStatic",Response=ECR_Ignore),(Channel="WorldDynamic",Response=ECR_Ignore),(Channel="Pawn",Response=ECR_Ignore),(Channel="Visibility",Response=ECR_Ignore),(Channel="Camera",Response=ECR_Ignore),(Channel="PhysicsBody",Response=ECR_Ignore),(Channel="Vehicle",Response=ECR_Ignore),(Channel="InteractableTrace")),HelpMessage="Minigame object")
+Profiles=(Name="AgeOfWarUnitComputer",CollisionEnabled=QueryOnly,bCanModify=True,ObjectTypeName="Destructible",CustomResponses=((Channel="WorldStatic",Response=ECR_Ignore),(Channel="WorldDynamic",Response=ECR_Ignore),(Channel="Pawn",Response=ECR_Ignore),(Channel="Visibility",Response=ECR_Ignore),(Channel="Camera",Response=ECR_Ignore),(Channel="PhysicsBody",Response=ECR_Ignore),(Channel="Destructible",Response=ECR_Ignore),(Channel="InteractableTrace")),HelpMessage="Minigame object")
+DefaultChannelResponses=(Channel=ECC_GameTraceChannel1,DefaultResponse=ECR_Ignore,bTraceType=True,bStaticObject=False,Name="InteractableTrace")
+DefaultChannelResponses=(Channel=ECC_GameTraceChannel2,DefaultResponse=ECR_Block,bTraceType=False,bStaticObject=False,Name="Interactable")
+EditProfiles=(Name="Pawn",CustomResponses=((Channel="InteractableTrace"),(Channel="Interactable",Response=ECR_Overlap)))
+EditProfiles=(Name="OverlapAllDynamic",CustomResponses=((Channel="InteractableTrace",Response=ECR_Overlap),(Channel="Interactable",Response=ECR_Overlap)))
+EditProfiles=(Name="CharacterMesh",CustomResponses=((Channel="Interactable",Response=ECR_Ignore)))
+EditProfiles=(Name="Spectator",CustomResponses=((Channel="Interactable",Response=ECR_Ignore)))
-ProfileRedirects=(OldName="BlockingVolume",NewName="InvisibleWall")
-ProfileRedirects=(OldName="InterpActor",NewName="IgnoreOnlyPawn")
-ProfileRedirects=(OldName="StaticMeshComponent",NewName="BlockAllDynamic")
@ -163,6 +168,7 @@ ManualIPAddress=
+CollisionChannelRedirects=(OldName="Dynamic",NewName="WorldDynamic")
+CollisionChannelRedirects=(OldName="VehicleMovement",NewName="Vehicle")
+CollisionChannelRedirects=(OldName="PawnMovement",NewName="Pawn")
+CollisionChannelRedirects=(OldName="Interactable",NewName="InteractableTrace")
[/Script/FMODStudio.FMODSettings]
bLoadAllBanks=True

View File

@ -24,6 +24,7 @@ UInCameraInteractableActivator::UInCameraInteractableActivator(const FObjectInit
capturer->interactableInScreenDelegate.BindUObject(this, &UInCameraInteractableActivator::NewSeenInteractable);
capturer->SetupAttachment(this);
capturer->scanDistance = scanDistance;
capturer->ignoredActors.Add(actor);
PrimaryComponentTick.bCanEverTick = true;
PrimaryComponentTick.bStartWithTickEnabled = false;

View File

@ -18,8 +18,9 @@ UInteractableActivator::UInteractableActivator(const FObjectInitializer& ObjectI
if(HasAnyFlags(RF_ClassDefaultObject | RF_ArchetypeObject))
return;
actor = GetOwner();
world = GetWorld();
player = Cast<APlayerBase>(GetOwner());
player = APlayerBase::Get();
collisionChannel = ECC_GameTraceChannel1;
if(auto collisions = UCollisionProfile::Get())

View File

@ -46,6 +46,7 @@ protected:
UPROPERTY(EditDefaultsOnly)
float scanDistance = 250;
class AActor* actor;
class UWorld* world;
class APlayerBase* player;
ECollisionChannel collisionChannel;

View File

@ -248,6 +248,8 @@ void UInteractableScreenCapturer::Process()
FHitResult result{};
FVector startLocation = view.Location;
FVector endLocation = worldLoc + worldDir * scanDistance;
FCollisionQueryParams hitParams;
hitParams.AddIgnoredActors(ignoredActors);
world->LineTraceSingleByChannel(
result,
startLocation,

View File

@ -28,6 +28,8 @@ public:
UPROPERTY(EditAnywhere)
float scanDistance = 7000;
TArray<AActor*> ignoredActors;
protected:
/** Enques render thread task to find obect on screen */
void Process();

View File

@ -21,12 +21,15 @@ void URaycastInteractableActivator::Scan_Implementation()
FHitResult result;
FVector startLocation = GetComponentLocation();
FVector endLocation = startLocation + (GetComponentRotation().Vector() * scanDistance);
FCollisionQueryParams hitParams;
hitParams.AddIgnoredActor(actor);
world->LineTraceSingleByChannel(
result,
startLocation,
endLocation,
collisionChannel
collisionChannel,
hitParams
);
if(result.bBlockingHit)

View File

@ -2,6 +2,7 @@
#include "Interactable.h"
#include "Engine/CollisionProfile.h"
#include "Kismet/GameplayStatics.h"
#include "Activators/InteractableActivator.h"
@ -11,6 +12,15 @@
#include "PlayerBase.h"
#include "Widgets/WidgetsManager.h"
#include <optional>
namespace
{
constexpr auto collisionProfile = TEXT("Interactable");
constexpr int32 sawStencil = 128;
constexpr int32 outlineStencil = 132;
}
TSet<TSubclassOf<class UInteractableActivator>> AInteractable::interactionActivators = {};
TSet<TSubclassOf<class UInteractableModificator>> AInteractable::interactionModificators = {};
@ -33,6 +43,19 @@ void AInteractable::AppendModificatorClass(TSubclassOf<class UInteractableModifi
ACustomPlayerController::AppendInputContext(IC);
}
ECollisionChannel AInteractable::GetCollisionChannel()
{
static std::optional<FCollisionResponseTemplate> collisionTemplate;
if(!collisionTemplate.has_value())
{
FCollisionResponseTemplate buffer;
UCollisionProfile::Get()->GetProfileTemplate(collisionProfile, buffer);
collisionTemplate = buffer;
}
return collisionTemplate->ObjectType;
}
int32 AInteractable::GetActivatedFlags()
{
return activated;
@ -83,12 +106,12 @@ void AInteractable::BeginPlay()
{
if(activatorTypes)
{
collision->SetCollisionProfileName(TEXT("Interactable"));
collision->SetCollisionProfileName(collisionProfile);
}
if(activatorTypes & static_cast<uint8>(EActivatorType::Saw))
{
collision->CustomDepthStencilValue = 128;
collision->CustomDepthStencilValue = sawStencil;
collision->CustomDepthStencilWriteMask = ERendererStencilMask::ERSM_Default;
collision->SetRenderCustomDepth(true);
}
@ -144,7 +167,7 @@ void AInteractable::Activate(EActivatorType type)
if(activated & static_cast<uint8>(EActivatorType::Use))
{
for(auto collision : collisions)
collision->SetCustomDepthStencilValue(132);
collision->SetCustomDepthStencilValue(outlineStencil);
}
OnActivate(type);
@ -178,6 +201,10 @@ void AInteractable::Deactivate(EActivatorType type)
if(!(activated & static_cast<uint8>(EActivatorType::Use)))
{
if(modificators.Contains(EActivatorType::Saw))
for(auto collision : collisions)
collision->SetCustomDepthStencilValue(sawStencil);
else
for(auto collision : collisions)
collision->SetCustomDepthStencilValue(0);
}

View File

@ -43,6 +43,8 @@ public:
static void AppendActivatorClass(TSubclassOf<class UInteractableActivator> activator);
static void AppendModificatorClass(TSubclassOf<class UInteractableModificator> modificator);
static ECollisionChannel GetCollisionChannel();
/** Interactables shared cache */
static TSet<TSubclassOf<class UInteractableActivator>> interactionActivators;
static TSet<TSubclassOf<class UInteractableModificator>> interactionModificators;

View File

@ -2,8 +2,12 @@
#include "MoveInteractableModificator.h"
#include "Components/BoxComponent.h"
#include "Components/CapsuleComponent.h"
#include "Components/PrimitiveComponent.h"
#include "EnhancedInputComponent.h"
#include "InputMappingContext.h"
#include "PhysicsEngine/PhysicsHandleComponent.h"
#include "Interactable/Interactable.h"
#include "MainGameModeBase.h"
@ -20,6 +24,11 @@ UMoveInteractableModificator::UMoveInteractableModificator(const FObjectInitiali
inputMapping = asset.Object;
actor = Cast<AInteractable>(GetOwner());
if(actor)
{
shape = FCollisionShape::MakeBox(actor->GetComponentsBoundingBox().GetExtent());
primitive = actor->GetComponentByClass<UPrimitiveComponent>();
}
PrimaryComponentTick.bCanEverTick = true;
PrimaryComponentTick.bStartWithTickEnabled = false;
@ -70,7 +79,7 @@ void UMoveInteractableModificator::Bind_Implementation(class UEnhancedInputCompo
}
lastInput = input;
player = Cast<APlayerBase>(Cast<APlayerController>(lastInput->GetOwner())->GetPawn());
player = APlayerBase::Get();
SetComponentTickEnabled(true);
OnMoveActivated.Broadcast();
@ -98,6 +107,16 @@ void UMoveInteractableModificator::TurnOnHolding()
{
FScopeLock lock1(&critical);
holding = true;
if(primitive && primitive->IsSimulatingPhysics())
{
positionUpdateType = PositionUpdateType::Physics;
player->physicsHandle->GrabComponentAtLocationWithRotation(primitive, TEXT("None"), actor->GetActorLocation(), actor->GetActorRotation());
}
else
{
positionUpdateType = PositionUpdateType::Simple;
}
ProcessState();
distance = (player->GetCameraLocation() - actor->GetActorLocation()).Length();
AMainGameModeBase::GetWidgetsManager()->AnimateInteractionHint(this, 0, EInputAnimatedWidgetAnimation::Hold);
@ -107,6 +126,8 @@ void UMoveInteractableModificator::TurnOffHolding()
{
FScopeLock lock1(&critical);
holding = false;
if(positionUpdateType == PositionUpdateType::Physics)
player->physicsHandle->ReleaseComponent();
ProcessState();
AMainGameModeBase::GetWidgetsManager()->AnimateInteractionHint(this, 0, EInputAnimatedWidgetAnimation::Unhold);
}
@ -139,6 +160,11 @@ void UMoveInteractableModificator::ProcessState()
else
{
actor->activationLockers.Remove(this);
if(indicating)
{
indicating = false;
AMainGameModeBase::GetWidgetsManager()->AnimateInteractionHint(this, 0, EInputAnimatedWidgetAnimation::TurnOffIndication);
}
if((actor->GetActivatedFlags() & static_cast<int32>(GetActivatorTypes())) == 0
&& !bindindingHandlers.IsEmpty())
{
@ -152,27 +178,42 @@ void UMoveInteractableModificator::UpdatePosition()
if(!player || (!holding && !rotating))
return;
if(player->IsOverlappingActor(actor))
return;
auto camLoc = player->GetCameraLocation();
auto dir = player->GetCameraDirection();
auto newLoc = camLoc + dir * distance;
auto oldLoc = actor->GetActorLocation();
//auto interpLoc = FMath::VInterpTo(oldLoc, newLoc, GetWorld()->GetDeltaSeconds(), 20.0f);
//auto interpLoc = FMath::Lerp(oldLoc, newLoc, 0.5f);
FHitResult hit;
actor->SetActorLocation(newLoc, true, &hit, ETeleportType::None);
static bool indicating = false;
if(hit.bBlockingHit && !indicating)
auto rot = actor->GetActorQuat();
bool blocked = MoveIsBlocked(newLoc, rot) || player->nearScanner->ComponentOverlapComponent(primitive, newLoc, actor->GetActorQuat(), {});
if(blocked)
{
if(!indicating)
{
indicating = true;
AMainGameModeBase::GetWidgetsManager()->AnimateInteractionHint(this, 0, EInputAnimatedWidgetAnimation::TurnOnIndication);
}
else if(!hit.bBlockingHit && indicating)
return;
}
else
{
if(indicating)
{
indicating = false;
AMainGameModeBase::GetWidgetsManager()->AnimateInteractionHint(this, 0, EInputAnimatedWidgetAnimation::TurnOffIndication);
}
}
switch(positionUpdateType)
{
case PositionUpdateType::Physics:
player->physicsHandle->SetTargetLocation(newLoc);
break;
default:
actor->SetActorLocation(newLoc, true, nullptr, ETeleportType::None);
break;
}
}
void UMoveInteractableModificator::Zooming(const FInputActionValue& value)
@ -180,8 +221,14 @@ void UMoveInteractableModificator::Zooming(const FInputActionValue& value)
if(!holding && !rotating)
return;
distance += value.Get<float>() * zoomSpeed;
distance = FMath::Clamp<float>(distance, minDistance, maxDistance);
float delta = value.Get<float>() * zoomSpeed;
auto start = actor->GetActorLocation();
auto end = start + player->GetCameraDirection() * delta;
auto rot = actor->GetActorQuat();
if(MoveIsBlocked(end, rot))
return;
distance = FMath::Clamp<float>(distance + delta, minDistance, maxDistance);
}
void UMoveInteractableModificator::Rotating(const FInputActionValue& axis)
@ -190,9 +237,35 @@ void UMoveInteractableModificator::Rotating(const FInputActionValue& axis)
return;
auto v = axis.Get<FVector>();
auto vec = player->GetCameraDirection();
auto currentRot = actor->GetActorRotation();
auto currentLoc = actor->GetActorLocation();
auto newRot = FRotator{ v.Y * vec.X, v.X, v.Y * vec.Y * -1 };
actor->AddActorWorldRotation(newRot, true, nullptr, ETeleportType::None); // sweep not supported from 4.xx+
auto dir = player->GetCameraDirection();
auto addRot = FRotator{ v.Y * dir.X, v.X, v.Y * dir.Y * -1 };
auto newRot = (addRot.Quaternion() * actor->GetActorQuat()).Rotator();
// rotation sweep is unsupported for some reason
// if(MoveIsBlocked(actor->GetActorLocation(), newRot.Quaternion()))
// return;
if(player->nearScanner->ComponentOverlapComponent(primitive, actor->GetActorLocation(), newRot, {})
|| player->feetScanner->ComponentOverlapComponent(primitive, actor->GetActorLocation(), newRot, {}))
return;
switch(positionUpdateType)
{
case PositionUpdateType::Physics:
player->physicsHandle->SetTargetRotation(newRot);
break;
default:
actor->SetActorRotation(newRot, ETeleportType::None);
break;
}
}
bool UMoveInteractableModificator::MoveIsBlocked(const FVector& end, const FQuat& rot)
{
FHitResult hit;
FVector start = actor->GetActorLocation();
FCollisionQueryParams hitParams;
hitParams.AddIgnoredActor(actor);
actor->GetWorld()->SweepSingleByChannel(hit, start, end, rot, AInteractable::GetCollisionChannel(), shape, hitParams);
return hit.bBlockingHit;
}

View File

@ -53,6 +53,7 @@ private:
void UpdatePosition();
void Zooming(const FInputActionValue& value);
void Rotating(const FInputActionValue& axis);
bool MoveIsBlocked(const FVector& end, const FQuat& rot);
class UEnhancedInputComponent* lastInput = nullptr;
TArray<int32> bindindingHandlers;
@ -61,4 +62,13 @@ private:
class AInteractable* actor = nullptr;
class APlayerBase* player = nullptr;
FCriticalSection critical;
bool indicating = false;
FCollisionShape shape;
class UPrimitiveComponent* primitive;
enum PositionUpdateType : uint8
{
Simple,
Physics
} positionUpdateType = Simple;
};

View File

@ -3,11 +3,14 @@
#include "PlayerBase.h"
#include "Camera/CameraComponent.h"
#include "Components/BoxComponent.h"
#include "Components/CapsuleComponent.h"
#include "GameFramework/CharacterMovementComponent.h"
#include "GameFramework/SpringArmComponent.h"
#include "InputMappingContext.h"
#include "Kismet/GameplayStatics.h"
#include "Kismet/KismetMathLibrary.h"
#include "PhysicsEngine/PhysicsHandleComponent.h"
#include "CustomGameSettings.h"
#include "CustomPlayerController.h"
@ -40,6 +43,12 @@ APlayerBase::APlayerBase()
itemDropSpringArm = CreateDefaultSubobject<USpringArmComponent>(TEXT("ItemDropSpringArm"));
itemDropSpringArm->TargetArmLength = -200;
itemDropSpringArm->SetupAttachment(camera);
physicsHandle = CreateDefaultSubobject<UPhysicsHandleComponent>(TEXT("PhysicsHandle"));
nearScanner = CreateDefaultSubobject<UCapsuleComponent>(TEXT("NearScanner"));
nearScanner->SetupAttachment(RootComponent);
feetScanner = CreateDefaultSubobject<UBoxComponent>(TEXT("FeetScanner"));
feetScanner->SetupAttachment(RootComponent);
}
void APlayerBase::Tick(float DeltaTime)
@ -195,6 +204,10 @@ void APlayerBase::Jump()
if(jumpLocked)
return;
if(auto primitive = physicsHandle->GetGrabbedComponent())
if(feetScanner->ComponentOverlapComponent(primitive, primitive->GetComponentLocation(), primitive->GetComponentRotation(), {}))
return;
ACharacter::Jump();
}

View File

@ -80,9 +80,18 @@ public:
FVector moveVector;
UPROPERTY()
class AActor* leftPocketItem = nullptr;
UPROPERTY()
class AActor* rightPocketItem = nullptr;
UPROPERTY()
class UPhysicsHandleComponent* physicsHandle;
UPROPERTY(EditAnywhere)
class UCapsuleComponent* nearScanner;
UPROPERTY(EditAnywhere)
class UBoxComponent* feetScanner;
protected:
virtual void BeginPlay() override;