Arrange fleet abilities around fire stick
This commit is contained in:
parent
cb6b0b69c6
commit
9864e59efc
8 changed files with 156 additions and 7 deletions
|
|
@ -1,4 +1,4 @@
|
||||||
[gd_scene load_steps=20 format=3]
|
[gd_scene load_steps=21 format=3]
|
||||||
|
|
||||||
[ext_resource type="Script" path="res://controllers/GameController.gd" id="1"]
|
[ext_resource type="Script" path="res://controllers/GameController.gd" id="1"]
|
||||||
[ext_resource type="PackedScene" path="res://surface/SurfaceBackground.tscn" id="3"]
|
[ext_resource type="PackedScene" path="res://surface/SurfaceBackground.tscn" id="3"]
|
||||||
|
|
@ -12,6 +12,7 @@
|
||||||
[ext_resource type="Script" path="res://controllers/GasBombController.gd" id="14"]
|
[ext_resource type="Script" path="res://controllers/GasBombController.gd" id="14"]
|
||||||
[ext_resource type="Script" path="res://controllers/LaserController.gd" id="16"]
|
[ext_resource type="Script" path="res://controllers/LaserController.gd" id="16"]
|
||||||
[ext_resource type="Script" path="res://controllers/DashController.gd" id="dash_ctrl"]
|
[ext_resource type="Script" path="res://controllers/DashController.gd" id="dash_ctrl"]
|
||||||
|
[ext_resource type="Script" path="res://ui/AbilityButtonLayout.gd" id="ability_layout"]
|
||||||
[ext_resource type="Script" path="res://ui/SpeedFader.gd" id="17"]
|
[ext_resource type="Script" path="res://ui/SpeedFader.gd" id="17"]
|
||||||
[ext_resource type="Script" path="res://surface/CaptureLabel.gd" id="15"]
|
[ext_resource type="Script" path="res://surface/CaptureLabel.gd" id="15"]
|
||||||
[ext_resource type="Script" path="res://ui/NarrationBanner.gd" id="banner"]
|
[ext_resource type="Script" path="res://ui/NarrationBanner.gd" id="banner"]
|
||||||
|
|
@ -43,6 +44,9 @@ script = ExtResource("16")
|
||||||
[node name="DashController" type="Node2D" parent="."]
|
[node name="DashController" type="Node2D" parent="."]
|
||||||
script = ExtResource("dash_ctrl")
|
script = ExtResource("dash_ctrl")
|
||||||
|
|
||||||
|
[node name="AbilityButtonLayout" type="Node" parent="."]
|
||||||
|
script = ExtResource("ability_layout")
|
||||||
|
|
||||||
[node name="Camera2D" type="Camera2D" parent="."]
|
[node name="Camera2D" type="Camera2D" parent="."]
|
||||||
position = Vector2(0, 0)
|
position = Vector2(0, 0)
|
||||||
zoom = Vector2(1, 1)
|
zoom = Vector2(1, 1)
|
||||||
|
|
|
||||||
90
tests/test_ability_button_layout.gd
Normal file
90
tests/test_ability_button_layout.gd
Normal file
|
|
@ -0,0 +1,90 @@
|
||||||
|
extends SceneTree
|
||||||
|
|
||||||
|
# The three aimed abilities share one responsive quarter-circle layout around
|
||||||
|
# the fire stick in both playable scenes. This exercises the real space HUD;
|
||||||
|
# PlanetSurface carries the same layout node and is checked structurally.
|
||||||
|
|
||||||
|
var main: Node
|
||||||
|
var fleet: Node
|
||||||
|
var stage: int = 0
|
||||||
|
var elapsed: float = 0.0
|
||||||
|
|
||||||
|
|
||||||
|
func _initialize() -> void:
|
||||||
|
var state: Node = root.get_node("GameState")
|
||||||
|
state.reset_new_game()
|
||||||
|
state.intro_active = false
|
||||||
|
state.vessel_levels["unlock_laser"] = 1
|
||||||
|
state.vessel_levels["unlock_gas_bomber"] = 1
|
||||||
|
state.vessel_levels["unlock_distorder"] = 1
|
||||||
|
state.fleet_inventory.total_capacity = -1
|
||||||
|
state.deposit_fleet_resource(GameState.RESOURCE_ENERGY, 500)
|
||||||
|
state.deposit_fleet_resource(GameState.RESOURCE_GAS, 500)
|
||||||
|
main = load("res://world/Main.tscn").instantiate()
|
||||||
|
root.add_child(main)
|
||||||
|
current_scene = main
|
||||||
|
fleet = main.get_node("Fleet")
|
||||||
|
|
||||||
|
|
||||||
|
func _process(delta: float) -> bool:
|
||||||
|
elapsed += delta
|
||||||
|
if stage == 0 and elapsed >= 0.2:
|
||||||
|
main.get_node("EnemySpawner").set_process(false)
|
||||||
|
main.get_node("AsteroidField").set_process(false)
|
||||||
|
fleet.spawn_ships(3, Vector2.ZERO, PackedStringArray([
|
||||||
|
GameState.VESSEL_DISTORDER,
|
||||||
|
GameState.VESSEL_GAS_BOMBER,
|
||||||
|
GameState.VESSEL_LASER,
|
||||||
|
]))
|
||||||
|
_refresh_layout()
|
||||||
|
var layout: Node = main.get_node("AbilityButtonLayout")
|
||||||
|
var center: Vector2 = _fire_center()
|
||||||
|
var previous_angle: float = -INF
|
||||||
|
for path in ["UI/DashButton", "UI/GasBombButton", "UI/LaserButton"]:
|
||||||
|
var button: Control = main.get_node(path)
|
||||||
|
if not button.visible:
|
||||||
|
return _fail("%s is hidden in a fleet that provides every ability" % path)
|
||||||
|
var offset: Vector2 = button.global_position + button.size * 0.5 - center
|
||||||
|
if absf(offset.length() - layout.arc_radius) > 1.0 \
|
||||||
|
or offset.x > 0.1 or offset.y > 0.1:
|
||||||
|
return _fail("%s is not on the fire stick's upper-left quarter circle" % path)
|
||||||
|
var angle: float = offset.angle()
|
||||||
|
if angle < 0.0:
|
||||||
|
angle += TAU
|
||||||
|
if previous_angle != -INF and angle <= previous_angle:
|
||||||
|
return _fail("ability buttons do not follow the quarter-circle order")
|
||||||
|
previous_angle = angle
|
||||||
|
|
||||||
|
fleet.spawn_ships(1, Vector2.ZERO, PackedStringArray([GameState.VESSEL_LASER]))
|
||||||
|
_refresh_layout()
|
||||||
|
var laser: Control = main.get_node("UI/LaserButton")
|
||||||
|
var single_offset: Vector2 = laser.global_position + laser.size * 0.5 - _fire_center()
|
||||||
|
if absf(single_offset.x) > 1.0 or single_offset.y >= 0.0:
|
||||||
|
return _fail("a single ability does not sit directly above the fire stick")
|
||||||
|
var surface: Node = load("res://surface/PlanetSurface.tscn").instantiate()
|
||||||
|
if surface.get_node_or_null("AbilityButtonLayout") == null:
|
||||||
|
return _fail("planet surface is missing the shared ability layout")
|
||||||
|
surface.free()
|
||||||
|
print("abilities fan through the fire stick's upper-left quarter circle")
|
||||||
|
print("TEST_ABILITY_BUTTON_LAYOUT: PASS")
|
||||||
|
quit(0)
|
||||||
|
return true
|
||||||
|
return false
|
||||||
|
|
||||||
|
|
||||||
|
func _refresh_layout() -> void:
|
||||||
|
main.get_node("DashController")._process(0.0)
|
||||||
|
main.get_node("GasBombController")._process(0.0)
|
||||||
|
main.get_node("LaserController")._process(0.0)
|
||||||
|
main.get_node("AbilityButtonLayout")._process(0.0)
|
||||||
|
|
||||||
|
|
||||||
|
func _fire_center() -> Vector2:
|
||||||
|
var stick: Control = main.get_node("UI/FireStick")
|
||||||
|
return stick.global_position + stick.size * 0.5
|
||||||
|
|
||||||
|
|
||||||
|
func _fail(message: String) -> bool:
|
||||||
|
print("TEST_ABILITY_BUTTON_LAYOUT: FAIL (%s)" % message)
|
||||||
|
quit(1)
|
||||||
|
return true
|
||||||
|
|
@ -97,6 +97,8 @@ func _process(delta: float) -> bool:
|
||||||
first_shooter = skill._next_ready_laser_ship()
|
first_shooter = skill._next_ready_laser_ship()
|
||||||
if first_shooter == null:
|
if first_shooter == null:
|
||||||
return _fail_now("no laser ship is ready right after spawning")
|
return _fail_now("no laser ship is ready right after spawning")
|
||||||
|
if absf(first_shooter.get_component("laser").beam_range - 2900.0) > 0.1:
|
||||||
|
return _fail_now("laser ship beam range was not doubled to 2900")
|
||||||
|
|
||||||
var press := InputEventScreenTouch.new()
|
var press := InputEventScreenTouch.new()
|
||||||
press.index = 7
|
press.index = 7
|
||||||
|
|
@ -131,7 +133,7 @@ func _process(delta: float) -> bool:
|
||||||
off_line_enemy.speed = 0.0
|
off_line_enemy.speed = 0.0
|
||||||
|
|
||||||
beyond_range_enemy = load("res://enemies/Enemy.tscn").instantiate()
|
beyond_range_enemy = load("res://enemies/Enemy.tscn").instantiate()
|
||||||
beyond_range_enemy.position = first_shooter.global_position + Vector2(2000.0, 0.0)
|
beyond_range_enemy.position = first_shooter.global_position + Vector2(3400.0, 0.0)
|
||||||
main.add_child(beyond_range_enemy)
|
main.add_child(beyond_range_enemy)
|
||||||
beyond_range_enemy.speed = 0.0
|
beyond_range_enemy.speed = 0.0
|
||||||
|
|
||||||
|
|
|
||||||
49
ui/AbilityButtonLayout.gd
Normal file
49
ui/AbilityButtonLayout.gd
Normal file
|
|
@ -0,0 +1,49 @@
|
||||||
|
class_name AbilityButtonLayout
|
||||||
|
extends Node
|
||||||
|
|
||||||
|
# Keeps the aimed fleet abilities close to the firing thumb. One ability sits
|
||||||
|
# directly above the fire stick; multiple abilities fan through its upper-left
|
||||||
|
# quadrant instead of becoming a detached horizontal toolbar.
|
||||||
|
|
||||||
|
@export var arc_radius: float = 280.0
|
||||||
|
|
||||||
|
@onready var fire_stick: Control = get_node("../UI/FireStick")
|
||||||
|
@onready var buttons: Array = [
|
||||||
|
get_node("../UI/DashButton"),
|
||||||
|
get_node("../UI/GasBombButton"),
|
||||||
|
get_node("../UI/LaserButton"),
|
||||||
|
]
|
||||||
|
|
||||||
|
var visibility_signature: int = -1
|
||||||
|
|
||||||
|
|
||||||
|
func _ready() -> void:
|
||||||
|
get_viewport().size_changed.connect(_layout_visible_buttons)
|
||||||
|
_layout_visible_buttons.call_deferred()
|
||||||
|
|
||||||
|
|
||||||
|
func _process(_delta: float) -> void:
|
||||||
|
var signature: int = 0
|
||||||
|
for i in range(buttons.size()):
|
||||||
|
if buttons[i].visible:
|
||||||
|
signature |= 1 << i
|
||||||
|
if signature == visibility_signature:
|
||||||
|
return
|
||||||
|
visibility_signature = signature
|
||||||
|
_layout_visible_buttons()
|
||||||
|
|
||||||
|
|
||||||
|
func _layout_visible_buttons() -> void:
|
||||||
|
var visible_buttons: Array = buttons.filter(func(button): return button.visible)
|
||||||
|
if visible_buttons.is_empty():
|
||||||
|
return
|
||||||
|
var center: Vector2 = fire_stick.global_position + fire_stick.size * 0.5
|
||||||
|
for i in range(visible_buttons.size()):
|
||||||
|
# Screen coordinates grow downward: PI points left and 3*PI/2 points
|
||||||
|
# upward, tracing exactly the useful quarter around a bottom-right stick.
|
||||||
|
var weight: float = 1.0 if visible_buttons.size() == 1 \
|
||||||
|
else float(i) / float(visible_buttons.size() - 1)
|
||||||
|
var angle: float = lerpf(PI, PI * 1.5, weight)
|
||||||
|
var button: Control = visible_buttons[i]
|
||||||
|
button.global_position = center + Vector2.from_angle(angle) * arc_radius \
|
||||||
|
- button.size * 0.5
|
||||||
|
|
@ -4,9 +4,9 @@
|
||||||
script = ExtResource("1")
|
script = ExtResource("1")
|
||||||
upgrade_id = "lsr_range"
|
upgrade_id = "lsr_range"
|
||||||
display_name = "Beam Collimator"
|
display_name = "Beam Collimator"
|
||||||
description = "+150 beam range per level."
|
description = "+300 beam range per level."
|
||||||
base_cost = 25
|
base_cost = 25
|
||||||
max_level = 3
|
max_level = 3
|
||||||
research_point_cost = 1
|
research_point_cost = 1
|
||||||
icon = 17
|
icon = 17
|
||||||
additive_modifiers = {"beam_range": 150.0}
|
additive_modifiers = {"beam_range": 300.0}
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ hull_points = PackedVector2Array(0, -26, -9, 14, -4, 10, 4, 10, 9, 14)
|
||||||
fleet_eligible = true
|
fleet_eligible = true
|
||||||
capabilities = PackedStringArray("laser")
|
capabilities = PackedStringArray("laser")
|
||||||
component_scenes = Array[PackedScene]([ExtResource("2")])
|
component_scenes = Array[PackedScene]([ExtResource("2")])
|
||||||
base_stats = {"max_speed": 660.0, "acceleration": 1890.0, "delivery_speed": 180.0, "damage": 2.0, "beam_range": 1450.0, "beam_cooldown": 4.0}
|
base_stats = {"max_speed": 660.0, "acceleration": 1890.0, "delivery_speed": 180.0, "damage": 2.0, "beam_range": 2900.0, "beam_cooldown": 4.0}
|
||||||
minimum_stats = {"beam_cooldown": 1.5}
|
minimum_stats = {"beam_cooldown": 1.5}
|
||||||
upgrades = Array[Resource]([ExtResource("3"), ExtResource("4"), ExtResource("5")])
|
upgrades = Array[Resource]([ExtResource("3"), ExtResource("4"), ExtResource("5")])
|
||||||
unlock_id = "unlock_laser"
|
unlock_id = "unlock_laser"
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ extends "res://vessels/VesselCooldownFillComponent.gd"
|
||||||
|
|
||||||
var capability_id := "laser"
|
var capability_id := "laser"
|
||||||
var damage: int = 2
|
var damage: int = 2
|
||||||
var beam_range: float = 950.0
|
var beam_range: float = 2900.0
|
||||||
|
|
||||||
const READY_COLOR := Color(0.3, 0.9, 1.0)
|
const READY_COLOR := Color(0.3, 0.9, 1.0)
|
||||||
const COOLING_COLOR := Color(0.08, 0.28, 0.34)
|
const COOLING_COLOR := Color(0.08, 0.28, 0.34)
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
[gd_scene load_steps=45 format=3]
|
[gd_scene load_steps=46 format=3]
|
||||||
[ext_resource type="PackedScene" path="res://ui/menus/BuildMenu.tscn" id="menu_build"]
|
[ext_resource type="PackedScene" path="res://ui/menus/BuildMenu.tscn" id="menu_build"]
|
||||||
[ext_resource type="PackedScene" path="res://ui/menus/HangarMenu.tscn" id="menu_hangar"]
|
[ext_resource type="PackedScene" path="res://ui/menus/HangarMenu.tscn" id="menu_hangar"]
|
||||||
[ext_resource type="PackedScene" path="res://ui/menus/LabMenu.tscn" id="menu_lab"]
|
[ext_resource type="PackedScene" path="res://ui/menus/LabMenu.tscn" id="menu_lab"]
|
||||||
|
|
@ -41,6 +41,7 @@
|
||||||
[ext_resource type="Script" path="res://controllers/GasBombController.gd" id="29"]
|
[ext_resource type="Script" path="res://controllers/GasBombController.gd" id="29"]
|
||||||
[ext_resource type="Script" path="res://controllers/LaserController.gd" id="30"]
|
[ext_resource type="Script" path="res://controllers/LaserController.gd" id="30"]
|
||||||
[ext_resource type="Script" path="res://controllers/DashController.gd" id="dash_ctrl"]
|
[ext_resource type="Script" path="res://controllers/DashController.gd" id="dash_ctrl"]
|
||||||
|
[ext_resource type="Script" path="res://ui/AbilityButtonLayout.gd" id="ability_layout"]
|
||||||
[ext_resource type="Script" path="res://ui/SpeedFader.gd" id="31"]
|
[ext_resource type="Script" path="res://ui/SpeedFader.gd" id="31"]
|
||||||
[ext_resource type="Script" path="res://world/QuestDirector.gd" id="quest_dir"]
|
[ext_resource type="Script" path="res://world/QuestDirector.gd" id="quest_dir"]
|
||||||
[ext_resource type="Script" path="res://ui/QuestPanel.gd" id="quest_panel"]
|
[ext_resource type="Script" path="res://ui/QuestPanel.gd" id="quest_panel"]
|
||||||
|
|
@ -87,6 +88,9 @@ script = ExtResource("30")
|
||||||
[node name="DashController" type="Node2D" parent="."]
|
[node name="DashController" type="Node2D" parent="."]
|
||||||
script = ExtResource("dash_ctrl")
|
script = ExtResource("dash_ctrl")
|
||||||
|
|
||||||
|
[node name="AbilityButtonLayout" type="Node" parent="."]
|
||||||
|
script = ExtResource("ability_layout")
|
||||||
|
|
||||||
[node name="Camera2D" type="Camera2D" parent="."]
|
[node name="Camera2D" type="Camera2D" parent="."]
|
||||||
position = Vector2(0, 0)
|
position = Vector2(0, 0)
|
||||||
zoom = Vector2(1, 1)
|
zoom = Vector2(1, 1)
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue