feat: Add Global Game instance + refacto

This commit is contained in:
Varylios 2025-09-04 17:59:23 +02:00
parent a2698da4a6
commit c6cdc15687
32 changed files with 340 additions and 325 deletions

View file

@ -56,7 +56,7 @@ func attack():
func death() -> void:
is_alive = false
died.emit()
TheCube.money += money
Game.money += money
$Sprite3D.visible = false
var death_vfx : CPUParticles3D = death_vfx_packed.instantiate()
get_tree().current_scene.add_child(death_vfx)

View file

@ -7,9 +7,9 @@ extends Node
signal tower_selected(towerType : Tower.TYPE)
## [b]Emitter[/b] : [TowerManager][br]
## [b]Subscriber[/b] hero_icon.gd:
signal tower_builded(tower : Tower)
## [b]Emitter[/b] : [Tower][br]
## [b]Subscriber[/b] [GuiButton], [gui.gd]:
signal tower_changed(tower : Tower)
## [b]Emitter[/b] : [UpgradeButton][br]
@ -17,21 +17,6 @@ signal tower_builded(tower : Tower)
signal tower_upgraded(towerType : Tower.TYPE, upgrade : TowerUpgrade)
## [b]Emitter[/b] : [TheCube][br]
## [b]Subscriber[/b] : gui.gd
signal cube_integrity_changed(newHealth : int)
## [b]Emitter[/b] : [TheCube][br]
## [b]Subscriber[/b] : gui.gd
signal money_changed(newAmount : int)
## [b]Emitter[/b] : [TheCube][br]
## [b]Subscriber[/b] : [WorldManager]
signal cube_ready(theCube : TheCube)
## [b]Emitter[/b] : [TowerManager][br]
## [b]Subscriber[/b] : gui.gd
signal tower_count_changed(count : int)
@ -53,25 +38,10 @@ signal projectile_shooted(projectile: Projectile, startPosition: Vector3)
## [b]Emitter[/b] : [WorldManager][br]
## [b]Subscriber[/b] : [TheCube]
## [b]Subscriber[/b] : [Game]
signal player_has_won()
## [b]Emitter[/b] : [TheCube][br]
## [b]Subscriber[/b] : [WorldManager]
signal player_defeated()
## [b]Emitter[/b] : [Tower][br]
## [b]Subscriber[/b] : [GuiButton]
signal energy_has_changed(tower : Tower)
## [b]Emitter[/b] : [WorldManager], [Level][br]
## [b]Subscriber[/b] : gui.gd
signal allowedTowerHasChange(allowedTowers : Array[Tower.TYPE])
## [b]Emitter[/b] : [WorldManager][br]
## [b]Subscriber[/b] : [code]null[/code]
signal waveHasChange(waveNumber : int)

View file

@ -1,97 +1,75 @@
@tool
class_name Game
extends Node
## Game
## COLORS ##
signal cube_integrity_changed
signal money_changed
signal loose
signal allowed_tower_has_change
enum COLOR { HEALTH, ENERGY, SELECTED, SECONDARY, BACKGROUND_PANEL }
var towerPackedScenes : Dictionary
var enmies : Dictionary
var towers : Dictionary
var allowedTowers : Array[Tower.TYPE] :
set(value):
allowedTowers = value
allowed_tower_has_change.emit()
const COLOR_HEALTH : Color = Color(0.921569, 0.419608, 0.415686, 1)
const COLOR_ENERGY : Color = Color(0.921569, 0.890196, 0.415686, 1)
const COLOR_SELECTED : Color = Color(0.721569, 0.600196, 0.355686, 1)
const COLOR_SECONDARY : Color = Color(0.341, 0.082, 0.094, 0.0)
const COLOR_BACKGROUND_PANEL : Color = Color(0.933, 0.933, 0.933, 1)
const COLOR_FALLBACK : Color = Color(0.341176, 0.0823529, 0.0941176, 0)
var max_health : int = 50
var health : int = max_health :
set(value):
health = value
cube_integrity_changed.emit()
if health <= 0:
death()
var healthPercentage : int :
get():
return float(health) / float(max_health) * 100.0
static func getColor(color : COLOR) -> Color :
match color:
COLOR.HEALTH : return COLOR_HEALTH
COLOR.ENERGY : return COLOR_ENERGY
COLOR.SELECTED : return COLOR_SELECTED
COLOR.SECONDARY : return COLOR_SECONDARY
COLOR.BACKGROUND_PANEL : return COLOR_BACKGROUND_PANEL
_: return COLOR_FALLBACK
var money : int = 0:
set(value):
money = value
money_changed.emit()
## END COLORS ##
const SCENE_DIR_PATTERN : String = "res://\\w+/(Scenes|Map \\d+)/$"
const SCENE_FILE_PATTERN : String = "([^/]*)\\.tscn$"
const RESOURCE_FILE_PATTERN : String = "([^/]*)\\.tres$"
const TOWER_DIR : String = "res://Towers/Scenes/"
const ENEMY_DIR : String = "res://Enemies/Scenes/"
const LEVEL_DIR : String = "res://Levels/"
static var towers : Dictionary
static var enmies : Dictionary
enum RESOURCE_TYPE { TOWER, ENEMY, LEVEL }
static func _static_init() -> void:
preloadSceneInGlobal(towers, RESOURCE_TYPE.TOWER)
#preloadSceneInGlobal(enemies, ENEMY_DIR)
## [color=crimson][b]WARNING :[/b] Work only with the [enum RESOURCE_TYPE] [param TOWER][/color]
static func preloadSceneInGlobal(property: Dictionary, type: RESOURCE_TYPE) -> void:
if type != RESOURCE_TYPE.TOWER:
return
var files : Array[String] = getPackedScenesPaths(type)
for file in files:
var scene = load(file)
if scene:
property.set(EnhancedResource.getPackedSceneProperty(scene, "tower_type"), scene)
property.sort()
func _ready() -> void:
EventBus.player_has_won.connect(win)
Helper.preloadSceneInGlobal(towerPackedScenes, Helper.RESOURCE_TYPE.TOWER)
#Helper.preloadSceneInGlobal(towerPackedScenes, Helper.RESOURCE_TYPE.ENEMY)
static func getPackedScenesPaths(type: RESOURCE_TYPE) -> Array[String]:
return getFileFromDir(getDirFromType(type), SCENE_FILE_PATTERN, SCENE_DIR_PATTERN)
func initTower(towerType: Tower.TYPE) -> Tower:
var tower : Tower = towerPackedScenes.get(towerType).instantiate()
towers.set(towerType, tower)
return tower
static func getResourcesPaths(type: RESOURCE_TYPE) -> Array[String]:
if type == RESOURCE_TYPE.LEVEL:
return getFileFromDir(getDirFromType(type), RESOURCE_FILE_PATTERN, LEVEL_DIR)
return []
func resetGame() -> void:
towers.values().map(queue_free)
towers.clear()
# DANGER Don't use [method clear] or you will clear the level datas
allowedTowers = []
money = 0
health = max_health
static func getDirFromType(type: RESOURCE_TYPE) -> String:
match type:
RESOURCE_TYPE.TOWER: return TOWER_DIR
RESOURCE_TYPE.ENEMY: return ENEMY_DIR
RESOURCE_TYPE.LEVEL: return LEVEL_DIR
_: return ""
func win():
Transition.goto("res://UI/win_screen.tscn")
resetGame()
static func getFileFromDir(path : String, regexPattern : String, pathRegexPattern : String = "") -> Array[String]:
var files : Array[String]
var regex : RegEx = RegEx.create_from_string(regexPattern)
var pathRegex : RegEx = RegEx.create_from_string(pathRegexPattern)
var dir : DirAccess = DirAccess.open(path)
func spendMoney(amount : int) -> bool:
if money > amount:
money -= amount
return true
return false
if pathRegexPattern:
for subDir in dir.get_directories():
subDir = path + subDir + "/"
if pathRegex.search(subDir):
files.append_array(getFileFromDir(subDir, regexPattern, pathRegexPattern))
for file in dir.get_files():
if regex.search(file) && pathRegex.search(path):
files.append(path + file)
return files
func death():
loose.emit()
Transition.goto("res://UI/defeat_screen.tscn")
resetGame()

22
Globals/GameColor.gd Normal file
View file

@ -0,0 +1,22 @@
@tool
class_name GameColor
enum COLOR { HEALTH, ENERGY, SELECTED, SECONDARY, BACKGROUND_PANEL }
const COLOR_HEALTH : Color = Color(0.921569, 0.419608, 0.415686, 1)
const COLOR_ENERGY : Color = Color(0.921569, 0.890196, 0.415686, 1)
const COLOR_SELECTED : Color = Color(0.721569, 0.600196, 0.355686, 1)
const COLOR_SECONDARY : Color = Color(0.341, 0.082, 0.094, 0.0)
const COLOR_BACKGROUND_PANEL : Color = Color(0.933, 0.933, 0.933, 1)
const COLOR_FALLBACK : Color = Color(0.341176, 0.0823529, 0.0941176, 0)
static func getColor(color : COLOR) -> Color :
match color:
COLOR.HEALTH : return COLOR_HEALTH
COLOR.ENERGY : return COLOR_ENERGY
COLOR.SELECTED : return COLOR_SELECTED
COLOR.SECONDARY : return COLOR_SECONDARY
COLOR.BACKGROUND_PANEL : return COLOR_BACKGROUND_PANEL
_: return COLOR_FALLBACK

1
Globals/GameColor.gd.uid Normal file
View file

@ -0,0 +1 @@
uid://dk2bu20d1fv6a

65
Globals/Helper.gd Normal file
View file

@ -0,0 +1,65 @@
@tool
class_name Helper
const SCENE_DIR_PATTERN : String = "res://\\w+/(Scenes|Map \\d+)/$"
const SCENE_FILE_PATTERN : String = "([^/]*)\\.tscn$"
const RESOURCE_FILE_PATTERN : String = "([^/]*)\\.tres$"
const TOWER_DIR : String = "res://Towers/Scenes/"
const ENEMY_DIR : String = "res://Enemies/Scenes/"
const LEVEL_DIR : String = "res://Levels/"
static var towers : Dictionary
static var enmies : Dictionary
enum RESOURCE_TYPE { TOWER, ENEMY, LEVEL }
## [color=crimson][b]WARNING :[/b] Work only with the [enum RESOURCE_TYPE] [param TOWER][/color]
static func preloadSceneInGlobal(property: Dictionary, type: RESOURCE_TYPE) -> void:
assert(type == RESOURCE_TYPE.TOWER)
var files : Array[String] = getPackedScenesPaths(type)
for file in files:
var scene = load(file)
if scene:
property.set(EnhancedResource.getPackedSceneProperty(scene, "type"), scene)
property.sort()
static func getPackedScenesPaths(type: RESOURCE_TYPE) -> Array[String]:
return getFileFromDir(getDirFromType(type), SCENE_FILE_PATTERN, SCENE_DIR_PATTERN)
static func getResourcesPaths(type: RESOURCE_TYPE) -> Array[String]:
if type == RESOURCE_TYPE.LEVEL:
return getFileFromDir(getDirFromType(type), RESOURCE_FILE_PATTERN, LEVEL_DIR)
return []
static func getDirFromType(type: RESOURCE_TYPE) -> String:
match type:
RESOURCE_TYPE.TOWER: return TOWER_DIR
RESOURCE_TYPE.ENEMY: return ENEMY_DIR
RESOURCE_TYPE.LEVEL: return LEVEL_DIR
_: return ""
static func getFileFromDir(path : String, regexPattern : String, pathRegexPattern : String = "") -> Array[String]:
var files : Array[String]
var regex : RegEx = RegEx.create_from_string(regexPattern)
var pathRegex : RegEx = RegEx.create_from_string(pathRegexPattern)
var dir : DirAccess = DirAccess.open(path)
if pathRegexPattern:
for subDir in dir.get_directories():
subDir = path + subDir + "/"
if pathRegex.search(subDir):
files.append_array(getFileFromDir(subDir, regexPattern, pathRegexPattern))
for file in dir.get_files():
if regex.search(file) && pathRegex.search(path):
files.append(path + file)
return files

1
Globals/Helper.gd.uid Normal file
View file

@ -0,0 +1 @@
uid://c2vef7352y3sp

View file

@ -17,7 +17,7 @@ var enemiesAlive : int = 0
func _ready() -> void:
EventBus.projectile_shooted.connect(onProjectileShooted)
EventBus.player_defeated.connect(queue_free)
Game.loose.connect(queue_free)
func onProjectileShooted(projectile: Projectile, startPosition: Vector3) -> void:
@ -106,6 +106,6 @@ func addMap(mapScene : PackedScene) -> void:
add_child(map)
level = map.level
paths = map.paths.get_children()
TheCube.money = level.startingMoney
EventBus.allowedTowerHasChange.emit(level.allowedTowers)
Game.money = level.startingMoney
Game.allowedTowers = level.allowedTowers
spawnNextWave()

View file

@ -1,42 +1,6 @@
extends StaticBody3D
class_name TheCube
@export var max_health : int = 50
var health : int = max_health :
set(value):
health = value
EventBus.cube_integrity_changed.emit(health)
if health <= 0:
death()
static var money : int :
set(value):
money = value
EventBus.money_changed.emit(money)
func _ready() -> void:
EventBus.player_has_won.connect(win)
EventBus.cube_ready.emit.call_deferred(self)
func take_damage(damage: int) -> void:
health -= damage
func win():
Transition.goto("res://UI/win_screen.tscn")
static func spendMoney(amount : int) -> bool:
if money > amount:
money -= amount
return true
return false
static func death():
EventBus.player_defeated.emit()
Transition.goto("res://UI/defeat_screen.tscn")
Game.health -= damage

View file

@ -2,14 +2,15 @@
[ext_resource type="PackedScene" uid="uid://trg7ag3dqr2l" path="res://Towers/tower.tscn" id="1_lr28p"]
[ext_resource type="Texture2D" uid="uid://c4ir6y45pchpl" path="res://Assets/Icones/seahorse.svg" id="3_4yx0u"]
[ext_resource type="Script" uid="uid://bg0x4egeu17qb" path="res://Upgrades/Tower/TowerUpgrade.gd" id="4_4yx0u"]
[sub_resource type="ViewportTexture" id="ViewportTexture_rcx4a"]
viewport_path = NodePath("EnergyBar3D/SubViewport")
[node name="Alex" instance=ExtResource("1_lr28p")]
tower_name = "Alex"
tower_type = 6
type = 6
icone = ExtResource("3_4yx0u")
bio = ""
tower_shop = Array[ExtResource("4_4yx0u")]([])
[node name="Sprite3D" parent="." index="5"]
frame = 30

View file

@ -26,7 +26,7 @@ radius = 3.0
[node name="Aline" instance=ExtResource("1_gvvig")]
tower_name = "Aline"
tower_type = 2
type = 2
icone = ExtResource("3_6h033")
bio = ""
price = 150

View file

@ -19,7 +19,7 @@ radius = 4.0
[node name="Evan" instance=ExtResource("1_yctfx")]
tower_name = "Evan"
tower_type = 5
type = 5
icone = ExtResource("2_5uh04")
bio = ""
projectileRessource = SubResource("Resource_mf185")

View file

@ -7,7 +7,7 @@
[node name="Geraldine" instance=ExtResource("1_bw8ui")]
tower_name = "Geraldine"
tower_type = 7
type = 7
icone = ExtResource("2_1pop4")
bio = ""
tower_shop = Array[ExtResource("4_nxn76")]([])

View file

@ -23,7 +23,7 @@ radius = 10.0
[node name="Maxence" instance=ExtResource("1_laam8")]
tower_name = "Maxence"
tower_type = 3
type = 3
icone = ExtResource("2_sciv6")
bio = ""
price = 200

View file

@ -23,7 +23,7 @@ viewport_path = NodePath("EnergyBar3D/SubViewport")
[node name="Pierre" instance=ExtResource("1_s6dfo")]
tower_name = "Pierre"
tower_type = 1
type = 1
icone = ExtResource("2_lcjqw")
projectileRessource = SubResource("Resource_r52mr")
towerRange = SubResource("SphereShape3D_c55ds")

View file

@ -24,7 +24,7 @@ radius = 4.0
[node name="Victoria" instance=ExtResource("1_ki73m")]
tower_name = "Victoria"
tower_type = 4
type = 4
icone = ExtResource("2_n34tq")
bio = ""
projectileRessource = SubResource("Resource_c1yif")

View file

@ -9,7 +9,7 @@ enum TYPE { NONE, PIERRE, ALINE, MAXENCE, VICTORIA, EVAN, ALEX, GERALDINE }
var projectileScene : PackedScene = preload("res://Towers/Projectiles/projectile.tscn")
@export var tower_name : String = "None"
@export var tower_type : TYPE
@export var type : TYPE
@export_group("Base data")
@export var icone : Texture2D
@export var bio : String
@ -23,7 +23,10 @@ var projectileScene : PackedScene = preload("res://Towers/Projectiles/projectile
action_cooldown = clamp(value, 0.3, 999)
@export_group("Energy")
@export var max_energy : float = 100.0
@export var max_energy : float = 100.0 :
set(value):
max_energy = value
towerChange.call_deferred()
@export var energy_regen : float = 10.0
@export var energy_cost : float = 50.0
@ -36,12 +39,12 @@ var projectileScene : PackedScene = preload("res://Towers/Projectiles/projectile
@onready var energyRecoveryCooldown : Timer = $EnergyRecoveryCooldown
var energy : float = 0:
var energy : float = max_energy:
set(value):
energyBar.value = value
energy = clampf(value, 0.0, max_energy)
is_exhausted = energy < energy_cost
EventBus.energy_has_changed.emit(self)
EventBus.tower_changed.emit(self)
var availableTargets : Array[Enemy]
var target : Enemy
@ -57,16 +60,13 @@ var builded : bool = false
func _ready() -> void:
EventBus.tower_upgraded.connect(apply_upgrade)
EventBus.energy_has_changed.emit(self)
energyRecoveryCooldown.timeout.connect(func(): energy += energy_regen)
# WARNING : Prevent .tscn file to be modified by the load of the scene in editor
if not Engine.is_editor_hint():
collision_layer = 0
collision_mask = 0
$PriceTag.text = str(price) + ""
energy = max_energy
$Range/Range.shape = towerRange
energyBar.value = energy
energyBar.max_value = max_energy
func _process(_delta: float) -> void:
@ -79,7 +79,7 @@ func get_available_upgrades() -> Array[TowerUpgrade]:
func apply_upgrade(towerType : Tower.TYPE, upgrade : TowerUpgrade):
if towerType == tower_type && upgrade.canUpgrade():
if towerType == type && upgrade.canUpgrade():
upgrade.upgrade(self)
@ -95,14 +95,18 @@ func resting() -> void:
visible = false
collision_layer = 0
collision_mask = 0
energyRecoveryCooldown.start()
if builded:
energyRecoveryCooldown.start()
func in_action() -> void:
visible = true
collision_layer = 0b100
collision_mask = 0b100
energyRecoveryCooldown.stop()
if builded:
collision_layer = 0b100
collision_mask = 0b100
energyRecoveryCooldown.stop()
func choose_target() -> void:
@ -113,16 +117,24 @@ func choose_target() -> void:
func build() -> bool:
if builded || not TheCube.spendMoney(price):
if builded || not Game.spendMoney(price):
return false
sprite.modulate = "ffffffff"
energyBar.value = energy
energyBar.max_value = max_energy
$EnergyBar3D.visible = true
builded = true
$PriceTag.visible = false
EventBus.tower_builded.emit(self)
EventBus.tower_changed.emit(self)
return true
func towerChange() -> void:
energyBar.max_value = max_energy
EventBus.tower_changed.emit(self)
func _on_range_body_entered(body: Node3D) -> void:
if body is Enemy:
availableTargets.append(body)

View file

@ -6,7 +6,6 @@ class_name TowerManager
@onready var selection_icon : Sprite3D = $Sprite3DSelection
var towers : Dictionary
var usedLocations : Dictionary
var selectedTile : Vector3
var selected_tower : Tower
@ -25,13 +24,13 @@ func _process(_delta: float) -> void:
tower = usedLocations.get(collider.global_position.round())
if Input.is_action_just_pressed("build"):
if not collider is GameTile:
if not collider is GameTile || tower == selected_tower:
return
if isTileFree(collider):
placeTower()
elif tower && selected_tower.builded:
EventBus.tower_selected.emit(tower.tower_type)
elif tower && selected_tower && selected_tower.builded:
EventBus.tower_selected.emit(tower.type)
if Input.is_action_just_pressed("rest"):
if tower:
@ -93,7 +92,7 @@ func moveTower(tower: Tower, toPosition: Vector3) -> void:
if toPosition == Vector3.INF:
tower.resting()
else:
usedLocations.set(global_position.round(), tower)
usedLocations.set(toPosition.round(), tower)
tower.global_position = toPosition
tower.in_action()
@ -105,30 +104,27 @@ func selectTower(towerType: Tower.TYPE):
if selected_tower && not selected_tower.builded:
selected_tower.visible = false
if selected_tower && selected_tower.tower_type == towerType || towerType == Tower.TYPE.NONE:
if selected_tower && selected_tower.type == towerType || towerType == Tower.TYPE.NONE:
selected_tower = null
elif towers.has(towerType):
selected_tower = towers.get(towerType)
selected_tower.visible = true
elif Game.towers.has(towerType):
selected_tower = Game.towers.get(towerType)
if not selected_tower.builded:
selected_tower.visible = true
else:
selected_tower = Game.towers.get(towerType).instantiate()
towers.set(towerType, selected_tower)
selected_tower = Game.initTower(towerType)
add_child(selected_tower)
func emitTeamChanges() -> void:
var team_in_action : int = 0
var team_in_rest : int = 0
var tower_count : int = 0
for towerType in towers:
var tower : Tower = towers[towerType]
for towerType in Game.towers:
var tower : Tower = Game.towers[towerType]
if tower.builded:
tower_count += 1
if tower.is_rest:
team_in_rest += 1
else:
team_in_action += 1
EventBus.team_in_action_changed.emit(team_in_action)
EventBus.team_in_action_changed.emit(usedLocations.size())
EventBus.team_in_rest_changed.emit(team_in_rest)
EventBus.tower_count_changed.emit(tower_count)

View file

@ -57,6 +57,7 @@ frame = 75
[node name="EnergyBar3D" type="Sprite3D" parent="."]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0)
visible = false
billboard = 2
texture = SubResource("ViewportTexture_jv31o")
@ -83,7 +84,7 @@ show_percentage = false
metadata/_custom_type_script = "uid://blnmjxmusrsa7"
[node name="PriceTag" type="Label3D" parent="."]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.2, 0)
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0)
billboard = 2
[connection signal="body_entered" from="Range" to="." method="_on_range_body_entered"]

View file

@ -3,14 +3,14 @@ extends StyleBoxFlat
class_name GameStyleBoxFlat
@export var color : Game.COLOR :
@export var color : GameColor.COLOR :
set(value):
color = value
bg_color = Game.getColor(color)
bg_color = GameColor.getColor(color)
static func createWithColor(_color : Game.COLOR) -> GameStyleBoxFlat:
static func createWithColor(_color : GameColor.COLOR) -> GameStyleBoxFlat:
var instance : GameStyleBoxFlat = GameStyleBoxFlat.new()
instance.bg_color = Game.getColor(_color)
instance.bg_color = GameColor.getColor(_color)
return instance

31
UI/TowerPanel.gd Normal file
View file

@ -0,0 +1,31 @@
extends HBoxContainer
var tower : Tower
func _ready() -> void:
EventBus.tower_selected.connect(onTowerSelected)
EventBus.tower_changed.connect(onEnergyChanged)
func onTowerSelected(towerType : Tower.TYPE) -> void:
if towerType == Tower.TYPE.NONE:
visible = false
tower = null
return
return
tower = Game.getTower(towerType)
%TowerIcon.texture = tower.icone
%TowerName.text = tower.tower_name
%TowerDamage.text = str(tower.projectileRessource.damage)
%TowerCooldown.text = str(tower.action_cooldown)
%TowerBio.text = tower.bio
onEnergyChanged(tower)
visible = true
func onEnergyChanged(_tower : Tower) -> void:
if _tower == tower:
%TowerEnergy.text = "%d/%d" % [ str(tower.energy), str(tower.max_energy) ]

1
UI/TowerPanel.gd.uid Normal file
View file

@ -0,0 +1 @@
uid://s4t3oa4v87xe

View file

@ -1,7 +1,7 @@
@tool
extends Control
const BUTTON_QTY = 8
const BUTTON_QTY = 4
const guiButton : PackedScene = preload("res://UI/gui_button.tscn")
@ -11,34 +11,21 @@ const guiButton : PackedScene = preload("res://UI/gui_button.tscn")
@onready var towerOnTerrainLabel = %LabelTowerOnTerrain
@onready var cubeIntegrity = %CubeIntegrity
var theCube : TheCube
var allowedTowers : Array[Tower.TYPE]
func _ready() -> void:
addTowerButtonNodes()
EventBus.cube_ready.connect(cubeReady)
EventBus.allowedTowerHasChange.connect(allowedTowerHasChange)
EventBus.money_changed.connect(func(amount): moneyLabel.text = str(amount) + "")
EventBus.team_in_rest_changed.connect(func(count): towerInCubeLabel.text = str(count) + " x Zzz")
EventBus.team_in_action_changed.connect(func(count): towerOnTerrainLabel.text = str(count) + " in action")
EventBus.cube_integrity_changed.connect(updateCubeLife)
Game.allowed_tower_has_change.connect(addTowerButtonNodes)
Game.cube_integrity_changed.connect(func(): cubeIntegrity.value = Game.healthPercentage)
Game.money_changed.connect(func(): moneyLabel.text = str(Game.money) + "")
cubeIntegrity.max_value = Game.max_health
func _on_button_cube_pressed() -> void:
pass # Replace with function body.
func cubeReady(cube: TheCube) -> void:
theCube = cube
cubeIntegrity.max_value = theCube.max_health
func updateCubeLife(newHealth : int) -> void:
cubeIntegrity.value = float(newHealth) / float(theCube.max_health) * 100.0
func quitLevel() -> void:
Transition.goto("res://UI/start_menu.tscn")
@ -47,36 +34,29 @@ func quitGame() -> void:
get_tree().quit()
func allowedTowerHasChange(_allowedTowers : Array[Tower.TYPE]) -> void:
allowedTowers = _allowedTowers
if is_node_ready():
addTowerButtonNodes()
func addTowerButtonNodes() -> void:
for node in buttonContainer.get_children():
if node.has_meta("dynamicButton"):
node.queue_free()
var additionalPlaceholder : int = 0
for towerType in Game.towers:
if not Engine.is_editor_hint() && not allowedTowers.has(towerType):
additionalPlaceholder += 1
else:
for towerType : int in Tower.TYPE.values() :
if towerType && (Engine.is_editor_hint() || Game.allowedTowers.has(towerType)):
createTowerButton(towerType)
for i in BUTTON_QTY - Game.towers.size() + additionalPlaceholder:
var placeholderBtn : Button = Button.new()
placeholderBtn.set_meta("dynamicButton", true)
placeholderBtn.custom_minimum_size = Vector2(80, 80)
buttonContainer.add_child(placeholderBtn)
for i in BUTTON_QTY - (buttonContainer.get_children().size() % BUTTON_QTY):
createTowerButton(Tower.TYPE.NONE)
func createTowerButton(towerType : Tower.TYPE) -> void:
var towerBtn : GuiButton = guiButton.instantiate()
var tower : PackedScene = Game.towers.get(towerType)
towerBtn.towerType = towerType
towerBtn.tooltip_text = str(EnhancedResource.getPackedSceneProperty(tower, "name"))
towerBtn.texture = EnhancedResource.getPackedSceneProperty(tower, "icone")
towerBtn.set_meta("dynamicButton", true)
buttonContainer.add_child(towerBtn)
var btn : GuiButton = guiButton.instantiate()
btn.set_meta("dynamicButton", true)
if towerType:
var tower : PackedScene = Game.towerPackedScenes.get(towerType)
btn.towerType = towerType
btn.tooltip_text = str(EnhancedResource.getPackedSceneProperty(tower, "name"))
btn.texture = EnhancedResource.getPackedSceneProperty(tower, "icone")
else:
btn.disabled = true
buttonContainer.add_child(btn)

View file

@ -1,4 +1,4 @@
[gd_scene load_steps=14 format=3 uid="uid://p6a6rb7sgeqd"]
[gd_scene load_steps=16 format=3 uid="uid://p6a6rb7sgeqd"]
[ext_resource type="Script" uid="uid://bhylcok1l6eke" path="res://UI/gui.gd" id="2_sac4j"]
[ext_resource type="Script" uid="uid://blnmjxmusrsa7" path="res://UI/GameStyleBoxFlat.gd" id="4_h4fn5"]
@ -7,8 +7,10 @@
[ext_resource type="PackedScene" uid="uid://dqb5o8w7u50hc" path="res://UI/gui_button.tscn" id="7_parkk"]
[ext_resource type="Texture2D" uid="uid://dfnf26suc8yb6" path="res://Assets/Icones/sideswipe.svg" id="8_ay13l"]
[ext_resource type="Texture2D" uid="uid://dootdihg7gkoj" path="res://Assets/Icones/exit-door.svg" id="8_decjp"]
[ext_resource type="Script" uid="uid://s4t3oa4v87xe" path="res://UI/TowerPanel.gd" id="9_3lugd"]
[ext_resource type="Script" uid="uid://dyhtr6g7kd1g2" path="res://UI/gui_button.gd" id="9_h4fn5"]
[ext_resource type="Texture2D" uid="uid://b4m5ejfdrm8s0" path="res://Assets/Icones/power-button.svg" id="9_reygo"]
[ext_resource type="Texture2D" uid="uid://uptdcefxlv4c" path="res://Assets/Icones/ppdf_bio_image_placeholder_2.png" id="10_parkk"]
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_h4fn5"]
bg_color = Color(0.933333, 0.933333, 0.933333, 1)
@ -102,6 +104,7 @@ size_flags_vertical = 1
tooltip_text = "Les points d'intégrités du Cube. S'ils arrivent à 0, fin de la partie."
theme_override_styles/background = SubResource("StyleBoxFlat_nxmp4")
theme_override_styles/fill = SubResource("StyleBoxFlat_epgl5")
max_value = 50.0
value = 50.0
fill_mode = 3
show_percentage = false
@ -148,10 +151,11 @@ layout_mode = 1
anchors_preset = 2
anchor_top = 1.0
anchor_bottom = 1.0
offset_top = -268.0
offset_right = 552.0
offset_top = -246.0
offset_right = 353.0
grow_vertical = 0
theme_override_constants/separation = 0
script = ExtResource("9_3lugd")
[node name="InfoPanel" type="PanelContainer" parent="TowerInfoPanel"]
custom_minimum_size = Vector2(200, 0)
@ -168,17 +172,41 @@ theme_override_constants/margin_bottom = 10
[node name="VBoxContainer" type="VBoxContainer" parent="TowerInfoPanel/InfoPanel/MarginContainer"]
layout_mode = 2
[node name="LabelMoney" type="Label" parent="TowerInfoPanel/InfoPanel/MarginContainer/VBoxContainer"]
[node name="HBoxContainer" type="HBoxContainer" parent="TowerInfoPanel/InfoPanel/MarginContainer/VBoxContainer"]
layout_mode = 2
theme_override_constants/separation = 20
[node name="VBoxContainer" type="VBoxContainer" parent="TowerInfoPanel/InfoPanel/MarginContainer/VBoxContainer/HBoxContainer"]
layout_mode = 2
[node name="TowerName" type="Label" parent="TowerInfoPanel/InfoPanel/MarginContainer/VBoxContainer/HBoxContainer/VBoxContainer"]
unique_name_in_owner = true
layout_mode = 2
size_flags_vertical = 1
tooltip_text = "La thune."
mouse_filter = 1
theme_override_colors/font_color = Color(0.2, 0.2, 0.2, 1)
text = "1'000'000 €"
text = "Name"
horizontal_alignment = 2
vertical_alignment = 2
[node name="LabelTowerInCube" type="Label" parent="TowerInfoPanel/InfoPanel/MarginContainer/VBoxContainer"]
[node name="TowerEnergy" type="Label" parent="TowerInfoPanel/InfoPanel/MarginContainer/VBoxContainer/HBoxContainer/VBoxContainer"]
unique_name_in_owner = true
layout_mode = 2
tooltip_text = "Le nombre de héros en action sur le terrain !"
mouse_filter = 1
theme_override_colors/font_color = Color(0.2, 0.2, 0.2, 1)
text = "0/0"
horizontal_alignment = 2
[node name="TowerIcon" type="TextureRect" parent="TowerInfoPanel/InfoPanel/MarginContainer/VBoxContainer/HBoxContainer"]
unique_name_in_owner = true
layout_mode = 2
texture = ExtResource("10_parkk")
expand_mode = 3
[node name="TowerDamage" type="Label" parent="TowerInfoPanel/InfoPanel/MarginContainer/VBoxContainer"]
unique_name_in_owner = true
layout_mode = 2
tooltip_text = "Le nombre de héros disponible dans le cube !"
mouse_filter = 1
@ -186,7 +214,8 @@ theme_override_colors/font_color = Color(0.2, 0.2, 0.2, 1)
text = "0"
horizontal_alignment = 2
[node name="LabelTowerOnTerrain" type="Label" parent="TowerInfoPanel/InfoPanel/MarginContainer/VBoxContainer"]
[node name="TowerCooldown" type="Label" parent="TowerInfoPanel/InfoPanel/MarginContainer/VBoxContainer"]
unique_name_in_owner = true
layout_mode = 2
tooltip_text = "Le nombre de héros en action sur le terrain !"
mouse_filter = 1
@ -194,26 +223,33 @@ theme_override_colors/font_color = Color(0.2, 0.2, 0.2, 1)
text = "0"
horizontal_alignment = 2
[node name="TowerInfoPanel" type="PanelContainer" parent="TowerInfoPanel"]
[node name="TowerBio" type="Label" parent="TowerInfoPanel/InfoPanel/MarginContainer/VBoxContainer"]
unique_name_in_owner = true
layout_mode = 2
tooltip_text = "Le nombre de héros en action sur le terrain !"
mouse_filter = 1
theme_override_colors/font_color = Color(0.2, 0.2, 0.2, 1)
text = "0"
horizontal_alignment = 2
[node name="UpgradeContainer" type="PanelContainer" parent="TowerInfoPanel"]
layout_mode = 2
size_flags_horizontal = 3
size_flags_vertical = 8
theme_override_styles/panel = SubResource("StyleBoxFlat_3lugd")
[node name="MarginContainer" type="MarginContainer" parent="TowerInfoPanel/TowerInfoPanel"]
[node name="MarginContainer" type="MarginContainer" parent="TowerInfoPanel/UpgradeContainer"]
layout_mode = 2
theme_override_constants/margin_left = 10
theme_override_constants/margin_top = 10
theme_override_constants/margin_right = 10
theme_override_constants/margin_bottom = 10
[node name="ButtonContainer" type="GridContainer" parent="TowerInfoPanel/TowerInfoPanel/MarginContainer"]
[node name="ButtonContainer" type="GridContainer" parent="TowerInfoPanel/UpgradeContainer/MarginContainer"]
layout_mode = 2
size_flags_horizontal = 0
size_flags_vertical = 0
columns = 4
[node name="Button" type="Button" parent="TowerInfoPanel/TowerInfoPanel/MarginContainer/ButtonContainer"]
[node name="Button" type="Button" parent="TowerInfoPanel/UpgradeContainer/MarginContainer/ButtonContainer"]
layout_mode = 2
theme_override_font_sizes/font_size = 20
text = "Améliorer"
@ -224,9 +260,10 @@ metadata/_custom_type_script = "uid://dyhtr6g7kd1g2"
[connection signal="pressed" from="HBoxContainer/ControlPanelBase/MarginContainer/ButtonContainer/QuitLevelBtn" to="." method="quitLevel"]
[connection signal="pressed" from="HBoxContainer/ControlPanelBase/MarginContainer/ButtonContainer/QuitGameBtn" to="." method="quitGame"]
[connection signal="toggled" from="HBoxContainer/ControlPanelBase/MarginContainer/ButtonContainer/TowerButton" to="HBoxContainer/ControlPanelBase/MarginContainer/ButtonContainer/TowerButton" method="buttonToggled"]
[connection signal="toggled" from="HBoxContainer/ControlPanelBase/MarginContainer/ButtonContainer/@Button@65726" to="HBoxContainer/ControlPanelBase/MarginContainer/ButtonContainer/@Button@65726" method="buttonToggled"]
[connection signal="toggled" from="HBoxContainer/ControlPanelBase/MarginContainer/ButtonContainer/@Button@65727" to="HBoxContainer/ControlPanelBase/MarginContainer/ButtonContainer/@Button@65727" method="buttonToggled"]
[connection signal="toggled" from="HBoxContainer/ControlPanelBase/MarginContainer/ButtonContainer/@Button@65728" to="HBoxContainer/ControlPanelBase/MarginContainer/ButtonContainer/@Button@65728" method="buttonToggled"]
[connection signal="toggled" from="HBoxContainer/ControlPanelBase/MarginContainer/ButtonContainer/@Button@65729" to="HBoxContainer/ControlPanelBase/MarginContainer/ButtonContainer/@Button@65729" method="buttonToggled"]
[connection signal="toggled" from="HBoxContainer/ControlPanelBase/MarginContainer/ButtonContainer/@Button@65730" to="HBoxContainer/ControlPanelBase/MarginContainer/ButtonContainer/@Button@65730" method="buttonToggled"]
[connection signal="toggled" from="HBoxContainer/ControlPanelBase/MarginContainer/ButtonContainer/@Button@65731" to="HBoxContainer/ControlPanelBase/MarginContainer/ButtonContainer/@Button@65731" method="buttonToggled"]
[connection signal="toggled" from="HBoxContainer/ControlPanelBase/MarginContainer/ButtonContainer/@Button@32868" to="HBoxContainer/ControlPanelBase/MarginContainer/ButtonContainer/@Button@32868" method="buttonToggled"]
[connection signal="toggled" from="HBoxContainer/ControlPanelBase/MarginContainer/ButtonContainer/@Button@32869" to="HBoxContainer/ControlPanelBase/MarginContainer/ButtonContainer/@Button@32869" method="buttonToggled"]
[connection signal="toggled" from="HBoxContainer/ControlPanelBase/MarginContainer/ButtonContainer/@Button@32870" to="HBoxContainer/ControlPanelBase/MarginContainer/ButtonContainer/@Button@32870" method="buttonToggled"]
[connection signal="toggled" from="HBoxContainer/ControlPanelBase/MarginContainer/ButtonContainer/@Button@32871" to="HBoxContainer/ControlPanelBase/MarginContainer/ButtonContainer/@Button@32871" method="buttonToggled"]
[connection signal="toggled" from="HBoxContainer/ControlPanelBase/MarginContainer/ButtonContainer/@Button@32872" to="HBoxContainer/ControlPanelBase/MarginContainer/ButtonContainer/@Button@32872" method="buttonToggled"]
[connection signal="toggled" from="HBoxContainer/ControlPanelBase/MarginContainer/ButtonContainer/@Button@32873" to="HBoxContainer/ControlPanelBase/MarginContainer/ButtonContainer/@Button@32873" method="buttonToggled"]
[connection signal="toggled" from="HBoxContainer/ControlPanelBase/MarginContainer/ButtonContainer/@Button@32874" to="HBoxContainer/ControlPanelBase/MarginContainer/ButtonContainer/@Button@32874" method="buttonToggled"]

View file

@ -3,7 +3,7 @@ extends Button
class_name GuiButton
enum TYPE { BASIC, TOWER }
enum TYPE { BASIC, TOWER, UPGRADE }
var type : TYPE = TYPE.BASIC
@ -15,11 +15,15 @@ var towerType : Tower.TYPE :
if towerType != Tower.TYPE.NONE:
type = TYPE.TOWER
toggle_mode = true
$EnergyBar.visible = true
add_theme_stylebox_override("pressed", GameStyleBoxFlat.createWithColor(Game.COLOR.SELECTED))
EventBus.energy_has_changed.connect(towerChanged)
EventBus.tower_builded.connect(towerChanged)
add_theme_stylebox_override("pressed", GameStyleBoxFlat.createWithColor(GameColor.COLOR.SELECTED))
EventBus.tower_changed.connect(towerChanged)
EventBus.tower_selected.connect(func(_type): set_pressed_no_signal(_type == towerType))
if type == TYPE.UPGRADE:
EventBus.tower_upgraded.connect(upgradeTower)
func upgradeTower(towerType : Tower.TYPE, upgrade : TowerUpgrade) -> void:
pass
@export var texture : Texture2D :
@ -34,6 +38,7 @@ func buttonToggled(state : bool) -> void:
func towerChanged(tower : Tower) -> void :
if tower.tower_type == towerType:
if tower.type == towerType:
$EnergyBar.value = tower.energy
$EnergyBar.max_value = tower.max_energy
$EnergyBar.visible = tower.builded

View file

@ -1,15 +0,0 @@
extends TextureButton
var _tower : Tower
@onready var progress_bar : ProgressBar = $ProgressBar
func _ready() -> void:
EventBus.tower_builded.connect(_on_EventBus_tower_builded)
func _on_EventBus_tower_builded(tower : Tower) -> void:
_tower = tower
func _process(delta: float) -> void:
if _tower:
progress_bar.value = _tower.energy/_tower.max_energy * 100

View file

@ -1 +0,0 @@
uid://cxl20r1p7u1h4

View file

@ -1,35 +0,0 @@
[gd_scene load_steps=5 format=3 uid="uid://2cuckqx3uiw7"]
[ext_resource type="Texture2D" uid="uid://dksohsrys0yy7" path="res://Assets/Icones/baby-face.svg" id="1_3epw4"]
[ext_resource type="Script" uid="uid://cxl20r1p7u1h4" path="res://UI/hero_icon.gd" id="2_45h83"]
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_6ujs1"]
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_wg577"]
bg_color = Color(0.96, 0.71808, 0.1536, 0.647059)
[node name="HeroIcon" type="TextureButton"]
custom_minimum_size = Vector2(50, 50)
size_flags_horizontal = 4
texture_normal = ExtResource("1_3epw4")
texture_pressed = ExtResource("1_3epw4")
texture_hover = ExtResource("1_3epw4")
texture_disabled = ExtResource("1_3epw4")
texture_focused = ExtResource("1_3epw4")
ignore_texture_size = true
stretch_mode = 0
script = ExtResource("2_45h83")
[node name="ProgressBar" type="ProgressBar" parent="."]
z_index = -1
layout_mode = 1
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
theme_override_styles/background = SubResource("StyleBoxEmpty_6ujs1")
theme_override_styles/fill = SubResource("StyleBoxFlat_wg577")
value = 50.0
fill_mode = 3
show_percentage = false

View file

@ -11,7 +11,7 @@ func _on_quit_button_pressed() -> void:
func _ready() -> void:
%LevelContainer.get_children().map(%LevelContainer.remove_child)
levels = Game.getPackedScenesPaths(Game.RESOURCE_TYPE.LEVEL)
levels = Helper.getPackedScenesPaths(Helper.RESOURCE_TYPE.LEVEL)
for i in levels.size():
var levelButton : Button = Button.new()
levelButton.text = "Level " + str(i + 1)

View file

@ -34,7 +34,7 @@ func upgradeUpgrade() -> void:
func canUpgrade():
return not isLevelMax && TheCube.money > cost
return not isLevelMax && Game.money > cost
func getNextValue(oldValue):

View file

@ -137,8 +137,8 @@ func cleanAndBuildMenu() -> void:
func resetApp() -> void:
enemies = getOptionsFromFile(Game.RESOURCE_TYPE.ENEMY)
levelSelect.setOptions(getOptionsFromFile(Game.RESOURCE_TYPE.LEVEL))
enemies = getOptionsFromFile(Helper.RESOURCE_TYPE.ENEMY)
levelSelect.setOptions(getOptionsFromFile(Helper.RESOURCE_TYPE.LEVEL))
cleanAndBuildMenu()
@ -192,7 +192,7 @@ func _on_new_level_pressed() -> void:
return
level = Level.new()
var levelName = "level_" + str(levelSelect.item_count + 1)
levelSelect.addOption(Game.LEVEL_DIR + levelName + ".tres", levelName, true)
levelSelect.addOption(Helper.LEVEL_DIR + levelName + ".tres", levelName, true)
_on_save_pressed()
@ -209,16 +209,16 @@ func onSelectedTowerChange(index: int, selected: int) -> void:
level.allowedTowers.erase(index)
func getOptionsFromFile(type: Game.RESOURCE_TYPE) -> Dictionary :
func getOptionsFromFile(type: Helper.RESOURCE_TYPE) -> Dictionary :
var files : Dictionary
var filePaths : Array[String]
var pattern : String
if type == Game.RESOURCE_TYPE.LEVEL:
filePaths = Game.getResourcesPaths(type)
pattern = Game.RESOURCE_FILE_PATTERN
if type == Helper.RESOURCE_TYPE.LEVEL:
filePaths = Helper.getResourcesPaths(type)
pattern = Helper.RESOURCE_FILE_PATTERN
else:
filePaths = Game.getPackedScenesPaths(type)
pattern = Game.SCENE_FILE_PATTERN
filePaths = Helper.getPackedScenesPaths(type)
pattern = Helper.SCENE_FILE_PATTERN
var regex : RegEx = RegEx.create_from_string(pattern)
for file in filePaths:

View file

@ -20,6 +20,7 @@ config/icon="res://icon.svg"
EventBus="*res://Globals/EventBus.gd"
Transition="*res://Globals/transition.tscn"
SignalLens="*res://addons/signal_lens/autoload/signal_lens_autoload.gd"
Game="*res://Globals/Game.gd"
[display]
@ -28,7 +29,7 @@ window/size/viewport_height=1080
[editor_plugins]
enabled=PackedStringArray("res://addons/LevelEditor/plugin.cfg", "res://addons/signal_lens/plugin.cfg")
enabled=PackedStringArray("res://addons/signal_lens/plugin.cfg")
[file_customization]