WIP commit before reorg
This commit is contained in:
79
scenes/spaceship/hull_volume.gd
Normal file
79
scenes/spaceship/hull_volume.gd
Normal file
@ -0,0 +1,79 @@
|
||||
# hull_volume.gd
|
||||
# An invisible Area2D that players place to define a "room."
|
||||
# It checks if its boundaries are completely enclosed by pressurized structural pieces.
|
||||
class_name HullVolume
|
||||
extends Area2D
|
||||
|
||||
# A small buffer for the raycast distance to avoid floating-point errors at the edge.
|
||||
const RAYCAST_BUFFER = 5.0
|
||||
const RAYCAST_INCREMENT = 10.0 # Cast a ray every 10 pixels along the edge.
|
||||
|
||||
@onready var collision_shape: CollisionShape2D = $CollisionShape2D
|
||||
|
||||
var leak_position: Vector2 = Vector2.ZERO
|
||||
|
||||
# Performs the "leak check."
|
||||
func check_seal() -> bool:
|
||||
# This is the core logic. A robust way to implement this:
|
||||
# 1. Get the polygon points of this Area2D's CollisionShape2D in global space.
|
||||
# 2. For each edge (segment) of the polygon:
|
||||
# a. Cast several rays (or a shape cast) outwards, perpendicular to the edge.
|
||||
# b. Check if ALL rays for that edge collide with a `StructuralPiece` where `is_pressurized == true`.
|
||||
# c. If any edge has rays that escape into empty space, a leak is found.
|
||||
# 3. If a leak is found, store the position (`leak_position`) and return `false`.
|
||||
# 4. If all edges are sealed, return `true`.
|
||||
|
||||
print("Checking for seal...")
|
||||
var parent_module = get_parent().get_parent()
|
||||
if not parent_module or not parent_module is RigidBody2D:
|
||||
print("HullVolume must be a child of a ModuleBuilderController.")
|
||||
return false
|
||||
|
||||
# Get the polygon points in the module's local space
|
||||
if not collision_shape or not collision_shape.shape is ConcavePolygonShape2D:
|
||||
print("Warning: HullVolume must use a ConcavePolygonShape2D.")
|
||||
return false
|
||||
|
||||
var module_points = (collision_shape.shape as ConcavePolygonShape2D).get_segments()
|
||||
|
||||
# The points are segments, so we iterate through pairs
|
||||
for i in range(0, module_points.size(), 2):
|
||||
var p1 = self.global_position + module_points[i]
|
||||
var p2 = self.global_position + module_points[i+1]
|
||||
|
||||
var edge_length = p1.distance_to(p2)
|
||||
var num_rays = int(ceil(edge_length / RAYCAST_INCREMENT))
|
||||
|
||||
# The normal is perpendicular to the edge, pointing outwards
|
||||
var normal = (p2 - p1).normalized().rotated(PI/2)
|
||||
|
||||
# Cast rays along the edge
|
||||
for r in range(num_rays):
|
||||
var ray_start = p1.lerp(p2, float(r) / float(num_rays))
|
||||
var ray_end = ray_start + normal * RAYCAST_BUFFER
|
||||
|
||||
# Use the physics space to check for a collision
|
||||
var query = PhysicsRayQueryParameters2D.create(ray_start, ray_end)
|
||||
var result = get_world_2d().direct_space_state.intersect_ray(query)
|
||||
|
||||
if result.is_empty():
|
||||
# Ray went into empty space, this is a leak!
|
||||
print("Leak found: Ray escaped to space.")
|
||||
leak_position = ray_start
|
||||
return false
|
||||
|
||||
var collider = result.collider
|
||||
if collider is StructuralPiece and collider.is_pressurized:
|
||||
# This ray hit a valid, pressurized wall. OK.
|
||||
continue
|
||||
else:
|
||||
# This ray hit something, but it's not a pressurized piece, so it's a leak.
|
||||
print("Leak found: Ray hit non-pressurized piece: ", collider.name)
|
||||
leak_position = ray_start
|
||||
return false
|
||||
|
||||
print("Module is successfully sealed.")
|
||||
return true
|
||||
|
||||
func get_leak_position() -> Vector2:
|
||||
return leak_position
|
||||
1
scenes/spaceship/hull_volume.gd.uid
Normal file
1
scenes/spaceship/hull_volume.gd.uid
Normal file
@ -0,0 +1 @@
|
||||
uid://bdctwdqx66bhp
|
||||
11
scenes/spaceship/hull_volume.tscn
Normal file
11
scenes/spaceship/hull_volume.tscn
Normal file
@ -0,0 +1,11 @@
|
||||
[gd_scene load_steps=3 format=3 uid="uid://dla2m5j414d3c"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://bdctwdqx66bhp" path="res://scenes/spaceship/hull_volume.gd" id="1_jlg8y"]
|
||||
|
||||
[sub_resource type="RectangleShape2D" id="RectangleShape2D_n63kp"]
|
||||
|
||||
[node name="HullVolume" type="Area2D"]
|
||||
script = ExtResource("1_jlg8y")
|
||||
|
||||
[node name="CollisionShape2D" type="CollisionShape2D" parent="."]
|
||||
shape = SubResource("RectangleShape2D_n63kp")
|
||||
12
scenes/spaceship/module.tscn
Normal file
12
scenes/spaceship/module.tscn
Normal file
@ -0,0 +1,12 @@
|
||||
[gd_scene load_steps=2 format=3 uid="uid://ds3qq4yg8y86y"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://6co67nfy8ngb" path="res://scenes/spaceship/module_builder_controller.gd" id="1_b1h2b"]
|
||||
|
||||
[node name="Module" type="RigidBody2D"]
|
||||
script = ExtResource("1_b1h2b")
|
||||
|
||||
[node name="StructuralContainer" type="Node2D" parent="."]
|
||||
|
||||
[node name="HullVolumeContainer" type="Node2D" parent="."]
|
||||
|
||||
[node name="AtmosphereVisualizer" type="Node2D" parent="."]
|
||||
113
scenes/spaceship/module_builder_controller.gd
Normal file
113
scenes/spaceship/module_builder_controller.gd
Normal file
@ -0,0 +1,113 @@
|
||||
# module_builder_controller.gd
|
||||
# The root script for a player-constructed ship module. This is a RigidBody2D that
|
||||
# acts as a container for all the player-placed structural pieces.
|
||||
class_name ModuleBuilderController
|
||||
extends RigidBody2D
|
||||
|
||||
# These nodes should be children of this RigidBody2D in the scene tree.
|
||||
@onready var structural_container: Node2D = $StructuralContainer
|
||||
@onready var hull_volume_container: Node2D = $HullVolumeContainer
|
||||
@onready var atmosphere_visualizer: Node2D = $AtmosphereVisualizer # For "gas leak" effects
|
||||
|
||||
enum ModuleState { IN_CONSTRUCTION, SEALED, PRESSURIZED, BREACHED }
|
||||
|
||||
var current_state: ModuleState = ModuleState.IN_CONSTRUCTION
|
||||
|
||||
# --- Public API for In-Game Construction ---
|
||||
|
||||
# Called by the player's construction tool to add a wall, plate, etc.
|
||||
func add_structural_piece(piece_scene: PackedScene, pos: Vector2, rot: float):
|
||||
var piece = piece_scene.instantiate() as Node2D
|
||||
piece.position = pos
|
||||
piece.rotation = rot
|
||||
structural_container.add_child(piece)
|
||||
# Every time the structure changes, we must update the module's physics.
|
||||
_recalculate_physics_properties()
|
||||
|
||||
# Called by the player to define the area that should contain an atmosphere.
|
||||
func add_hull_volume(volume_scene: PackedScene, pos: Vector2):
|
||||
var volume = volume_scene.instantiate() as Node2D
|
||||
volume.position = pos
|
||||
hull_volume_container.add_child(volume)
|
||||
|
||||
# This function checks if every defined room (Hull Volume) is properly sealed.
|
||||
func check_for_seal() -> bool:
|
||||
if hull_volume_container.get_child_count() == 0:
|
||||
print("Module integrity check failed: No hull volumes defined.")
|
||||
return false
|
||||
|
||||
var all_sealed = true
|
||||
for volume in hull_volume_container.get_children():
|
||||
if volume is HullVolume:
|
||||
if not volume.check_seal():
|
||||
all_sealed = false
|
||||
# The volume can be responsible for showing its own leak effect.
|
||||
if atmosphere_visualizer.has_method("show_leak_at"):
|
||||
atmosphere_visualizer.show_leak_at(volume.get_leak_position())
|
||||
|
||||
if all_sealed:
|
||||
print("Module is sealed! Ready for pressurization and component installation.")
|
||||
current_state = ModuleState.SEALED
|
||||
return true
|
||||
else:
|
||||
print("One or more hull volumes reported a leak.")
|
||||
current_state = ModuleState.IN_CONSTRUCTION
|
||||
return false
|
||||
|
||||
# --- Internal Physics Management ---
|
||||
|
||||
# Recalculates the total mass, center of mass, and combines all collision shapes.
|
||||
func _recalculate_physics_properties():
|
||||
print("Recalculating physics properties...")
|
||||
|
||||
# 1. Sum masses and find a weighted center of mass
|
||||
var total_mass: float = 0.0
|
||||
var total_mass_pos = Vector2.ZERO
|
||||
var all_structural_pieces = structural_container.get_children()
|
||||
|
||||
for piece in all_structural_pieces:
|
||||
if piece is StructuralPiece:
|
||||
total_mass += piece.piece_mass
|
||||
# The position is relative to the structural_container.
|
||||
total_mass_pos += piece.position * piece.piece_mass
|
||||
|
||||
if total_mass > 0:
|
||||
var new_center_of_mass = total_mass_pos / total_mass
|
||||
# We set the center of mass in the RigidBody2D.
|
||||
self.set_center_of_mass(new_center_of_mass)
|
||||
self.mass = total_mass
|
||||
|
||||
# --- Combine all collision shapes into one for the RigidBody ---
|
||||
# This is a key part of your design, allowing for efficient physics calculations.
|
||||
# Note: This is an expensive operation and should only be done on demand.
|
||||
|
||||
# Remove any existing collision shapes from this RigidBody2D
|
||||
for child in get_children():
|
||||
if child is CollisionShape2D or child is CollisionPolygon2D:
|
||||
child.queue_free()
|
||||
|
||||
var shape = ConcavePolygonShape2D.new()
|
||||
var all_points: PackedVector2Array = []
|
||||
|
||||
# Iterate through all structural pieces to get their collision polygons
|
||||
for piece in all_structural_pieces:
|
||||
if piece is StructuralPiece:
|
||||
for child in piece.get_children():
|
||||
if child is CollisionPolygon2D:
|
||||
# Get the points in the structural piece's local space
|
||||
var piece_points = child.polygon
|
||||
var piece_xform = piece.transform
|
||||
|
||||
# Transform the points to the module's local space
|
||||
for p in piece_points:
|
||||
all_points.append(piece_xform.xform(p))
|
||||
|
||||
shape.set_segments(all_points)
|
||||
|
||||
var new_collision_shape = CollisionShape2D.new()
|
||||
new_collision_shape.shape = shape
|
||||
add_child(new_collision_shape)
|
||||
|
||||
print("Physics Recalculated: Total Mass: %.2f kg" % total_mass)
|
||||
else:
|
||||
print("No structural pieces found. Physics properties not updated.")
|
||||
1
scenes/spaceship/module_builder_controller.gd.uid
Normal file
1
scenes/spaceship/module_builder_controller.gd.uid
Normal file
@ -0,0 +1 @@
|
||||
uid://6co67nfy8ngb
|
||||
16
scenes/spaceship/structural_piece.gd
Normal file
16
scenes/spaceship/structural_piece.gd
Normal file
@ -0,0 +1,16 @@
|
||||
# structural_piece.gd
|
||||
# A script for the individual, player-placeable pieces like walls, floors, and girders.
|
||||
class_name StructuralPiece
|
||||
extends StaticBody2D
|
||||
|
||||
# The mass this piece contributes to its parent module.
|
||||
@export var piece_mass: float = 10.0
|
||||
|
||||
# Does this piece block atmosphere? (e.g., a hull plate would, a girder would not).
|
||||
@export var is_pressurized: bool = true
|
||||
|
||||
# The health of this specific piece.
|
||||
@export var health: float = 100.0
|
||||
|
||||
func get_mass() -> float:
|
||||
return piece_mass
|
||||
1
scenes/spaceship/structural_piece.gd.uid
Normal file
1
scenes/spaceship/structural_piece.gd.uid
Normal file
@ -0,0 +1 @@
|
||||
uid://b7f8x2qimvn37
|
||||
6
scenes/spaceship/structural_piece.tscn
Normal file
6
scenes/spaceship/structural_piece.tscn
Normal file
@ -0,0 +1,6 @@
|
||||
[gd_scene load_steps=2 format=3 uid="uid://ds4eilbvihjy7"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://b7f8x2qimvn37" path="res://scenes/spaceship/structural_piece.gd" id="1_6jsoj"]
|
||||
|
||||
[node name="StructuralPiece" type="StaticBody2D"]
|
||||
script = ExtResource("1_6jsoj")
|
||||
Reference in New Issue
Block a user