From 491d0a0b323e43042128008f62386517cf743cb7 Mon Sep 17 00:00:00 2001 From: Fabio Iotti Date: Thu, 15 Aug 2024 11:18:54 +0200 Subject: [PATCH] Refactoring --- main.tscn | 79 ++++++------ .../background_nebula.gdshader} | 0 .../background_nebula.tscn} | 4 +- .../control_planet.gd} | 4 +- .../control_planet.tscn} | 4 +- .../planet_selection.gdshader | 0 scenes/player/local_player.gd | 10 -- scenes/player/player.gd | 14 --- scenes/ships_fleet/ships_fleet.gd | 41 +++++-- scenes/templates/template_scenes.gd | 4 + scenes/templates/templates.tres | 8 ++ scripts/game_logic.gd | 112 ++++++++++-------- scripts/game_operation.gd | 2 - scripts/game_operation_send_fleet.gd | 8 -- scripts/game_state.gd | 102 ++++++++++++++++ scripts/planet.gd | 10 ++ scripts/player.gd | 9 ++ scripts/player_ai.gd | 5 + scripts/player_local.gd | 5 + scripts/ui/planets_ui.gd | 80 +++++++++++++ scripts/{util.gd => utils.gd} | 2 +- ui.gd | 88 -------------- 22 files changed, 361 insertions(+), 230 deletions(-) rename scenes/{nebula/nebula.gdshader => background_nebula/background_nebula.gdshader} (100%) rename scenes/{nebula/nebula.tscn => background_nebula/background_nebula.tscn} (79%) rename scenes/{planet/planet.gd => control_planet/control_planet.gd} (90%) rename scenes/{planet/planet.tscn => control_planet/control_planet.tscn} (92%) rename scenes/{planet => control_planet}/planet_selection.gdshader (100%) delete mode 100644 scenes/player/local_player.gd delete mode 100644 scenes/player/player.gd create mode 100644 scenes/templates/template_scenes.gd create mode 100644 scenes/templates/templates.tres delete mode 100644 scripts/game_operation.gd delete mode 100644 scripts/game_operation_send_fleet.gd create mode 100644 scripts/game_state.gd create mode 100644 scripts/planet.gd create mode 100644 scripts/player.gd create mode 100644 scripts/player_ai.gd create mode 100644 scripts/player_local.gd create mode 100644 scripts/ui/planets_ui.gd rename scripts/{util.gd => utils.gd} (96%) delete mode 100644 ui.gd diff --git a/main.tscn b/main.tscn index a922d8c..733336b 100644 --- a/main.tscn +++ b/main.tscn @@ -1,66 +1,73 @@ -[gd_scene load_steps=12 format=3 uid="uid://cdaf4bh0jaa45"] +[gd_scene load_steps=21 format=3 uid="uid://cdaf4bh0jaa45"] -[ext_resource type="PackedScene" uid="uid://dq00mi6jwsa1f" path="res://scenes/planet/planet.tscn" id="1_0p552"] -[ext_resource type="Script" path="res://scripts/game_logic.gd" id="1_kb05v"] -[ext_resource type="Script" path="res://scenes/player/player.gd" id="2_plgh6"] +[ext_resource type="Script" path="res://scripts/game_logic.gd" id="1_uj8ti"] +[ext_resource type="Resource" uid="uid://cp0dudi0f5r62" path="res://scenes/templates/templates.tres" id="2_1lypt"] +[ext_resource type="Script" path="res://scripts/player.gd" id="2_plgh6"] [ext_resource type="Texture2D" uid="uid://bydmcc5d53ldx" path="res://icons/paw_print.svg" id="3_mxakn"] [ext_resource type="Texture2D" uid="uid://1xh0qil16bkh" path="res://icons/character.svg" id="3_qxmev"] -[ext_resource type="Script" path="res://scenes/player/local_player.gd" id="4_7rlmh"] +[ext_resource type="Script" path="res://scripts/player_local.gd" id="4_7rlmh"] [ext_resource type="Texture2D" uid="uid://dx1wjviioa8u5" path="res://icons/chip.svg" id="4_pgo63"] -[ext_resource type="Script" path="res://ui.gd" id="7_khbdl"] -[ext_resource type="PackedScene" uid="uid://dtlatmtuggp6x" path="res://scenes/nebula/nebula.tscn" id="7_sv4lv"] +[ext_resource type="Script" path="res://scripts/ui/planets_ui.gd" id="7_khbdl"] +[ext_resource type="PackedScene" uid="uid://dtlatmtuggp6x" path="res://scenes/background_nebula/background_nebula.tscn" id="7_sv4lv"] +[ext_resource type="Script" path="res://scripts/player_ai.gd" id="7_v73fw"] +[ext_resource type="Script" path="res://scripts/planet.gd" id="8_ve3b1"] [ext_resource type="PackedScene" uid="uid://cpffyaoh8x5bp" path="res://scenes/ships_fleet/ships_fleet.tscn" id="9_be18b"] [ext_resource type="PackedScene" uid="uid://ckfk1xgxfk1c3" path="res://scenes/trail/trail.tscn" id="10_b5ql7"] -[node name="Main" type="Node"] - -[node name="Logic" type="Node" parent="." node_paths=PackedStringArray("neutral_player", "players", "planets")] -script = ExtResource("1_kb05v") -neutral_player = NodePath("Players/0_Nature") -players = [NodePath("Players/1_LocalPlayer"), NodePath("Players/2_AI")] -planets = [NodePath("../Game/Planets/Planet1"), NodePath("../Game/Planets/Planet2"), NodePath("../Game/Planets/Planet3"), NodePath("../Game/Planets/Planet4")] - -[node name="Players" type="Node" parent="Logic"] - -[node name="0_Nature" type="Node" parent="Logic/Players"] +[sub_resource type="Resource" id="Resource_mxp7y"] script = ExtResource("2_plgh6") color = Color(0.745, 0.745, 0.745, 1) icon = ExtResource("3_mxakn") -[node name="1_LocalPlayer" type="Node" parent="Logic/Players" node_paths=PackedStringArray("ui")] +[sub_resource type="Resource" id="Resource_1dtpf"] script = ExtResource("4_7rlmh") -ui = NodePath("../../../UI") -color = Color(0.184314, 0.329412, 1, 1) +color = Color(0.236993, 0.373968, 1, 1) icon = ExtResource("3_qxmev") -[node name="2_AI" type="Node" parent="Logic/Players"] -script = ExtResource("2_plgh6") +[sub_resource type="Resource" id="Resource_7wtc7"] +script = ExtResource("7_v73fw") color = Color(0.835294, 0.160784, 0, 1) icon = ExtResource("4_pgo63") -[node name="Nebula" parent="." instance=ExtResource("7_sv4lv")] +[sub_resource type="Resource" id="Resource_50eg2"] +script = ExtResource("8_ve3b1") +location = Vector2(200, 200) +type = 0 -[node name="Game" type="Node2D" parent="."] +[sub_resource type="Resource" id="Resource_2525o"] +script = ExtResource("8_ve3b1") +location = Vector2(952, 448) +type = 0 -[node name="Planets" type="Node2D" parent="Game"] +[sub_resource type="Resource" id="Resource_irtww"] +script = ExtResource("8_ve3b1") +location = Vector2(450, 234) +type = 0 -[node name="Planet1" parent="Game/Planets" instance=ExtResource("1_0p552")] -position = Vector2(200, 200) +[sub_resource type="Resource" id="Resource_wdycy"] +script = ExtResource("8_ve3b1") +location = Vector2(702, 414) +type = 0 -[node name="Planet2" parent="Game/Planets" instance=ExtResource("1_0p552")] -position = Vector2(952, 448) +[node name="Main" type="Node"] -[node name="Planet3" parent="Game/Planets" instance=ExtResource("1_0p552")] -position = Vector2(450, 234) +[node name="GameLogic" type="Node" parent="." node_paths=PackedStringArray("planets_container", "planets_ui")] +script = ExtResource("1_uj8ti") +templates = ExtResource("2_1lypt") +planets_container = NodePath("../Planets") +planets_ui = NodePath("../PlanetsUI") +players = Array[ExtResource("2_plgh6")]([SubResource("Resource_mxp7y"), SubResource("Resource_1dtpf"), SubResource("Resource_7wtc7")]) +planets = Array[ExtResource("8_ve3b1")]([SubResource("Resource_50eg2"), SubResource("Resource_2525o"), SubResource("Resource_irtww"), SubResource("Resource_wdycy")]) -[node name="Planet4" parent="Game/Planets" instance=ExtResource("1_0p552")] -position = Vector2(702, 414) +[node name="BackgroundNebula" parent="." instance=ExtResource("7_sv4lv")] + +[node name="Planets" type="Node2D" parent="."] [node name="ShipsFleet" parent="." instance=ExtResource("9_be18b")] position = Vector2(246, 394) count = 29 -[node name="UI" type="Control" parent="." node_paths=PackedStringArray("trail")] +[node name="PlanetsUI" type="Control" parent="." node_paths=PackedStringArray("trail")] layout_mode = 3 anchors_preset = 15 anchor_right = 1.0 @@ -71,5 +78,5 @@ mouse_filter = 2 script = ExtResource("7_khbdl") trail = NodePath("Trail") -[node name="Trail" parent="UI" instance=ExtResource("10_b5ql7")] +[node name="Trail" parent="PlanetsUI" instance=ExtResource("10_b5ql7")] visible = false diff --git a/scenes/nebula/nebula.gdshader b/scenes/background_nebula/background_nebula.gdshader similarity index 100% rename from scenes/nebula/nebula.gdshader rename to scenes/background_nebula/background_nebula.gdshader diff --git a/scenes/nebula/nebula.tscn b/scenes/background_nebula/background_nebula.tscn similarity index 79% rename from scenes/nebula/nebula.tscn rename to scenes/background_nebula/background_nebula.tscn index b48c073..1448855 100644 --- a/scenes/nebula/nebula.tscn +++ b/scenes/background_nebula/background_nebula.tscn @@ -1,6 +1,6 @@ [gd_scene load_steps=5 format=3 uid="uid://dtlatmtuggp6x"] -[ext_resource type="Shader" path="res://scenes/nebula/nebula.gdshader" id="1_nqp0c"] +[ext_resource type="Shader" path="res://scenes/background_nebula/background_nebula.gdshader" id="1_nqp0c"] [sub_resource type="FastNoiseLite" id="FastNoiseLite_8c2xm"] @@ -14,7 +14,7 @@ noise = SubResource("FastNoiseLite_8c2xm") shader = ExtResource("1_nqp0c") shader_parameter/noise = SubResource("NoiseTexture2D_cukca") -[node name="Nebula" type="ColorRect"] +[node name="BackgroundNebula" type="ColorRect"] material = SubResource("ShaderMaterial_y72ex") anchors_preset = 15 anchor_right = 1.0 diff --git a/scenes/planet/planet.gd b/scenes/control_planet/control_planet.gd similarity index 90% rename from scenes/planet/planet.gd rename to scenes/control_planet/control_planet.gd index 7cdb576..3cda2e3 100644 --- a/scenes/planet/planet.gd +++ b/scenes/control_planet/control_planet.gd @@ -1,5 +1,5 @@ extends Node2D -class_name Planet +class_name ControlPlanet ## The player currenly controlling this planet. var player: Player : @@ -32,7 +32,7 @@ var is_selected: bool : set(value): %Selection.visible = value -func _on_input_listener_input_event(viewport: Node, event: InputEvent, shape_idx: int) -> void: +func _on_input_listener_input_event(_viewport: Node, event: InputEvent, _shape_idx: int) -> void: # TODO: handle touch appropriately (InputEventScreenTouch). if event is InputEventMouseButton and event.button_index == MOUSE_BUTTON_LEFT and event.is_pressed(): selected.emit(self) diff --git a/scenes/planet/planet.tscn b/scenes/control_planet/control_planet.tscn similarity index 92% rename from scenes/planet/planet.tscn rename to scenes/control_planet/control_planet.tscn index c14cf48..a32b6ca 100644 --- a/scenes/planet/planet.tscn +++ b/scenes/control_planet/control_planet.tscn @@ -1,8 +1,8 @@ [gd_scene load_steps=7 format=3 uid="uid://dq00mi6jwsa1f"] [ext_resource type="PackedScene" uid="uid://dnerbdusnaofr" path="res://scenes/procedural_planet/procedural_planet.tscn" id="1_8mf3x"] -[ext_resource type="Script" path="res://scenes/planet/planet.gd" id="1_e208c"] -[ext_resource type="Shader" path="res://scenes/planet/planet_selection.gdshader" id="2_bl05u"] +[ext_resource type="Script" path="res://scenes/control_planet/control_planet.gd" id="1_e208c"] +[ext_resource type="Shader" path="res://scenes/control_planet/planet_selection.gdshader" id="2_bl05u"] [ext_resource type="Texture2D" uid="uid://1xh0qil16bkh" path="res://icons/character.svg" id="2_kglxp"] [sub_resource type="CircleShape2D" id="CircleShape2D_tsywx"] diff --git a/scenes/planet/planet_selection.gdshader b/scenes/control_planet/planet_selection.gdshader similarity index 100% rename from scenes/planet/planet_selection.gdshader rename to scenes/control_planet/planet_selection.gdshader diff --git a/scenes/player/local_player.gd b/scenes/player/local_player.gd deleted file mode 100644 index ba145e7..0000000 --- a/scenes/player/local_player.gd +++ /dev/null @@ -1,10 +0,0 @@ -extends Player -class_name LocalPlayer - -@export var ui: GameUI - -func _on_game_start(game: GameLogic) -> void: - ui._on_game_started(game) - -func _on_game_tick(game: GameLogic, tick: int) -> void: - pass diff --git a/scenes/player/player.gd b/scenes/player/player.gd deleted file mode 100644 index c866ed7..0000000 --- a/scenes/player/player.gd +++ /dev/null @@ -1,14 +0,0 @@ -extends Node -class_name Player - -@export var color: Color = Color.MAGENTA - -@export var icon: Texture2D - -var pending_operations: Array[GameOperation] = [] - -func _on_game_start(game: GameLogic) -> void: - pass - -func _on_game_tick(game: GameLogic, tick: int) -> void: - pass diff --git a/scenes/ships_fleet/ships_fleet.gd b/scenes/ships_fleet/ships_fleet.gd index 66588ef..60b9c32 100644 --- a/scenes/ships_fleet/ships_fleet.gd +++ b/scenes/ships_fleet/ships_fleet.gd @@ -1,22 +1,37 @@ extends Node2D +class_name ShipFleet + +@export var departed_at: int + +@export var arrives_at: int + +@export var from: Vector2 + +@export var to: Vector2 + +@export var count: int : + set(value): + count = value + _update_instances_count() + +#region Graphics var instances: Array[Node2D] = [] @export var ship_template: PackedScene -@export var count: int : - set(value): - count = value +func _update_instances_count() -> void : + var diff = count - instances.size() - var diff = count - instances.size() + for i in range(diff): + var j = float(1 + instances.size()) + var ship := ship_template.instantiate() + add_child(ship) + ship.position = Vector2.from_angle(j) * j * 2. + instances.push_back(ship) - for i in range(diff): - var j = float(1 + instances.size()) - var ship := ship_template.instantiate() - add_child(ship) - ship.position = Vector2.from_angle(j) * j * 2. - instances.push_back(ship) + for i in range(-diff): + var ship: Node2D = instances.pop_back() + remove_child(ship) - for i in range(-diff): - var ship: Node2D = instances.pop_back() - remove_child(ship) +#endregion diff --git a/scenes/templates/template_scenes.gd b/scenes/templates/template_scenes.gd new file mode 100644 index 0000000..4a64ddb --- /dev/null +++ b/scenes/templates/template_scenes.gd @@ -0,0 +1,4 @@ +class_name TemplateScenes +extends Resource + +@export var control_planet: PackedScene diff --git a/scenes/templates/templates.tres b/scenes/templates/templates.tres new file mode 100644 index 0000000..11026ef --- /dev/null +++ b/scenes/templates/templates.tres @@ -0,0 +1,8 @@ +[gd_resource type="Resource" script_class="TemplateScenes" load_steps=3 format=3 uid="uid://cp0dudi0f5r62"] + +[ext_resource type="PackedScene" uid="uid://dq00mi6jwsa1f" path="res://scenes/control_planet/control_planet.tscn" id="1_3rbtf"] +[ext_resource type="Script" path="res://scenes/templates/template_scenes.gd" id="1_yvn3m"] + +[resource] +script = ExtResource("1_yvn3m") +control_planet = ExtResource("1_3rbtf") diff --git a/scripts/game_logic.gd b/scripts/game_logic.gd index e6d109b..9cf36a7 100644 --- a/scripts/game_logic.gd +++ b/scripts/game_logic.gd @@ -1,69 +1,77 @@ -extends Node class_name GameLogic +extends Node -const LOGIC_TICKS_PER_SECOND: float = 20. -const LOGIC_SECONDS_PER_TICK = 1. / LOGIC_TICKS_PER_SECOND +const LOGIC_TICKS_PER_SECOND := 20. +const LOGIC_SECONDS_PER_TICK := 1. / LOGIC_TICKS_PER_SECOND -## Neutral player owning all non-conquered planets. -@export var neutral_player: Player +## Templates for spawnable stuff. +@export var templates: TemplateScenes + +## Container for planets. +@export var planets_container: Node2D + +## Interface to interact with planets. +@export var planets_ui: PlanetsUI ## Game players. -@export var players: Array[Player] = [] +@export var players: Array[Player] ## Game planets. -@export var planets: Array[Planet] = [] +@export var planets: Array[Planet] -var ticks_count: int -var extra_time: float +var _game: GameState +var _planet_controls: Array[ControlPlanet] -signal game_start(game: GameLogic) -signal game_tick(game: GameLogic, tick: int) +var _extra_time: float func _ready() -> void: - _game_init() - game_start.emit(self) + # New game. + _game = GameState.new() + + # Add players. + for i in range(players.size()): + _game.add_player() + + # Add planets. + for i in range(planets.size()): + # Data. + var data := GameState.PlanetData.new() + data.position = Vector2i(planets[i].location) + data.grow_every_ticks = 10 + data.player_id = (i + 1) if (i < players.size() - 1) else 0 + data.population = 0 + _game.add_planet(data) + + # UI control. + var control: ControlPlanet = templates.control_planet.instantiate() + control.position = planets[i].location + control.player = players[data.player_id] + control.population = data.population + _planet_controls.push_back(control) + planets_container.add_child(control) + planets_ui.register_planet(control) + + # Register UI signals. + _game.planet_player_changed.connect(_set_planet_player) + _game.planet_population_changed.connect(_set_planet_population) + planets_ui.fleet_dispatched.connect(_dispatch_fleet) func _process(delta: float) -> void: - extra_time += delta + _extra_time += delta - while extra_time > LOGIC_SECONDS_PER_TICK: - extra_time -= LOGIC_SECONDS_PER_TICK - _game_tick(ticks_count) - ticks_count += 1 + while _extra_time > LOGIC_SECONDS_PER_TICK: + _extra_time -= LOGIC_SECONDS_PER_TICK + _game.tick() -func _game_init() -> void: - ticks_count = 0 - extra_time = 0. +func _set_planet_player(planet_id: int, player_id: int) -> void: + _planet_controls[planet_id].player = players[player_id] - for player in players: - game_start.connect(player._on_game_start) - game_tick.connect(player._on_game_tick) +func _set_planet_population(planet_id: int, population: int) -> void: + _planet_controls[planet_id].population = population - for i in range(planets.size()): - var planet := planets[i] - planet.player = players[i] if i < players.size() else neutral_player - planet.is_selected = false - -func _game_tick(tick: int) -> void: - for planet in planets: - if planet.player != neutral_player and tick % 10 == 0: - planet.population += 1 - - for player in players: - for op in player.pending_operations: - if op is GameOperationSendFleet: - var count = min(op.max_count, op.from.population) - op.from.population -= count - if op.from.player == op.to.player: - op.to.population += count - else: - op.to.population -= count - if op.to.population <= 0: - op.to.player = op.from.player - op.to.population = abs(op.from.population) - else: - assert(false, "Unknown GameOperation: %s" % [op]) - - player.pending_operations.clear() - - game_tick.emit(self, tick) +func _dispatch_fleet(from: ControlPlanet, to: ControlPlanet) -> void: + var player_id := players.find(from.player) + var from_planet_id := _planet_controls.find(from) + var to_planet_id := _planet_controls.find(to) + var max_count: int = ceil(from.population / 2.) + _game.dispatch_fleet(player_id, from_planet_id, to_planet_id, max_count) diff --git a/scripts/game_operation.gd b/scripts/game_operation.gd deleted file mode 100644 index 01f358d..0000000 --- a/scripts/game_operation.gd +++ /dev/null @@ -1,2 +0,0 @@ -extends RefCounted -class_name GameOperation diff --git a/scripts/game_operation_send_fleet.gd b/scripts/game_operation_send_fleet.gd deleted file mode 100644 index acadd45..0000000 --- a/scripts/game_operation_send_fleet.gd +++ /dev/null @@ -1,8 +0,0 @@ -extends GameOperation -class_name GameOperationSendFleet - -var from: Planet - -var to: Planet - -var max_count: int diff --git a/scripts/game_state.gd b/scripts/game_state.gd new file mode 100644 index 0000000..441e60d --- /dev/null +++ b/scripts/game_state.gd @@ -0,0 +1,102 @@ +class_name GameState +extends Resource + +class PlayerData: + var commands: Array[Command] = [] + +class PlanetData: + var position: Vector2i + var grow_every_ticks: int + var player_id: int ## 0 = none + var population: int + +class FleetData: + var count: int + +enum CommandType { + DISPATCH_FLEET, +} + +class Command: + var type: CommandType + var wait_tick: int + +class DispatchFleedCommand extends Command: + var from_planet_id: int + var to_planet_id: int + var max_count: int + func _init(): + type = CommandType.DISPATCH_FLEET + +signal game_ticked(tick: int) +signal planet_population_changed(planet_id: int, population: int) +signal planet_player_changed(planet_id: int, player_id: int) + +var _players: Array[PlayerData] = [] +var _planets: Array[PlanetData] = [] +var _fleets: Array[FleetData] = [] + +var current_tick: int + +## Add a player to the game. +## The first player is expected to be the game master / neutral player, +## who does not play and for whom the population never increases. +func add_player(data := PlayerData.new()) -> int: + _players.push_back(data) + return _players.size() - 1 + +## Add a planet to the game. +func add_planet(data := PlanetData.new()) -> int: + _planets.push_back(data) + return _planets.size() - 1 + +## Advance game status by one tick. +func tick() -> void: + current_tick += 1 + + for planet_id in range(_planets.size()): + var planet := _planets[planet_id] + if planet.player_id != 0 and current_tick % planet.grow_every_ticks == 0: + planet.population += 1 + planet_population_changed.emit(planet_id, planet.population) + + for player_id in range(_players.size()): + var player := _players[player_id] + if player.commands.size() > 0 && current_tick >= player.commands[0].wait_tick: + var command: Command = player.commands.pop_back() + match command.type: + CommandType.DISPATCH_FLEET: + _handle_dispatch_fleet(player_id, command) + _: + assert(false, "Unknown command: %s" % [command]) + + game_ticked.emit(current_tick) + +## Dispatch a fleet. +func dispatch_fleet(player_id: int, from_planet_id: int, to_planet_id: int, max_count: int) -> void: + var dispatch := DispatchFleedCommand.new() + dispatch.from_planet_id = from_planet_id + dispatch.to_planet_id = to_planet_id + dispatch.max_count = max_count + _issue_command(player_id, dispatch) + +func _issue_command(player_id: int, command: Command) -> void: + var commands := _players[player_id].commands + var index := commands.map(func (x): return x.wait_tick).bsearch(command.wait_tick, false) + commands.insert(index, command) + +func _handle_dispatch_fleet(player_id: int, dispatch: DispatchFleedCommand) -> void: + var from = _planets[dispatch.from_planet_id] + var to = _planets[dispatch.to_planet_id] + var count = min(dispatch.max_count, from.population) + from.population -= count + if from.player_id == to.player_id: + to.population += count + else: + to.population -= count + if to.population <= 0: + to.player_id = from.player_id + to.population = abs(from.population) + planet_player_changed.emit(dispatch.to_planet_id, to.player_id) + planet_population_changed.emit(dispatch.from_planet_id, from.population) + planet_population_changed.emit(dispatch.to_planet_id, to.population) diff --git a/scripts/planet.gd b/scripts/planet.gd new file mode 100644 index 0000000..401b673 --- /dev/null +++ b/scripts/planet.gd @@ -0,0 +1,10 @@ +class_name Planet +extends Resource + +enum PlanetType { + TERRESTRIAL, +} + +@export var location: Vector2 + +@export var type: PlanetType diff --git a/scripts/player.gd b/scripts/player.gd new file mode 100644 index 0000000..b88b858 --- /dev/null +++ b/scripts/player.gd @@ -0,0 +1,9 @@ +class_name Player +extends Resource + +@export var color: Color = Color.MAGENTA + +@export var icon: Texture2D + +func process_game_tick(_game: GameLogic) -> void: + pass diff --git a/scripts/player_ai.gd b/scripts/player_ai.gd new file mode 100644 index 0000000..b8504f2 --- /dev/null +++ b/scripts/player_ai.gd @@ -0,0 +1,5 @@ +class_name AIPlayer +extends Player + +func process_game_tick(_game: GameLogic) -> void: + pass diff --git a/scripts/player_local.gd b/scripts/player_local.gd new file mode 100644 index 0000000..483d8d0 --- /dev/null +++ b/scripts/player_local.gd @@ -0,0 +1,5 @@ +class_name LocalPlayer +extends Player + +func process_game_tick(_game: GameLogic) -> void: + pass diff --git a/scripts/ui/planets_ui.gd b/scripts/ui/planets_ui.gd new file mode 100644 index 0000000..2e3a300 --- /dev/null +++ b/scripts/ui/planets_ui.gd @@ -0,0 +1,80 @@ +class_name PlanetsUI +extends Control + +@export var trail: Trail + +signal fleet_dispatched(from: ControlPlanet, to: ControlPlanet) + +func register_planet(control: ControlPlanet) -> void: + control.selected.connect(_on_planet_selected) + control.pointer_entered.connect(_on_planet_pointer_entered) + control.pointer_exited.connect(_on_planet_pointer_exited) + +func _process(delta: float) -> void: + _update_trail(delta, false) + +func _unhandled_input(event: InputEvent) -> void: + if event is InputEventMouse: + _handle_mouse_input(event) + +#region Mouse input + +var _last_cursor_position: Vector2 + +func _handle_mouse_input(event: InputEventMouse) -> void: + if event is InputEventMouseMotion: + # The trail follows the cursor. + _last_cursor_position = event.global_position + + if event is InputEventMouseButton and event.button_index == MOUSE_BUTTON_LEFT and event.is_released(): + # The trail disappears when no longer dragging. + _dragging_from_planet = false + + # Detect mouse released on a planet and spawn a fleet. + if _selected_planet != null and _selected_planet.player is LocalPlayer and _pointed_planet != null: + fleet_dispatched.emit(_selected_planet, _pointed_planet) + +#endregion + +#region Planets + +var _selected_planet: ControlPlanet +var _pointed_planet: ControlPlanet +var _dragging_from_planet: bool + +func _on_planet_selected(planet: ControlPlanet) -> void: + if _selected_planet != null: + _selected_planet.is_selected = false + + _selected_planet = planet + _selected_planet.is_selected = true + + _dragging_from_planet = true + _update_trail(0., true) + +func _on_planet_pointer_entered(planet: ControlPlanet) -> void: + _pointed_planet = planet + +func _on_planet_pointer_exited(planet: ControlPlanet) -> void: + if _pointed_planet == planet: + _pointed_planet = null + +#endregion + +#region Trail + +var _trail_opacity := 0. + +func _update_trail(delta: float, snap_position: bool) -> void: + var show_trail := _dragging_from_planet and _selected_planet != null and _selected_planet.player is LocalPlayer + if show_trail or trail.visible: + _trail_opacity = Utils.damp(_trail_opacity, 1. if show_trail else 0., 1e-4, delta) + trail.color = Color(_selected_planet.player.color, _trail_opacity) + trail.visible = _trail_opacity > .01 + + if show_trail: + var target_position = _last_cursor_position if _pointed_planet == null else _pointed_planet.global_position + trail.start_position = _selected_planet.global_position + trail.end_position = target_position if snap_position else Utils.damp(trail.end_position, target_position, 1e-20, delta) + +#endregion diff --git a/scripts/util.gd b/scripts/utils.gd similarity index 96% rename from scripts/util.gd rename to scripts/utils.gd index f44479d..56a4ef9 100644 --- a/scripts/util.gd +++ b/scripts/utils.gd @@ -1,4 +1,4 @@ -class_name Util +class_name Utils ## Time-independent damping with exponential-decay. ## diff --git a/ui.gd b/ui.gd deleted file mode 100644 index a5800c1..0000000 --- a/ui.gd +++ /dev/null @@ -1,88 +0,0 @@ -extends Control -class_name GameUI - -@export var trail: Trail - -var game: GameLogic - - -func _on_game_started(game: GameLogic) -> void: - self.game = game - - for planet in game.planets: - planet.selected.connect(_on_planet_selected) - planet.pointer_entered.connect(_on_planet_pointer_entered) - planet.pointer_exited.connect(_on_planet_pointer_exited) - -func _process(delta: float) -> void: - _update_trail(delta, false) - -func _unhandled_input(event: InputEvent) -> void: - if event is InputEventMouse: - _handle_mouse_input(event) - -#region Mouse input - -var last_cursor_position: Vector2 - -func _handle_mouse_input(event: InputEventMouse) -> void: - if event is InputEventMouseMotion: - # The trail follows the cursor. - last_cursor_position = event.global_position - - if event is InputEventMouseButton and event.button_index == MOUSE_BUTTON_LEFT and event.is_released(): - # The trail disappears when no longer dragging. - dragging_from_planet = false - - # Detect mouse released on a planet and spawn a fleet. - if selected_planet != null and selected_planet.player is LocalPlayer and pointed_planet != null: - var op := GameOperationSendFleet.new() - op.from = selected_planet - op.to = pointed_planet - op.max_count = ceil(selected_planet.population / 2) - selected_planet.player.pending_operations.push_front(op) - -#endregion - -#region Planets - -var selected_planet: Planet -var pointed_planet: Planet -var dragging_from_planet: bool - -func _on_planet_selected(planet: Planet) -> void: - if selected_planet != null: - selected_planet.is_selected = false - - selected_planet = planet - selected_planet.is_selected = true - - dragging_from_planet = true - _update_trail(0., true) - -func _on_planet_pointer_entered(planet: Planet) -> void: - pointed_planet = planet - -func _on_planet_pointer_exited(planet: Planet) -> void: - if pointed_planet == planet: - pointed_planet = null - -#endregion - -#region Trail - -var trail_opacity := 0. - -func _update_trail(delta: float, snap_position: bool) -> void: - var show_trail := dragging_from_planet and selected_planet != null and selected_planet.player is LocalPlayer - if show_trail or trail.visible: - trail_opacity = Util.damp(trail_opacity, 1. if show_trail else 0., 1e-4, delta) - trail.color = Color(selected_planet.player.color, trail_opacity) - trail.visible = trail_opacity > .01 - - if show_trail: - var target_position = last_cursor_position if pointed_planet == null else pointed_planet.global_position - trail.start_position = selected_planet.global_position - trail.end_position = target_position if snap_position else Util.damp(trail.end_position, target_position, 1e-20, delta) - -#endregion