diff --git a/DoomDeathmatch/src/Component/MVC/MovementComponent.cs b/DoomDeathmatch/src/Component/MVC/MovementComponent.cs
index 60484f4..2e287e6 100644
--- a/DoomDeathmatch/src/Component/MVC/MovementComponent.cs
+++ b/DoomDeathmatch/src/Component/MVC/MovementComponent.cs
@@ -13,6 +13,11 @@ public class MovementComponent : Engine.Scene.Component.Component
///
public float Speed { get; set; } = 10.0f;
+ ///
+ /// The rotation speed in degrees per second.
+ ///
+ public float RotationSpeed { get; set; } = 90.0f;
+
///
/// The rigidbody component for the game object.
///
@@ -40,4 +45,14 @@ public class MovementComponent : Engine.Scene.Component.Component
{
_rigidbody.Force += _dragComponent.Drag * Speed * parDirection.Normalized();
}
+
+ ///
+ /// Applies rotational torque to the object around a specified axis.
+ ///
+ /// The axis of rotation.
+ public void ApplyRotation(Vector3 parAxis)
+ {
+ var radiansPerSecond = MathHelper.DegreesToRadians(RotationSpeed);
+ _rigidbody.Torque += _dragComponent.RotationalDrag * radiansPerSecond * parAxis.Normalized();
+ }
}
\ No newline at end of file
diff --git a/DoomDeathmatch/src/Component/Physics/DragComponent.cs b/DoomDeathmatch/src/Component/Physics/DragComponent.cs
index 8d865f3..33dcc38 100644
--- a/DoomDeathmatch/src/Component/Physics/DragComponent.cs
+++ b/DoomDeathmatch/src/Component/Physics/DragComponent.cs
@@ -12,11 +12,21 @@ public class DragComponent : Engine.Scene.Component.Component
///
public float Drag { get; set; } = 1f;
+ ///
+ /// The rotational drag coefficient applied to the angular velocity of the rigidbody.
+ ///
+ public float RotationalDrag { get; set; } = 1f;
+
///
/// A multiplier applied to each axis of the velocity when calculating drag.
///
public Vector3 Multiplier { get; set; } = Vector3.One;
+ ///
+ /// A multiplier applied to each axis of the angular velocity when calculating rotational drag.
+ ///
+ public Vector3 RotationalMultiplier { get; set; } = Vector3.One;
+
///
/// The rigidbody to apply drag to.
///
@@ -31,6 +41,12 @@ public class DragComponent : Engine.Scene.Component.Component
public override void Update(double parDeltaTime)
{
+ if (_rigidbody.IsStatic)
+ {
+ return;
+ }
+
_rigidbody.Force -= Drag * (_rigidbody.Velocity * Multiplier);
+ _rigidbody.Torque -= RotationalDrag * (_rigidbody.AngularVelocity * RotationalMultiplier);
}
}
\ No newline at end of file
diff --git a/DoomDeathmatch/src/Component/Physics/RigidbodyComponent.cs b/DoomDeathmatch/src/Component/Physics/RigidbodyComponent.cs
index 19fb26b..837ebde 100644
--- a/DoomDeathmatch/src/Component/Physics/RigidbodyComponent.cs
+++ b/DoomDeathmatch/src/Component/Physics/RigidbodyComponent.cs
@@ -12,6 +12,12 @@ public class RigidbodyComponent : Engine.Scene.Component.Component
///
public float Mass { get; set; } = 1.0f;
+ ///
+ /// The moment of inertia of the rigidbody.
+ /// For simplicity, this assumes a scalar value, suitable for symmetric objects.
+ ///
+ public float MomentOfInertia { get; set; } = 1.0f;
+
///
/// Indicates whether the rigidbody is static and unaffected by forces.
///
@@ -34,6 +40,23 @@ public class RigidbodyComponent : Engine.Scene.Component.Component
}
}
+ ///
+ /// The torque currently applied to the rigidbody.
+ ///
+ public Vector3 Torque
+ {
+ get => _torque;
+ set
+ {
+ if (IsStatic)
+ {
+ return;
+ }
+
+ _torque = value;
+ }
+ }
+
///
/// The velocity of the rigidbody.
///
@@ -51,6 +74,23 @@ public class RigidbodyComponent : Engine.Scene.Component.Component
}
}
+ ///
+ /// The angular velocity of the rigidbody.
+ ///
+ public Vector3 AngularVelocity
+ {
+ get => _angularVelocity;
+ set
+ {
+ if (IsStatic)
+ {
+ return;
+ }
+
+ _angularVelocity = value;
+ }
+ }
+
///
/// The force currently applied to the rigidbody.
///
@@ -66,6 +106,21 @@ public class RigidbodyComponent : Engine.Scene.Component.Component
///
private Vector3 _velocity = Vector3.Zero;
+ ///
+ /// The torque currently applied to the rigidbody.
+ ///
+ private Vector3 _torque = Vector3.Zero;
+
+ ///
+ /// The angular acceleration of the rigidbody.
+ ///
+ private Vector3 _angularAcceleration = Vector3.Zero;
+
+ ///
+ /// The angular velocity of the rigidbody.
+ ///
+ private Vector3 _angularVelocity = Vector3.Zero;
+
public override void PostUpdate(double parDeltaTime)
{
if (IsStatic)
@@ -73,10 +128,43 @@ public class RigidbodyComponent : Engine.Scene.Component.Component
return;
}
+ ApplyForce(parDeltaTime);
+ ApplyTorque(parDeltaTime);
+ }
+
+ ///
+ /// Applies force to the rigidbody.
+ ///
+ /// The time in seconds since the last update.
+ private void ApplyForce(double parDeltaTime)
+ {
_acceleration = Force / Mass;
Velocity += _acceleration * (float)parDeltaTime;
GameObject.Transform.Translation += Velocity * (float)parDeltaTime;
Force = Vector3.Zero;
}
+
+ ///
+ /// Applies torque to the rigidbody.
+ ///
+ /// The time in seconds since the last update.
+ private void ApplyTorque(double parDeltaTime)
+ {
+ _angularAcceleration = Torque / MomentOfInertia;
+ AngularVelocity += _angularAcceleration * (float)parDeltaTime;
+
+ // Update rotation using quaternion math
+ var rotation = GameObject.Transform.Rotation;
+ var angularVelocityQuat = new Quaternion(AngularVelocity, 0.0f);
+
+ // Quaternion rotation integration: Δq = 0.5 * angularVelocityQuat * rotation
+ var deltaRotation = 0.5f * angularVelocityQuat * rotation;
+ rotation += deltaRotation * (float)parDeltaTime;
+ rotation.Normalize(); // Ensure the quaternion remains normalized
+
+ GameObject.Transform.Rotation = rotation;
+
+ Torque = Vector3.Zero;
+ }
}
\ No newline at end of file
diff --git a/DoomDeathmatch/src/Component/Util/PlayerMovementComponent.cs b/DoomDeathmatch/src/Component/Util/PlayerMovementComponent.cs
index 646bf2b..c13f1d5 100644
--- a/DoomDeathmatch/src/Component/Util/PlayerMovementComponent.cs
+++ b/DoomDeathmatch/src/Component/Util/PlayerMovementComponent.cs
@@ -10,11 +10,6 @@ namespace DoomDeathmatch.Component.Util;
///
public class PlayerMovementComponent : Engine.Scene.Component.Component
{
- ///
- /// The speed at which the player rotates in degrees per second.
- ///
- public float RotationSpeed { get; set; } = 110.0f;
-
///
/// Handles input from the player.
///
@@ -35,7 +30,7 @@ public class PlayerMovementComponent : Engine.Scene.Component.Component
public override void Update(double parDeltaTime)
{
var movement = Vector3.Zero;
- var rotation = 0.0f;
+ var rotation = 0;
if (_inputHandler.IsKeyPressed(KeyboardButtonCode.W))
{
@@ -59,12 +54,12 @@ public class PlayerMovementComponent : Engine.Scene.Component.Component
if (_inputHandler.IsKeyPressed(KeyboardButtonCode.Q))
{
- rotation += RotationSpeed;
+ rotation = 1;
}
if (_inputHandler.IsKeyPressed(KeyboardButtonCode.E))
{
- rotation -= RotationSpeed;
+ rotation = -1;
}
if (movement.LengthSquared > 0)
@@ -75,7 +70,9 @@ public class PlayerMovementComponent : Engine.Scene.Component.Component
_movementComponent.ApplyMovement(movement);
}
- GameObject.Transform.Rotation *= Quaternion.FromAxisAngle(Vector3.UnitZ, MathHelper.DegreesToRadians(rotation) *
- (float)parDeltaTime);
+ if (rotation != 0)
+ {
+ _movementComponent.ApplyRotation(Vector3.UnitZ * rotation);
+ }
}
}
\ No newline at end of file
diff --git a/DoomDeathmatch/src/Scene/Play/Prefab/PlayerPrefab.cs b/DoomDeathmatch/src/Scene/Play/Prefab/PlayerPrefab.cs
index 845645c..edd578a 100644
--- a/DoomDeathmatch/src/Scene/Play/Prefab/PlayerPrefab.cs
+++ b/DoomDeathmatch/src/Scene/Play/Prefab/PlayerPrefab.cs
@@ -19,7 +19,7 @@ public static class PlayerPrefab
perspectiveCameraObject.Transform.Translation.Z = 2;
var playerObject = GameObjectUtil.CreateGameObject(parScene, [
new RigidbodyComponent(),
- new DragComponent { Drag = 10f, Multiplier = new Vector3(1, 1, 0) },
+ new DragComponent { Drag = 10f, RotationalDrag = 10f, },
new AABBColliderComponent
{
@@ -29,8 +29,11 @@ public static class PlayerPrefab
ExcludeColliderCollideGroups = { "player" }
},
- new MovementComponent { Speed = GameConstants.PLAYER_BASE_SPEED },
- new PlayerMovementComponent { RotationSpeed = GameConstants.PLAYER_BASE_ROTATION_SPEED },
+ new MovementComponent
+ {
+ Speed = GameConstants.PLAYER_BASE_SPEED, RotationSpeed = GameConstants.PLAYER_BASE_ROTATION_SPEED
+ },
+ new PlayerMovementComponent(),
new PlayerController(perspectiveCamera),