A manually aimed instant beam, modelled on the gas bomber's press-drag-
release aiming (GasBombController/VesselGasBomberComponent) but firing
the moment the touch releases - no projectile travel time. Damage,
beam_range and cooldown are resolved per ship from base_stats/upgrades
(VesselLaserComponent.apply_stats(), the same pattern
VesselWeaponComponent uses) rather than hardcoded in the controller, so
the new damage/range/cooldown ship-lab upgrades actually reach them.
Cooldown lives on the component (per ship), not the controller (per
fleet) - two laser ships give two shots, the exact bug already fixed
for bombers in eb79efd.
LaserController.gd is reused unmodified by both Main.tscn and
PlanetSurface.tscn (relative ../Fleet, ../Camera2D, ../UI/LaserButton
paths, matching GasBombController), so it works identically in space
and on a landed surface. Wired into GameController's touch/drag
first-refusal chain alongside the bomb controller.
The crafter, hangar and ship-lab menus were already generic over
VesselDefinitions.fleet()/.all() - only the per-vessel Main.tscn nodes
are hand-placed, not the logic - so this repacks those rows to
5/5/6 columns and extends BuildController's onready arrays. No new
signal handlers were needed. Also fixes test_vessel_composition.gd's
hardcoded fleet-catalog size again (4 -> 5) now that laser is a fifth
fleet-eligible vessel.
Note for later tickets: a brand-new class_name script (LaserController)
resolves fine as a static type when its own file is the godot -s entry
point, but the identical type hint fails to parse ("Could not find
type") when the script holding it is only reached indirectly - e.g.
Main.tscn loaded from inside a _screenshot_tool.gd preview. Untyped
Node + duck-typed calls sidesteps it; GameController.gd's
laser_controller field documents this in place.
49 lines
2 KiB
GDScript
49 lines
2 KiB
GDScript
extends Node2D
|
|
|
|
# Preview, not a test - #58's aim-state screenshot: two laser ships (one
|
|
# ready, one rearming), aiming with the beam preview drawn and enemies
|
|
# placed along its line.
|
|
#
|
|
# bash tests/screenshot.sh res://tests/_laser_aim_preview.tscn /tmp/laser.png 20 720x1280
|
|
|
|
|
|
func _ready() -> void:
|
|
GameState.buildings.clear()
|
|
GameState.extractors.clear()
|
|
GameState.transporters.clear()
|
|
GameState.vessel_levels["unlock_laser"] = 1
|
|
var main: Node = load("res://Main.tscn").instantiate()
|
|
add_child(main)
|
|
main.get_node("BackgroundLayer").visible = false
|
|
main.get_node("AsteroidField").visible = false
|
|
main.get_node("PlanetField").visible = false
|
|
main.get_node("BuildingField").visible = false
|
|
main.get_node("EnemySpawner").set_process(false)
|
|
main.get_node("AsteroidField").set_process(false)
|
|
var fleet: Node = main.get_node("Fleet")
|
|
fleet.spawn_ships(4, Vector2.ZERO, PackedStringArray([
|
|
GameState.VESSEL_INTERCEPTOR, GameState.VESSEL_SHIELD,
|
|
GameState.VESSEL_LASER, GameState.VESSEL_LASER]))
|
|
var skill: Node = main.get_node("LaserController")
|
|
skill._process(0.0)
|
|
# Show both per-ship states in one frame: one laser ship rearming, the
|
|
# other ready and supplying the shot.
|
|
var rearming: Node = fleet.ships[2].get_component("laser")
|
|
rearming.consume_shot()
|
|
rearming.tick(rearming.cooldown_duration * 0.5)
|
|
main.get_node("Camera2D").zoom = Vector2(1.8, 1.8)
|
|
var button: Control = main.get_node("UI/LaserButton")
|
|
var press := InputEventScreenTouch.new()
|
|
press.index = 9
|
|
press.position = button.global_position + button.size * 0.5
|
|
press.pressed = true
|
|
skill.handle_touch(press)
|
|
var drag := InputEventScreenDrag.new()
|
|
drag.index = 9
|
|
drag.position = press.position + Vector2(-245.0, -235.0)
|
|
skill.handle_drag(drag)
|
|
for t in [0.35, 0.6]:
|
|
var enemy: Node = load("res://Enemy.tscn").instantiate()
|
|
enemy.position = fleet.get_centroid().lerp(skill.aim_target, t)
|
|
main.add_child(enemy)
|
|
enemy.speed = 0.0 # after add_child - _ready() sets it from the definition
|