Use static typing in all demos (#1063)

This leads to code that is easier to understand and runs
faster thanks to GDScript's typed instructions.

The untyped declaration warning is now enabled on all projects
where type hints were added. All projects currently run without
any untyped declration warnings.

Dodge the Creeps and Squash the Creeps demos intentionally don't
use type hints to match the documentation, where type hints haven't
been adopted yet (given its beginner focus).
This commit is contained in:
Hugo Locurcio
2024-06-01 12:12:18 +02:00
committed by GitHub
parent 8e9c180278
commit bac1e69164
498 changed files with 5218 additions and 4776 deletions

View File

@@ -1,12 +1,11 @@
extends Node
signal combat_finished(winner, loser)
signal combat_finished(winner: Combatant, loser: Combatant)
func initialize(combat_combatants):
for combatant in combat_combatants:
combatant = combatant.instantiate()
func initialize(combat_combatants: Array[PackedScene]) -> void:
for combatant_scene in combat_combatants:
var combatant := combatant_scene.instantiate()
if combatant is Combatant:
$Combatants.add_combatant(combatant)
combatant.get_node("Health").dead.connect(_on_combatant_death.bind(combatant))
@@ -16,19 +15,20 @@ func initialize(combat_combatants):
$TurnQueue.initialize()
func clear_combat():
func clear_combat() -> void:
for n in $Combatants.get_children():
n.queue_free()
for n in $UI/Combatants.get_children():
n.queue_free()
func finish_combat(winner, loser):
func finish_combat(winner: Combatant, loser: Combatant) -> void:
# FIXME: Error calling from signal 'combat_finished' to callable: 'Node(game.gd)::_on_combat_finished': Cannot convert argument 1 from Object to Object.
combat_finished.emit(winner, loser)
func _on_combatant_death(combatant):
var winner
func _on_combatant_death(combatant: Combatant) -> void:
var winner: Combatant
if not combatant.name == "Player":
winner = $Combatants/Player
else:
@@ -36,4 +36,5 @@ func _on_combatant_death(combatant):
if not n.name == "Player":
winner = n
break
finish_combat(winner, combatant)

View File

@@ -4,7 +4,7 @@
[ext_resource type="Script" path="res://combat/turn_queue.gd" id="2"]
[ext_resource type="Theme" uid="uid://dtao6d0ebglcf" path="res://theme/theme.tres" id="3"]
[ext_resource type="Script" path="res://combat/interface/ui.gd" id="4"]
[ext_resource type="PackedScene" path="res://combat/interface/info.tscn" id="5"]
[ext_resource type="PackedScene" uid="uid://bypumcqt7j0iv" path="res://combat/interface/info.tscn" id="5"]
[ext_resource type="Texture2D" uid="uid://dh804n3h2bl5h" path="res://combat/background/combat_background.png" id="6"]
[ext_resource type="Texture2D" uid="uid://mi3mmtft0snh" path="res://decoration/grass.png" id="7"]
[ext_resource type="Material" uid="uid://blst65bnoqyam" path="res://decoration/wind_sway.tres" id="8"]
@@ -19,7 +19,7 @@
[sub_resource type="GDScript" id="1"]
script/source = "extends Node2D
func add_combatant(new_combatant):
func add_combatant(new_combatant: Node2D) -> void:
new_combatant.position.x += 200 * get_child_count()
add_child(new_combatant)
"

View File

@@ -1,17 +1,14 @@
class_name Combatant
extends Node
signal turn_finished
@export var damage: int = 1
@export var defense: int = 1
@export var damage := 1
@export var defense := 1
var active = false: set = set_active
var active := false: set = set_active
func set_active(value):
func set_active(value: bool) -> void:
active = value
set_process(value)
set_process_input(value)
@@ -22,25 +19,20 @@ func set_active(value):
$Health.armor = $Health.base_armor
func attack(target):
func attack(target: Combatant) -> void:
target.take_damage(damage)
turn_finished.emit()
func consume(item):
item.use(self)
turn_finished.emit()
func defend():
func defend() -> void:
$Health.armor += defense
turn_finished.emit()
func flee():
func flee() -> void:
turn_finished.emit()
func take_damage(damage_to_take):
func take_damage(damage_to_take: float) -> void:
$Health.take_damage(damage_to_take)
$Sprite2D/AnimationPlayer.play("take_damage")

View File

@@ -1,20 +1,19 @@
extends Node
signal dead
signal health_changed(life)
signal health_changed(life: float)
@export var life = 0
@export var max_life = 10
@export var base_armor = 0
var armor = 0
@export var life := 0
@export var max_life := 10
@export var base_armor := 0
var armor := 0
func _ready():
func _ready() -> void:
armor = base_armor
func take_damage(damage):
func take_damage(damage: int) -> void:
life = life - damage + armor
if life <= 0:
dead.emit()
@@ -22,11 +21,11 @@ func take_damage(damage):
health_changed.emit(life)
func heal(amount):
func heal(amount: int) -> void:
life += amount
life = clamp(life, life, max_life)
health_changed.emit(life)
func get_health_ratio():
return life / max_life
func get_health_ratio() -> float:
return float(life) / max_life

View File

@@ -1,18 +1,20 @@
extends Combatant
func set_active(value):
func set_active(value: bool) -> void:
super.set_active(value)
if not active:
return
if not $Timer.is_inside_tree():
return
$Timer.start()
await $Timer.timeout
var target
var target: Node
for actor in get_parent().get_children():
if not actor == self:
target = actor
break
attack(target)

View File

@@ -5,35 +5,39 @@ extends Control
@export var info_scene: PackedScene
func initialize():
func initialize() -> void:
for combatant in combatants_node.get_children():
var health = combatant.get_node("Health")
var info = info_scene.instantiate()
var health_info = info.get_node("VBoxContainer/HealthContainer/Health")
var health := combatant.get_node("Health")
var info := info_scene.instantiate()
var health_info := info.get_node("VBoxContainer/HealthContainer/Health")
health_info.value = health.life
health_info.max_value = health.max_life
info.get_node("VBoxContainer/NameContainer/Name").text = combatant.name
health.health_changed.connect(health_info.set_value)
$Combatants.add_child(info)
$Buttons/GridContainer/Attack.grab_focus()
func _on_Attack_button_up():
func _on_Attack_button_up() -> void:
if not combatants_node.get_node("Player").active:
return
combatants_node.get_node("Player").attack(combatants_node.get_node("Opponent"))
func _on_Defend_button_up():
func _on_Defend_button_up() -> void:
if not combatants_node.get_node("Player").active:
return
combatants_node.get_node("Player").defend()
func _on_Flee_button_up():
func _on_Flee_button_up() -> void:
if not combatants_node.get_node("Player").active:
return
combatants_node.get_node("Player").flee()
var loser = combatants_node.get_node("Player")
var winner = combatants_node.get_node("Opponent")
var loser: Combatant = combatants_node.get_node("Player")
var winner: Combatant = combatants_node.get_node("Opponent")
get_parent().finish_combat(winner, loser)

View File

@@ -1,42 +1,41 @@
extends Node
signal active_combatant_changed(active_combatant)
signal active_combatant_changed(active_combatant: Combatant)
@export var combatants_list: Node
var queue = []: set = set_queue
var active_combatant = null: set = _set_active_combatant
var queue: Array[Node] = []: set = set_queue
var active_combatant: Combatant = null: set = _set_active_combatant
func initialize():
func initialize() -> void:
set_queue(combatants_list.get_children())
play_turn()
func play_turn():
func play_turn() -> void:
await active_combatant.turn_finished
get_next_in_queue()
play_turn()
func get_next_in_queue():
var current_combatant = queue.pop_front()
func get_next_in_queue() -> Node:
var current_combatant: Node = queue.pop_front()
current_combatant.active = false
queue.append(current_combatant)
active_combatant = queue[0]
return active_combatant
func remove(combatant):
var new_queue = []
func remove(combatant: Combatant) -> void:
var new_queue := []
for n in queue:
new_queue.append(n)
new_queue.remove(new_queue.find(combatant))
new_queue.remove_at(new_queue.find(combatant))
combatant.queue_free()
queue = new_queue
func set_queue(new_queue):
func set_queue(new_queue: Array[Node]) -> void:
queue.clear()
for node in new_queue:
if not node is Combatant:
@@ -47,7 +46,7 @@ func set_queue(new_queue):
active_combatant = queue[0]
func _set_active_combatant(new_combatant):
func _set_active_combatant(new_combatant: Combatant) -> void:
active_combatant = new_combatant
active_combatant.active = true
active_combatant_changed.emit(active_combatant)

6
2d/role_playing_game/dialogue/dialogue_data/npc.json Executable file → Normal file
View File

@@ -1,5 +1,5 @@
{
"dialog_1" : {"name": "UNKNOWN", "text": "Hey, it's a good time to have a JRPG fight, right?"},
"dialog_2" : {"name": "UNKNOWN", "text": "Let me introduce myself, I'm your OPPONENT"},
"dialog_3" : {"name": "OPPONENT", "text": "Enough talking. Let's fight!"},
"dialog_1" : { "name": "UNKNOWN", "text": "Hey, it's a good time to have a JRPG fight, right?" },
"dialog_2" : { "name": "UNKNOWN", "text": "Let me introduce myself, I'm your OPPONENT." },
"dialog_3" : { "name": "OPPONENT", "text": "Enough talking. Let's fight!" },
}

View File

@@ -1,3 +1,3 @@
{
"dialog_1" : {"name":"PLAYER", "text":"Just a key..." }
"dialog_1" : { "name": "PLAYER", "text": "Just a key..." }
}

View File

@@ -1,3 +1,3 @@
{
"dialog_1" : {"name": "OPPONENT", "text": "Aha! I won, maybe you can try again next time"}
"dialog_1" : { "name": "OPPONENT", "text": "Aha! I won, maybe you can try again next time." }
}

View File

@@ -1,3 +1,3 @@
{
"dialog_1" : {"name": "OPPONENT", "text": "Congratulations, you won!"}
"dialog_1" : { "name": "OPPONENT", "text": "Congratulations, you won!" }
}

View File

@@ -1,17 +1,16 @@
extends Node
signal dialogue_started
signal dialogue_finished
@export_file("*.json") var dialogue_file: String
var dialogue_keys = []
var dialogue_name = ""
var current = 0
var dialogue_text = ""
var dialogue_keys := []
var dialogue_name := ""
var current := 0
var dialogue_text := ""
func start_dialogue():
func start_dialogue() -> void:
dialogue_started.emit()
current = 0
index_dialogue()
@@ -19,7 +18,7 @@ func start_dialogue():
dialogue_name = dialogue_keys[current].name
func next_dialogue():
func next_dialogue() -> void:
current += 1
if current == dialogue_keys.size():
dialogue_finished.emit()
@@ -28,17 +27,18 @@ func next_dialogue():
dialogue_name = dialogue_keys[current].name
func index_dialogue():
var dialogue = load_dialogue(dialogue_file)
func index_dialogue() -> void:
var dialogue: Dictionary = load_dialogue(dialogue_file)
dialogue_keys.clear()
for key in dialogue:
for key: String in dialogue:
dialogue_keys.append(dialogue[key])
func load_dialogue(file_path):
var file = FileAccess.open(file_path, FileAccess.READ)
func load_dialogue(file_path: String) -> Dictionary:
var file := FileAccess.open(file_path, FileAccess.READ)
if file:
var test_json_conv = JSON.new()
var test_json_conv := JSON.new()
test_json_conv.parse(file.get_as_text())
var dialogue = test_json_conv.get_data()
return dialogue
return test_json_conv.data
return {}

View File

@@ -1,6 +1,6 @@
[gd_scene load_steps=2 format=2]
[gd_scene load_steps=2 format=3 uid="uid://cid4iajexfsg2"]
[ext_resource path="res://dialogue/dialogue_player/dialogue_player.gd" type="Script" id=1]
[ext_resource type="Script" path="res://dialogue/dialogue_player/dialogue_player.gd" id="1"]
[node name="DialoguePlayer" type="Node"]
script = ExtResource( 1 )
script = ExtResource("1")

View File

@@ -1,23 +1,23 @@
extends Control
var dialogue_node: Node = null
var dialogue_node = null
func _ready() -> void:
visible = false
func _ready():
hide()
func show_dialogue(player, dialogue):
show()
func show_dialogue(player: Pawn, dialogue: Node) -> void:
visible = true
$Button.grab_focus()
dialogue_node = dialogue
for c in dialogue.get_signal_connection_list("dialogue_started"):
if player == c.callable.get_object():
dialogue_node.start_dialogue()
$Name.text = "[center]" + dialogue_node.dialogue_name + "[/center]"
$Text.text = dialogue_node.dialogue_text
return
dialogue_node.dialogue_started.connect(player.set_active.bind(false))
dialogue_node.dialogue_finished.connect(player.set_active.bind(true))
dialogue_node.dialogue_finished.connect(hide)
@@ -27,13 +27,13 @@ func show_dialogue(player, dialogue):
$Text.text = dialogue_node.dialogue_text
func _on_Button_button_up():
func _on_Button_button_up() -> void:
dialogue_node.next_dialogue()
$Name.text = "[center]" + dialogue_node.dialogue_name + "[/center]"
$Text.text = dialogue_node.dialogue_text
func _on_dialogue_finished(player):
func _on_dialogue_finished(player: Pawn) -> void:
dialogue_node.dialogue_started.disconnect(player.set_active)
dialogue_node.dialogue_finished.disconnect(player.set_active)
dialogue_node.dialogue_finished.disconnect(hide)

View File

@@ -1,14 +1,13 @@
extends Node
const PLAYER_WIN = "res://dialogue/dialogue_data/player_won.json"
const PLAYER_LOSE = "res://dialogue/dialogue_data/player_lose.json"
@export var combat_screen: Node
@export var exploration_screen: Node
@export var combat_screen: Node2D
@export var exploration_screen: Node2D
func _ready():
func _ready() -> void:
combat_screen.combat_finished.connect(_on_combat_finished)
for n in $Exploration/Grid.get_children():
@@ -21,7 +20,7 @@ func _ready():
remove_child(combat_screen)
func start_combat(combat_actors):
func start_combat(combat_actors: Array[PackedScene]) -> void:
remove_child($Exploration)
$AnimationPlayer.play("fade")
await $AnimationPlayer.animation_finished
@@ -31,19 +30,19 @@ func start_combat(combat_actors):
$AnimationPlayer.play_backwards("fade")
func _on_opponent_dialogue_finished(opponent):
func _on_opponent_dialogue_finished(opponent: Pawn) -> void:
if opponent.lost:
return
var player = $Exploration/Grid/Player
var combatants = [player.combat_actor, opponent.combat_actor]
var player: Node2D = $Exploration/Grid/Player
var combatants: Array[PackedScene] = [player.combat_actor, opponent.combat_actor]
start_combat(combatants)
func _on_combat_finished(winner, _loser):
func _on_combat_finished(winner: Combatant, _loser: Combatant) -> void:
remove_child(combat_screen)
$AnimationPlayer.play_backwards("fade")
add_child(exploration_screen)
var dialogue = load("res://dialogue/dialogue_player/dialogue_player.tscn").instantiate()
var dialogue: Node = load("res://dialogue/dialogue_player/dialogue_player.tscn").instantiate()
if winner.name == "Player":
dialogue.dialogue_file = PLAYER_WIN
@@ -51,7 +50,7 @@ func _on_combat_finished(winner, _loser):
dialogue.dialogue_file = PLAYER_LOSE
await $AnimationPlayer.animation_finished
var player = $Exploration/Grid/Player
var player: Pawn = $Exploration/Grid/Player
exploration_screen.get_node("DialogueUI").show_dialogue(player, dialogue)
combat_screen.clear_combat()
await dialogue.dialogue_finished

View File

@@ -1,38 +1,45 @@
extends TileMap
enum CellType {
ACTOR,
OBSTACLE,
OBJECT,
}
enum CellType { ACTOR, OBSTACLE, OBJECT }
@export var dialogue_ui: Node
func _ready():
func _ready() -> void:
for child in get_children():
set_cell(0, local_to_map(child.position), child.type, Vector2i.ZERO)
func get_cell_pawn(cell, type = CellType.ACTOR):
func get_cell_pawn(cell: Vector2i, type: CellType = CellType.ACTOR) -> Node2D:
for node in get_children():
if node.type != type:
continue
if local_to_map(node.position) == cell:
return(node)
return node
return null
func request_move(pawn, direction: Vector2i):
var cell_start = local_to_map(pawn.position)
var cell_target = cell_start + direction
func request_move(pawn: Pawn, direction: Vector2i) -> Vector2i:
var cell_start := local_to_map(pawn.position)
var cell_target := cell_start + direction
var cell_tile_id = get_cell_source_id(0, cell_target)
var cell_tile_id := get_cell_source_id(0, cell_target)
match cell_tile_id:
-1:
set_cell(0, cell_target, CellType.ACTOR, Vector2i.ZERO)
set_cell(0, cell_start, -1, Vector2i.ZERO)
return map_to_local(cell_target)
CellType.OBJECT, CellType.ACTOR:
var target_pawn = get_cell_pawn(cell_target, cell_tile_id)
var target_pawn := get_cell_pawn(cell_target, cell_tile_id)
#print("Cell %s contains %s" % [cell_target, target_pawn.name])
if not target_pawn.has_node("DialoguePlayer"):
return
return Vector2i.ZERO
dialogue_ui.show_dialogue(pawn, target_pawn.get_node("DialoguePlayer"))
return Vector2i.ZERO

View File

@@ -1,6 +1,5 @@
extends Pawn
var lost = false
@onready var Grid = get_parent()

View File

@@ -1,11 +1,7 @@
extends Pawn
#warning-ignore:unused_class_variable
@export var combat_actor: PackedScene
#warning-ignore:unused_class_variable
var lost = false
var lost := false
func _ready():
func _ready() -> void:
set_process(false)

View File

@@ -1,15 +1,17 @@
class_name Pawn
extends Node2D
enum CellType {
ACTOR,
OBSTACLE,
OBJECT,
}
enum CellType { ACTOR, OBSTACLE, OBJECT }
#warning-ignore:unused_class_variable
@export var type: CellType = CellType.ACTOR
@export var type := CellType.ACTOR
var active = true: set = set_active
var active := true: set = set_active
func set_active(value):
func set_active(value: bool) -> void:
active = value
set_process(value)
set_process_input(value)

View File

@@ -1,53 +1,53 @@
extends Pawn
#warning-ignore:unused_class_variable
@export var combat_actor: PackedScene
#warning-ignore:unused_class_variable
var lost = false
var grid_size
@onready var parent = get_parent()
@onready var animation_playback = $AnimationTree.get("parameters/playback")
@onready var walk_animation_time = $AnimationPlayer.get_animation("walk").length
var lost := false
var grid_size: float
@onready var parent := get_parent()
@onready var animation_playback: AnimationNodeStateMachinePlayback = $AnimationTree.get("parameters/playback")
@onready var walk_animation_time: float = $AnimationPlayer.get_animation("walk").length
func _ready():
func _ready() -> void:
update_look_direction(Vector2.RIGHT)
grid_size = parent.tile_set.tile_size.x
func _process(_delta):
var input_direction = get_input_direction()
func _process(_delta: float) -> void:
var input_direction := get_input_direction()
if input_direction.is_zero_approx():
return
update_look_direction(input_direction)
var target_position = parent.request_move(self, input_direction)
var target_position: Vector2 = parent.request_move(self, input_direction)
if target_position:
move_to(target_position)
elif active:
bump()
func get_input_direction():
func get_input_direction() -> Vector2:
return Vector2(
Input.get_action_strength("move_right") - Input.get_action_strength("move_left"),
Input.get_action_strength("move_down") - Input.get_action_strength("move_up")
Input.get_action_strength("move_right") - Input.get_action_strength("move_left"),
Input.get_action_strength("move_down") - Input.get_action_strength("move_up")
)
func update_look_direction(direction):
func update_look_direction(direction: Vector2) -> void:
$Pivot/Sprite2D.rotation = direction.angle()
func move_to(target_position):
func move_to(target_position: Vector2) -> void:
set_process(false)
var move_direction = (target_position - position).normalized()
var move_direction := (target_position - position).normalized()
animation_playback.start("walk")
var tween := create_tween()
tween.set_ease(Tween.EASE_IN)
var end = $Pivot.position + move_direction * grid_size
var end: Vector2 = $Pivot.position + move_direction * grid_size
tween.tween_property($Pivot, "position", end, walk_animation_time)
await tween.finished
@@ -57,7 +57,8 @@ func move_to(target_position):
set_process(true)
func bump():
func bump() -> void:
set_process(false)
animation_playback.start("bump")
await $AnimationTree.animation_finished

View File

@@ -19,6 +19,10 @@ run/main_scene="res://game.tscn"
config/features=PackedStringArray("4.2")
config/icon="res://icon.svg"
[debug]
gdscript/warnings/untyped_declaration=1
[display]
window/size/viewport_width=1280