Skip to content

Instantly share code, notes, and snippets.

@KroniK907
Created February 24, 2018 01:19
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save KroniK907/291ca69d875e36db53bc0718fa21fc55 to your computer and use it in GitHub Desktop.
Save KroniK907/291ca69d875e36db53bc0718fa21fc55 to your computer and use it in GitHub Desktop.
Quake 3 Movement in UE4
/* Copyright (C) Terence-Lee 'Zinglish' Davis
* Written by Terence-Lee 'Zinglish' Davis <zinglish[at]gmail.com>
*/
#include "PlayerMoveComponent.h"
#include ".h"
#include "Player.h"
#include "PlayerCollisionComponent.h"
#include "Runtime/Core/Public/GenericPlatform/GenericPlatformMath.h"
#include "Engine.h"
// Sets default values for this component's properties
UPlayerMoveComponent::UPlayerMoveComponent(const FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer)
{
// Set this component to be initialized when the game starts, and to be ticked every frame. You can turn these features
// off to improve performance if you don't need them.
PrimaryComponentTick.bCanEverTick = true;
}
// Called when the game starts
void UPlayerMoveComponent::BeginPlay()
{
Super::BeginPlay();
Origin = Player->GetTransform().GetLocation();
}
// Called every frame
void UPlayerMoveComponent::TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction)
{
Delta = DeltaTime;
if(Player)
{
// Grab the input from the player
WishMove = Player->ConsumeMovementInput();
if(MovementType == EMovementType::Spectate)
{
FlyMove();
Player->Collider->SetWorldLocation(Origin);
return;
}
QueueJump();
CollisionComponent->TraceGround();
if(CollisionComponent->CanGroundMove)
GroundMove();
else
AirMove();
CollisionComponent->TraceGround();
// Record the ground velocity and speed of the player
GroundVelocity.X = PlayerVelocity.X;
GroundVelocity.Y = PlayerVelocity.Y;
GroundSpeed = GroundVelocity.Size();
Player->Collider->SetWorldLocation(Origin);
// Logs
/*GEngine->AddOnScreenDebugMessage(20, 0.01f, FColor::Red, FString::Printf(TEXT("Position [X: %.6f, Y: %.6f, Z: %.6f]"), GetOrigin().X, GetOrigin().Y, GetOrigin().Z));
GEngine->AddOnScreenDebugMessage(2, 0.01f, FColor::Green, FString::Printf(TEXT("Is Grounded [%d]"), CollisionComponent->IsGrounded));
GEngine->AddOnScreenDebugMessage(0, 0.01f, FColor::Green, FString::Printf(TEXT("Desired Velocity [X: %.2f, Y: %.2f, Z: %.2f]"), PlayerVelocity.X, PlayerVelocity.Y, PlayerVelocity.Z));
GEngine->AddOnScreenDebugMessage(1, 0.01f, FColor::Green, FString::Printf(TEXT("Desired Linear Speed [%.2fups]"), GroundSpeed));*/
}
else
{
GEngine->AddOnScreenDebugMessage(0, 0.01f, FColor::Red, TEXT("NO OWNER"));
}
}
void UPlayerMoveComponent::ApplyFriction()
{
float speed;
float newSpeed;
float control;
float drop = 0.0f;
speed = PlayerVelocity.Size();
if(CollisionComponent->IsGrounded)
{
control = speed < GroundAcceleration ? GroundDampening : speed;
drop = control * Friction * Delta;
}
if(MovementType == EMovementType::Spectate)
drop += speed * SpectatorFriction * Delta;
newSpeed = speed - drop;
if(newSpeed < 0.f)
newSpeed = 0.f;
if(speed > 0.f)
newSpeed /= speed;
PlayerVelocity.X *= newSpeed;
PlayerVelocity.Y *= newSpeed;
}
void UPlayerMoveComponent::GroundMove()
{
if(CheckJump())
{
AirMove();
return;
}
ApplyFriction();
FVector wishDirection;
FVector wishvel = FVector::ZeroVector;
FVector TransformForward = Player->ForwardVector;
FVector TransformRight = Player->RightVector;
wishvel.X = TransformForward.X * WishMove.X + TransformRight.X * WishMove.Y;
wishvel.Y = TransformForward.Y * WishMove.X + TransformRight.Y * WishMove.Y;
wishvel.Z = TransformForward.Z * WishMove.X + TransformRight.Z * WishMove.Y;
wishDirection = wishvel;
float wishSpeed = wishDirection.Size();
wishDirection.Normalize();
wishSpeed *= GroundMaxSpeed;
ApplyAcceleration(wishDirection, wishSpeed, GroundAcceleration);
float vel = PlayerVelocity.Size();
ClipVelocity(PlayerVelocity, CollisionComponent->GroundTrace.ImpactNormal, PlayerVelocity, CollisionComponent->Overclip);
PlayerVelocity.Normalize();
PlayerVelocity *= vel;
// Don't do anything if standing still
if(PlayerVelocity.X == 0.f && PlayerVelocity.Y == 0.f)
return;
CollisionComponent->StepSlideMove(false);
}
void UPlayerMoveComponent::AirMove()
{
FVector wishDirection;
FVector currentVelocity;
float dynamicAcceleration;
//ApplyFriction();
// Set target direction for the character body to its inital state.
wishDirection.X = Player->ForwardVector.X * WishMove.X + Player->RightVector.X * WishMove.Y;
wishDirection.Y = Player->ForwardVector.Y * WishMove.X + Player->RightVector.Y * WishMove.Y;
wishDirection.Z = 0.f;
float wishSpeed = wishDirection.Size();
wishDirection.Normalize();
wishSpeed *= AirMaxSpeed;
// CPM: Aircontrol
float wishSpeed2 = wishSpeed;
if (FVector::DotProduct(PlayerVelocity, wishDirection) < 0)
dynamicAcceleration = AirStopAccelerate;
if (WishMove.X == 0.f && WishMove.Y != 0.0f)
{
if (wishSpeed > AirStrafeSpeed)
wishSpeed = AirStrafeSpeed;
dynamicAcceleration = AirStrafeAcceleration;
}
ApplyAcceleration(wishDirection, wishSpeed, dynamicAcceleration);
//AirControl(wishDirection, wishSpeed);
// Apply gravity
PlayerVelocity.Z -= Gravity * Delta;
CollisionComponent->StepSlideMove(true);
}
void UPlayerMoveComponent::AirControl(FVector WishDirection, float WishSpeed)
{
float zspeed, speed, dot, k;
// Can't control movement if not moving forward or backward
if(WishMove.X != 0.f || WishSpeed == 0.f)
return;
zspeed = PlayerVelocity.Z;
PlayerVelocity.Z = 0;
speed = PlayerVelocity.Size();
PlayerVelocity.Normalize();
dot = FVector::DotProduct(PlayerVelocity, WishDirection);
k = 32.f;
k *= CPMAirControl * dot * dot * Delta;
// We can't change direction while slowing down
if(dot > 0)
{
PlayerVelocity.X = PlayerVelocity.X * speed + WishDirection.X * k;
PlayerVelocity.Y = PlayerVelocity.Y * speed + WishDirection.Y * k;
PlayerVelocity.Normalize();
}
PlayerVelocity.X *= speed;
PlayerVelocity.Y *= speed;
PlayerVelocity.Z = zspeed;
}
void UPlayerMoveComponent::ApplyAcceleration(FVector WishDirection, float WishSpeed, float DynamicAcceleration)
{
float AddSpeed;
float AccelerationSpeed;
float CurrentSpeed;
CurrentSpeed = FVector::DotProduct(WishDirection, PlayerVelocity);
AddSpeed = WishSpeed - CurrentSpeed;
if(AddSpeed <= 0.f)
return;
AccelerationSpeed = DynamicAcceleration * Delta * WishSpeed;
if(AccelerationSpeed > AddSpeed)
AccelerationSpeed = AddSpeed;
PlayerVelocity.X += AccelerationSpeed * WishDirection.X;
PlayerVelocity.Y += AccelerationSpeed * WishDirection.Y;
PlayerVelocity.Z += AccelerationSpeed * WishDirection.Z;
}
void UPlayerMoveComponent::FlyMove()
{
float speed, drop, friction, control, newspeed;
FVector wishvel;
float fmove, smove;
FVector wishdir;
float wishspeed;
// float scale;
// Set the view height
//pm->ps->viewheight = DEFAULT_VIEWHEIGHT;
// friction
speed = PlayerVelocity.Size();
if(speed < 1)
{
PlayerVelocity = FVector::ZeroVector;
}
else
{
drop = 0;
friction = Friction * 1.5; // extra friction
control = speed < SpectatorStopSpeed ? SpectatorStopSpeed : speed;
drop += control*friction * Delta;
// scale the velocity
newspeed = speed - drop;
if (newspeed < 0)
newspeed = 0;
newspeed /= speed;
PlayerVelocity *= newspeed;
}
// accelerate
//scale = PM_CmdScale(&pm->cmd);
fmove = WishMove.X;
smove = WishMove.Y;
wishvel.X = Player->ForwardVector.X * fmove + Player->RightVector.X * smove;
wishvel.Y = Player->ForwardVector.Y * fmove + Player->RightVector.Y * smove;
wishvel.Z += 0.f;
wishdir = wishvel;
wishspeed = wishdir.Size();
wishdir.Normalize();
wishspeed *= 1000.f;
ApplyAcceleration(wishdir, wishspeed, SpectatorAccelerate);
// move
Player->CollisionComponent->VectorMA(GetOrigin(), Delta, PlayerVelocity, Origin);
Origin.Z = 0.f;
}
bool UPlayerMoveComponent::CheckJump()
{
if(WishJump)
{
PlayerVelocity.Z = JumpForce;
Player->PlayJumpSound();
WishJump = false;
return true;
}
return false;
}
void UPlayerMoveComponent::QueueJump()
{
if(Player->JumpInput && !WishJump)
WishJump = true;
if(!Player->JumpInput)
WishJump = false;
}
float UPlayerMoveComponent::CmdScale()
{
int max;
float total;
float scale;
max = FGenericPlatformMath::Abs(WishMove.X);
if (FGenericPlatformMath::Abs(WishMove.Y) > max) {
max = FGenericPlatformMath::Abs(WishMove.Y);
}
/*if (abs(cmd->upmove) > max) {
max = abs(cmd->upmove);
}*/
if (!max) {
return 0;
}
total = sqrt(WishMove.X * WishMove.X + WishMove.Y * WishMove.Y);
scale = (float)GroundSpeed * max / (127.0 * total);
return scale;
}
void UPlayerMoveComponent::ClipVelocity(FVector In, FVector Normal, FVector& Out, float Overbounce)
{
float Backoff = FVector::DotProduct(In, Normal);
if (Backoff < 0.f)
Backoff *= Overbounce;
else
Backoff /= Overbounce;
Out.X = In.X - (Normal.X * Backoff);
Out.Y = In.Y - (Normal.Y * Backoff);
Out.Z = In.Z - (Normal.Z * Backoff);
}
void UPlayerMoveComponent::SetOrigin(FVector Position)
{
Origin = Position;
}
FVector UPlayerMoveComponent::GetOrigin()
{
return Origin;
}
/* Copyright (C) Terence-Lee 'Zinglish' Davis
* Written by Terence-Lee 'Zinglish' Davis <zinglish[at]gmail.com>
*/
#pragma once
#include "GameFramework/PawnMovementComponent.h"
#include "PlayerMoveComponent.generated.h"
class APlayer;
class UPlayerCollisionComponent;
UENUM(BlueprintType)
enum class EMovementType : uint8
{
Fly,
Spectate,
Normal
};
UCLASS(ClassGroup = (Custom), meta = (BlueprintSpawnableComponent))
class _API UPlayerMoveComponent : public UPawnMovementComponent
{
GENERATED_BODY()
public:
UPlayerMoveComponent(const FObjectInitializer& ObjectInitializer = FObjectInitializer::Get());
/** Character this belongs to */
APlayer* Player;
/** Collision component */
UPlayerCollisionComponent* CollisionComponent;
virtual void BeginPlay() override;
virtual void TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction *ThisTickFunction) override;
public:
float Delta;
FVector2D WishMove;
bool WishJump;
FVector PlayerVelocity;
bool IsGrounded;
FVector Origin = FVector::ZeroVector;
FVector GroundVelocity = FVector::ZeroVector;
float GroundSpeed = 0.f;
EMovementType MovementType = EMovementType::Normal;
public:
/** Custom gravity scale. Gravity is multiplied by this amount for the character */
UPROPERTY(Category = "General Movement", EditAnywhere, BlueprintReadWrite)
float Gravity = 20.f;
/** Amount of jumping force the player has, does not represent absolute jump height */
UPROPERTY(Category = "General Movement", EditAnywhere, BlueprintReadWrite)
float JumpForce = 8.f;
/** Ground friction */
UPROPERTY(Category = "General Movement", EditAnywhere, BlueprintReadWrite)
float Friction = 6.f;
/** The rate at which the player stops when on the ground */
UPROPERTY(Category = "Ground Movement", EditAnywhere, BlueprintReadWrite)
float GroundStopSpeed = 100.f;
/** The maximum speed the player can travel while on the ground */
UPROPERTY(Category = "Ground Movement", EditAnywhere, BlueprintReadWrite)
float GroundMaxSpeed = 8.f;
/** The rate at which the player gains speed while on the ground */
UPROPERTY(Category = "Ground Movement", EditAnywhere, BlueprintReadWrite)
float GroundAcceleration = 15.0f;
/** The rate at which the player loses speed while on the ground */
UPROPERTY(Category = "Ground Movement", EditAnywhere, BlueprintReadWrite)
float GroundDampening = 8.f;
/** The maximum speed the player can achieve while not strafe jumping */
UPROPERTY(Category = "Air Movement", EditAnywhere, BlueprintReadWrite)
float AirMaxSpeed = 7.f;
/** */
UPROPERTY(Category = "Air Movement", EditAnywhere, BlueprintReadWrite)
float AirStopAccelerate = 2.5f;
/** The maximum speed the player can achieve when strafing, but not actually strafe jumping */
UPROPERTY(Category = "Air Movement", EditAnywhere, BlueprintReadWrite)
float AirStrafeSpeed = 4.f;
/** The rate at which the player gains speed to achieve Air Strafe Speed */
UPROPERTY(Category = "Air Movement", EditAnywhere, BlueprintReadWrite)
float AirStrafeAcceleration = 10.f;
/** The amount of air control the player has */
UPROPERTY(Category = "Air Movement", EditAnywhere, BlueprintReadWrite)
float CPMAirControl = 2.f;
/* Friction for spectator modes */
UPROPERTY(Category = "General Movement", EditAnywhere, BlueprintReadWrite)
float SpectatorFriction = 6.f;
UPROPERTY(Category = "General Movement", EditAnywhere, BlueprintReadWrite)
float SpectatorAccelerate = 10.f;
UPROPERTY(Category = "General Movement", EditAnywhere, BlueprintReadWrite)
float SpectatorStopSpeed = 100.f;
public:
void PlayerMoveSingle();
void GroundMove();
void ApplyFriction();
void AirMove();
bool CheckJump();
void QueueJump();
void FlyMove();
void ApplyAcceleration(FVector WishDirection, float WishSpeed, float DynamicAcceleration);
void AirControl(FVector WishDirection, float WishSpeed);
void ApplyGravity();
float CmdScale();
void ClipVelocity(FVector In, FVector Normal, FVector& Out, float Overbounce);
public:
void SetOrigin(FVector Position);
FVector GetOrigin();
};
@xardas110
Copy link

Hey, can you upload your "PlayerCollisionComponent.h". I'm trying to make this work for me too, but I lack a few functions that you have not uploaded :(

@Rikoshet-234
Copy link

the same issue, i need PlayerCollisionComponent.h to made it works. Can you please upload it ? if you still have that ofc...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment