Fleets
This commit is contained in:
parent
a613e3e735
commit
7b95fc4959
12 changed files with 205 additions and 71 deletions
23
main.tscn
23
main.tscn
|
@ -1,7 +1,6 @@
|
|||
[gd_scene load_steps=21 format=3 uid="uid://cdaf4bh0jaa45"]
|
||||
[gd_scene load_steps=18 format=3 uid="uid://cdaf4bh0jaa45"]
|
||||
|
||||
[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"]
|
||||
|
@ -11,8 +10,6 @@
|
|||
[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"]
|
||||
|
||||
[sub_resource type="Resource" id="Resource_mxp7y"]
|
||||
script = ExtResource("2_plgh6")
|
||||
|
@ -51,10 +48,11 @@ type = 0
|
|||
|
||||
[node name="Main" type="Node"]
|
||||
|
||||
[node name="GameLogic" type="Node" parent="." node_paths=PackedStringArray("planets_container", "planets_ui")]
|
||||
[node name="GameLogic" type="Node" parent="." node_paths=PackedStringArray("planets_container", "trails_container", "fleets_container", "planets_ui")]
|
||||
script = ExtResource("1_uj8ti")
|
||||
templates = ExtResource("2_1lypt")
|
||||
planets_container = NodePath("../Planets")
|
||||
trails_container = NodePath("../Trails")
|
||||
fleets_container = NodePath("../Fleets")
|
||||
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")])
|
||||
|
@ -63,11 +61,11 @@ planets = Array[ExtResource("8_ve3b1")]([SubResource("Resource_50eg2"), SubResou
|
|||
|
||||
[node name="Planets" type="Node2D" parent="."]
|
||||
|
||||
[node name="ShipsFleet" parent="." instance=ExtResource("9_be18b")]
|
||||
position = Vector2(246, 394)
|
||||
count = 29
|
||||
[node name="Trails" type="Node2D" parent="."]
|
||||
|
||||
[node name="PlanetsUI" type="Control" parent="." node_paths=PackedStringArray("trail")]
|
||||
[node name="Fleets" type="Node2D" parent="."]
|
||||
|
||||
[node name="PlanetsUI" type="Control" parent="." node_paths=PackedStringArray("trails_container")]
|
||||
layout_mode = 3
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
|
@ -76,7 +74,4 @@ grow_horizontal = 2
|
|||
grow_vertical = 2
|
||||
mouse_filter = 2
|
||||
script = ExtResource("7_khbdl")
|
||||
trail = NodePath("Trail")
|
||||
|
||||
[node name="Trail" parent="PlanetsUI" instance=ExtResource("10_b5ql7")]
|
||||
visible = false
|
||||
trails_container = NodePath("../Trails")
|
||||
|
|
|
@ -15,6 +15,7 @@ seamless = true
|
|||
noise = SubResource("FastNoiseLite_xihql")
|
||||
|
||||
[sub_resource type="ShaderMaterial" id="ShaderMaterial_m4mhh"]
|
||||
resource_local_to_scene = true
|
||||
shader = ExtResource("1_tl7a6")
|
||||
shader_parameter/size = 100.0
|
||||
shader_parameter/rotationSpeed = 0.05
|
||||
|
|
|
@ -1,37 +1,70 @@
|
|||
extends Node2D
|
||||
class_name ShipFleet
|
||||
class_name ShipsFleet
|
||||
|
||||
@export var departed_at: int
|
||||
@export var departed_at: float # Time.get_ticks_msec()
|
||||
|
||||
@export var arrives_at: int
|
||||
@export var arrives_at: float # Time.get_ticks_msec()
|
||||
|
||||
@export var from: Vector2
|
||||
|
||||
@export var to: Vector2
|
||||
|
||||
@export var player: Player
|
||||
|
||||
@export var count: int :
|
||||
set(value):
|
||||
count = value
|
||||
_update_instances_count()
|
||||
_update__instances_count()
|
||||
|
||||
@export var trail: Trail
|
||||
|
||||
var _game: GameState
|
||||
|
||||
func register_game(game: GameState) -> void:
|
||||
_game = game
|
||||
_game.game_ticked.connect(_update_position)
|
||||
_update_position(game.current_tick)
|
||||
|
||||
func _exit_tree() -> void:
|
||||
if _game != null:
|
||||
_game.game_ticked.disconnect(_update_position)
|
||||
_game = null
|
||||
|
||||
#region Graphics
|
||||
|
||||
var instances: Array[Node2D] = []
|
||||
var _instances: Array[Node2D] = []
|
||||
|
||||
@export var ship_template: PackedScene
|
||||
|
||||
func _update_instances_count() -> void :
|
||||
var diff = count - instances.size()
|
||||
func _update__instances_count() -> void:
|
||||
var diff = count - _instances.size()
|
||||
|
||||
for i in range(diff):
|
||||
var j = float(1 + instances.size())
|
||||
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)
|
||||
_instances.push_back(ship)
|
||||
|
||||
for i in range(-diff):
|
||||
var ship: Node2D = instances.pop_back()
|
||||
var ship: Node2D = _instances.pop_back()
|
||||
remove_child(ship)
|
||||
|
||||
var _arrived := false
|
||||
|
||||
func _update_position(tick: int) -> void:
|
||||
if not _arrived:
|
||||
var clamped_tick := clampi(tick, departed_at, arrives_at)
|
||||
var progress := float(clamped_tick - departed_at) / float(arrives_at - departed_at)
|
||||
position = lerp(from, to, smoothstep(0., 1., progress))
|
||||
if tick >= arrives_at:
|
||||
_arrived = true
|
||||
trail.show = false
|
||||
|
||||
for ship in _instances:
|
||||
ship.emitting = false
|
||||
|
||||
await get_tree().create_timer(5.).timeout
|
||||
queue_free()
|
||||
|
||||
#endregion
|
||||
|
|
10
scenes/templates/scene_templates.gd
Normal file
10
scenes/templates/scene_templates.gd
Normal file
|
@ -0,0 +1,10 @@
|
|||
class_name SceneTemplates
|
||||
extends Resource
|
||||
|
||||
static var scenes = preload("res://scenes/templates/scene_templates.tres")
|
||||
|
||||
@export var control_planet: PackedScene
|
||||
|
||||
@export var trail: PackedScene
|
||||
|
||||
@export var ships_fleet: PackedScene
|
12
scenes/templates/scene_templates.tres
Normal file
12
scenes/templates/scene_templates.tres
Normal file
|
@ -0,0 +1,12 @@
|
|||
[gd_resource type="Resource" script_class="TemplateScenes" load_steps=5 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/scene_templates.gd" id="1_yvn3m"]
|
||||
[ext_resource type="PackedScene" uid="uid://cpffyaoh8x5bp" path="res://scenes/ships_fleet/ships_fleet.tscn" id="3_x17ul"]
|
||||
[ext_resource type="PackedScene" uid="uid://ckfk1xgxfk1c3" path="res://scenes/trail/trail.tscn" id="4_hiuw1"]
|
||||
|
||||
[resource]
|
||||
script = ExtResource("1_yvn3m")
|
||||
control_planet = ExtResource("1_3rbtf")
|
||||
trail = ExtResource("4_hiuw1")
|
||||
ships_fleet = ExtResource("3_x17ul")
|
|
@ -1,4 +0,0 @@
|
|||
class_name TemplateScenes
|
||||
extends Resource
|
||||
|
||||
@export var control_planet: PackedScene
|
|
@ -1,8 +0,0 @@
|
|||
[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")
|
|
@ -1,11 +1,19 @@
|
|||
extends Sprite2D
|
||||
class_name Trail
|
||||
|
||||
@onready var inv_texture_width = 1. / texture.get_width()
|
||||
static var _inv_texture_width := NAN
|
||||
|
||||
@export var color: Color :
|
||||
set(value):
|
||||
material.set_shader_parameter('color', value)
|
||||
color = value
|
||||
_update_color(color)
|
||||
|
||||
@export var show: bool = true :
|
||||
set(value):
|
||||
show = value
|
||||
visible = true
|
||||
|
||||
@export var auto_free: bool
|
||||
|
||||
var start_position: Vector2 :
|
||||
set(value):
|
||||
|
@ -17,7 +25,31 @@ var end_position: Vector2 :
|
|||
end_position = value
|
||||
_update_transform(start_position, value)
|
||||
|
||||
var _opacity := 0.
|
||||
|
||||
func _update_transform(start: Vector2, end: Vector2) -> void:
|
||||
global_position = (start + end) * .5
|
||||
look_at(end)
|
||||
scale = Vector2((end - start).length() * inv_texture_width, 1.)
|
||||
look_at(end)
|
||||
|
||||
if is_nan(_inv_texture_width):
|
||||
_inv_texture_width = 1. / texture.get_width()
|
||||
|
||||
scale = Vector2((end - start).length() * _inv_texture_width, 1.)
|
||||
|
||||
func _update_color(color: Color) -> void:
|
||||
var c := Color(color.r, color.g, color.b, color.a * _opacity)
|
||||
material.set_shader_parameter('color', c)
|
||||
|
||||
func _process(delta: float) -> void:
|
||||
var prev_opacity := _opacity
|
||||
_opacity = Utils.damp(_opacity, 1. if show else 0., 1e-4, delta)
|
||||
if _opacity != prev_opacity:
|
||||
if _opacity < .01:
|
||||
_opacity = 0.
|
||||
visible = false
|
||||
if auto_free:
|
||||
queue_free()
|
||||
elif _opacity > .99:
|
||||
_opacity = 1.
|
||||
|
||||
_update_color(color)
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
[ext_resource type="Script" path="res://scenes/trail/trail.gd" id="3_cnvkj"]
|
||||
|
||||
[sub_resource type="ShaderMaterial" id="ShaderMaterial_f7lnm"]
|
||||
resource_local_to_scene = true
|
||||
shader = ExtResource("1_fjdrv")
|
||||
shader_parameter/color = Color(1, 0, 1, 1)
|
||||
|
||||
|
|
|
@ -4,13 +4,14 @@ extends Node
|
|||
const LOGIC_TICKS_PER_SECOND := 20.
|
||||
const LOGIC_SECONDS_PER_TICK := 1. / LOGIC_TICKS_PER_SECOND
|
||||
|
||||
## Templates for spawnable stuff.
|
||||
@export var templates: TemplateScenes
|
||||
|
||||
## Container for planets.
|
||||
@export var planets_container: Node2D
|
||||
## Container for trails.
|
||||
@export var trails_container: Node2D
|
||||
## Container for fleets.
|
||||
@export var fleets_container: Node2D
|
||||
|
||||
## Interface to interact with planets.
|
||||
## UI to interact with planets.
|
||||
@export var planets_ui: PlanetsUI
|
||||
|
||||
## Game players.
|
||||
|
@ -43,7 +44,7 @@ func _ready() -> void:
|
|||
_game.add_planet(data)
|
||||
|
||||
# UI control.
|
||||
var control: ControlPlanet = templates.control_planet.instantiate()
|
||||
var control: ControlPlanet = SceneTemplates.scenes.control_planet.instantiate()
|
||||
control.position = planets[i].location
|
||||
control.player = players[data.player_id]
|
||||
control.population = data.population
|
||||
|
@ -54,6 +55,7 @@ func _ready() -> void:
|
|||
# Register UI signals.
|
||||
_game.planet_player_changed.connect(_set_planet_player)
|
||||
_game.planet_population_changed.connect(_set_planet_population)
|
||||
_game.fleet_dispatched.connect(_show_dispatched_fleet)
|
||||
planets_ui.fleet_dispatched.connect(_dispatch_fleet)
|
||||
|
||||
func _process(delta: float) -> void:
|
||||
|
@ -63,15 +65,43 @@ func _process(delta: float) -> void:
|
|||
_extra_time -= LOGIC_SECONDS_PER_TICK
|
||||
_game.tick()
|
||||
|
||||
#region Graphics
|
||||
|
||||
func _set_planet_player(planet_id: int, player_id: int) -> void:
|
||||
_planet_controls[planet_id].player = players[player_id]
|
||||
|
||||
func _set_planet_population(planet_id: int, population: int) -> void:
|
||||
_planet_controls[planet_id].population = population
|
||||
|
||||
func _show_dispatched_fleet(from_planet_id: int, to_planet_id: int, count: int, player_id: int, departed_at_tick: int, arrives_at_tick: int) -> void:
|
||||
var trail: Trail = SceneTemplates.scenes.trail.instantiate()
|
||||
trail.start_position = planets[from_planet_id].location
|
||||
trail.end_position = planets[to_planet_id].location
|
||||
trail.color = players[player_id].color
|
||||
trail.auto_free = true
|
||||
trails_container.add_child(trail)
|
||||
|
||||
var fleet: ShipsFleet = SceneTemplates.scenes.ships_fleet.instantiate()
|
||||
fleet.departed_at = departed_at_tick
|
||||
fleet.arrives_at = arrives_at_tick
|
||||
fleet.from = planets[from_planet_id].location
|
||||
fleet.to = planets[to_planet_id].location
|
||||
fleet.player = players[player_id]
|
||||
fleet.count = count
|
||||
fleet.trail = trail
|
||||
fleets_container.add_child(fleet)
|
||||
|
||||
fleet.register_game(_game)
|
||||
|
||||
#endregion
|
||||
|
||||
#region Commands
|
||||
|
||||
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)
|
||||
|
||||
#endregion
|
||||
|
|
|
@ -7,11 +7,14 @@ class PlayerData:
|
|||
class PlanetData:
|
||||
var position: Vector2i
|
||||
var grow_every_ticks: int
|
||||
var player_id: int ## 0 = none
|
||||
var player_id: int
|
||||
var population: int
|
||||
|
||||
class FleetData:
|
||||
var count: int
|
||||
var player_id: int
|
||||
var to_planet_id: int
|
||||
var arrives_at_tick: int
|
||||
|
||||
enum CommandType {
|
||||
DISPATCH_FLEET,
|
||||
|
@ -28,9 +31,14 @@ class DispatchFleedCommand extends Command:
|
|||
func _init():
|
||||
type = CommandType.DISPATCH_FLEET
|
||||
|
||||
const NEUTRAL_PLAYER_ID := 0
|
||||
const FLEET_TAKEOFF_PLUS_LANDING_TIME := 20 # ticks
|
||||
const FLEET_SPEED := 2 # pixels/tick
|
||||
|
||||
signal game_ticked(tick: int)
|
||||
signal planet_population_changed(planet_id: int, population: int)
|
||||
signal planet_player_changed(planet_id: int, player_id: int)
|
||||
signal fleet_dispatched(from_planet_id: int, to_planet_id: int, count: int, player_id: int, departed_at_tick: int, arrives_at_tick: int)
|
||||
|
||||
var _players: Array[PlayerData] = []
|
||||
var _planets: Array[PlanetData] = []
|
||||
|
@ -54,12 +62,14 @@ func add_planet(data := PlanetData.new()) -> int:
|
|||
func tick() -> void:
|
||||
current_tick += 1
|
||||
|
||||
# Handle planets growth.
|
||||
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:
|
||||
if planet.player_id != NEUTRAL_PLAYER_ID and current_tick % planet.grow_every_ticks == 0:
|
||||
planet.population += 1
|
||||
planet_population_changed.emit(planet_id, planet.population)
|
||||
|
||||
# Handle player commands.
|
||||
for player_id in range(_players.size()):
|
||||
var player := _players[player_id]
|
||||
if player.commands.size() > 0 && current_tick >= player.commands[0].wait_tick:
|
||||
|
@ -70,6 +80,11 @@ func tick() -> void:
|
|||
_:
|
||||
assert(false, "Unknown command: %s" % [command])
|
||||
|
||||
# Handle fleets arrival.
|
||||
while _fleets.size() > 0 && current_tick >= _fleets[0].arrives_at_tick:
|
||||
var fleet: FleetData = _fleets.pop_back()
|
||||
_handle_fleet_arrival(fleet)
|
||||
|
||||
game_ticked.emit(current_tick)
|
||||
|
||||
## Dispatch a fleet.
|
||||
|
@ -87,16 +102,31 @@ func _issue_command(player_id: int, command: Command) -> void:
|
|||
|
||||
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
|
||||
if from.player_id == player_id:
|
||||
var to = _planets[dispatch.to_planet_id]
|
||||
var count = min(dispatch.max_count, from.population)
|
||||
from.population -= count
|
||||
planet_population_changed.emit(dispatch.from_planet_id, from.population)
|
||||
|
||||
var fleet := FleetData.new()
|
||||
fleet.count = count
|
||||
fleet.player_id = player_id
|
||||
fleet.to_planet_id = dispatch.to_planet_id
|
||||
fleet.arrives_at_tick = current_tick + FLEET_TAKEOFF_PLUS_LANDING_TIME + ceili(from.position.distance_to(to.position) / FLEET_SPEED)
|
||||
|
||||
var index := _fleets.map(func (x): return x.arrives_at_tick).bsearch(fleet.arrives_at_tick, false)
|
||||
_fleets.insert(index, fleet)
|
||||
|
||||
fleet_dispatched.emit(dispatch.from_planet_id, fleet.to_planet_id, fleet.count, fleet.player_id, current_tick, fleet.arrives_at_tick)
|
||||
|
||||
func _handle_fleet_arrival(fleet: FleetData) -> void:
|
||||
var to = _planets[fleet.to_planet_id]
|
||||
if fleet.player_id == to.player_id:
|
||||
to.population += fleet.count
|
||||
else:
|
||||
to.population -= count
|
||||
to.population -= fleet.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)
|
||||
to.player_id = fleet.player_id
|
||||
to.population = abs(to.population)
|
||||
planet_player_changed.emit(fleet.to_planet_id, to.player_id)
|
||||
planet_population_changed.emit(fleet.to_planet_id, to.population)
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
class_name PlanetsUI
|
||||
extends Control
|
||||
|
||||
@export var trail: Trail
|
||||
## Container for trails.
|
||||
@export var trails_container: Node2D
|
||||
|
||||
var _trail: Trail
|
||||
|
||||
signal fleet_dispatched(from: ControlPlanet, to: ControlPlanet)
|
||||
|
||||
|
@ -10,6 +13,11 @@ func register_planet(control: ControlPlanet) -> void:
|
|||
control.pointer_entered.connect(_on_planet_pointer_entered)
|
||||
control.pointer_exited.connect(_on_planet_pointer_exited)
|
||||
|
||||
func _ready() -> void:
|
||||
_trail = SceneTemplates.scenes.trail.instantiate()
|
||||
_trail.visible = false
|
||||
trails_container.add_child(_trail)
|
||||
|
||||
func _process(delta: float) -> void:
|
||||
_update_trail(delta, false)
|
||||
|
||||
|
@ -63,18 +71,12 @@ func _on_planet_pointer_exited(planet: ControlPlanet) -> void:
|
|||
|
||||
#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)
|
||||
_trail.show = _dragging_from_planet and _selected_planet != null and _selected_planet.player is LocalPlayer
|
||||
if _trail.show:
|
||||
_trail.color = _selected_planet.player.color
|
||||
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
|
||||
|
|
Loading…
Reference in a new issue