[code] add character rotation to movement component
parent
01ef4abe50
commit
df3deef577
|
|
@ -10,6 +10,7 @@ import { Cast } from '#root/UE/Cast.ts';
|
|||
import type { Controller } from '#root/UE/Controller.ts';
|
||||
import { EnhancedInputLocalPlayerSubsystem } from '#root/UE/EnhancedInputLocalPlayerSubsystem.ts';
|
||||
import type { Float } from '#root/UE/Float.ts';
|
||||
import { MathLibrary } from '#root/UE/MathLibrary.ts';
|
||||
import { Pawn } from '#root/UE/Pawn.ts';
|
||||
import type { PlayerController } from '#root/UE/PlayerController.ts';
|
||||
import { Rotator } from '#root/UE/Rotator.ts';
|
||||
|
|
@ -94,14 +95,43 @@ export class BP_MainCharacter extends Pawn {
|
|||
|
||||
/**
|
||||
* Process movement input for ground-based movement
|
||||
* @param actionValueX - Horizontal movement input value (-1 to 1)
|
||||
* @param actionValueY - Vertical movement input value (-1 to 1)
|
||||
* @param ActionValueX - Horizontal movement input value (-1 to 1)
|
||||
* @param ActionValueY - Vertical movement input value (-1 to 1)
|
||||
*/
|
||||
EnhancedInputActionMoveTriggered(
|
||||
ActionValueX: Float,
|
||||
ActionValueY: Float
|
||||
): void {
|
||||
const CalculateResultMovementInputVector = (
|
||||
rightVector: Vector,
|
||||
forwardVector: Vector,
|
||||
actionValueX: Float,
|
||||
actionValueY: Float
|
||||
): void {
|
||||
this.CurrentMovementInput = new Vector(actionValueY, actionValueX, 0);
|
||||
): Vector => {
|
||||
const vec1 = new Vector(
|
||||
rightVector.X * actionValueX,
|
||||
rightVector.Y * actionValueX,
|
||||
0
|
||||
);
|
||||
const vec2 = new Vector(
|
||||
forwardVector.X * actionValueY,
|
||||
forwardVector.Y * actionValueY,
|
||||
0
|
||||
);
|
||||
|
||||
return new Vector(vec1.X + vec2.X, vec1.Y + vec2.Y, 0);
|
||||
};
|
||||
|
||||
this.CurrentMovementInput = CalculateResultMovementInputVector(
|
||||
MathLibrary.GetRightVector(
|
||||
this.GetControlRotation().roll,
|
||||
0,
|
||||
this.GetControlRotation().yaw
|
||||
),
|
||||
MathLibrary.GetForwardVector(0, 0, this.GetControlRotation().yaw),
|
||||
ActionValueX,
|
||||
ActionValueY
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -167,7 +197,7 @@ export class BP_MainCharacter extends Pawn {
|
|||
this.CurrentMovementInput,
|
||||
DeltaTime
|
||||
);
|
||||
this.ApplyMovementToActor();
|
||||
this.ApplyMovementAndRotation();
|
||||
}
|
||||
|
||||
// ════════════════════════════════════════════════════════════════════════════════════════
|
||||
|
|
@ -178,7 +208,9 @@ export class BP_MainCharacter extends Pawn {
|
|||
* Apply calculated movement velocity to actor position
|
||||
* @category Movement Application
|
||||
*/
|
||||
private ApplyMovementToActor(): void {
|
||||
private ApplyMovementAndRotation(): void {
|
||||
this.SetActorRotation(this.MovementComponent.CurrentRotation);
|
||||
|
||||
const CalculateNewLocation = (
|
||||
currentLocation: Vector,
|
||||
velocity: Vector
|
||||
|
|
|
|||
BIN
Content/Blueprints/BP_MainCharacter.uasset (Stored with Git LFS)
BIN
Content/Blueprints/BP_MainCharacter.uasset (Stored with Git LFS)
Binary file not shown.
BIN
Content/Debug/Components/AC_DebugHUD.uasset (Stored with Git LFS)
BIN
Content/Debug/Components/AC_DebugHUD.uasset (Stored with Git LFS)
Binary file not shown.
|
|
@ -8,6 +8,7 @@ import type { S_MovementConstants } from '#root/Movement/Structs/S_MovementConst
|
|||
import { ActorComponent } from '#root/UE/ActorComponent.ts';
|
||||
import type { Float } from '#root/UE/Float.ts';
|
||||
import { MathLibrary } from '#root/UE/MathLibrary.ts';
|
||||
import { Rotator } from '#root/UE/Rotator.ts';
|
||||
import { Vector } from '#root/UE/Vector.ts';
|
||||
|
||||
/**
|
||||
|
|
@ -132,6 +133,9 @@ export class AC_Movement extends ActorComponent {
|
|||
if (this.IsInitialized) {
|
||||
this.InputMagnitude = MathLibrary.VectorLength(InputVector);
|
||||
|
||||
this.TargetRotation = this.CalculateTargetRotation(InputVector);
|
||||
this.UpdateCharacterRotation(DeltaTime);
|
||||
|
||||
// Only process movement on walkable surfaces
|
||||
if (this.IsSurfaceWalkable(this.CurrentSurface) && this.IsGrounded) {
|
||||
this.ProcessGroundMovement(InputVector, DeltaTime);
|
||||
|
|
@ -252,6 +256,93 @@ export class AC_Movement extends ActorComponent {
|
|||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate target rotation based on movement direction
|
||||
* Determines what rotation character should have based on movement
|
||||
* @param MovementDirection - Camera-relative movement direction from Blueprint
|
||||
* @returns Target rotation for character
|
||||
* @pure true
|
||||
* @category Character Rotation
|
||||
*/
|
||||
public CalculateTargetRotation(MovementDirection: Vector): Rotator {
|
||||
const TargetYaw = (
|
||||
movementDirectionX: Float,
|
||||
movementDirectionY: Float
|
||||
): Float =>
|
||||
MathLibrary.RadiansToDegrees(
|
||||
MathLibrary.Atan2(movementDirectionY, movementDirectionX)
|
||||
);
|
||||
|
||||
if (MathLibrary.VectorLength(MovementDirection) < 0.01) {
|
||||
// No movement, maintain current target rotation
|
||||
return this.TargetRotation;
|
||||
}
|
||||
|
||||
// Character should remain level (pitch = 0, roll = 0, only yaw changes)
|
||||
return new Rotator(
|
||||
0,
|
||||
TargetYaw(MovementDirection.X, MovementDirection.Y),
|
||||
0
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update character rotation towards target
|
||||
* Uses instant rotation approach similar to Zelda: BotW
|
||||
* @param DeltaTime - Time since last frame
|
||||
* @category Character Rotation
|
||||
*/
|
||||
public UpdateCharacterRotation(DeltaTime: Float): void {
|
||||
if (this.ShouldRotateToMovement) {
|
||||
const ShouldRotate = (): boolean =>
|
||||
this.CurrentSpeed >= this.MinSpeedForRotation;
|
||||
|
||||
if (ShouldRotate()) {
|
||||
let yawDifference = this.CurrentRotation.yaw - this.TargetRotation.yaw;
|
||||
|
||||
if (yawDifference > 180) {
|
||||
yawDifference = yawDifference - 360;
|
||||
} else if (yawDifference < -180) {
|
||||
yawDifference = yawDifference + 360;
|
||||
}
|
||||
|
||||
const NewYaw = (
|
||||
currentYaw: Float,
|
||||
clampedRotationAmount: Float,
|
||||
coef: Float
|
||||
): Float => currentYaw + clampedRotationAmount * coef;
|
||||
|
||||
const ClampedRotationAmount = (deltaTime: Float): Float =>
|
||||
MathLibrary.Min(
|
||||
this.RotationSpeed * deltaTime,
|
||||
MathLibrary.abs(yawDifference)
|
||||
);
|
||||
|
||||
this.RotationDelta = MathLibrary.abs(yawDifference);
|
||||
|
||||
if (this.RotationDelta > 1) {
|
||||
this.IsCharacterRotating = true;
|
||||
|
||||
this.CurrentRotation = new Rotator(
|
||||
0,
|
||||
NewYaw(
|
||||
this.CurrentRotation.yaw,
|
||||
ClampedRotationAmount(DeltaTime),
|
||||
yawDifference > 0 ? -1 : 1
|
||||
),
|
||||
0
|
||||
);
|
||||
} else {
|
||||
this.IsCharacterRotating = false;
|
||||
this.CurrentRotation = this.TargetRotation;
|
||||
}
|
||||
} else {
|
||||
this.IsCharacterRotating = false;
|
||||
this.RotationDelta = 0.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize movement system with angle conversion
|
||||
* Converts degree thresholds to radians for runtime performance
|
||||
|
|
@ -359,4 +450,56 @@ export class AC_Movement extends ActorComponent {
|
|||
* @category Movement State
|
||||
*/
|
||||
public CurrentSpeed: Float = 0.0;
|
||||
|
||||
/**
|
||||
* Rotation speed in degrees per second
|
||||
* Controls how fast character rotates towards movement direction
|
||||
* @category Character Rotation Config
|
||||
* @instanceEditable true
|
||||
*/
|
||||
public RotationSpeed: Float = 720.0;
|
||||
|
||||
/**
|
||||
* Should character rotate when moving
|
||||
* Allows disabling rotation system if needed
|
||||
* @category Character Rotation Config
|
||||
* @instanceEditable true
|
||||
*/
|
||||
public ShouldRotateToMovement: boolean = true;
|
||||
|
||||
/**
|
||||
* Minimum movement speed to trigger rotation
|
||||
* Prevents character from rotating during very slow movement
|
||||
* @category Character Rotation Config
|
||||
* @instanceEditable true
|
||||
*/
|
||||
public MinSpeedForRotation: Float = 50.0;
|
||||
|
||||
/**
|
||||
* Current character rotation
|
||||
* Used for smooth interpolation to target rotation
|
||||
* @category Character Rotation State
|
||||
*/
|
||||
public CurrentRotation: Rotator = new Rotator(0, 0, 0);
|
||||
|
||||
/**
|
||||
* Target character rotation
|
||||
* Calculated based on movement direction and camera orientation
|
||||
* @category Character Rotation State
|
||||
*/
|
||||
public TargetRotation: Rotator = new Rotator(0, 0, 0);
|
||||
|
||||
/**
|
||||
* Whether character is currently rotating
|
||||
* Used for animation and debug purposes
|
||||
* @category Character Rotation State
|
||||
*/
|
||||
public IsCharacterRotating: boolean = false;
|
||||
|
||||
/**
|
||||
* Angular difference between current and target rotation
|
||||
* Used for determining rotation completion and debug display
|
||||
* @category Character Rotation State
|
||||
*/
|
||||
public RotationDelta: Float = 0.0;
|
||||
}
|
||||
|
|
|
|||
BIN
Content/Movement/Components/AC_Movement.uasset (Stored with Git LFS)
BIN
Content/Movement/Components/AC_Movement.uasset (Stored with Git LFS)
Binary file not shown.
|
|
@ -1,6 +1,7 @@
|
|||
// UE/Actor.ts
|
||||
|
||||
import { Name } from '#root/UE/Name.ts';
|
||||
import { Rotator } from '#root/UE/Rotator.ts';
|
||||
import { UEObject } from '#root/UE/UEObject.ts';
|
||||
import { Vector } from '#root/UE/Vector.ts';
|
||||
|
||||
|
|
@ -18,6 +19,14 @@ export class Actor extends UEObject {
|
|||
// Implementation for setting actor location
|
||||
}
|
||||
|
||||
public SetActorRotation(
|
||||
NewRotation: Rotator = new Rotator(),
|
||||
TeleportPhysics: boolean = false
|
||||
): void {
|
||||
console.log(NewRotation, TeleportPhysics);
|
||||
// Implementation for setting actor rotation
|
||||
}
|
||||
|
||||
public GetActorLocation(): Vector {
|
||||
return new Vector(); // Placeholder implementation
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,6 +35,18 @@ class MathLibraryClass extends BlueprintFunctionLibrary {
|
|||
return (Degrees * Math.PI) / 180;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert radians to degrees
|
||||
* @param Radians - Angle in radians
|
||||
* @returns Angle in degrees
|
||||
* @example
|
||||
* // Convert π/2 radians to degrees
|
||||
* RadiansToDegrees(Math.PI / 2) // returns 90
|
||||
*/
|
||||
public RadiansToDegrees(Radians: Float): Float {
|
||||
return (Radians * 180) / Math.PI;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate sine of angle in radians
|
||||
* @param Value - Angle in radians
|
||||
|
|
@ -62,6 +74,16 @@ class MathLibraryClass extends BlueprintFunctionLibrary {
|
|||
return Math.acos(Value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate arctangent2 of Y and X
|
||||
* @param Y - Y coordinate
|
||||
* @param X - X coordinate
|
||||
* @returns Angle in radians (-π to π)
|
||||
*/
|
||||
public Atan2(Y: Float, X: Float): Float {
|
||||
return Math.atan2(Y, X);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate dot product of two vectors
|
||||
* @param Vector1 - First vector
|
||||
|
|
@ -207,6 +229,69 @@ class MathLibraryClass extends BlueprintFunctionLibrary {
|
|||
|
||||
return new Vector(0, 0, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the minimum of two float values
|
||||
* @param A - First value
|
||||
* @param B - Second value
|
||||
* @returns Minimum value
|
||||
* @example
|
||||
* // Minimum of 3 and 5
|
||||
* Min(3, 5) // returns 3
|
||||
*/
|
||||
public Min(A: Float, B: Float): Float {
|
||||
return Math.min(A, B);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get right vector from roll, pitch, yaw angles
|
||||
* @param Roll - Rotation around forward axis in radians
|
||||
* @param Pitch - Rotation around right axis in radians
|
||||
* @param Yaw - Rotation around up axis in radians
|
||||
* @returns Right direction vector
|
||||
* @example
|
||||
* // Right vector for no rotation
|
||||
* GetRightVector(0, 0, 0) // returns Vector(1,0,0)
|
||||
*/
|
||||
public GetRightVector(
|
||||
Roll: Float = 0,
|
||||
Pitch: Float = 0,
|
||||
Yaw: Float = 0
|
||||
): Vector {
|
||||
const CP = this.Cos(Pitch);
|
||||
const SP = this.Sin(Pitch);
|
||||
const CY = this.Cos(Yaw);
|
||||
const SY = this.Sin(Yaw);
|
||||
|
||||
console.log(Roll);
|
||||
|
||||
return new Vector(CP * CY, CP * SY, SP);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get forward vector from roll, pitch, yaw angles
|
||||
* @param Roll - Rotation around forward axis in radians
|
||||
* @param Pitch - Rotation around right axis in radians
|
||||
* @param Yaw - Rotation around up axis in radians
|
||||
* @returns Forward direction vector
|
||||
* @example
|
||||
* // Forward vector for no rotation
|
||||
* GetForwardVector(0, 0, 0) // returns Vector(1,0,0)
|
||||
*/
|
||||
public GetForwardVector(
|
||||
Roll: Float = 0,
|
||||
Pitch: Float = 0,
|
||||
Yaw: Float = 0
|
||||
): Vector {
|
||||
const CP = this.Cos(Pitch);
|
||||
const SP = this.Sin(Pitch);
|
||||
const CY = this.Cos(Yaw);
|
||||
const SY = this.Sin(Yaw);
|
||||
|
||||
console.log(Roll);
|
||||
|
||||
return new Vector(CP * CY, CP * SY, SP);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
import { Actor } from '#root/UE/Actor.ts';
|
||||
import { Controller } from '#root/UE/Controller.ts';
|
||||
import { Name } from '#root/UE/Name.ts';
|
||||
import { Rotator } from '#root/UE/Rotator.ts';
|
||||
import { UEObject } from '#root/UE/UEObject.ts';
|
||||
|
||||
export class Pawn extends Actor {
|
||||
|
|
@ -13,4 +14,8 @@ export class Pawn extends Actor {
|
|||
public GetController(): Controller {
|
||||
return new Controller(this);
|
||||
}
|
||||
|
||||
public GetControlRotation(): Rotator {
|
||||
return new Rotator();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue