mirror of
https://github.com/jcreek/CosmicClash.git
synced 2026-07-12 18:43:49 +00:00
feat(*): Add much better ship controls
This commit is contained in:
@@ -0,0 +1,186 @@
|
||||
# 🚀 Cosmic Clash Flight Manual
|
||||
|
||||
Welcome to space, pilot! This guide will teach you everything you need to know about piloting your ship in the vast cosmos.
|
||||
|
||||
## 🎮 Control Schemes
|
||||
|
||||
### Keyboard Controls
|
||||
|
||||
#### Translation (Movement)
|
||||
|
||||
- `W` - Forward Thrust (Main Engines)
|
||||
- `S` - Reverse Thrust (Retro Engines)
|
||||
- `A` - Strafe Left (Port Thrusters)
|
||||
- `D` - Strafe Right (Starboard Thrusters)
|
||||
- `E` - Thrust Up (Dorsal Thrusters)
|
||||
- `Q` - Thrust Down (Ventral Thrusters)
|
||||
- `Shift` - Turbo Boost (Forward Only)
|
||||
|
||||
#### Rotation (Attitude Control)
|
||||
|
||||
- `J` - Turn Left (Yaw Left)
|
||||
- `L` - Turn Right (Yaw Right)
|
||||
- `I` - Pitch Up (Nose Up)
|
||||
- `K` - Pitch Down (Nose Down)
|
||||
- `U` - Roll Left (Bank Left)
|
||||
- `O` - Roll Right (Bank Right)
|
||||
|
||||
### Controller Controls
|
||||
|
||||
#### Translation
|
||||
|
||||
- Left Stick - Strafe (Left/Right) + Thrust (Forward/Back)
|
||||
- Right Trigger - Forward Thrust
|
||||
- Left Trigger - Reverse Thrust
|
||||
- Face Buttons - Up/Down Thrust
|
||||
|
||||
#### Rotation
|
||||
|
||||
- Right Stick - Pitch/Yaw
|
||||
- Shoulder Buttons - Roll
|
||||
- `A Button` - Turbo Boost
|
||||
|
||||
## 🛸 Basic Flight Principles
|
||||
|
||||
### Understanding Your Ship
|
||||
|
||||
Your ship is a **realistic space vehicle** with the following characteristics:
|
||||
|
||||
- **Momentum Conservation**: You keep moving even when not thrusting
|
||||
- **Independent Rotation**: Your ship can face any direction while moving in another
|
||||
- **Thruster-Based Movement**: Different thrusters provide different amounts of force
|
||||
|
||||
### Thruster Systems
|
||||
|
||||
1. **Main Engines** (Forward/Reverse): Most powerful, used for primary acceleration
|
||||
2. **Maneuvering Thrusters** (Strafe/Vertical): Less powerful, for precise positioning
|
||||
3. **Attitude Control** (Rotation): Independent rotational control around all three axes
|
||||
|
||||
## 🎯 Flight Techniques
|
||||
|
||||
### Beginner Maneuvers
|
||||
|
||||
#### Basic Movement
|
||||
|
||||
1. **Forward Flight**: Hold `W` to accelerate forward
|
||||
2. **Turning**: Use `J`/`L` to turn left/right while moving
|
||||
3. **Stopping**: Turn around 180° and thrust forward to decelerate
|
||||
4. **Hovering**: Use vertical thrusters (`E`/`Q`) to maintain altitude
|
||||
|
||||
#### Camera Control
|
||||
|
||||
- **Ball Cam**: Press `Enter` to toggle ball tracking camera
|
||||
- **Ship Cam**: Normal follow camera that looks where your ship points
|
||||
|
||||
### Intermediate Maneuvers
|
||||
|
||||
#### Efficient Movement
|
||||
|
||||
1. **Momentum Management**: Coast when possible to conserve energy
|
||||
2. **Precision Landing**: Use gentle bursts of opposing thrust
|
||||
3. **Quick Turns**: Combine rotation with strafe thrusters for sharp direction changes
|
||||
|
||||
#### Combat Positioning
|
||||
|
||||
1. **Strafing**: Move sideways while keeping guns on target
|
||||
2. **Evasive Maneuvers**: Unpredictable movement patterns using all thrusters
|
||||
|
||||
### Advanced Techniques
|
||||
|
||||
#### Orbital Mechanics
|
||||
|
||||
1. **Prograde Burn**: Thrust in direction of movement to speed up
|
||||
2. **Retrograde Burn**: Thrust opposite to movement to slow down
|
||||
3. **Radial Burns**: Thrust perpendicular to movement to change orbit
|
||||
|
||||
#### Expert Maneuvers
|
||||
|
||||
1. **Flip and Burn**:
|
||||
|
||||
- Accelerate forward until at desired speed
|
||||
- Rotate 180° while maintaining momentum
|
||||
- Fire main engines to decelerate efficiently
|
||||
- Most fuel-efficient way to stop
|
||||
|
||||
2. **Translation Sliding**:
|
||||
|
||||
- Build up forward momentum
|
||||
- Use strafe thrusters to "slide" sideways
|
||||
- Maintain forward velocity while moving laterally
|
||||
|
||||
3. **Zero-G Ballet**:
|
||||
- Combine all rotation axes for complex orientation changes
|
||||
- Use momentum to coast through tight spaces
|
||||
- Master the "six degrees of freedom"
|
||||
|
||||
## 🎮 Ball Cam vs Ship Cam
|
||||
|
||||
### Ball Cam Mode (`Enter` to toggle)
|
||||
|
||||
- **Camera**: Always looks toward the ball
|
||||
- **Ship Control**: Based on ship orientation (NOT camera view)
|
||||
- **Best For**: Tracking the ball during gameplay
|
||||
- **Challenge**: Movement direction may not match what you're looking at
|
||||
|
||||
### Ship Cam Mode
|
||||
|
||||
- **Camera**: Looks where your ship is pointing
|
||||
- **Ship Control**: Intuitive - forward is where you're looking
|
||||
- **Best For**: Precise navigation and docking
|
||||
- **Advantage**: What you see is where you'll go
|
||||
|
||||
## ⚡ Energy Management
|
||||
|
||||
### Turbo System
|
||||
|
||||
- **Activation**: Hold `Shift` (keyboard) or `A` (controller) while thrusting forward
|
||||
- **Effect**: 2.5x thrust multiplier on main engines only
|
||||
- **Strategy**: Use for quick acceleration or emergency maneuvers
|
||||
|
||||
### Thrust Efficiency
|
||||
|
||||
- **Main Engines**: Most powerful, use for primary movement
|
||||
- **Maneuvering Thrusters**: Less powerful but more precise
|
||||
- **Conservation**: Coast on momentum when possible
|
||||
|
||||
## 🏆 Mastery Tips
|
||||
|
||||
### "Easy to Learn, Hard to Master"
|
||||
|
||||
1. **Start Simple**: Learn basic forward movement and turning
|
||||
2. **Add Complexity**: Gradually incorporate strafe and vertical movement
|
||||
3. **Master Physics**: Understand momentum and how forces combine
|
||||
4. **Think in 3D**: Space has no "up" - use all six degrees of freedom
|
||||
|
||||
### Skill Development Path
|
||||
|
||||
1. **Novice**: Can fly forward and turn
|
||||
2. **Pilot**: Comfortable with all basic movements
|
||||
3. **Ace**: Uses momentum and efficient maneuvering
|
||||
4. **Commander**: Masters complex orbital mechanics and combat flying
|
||||
|
||||
### Practice Exercises
|
||||
|
||||
1. **Figure-8 Flying**: Practice smooth turns and momentum control
|
||||
2. **Precision Landing**: Land gently on targets using minimal thrust
|
||||
3. **Obstacle Course**: Navigate tight spaces using translation controls
|
||||
4. **Combat Training**: Practice keeping guns on target while evading
|
||||
|
||||
## 🔧 Tuning Your Ship
|
||||
|
||||
The following parameters can be adjusted for different flight characteristics:
|
||||
|
||||
- **Thrust Power**: How quickly you accelerate
|
||||
- **Maneuvering Thrust**: Precision vs power for side movement
|
||||
- **Rotation Power**: How quickly you can turn
|
||||
- **Drag Coefficients**: How much momentum you retain
|
||||
|
||||
## 🌌 Welcome to Space
|
||||
|
||||
Remember: In space, every action has an equal and opposite reaction. Master the physics, and you'll master the game. Your ship responds to real forces - there's no magic "turn toward movement" or artificial limitations.
|
||||
|
||||
**Fly safe, pilot. The cosmos awaits!**
|
||||
|
||||
---
|
||||
|
||||
_"The universe is not only stranger than we imagine, it is stranger than we can imagine." - But your ship controls make perfect sense once you learn them._
|
||||
+11
-3
@@ -1,12 +1,20 @@
|
||||
[gd_scene load_steps=3 format=3 uid="uid://27u3tdc5yqnl"]
|
||||
[gd_scene load_steps=4 format=3 uid="uid://27u3tdc5yqnl"]
|
||||
|
||||
[ext_resource type="ArrayMesh" uid="uid://ucw1lyo43yi4" path="res://assets/models/gold_ball.res" id="1_ct1s3"]
|
||||
|
||||
[sub_resource type="SphereShape3D" id="SphereShape3D_c5p07"]
|
||||
|
||||
[sub_resource type="PhysicsMaterial" id="PhysicsMaterial_ball"]
|
||||
bounce = 0.8
|
||||
friction = 0.3
|
||||
|
||||
[node name="Ball" type="RigidBody3D"]
|
||||
mass = 100.0
|
||||
inertia = Vector3(100, 100, 100)
|
||||
mass = 3
|
||||
physics_material_override = SubResource("PhysicsMaterial_ball")
|
||||
inertia = Vector3(3, 3, 3)
|
||||
gravity_scale = 0.8
|
||||
linear_damp = 0.1
|
||||
angular_damp = 0.1
|
||||
metadata/_edit_group_ = true
|
||||
|
||||
[node name="CollisionShape3D" type="CollisionShape3D" parent="."]
|
||||
|
||||
@@ -65,6 +65,43 @@ move_down={
|
||||
turbo={
|
||||
"deadzone": 0.2,
|
||||
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":4194325,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null)
|
||||
, Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"button_index":0,"pressure":0.0,"pressed":false,"script":null)
|
||||
]
|
||||
}
|
||||
turn_left={
|
||||
"deadzone": 0.2,
|
||||
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":74,"key_label":0,"unicode":106,"location":0,"echo":false,"script":null)
|
||||
, Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":-1,"axis":0,"axis_value":-1.0,"script":null)
|
||||
]
|
||||
}
|
||||
turn_right={
|
||||
"deadzone": 0.2,
|
||||
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":76,"key_label":0,"unicode":108,"location":0,"echo":false,"script":null)
|
||||
, Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":-1,"axis":0,"axis_value":1.0,"script":null)
|
||||
]
|
||||
}
|
||||
pitch_up={
|
||||
"deadzone": 0.2,
|
||||
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":73,"key_label":0,"unicode":105,"location":0,"echo":false,"script":null)
|
||||
, Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":-1,"axis":1,"axis_value":-1.0,"script":null)
|
||||
]
|
||||
}
|
||||
pitch_down={
|
||||
"deadzone": 0.2,
|
||||
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":75,"key_label":0,"unicode":107,"location":0,"echo":false,"script":null)
|
||||
, Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":-1,"axis":1,"axis_value":1.0,"script":null)
|
||||
]
|
||||
}
|
||||
roll_left={
|
||||
"deadzone": 0.2,
|
||||
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":85,"key_label":0,"unicode":117,"location":0,"echo":false,"script":null)
|
||||
, Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"button_index":9,"pressure":0.0,"pressed":false,"script":null)
|
||||
]
|
||||
}
|
||||
roll_right={
|
||||
"deadzone": 0.2,
|
||||
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":79,"key_label":0,"unicode":111,"location":0,"echo":false,"script":null)
|
||||
, Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"button_index":10,"pressure":0.0,"pressed":false,"script":null)
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
@@ -42,10 +42,10 @@ process_callback = 0
|
||||
autostart = true
|
||||
|
||||
[node name="Ship" parent="." instance=ExtResource("4_iywne")]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 3.16266, 2.82216, 16.1299)
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.497204, 2.82216, 27.8553)
|
||||
lock_rotation = true
|
||||
|
||||
[node name="Ball" parent="." instance=ExtResource("5_iywne")]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 18.2942, 1.46401, -2.82393)
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.464103, 1.46401, -2.82393)
|
||||
|
||||
[connection signal="timeout" from="Timer" to="." method="_on_timer_timeout"]
|
||||
|
||||
+143
-47
@@ -2,10 +2,15 @@ class_name Ship
|
||||
extends RigidBody3D
|
||||
|
||||
@export_group("Movement")
|
||||
var max_speed = 15.0
|
||||
var acceleration = 50.0
|
||||
var air_resistance = 0.98
|
||||
var turn_speed = 2.0
|
||||
@export var thrust_power = 150.0 # Main thruster power
|
||||
@export var maneuvering_thrust = 75.0 # Side/vertical thruster power
|
||||
@export var vertical_thrust = 120.0 # Up/down thruster power
|
||||
@export var turbo_multiplier = 2.5 # Turbo boost multiplier
|
||||
@export var max_speed = 25.0 # Maximum velocity
|
||||
@export var rotation_power = 20.0 # Angular thrust power
|
||||
@export var max_angular_speed = 3.0 # Maximum rotation speed
|
||||
@export var drag_coefficient = 0.98 # Linear drag (air resistance)
|
||||
@export var angular_drag = 0.95 # Rotational drag
|
||||
|
||||
@export_group("Camera")
|
||||
var camera_distance = 8.0
|
||||
@@ -19,12 +24,35 @@ var camera_smoothing = 10.0
|
||||
var ball_cam_enabled = true
|
||||
|
||||
func _ready():
|
||||
mass = 5
|
||||
gravity_scale = 1.0
|
||||
|
||||
# Set custom inertia for better rotation
|
||||
inertia = Vector3(1.0, 1.0, 1.0)
|
||||
|
||||
# Create and apply low-friction physics material
|
||||
var ship_material = PhysicsMaterial.new()
|
||||
ship_material.friction = 0.1 # Very low friction
|
||||
ship_material.bounce = 0.2 # Slight bounce
|
||||
physics_material_override = ship_material
|
||||
|
||||
# Make sure the RigidBody is completely free to move and rotate
|
||||
freeze = false
|
||||
lock_rotation = false
|
||||
|
||||
# Ensure all axes can rotate
|
||||
axis_lock_angular_x = false
|
||||
axis_lock_angular_y = false
|
||||
axis_lock_angular_z = false
|
||||
|
||||
var game_scene = get_parent()
|
||||
if game_scene and game_scene.has_signal("timer_updated"):
|
||||
game_scene.timer_updated.connect(_on_timer_updated)
|
||||
print("Connected to game scene timer signal")
|
||||
else:
|
||||
print("Game scene not found or doesn't have timer_updated signal")
|
||||
|
||||
print("Ship physics configured - Mass: ", mass, " Gravity scale: ", gravity_scale, " Inertia: ", inertia)
|
||||
print("Rotation locks - X:", axis_lock_angular_x, " Y:", axis_lock_angular_y, " Z:", axis_lock_angular_z)
|
||||
|
||||
func _input(event):
|
||||
if event.is_action_pressed("ui_accept"): # Enter key
|
||||
@@ -88,51 +116,119 @@ func _update_ship_cam(delta):
|
||||
camera.look_at(look_target, Vector3.UP)
|
||||
|
||||
func _integrate_forces(state):
|
||||
# Get input in ship's local coordinate system
|
||||
var input = get_ship_input()
|
||||
# Get thruster input
|
||||
var thrust_input = get_thrust_input()
|
||||
var rotation_input = get_rotation_input()
|
||||
|
||||
# Apply forces based on ship's orientation
|
||||
if input.length() > 0.01:
|
||||
var ship_forward = -global_transform.basis.z
|
||||
var ship_right = global_transform.basis.x
|
||||
|
||||
# Calculate movement direction based on ship orientation
|
||||
var movement_dir = Vector3.ZERO
|
||||
movement_dir += ship_forward * input.z # Forward/backward
|
||||
movement_dir += ship_right * input.x # Left/right
|
||||
movement_dir.y += input.y # Up/down
|
||||
|
||||
# Apply acceleration force
|
||||
var target_velocity = movement_dir.normalized() * max_speed
|
||||
var velocity_diff = target_velocity - state.linear_velocity
|
||||
var force = velocity_diff * acceleration * mass
|
||||
|
||||
state.apply_central_force(force)
|
||||
|
||||
# Turn the ship to face movement direction (only if moving horizontally)
|
||||
var horizontal_movement = Vector3(movement_dir.x, 0, movement_dir.z)
|
||||
if horizontal_movement.length() > 0.1:
|
||||
var target_transform = global_transform.looking_at(global_transform.origin + horizontal_movement, Vector3.UP)
|
||||
state.transform.basis = state.transform.basis.slerp(target_transform.basis, turn_speed * state.step)
|
||||
# === TRANSLATION (Movement) ===
|
||||
apply_thruster_forces(state, thrust_input)
|
||||
|
||||
# Apply air resistance
|
||||
state.linear_velocity *= air_resistance
|
||||
# === ROTATION (Turning) ===
|
||||
apply_rotation_forces(state, rotation_input)
|
||||
|
||||
# === DRAG AND LIMITS ===
|
||||
apply_drag_and_limits(state, rotation_input)
|
||||
|
||||
func get_ship_input() -> Vector3:
|
||||
var input = Vector3.ZERO
|
||||
func get_thrust_input() -> Vector3:
|
||||
var thrust = Vector3.ZERO
|
||||
|
||||
# Get input as if controlling a ship (forward/backward/left/right relative to ship)
|
||||
# Forward/Backward thrust (main engines)
|
||||
if Input.is_action_pressed("move_forward"):
|
||||
input.z += 1.0
|
||||
if Input.is_action_pressed("move_backward"):
|
||||
input.z -= 1.0
|
||||
if Input.is_action_pressed("move_left"):
|
||||
input.x -= 1.0
|
||||
if Input.is_action_pressed("move_right"):
|
||||
input.x += 1.0
|
||||
if Input.is_action_pressed("move_up"):
|
||||
input.y += 1.0
|
||||
if Input.is_action_pressed("move_down"):
|
||||
input.y -= 1.0
|
||||
thrust.z += 1.0
|
||||
if Input.is_action_pressed("move_back"):
|
||||
thrust.z -= 1.0
|
||||
|
||||
return input
|
||||
# Strafe thrusters (left/right)
|
||||
if Input.is_action_pressed("move_left"):
|
||||
thrust.x -= 1.0
|
||||
if Input.is_action_pressed("move_right"):
|
||||
thrust.x += 1.0
|
||||
|
||||
# Vertical thrusters (up/down)
|
||||
if Input.is_action_pressed("move_up"):
|
||||
thrust.y += 1.0
|
||||
if Input.is_action_pressed("move_down"):
|
||||
thrust.y -= 1.0
|
||||
|
||||
return thrust
|
||||
|
||||
func get_rotation_input() -> Vector3:
|
||||
var rotation = Vector3.ZERO
|
||||
|
||||
# Yaw (turn left/right around Y axis) - only use these if they exist
|
||||
if Input.is_action_pressed("turn_left"):
|
||||
rotation.y += 1.0
|
||||
if Input.is_action_pressed("turn_right"):
|
||||
rotation.y -= 1.0
|
||||
|
||||
# Pitch (nose up/down around X axis)
|
||||
if Input.is_action_pressed("pitch_up"):
|
||||
rotation.x -= 1.0
|
||||
if Input.is_action_pressed("pitch_down"):
|
||||
rotation.x += 1.0
|
||||
|
||||
# Roll (bank left/right around Z axis)
|
||||
if Input.is_action_pressed("roll_left"):
|
||||
rotation.z += 1.0
|
||||
if Input.is_action_pressed("roll_right"):
|
||||
rotation.z -= 1.0
|
||||
|
||||
return rotation
|
||||
|
||||
func apply_thruster_forces(state: PhysicsDirectBodyState3D, thrust_input: Vector3):
|
||||
if thrust_input.length() < 0.01:
|
||||
return
|
||||
|
||||
# Convert thrust input to world space forces based on ship orientation
|
||||
var ship_basis = global_transform.basis
|
||||
var world_thrust = Vector3.ZERO
|
||||
|
||||
# All thrusters should work relative to ship orientation
|
||||
# Forward/backward thrust (main engines)
|
||||
world_thrust += -ship_basis.z * thrust_input.z * thrust_power
|
||||
|
||||
# Strafe thrust (left/right maneuvering thrusters)
|
||||
world_thrust += ship_basis.x * thrust_input.x * maneuvering_thrust
|
||||
|
||||
# Vertical thrust (up/down thrusters relative to ship orientation)
|
||||
world_thrust += ship_basis.y * thrust_input.y * vertical_thrust
|
||||
|
||||
# Check for turbo
|
||||
var is_turbo = Input.is_action_pressed("turbo") and thrust_input.z > 0
|
||||
if is_turbo:
|
||||
world_thrust *= turbo_multiplier
|
||||
|
||||
# Apply the force
|
||||
state.apply_central_force(world_thrust)
|
||||
|
||||
func apply_rotation_forces(state: PhysicsDirectBodyState3D, rotation_input: Vector3):
|
||||
if rotation_input.length() < 0.01:
|
||||
return
|
||||
|
||||
# Apply torque for rotation - simple and effective
|
||||
var torque = Vector3(
|
||||
rotation_input.x * rotation_power, # Pitch
|
||||
rotation_input.y * rotation_power, # Yaw
|
||||
rotation_input.z * rotation_power # Roll
|
||||
)
|
||||
|
||||
state.apply_torque(torque)
|
||||
|
||||
func apply_drag_and_limits(state: PhysicsDirectBodyState3D, rotation_input: Vector3):
|
||||
# Linear drag (air resistance)
|
||||
state.linear_velocity *= drag_coefficient
|
||||
|
||||
# Angular drag (rotational resistance) - more aggressive when not rotating
|
||||
if rotation_input.length() < 0.01:
|
||||
# More drag when not actively rotating to stop quicker
|
||||
state.angular_velocity *= 0.9
|
||||
else:
|
||||
# Normal drag when actively rotating
|
||||
state.angular_velocity *= angular_drag
|
||||
|
||||
# Limit maximum speeds
|
||||
if state.linear_velocity.length() > max_speed:
|
||||
state.linear_velocity = state.linear_velocity.normalized() * max_speed
|
||||
|
||||
if state.angular_velocity.length() > max_angular_speed:
|
||||
state.angular_velocity = state.angular_velocity.normalized() * max_angular_speed
|
||||
|
||||
Reference in New Issue
Block a user