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
|
||||
bEnableMotionControls=True
|
||||
bFilterInputByPlatformUser=False
|
||||
bEnableInputDeviceSubsystem=True
|
||||
bShouldFlushPressedKeysOnViewportFocusLost=True
|
||||
bEnableDynamicComponentInputBinding=True
|
||||
bAlwaysShowTouchInterface=False
|
||||
bShowConsoleOnFourFingerTap=True
|
||||
bEnableGestureRecognizer=False
|
||||
@ -85,4 +87,5 @@ DefaultTouchInterface=/Engine/MobileResources/HUD/DefaultVirtualJoysticks.Defaul
|
||||
-ConsoleKeys=Tilde
|
||||
+ConsoleKeys=Tilde
|
||||
+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 "Components/SplineComponent.h"
|
||||
#include "GameplayModes/Combat/PwnCombatPlatformerPath.h"
|
||||
|
||||
void UPwnGameplayModeSubsystem::Initialize(FSubsystemCollectionBase& Collection) {
|
||||
Super::Initialize(Collection);
|
||||
CurrentGameplayMode = EPwnGameplayMode::Narrative;
|
||||
@ -25,6 +28,46 @@ EPwnGameplayMode UPwnGameplayModeSubsystem::GetCurrentGameplayMode() const {
|
||||
bool UPwnGameplayModeSubsystem::IsNarrativeMode() const {
|
||||
return CurrentGameplayMode == EPwnGameplayMode::Narrative;
|
||||
}
|
||||
|
||||
bool UPwnGameplayModeSubsystem::IsCombatMode() const {
|
||||
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 "PwnGameplayModeSubsystem.generated.h"
|
||||
|
||||
class APwnCombatPlatformerPath;
|
||||
|
||||
UENUM(BlueprintType, DisplayName = "Gameplay Mode")
|
||||
enum class EPwnGameplayMode : uint8 {
|
||||
Narrative,
|
||||
@ -33,10 +35,24 @@ public:
|
||||
UFUNCTION(BlueprintCallable, BlueprintPure, Category="Gameplay Modes")
|
||||
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:
|
||||
UPROPERTY(BlueprintAssignable)
|
||||
FGameplayModeChangedDelegate OnGameplayModeChanged;
|
||||
|
||||
private:
|
||||
UPROPERTY()
|
||||
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