1
0
Fork 0

Compare commits

...

2 commits

Author SHA1 Message Date
7b95fc4959
Fleets 2024-08-15 21:45:07 +02:00
a613e3e735
Godot 4.3 2024-08-15 17:07:26 +02:00
13 changed files with 208 additions and 73 deletions

View file

@ -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")

View file

@ -12,10 +12,11 @@ config_version=5
config/name="Space Capture"
run/main_scene="res://main.tscn"
config/features=PackedStringArray("4.2", "GL Compatibility")
config/features=PackedStringArray("4.3", "GL Compatibility")
config/icon="res://icon.svg"
[rendering]
renderer/rendering_method="mobile"
renderer/rendering_method="gl_compatibility"
renderer/rendering_method.mobile="gl_compatibility"
environment/defaults/default_clear_color=Color(0, 0, 0, 1)

View file

@ -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

View file

@ -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

View 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

View 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")

View file

@ -1,4 +0,0 @@
class_name TemplateScenes
extends Resource
@export var control_planet: PackedScene

View file

@ -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")

View file

@ -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)

View file

@ -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)

View file

@ -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

View file

@ -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)

View file

@ -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