First iteration of spline movement mechanic in C++
This commit is contained in:
parent
f70079c04f
commit
2bfd6d4f15
@ -70,7 +70,9 @@ bCaptureMouseOnLaunch=True
|
|||||||
bEnableLegacyInputScales=True
|
bEnableLegacyInputScales=True
|
||||||
bEnableMotionControls=True
|
bEnableMotionControls=True
|
||||||
bFilterInputByPlatformUser=False
|
bFilterInputByPlatformUser=False
|
||||||
|
bEnableInputDeviceSubsystem=True
|
||||||
bShouldFlushPressedKeysOnViewportFocusLost=True
|
bShouldFlushPressedKeysOnViewportFocusLost=True
|
||||||
|
bEnableDynamicComponentInputBinding=True
|
||||||
bAlwaysShowTouchInterface=False
|
bAlwaysShowTouchInterface=False
|
||||||
bShowConsoleOnFourFingerTap=True
|
bShowConsoleOnFourFingerTap=True
|
||||||
bEnableGestureRecognizer=False
|
bEnableGestureRecognizer=False
|
||||||
@ -85,4 +87,5 @@ DefaultTouchInterface=/Engine/MobileResources/HUD/DefaultVirtualJoysticks.Defaul
|
|||||||
-ConsoleKeys=Tilde
|
-ConsoleKeys=Tilde
|
||||||
+ConsoleKeys=Tilde
|
+ConsoleKeys=Tilde
|
||||||
+ConsoleKeys=Caret
|
+ConsoleKeys=Caret
|
||||||
|
+ConsoleKeys=²
|
||||||
|
|
||||||
|
|||||||
BIN
Pawn_Unreal/Content/Characters/BP_Judy.uasset
(Stored with Git LFS)
BIN
Pawn_Unreal/Content/Characters/BP_Judy.uasset
(Stored with Git LFS)
Binary file not shown.
BIN
Pawn_Unreal/Content/Characters/Base/ABP_Character.uasset
(Stored with Git LFS)
BIN
Pawn_Unreal/Content/Characters/Base/ABP_Character.uasset
(Stored with Git LFS)
Binary file not shown.
BIN
Pawn_Unreal/Content/Input/BP_MainPlayerController.uasset
(Stored with Git LFS)
BIN
Pawn_Unreal/Content/Input/BP_MainPlayerController.uasset
(Stored with Git LFS)
Binary file not shown.
BIN
Pawn_Unreal/Content/__ExternalActors__/Maps/Dev/MAP_ControllerGym/0/91/BERD0JFDCI5RAYAPS4DY1P.uasset
(Stored with Git LFS)
Normal file
BIN
Pawn_Unreal/Content/__ExternalActors__/Maps/Dev/MAP_ControllerGym/0/91/BERD0JFDCI5RAYAPS4DY1P.uasset
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
Pawn_Unreal/Content/__ExternalActors__/Maps/Dev/MAP_ControllerGym/0/XC/EES9G2P00B5EO5FPWE8N4U.uasset
(Stored with Git LFS)
Normal file
BIN
Pawn_Unreal/Content/__ExternalActors__/Maps/Dev/MAP_ControllerGym/0/XC/EES9G2P00B5EO5FPWE8N4U.uasset
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
Pawn_Unreal/Content/__ExternalActors__/Maps/Dev/MAP_ControllerGym/1/LE/RIS6ZA9R1KK7MS3EGVDKZV.uasset
(Stored with Git LFS)
Normal file
BIN
Pawn_Unreal/Content/__ExternalActors__/Maps/Dev/MAP_ControllerGym/1/LE/RIS6ZA9R1KK7MS3EGVDKZV.uasset
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
Pawn_Unreal/Content/__ExternalActors__/Maps/Dev/MAP_ControllerGym/3/JJ/2G4XZ4FX8KSV5ISWLBUX9T.uasset
(Stored with Git LFS)
BIN
Pawn_Unreal/Content/__ExternalActors__/Maps/Dev/MAP_ControllerGym/3/JJ/2G4XZ4FX8KSV5ISWLBUX9T.uasset
(Stored with Git LFS)
Binary file not shown.
BIN
Pawn_Unreal/Content/__ExternalActors__/Maps/Dev/MAP_ControllerGym/3/S1/Q0FDQMTTCM0M6RLWXOTPMF.uasset
(Stored with Git LFS)
BIN
Pawn_Unreal/Content/__ExternalActors__/Maps/Dev/MAP_ControllerGym/3/S1/Q0FDQMTTCM0M6RLWXOTPMF.uasset
(Stored with Git LFS)
Binary file not shown.
BIN
Pawn_Unreal/Content/__ExternalActors__/Maps/Dev/MAP_ControllerGym/3/ZC/SPZ5ZSIG7BW3194FWIBEWC.uasset
(Stored with Git LFS)
Normal file
BIN
Pawn_Unreal/Content/__ExternalActors__/Maps/Dev/MAP_ControllerGym/3/ZC/SPZ5ZSIG7BW3194FWIBEWC.uasset
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
Pawn_Unreal/Content/__ExternalActors__/Maps/Dev/MAP_ControllerGym/4/OH/3YZOO5HQPTMDBNJPPM4RV0.uasset
(Stored with Git LFS)
Normal file
BIN
Pawn_Unreal/Content/__ExternalActors__/Maps/Dev/MAP_ControllerGym/4/OH/3YZOO5HQPTMDBNJPPM4RV0.uasset
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
Pawn_Unreal/Content/__ExternalActors__/Maps/Dev/MAP_ControllerGym/7/XC/WIQNHKPM06P8T5BPNH23RN.uasset
(Stored with Git LFS)
BIN
Pawn_Unreal/Content/__ExternalActors__/Maps/Dev/MAP_ControllerGym/7/XC/WIQNHKPM06P8T5BPNH23RN.uasset
(Stored with Git LFS)
Binary file not shown.
BIN
Pawn_Unreal/Content/__ExternalActors__/Maps/Dev/MAP_ControllerGym/9/RQ/JYNZEWOG6SXNE3HGUCSZIE.uasset
(Stored with Git LFS)
Normal file
BIN
Pawn_Unreal/Content/__ExternalActors__/Maps/Dev/MAP_ControllerGym/9/RQ/JYNZEWOG6SXNE3HGUCSZIE.uasset
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
Pawn_Unreal/Content/__ExternalActors__/Maps/Dev/MAP_ControllerGym/9/SL/CVWLA6QDNV8TESDOTZTWDN.uasset
(Stored with Git LFS)
BIN
Pawn_Unreal/Content/__ExternalActors__/Maps/Dev/MAP_ControllerGym/9/SL/CVWLA6QDNV8TESDOTZTWDN.uasset
(Stored with Git LFS)
Binary file not shown.
BIN
Pawn_Unreal/Content/__ExternalActors__/Maps/Dev/MAP_ControllerGym/A/BZ/XZUBN8NU0UZ2W8T2MBWCYN.uasset
(Stored with Git LFS)
Normal file
BIN
Pawn_Unreal/Content/__ExternalActors__/Maps/Dev/MAP_ControllerGym/A/BZ/XZUBN8NU0UZ2W8T2MBWCYN.uasset
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
Pawn_Unreal/Content/__ExternalActors__/Maps/Dev/MAP_ControllerGym/A/U2/4ECO0ADAHJEURYSR8OYVEX.uasset
(Stored with Git LFS)
Normal file
BIN
Pawn_Unreal/Content/__ExternalActors__/Maps/Dev/MAP_ControllerGym/A/U2/4ECO0ADAHJEURYSR8OYVEX.uasset
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
Pawn_Unreal/Content/__ExternalActors__/Maps/Dev/MAP_ControllerGym/C/BU/19EKBOJAPNXX8XDUPL0Z18.uasset
(Stored with Git LFS)
BIN
Pawn_Unreal/Content/__ExternalActors__/Maps/Dev/MAP_ControllerGym/C/BU/19EKBOJAPNXX8XDUPL0Z18.uasset
(Stored with Git LFS)
Binary file not shown.
BIN
Pawn_Unreal/Content/__ExternalActors__/Maps/Dev/MAP_ControllerGym/D/11/8KRHTI8SRC72YR9XJOITVN.uasset
(Stored with Git LFS)
BIN
Pawn_Unreal/Content/__ExternalActors__/Maps/Dev/MAP_ControllerGym/D/11/8KRHTI8SRC72YR9XJOITVN.uasset
(Stored with Git LFS)
Binary file not shown.
BIN
Pawn_Unreal/Content/__ExternalActors__/Maps/Dev/MAP_ControllerGym/D/VD/LJAQY01SJR93NPW0FPCPIL.uasset
(Stored with Git LFS)
Normal file
BIN
Pawn_Unreal/Content/__ExternalActors__/Maps/Dev/MAP_ControllerGym/D/VD/LJAQY01SJR93NPW0FPCPIL.uasset
(Stored with Git LFS)
Normal file
Binary file not shown.
2
Pawn_Unreal/Pawn.sln.DotSettings
Normal file
2
Pawn_Unreal/Pawn.sln.DotSettings
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
|
||||||
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=Platformer/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
|
||||||
2
Pawn_Unreal/Pawn.sln.DotSettings.user
Normal file
2
Pawn_Unreal/Pawn.sln.DotSettings.user
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
|
||||||
|
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=8C1CE801_002DA611_002D3A51_002DBA22_002DD1481FF14826_002Fdl_003ASource_003A_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003FProgram_0020Files_003FEpic_0020Games_003FUE_005F5_002E2_003FEngine_003FSource_002Fd_003ARuntime_002Fd_003AEngine_002Fd_003APrivate_002Fd_003AComponents_002Ff_003ACharacterMovementComponent_002Ecpp/@EntryIndexedValue">ForceIncluded</s:String></wpf:ResourceDictionary>
|
||||||
@ -0,0 +1,18 @@
|
|||||||
|
#include "Characters/PwnCharacterBase.h"
|
||||||
|
|
||||||
|
#include "Characters/PwnCharacterMovementComponent.h"
|
||||||
|
|
||||||
|
APwnCharacterBase::APwnCharacterBase(const FObjectInitializer& ObjectInitializer)
|
||||||
|
: Super(ObjectInitializer.SetDefaultSubobjectClass<UPwnCharacterMovementComponent>(CharacterMovementComponentName)) {
|
||||||
|
PrimaryActorTick.bCanEverTick = true;
|
||||||
|
|
||||||
|
PwnCharacterMovementComponent = CastChecked<UPwnCharacterMovementComponent>(GetCharacterMovement());
|
||||||
|
}
|
||||||
|
|
||||||
|
void APwnCharacterBase::BeginPlay() {
|
||||||
|
Super::BeginPlay();
|
||||||
|
}
|
||||||
|
|
||||||
|
void APwnCharacterBase::Tick(float DeltaTime) {
|
||||||
|
Super::Tick(DeltaTime);
|
||||||
|
}
|
||||||
@ -0,0 +1,299 @@
|
|||||||
|
#include "Characters/PwnCharacterMovementComponent.h"
|
||||||
|
|
||||||
|
#include "Characters/PwnCharacterBase.h"
|
||||||
|
#include "Components/SplineComponent.h"
|
||||||
|
#include "GameplayModes/PwnGameplayModeSubsystem.h"
|
||||||
|
#include "GameplayModes/Combat/PwnCombatPlatformerPath.h"
|
||||||
|
#include "Utils/EngineUtils.h"
|
||||||
|
|
||||||
|
UPwnCharacterMovementComponent::UPwnCharacterMovementComponent() {
|
||||||
|
PrimaryComponentTick.bCanEverTick = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void UPwnCharacterMovementComponent::BeginPlay() {
|
||||||
|
Super::BeginPlay();
|
||||||
|
}
|
||||||
|
|
||||||
|
float UPwnCharacterMovementComponent::GetMaxBrakingDeceleration() const {
|
||||||
|
if (MovementMode == MOVE_Custom) {
|
||||||
|
switch (CustomMovementMode) {
|
||||||
|
case SplineWalking: return BrakingDecelerationWalking;
|
||||||
|
case SplineFalling: return BrakingDecelerationFalling;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Super::GetMaxBrakingDeceleration();
|
||||||
|
}
|
||||||
|
|
||||||
|
float UPwnCharacterMovementComponent::GetMaxSpeed() const {
|
||||||
|
if (MovementMode == MOVE_Custom) {
|
||||||
|
switch (CustomMovementMode) {
|
||||||
|
case SplineWalking: return IsCrouching() ? MaxWalkSpeedCrouched : MaxWalkSpeed;;
|
||||||
|
case SplineFalling: return MaxWalkSpeed;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Super::GetMaxSpeed();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool UPwnCharacterMovementComponent::IsMovingOnGround() const {
|
||||||
|
return Super::IsMovingOnGround() || IsCustomMovementMode(SplineWalking);
|
||||||
|
}
|
||||||
|
|
||||||
|
void UPwnCharacterMovementComponent::EnterSplineFollowMode() {
|
||||||
|
SetMovementMode(MOVE_Custom, SplineWalking);
|
||||||
|
|
||||||
|
const UPwnGameplayModeSubsystem* Subsystem = GetWorld()->GetSubsystem<UPwnGameplayModeSubsystem>();
|
||||||
|
check(Subsystem);
|
||||||
|
|
||||||
|
FVector OutLocation;
|
||||||
|
APwnCombatPlatformerPath* OutCombatPath;
|
||||||
|
float OutDistanceAloneSpline;
|
||||||
|
if (Subsystem->FindClosestCombatPathLocation(UpdatedComponent->GetComponentLocation(), OutLocation, OutCombatPath, OutDistanceAloneSpline)) {
|
||||||
|
DistanceAlongSpline = OutDistanceAloneSpline;
|
||||||
|
CombatPath = OutCombatPath;
|
||||||
|
DotDirection = CombatPath->Reversed ? -1.0f : 1.0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void UPwnCharacterMovementComponent::ExitSplineFollowMode() {
|
||||||
|
SetMovementMode(MOVE_Walking);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool UPwnCharacterMovementComponent::IsCustomMovementMode(const ECustomMovementMode Mode) const {
|
||||||
|
return MovementMode == MOVE_Custom && CustomMovementMode == Mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
void UPwnCharacterMovementComponent::PhysCustom(const float DeltaTime, const int32 Iterations) {
|
||||||
|
Super::PhysCustom(DeltaTime, Iterations);
|
||||||
|
|
||||||
|
switch (CustomMovementMode) {
|
||||||
|
case SplineWalking: PhysSplineFollow(DeltaTime, Iterations);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
UE_LOG(LogTemp, Fatal, TEXT("Invalid custom movement mode"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
UE_DISABLE_OPTIMIZATION
|
||||||
|
|
||||||
|
void UPwnCharacterMovementComponent::PhysSplineFollow(const float DeltaTime, int32 Iterations) {
|
||||||
|
if (DeltaTime < MIN_TICK_TIME) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!CharacterOwner || (!CharacterOwner->Controller && !bRunPhysicsWithNoController && !HasAnimRootMotion() && !CurrentRootMotion.
|
||||||
|
HasOverrideVelocity() && (CharacterOwner->GetLocalRole() != ROLE_SimulatedProxy))) {
|
||||||
|
Acceleration = FVector::ZeroVector;
|
||||||
|
Velocity = FVector::ZeroVector;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!UpdatedComponent->IsQueryCollisionEnabled()) {
|
||||||
|
SetMovementMode(MOVE_Walking);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
bJustTeleported = false;
|
||||||
|
bool bCheckedFall = false;
|
||||||
|
bool bTriedLedgeMove = false;
|
||||||
|
float RemainingTime = DeltaTime;
|
||||||
|
// Perform the move
|
||||||
|
while ((RemainingTime >= MIN_TICK_TIME) && (Iterations < MaxSimulationIterations) && CharacterOwner && (CharacterOwner->Controller ||
|
||||||
|
bRunPhysicsWithNoController || HasAnimRootMotion() || CurrentRootMotion.HasOverrideVelocity() || (CharacterOwner->GetLocalRole() ==
|
||||||
|
ROLE_SimulatedProxy))) {
|
||||||
|
Iterations++;
|
||||||
|
bJustTeleported = false;
|
||||||
|
const float TimeTick = GetSimulationTimeStep(RemainingTime, Iterations);
|
||||||
|
RemainingTime -= TimeTick;
|
||||||
|
|
||||||
|
// Save current values
|
||||||
|
UPrimitiveComponent* const OldBase = GetMovementBase();
|
||||||
|
const FVector PreviousBaseLocation = OldBase != nullptr ? OldBase->GetComponentLocation() : FVector::ZeroVector;
|
||||||
|
const FVector OldLocation = UpdatedComponent->GetComponentLocation();
|
||||||
|
const FFindFloorResult OldFloor = CurrentFloor;
|
||||||
|
const FVector OldVelocity = Velocity;
|
||||||
|
|
||||||
|
RestorePreAdditiveRootMotionVelocity();
|
||||||
|
MaintainHorizontalGroundVelocity();
|
||||||
|
Acceleration.Z = 0.f;
|
||||||
|
|
||||||
|
if (!HasAnimRootMotion() && !CurrentRootMotion.HasOverrideVelocity()) {
|
||||||
|
CalcVelocity(TimeTick, GroundFriction, false, GetMaxBrakingDeceleration());
|
||||||
|
}
|
||||||
|
|
||||||
|
float VelocityDirection = FMath::Sign(Velocity.X) * DotDirection;
|
||||||
|
float NewDistanceAlongSpline = DistanceAlongSpline + VelocityDirection * Velocity.Size() * TimeTick;
|
||||||
|
NewDistanceAlongSpline = FMath::Clamp(NewDistanceAlongSpline, 0.0f, CombatPath->Spline->GetSplineLength());
|
||||||
|
|
||||||
|
FVector TargetLocation = CombatPath->Spline->GetLocationAtDistanceAlongSpline(NewDistanceAlongSpline, ESplineCoordinateSpace::World);
|
||||||
|
TargetLocation.Z = OldLocation.Z;
|
||||||
|
|
||||||
|
FVector Direction = (TargetLocation - OldLocation).GetSafeNormal();
|
||||||
|
|
||||||
|
FHitResult MyHit;
|
||||||
|
|
||||||
|
float DistanceOffset = NewDistanceAlongSpline - DistanceAlongSpline;
|
||||||
|
FVector Delta2 = TargetLocation - OldLocation;
|
||||||
|
SafeMoveUpdatedComponent(Delta2, UpdatedComponent->GetComponentQuat(), true, MyHit);
|
||||||
|
if (MyHit.Time < 1.0f) {
|
||||||
|
HandleImpact(MyHit, TimeTick, Delta2);
|
||||||
|
//DistanceAlongSpline += InputDotDirection * Velocity.Size() * TimeTick * MyHit.Distance;
|
||||||
|
} else {
|
||||||
|
DistanceAlongSpline = NewDistanceAlongSpline;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (OldLocation == UpdatedComponent->GetComponentLocation()) {
|
||||||
|
Velocity = FVector::Zero();
|
||||||
|
}
|
||||||
|
|
||||||
|
//continue;
|
||||||
|
|
||||||
|
//Velocity = OldVelocity;
|
||||||
|
// Apply acceleration
|
||||||
|
if (!HasAnimRootMotion() && !CurrentRootMotion.HasOverrideVelocity()) {
|
||||||
|
//CalcVelocity(TimeTick, GroundFriction, false, GetMaxBrakingDeceleration());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IsFalling()) {
|
||||||
|
// Root motion could have put us into Falling.
|
||||||
|
// No movement has taken place this movement tick so we pass on full time/past iteration count
|
||||||
|
StartNewPhysics(RemainingTime + TimeTick, Iterations - 1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compute move parameters
|
||||||
|
const FVector MoveVelocity = Velocity;
|
||||||
|
const FVector Delta = TimeTick * MoveVelocity;
|
||||||
|
const bool bZeroDelta = Delta.IsNearlyZero();
|
||||||
|
FStepDownResult StepDownResult;
|
||||||
|
|
||||||
|
if (bZeroDelta) {
|
||||||
|
RemainingTime = 0.f;
|
||||||
|
} else {
|
||||||
|
/*// try to move forward
|
||||||
|
MoveAlongFloor(MoveVelocity, TimeTick, &StepDownResult);
|
||||||
|
|
||||||
|
if (IsFalling()) {
|
||||||
|
// pawn decided to jump up
|
||||||
|
const float DesiredDist = Delta.Size();
|
||||||
|
if (DesiredDist > UE_KINDA_SMALL_NUMBER) {
|
||||||
|
const float ActualDist = (UpdatedComponent->GetComponentLocation() - OldLocation).Size2D();
|
||||||
|
RemainingTime += TimeTick * (1.f - FMath::Min(1.f, ActualDist / DesiredDist));
|
||||||
|
}
|
||||||
|
StartNewPhysics(RemainingTime, Iterations);
|
||||||
|
return;
|
||||||
|
} else if (IsSwimming()) //just entered water
|
||||||
|
{
|
||||||
|
StartSwimming(OldLocation, OldVelocity, TimeTick, RemainingTime, Iterations);
|
||||||
|
return;
|
||||||
|
}*/
|
||||||
|
}
|
||||||
|
|
||||||
|
continue;
|
||||||
|
// Update floor.
|
||||||
|
// StepUp might have already done it for us.
|
||||||
|
if (StepDownResult.bComputedFloor) {
|
||||||
|
CurrentFloor = StepDownResult.FloorResult;
|
||||||
|
} else {
|
||||||
|
FindFloor(UpdatedComponent->GetComponentLocation(), CurrentFloor, bZeroDelta, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
// check for ledges here
|
||||||
|
const bool bCheckLedges = !CanWalkOffLedges();
|
||||||
|
if (bCheckLedges && !CurrentFloor.IsWalkableFloor()) {
|
||||||
|
// calculate possible alternate movement
|
||||||
|
const FVector GravDir = FVector(0.f, 0.f, -1.f);
|
||||||
|
const FVector NewDelta = bTriedLedgeMove ? FVector::ZeroVector : GetLedgeMove(OldLocation, Delta, GravDir);
|
||||||
|
if (!NewDelta.IsZero()) {
|
||||||
|
// first revert this move
|
||||||
|
RevertMove(OldLocation, OldBase, PreviousBaseLocation, OldFloor, false);
|
||||||
|
|
||||||
|
// avoid repeated ledge moves if the first one fails
|
||||||
|
bTriedLedgeMove = true;
|
||||||
|
|
||||||
|
// Try new movement direction
|
||||||
|
Velocity = NewDelta / TimeTick;
|
||||||
|
RemainingTime += TimeTick;
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
// see if it is OK to jump
|
||||||
|
// @todo collision : only thing that can be problem is that oldbase has world collision on
|
||||||
|
bool bMustJump = bZeroDelta || (OldBase == NULL || (!OldBase->IsQueryCollisionEnabled() &&
|
||||||
|
MovementBaseUtility::IsDynamicBase(OldBase)));
|
||||||
|
if ((bMustJump || !bCheckedFall) && CheckFall(OldFloor, CurrentFloor.HitResult, Delta, OldLocation, RemainingTime, TimeTick,
|
||||||
|
Iterations, bMustJump)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
bCheckedFall = true;
|
||||||
|
|
||||||
|
// revert this move
|
||||||
|
RevertMove(OldLocation, OldBase, PreviousBaseLocation, OldFloor, true);
|
||||||
|
RemainingTime = 0.f;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Validate the floor check
|
||||||
|
if (CurrentFloor.IsWalkableFloor()) {
|
||||||
|
if (ShouldCatchAir(OldFloor, CurrentFloor)) {
|
||||||
|
HandleWalkingOffLedge(OldFloor.HitResult.ImpactNormal, OldFloor.HitResult.Normal, OldLocation, TimeTick);
|
||||||
|
if (IsMovingOnGround()) {
|
||||||
|
// If still walking, then fall. If not, assume the user set a different mode they want to keep.
|
||||||
|
StartFalling(Iterations, RemainingTime, TimeTick, Delta, OldLocation);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
AdjustFloorHeight();
|
||||||
|
SetBase(CurrentFloor.HitResult.Component.Get(), CurrentFloor.HitResult.BoneName);
|
||||||
|
} else if (CurrentFloor.HitResult.bStartPenetrating && RemainingTime <= 0.f) {
|
||||||
|
// The floor check failed because it started in penetration
|
||||||
|
// We do not want to try to move downward because the downward sweep failed, rather we'd like to try to pop out of the floor.
|
||||||
|
FHitResult Hit(CurrentFloor.HitResult);
|
||||||
|
Hit.TraceEnd = Hit.TraceStart + FVector(0.f, 0.f, MAX_FLOOR_DIST);
|
||||||
|
const FVector RequestedAdjustment = GetPenetrationAdjustment(Hit);
|
||||||
|
ResolvePenetration(RequestedAdjustment, Hit, UpdatedComponent->GetComponentQuat());
|
||||||
|
bForceNextFloorCheck = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if just entered water
|
||||||
|
if (IsSwimming()) {
|
||||||
|
StartSwimming(OldLocation, Velocity, TimeTick, RemainingTime, Iterations);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// See if we need to start falling.
|
||||||
|
if (!CurrentFloor.IsWalkableFloor() && !CurrentFloor.HitResult.bStartPenetrating) {
|
||||||
|
const bool bMustJump = bJustTeleported || bZeroDelta || (OldBase == NULL || (!OldBase->IsQueryCollisionEnabled() &&
|
||||||
|
MovementBaseUtility::IsDynamicBase(OldBase)));
|
||||||
|
if ((bMustJump || !bCheckedFall) && CheckFall(OldFloor, CurrentFloor.HitResult, Delta, OldLocation, RemainingTime, TimeTick,
|
||||||
|
Iterations, bMustJump)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
bCheckedFall = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allow overlap events and such to change physics state and velocity
|
||||||
|
/*if (IsMovingOnGround()) {
|
||||||
|
// Make velocity reflect actual move
|
||||||
|
if (!bJustTeleported && !HasAnimRootMotion() && !CurrentRootMotion.HasOverrideVelocity() && TimeTick >= MIN_TICK_TIME) {
|
||||||
|
// TODO-RootMotionSource: Allow this to happen during partial override Velocity, but only set allowed axes?
|
||||||
|
Velocity = (UpdatedComponent->GetComponentLocation() - OldLocation) / TimeTick;
|
||||||
|
MaintainHorizontalGroundVelocity();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we didn't move at all this iteration then abort (since future iterations will also be stuck).
|
||||||
|
if (UpdatedComponent->GetComponentLocation() == OldLocation) {
|
||||||
|
RemainingTime = 0.f;
|
||||||
|
break;
|
||||||
|
}*/
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IsMovingOnGround()) {
|
||||||
|
MaintainHorizontalGroundVelocity();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
UE_ENABLE_OPTIMIZATION
|
||||||
@ -0,0 +1,30 @@
|
|||||||
|
#include "GameplayModes/Combat/PwnCombatPlatformerPath.h"
|
||||||
|
|
||||||
|
#include "Components/SplineComponent.h"
|
||||||
|
#include "GameplayModes/PwnGameplayModeSubsystem.h"
|
||||||
|
|
||||||
|
APwnCombatPlatformerPath::APwnCombatPlatformerPath() {
|
||||||
|
PrimaryActorTick.bCanEverTick = false;
|
||||||
|
|
||||||
|
Spline = CreateDefaultSubobject<USplineComponent>(TEXT("Spline"));
|
||||||
|
SetRootComponent(Spline);
|
||||||
|
|
||||||
|
#if WITH_EDITORONLY_DATA
|
||||||
|
Spline->EditorSelectedSplineSegmentColor = FColor::FromHex("EBA30AFF");
|
||||||
|
Spline->EditorUnselectedSplineSegmentColor = FColor::Red;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void APwnCombatPlatformerPath::BeginPlay() {
|
||||||
|
UPwnGameplayModeSubsystem* Subsystem = GetWorld()->GetSubsystem<UPwnGameplayModeSubsystem>();
|
||||||
|
check(Subsystem);
|
||||||
|
Subsystem->RegisterCombatPath(this);
|
||||||
|
Super::BeginPlay();
|
||||||
|
}
|
||||||
|
|
||||||
|
void APwnCombatPlatformerPath::EndPlay(const EEndPlayReason::Type EndPlayReason) {
|
||||||
|
if (UPwnGameplayModeSubsystem* Subsystem = GetWorld()->GetSubsystem<UPwnGameplayModeSubsystem>()) {
|
||||||
|
Subsystem->UnregisterCombatPath(this);
|
||||||
|
}
|
||||||
|
Super::EndPlay(EndPlayReason);
|
||||||
|
}
|
||||||
@ -1,5 +1,8 @@
|
|||||||
#include "GameplayModes/PwnGameplayModeSubsystem.h"
|
#include "GameplayModes/PwnGameplayModeSubsystem.h"
|
||||||
|
|
||||||
|
#include "Components/SplineComponent.h"
|
||||||
|
#include "GameplayModes/Combat/PwnCombatPlatformerPath.h"
|
||||||
|
|
||||||
void UPwnGameplayModeSubsystem::Initialize(FSubsystemCollectionBase& Collection) {
|
void UPwnGameplayModeSubsystem::Initialize(FSubsystemCollectionBase& Collection) {
|
||||||
Super::Initialize(Collection);
|
Super::Initialize(Collection);
|
||||||
CurrentGameplayMode = EPwnGameplayMode::Narrative;
|
CurrentGameplayMode = EPwnGameplayMode::Narrative;
|
||||||
@ -25,6 +28,46 @@ EPwnGameplayMode UPwnGameplayModeSubsystem::GetCurrentGameplayMode() const {
|
|||||||
bool UPwnGameplayModeSubsystem::IsNarrativeMode() const {
|
bool UPwnGameplayModeSubsystem::IsNarrativeMode() const {
|
||||||
return CurrentGameplayMode == EPwnGameplayMode::Narrative;
|
return CurrentGameplayMode == EPwnGameplayMode::Narrative;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool UPwnGameplayModeSubsystem::IsCombatMode() const {
|
bool UPwnGameplayModeSubsystem::IsCombatMode() const {
|
||||||
return CurrentGameplayMode == EPwnGameplayMode::Combat;
|
return CurrentGameplayMode == EPwnGameplayMode::Combat;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void UPwnGameplayModeSubsystem::RegisterCombatPath(APwnCombatPlatformerPath* CombatPath) {
|
||||||
|
CombatPaths.Add(CombatPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
void UPwnGameplayModeSubsystem::UnregisterCombatPath(APwnCombatPlatformerPath* CombatPath) {
|
||||||
|
CombatPaths.Remove(CombatPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool UPwnGameplayModeSubsystem::FindClosestCombatPathLocation(const FVector& Location, FVector& OutCombatPathLocation,
|
||||||
|
APwnCombatPlatformerPath*& OutCombatPath, float& OutDistanceAlongSpline) const {
|
||||||
|
float ShortestDistance = FLT_MAX;
|
||||||
|
float ClosestKey = 0.0f;
|
||||||
|
FVector ClosestLocation = FVector::ZeroVector;
|
||||||
|
APwnCombatPlatformerPath* ClosestCombatPath = nullptr;
|
||||||
|
bool Found = false;
|
||||||
|
|
||||||
|
for (APwnCombatPlatformerPath* CombatPath : CombatPaths) {
|
||||||
|
const USplineComponent* CurrentSpline = CombatPath->Spline;
|
||||||
|
|
||||||
|
const float CurrentKey = CurrentSpline->FindInputKeyClosestToWorldLocation(Location);
|
||||||
|
FVector CurrentLocation = CurrentSpline->GetLocationAtSplineInputKey(CurrentKey, ESplineCoordinateSpace::World);
|
||||||
|
const float CurrentDistance = FVector::DistSquared(Location, CurrentLocation);
|
||||||
|
if (CurrentDistance < ShortestDistance) {
|
||||||
|
ShortestDistance = CurrentDistance;
|
||||||
|
ClosestKey = CurrentKey;
|
||||||
|
ClosestLocation = CurrentLocation;
|
||||||
|
ClosestCombatPath = CombatPath;
|
||||||
|
Found = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Found) {
|
||||||
|
OutCombatPathLocation = ClosestLocation;
|
||||||
|
OutCombatPath = ClosestCombatPath;
|
||||||
|
OutDistanceAlongSpline = OutCombatPath->Spline->GetDistanceAlongSplineAtSplineInputKey(ClosestKey);
|
||||||
|
}
|
||||||
|
return Found;
|
||||||
|
}
|
||||||
|
|||||||
25
Pawn_Unreal/Source/Pawn/Public/Characters/PwnCharacterBase.h
Normal file
25
Pawn_Unreal/Source/Pawn/Public/Characters/PwnCharacterBase.h
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "CoreMinimal.h"
|
||||||
|
#include "GameFramework/Character.h"
|
||||||
|
#include "PwnCharacterBase.generated.h"
|
||||||
|
|
||||||
|
class UPwnCharacterMovementComponent;
|
||||||
|
|
||||||
|
UCLASS()
|
||||||
|
class PAWN_API APwnCharacterBase : public ACharacter {
|
||||||
|
GENERATED_BODY()
|
||||||
|
|
||||||
|
public:
|
||||||
|
APwnCharacterBase(const FObjectInitializer& ObjectInitializer);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void BeginPlay() override;
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual void Tick(float DeltaTime) override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category="Components")
|
||||||
|
TObjectPtr<UPwnCharacterMovementComponent> PwnCharacterMovementComponent;
|
||||||
|
};
|
||||||
@ -0,0 +1,59 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "CoreMinimal.h"
|
||||||
|
#include "GameFramework/CharacterMovementComponent.h"
|
||||||
|
#include "PwnCharacterMovementComponent.generated.h"
|
||||||
|
|
||||||
|
class APwnCombatPlatformerPath;
|
||||||
|
|
||||||
|
UENUM(BlueprintType)
|
||||||
|
enum ECustomMovementMode : uint8 {
|
||||||
|
None UMETA(Hidden),
|
||||||
|
SplineWalking,
|
||||||
|
SplineFalling
|
||||||
|
};
|
||||||
|
|
||||||
|
UCLASS(meta=(BlueprintSpawnableComponent))
|
||||||
|
class PAWN_API UPwnCharacterMovementComponent : public UCharacterMovementComponent {
|
||||||
|
GENERATED_BODY()
|
||||||
|
|
||||||
|
public:
|
||||||
|
UPwnCharacterMovementComponent();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void BeginPlay() override;
|
||||||
|
|
||||||
|
virtual float GetMaxBrakingDeceleration() const override;
|
||||||
|
|
||||||
|
virtual float GetMaxSpeed() const override;
|
||||||
|
|
||||||
|
virtual bool IsMovingOnGround() const override;
|
||||||
|
|
||||||
|
public:
|
||||||
|
UFUNCTION(BlueprintCallable, Category="CharacterMovement")
|
||||||
|
void EnterSplineFollowMode();
|
||||||
|
|
||||||
|
UFUNCTION(BlueprintCallable, Category="CharacterMovement")
|
||||||
|
void ExitSplineFollowMode();
|
||||||
|
|
||||||
|
UFUNCTION(BlueprintCallable, Category="CharacterMovement")
|
||||||
|
bool IsCustomMovementMode(const ECustomMovementMode Mode) const;
|
||||||
|
|
||||||
|
virtual void PhysCustom(const float DeltaTime, int32 Iterations) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void PhysSplineFollow(const float DeltaTime, int32 Iterations);
|
||||||
|
|
||||||
|
public:
|
||||||
|
UPROPERTY(BlueprintReadOnly)
|
||||||
|
TObjectPtr<APwnCombatPlatformerPath> CombatPath;
|
||||||
|
|
||||||
|
UPROPERTY(BlueprintReadOnly)
|
||||||
|
float DistanceAlongSpline;
|
||||||
|
|
||||||
|
UPROPERTY(BlueprintReadOnly)
|
||||||
|
float DotDirection;
|
||||||
|
|
||||||
|
UPROPERTY(BlueprintReadWrite)
|
||||||
|
float Input;
|
||||||
|
};
|
||||||
@ -0,0 +1,30 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "CoreMinimal.h"
|
||||||
|
#include "GameFramework/Actor.h"
|
||||||
|
#include "PwnCombatPlatformerPath.generated.h"
|
||||||
|
|
||||||
|
class USplineComponent;
|
||||||
|
|
||||||
|
UCLASS()
|
||||||
|
class PAWN_API APwnCombatPlatformerPath : public AActor {
|
||||||
|
GENERATED_BODY()
|
||||||
|
|
||||||
|
public:
|
||||||
|
APwnCombatPlatformerPath();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void BeginPlay() override;
|
||||||
|
|
||||||
|
virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override;
|
||||||
|
|
||||||
|
public:
|
||||||
|
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category="Components")
|
||||||
|
TObjectPtr<USplineComponent> Spline;
|
||||||
|
|
||||||
|
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category="Combat Platformer Path")
|
||||||
|
bool Reversed;
|
||||||
|
|
||||||
|
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category="Combat Platformer Path")
|
||||||
|
bool SwapCamera;
|
||||||
|
};
|
||||||
@ -4,6 +4,8 @@
|
|||||||
#include "Subsystems/WorldSubsystem.h"
|
#include "Subsystems/WorldSubsystem.h"
|
||||||
#include "PwnGameplayModeSubsystem.generated.h"
|
#include "PwnGameplayModeSubsystem.generated.h"
|
||||||
|
|
||||||
|
class APwnCombatPlatformerPath;
|
||||||
|
|
||||||
UENUM(BlueprintType, DisplayName = "Gameplay Mode")
|
UENUM(BlueprintType, DisplayName = "Gameplay Mode")
|
||||||
enum class EPwnGameplayMode : uint8 {
|
enum class EPwnGameplayMode : uint8 {
|
||||||
Narrative,
|
Narrative,
|
||||||
@ -33,10 +35,24 @@ public:
|
|||||||
UFUNCTION(BlueprintCallable, BlueprintPure, Category="Gameplay Modes")
|
UFUNCTION(BlueprintCallable, BlueprintPure, Category="Gameplay Modes")
|
||||||
bool IsCombatMode() const;
|
bool IsCombatMode() const;
|
||||||
|
|
||||||
|
UFUNCTION()
|
||||||
|
void RegisterCombatPath(APwnCombatPlatformerPath* CombatPath);
|
||||||
|
|
||||||
|
UFUNCTION()
|
||||||
|
void UnregisterCombatPath(APwnCombatPlatformerPath* CombatPath);
|
||||||
|
|
||||||
|
UFUNCTION()
|
||||||
|
bool FindClosestCombatPathLocation(const FVector& Location, FVector& OutCombatPathLocation, APwnCombatPlatformerPath*& OutCombatPath,
|
||||||
|
float& OutDistanceAlongSpline) const;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
UPROPERTY(BlueprintAssignable)
|
UPROPERTY(BlueprintAssignable)
|
||||||
FGameplayModeChangedDelegate OnGameplayModeChanged;
|
FGameplayModeChangedDelegate OnGameplayModeChanged;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
UPROPERTY()
|
||||||
EPwnGameplayMode CurrentGameplayMode;
|
EPwnGameplayMode CurrentGameplayMode;
|
||||||
|
|
||||||
|
UPROPERTY()
|
||||||
|
TArray<TObjectPtr<APwnCombatPlatformerPath>> CombatPaths;
|
||||||
};
|
};
|
||||||
|
|||||||
9
Pawn_Unreal/Source/Pawn/Public/Utils/EngineUtils.h
Normal file
9
Pawn_Unreal/Source/Pawn/Public/Utils/EngineUtils.h
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#define PRINT_STRING(Key, Time, Color, Content, ...) GEngine->AddOnScreenDebugMessage(Key, Time, Color, FString::Printf(TEXT(Content), __VA_ARGS__));
|
||||||
|
#define PRINT_STRING_GENERIC(Color, Content, ...) PRINT_STRING(-1, 4.0f, Color, Content, __VA_ARGS__);
|
||||||
|
#define PRINT_STRING_WHITE(Content, ...) PRINT_STRING_GENERIC(FColor::White, Content, __VA_ARGS__);
|
||||||
|
#define PRINT_STRING_BLUE(Content, ...) PRINT_STRING_GENERIC(FColor::Blue, Content, __VA_ARGS__);
|
||||||
|
#define PRINT_STRING_RED(Content, ...) PRINT_STRING_GENERIC(FColor::Red, Content, __VA_ARGS__);
|
||||||
|
#define PRINT_STRING_YELLOW(Content, ...) PRINT_STRING_GENERIC(FColor::Yellow, Content, __VA_ARGS__);
|
||||||
|
#define PRINT_STRING_GREEN(Content, ...) PRINT_STRING_GENERIC(FColor::Green, Content, __VA_ARGS__);
|
||||||
Loading…
x
Reference in New Issue
Block a user