diff --git a/FLIGHT_MANUAL.md b/FLIGHT_MANUAL.md new file mode 100644 index 0000000..172c7e6 --- /dev/null +++ b/FLIGHT_MANUAL.md @@ -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._ diff --git a/Game/objects/ball.tscn b/Game/objects/ball.tscn index a3c42fe..5c3cca7 100644 --- a/Game/objects/ball.tscn +++ b/Game/objects/ball.tscn @@ -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="."] diff --git a/Game/project.godot b/Game/project.godot index f681007..cf4ff02 100644 --- a/Game/project.godot +++ b/Game/project.godot @@ -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) ] } diff --git a/Game/scenes/Game.tscn b/Game/scenes/Game.tscn index 715897a..7e4fa0a 100644 --- a/Game/scenes/Game.tscn +++ b/Game/scenes/Game.tscn @@ -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"] diff --git a/Game/scripts/ship.gd b/Game/scripts/ship.gd index 6d190b5..2961114 100644 --- a/Game/scripts/ship.gd +++ b/Game/scripts/ship.gd @@ -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