From 353117f97a15ea70304e6f1e13c658f16f122f6c Mon Sep 17 00:00:00 2001 From: lionarius Date: Wed, 8 Jan 2025 05:05:04 +0300 Subject: [PATCH] torque --- .../src/Component/MVC/MovementComponent.cs | 15 ++++ .../src/Component/Physics/DragComponent.cs | 16 ++++ .../Component/Physics/RigidbodyComponent.cs | 88 +++++++++++++++++++ .../Component/Util/PlayerMovementComponent.cs | 17 ++-- .../src/Scene/Play/Prefab/PlayerPrefab.cs | 9 +- 5 files changed, 132 insertions(+), 13 deletions(-) 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),