Working calibration and thruster control
This commit is contained in:
@ -327,8 +327,8 @@ func _place_component_from_preview():
|
||||
undo_redo.create_action("Place Component")
|
||||
undo_redo.add_do_method(target_module, "attach_component", component_to_place, closest_point.position, closest_point.piece)
|
||||
undo_redo.add_undo_method(target_module, "remove_child", component_to_place)
|
||||
undo_redo.add_do_method(target_module, "_update_mass_and_inertia")
|
||||
undo_redo.add_undo_method(target_module, "_update_mass_and_inertia")
|
||||
undo_redo.add_do_method(target_module, "recalculate_physical_properties")
|
||||
undo_redo.add_undo_method(target_module, "recalculate_physical_properties")
|
||||
undo_redo.commit_action()
|
||||
|
||||
preview_node.global_position = closest_point.position
|
||||
|
||||
@ -15,6 +15,8 @@
|
||||
|
||||
[node name="Module" type="Node2D"]
|
||||
script = ExtResource("1_nqe0s")
|
||||
mass = 13.0
|
||||
inertia = 18.0
|
||||
metadata/_custom_type_script = "uid://0isnsk356que"
|
||||
|
||||
[node name="StructuralContainer" type="Node2D" parent="."]
|
||||
@ -24,38 +26,49 @@ metadata/_custom_type_script = "uid://0isnsk356que"
|
||||
[node name="AtmosphereVisualizer" type="Node2D" parent="."]
|
||||
|
||||
[node name="Hullplate" parent="." instance=ExtResource("2_foqop")]
|
||||
mass = 1.0
|
||||
|
||||
[node name="@StaticBody2D@30634" parent="." instance=ExtResource("2_foqop")]
|
||||
position = Vector2(0, 100)
|
||||
mass = 1.0
|
||||
|
||||
[node name="@StaticBody2D@30635" parent="." instance=ExtResource("2_foqop")]
|
||||
position = Vector2(0, -100)
|
||||
mass = 1.0
|
||||
|
||||
[node name="Bulkhead" parent="." instance=ExtResource("4_dmrms")]
|
||||
position = Vector2(-50, 100)
|
||||
mass = 1.0
|
||||
|
||||
[node name="@StaticBody2D@30636" parent="." instance=ExtResource("4_dmrms")]
|
||||
position = Vector2(-50, 0)
|
||||
mass = 1.0
|
||||
|
||||
[node name="@StaticBody2D@30637" parent="." instance=ExtResource("4_dmrms")]
|
||||
position = Vector2(-50, -100)
|
||||
mass = 1.0
|
||||
|
||||
[node name="@StaticBody2D@30638" parent="." instance=ExtResource("4_dmrms")]
|
||||
position = Vector2(50, -100)
|
||||
mass = 1.0
|
||||
|
||||
[node name="@StaticBody2D@30639" parent="." instance=ExtResource("4_dmrms")]
|
||||
position = Vector2(0, -150)
|
||||
rotation = 1.5708
|
||||
mass = 1.0
|
||||
|
||||
[node name="@StaticBody2D@30640" parent="." instance=ExtResource("4_dmrms")]
|
||||
position = Vector2(0, 150)
|
||||
rotation = 4.71239
|
||||
mass = 1.0
|
||||
|
||||
[node name="@StaticBody2D@30641" parent="." instance=ExtResource("4_dmrms")]
|
||||
position = Vector2(50, 100)
|
||||
mass = 1.0
|
||||
|
||||
[node name="@StaticBody2D@30642" parent="." instance=ExtResource("4_dmrms")]
|
||||
position = Vector2(50, 0)
|
||||
mass = 1.0
|
||||
|
||||
[node name="PilotBall" parent="." instance=ExtResource("4_i3kos")]
|
||||
|
||||
@ -63,6 +76,7 @@ position = Vector2(50, 0)
|
||||
position = Vector2(1, -53)
|
||||
panels = Array[ExtResource("6_oqcn4")]([ExtResource("7_vmx8o"), ExtResource("8_83bu1"), ExtResource("9_ixntg")])
|
||||
installed_databanks = Array[ExtResource("6_ft4kn")]([ExtResource("7_dmrms")])
|
||||
mass = 1.0
|
||||
|
||||
[node name="Thruster" parent="." instance=ExtResource("12_vmx8o")]
|
||||
position = Vector2(-95, -130)
|
||||
@ -84,5 +98,5 @@ position = Vector2(95, -130)
|
||||
rotation = -1.5708
|
||||
main_thruster = false
|
||||
|
||||
[node name="Thruster5" parent="." instance=ExtResource("12_vmx8o")]
|
||||
[node name="MainEngine" parent="." instance=ExtResource("12_vmx8o")]
|
||||
position = Vector2(0, 195)
|
||||
|
||||
@ -66,7 +66,7 @@ func attach_component(component: Component, global_pos: Vector2, parent_piece: S
|
||||
component.attached_piece = parent_piece
|
||||
add_child(component)
|
||||
component.owner = self
|
||||
_update_mass_and_inertia()
|
||||
recalculate_physical_properties()
|
||||
|
||||
# --- UPDATED: Logic now uses the helper function ---
|
||||
func _recalculate_collision_shape():
|
||||
|
||||
@ -14,6 +14,7 @@ enum AttachmentType { INTERIOR_WALL, EXTERIOR_HULL, FLOOR_OR_CEILING }
|
||||
var attached_piece: StructuralPiece = null
|
||||
|
||||
func _ready():
|
||||
super()
|
||||
# OrbitalBody2D will handle mass initialization and physics setup.
|
||||
pass
|
||||
|
||||
|
||||
@ -11,6 +11,7 @@ extends Component
|
||||
@onready var rear_spring: DampedSpringJoint2D = $RearSpring
|
||||
|
||||
func _ready() -> void:
|
||||
super()
|
||||
# Configure the springs based on the exported variables
|
||||
front_spring.stiffness = spring_stiffness
|
||||
rear_spring.stiffness = spring_stiffness
|
||||
|
||||
@ -9,6 +9,7 @@ class_name Ladder
|
||||
# --- Inherited OrbitalBody2D & Component Setup ---
|
||||
|
||||
func _ready():
|
||||
super()
|
||||
# Set the base mass based on its material/size
|
||||
base_mass = float(ladder_grid_height) * 25.0 # Example: 25kg per grid unit height
|
||||
|
||||
|
||||
@ -17,6 +17,7 @@ var occupant_panel_map: Dictionary = {}
|
||||
# --- LIFECYCLE ---
|
||||
|
||||
func _ready():
|
||||
super()
|
||||
# --- FIX: Instantiate and initialize shards ONCE at startup ---
|
||||
# The logic is now persistent and runs as long as the station exists.
|
||||
var root_module = get_root_module()
|
||||
@ -108,7 +109,7 @@ func _connect_internals(panel_instances: Array, shard_instances: Array):
|
||||
# This logic remains the same, but it's now called with the relevant instances
|
||||
# every time a user sits down.
|
||||
var lever_panel
|
||||
var helm_shard
|
||||
var helm_shard: HelmLogicShard
|
||||
var button_panel
|
||||
|
||||
for panel in panel_instances:
|
||||
@ -128,6 +129,9 @@ func _connect_internals(panel_instances: Array, shard_instances: Array):
|
||||
# You would do the same for the button panel, connecting its signals
|
||||
# to a set_rotation_input or similar function on the helm_shard.
|
||||
if helm_shard and button_panel:
|
||||
button_panel.connect("button_1_pressed", func(): helm_shard.set_rotation_input(1.0))
|
||||
button_panel.connect("button_2_pressed", func(): helm_shard.set_rotation_input(-1.0))
|
||||
button_panel.connect("button_3_pressed", helm_shard.shutdown_rcs)
|
||||
button_panel.connect("button_4_pressed", helm_shard.calibrate_rcs_performance)
|
||||
|
||||
# Helper to find the main ship/module this station belongs to
|
||||
|
||||
@ -5,9 +5,6 @@ extends Component
|
||||
@onready var pin_joint_a: PinJoint2D = $PinJointA
|
||||
@onready var pin_joint_b: PinJoint2D = $PinJointB
|
||||
|
||||
# Get a reference to the parent ship.
|
||||
@onready var ship: Spaceship = GameManager._find_parent_ship(self)
|
||||
|
||||
# Max force the thruster can produce (in scaled Newtons).
|
||||
@export var max_thrust: float = 0.1
|
||||
|
||||
@ -26,23 +23,22 @@ var is_firing: bool = false
|
||||
func _ready() -> void:
|
||||
super()
|
||||
|
||||
# TODO: Figure out where this should go if anywhere
|
||||
# --- Self-connecting logic ---
|
||||
if ship and ship.get_path():
|
||||
var ship_path = ship.get_path()
|
||||
var self_path = get_path()
|
||||
|
||||
# --- Configure Pin Joint A ---
|
||||
pin_joint_a.node_b = ship_path
|
||||
|
||||
# --- Configure Pin Joint B ---
|
||||
pin_joint_b.node_b = ship_path
|
||||
else:
|
||||
print("Thruster Warning: 'Attach To Node' path is not set for ", self.name)
|
||||
#if ship and ship.get_path():
|
||||
#var ship_path = ship.get_path()
|
||||
#var self_path = get_path()
|
||||
#
|
||||
## --- Configure Pin Joint A ---
|
||||
#pin_joint_a.node_b = ship_path
|
||||
#
|
||||
## --- Configure Pin Joint B ---
|
||||
#pin_joint_b.node_b = ship_path
|
||||
#else:
|
||||
#print("Thruster Warning: 'Attach To Node' path is not set for ", self.name)
|
||||
|
||||
# This thruster announces its existence to the whole scene tree.
|
||||
add_to_group("ship_thrusters")
|
||||
#self.body_entered.connect(_on_body_entered)
|
||||
|
||||
|
||||
# This function calculates how much fuel is needed for a given thrust level and duration.
|
||||
func calculate_fuel_consumption(thrust_force: float, delta_time: float) -> float:
|
||||
@ -61,25 +57,25 @@ func _on_body_entered(body: Node) -> void:
|
||||
|
||||
# The controller calls this ONCE to activate the thruster.
|
||||
func turn_on():
|
||||
print("Thruster: Recieved Turn On Signal")
|
||||
#print("Thruster: Recieved Turn On Signal")
|
||||
if enabled:
|
||||
is_firing = true
|
||||
|
||||
await get_tree().physics_frame
|
||||
print(" - firing: %s" % is_firing)
|
||||
#print(" - firing: %s" % is_firing)
|
||||
|
||||
# The controller calls this ONCE to deactivate the thruster.
|
||||
func turn_off():
|
||||
print("Thruster: Recieved Turn Off Signal")
|
||||
#print("Thruster: Recieved Turn Off Signal")
|
||||
is_firing = false
|
||||
|
||||
await get_tree().physics_frame
|
||||
print(" - firing: %s" % is_firing)
|
||||
#print(" - firing: %s" % is_firing)
|
||||
|
||||
# --- Godot Physics Callback ---
|
||||
func _physics_process(_delta: float):
|
||||
func _physics_process(delta: float):
|
||||
super(delta)
|
||||
if not enabled:
|
||||
print("thruster not enabled")
|
||||
is_firing = false
|
||||
|
||||
# If the thruster is active, apply a constant central force in its local "up" direction.
|
||||
|
||||
@ -10,11 +10,11 @@ signal button_4_pressed
|
||||
|
||||
@onready var RCSPosBtn: Button = $RCSPos
|
||||
@onready var RCSNegBtn: Button = $RCSNeg
|
||||
@onready var MainEngineBtn: Button = $MainEngine
|
||||
@onready var ShutdownBtn: Button = $RCSShutdown
|
||||
@onready var CalibrateRcsBtn: Button = $CalibrateRCS
|
||||
|
||||
func _ready():
|
||||
RCSPosBtn.pressed.connect(func(): emit_signal("button_1_pressed"))
|
||||
RCSNegBtn.pressed.connect(func(): emit_signal("button_2_pressed"))
|
||||
MainEngineBtn.pressed.connect(func(): emit_signal("button_3_pressed"))
|
||||
ShutdownBtn.pressed.connect(func(): emit_signal("button_3_pressed"))
|
||||
CalibrateRcsBtn.pressed.connect(func(): emit_signal("button_4_pressed"))
|
||||
|
||||
@ -15,9 +15,9 @@ text = "RCS Pos"
|
||||
layout_mode = 2
|
||||
text = "RCS Neg"
|
||||
|
||||
[node name="MainEngine" type="Button" parent="."]
|
||||
[node name="RCSShutdown" type="Button" parent="."]
|
||||
layout_mode = 2
|
||||
text = "Main"
|
||||
text = "RCS Shutdown"
|
||||
|
||||
[node name="CalibrateRCS" type="Button" parent="."]
|
||||
layout_mode = 2
|
||||
|
||||
@ -76,16 +76,19 @@ func _perform_manual_hold():
|
||||
|
||||
# --- REFACTORED: This is the other key change ---
|
||||
func apply_rotational_thrust(desired_torque: float):
|
||||
print("Applying rotational thrust")
|
||||
for thruster in thrusters:
|
||||
if not thruster.main_thruster:
|
||||
# Placeholder logic to determine which thrusters to fire
|
||||
var thruster_torque_direction = 1.0 if thruster.position.x < 0 else -1.0
|
||||
|
||||
if sign(thruster_torque_direction) == sign(desired_torque):
|
||||
thruster.turn_on()
|
||||
else:
|
||||
thruster.turn_off()
|
||||
if not is_instance_valid(root_module):
|
||||
return
|
||||
|
||||
# Iterate through all available RCS thrusters that have been calibrated
|
||||
for thruster in thruster_data_map:
|
||||
var thruster_data: ThrusterData = thruster_data_map[thruster]
|
||||
|
||||
# If this thruster can help apply the desired torque, turn it on.
|
||||
# Otherwise, explicitly turn it off to ensure it's not firing incorrectly.
|
||||
if sign(thruster_data.measured_torque) == sign(desired_torque) and desired_torque != 0:
|
||||
thruster.turn_on()
|
||||
else:
|
||||
thruster.turn_off()
|
||||
|
||||
func shutdown_rcs():
|
||||
for thruster in thrusters:
|
||||
|
||||
@ -3,9 +3,9 @@ class_name OrbitalBody2D
|
||||
|
||||
# Mass of this individual component
|
||||
@export var base_mass: float = 1.0
|
||||
var mass: float = 0.0 # Aggregated mass of this body and all its OrbitalBody2D children
|
||||
var linear_velocity: Vector2 = Vector2.ZERO
|
||||
var angular_velocity: float = 0.0
|
||||
@export var mass: float = 0.0 # Aggregated mass of this body and all its OrbitalBody2D children
|
||||
@export var linear_velocity: Vector2 = Vector2.ZERO
|
||||
@export var angular_velocity: float = 0.0
|
||||
|
||||
# Variables to accumulate forces applied during the current physics frame
|
||||
var accumulated_force: Vector2 = Vector2.ZERO
|
||||
@ -18,8 +18,6 @@ var accumulated_torque: float = 0.0
|
||||
var is_sim_root: bool = true
|
||||
|
||||
func _ready():
|
||||
# FIX 1: Ensure mass update runs immediately before the first _physics_process.
|
||||
_update_mass_and_inertia()
|
||||
|
||||
# Check if a parent is also an OrbitalBody2D
|
||||
var p = get_parent()
|
||||
@ -29,16 +27,18 @@ func _ready():
|
||||
break
|
||||
p = p.get_parent()
|
||||
|
||||
# Ensure mass update runs immediately before the first _physics_process.
|
||||
recalculate_physical_properties()
|
||||
# FIX: Enable _physics_process for ALL OrbitalBody2D nodes (including Thrusters).
|
||||
# The 'if is_sim_root' inside _physics_process will prevent integration for children.
|
||||
set_physics_process(Engine.is_editor_hint())
|
||||
#The 'if is_sim_root' inside _physics_process will prevent integration for children.
|
||||
#set_physics_process(Engine.is_editor_hint())
|
||||
|
||||
# --- PUBLIC FORCE APPLICATION METHODS ---
|
||||
# This method is called by a component (like Thruster) at its global position.
|
||||
func apply_force(force: Vector2, position: Vector2 = Vector2.ZERO):
|
||||
# This is the force routing logic.
|
||||
if is_sim_root:
|
||||
# If we are the root, accumulate the force and calculate torque on the total body.
|
||||
# If we are the root, accumulate the force and calculate torque on the total body.
|
||||
accumulated_force += force
|
||||
|
||||
# Calculate torque (2D cross product: T = r x F = r.x * F.y - r.y * F.x)
|
||||
@ -47,7 +47,7 @@ func apply_force(force: Vector2, position: Vector2 = Vector2.ZERO):
|
||||
var torque = r.x * force.y - r.y * force.x
|
||||
accumulated_torque += torque
|
||||
else:
|
||||
# If we are not the root, we must route the force to the next OrbitalBody2D parent.
|
||||
# If we are not the root, we must route the force to the next OrbitalBody2D parent.
|
||||
var p = get_parent()
|
||||
while p:
|
||||
if p is OrbitalBody2D:
|
||||
@ -98,3 +98,58 @@ func _physics_process(delta):
|
||||
# 5. Reset accumulated forces for the next frame
|
||||
accumulated_force = Vector2.ZERO
|
||||
accumulated_torque = 0.0
|
||||
|
||||
# This is the new, corrected function.
|
||||
func recalculate_physical_properties():
|
||||
if not is_sim_root:
|
||||
return
|
||||
|
||||
var all_parts: Array[OrbitalBody2D] = []
|
||||
_collect_all_parts(all_parts)
|
||||
|
||||
if all_parts.is_empty():
|
||||
mass = base_mass
|
||||
inertia = 1.0
|
||||
return
|
||||
|
||||
# --- Step 1: Calculate Total Mass and LOCAL Center of Mass ---
|
||||
var total_mass = 0.0
|
||||
var weighted_local_pos_sum = Vector2.ZERO
|
||||
for part in all_parts:
|
||||
total_mass += part.base_mass
|
||||
# We get the part's position *relative to the root module*
|
||||
var local_pos = part.global_position - self.global_position
|
||||
weighted_local_pos_sum += local_pos * part.base_mass
|
||||
|
||||
var local_center_of_mass = Vector2.ZERO
|
||||
if total_mass > 0:
|
||||
local_center_of_mass = weighted_local_pos_sum / total_mass
|
||||
|
||||
# --- Step 2: Calculate Total Moment of Inertia around the LOCAL CoM ---
|
||||
var total_inertia = 0.0
|
||||
for part in all_parts:
|
||||
# Get the part's position relative to the root module again
|
||||
var local_pos = part.global_position - self.global_position
|
||||
# The radius is the distance from the part's local position to the ship's local center of mass
|
||||
var r_squared = (local_pos - local_center_of_mass).length_squared()
|
||||
total_inertia += part.base_mass * r_squared
|
||||
|
||||
# --- Step 3: Assign the final values ---
|
||||
self.mass = total_mass
|
||||
# We apply a scaling factor here because our "units" are pixels.
|
||||
# This brings the final value into a range that feels good for gameplay.
|
||||
# You can tune this factor to make ships feel heavier or lighter.
|
||||
self.inertia = total_inertia * 0.01
|
||||
|
||||
print("Physics Recalculated: Mass=%.2f kg, Inertia=%.2f" % [mass, inertia])
|
||||
|
||||
# A recursive helper function to get an array of all OrbitalBody2D children.
|
||||
func _collect_all_parts(parts_array: Array):
|
||||
# Add self to the list
|
||||
parts_array.append(self)
|
||||
|
||||
# Recurse into children
|
||||
# TODO: this assumes that all OrbitalBody2D that are attached are done in a clean chain without breaks, which may not be the case
|
||||
for child in get_children():
|
||||
if child is OrbitalBody2D:
|
||||
child._collect_all_parts(parts_array)
|
||||
|
||||
Reference in New Issue
Block a user