├── 9-game-hud
├── hud.gd.uid
├── main.gd.uid
├── map.gd.uid
├── detector.gd.uid
├── main_menu.gd.uid
├── lively_light.gd.uid
├── map_transition.gd.uid
├── movable_object.gd.uid
├── player_character.gd.uid
├── tile_set.png
├── main_menu.gd
├── map_transition.gd
├── player_character.gd
├── hud.gd
├── tile_set.png.import
├── lively_light.gd
├── icon.svg
├── icon.svg.import
├── project.godot
├── lively_light.tscn
├── movable_object.gd
├── hud.tscn
├── movable_object.tscn
├── map.gd
├── detector.gd
├── detector.tscn
├── main_menu.tscn
└── tile_set.tres
├── 10-extra-map-info
├── hud.gd.uid
├── main.gd.uid
├── map.gd.uid
├── detector.gd.uid
├── main_menu.gd.uid
├── lively_light.gd.uid
├── map_transition.gd.uid
├── movable_object.gd.uid
├── player_character.gd.uid
├── tile_set.png
├── main_menu.gd
├── map_transition.gd
├── tile_set.png.import
├── lively_light.gd
├── icon.svg
├── icon.svg.import
├── project.godot
├── lively_light.tscn
├── player_character.gd
├── movable_object.gd
├── movable_object.tscn
├── detector.gd
├── detector.tscn
├── hud.gd
├── main_menu.tscn
├── tile_set.tres
├── map.gd
└── hud.tscn
├── 12-teleporters
├── hud.gd.uid
├── main.gd.uid
├── map.gd.uid
├── detector.gd.uid
├── lively_light.gd.uid
├── main_menu.gd.uid
├── map_transition.gd.uid
├── movable_object.gd.uid
├── player_character.gd.uid
├── interactive_object.gd.uid
├── teleporters
│ ├── teleporter_line.gdshader.uid
│ ├── teleporter_source.gd.uid
│ ├── teleporter_destination.gd.uid
│ ├── teleporter_source.png
│ ├── teleporter_destination.png
│ ├── teleporter_line.gdshader
│ ├── teleporter_destination.gd
│ ├── teleporter_source.png.import
│ ├── teleporter_destination.png.import
│ ├── teleporter_source.gd
│ └── teleporter_destination.tscn
├── tile_set.png
├── interactive_object.gd
├── main_menu.gd
├── map_transition.gd
├── tile_set.png.import
├── lively_light.gd
├── icon.svg
├── icon.svg.import
├── project.godot
├── lively_light.tscn
├── movable_object.gd
├── player_character.gd
├── movable_object.tscn
├── detector.gd
├── detector.tscn
├── main_menu.tscn
├── tile_set.tres
├── hud.gd
├── hud.tscn
└── map.gd
├── 8-saving-progress
├── main.gd.uid
├── map.gd.uid
├── detector.gd.uid
├── main_menu.gd.uid
├── lively_light.gd.uid
├── map_transition.gd.uid
├── movable_object.gd.uid
├── player_character.gd.uid
├── tile_set.png
├── main_menu.gd
├── map_transition.gd
├── map.gd
├── player_character.gd
├── tile_set.png.import
├── lively_light.gd
├── icon.svg
├── project.godot
├── icon.svg.import
├── lively_light.tscn
├── movable_object.gd
├── movable_object.tscn
├── detector.gd
├── detector.tscn
├── main_menu.tscn
├── tile_set.tres
└── main.gd
├── 11-showing-best-scores
├── hud.gd.uid
├── main.gd.uid
├── map.gd.uid
├── detector.gd.uid
├── main_menu.gd.uid
├── lively_light.gd.uid
├── map_transition.gd.uid
├── movable_object.gd.uid
├── player_character.gd.uid
├── tile_set.png
├── main_menu.gd
├── map_transition.gd
├── tile_set.png.import
├── lively_light.gd
├── icon.svg
├── icon.svg.import
├── project.godot
├── player_character.gd
├── lively_light.tscn
├── movable_object.gd
├── movable_object.tscn
├── detector.gd
├── detector.tscn
├── main_menu.tscn
├── tile_set.tres
├── hud.gd
├── hud.tscn
└── map.gd
├── 1-tile-map
├── tile_set.png
├── project.godot
├── tile_set.tres
├── tile_set.png.import
├── icon.svg
└── icon.svg.import
├── 5-detectors
├── tile_set.png
├── player_character.gd
├── project.godot
├── tile_set.png.import
├── icon.svg
├── lively_light.gd
├── icon.svg.import
├── lively_light.tscn
├── movable_object.gd
├── detector.gd
├── movable_object.tscn
├── detector.tscn
└── tile_set.tres
├── 6-multiple-maps
├── tile_set.png
├── player_character.gd
├── project.godot
├── tile_set.png.import
├── lively_light.gd
├── icon.svg
├── icon.svg.import
├── lively_light.tscn
├── movable_object.gd
├── map.gd
├── movable_object.tscn
├── detector.gd
├── detector.tscn
└── tile_set.tres
├── 2-player-character
├── tile_set.png
├── player_character.gd
├── project.godot
├── tile_set.png.import
├── icon.svg
├── icon.svg.import
└── tile_set.tres
├── 3-movable-objects
├── tile_set.png
├── player_character.gd
├── project.godot
├── tile_set.png.import
├── movable_object.tscn
├── icon.svg
├── icon.svg.import
├── movable_object.gd
└── tile_set.tres
├── 4-light-and-shadow
├── tile_set.png
├── player_character.gd
├── project.godot
├── tile_set.png.import
├── lively_light.gd
├── icon.svg
├── icon.svg.import
├── lively_light.tscn
├── movable_object.gd
├── movable_object.tscn
└── tile_set.tres
├── 7-map-transitions
├── tile_set.png
├── map_transition.gd
├── map.gd
├── player_character.gd
├── main.gd
├── tile_set.png.import
├── lively_light.gd
├── icon.svg
├── project.godot
├── icon.svg.import
├── lively_light.tscn
├── movable_object.gd
├── movable_object.tscn
├── detector.gd
├── detector.tscn
└── tile_set.tres
├── .gitignore
├── LICENSE
├── CHANGELOG.md
└── README.md
/9-game-hud/hud.gd.uid:
--------------------------------------------------------------------------------
1 | uid://cv3i66vvgu2ra
2 |
--------------------------------------------------------------------------------
/9-game-hud/main.gd.uid:
--------------------------------------------------------------------------------
1 | uid://uwkiknpq3u2m
2 |
--------------------------------------------------------------------------------
/9-game-hud/map.gd.uid:
--------------------------------------------------------------------------------
1 | uid://bgk0njn8kou4j
2 |
--------------------------------------------------------------------------------
/10-extra-map-info/hud.gd.uid:
--------------------------------------------------------------------------------
1 | uid://cv3i66vvgu2ra
2 |
--------------------------------------------------------------------------------
/10-extra-map-info/main.gd.uid:
--------------------------------------------------------------------------------
1 | uid://uwkiknpq3u2m
2 |
--------------------------------------------------------------------------------
/10-extra-map-info/map.gd.uid:
--------------------------------------------------------------------------------
1 | uid://bgk0njn8kou4j
2 |
--------------------------------------------------------------------------------
/12-teleporters/hud.gd.uid:
--------------------------------------------------------------------------------
1 | uid://cv3i66vvgu2ra
2 |
--------------------------------------------------------------------------------
/12-teleporters/main.gd.uid:
--------------------------------------------------------------------------------
1 | uid://uwkiknpq3u2m
2 |
--------------------------------------------------------------------------------
/12-teleporters/map.gd.uid:
--------------------------------------------------------------------------------
1 | uid://bgk0njn8kou4j
2 |
--------------------------------------------------------------------------------
/8-saving-progress/main.gd.uid:
--------------------------------------------------------------------------------
1 | uid://uwkiknpq3u2m
2 |
--------------------------------------------------------------------------------
/8-saving-progress/map.gd.uid:
--------------------------------------------------------------------------------
1 | uid://bgk0njn8kou4j
2 |
--------------------------------------------------------------------------------
/9-game-hud/detector.gd.uid:
--------------------------------------------------------------------------------
1 | uid://cva53g77vgubi
2 |
--------------------------------------------------------------------------------
/9-game-hud/main_menu.gd.uid:
--------------------------------------------------------------------------------
1 | uid://b53qr6le0v04
2 |
--------------------------------------------------------------------------------
/10-extra-map-info/detector.gd.uid:
--------------------------------------------------------------------------------
1 | uid://cva53g77vgubi
2 |
--------------------------------------------------------------------------------
/10-extra-map-info/main_menu.gd.uid:
--------------------------------------------------------------------------------
1 | uid://b53qr6le0v04
2 |
--------------------------------------------------------------------------------
/11-showing-best-scores/hud.gd.uid:
--------------------------------------------------------------------------------
1 | uid://cv3i66vvgu2ra
2 |
--------------------------------------------------------------------------------
/11-showing-best-scores/main.gd.uid:
--------------------------------------------------------------------------------
1 | uid://uwkiknpq3u2m
2 |
--------------------------------------------------------------------------------
/11-showing-best-scores/map.gd.uid:
--------------------------------------------------------------------------------
1 | uid://bgk0njn8kou4j
2 |
--------------------------------------------------------------------------------
/12-teleporters/detector.gd.uid:
--------------------------------------------------------------------------------
1 | uid://cva53g77vgubi
2 |
--------------------------------------------------------------------------------
/12-teleporters/lively_light.gd.uid:
--------------------------------------------------------------------------------
1 | uid://cgoe12geigody
2 |
--------------------------------------------------------------------------------
/12-teleporters/main_menu.gd.uid:
--------------------------------------------------------------------------------
1 | uid://b53qr6le0v04
2 |
--------------------------------------------------------------------------------
/8-saving-progress/detector.gd.uid:
--------------------------------------------------------------------------------
1 | uid://cva53g77vgubi
2 |
--------------------------------------------------------------------------------
/8-saving-progress/main_menu.gd.uid:
--------------------------------------------------------------------------------
1 | uid://b53qr6le0v04
2 |
--------------------------------------------------------------------------------
/9-game-hud/lively_light.gd.uid:
--------------------------------------------------------------------------------
1 | uid://cgoe12geigody
2 |
--------------------------------------------------------------------------------
/9-game-hud/map_transition.gd.uid:
--------------------------------------------------------------------------------
1 | uid://napvaw5g8duc
2 |
--------------------------------------------------------------------------------
/9-game-hud/movable_object.gd.uid:
--------------------------------------------------------------------------------
1 | uid://on8oe1ncp37d
2 |
--------------------------------------------------------------------------------
/9-game-hud/player_character.gd.uid:
--------------------------------------------------------------------------------
1 | uid://fpaopiu0nhaj
2 |
--------------------------------------------------------------------------------
/10-extra-map-info/lively_light.gd.uid:
--------------------------------------------------------------------------------
1 | uid://cgoe12geigody
2 |
--------------------------------------------------------------------------------
/10-extra-map-info/map_transition.gd.uid:
--------------------------------------------------------------------------------
1 | uid://napvaw5g8duc
2 |
--------------------------------------------------------------------------------
/10-extra-map-info/movable_object.gd.uid:
--------------------------------------------------------------------------------
1 | uid://on8oe1ncp37d
2 |
--------------------------------------------------------------------------------
/11-showing-best-scores/detector.gd.uid:
--------------------------------------------------------------------------------
1 | uid://cva53g77vgubi
2 |
--------------------------------------------------------------------------------
/11-showing-best-scores/main_menu.gd.uid:
--------------------------------------------------------------------------------
1 | uid://b53qr6le0v04
2 |
--------------------------------------------------------------------------------
/12-teleporters/map_transition.gd.uid:
--------------------------------------------------------------------------------
1 | uid://napvaw5g8duc
2 |
--------------------------------------------------------------------------------
/12-teleporters/movable_object.gd.uid:
--------------------------------------------------------------------------------
1 | uid://on8oe1ncp37d
2 |
--------------------------------------------------------------------------------
/12-teleporters/player_character.gd.uid:
--------------------------------------------------------------------------------
1 | uid://fpaopiu0nhaj
2 |
--------------------------------------------------------------------------------
/8-saving-progress/lively_light.gd.uid:
--------------------------------------------------------------------------------
1 | uid://cgoe12geigody
2 |
--------------------------------------------------------------------------------
/8-saving-progress/map_transition.gd.uid:
--------------------------------------------------------------------------------
1 | uid://napvaw5g8duc
2 |
--------------------------------------------------------------------------------
/8-saving-progress/movable_object.gd.uid:
--------------------------------------------------------------------------------
1 | uid://on8oe1ncp37d
2 |
--------------------------------------------------------------------------------
/10-extra-map-info/player_character.gd.uid:
--------------------------------------------------------------------------------
1 | uid://fpaopiu0nhaj
2 |
--------------------------------------------------------------------------------
/11-showing-best-scores/lively_light.gd.uid:
--------------------------------------------------------------------------------
1 | uid://cgoe12geigody
2 |
--------------------------------------------------------------------------------
/11-showing-best-scores/map_transition.gd.uid:
--------------------------------------------------------------------------------
1 | uid://napvaw5g8duc
2 |
--------------------------------------------------------------------------------
/11-showing-best-scores/movable_object.gd.uid:
--------------------------------------------------------------------------------
1 | uid://on8oe1ncp37d
2 |
--------------------------------------------------------------------------------
/12-teleporters/interactive_object.gd.uid:
--------------------------------------------------------------------------------
1 | uid://bt8vrxi771m6m
2 |
--------------------------------------------------------------------------------
/8-saving-progress/player_character.gd.uid:
--------------------------------------------------------------------------------
1 | uid://fpaopiu0nhaj
2 |
--------------------------------------------------------------------------------
/11-showing-best-scores/player_character.gd.uid:
--------------------------------------------------------------------------------
1 | uid://fpaopiu0nhaj
2 |
--------------------------------------------------------------------------------
/12-teleporters/teleporters/teleporter_line.gdshader.uid:
--------------------------------------------------------------------------------
1 | uid://u1jp4gvurjpa
2 |
--------------------------------------------------------------------------------
/12-teleporters/teleporters/teleporter_source.gd.uid:
--------------------------------------------------------------------------------
1 | uid://cdbb4xwhu0vne
2 |
--------------------------------------------------------------------------------
/12-teleporters/teleporters/teleporter_destination.gd.uid:
--------------------------------------------------------------------------------
1 | uid://dwu02xxnacil7
2 |
--------------------------------------------------------------------------------
/1-tile-map/tile_set.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasper-flick/godot-true-top-down-2d/HEAD/1-tile-map/tile_set.png
--------------------------------------------------------------------------------
/9-game-hud/tile_set.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasper-flick/godot-true-top-down-2d/HEAD/9-game-hud/tile_set.png
--------------------------------------------------------------------------------
/5-detectors/tile_set.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasper-flick/godot-true-top-down-2d/HEAD/5-detectors/tile_set.png
--------------------------------------------------------------------------------
/12-teleporters/tile_set.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasper-flick/godot-true-top-down-2d/HEAD/12-teleporters/tile_set.png
--------------------------------------------------------------------------------
/6-multiple-maps/tile_set.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasper-flick/godot-true-top-down-2d/HEAD/6-multiple-maps/tile_set.png
--------------------------------------------------------------------------------
/10-extra-map-info/tile_set.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasper-flick/godot-true-top-down-2d/HEAD/10-extra-map-info/tile_set.png
--------------------------------------------------------------------------------
/2-player-character/tile_set.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasper-flick/godot-true-top-down-2d/HEAD/2-player-character/tile_set.png
--------------------------------------------------------------------------------
/3-movable-objects/tile_set.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasper-flick/godot-true-top-down-2d/HEAD/3-movable-objects/tile_set.png
--------------------------------------------------------------------------------
/4-light-and-shadow/tile_set.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasper-flick/godot-true-top-down-2d/HEAD/4-light-and-shadow/tile_set.png
--------------------------------------------------------------------------------
/7-map-transitions/tile_set.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasper-flick/godot-true-top-down-2d/HEAD/7-map-transitions/tile_set.png
--------------------------------------------------------------------------------
/8-saving-progress/tile_set.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasper-flick/godot-true-top-down-2d/HEAD/8-saving-progress/tile_set.png
--------------------------------------------------------------------------------
/11-showing-best-scores/tile_set.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasper-flick/godot-true-top-down-2d/HEAD/11-showing-best-scores/tile_set.png
--------------------------------------------------------------------------------
/12-teleporters/teleporters/teleporter_source.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasper-flick/godot-true-top-down-2d/HEAD/12-teleporters/teleporters/teleporter_source.png
--------------------------------------------------------------------------------
/12-teleporters/teleporters/teleporter_destination.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jasper-flick/godot-true-top-down-2d/HEAD/12-teleporters/teleporters/teleporter_destination.png
--------------------------------------------------------------------------------
/12-teleporters/teleporters/teleporter_line.gdshader:
--------------------------------------------------------------------------------
1 | shader_type canvas_item;
2 | render_mode unshaded;
3 |
4 | void fragment() {
5 | COLOR.a *= step(0.75, fract(UV.x * 0.25 - TIME * 0.5));
6 | }
7 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Godot 4+ specific ignores
2 | .godot/
3 |
4 | # Godot-specific ignores
5 | .import/
6 | export.cfg
7 | export_presets.cfg
8 |
9 | # Imported translations (automatically generated from CSV files)
10 | *.translation
11 |
12 | # Mono-specific ignores
13 | .mono/
14 | data_*/
15 | mono_crash.*.json
16 |
17 | .DS_Store
18 |
--------------------------------------------------------------------------------
/12-teleporters/interactive_object.gd:
--------------------------------------------------------------------------------
1 | class_name InteractiveObject
2 | extends CharacterBody2D
3 |
4 | @export var colission_shape: CollisionShape2D
5 |
6 |
7 | func get_current_rect() -> Rect2:
8 | var rect := colission_shape.shape.get_rect()
9 | rect.position += position
10 | return rect
11 |
12 |
13 | func displace(offset: Vector2) -> void:
14 | position += offset
15 |
--------------------------------------------------------------------------------
/2-player-character/player_character.gd:
--------------------------------------------------------------------------------
1 | extends CharacterBody2D
2 |
3 | ## Speed in pixels per second.
4 | @export_range(0, 1000) var speed := 60
5 |
6 |
7 | func _physics_process(_delta: float) -> void:
8 | get_player_input()
9 | move_and_slide()
10 |
11 |
12 | func get_player_input() -> void:
13 | var vector := Input.get_vector("ui_left", "ui_right", "ui_up", "ui_down")
14 | velocity = vector * speed
15 |
--------------------------------------------------------------------------------
/9-game-hud/main_menu.gd:
--------------------------------------------------------------------------------
1 | extends Control
2 |
3 | @export var first_map: PackedScene
4 | @export var continue_button: Button
5 |
6 |
7 | func _ready() -> void:
8 | if not Main.can_continue():
9 | continue_button.disabled = true
10 |
11 | func _on_new_game_button_pressed() -> void:
12 | Main.load_map(first_map.resource_path)
13 |
14 |
15 | func _on_continue_button_pressed() -> void:
16 | Main.load_continue_map()
17 |
--------------------------------------------------------------------------------
/12-teleporters/main_menu.gd:
--------------------------------------------------------------------------------
1 | extends Control
2 |
3 | @export var first_map: PackedScene
4 | @export var continue_button: Button
5 |
6 |
7 | func _ready() -> void:
8 | if not Main.can_continue():
9 | continue_button.disabled = true
10 |
11 | func _on_new_game_button_pressed() -> void:
12 | Main.load_map(first_map.resource_path)
13 |
14 |
15 | func _on_continue_button_pressed() -> void:
16 | Main.load_continue_map()
17 |
--------------------------------------------------------------------------------
/10-extra-map-info/main_menu.gd:
--------------------------------------------------------------------------------
1 | extends Control
2 |
3 | @export var first_map: PackedScene
4 | @export var continue_button: Button
5 |
6 |
7 | func _ready() -> void:
8 | if not Main.can_continue():
9 | continue_button.disabled = true
10 |
11 | func _on_new_game_button_pressed() -> void:
12 | Main.load_map(first_map.resource_path)
13 |
14 |
15 | func _on_continue_button_pressed() -> void:
16 | Main.load_continue_map()
17 |
--------------------------------------------------------------------------------
/8-saving-progress/main_menu.gd:
--------------------------------------------------------------------------------
1 | extends Control
2 |
3 | @export var first_map: PackedScene
4 | @export var continue_button: Button
5 |
6 |
7 | func _ready() -> void:
8 | if not Main.can_continue():
9 | continue_button.disabled = true
10 |
11 | func _on_new_game_button_pressed() -> void:
12 | Main.load_map(first_map.resource_path)
13 |
14 |
15 | func _on_continue_button_pressed() -> void:
16 | Main.load_continue_map()
17 |
--------------------------------------------------------------------------------
/11-showing-best-scores/main_menu.gd:
--------------------------------------------------------------------------------
1 | extends Control
2 |
3 | @export var first_map: PackedScene
4 | @export var continue_button: Button
5 |
6 |
7 | func _ready() -> void:
8 | if not Main.can_continue():
9 | continue_button.disabled = true
10 |
11 | func _on_new_game_button_pressed() -> void:
12 | Main.load_map(first_map.resource_path)
13 |
14 |
15 | func _on_continue_button_pressed() -> void:
16 | Main.load_continue_map()
17 |
--------------------------------------------------------------------------------
/12-teleporters/teleporters/teleporter_destination.gd:
--------------------------------------------------------------------------------
1 | class_name TeleporterDestination
2 | extends Area2D
3 |
4 | signal validity_changed(valid: bool)
5 |
6 | @export var sprite: Sprite2D
7 |
8 | @export var particles: GPUParticles2D
9 |
10 | var object_count := 0
11 |
12 |
13 | func _on_body_entered(_body: Node2D) -> void:
14 | if object_count == 0:
15 | validity_changed.emit(false)
16 | object_count += 1
17 |
18 |
19 | func _on_body_exited(_body: Node2D) -> void:
20 | object_count -= 1
21 | if object_count == 0:
22 | validity_changed.emit(true)
23 |
--------------------------------------------------------------------------------
/9-game-hud/map_transition.gd:
--------------------------------------------------------------------------------
1 | extends Node
2 |
3 | @export var animation_player : AnimationPlayer
4 |
5 | var root_window : Window
6 |
7 |
8 | func _ready() -> void:
9 | root_window = get_tree().root
10 | root_window.remove_child.call_deferred(self)
11 |
12 |
13 | func play_exit_map() -> void:
14 | root_window.add_child(self)
15 | animation_player.play("exit_map")
16 | await animation_player.animation_finished
17 |
18 |
19 | func play_enter_map() -> void:
20 | animation_player.play("enter_map")
21 | await animation_player.animation_finished
22 | root_window.remove_child(self)
23 |
--------------------------------------------------------------------------------
/10-extra-map-info/map_transition.gd:
--------------------------------------------------------------------------------
1 | extends Node
2 |
3 | @export var animation_player : AnimationPlayer
4 |
5 | var root_window : Window
6 |
7 |
8 | func _ready() -> void:
9 | root_window = get_tree().root
10 | root_window.remove_child.call_deferred(self)
11 |
12 |
13 | func play_exit_map() -> void:
14 | root_window.add_child(self)
15 | animation_player.play("exit_map")
16 | await animation_player.animation_finished
17 |
18 |
19 | func play_enter_map() -> void:
20 | animation_player.play("enter_map")
21 | await animation_player.animation_finished
22 | root_window.remove_child(self)
23 |
--------------------------------------------------------------------------------
/12-teleporters/map_transition.gd:
--------------------------------------------------------------------------------
1 | extends Node
2 |
3 | @export var animation_player : AnimationPlayer
4 |
5 | var root_window : Window
6 |
7 |
8 | func _ready() -> void:
9 | root_window = get_tree().root
10 | root_window.remove_child.call_deferred(self)
11 |
12 |
13 | func play_exit_map() -> void:
14 | root_window.add_child(self)
15 | animation_player.play("exit_map")
16 | await animation_player.animation_finished
17 |
18 |
19 | func play_enter_map() -> void:
20 | animation_player.play("enter_map")
21 | await animation_player.animation_finished
22 | root_window.remove_child(self)
23 |
--------------------------------------------------------------------------------
/7-map-transitions/map_transition.gd:
--------------------------------------------------------------------------------
1 | extends Node
2 |
3 | @export var animation_player : AnimationPlayer
4 |
5 | var root_window : Window
6 |
7 |
8 | func _ready() -> void:
9 | root_window = get_tree().root
10 | root_window.remove_child.call_deferred(self)
11 |
12 |
13 | func play_exit_map() -> void:
14 | root_window.add_child(self)
15 | animation_player.play("exit_map")
16 | await animation_player.animation_finished
17 |
18 |
19 | func play_enter_map() -> void:
20 | animation_player.play("enter_map")
21 | await animation_player.animation_finished
22 | root_window.remove_child(self)
23 |
--------------------------------------------------------------------------------
/8-saving-progress/map_transition.gd:
--------------------------------------------------------------------------------
1 | extends Node
2 |
3 | @export var animation_player : AnimationPlayer
4 |
5 | var root_window : Window
6 |
7 |
8 | func _ready() -> void:
9 | root_window = get_tree().root
10 | root_window.remove_child.call_deferred(self)
11 |
12 |
13 | func play_exit_map() -> void:
14 | root_window.add_child(self)
15 | animation_player.play("exit_map")
16 | await animation_player.animation_finished
17 |
18 |
19 | func play_enter_map() -> void:
20 | animation_player.play("enter_map")
21 | await animation_player.animation_finished
22 | root_window.remove_child(self)
23 |
--------------------------------------------------------------------------------
/11-showing-best-scores/map_transition.gd:
--------------------------------------------------------------------------------
1 | extends Node
2 |
3 | @export var animation_player : AnimationPlayer
4 |
5 | var root_window : Window
6 |
7 |
8 | func _ready() -> void:
9 | root_window = get_tree().root
10 | root_window.remove_child.call_deferred(self)
11 |
12 |
13 | func play_exit_map() -> void:
14 | root_window.add_child(self)
15 | animation_player.play("exit_map")
16 | await animation_player.animation_finished
17 |
18 |
19 | func play_enter_map() -> void:
20 | animation_player.play("enter_map")
21 | await animation_player.animation_finished
22 | root_window.remove_child(self)
23 |
--------------------------------------------------------------------------------
/7-map-transitions/map.gd:
--------------------------------------------------------------------------------
1 | extends Node
2 |
3 | var registered_detector_count := 0
4 | var valid_detector_count := 0
5 |
6 |
7 | func _ready() -> void:
8 | for child_node in get_children():
9 | var detector := child_node as Detector
10 | if detector:
11 | registered_detector_count += 1
12 | detector.validity_changed.connect(_on_detector_validity_changed)
13 |
14 |
15 | func _on_detector_validity_changed(valid: bool) -> void:
16 | if valid:
17 | valid_detector_count += 1
18 | if valid_detector_count == registered_detector_count:
19 | Main.load_next_map()
20 | else:
21 | valid_detector_count -= 1
22 |
--------------------------------------------------------------------------------
/8-saving-progress/map.gd:
--------------------------------------------------------------------------------
1 | extends Node
2 |
3 | var registered_detector_count := 0
4 | var valid_detector_count := 0
5 |
6 |
7 | func _ready() -> void:
8 | for child_node in get_children():
9 | var detector := child_node as Detector
10 | if detector:
11 | registered_detector_count += 1
12 | detector.validity_changed.connect(_on_detector_validity_changed)
13 |
14 | Main.map_loaded(scene_file_path)
15 |
16 |
17 | func _on_detector_validity_changed(valid: bool) -> void:
18 | if valid:
19 | valid_detector_count += 1
20 | if valid_detector_count == registered_detector_count:
21 | Main.load_next_map()
22 | else:
23 | valid_detector_count -= 1
24 |
--------------------------------------------------------------------------------
/5-detectors/player_character.gd:
--------------------------------------------------------------------------------
1 | extends CharacterBody2D
2 |
3 | ## Speed in pixels per second.
4 | @export_range(0, 1000) var speed := 60
5 |
6 |
7 | func _physics_process(_delta: float) -> void:
8 | get_player_input()
9 | if move_and_slide():
10 | resolve_collisions()
11 |
12 |
13 | func resolve_collisions() -> void:
14 | for i in get_slide_collision_count():
15 | var collision := get_slide_collision(i)
16 | var body := collision.get_collider() as MovableObject
17 | if body:
18 | body.apply_impact(velocity)
19 |
20 |
21 | func get_player_input() -> void:
22 | var vector := Input.get_vector("ui_left", "ui_right", "ui_up", "ui_down")
23 | velocity = vector * speed
24 |
--------------------------------------------------------------------------------
/9-game-hud/player_character.gd:
--------------------------------------------------------------------------------
1 | extends CharacterBody2D
2 |
3 | ## Speed in pixels per second.
4 | @export_range(0, 1000) var speed := 60
5 |
6 |
7 | func _physics_process(_delta: float) -> void:
8 | get_player_input()
9 | if move_and_slide():
10 | resolve_collisions()
11 |
12 |
13 | func resolve_collisions() -> void:
14 | for i in get_slide_collision_count():
15 | var collision := get_slide_collision(i)
16 | var body := collision.get_collider() as MovableObject
17 | if body:
18 | body.apply_impact(velocity)
19 |
20 |
21 | func get_player_input() -> void:
22 | var vector := Input.get_vector("ui_left", "ui_right", "ui_up", "ui_down")
23 | velocity = vector * speed
24 |
--------------------------------------------------------------------------------
/6-multiple-maps/player_character.gd:
--------------------------------------------------------------------------------
1 | extends CharacterBody2D
2 |
3 | ## Speed in pixels per second.
4 | @export_range(0, 1000) var speed := 60
5 |
6 |
7 | func _physics_process(_delta: float) -> void:
8 | get_player_input()
9 | if move_and_slide():
10 | resolve_collisions()
11 |
12 |
13 | func resolve_collisions() -> void:
14 | for i in get_slide_collision_count():
15 | var collision := get_slide_collision(i)
16 | var body := collision.get_collider() as MovableObject
17 | if body:
18 | body.apply_impact(velocity)
19 |
20 |
21 | func get_player_input() -> void:
22 | var vector := Input.get_vector("ui_left", "ui_right", "ui_up", "ui_down")
23 | velocity = vector * speed
24 |
--------------------------------------------------------------------------------
/3-movable-objects/player_character.gd:
--------------------------------------------------------------------------------
1 | extends CharacterBody2D
2 |
3 | ## Speed in pixels per second.
4 | @export_range(0, 1000) var speed := 60
5 |
6 |
7 | func _physics_process(_delta: float) -> void:
8 | get_player_input()
9 | if move_and_slide():
10 | resolve_collisions()
11 |
12 |
13 | func resolve_collisions() -> void:
14 | for i in get_slide_collision_count():
15 | var collision := get_slide_collision(i)
16 | var body := collision.get_collider() as MovableObject
17 | if body:
18 | body.apply_impact(velocity)
19 |
20 |
21 | func get_player_input() -> void:
22 | var vector := Input.get_vector("ui_left", "ui_right", "ui_up", "ui_down")
23 | velocity = vector * speed
24 |
--------------------------------------------------------------------------------
/4-light-and-shadow/player_character.gd:
--------------------------------------------------------------------------------
1 | extends CharacterBody2D
2 |
3 | ## Speed in pixels per second.
4 | @export_range(0, 1000) var speed := 60
5 |
6 |
7 | func _physics_process(_delta: float) -> void:
8 | get_player_input()
9 | if move_and_slide():
10 | resolve_collisions()
11 |
12 |
13 | func resolve_collisions() -> void:
14 | for i in get_slide_collision_count():
15 | var collision := get_slide_collision(i)
16 | var body := collision.get_collider() as MovableObject
17 | if body:
18 | body.apply_impact(velocity)
19 |
20 |
21 | func get_player_input() -> void:
22 | var vector := Input.get_vector("ui_left", "ui_right", "ui_up", "ui_down")
23 | velocity = vector * speed
24 |
--------------------------------------------------------------------------------
/7-map-transitions/player_character.gd:
--------------------------------------------------------------------------------
1 | extends CharacterBody2D
2 |
3 | ## Speed in pixels per second.
4 | @export_range(0, 1000) var speed := 60
5 |
6 |
7 | func _physics_process(_delta: float) -> void:
8 | get_player_input()
9 | if move_and_slide():
10 | resolve_collisions()
11 |
12 |
13 | func resolve_collisions() -> void:
14 | for i in get_slide_collision_count():
15 | var collision := get_slide_collision(i)
16 | var body := collision.get_collider() as MovableObject
17 | if body:
18 | body.apply_impact(velocity)
19 |
20 |
21 | func get_player_input() -> void:
22 | var vector := Input.get_vector("ui_left", "ui_right", "ui_up", "ui_down")
23 | velocity = vector * speed
24 |
--------------------------------------------------------------------------------
/8-saving-progress/player_character.gd:
--------------------------------------------------------------------------------
1 | extends CharacterBody2D
2 |
3 | ## Speed in pixels per second.
4 | @export_range(0, 1000) var speed := 60
5 |
6 |
7 | func _physics_process(_delta: float) -> void:
8 | get_player_input()
9 | if move_and_slide():
10 | resolve_collisions()
11 |
12 |
13 | func resolve_collisions() -> void:
14 | for i in get_slide_collision_count():
15 | var collision := get_slide_collision(i)
16 | var body := collision.get_collider() as MovableObject
17 | if body:
18 | body.apply_impact(velocity)
19 |
20 |
21 | func get_player_input() -> void:
22 | var vector := Input.get_vector("ui_left", "ui_right", "ui_up", "ui_down")
23 | velocity = vector * speed
24 |
--------------------------------------------------------------------------------
/1-tile-map/project.godot:
--------------------------------------------------------------------------------
1 | ; Engine configuration file.
2 | ; It's best edited using the editor UI and not directly,
3 | ; since the parameters that go here are not all obvious.
4 | ;
5 | ; Format:
6 | ; [section] ; section goes between []
7 | ; param=value ; assign values to parameters
8 |
9 | config_version=5
10 |
11 | [application]
12 |
13 | config/name="True Top-Down 2D"
14 | config/features=PackedStringArray("4.3", "Forward Plus")
15 | config/icon="res://icon.svg"
16 |
17 | [display]
18 |
19 | window/size/viewport_width=400
20 | window/size/viewport_height=240
21 | window/size/mode=4
22 | window/stretch/mode="viewport"
23 | window/stretch/scale_mode="integer"
24 |
25 | [filesystem]
26 |
27 | import/blender/enabled=false
28 |
--------------------------------------------------------------------------------
/9-game-hud/hud.gd:
--------------------------------------------------------------------------------
1 | extends CanvasLayer
2 |
3 | @export var map_name_label: Label
4 | @export var map_time_label: Label
5 | @export var new_best_map_time_label: Label
6 |
7 |
8 | func _ready() -> void:
9 | visible = false
10 | new_best_map_time_label.visible = false
11 |
12 |
13 | func show_map_info(map: GameMap) -> void:
14 | map_name_label.text = map.map_name
15 | show_map_time(0.0)
16 | visible = true
17 | new_best_map_time_label.visible = false
18 |
19 |
20 | func show_map_time(time: float) -> void:
21 | map_time_label.text = "%ds" % time
22 |
23 |
24 | func show_new_best_map_time(new_time: int) -> void:
25 | new_best_map_time_label.text = "New best time: %ds" % new_time
26 | new_best_map_time_label.visible = true
27 |
--------------------------------------------------------------------------------
/2-player-character/project.godot:
--------------------------------------------------------------------------------
1 | ; Engine configuration file.
2 | ; It's best edited using the editor UI and not directly,
3 | ; since the parameters that go here are not all obvious.
4 | ;
5 | ; Format:
6 | ; [section] ; section goes between []
7 | ; param=value ; assign values to parameters
8 |
9 | config_version=5
10 |
11 | [application]
12 |
13 | config/name="True Top-Down 2D"
14 | config/version="2.0"
15 | run/main_scene="res://map.tscn"
16 | config/features=PackedStringArray("4.3", "Forward Plus")
17 | config/icon="res://icon.svg"
18 |
19 | [display]
20 |
21 | window/size/viewport_width=400
22 | window/size/viewport_height=240
23 | window/size/mode=4
24 | window/stretch/mode="viewport"
25 | window/stretch/scale_mode="integer"
26 |
27 | [filesystem]
28 |
29 | import/blender/enabled=false
30 |
--------------------------------------------------------------------------------
/7-map-transitions/main.gd:
--------------------------------------------------------------------------------
1 | extends Node
2 |
3 |
4 | func load_next_map() -> void:
5 | var current_map_path := get_tree().current_scene.scene_file_path
6 | var split_path := current_map_path.split(".")
7 | var next_map_number := split_path[1].to_int() + 1
8 | split_path[1] = str(next_map_number).pad_zeros(3)
9 | var next_map_path = ".".join(split_path)
10 |
11 | if not ResourceLoader.exists(next_map_path):
12 | split_path[1] = "001"
13 | next_map_path = ".".join(split_path)
14 |
15 | ResourceLoader.load_threaded_request(next_map_path)
16 |
17 | get_tree().paused = true
18 | await MapTransition.play_exit_map()
19 |
20 | get_tree().change_scene_to_packed(
21 | ResourceLoader.load_threaded_get(next_map_path)
22 | )
23 |
24 | await MapTransition.play_enter_map()
25 | get_tree().paused = false
26 |
--------------------------------------------------------------------------------
/1-tile-map/tile_set.tres:
--------------------------------------------------------------------------------
1 | [gd_resource type="TileSet" load_steps=3 format=3 uid="uid://ct1sg2j0vfyxf"]
2 |
3 | [ext_resource type="Texture2D" uid="uid://brq3awcnk4gep" path="res://tile_set.png" id="1_yp80t"]
4 |
5 | [sub_resource type="TileSetAtlasSource" id="TileSetAtlasSource_6asb7"]
6 | texture = ExtResource("1_yp80t")
7 | 0:0/animation_columns = 2
8 | 0:0/0 = 0
9 | 1:0/0 = 0
10 | 2:0/0 = 0
11 | 0:1/0 = 0
12 | 1:1/0 = 0
13 | 2:1/0 = 0
14 | 0:2/0 = 0
15 | 1:2/0 = 0
16 | 2:2/0 = 0
17 | 0:3/0 = 0
18 | 1:3/0 = 0
19 | 2:3/0 = 0
20 | 0:4/0 = 0
21 | 1:4/0 = 0
22 | 2:4/0 = 0
23 | 0:5/animation_mode = 1
24 | 0:5/animation_frame_0/duration = 1.0
25 | 0:5/animation_frame_1/duration = 1.0
26 | 0:5/0 = 0
27 | 0:6/animation_mode = 1
28 | 0:6/animation_frame_0/duration = 1.0
29 | 0:6/animation_frame_1/duration = 1.0
30 | 0:6/0 = 0
31 |
32 | [resource]
33 | sources/0 = SubResource("TileSetAtlasSource_6asb7")
34 |
--------------------------------------------------------------------------------
/5-detectors/project.godot:
--------------------------------------------------------------------------------
1 | ; Engine configuration file.
2 | ; It's best edited using the editor UI and not directly,
3 | ; since the parameters that go here are not all obvious.
4 | ;
5 | ; Format:
6 | ; [section] ; section goes between []
7 | ; param=value ; assign values to parameters
8 |
9 | config_version=5
10 |
11 | [application]
12 |
13 | config/name="True Top-Down 2D"
14 | config/version="5.0"
15 | run/main_scene="res://map.tscn"
16 | config/features=PackedStringArray("4.3", "Forward Plus")
17 | config/icon="res://icon.svg"
18 |
19 | [display]
20 |
21 | window/size/viewport_width=400
22 | window/size/viewport_height=240
23 | window/size/mode=4
24 | window/stretch/mode="viewport"
25 | window/stretch/scale_mode="integer"
26 | window/snap/snap_2d_transforms_to_pixel=false
27 |
28 | [filesystem]
29 |
30 | import/blender/enabled=false
31 |
32 | [physics]
33 |
34 | 2d/default_gravity=0.0
35 |
--------------------------------------------------------------------------------
/3-movable-objects/project.godot:
--------------------------------------------------------------------------------
1 | ; Engine configuration file.
2 | ; It's best edited using the editor UI and not directly,
3 | ; since the parameters that go here are not all obvious.
4 | ;
5 | ; Format:
6 | ; [section] ; section goes between []
7 | ; param=value ; assign values to parameters
8 |
9 | config_version=5
10 |
11 | [application]
12 |
13 | config/name="True Top-Down 2D"
14 | config/version="3.0"
15 | run/main_scene="res://map.tscn"
16 | config/features=PackedStringArray("4.3", "Forward Plus")
17 | config/icon="res://icon.svg"
18 |
19 | [display]
20 |
21 | window/size/viewport_width=400
22 | window/size/viewport_height=240
23 | window/size/mode=4
24 | window/stretch/mode="viewport"
25 | window/stretch/scale_mode="integer"
26 | window/snap/snap_2d_transforms_to_pixel=false
27 |
28 | [filesystem]
29 |
30 | import/blender/enabled=false
31 |
32 | [physics]
33 |
34 | 2d/default_gravity=0.0
35 |
--------------------------------------------------------------------------------
/4-light-and-shadow/project.godot:
--------------------------------------------------------------------------------
1 | ; Engine configuration file.
2 | ; It's best edited using the editor UI and not directly,
3 | ; since the parameters that go here are not all obvious.
4 | ;
5 | ; Format:
6 | ; [section] ; section goes between []
7 | ; param=value ; assign values to parameters
8 |
9 | config_version=5
10 |
11 | [application]
12 |
13 | config/name="True Top-Down 2D"
14 | config/version="4.0"
15 | run/main_scene="res://map.tscn"
16 | config/features=PackedStringArray("4.3", "Forward Plus")
17 | config/icon="res://icon.svg"
18 |
19 | [display]
20 |
21 | window/size/viewport_width=400
22 | window/size/viewport_height=240
23 | window/size/mode=4
24 | window/stretch/mode="viewport"
25 | window/stretch/scale_mode="integer"
26 | window/snap/snap_2d_transforms_to_pixel=false
27 |
28 | [filesystem]
29 |
30 | import/blender/enabled=false
31 |
32 | [physics]
33 |
34 | 2d/default_gravity=0.0
35 |
--------------------------------------------------------------------------------
/6-multiple-maps/project.godot:
--------------------------------------------------------------------------------
1 | ; Engine configuration file.
2 | ; It's best edited using the editor UI and not directly,
3 | ; since the parameters that go here are not all obvious.
4 | ;
5 | ; Format:
6 | ; [section] ; section goes between []
7 | ; param=value ; assign values to parameters
8 |
9 | config_version=5
10 |
11 | [application]
12 |
13 | config/name="True Top-Down 2D"
14 | config/version="6.0"
15 | run/main_scene="res://maps/map.001.tscn"
16 | config/features=PackedStringArray("4.3", "Forward Plus")
17 | config/icon="res://icon.svg"
18 |
19 | [display]
20 |
21 | window/size/viewport_width=400
22 | window/size/viewport_height=240
23 | window/size/mode=4
24 | window/stretch/mode="viewport"
25 | window/stretch/scale_mode="integer"
26 | window/snap/snap_2d_transforms_to_pixel=false
27 |
28 | [filesystem]
29 |
30 | import/blender/enabled=false
31 |
32 | [physics]
33 |
34 | 2d/default_gravity=0.0
35 |
--------------------------------------------------------------------------------
/1-tile-map/tile_set.png.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="CompressedTexture2D"
5 | uid="uid://brq3awcnk4gep"
6 | path="res://.godot/imported/tile_set.png-0c317f5c3892f579c700f587287d3095.ctex"
7 | metadata={
8 | "vram_texture": false
9 | }
10 |
11 | [deps]
12 |
13 | source_file="res://tile_set.png"
14 | dest_files=["res://.godot/imported/tile_set.png-0c317f5c3892f579c700f587287d3095.ctex"]
15 |
16 | [params]
17 |
18 | compress/mode=0
19 | compress/high_quality=false
20 | compress/lossy_quality=0.7
21 | compress/hdr_compression=1
22 | compress/normal_map=0
23 | compress/channel_pack=0
24 | mipmaps/generate=false
25 | mipmaps/limit=-1
26 | roughness/mode=0
27 | roughness/src_normal=""
28 | process/fix_alpha_border=true
29 | process/premult_alpha=false
30 | process/normal_map_invert_y=false
31 | process/hdr_as_srgb=false
32 | process/hdr_clamp_exposure=false
33 | process/size_limit=0
34 | detect_3d/compress_to=1
35 |
--------------------------------------------------------------------------------
/12-teleporters/tile_set.png.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="CompressedTexture2D"
5 | uid="uid://brq3awcnk4gep"
6 | path="res://.godot/imported/tile_set.png-0c317f5c3892f579c700f587287d3095.ctex"
7 | metadata={
8 | "vram_texture": false
9 | }
10 |
11 | [deps]
12 |
13 | source_file="res://tile_set.png"
14 | dest_files=["res://.godot/imported/tile_set.png-0c317f5c3892f579c700f587287d3095.ctex"]
15 |
16 | [params]
17 |
18 | compress/mode=0
19 | compress/high_quality=false
20 | compress/lossy_quality=0.7
21 | compress/hdr_compression=1
22 | compress/normal_map=0
23 | compress/channel_pack=0
24 | mipmaps/generate=false
25 | mipmaps/limit=-1
26 | roughness/mode=0
27 | roughness/src_normal=""
28 | process/fix_alpha_border=true
29 | process/premult_alpha=false
30 | process/normal_map_invert_y=false
31 | process/hdr_as_srgb=false
32 | process/hdr_clamp_exposure=false
33 | process/size_limit=0
34 | detect_3d/compress_to=1
35 |
--------------------------------------------------------------------------------
/5-detectors/tile_set.png.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="CompressedTexture2D"
5 | uid="uid://brq3awcnk4gep"
6 | path="res://.godot/imported/tile_set.png-0c317f5c3892f579c700f587287d3095.ctex"
7 | metadata={
8 | "vram_texture": false
9 | }
10 |
11 | [deps]
12 |
13 | source_file="res://tile_set.png"
14 | dest_files=["res://.godot/imported/tile_set.png-0c317f5c3892f579c700f587287d3095.ctex"]
15 |
16 | [params]
17 |
18 | compress/mode=0
19 | compress/high_quality=false
20 | compress/lossy_quality=0.7
21 | compress/hdr_compression=1
22 | compress/normal_map=0
23 | compress/channel_pack=0
24 | mipmaps/generate=false
25 | mipmaps/limit=-1
26 | roughness/mode=0
27 | roughness/src_normal=""
28 | process/fix_alpha_border=true
29 | process/premult_alpha=false
30 | process/normal_map_invert_y=false
31 | process/hdr_as_srgb=false
32 | process/hdr_clamp_exposure=false
33 | process/size_limit=0
34 | detect_3d/compress_to=1
35 |
--------------------------------------------------------------------------------
/9-game-hud/tile_set.png.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="CompressedTexture2D"
5 | uid="uid://brq3awcnk4gep"
6 | path="res://.godot/imported/tile_set.png-0c317f5c3892f579c700f587287d3095.ctex"
7 | metadata={
8 | "vram_texture": false
9 | }
10 |
11 | [deps]
12 |
13 | source_file="res://tile_set.png"
14 | dest_files=["res://.godot/imported/tile_set.png-0c317f5c3892f579c700f587287d3095.ctex"]
15 |
16 | [params]
17 |
18 | compress/mode=0
19 | compress/high_quality=false
20 | compress/lossy_quality=0.7
21 | compress/hdr_compression=1
22 | compress/normal_map=0
23 | compress/channel_pack=0
24 | mipmaps/generate=false
25 | mipmaps/limit=-1
26 | roughness/mode=0
27 | roughness/src_normal=""
28 | process/fix_alpha_border=true
29 | process/premult_alpha=false
30 | process/normal_map_invert_y=false
31 | process/hdr_as_srgb=false
32 | process/hdr_clamp_exposure=false
33 | process/size_limit=0
34 | detect_3d/compress_to=1
35 |
--------------------------------------------------------------------------------
/10-extra-map-info/tile_set.png.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="CompressedTexture2D"
5 | uid="uid://brq3awcnk4gep"
6 | path="res://.godot/imported/tile_set.png-0c317f5c3892f579c700f587287d3095.ctex"
7 | metadata={
8 | "vram_texture": false
9 | }
10 |
11 | [deps]
12 |
13 | source_file="res://tile_set.png"
14 | dest_files=["res://.godot/imported/tile_set.png-0c317f5c3892f579c700f587287d3095.ctex"]
15 |
16 | [params]
17 |
18 | compress/mode=0
19 | compress/high_quality=false
20 | compress/lossy_quality=0.7
21 | compress/hdr_compression=1
22 | compress/normal_map=0
23 | compress/channel_pack=0
24 | mipmaps/generate=false
25 | mipmaps/limit=-1
26 | roughness/mode=0
27 | roughness/src_normal=""
28 | process/fix_alpha_border=true
29 | process/premult_alpha=false
30 | process/normal_map_invert_y=false
31 | process/hdr_as_srgb=false
32 | process/hdr_clamp_exposure=false
33 | process/size_limit=0
34 | detect_3d/compress_to=1
35 |
--------------------------------------------------------------------------------
/2-player-character/tile_set.png.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="CompressedTexture2D"
5 | uid="uid://brq3awcnk4gep"
6 | path="res://.godot/imported/tile_set.png-0c317f5c3892f579c700f587287d3095.ctex"
7 | metadata={
8 | "vram_texture": false
9 | }
10 |
11 | [deps]
12 |
13 | source_file="res://tile_set.png"
14 | dest_files=["res://.godot/imported/tile_set.png-0c317f5c3892f579c700f587287d3095.ctex"]
15 |
16 | [params]
17 |
18 | compress/mode=0
19 | compress/high_quality=false
20 | compress/lossy_quality=0.7
21 | compress/hdr_compression=1
22 | compress/normal_map=0
23 | compress/channel_pack=0
24 | mipmaps/generate=false
25 | mipmaps/limit=-1
26 | roughness/mode=0
27 | roughness/src_normal=""
28 | process/fix_alpha_border=true
29 | process/premult_alpha=false
30 | process/normal_map_invert_y=false
31 | process/hdr_as_srgb=false
32 | process/hdr_clamp_exposure=false
33 | process/size_limit=0
34 | detect_3d/compress_to=1
35 |
--------------------------------------------------------------------------------
/3-movable-objects/tile_set.png.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="CompressedTexture2D"
5 | uid="uid://brq3awcnk4gep"
6 | path="res://.godot/imported/tile_set.png-0c317f5c3892f579c700f587287d3095.ctex"
7 | metadata={
8 | "vram_texture": false
9 | }
10 |
11 | [deps]
12 |
13 | source_file="res://tile_set.png"
14 | dest_files=["res://.godot/imported/tile_set.png-0c317f5c3892f579c700f587287d3095.ctex"]
15 |
16 | [params]
17 |
18 | compress/mode=0
19 | compress/high_quality=false
20 | compress/lossy_quality=0.7
21 | compress/hdr_compression=1
22 | compress/normal_map=0
23 | compress/channel_pack=0
24 | mipmaps/generate=false
25 | mipmaps/limit=-1
26 | roughness/mode=0
27 | roughness/src_normal=""
28 | process/fix_alpha_border=true
29 | process/premult_alpha=false
30 | process/normal_map_invert_y=false
31 | process/hdr_as_srgb=false
32 | process/hdr_clamp_exposure=false
33 | process/size_limit=0
34 | detect_3d/compress_to=1
35 |
--------------------------------------------------------------------------------
/4-light-and-shadow/tile_set.png.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="CompressedTexture2D"
5 | uid="uid://brq3awcnk4gep"
6 | path="res://.godot/imported/tile_set.png-0c317f5c3892f579c700f587287d3095.ctex"
7 | metadata={
8 | "vram_texture": false
9 | }
10 |
11 | [deps]
12 |
13 | source_file="res://tile_set.png"
14 | dest_files=["res://.godot/imported/tile_set.png-0c317f5c3892f579c700f587287d3095.ctex"]
15 |
16 | [params]
17 |
18 | compress/mode=0
19 | compress/high_quality=false
20 | compress/lossy_quality=0.7
21 | compress/hdr_compression=1
22 | compress/normal_map=0
23 | compress/channel_pack=0
24 | mipmaps/generate=false
25 | mipmaps/limit=-1
26 | roughness/mode=0
27 | roughness/src_normal=""
28 | process/fix_alpha_border=true
29 | process/premult_alpha=false
30 | process/normal_map_invert_y=false
31 | process/hdr_as_srgb=false
32 | process/hdr_clamp_exposure=false
33 | process/size_limit=0
34 | detect_3d/compress_to=1
35 |
--------------------------------------------------------------------------------
/6-multiple-maps/tile_set.png.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="CompressedTexture2D"
5 | uid="uid://brq3awcnk4gep"
6 | path="res://.godot/imported/tile_set.png-0c317f5c3892f579c700f587287d3095.ctex"
7 | metadata={
8 | "vram_texture": false
9 | }
10 |
11 | [deps]
12 |
13 | source_file="res://tile_set.png"
14 | dest_files=["res://.godot/imported/tile_set.png-0c317f5c3892f579c700f587287d3095.ctex"]
15 |
16 | [params]
17 |
18 | compress/mode=0
19 | compress/high_quality=false
20 | compress/lossy_quality=0.7
21 | compress/hdr_compression=1
22 | compress/normal_map=0
23 | compress/channel_pack=0
24 | mipmaps/generate=false
25 | mipmaps/limit=-1
26 | roughness/mode=0
27 | roughness/src_normal=""
28 | process/fix_alpha_border=true
29 | process/premult_alpha=false
30 | process/normal_map_invert_y=false
31 | process/hdr_as_srgb=false
32 | process/hdr_clamp_exposure=false
33 | process/size_limit=0
34 | detect_3d/compress_to=1
35 |
--------------------------------------------------------------------------------
/7-map-transitions/tile_set.png.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="CompressedTexture2D"
5 | uid="uid://brq3awcnk4gep"
6 | path="res://.godot/imported/tile_set.png-0c317f5c3892f579c700f587287d3095.ctex"
7 | metadata={
8 | "vram_texture": false
9 | }
10 |
11 | [deps]
12 |
13 | source_file="res://tile_set.png"
14 | dest_files=["res://.godot/imported/tile_set.png-0c317f5c3892f579c700f587287d3095.ctex"]
15 |
16 | [params]
17 |
18 | compress/mode=0
19 | compress/high_quality=false
20 | compress/lossy_quality=0.7
21 | compress/hdr_compression=1
22 | compress/normal_map=0
23 | compress/channel_pack=0
24 | mipmaps/generate=false
25 | mipmaps/limit=-1
26 | roughness/mode=0
27 | roughness/src_normal=""
28 | process/fix_alpha_border=true
29 | process/premult_alpha=false
30 | process/normal_map_invert_y=false
31 | process/hdr_as_srgb=false
32 | process/hdr_clamp_exposure=false
33 | process/size_limit=0
34 | detect_3d/compress_to=1
35 |
--------------------------------------------------------------------------------
/8-saving-progress/tile_set.png.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="CompressedTexture2D"
5 | uid="uid://brq3awcnk4gep"
6 | path="res://.godot/imported/tile_set.png-0c317f5c3892f579c700f587287d3095.ctex"
7 | metadata={
8 | "vram_texture": false
9 | }
10 |
11 | [deps]
12 |
13 | source_file="res://tile_set.png"
14 | dest_files=["res://.godot/imported/tile_set.png-0c317f5c3892f579c700f587287d3095.ctex"]
15 |
16 | [params]
17 |
18 | compress/mode=0
19 | compress/high_quality=false
20 | compress/lossy_quality=0.7
21 | compress/hdr_compression=1
22 | compress/normal_map=0
23 | compress/channel_pack=0
24 | mipmaps/generate=false
25 | mipmaps/limit=-1
26 | roughness/mode=0
27 | roughness/src_normal=""
28 | process/fix_alpha_border=true
29 | process/premult_alpha=false
30 | process/normal_map_invert_y=false
31 | process/hdr_as_srgb=false
32 | process/hdr_clamp_exposure=false
33 | process/size_limit=0
34 | detect_3d/compress_to=1
35 |
--------------------------------------------------------------------------------
/9-game-hud/lively_light.gd:
--------------------------------------------------------------------------------
1 | extends Node2D
2 |
3 | ## Maximum jitter offset per dimension, in pixels.
4 | @export var jitter_offset := 0.25
5 | ## How fast the light changes, in jitters per second.
6 | @export var jitter_speed := 6.0
7 | ## Minimum light energy level caused by jittering.
8 | @export_range(0.0, 1.0) var jitter_min_energy := 0.95
9 |
10 | @export var light_a: PointLight2D
11 | @export var light_b: PointLight2D
12 |
13 | var progress := 0.0
14 |
15 |
16 | func _process(delta: float) -> void:
17 | progress += delta * jitter_speed
18 | if progress >= 1.0:
19 | progress -= 1.0
20 | jitter()
21 |
22 |
23 | func jitter() -> void:
24 | var p := Vector2(
25 | randf_range(-jitter_offset, jitter_offset),
26 | randf_range(-jitter_offset, jitter_offset)
27 | )
28 | light_a.position = p
29 | light_b.position = p
30 |
31 | var e := randf_range(jitter_min_energy, 1.0)
32 | light_a.energy = e
33 | light_b.energy = e
34 |
--------------------------------------------------------------------------------
/1-tile-map/icon.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/11-showing-best-scores/tile_set.png.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="CompressedTexture2D"
5 | uid="uid://brq3awcnk4gep"
6 | path="res://.godot/imported/tile_set.png-0c317f5c3892f579c700f587287d3095.ctex"
7 | metadata={
8 | "vram_texture": false
9 | }
10 |
11 | [deps]
12 |
13 | source_file="res://tile_set.png"
14 | dest_files=["res://.godot/imported/tile_set.png-0c317f5c3892f579c700f587287d3095.ctex"]
15 |
16 | [params]
17 |
18 | compress/mode=0
19 | compress/high_quality=false
20 | compress/lossy_quality=0.7
21 | compress/hdr_compression=1
22 | compress/normal_map=0
23 | compress/channel_pack=0
24 | mipmaps/generate=false
25 | mipmaps/limit=-1
26 | roughness/mode=0
27 | roughness/src_normal=""
28 | process/fix_alpha_border=true
29 | process/premult_alpha=false
30 | process/normal_map_invert_y=false
31 | process/hdr_as_srgb=false
32 | process/hdr_clamp_exposure=false
33 | process/size_limit=0
34 | detect_3d/compress_to=1
35 |
--------------------------------------------------------------------------------
/12-teleporters/lively_light.gd:
--------------------------------------------------------------------------------
1 | extends Node2D
2 |
3 | ## Maximum jitter offset per dimension, in pixels.
4 | @export var jitter_offset := 0.25
5 | ## How fast the light changes, in jitters per second.
6 | @export var jitter_speed := 6.0
7 | ## Minimum light energy level caused by jittering.
8 | @export_range(0.0, 1.0) var jitter_min_energy := 0.95
9 |
10 | @export var light_a: PointLight2D
11 | @export var light_b: PointLight2D
12 |
13 | var progress := 0.0
14 |
15 |
16 | func _process(delta: float) -> void:
17 | progress += delta * jitter_speed
18 | if progress >= 1.0:
19 | progress -= 1.0
20 | jitter()
21 |
22 |
23 | func jitter() -> void:
24 | var p := Vector2(
25 | randf_range(-jitter_offset, jitter_offset),
26 | randf_range(-jitter_offset, jitter_offset)
27 | )
28 | light_a.position = p
29 | light_b.position = p
30 |
31 | var e := randf_range(jitter_min_energy, 1.0)
32 | light_a.energy = e
33 | light_b.energy = e
34 |
--------------------------------------------------------------------------------
/5-detectors/icon.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/5-detectors/lively_light.gd:
--------------------------------------------------------------------------------
1 | extends Node2D
2 |
3 | ## Maximum jitter offset per dimension, in pixels.
4 | @export var jitter_offset := 0.25
5 | ## How fast the light changes, in jitters per second.
6 | @export var jitter_speed := 6.0
7 | ## Minimum light energy level caused by jittering.
8 | @export_range(0.0, 1.0) var jitter_min_energy := 0.95
9 |
10 | @export var light_a: PointLight2D
11 | @export var light_b: PointLight2D
12 |
13 | var progress := 0.0
14 |
15 |
16 | func _process(delta: float) -> void:
17 | progress += delta * jitter_speed
18 | if progress >= 1.0:
19 | progress -= 1.0
20 | jitter()
21 |
22 |
23 | func jitter() -> void:
24 | var p := Vector2(
25 | randf_range(-jitter_offset, jitter_offset),
26 | randf_range(-jitter_offset, jitter_offset)
27 | )
28 | light_a.position = p
29 | light_b.position = p
30 |
31 | var e := randf_range(jitter_min_energy, 1.0)
32 | light_a.energy = e
33 | light_b.energy = e
34 |
--------------------------------------------------------------------------------
/6-multiple-maps/lively_light.gd:
--------------------------------------------------------------------------------
1 | extends Node2D
2 |
3 | ## Maximum jitter offset per dimension, in pixels.
4 | @export var jitter_offset := 0.25
5 | ## How fast the light changes, in jitters per second.
6 | @export var jitter_speed := 6.0
7 | ## Minimum light energy level caused by jittering.
8 | @export_range(0.0, 1.0) var jitter_min_energy := 0.95
9 |
10 | @export var light_a: PointLight2D
11 | @export var light_b: PointLight2D
12 |
13 | var progress := 0.0
14 |
15 |
16 | func _process(delta: float) -> void:
17 | progress += delta * jitter_speed
18 | if progress >= 1.0:
19 | progress -= 1.0
20 | jitter()
21 |
22 |
23 | func jitter() -> void:
24 | var p := Vector2(
25 | randf_range(-jitter_offset, jitter_offset),
26 | randf_range(-jitter_offset, jitter_offset)
27 | )
28 | light_a.position = p
29 | light_b.position = p
30 |
31 | var e := randf_range(jitter_min_energy, 1.0)
32 | light_a.energy = e
33 | light_b.energy = e
34 |
--------------------------------------------------------------------------------
/9-game-hud/icon.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/10-extra-map-info/lively_light.gd:
--------------------------------------------------------------------------------
1 | extends Node2D
2 |
3 | ## Maximum jitter offset per dimension, in pixels.
4 | @export var jitter_offset := 0.25
5 | ## How fast the light changes, in jitters per second.
6 | @export var jitter_speed := 6.0
7 | ## Minimum light energy level caused by jittering.
8 | @export_range(0.0, 1.0) var jitter_min_energy := 0.95
9 |
10 | @export var light_a: PointLight2D
11 | @export var light_b: PointLight2D
12 |
13 | var progress := 0.0
14 |
15 |
16 | func _process(delta: float) -> void:
17 | progress += delta * jitter_speed
18 | if progress >= 1.0:
19 | progress -= 1.0
20 | jitter()
21 |
22 |
23 | func jitter() -> void:
24 | var p := Vector2(
25 | randf_range(-jitter_offset, jitter_offset),
26 | randf_range(-jitter_offset, jitter_offset)
27 | )
28 | light_a.position = p
29 | light_b.position = p
30 |
31 | var e := randf_range(jitter_min_energy, 1.0)
32 | light_a.energy = e
33 | light_b.energy = e
34 |
--------------------------------------------------------------------------------
/12-teleporters/icon.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/3-movable-objects/movable_object.tscn:
--------------------------------------------------------------------------------
1 | [gd_scene load_steps=5 format=3 uid="uid://bqy67mam7pouu"]
2 |
3 | [ext_resource type="Script" path="res://movable_object.gd" id="1_hxfrg"]
4 |
5 | [sub_resource type="RectangleShape2D" id="RectangleShape2D_obpkd"]
6 | size = Vector2(8, 8)
7 |
8 | [sub_resource type="Gradient" id="Gradient_mld41"]
9 |
10 | [sub_resource type="GradientTexture2D" id="GradientTexture2D_l17ur"]
11 | gradient = SubResource("Gradient_mld41")
12 | width = 8
13 | height = 8
14 | fill = 2
15 | fill_from = Vector2(0.5, 0.5)
16 | fill_to = Vector2(1, 0.5)
17 |
18 | [node name="MovableObject" type="CharacterBody2D"]
19 | motion_mode = 1
20 | script = ExtResource("1_hxfrg")
21 |
22 | [node name="CollisionShape2D" type="CollisionShape2D" parent="."]
23 | shape = SubResource("RectangleShape2D_obpkd")
24 |
25 | [node name="Sprite2D" type="Sprite2D" parent="."]
26 | texture_filter = 1
27 | texture = SubResource("GradientTexture2D_l17ur")
28 |
--------------------------------------------------------------------------------
/4-light-and-shadow/lively_light.gd:
--------------------------------------------------------------------------------
1 | extends Node2D
2 |
3 | ## Maximum jitter offset per dimension, in pixels.
4 | @export var jitter_offset := 0.25
5 | ## How fast the light changes, in jitters per second.
6 | @export var jitter_speed := 6.0
7 | ## Minimum light energy level caused by jittering.
8 | @export_range(0.0, 1.0) var jitter_min_energy := 0.95
9 |
10 | @export var light_a: PointLight2D
11 | @export var light_b: PointLight2D
12 |
13 | var progress := 0.0
14 |
15 |
16 | func _process(delta: float) -> void:
17 | progress += delta * jitter_speed
18 | if progress >= 1.0:
19 | progress -= 1.0
20 | jitter()
21 |
22 |
23 | func jitter() -> void:
24 | var p := Vector2(
25 | randf_range(-jitter_offset, jitter_offset),
26 | randf_range(-jitter_offset, jitter_offset)
27 | )
28 | light_a.position = p
29 | light_b.position = p
30 |
31 | var e := randf_range(jitter_min_energy, 1.0)
32 | light_a.energy = e
33 | light_b.energy = e
34 |
--------------------------------------------------------------------------------
/6-multiple-maps/icon.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/7-map-transitions/lively_light.gd:
--------------------------------------------------------------------------------
1 | extends Node2D
2 |
3 | ## Maximum jitter offset per dimension, in pixels.
4 | @export var jitter_offset := 0.25
5 | ## How fast the light changes, in jitters per second.
6 | @export var jitter_speed := 6.0
7 | ## Minimum light energy level caused by jittering.
8 | @export_range(0.0, 1.0) var jitter_min_energy := 0.95
9 |
10 | @export var light_a: PointLight2D
11 | @export var light_b: PointLight2D
12 |
13 | var progress := 0.0
14 |
15 |
16 | func _process(delta: float) -> void:
17 | progress += delta * jitter_speed
18 | if progress >= 1.0:
19 | progress -= 1.0
20 | jitter()
21 |
22 |
23 | func jitter() -> void:
24 | var p := Vector2(
25 | randf_range(-jitter_offset, jitter_offset),
26 | randf_range(-jitter_offset, jitter_offset)
27 | )
28 | light_a.position = p
29 | light_b.position = p
30 |
31 | var e := randf_range(jitter_min_energy, 1.0)
32 | light_a.energy = e
33 | light_b.energy = e
34 |
--------------------------------------------------------------------------------
/8-saving-progress/lively_light.gd:
--------------------------------------------------------------------------------
1 | extends Node2D
2 |
3 | ## Maximum jitter offset per dimension, in pixels.
4 | @export var jitter_offset := 0.25
5 | ## How fast the light changes, in jitters per second.
6 | @export var jitter_speed := 6.0
7 | ## Minimum light energy level caused by jittering.
8 | @export_range(0.0, 1.0) var jitter_min_energy := 0.95
9 |
10 | @export var light_a: PointLight2D
11 | @export var light_b: PointLight2D
12 |
13 | var progress := 0.0
14 |
15 |
16 | func _process(delta: float) -> void:
17 | progress += delta * jitter_speed
18 | if progress >= 1.0:
19 | progress -= 1.0
20 | jitter()
21 |
22 |
23 | func jitter() -> void:
24 | var p := Vector2(
25 | randf_range(-jitter_offset, jitter_offset),
26 | randf_range(-jitter_offset, jitter_offset)
27 | )
28 | light_a.position = p
29 | light_b.position = p
30 |
31 | var e := randf_range(jitter_min_energy, 1.0)
32 | light_a.energy = e
33 | light_b.energy = e
34 |
--------------------------------------------------------------------------------
/10-extra-map-info/icon.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/11-showing-best-scores/lively_light.gd:
--------------------------------------------------------------------------------
1 | extends Node2D
2 |
3 | ## Maximum jitter offset per dimension, in pixels.
4 | @export var jitter_offset := 0.25
5 | ## How fast the light changes, in jitters per second.
6 | @export var jitter_speed := 6.0
7 | ## Minimum light energy level caused by jittering.
8 | @export_range(0.0, 1.0) var jitter_min_energy := 0.95
9 |
10 | @export var light_a: PointLight2D
11 | @export var light_b: PointLight2D
12 |
13 | var progress := 0.0
14 |
15 |
16 | func _process(delta: float) -> void:
17 | progress += delta * jitter_speed
18 | if progress >= 1.0:
19 | progress -= 1.0
20 | jitter()
21 |
22 |
23 | func jitter() -> void:
24 | var p := Vector2(
25 | randf_range(-jitter_offset, jitter_offset),
26 | randf_range(-jitter_offset, jitter_offset)
27 | )
28 | light_a.position = p
29 | light_b.position = p
30 |
31 | var e := randf_range(jitter_min_energy, 1.0)
32 | light_a.energy = e
33 | light_b.energy = e
34 |
--------------------------------------------------------------------------------
/2-player-character/icon.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/3-movable-objects/icon.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/4-light-and-shadow/icon.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/7-map-transitions/icon.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/8-saving-progress/icon.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/11-showing-best-scores/icon.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT No Attribution (MIT-0)
2 |
3 | Copyright 2025 Jasper FLick
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this
6 | software and associated documentation files (the "Software"), to deal in the Software
7 | without restriction, including without limitation the rights to use, copy, modify,
8 | merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
9 | permit persons to whom the Software is furnished to do so.
10 |
11 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
12 | INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
13 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
14 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
15 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
16 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
17 |
--------------------------------------------------------------------------------
/8-saving-progress/project.godot:
--------------------------------------------------------------------------------
1 | ; Engine configuration file.
2 | ; It's best edited using the editor UI and not directly,
3 | ; since the parameters that go here are not all obvious.
4 | ;
5 | ; Format:
6 | ; [section] ; section goes between []
7 | ; param=value ; assign values to parameters
8 |
9 | config_version=5
10 |
11 | [application]
12 |
13 | config/name="True Top-Down 2D"
14 | config/version="8.0"
15 | run/main_scene="uid://bk1rkxiuhfn52"
16 | config/features=PackedStringArray("4.4", "Forward Plus")
17 | config/icon="res://icon.svg"
18 |
19 | [autoload]
20 |
21 | Main="*res://main.gd"
22 | MapTransition="*res://map_transition.tscn"
23 |
24 | [display]
25 |
26 | window/size/viewport_width=400
27 | window/size/viewport_height=240
28 | window/size/mode=4
29 | window/stretch/mode="viewport"
30 | window/stretch/scale_mode="integer"
31 | window/snap/snap_2d_transforms_to_pixel=false
32 |
33 | [filesystem]
34 |
35 | import/blender/enabled=false
36 |
37 | [physics]
38 |
39 | 2d/default_gravity=0.0
40 |
--------------------------------------------------------------------------------
/7-map-transitions/project.godot:
--------------------------------------------------------------------------------
1 | ; Engine configuration file.
2 | ; It's best edited using the editor UI and not directly,
3 | ; since the parameters that go here are not all obvious.
4 | ;
5 | ; Format:
6 | ; [section] ; section goes between []
7 | ; param=value ; assign values to parameters
8 |
9 | config_version=5
10 |
11 | [application]
12 |
13 | config/name="True Top-Down 2D"
14 | config/version="7.0"
15 | run/main_scene="res://maps/map.001.tscn"
16 | config/features=PackedStringArray("4.3", "Forward Plus")
17 | config/icon="res://icon.svg"
18 |
19 | [autoload]
20 |
21 | Main="*res://main.gd"
22 | MapTransition="*res://map_transition.tscn"
23 |
24 | [display]
25 |
26 | window/size/viewport_width=400
27 | window/size/viewport_height=240
28 | window/size/mode=4
29 | window/stretch/mode="viewport"
30 | window/stretch/scale_mode="integer"
31 | window/snap/snap_2d_transforms_to_pixel=false
32 |
33 | [filesystem]
34 |
35 | import/blender/enabled=false
36 |
37 | [physics]
38 |
39 | 2d/default_gravity=0.0
40 |
--------------------------------------------------------------------------------
/1-tile-map/icon.svg.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="CompressedTexture2D"
5 | uid="uid://hm31mdvjsuxu"
6 | path="res://.godot/imported/icon.svg-218a8f2b3041327d8a5756f3a245f83b.ctex"
7 | metadata={
8 | "vram_texture": false
9 | }
10 |
11 | [deps]
12 |
13 | source_file="res://icon.svg"
14 | dest_files=["res://.godot/imported/icon.svg-218a8f2b3041327d8a5756f3a245f83b.ctex"]
15 |
16 | [params]
17 |
18 | compress/mode=0
19 | compress/high_quality=false
20 | compress/lossy_quality=0.7
21 | compress/hdr_compression=1
22 | compress/normal_map=0
23 | compress/channel_pack=0
24 | mipmaps/generate=false
25 | mipmaps/limit=-1
26 | roughness/mode=0
27 | roughness/src_normal=""
28 | process/fix_alpha_border=true
29 | process/premult_alpha=false
30 | process/normal_map_invert_y=false
31 | process/hdr_as_srgb=false
32 | process/hdr_clamp_exposure=false
33 | process/size_limit=0
34 | detect_3d/compress_to=1
35 | svg/scale=1.0
36 | editor/scale_with_editor_scale=false
37 | editor/convert_colors_with_editor_theme=false
38 |
--------------------------------------------------------------------------------
/12-teleporters/icon.svg.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="CompressedTexture2D"
5 | uid="uid://hm31mdvjsuxu"
6 | path="res://.godot/imported/icon.svg-218a8f2b3041327d8a5756f3a245f83b.ctex"
7 | metadata={
8 | "vram_texture": false
9 | }
10 |
11 | [deps]
12 |
13 | source_file="res://icon.svg"
14 | dest_files=["res://.godot/imported/icon.svg-218a8f2b3041327d8a5756f3a245f83b.ctex"]
15 |
16 | [params]
17 |
18 | compress/mode=0
19 | compress/high_quality=false
20 | compress/lossy_quality=0.7
21 | compress/hdr_compression=1
22 | compress/normal_map=0
23 | compress/channel_pack=0
24 | mipmaps/generate=false
25 | mipmaps/limit=-1
26 | roughness/mode=0
27 | roughness/src_normal=""
28 | process/fix_alpha_border=true
29 | process/premult_alpha=false
30 | process/normal_map_invert_y=false
31 | process/hdr_as_srgb=false
32 | process/hdr_clamp_exposure=false
33 | process/size_limit=0
34 | detect_3d/compress_to=1
35 | svg/scale=1.0
36 | editor/scale_with_editor_scale=false
37 | editor/convert_colors_with_editor_theme=false
38 |
--------------------------------------------------------------------------------
/5-detectors/icon.svg.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="CompressedTexture2D"
5 | uid="uid://hm31mdvjsuxu"
6 | path="res://.godot/imported/icon.svg-218a8f2b3041327d8a5756f3a245f83b.ctex"
7 | metadata={
8 | "vram_texture": false
9 | }
10 |
11 | [deps]
12 |
13 | source_file="res://icon.svg"
14 | dest_files=["res://.godot/imported/icon.svg-218a8f2b3041327d8a5756f3a245f83b.ctex"]
15 |
16 | [params]
17 |
18 | compress/mode=0
19 | compress/high_quality=false
20 | compress/lossy_quality=0.7
21 | compress/hdr_compression=1
22 | compress/normal_map=0
23 | compress/channel_pack=0
24 | mipmaps/generate=false
25 | mipmaps/limit=-1
26 | roughness/mode=0
27 | roughness/src_normal=""
28 | process/fix_alpha_border=true
29 | process/premult_alpha=false
30 | process/normal_map_invert_y=false
31 | process/hdr_as_srgb=false
32 | process/hdr_clamp_exposure=false
33 | process/size_limit=0
34 | detect_3d/compress_to=1
35 | svg/scale=1.0
36 | editor/scale_with_editor_scale=false
37 | editor/convert_colors_with_editor_theme=false
38 |
--------------------------------------------------------------------------------
/9-game-hud/icon.svg.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="CompressedTexture2D"
5 | uid="uid://hm31mdvjsuxu"
6 | path="res://.godot/imported/icon.svg-218a8f2b3041327d8a5756f3a245f83b.ctex"
7 | metadata={
8 | "vram_texture": false
9 | }
10 |
11 | [deps]
12 |
13 | source_file="res://icon.svg"
14 | dest_files=["res://.godot/imported/icon.svg-218a8f2b3041327d8a5756f3a245f83b.ctex"]
15 |
16 | [params]
17 |
18 | compress/mode=0
19 | compress/high_quality=false
20 | compress/lossy_quality=0.7
21 | compress/hdr_compression=1
22 | compress/normal_map=0
23 | compress/channel_pack=0
24 | mipmaps/generate=false
25 | mipmaps/limit=-1
26 | roughness/mode=0
27 | roughness/src_normal=""
28 | process/fix_alpha_border=true
29 | process/premult_alpha=false
30 | process/normal_map_invert_y=false
31 | process/hdr_as_srgb=false
32 | process/hdr_clamp_exposure=false
33 | process/size_limit=0
34 | detect_3d/compress_to=1
35 | svg/scale=1.0
36 | editor/scale_with_editor_scale=false
37 | editor/convert_colors_with_editor_theme=false
38 |
--------------------------------------------------------------------------------
/10-extra-map-info/icon.svg.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="CompressedTexture2D"
5 | uid="uid://hm31mdvjsuxu"
6 | path="res://.godot/imported/icon.svg-218a8f2b3041327d8a5756f3a245f83b.ctex"
7 | metadata={
8 | "vram_texture": false
9 | }
10 |
11 | [deps]
12 |
13 | source_file="res://icon.svg"
14 | dest_files=["res://.godot/imported/icon.svg-218a8f2b3041327d8a5756f3a245f83b.ctex"]
15 |
16 | [params]
17 |
18 | compress/mode=0
19 | compress/high_quality=false
20 | compress/lossy_quality=0.7
21 | compress/hdr_compression=1
22 | compress/normal_map=0
23 | compress/channel_pack=0
24 | mipmaps/generate=false
25 | mipmaps/limit=-1
26 | roughness/mode=0
27 | roughness/src_normal=""
28 | process/fix_alpha_border=true
29 | process/premult_alpha=false
30 | process/normal_map_invert_y=false
31 | process/hdr_as_srgb=false
32 | process/hdr_clamp_exposure=false
33 | process/size_limit=0
34 | detect_3d/compress_to=1
35 | svg/scale=1.0
36 | editor/scale_with_editor_scale=false
37 | editor/convert_colors_with_editor_theme=false
38 |
--------------------------------------------------------------------------------
/2-player-character/icon.svg.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="CompressedTexture2D"
5 | uid="uid://hm31mdvjsuxu"
6 | path="res://.godot/imported/icon.svg-218a8f2b3041327d8a5756f3a245f83b.ctex"
7 | metadata={
8 | "vram_texture": false
9 | }
10 |
11 | [deps]
12 |
13 | source_file="res://icon.svg"
14 | dest_files=["res://.godot/imported/icon.svg-218a8f2b3041327d8a5756f3a245f83b.ctex"]
15 |
16 | [params]
17 |
18 | compress/mode=0
19 | compress/high_quality=false
20 | compress/lossy_quality=0.7
21 | compress/hdr_compression=1
22 | compress/normal_map=0
23 | compress/channel_pack=0
24 | mipmaps/generate=false
25 | mipmaps/limit=-1
26 | roughness/mode=0
27 | roughness/src_normal=""
28 | process/fix_alpha_border=true
29 | process/premult_alpha=false
30 | process/normal_map_invert_y=false
31 | process/hdr_as_srgb=false
32 | process/hdr_clamp_exposure=false
33 | process/size_limit=0
34 | detect_3d/compress_to=1
35 | svg/scale=1.0
36 | editor/scale_with_editor_scale=false
37 | editor/convert_colors_with_editor_theme=false
38 |
--------------------------------------------------------------------------------
/3-movable-objects/icon.svg.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="CompressedTexture2D"
5 | uid="uid://hm31mdvjsuxu"
6 | path="res://.godot/imported/icon.svg-218a8f2b3041327d8a5756f3a245f83b.ctex"
7 | metadata={
8 | "vram_texture": false
9 | }
10 |
11 | [deps]
12 |
13 | source_file="res://icon.svg"
14 | dest_files=["res://.godot/imported/icon.svg-218a8f2b3041327d8a5756f3a245f83b.ctex"]
15 |
16 | [params]
17 |
18 | compress/mode=0
19 | compress/high_quality=false
20 | compress/lossy_quality=0.7
21 | compress/hdr_compression=1
22 | compress/normal_map=0
23 | compress/channel_pack=0
24 | mipmaps/generate=false
25 | mipmaps/limit=-1
26 | roughness/mode=0
27 | roughness/src_normal=""
28 | process/fix_alpha_border=true
29 | process/premult_alpha=false
30 | process/normal_map_invert_y=false
31 | process/hdr_as_srgb=false
32 | process/hdr_clamp_exposure=false
33 | process/size_limit=0
34 | detect_3d/compress_to=1
35 | svg/scale=1.0
36 | editor/scale_with_editor_scale=false
37 | editor/convert_colors_with_editor_theme=false
38 |
--------------------------------------------------------------------------------
/4-light-and-shadow/icon.svg.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="CompressedTexture2D"
5 | uid="uid://hm31mdvjsuxu"
6 | path="res://.godot/imported/icon.svg-218a8f2b3041327d8a5756f3a245f83b.ctex"
7 | metadata={
8 | "vram_texture": false
9 | }
10 |
11 | [deps]
12 |
13 | source_file="res://icon.svg"
14 | dest_files=["res://.godot/imported/icon.svg-218a8f2b3041327d8a5756f3a245f83b.ctex"]
15 |
16 | [params]
17 |
18 | compress/mode=0
19 | compress/high_quality=false
20 | compress/lossy_quality=0.7
21 | compress/hdr_compression=1
22 | compress/normal_map=0
23 | compress/channel_pack=0
24 | mipmaps/generate=false
25 | mipmaps/limit=-1
26 | roughness/mode=0
27 | roughness/src_normal=""
28 | process/fix_alpha_border=true
29 | process/premult_alpha=false
30 | process/normal_map_invert_y=false
31 | process/hdr_as_srgb=false
32 | process/hdr_clamp_exposure=false
33 | process/size_limit=0
34 | detect_3d/compress_to=1
35 | svg/scale=1.0
36 | editor/scale_with_editor_scale=false
37 | editor/convert_colors_with_editor_theme=false
38 |
--------------------------------------------------------------------------------
/6-multiple-maps/icon.svg.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="CompressedTexture2D"
5 | uid="uid://hm31mdvjsuxu"
6 | path="res://.godot/imported/icon.svg-218a8f2b3041327d8a5756f3a245f83b.ctex"
7 | metadata={
8 | "vram_texture": false
9 | }
10 |
11 | [deps]
12 |
13 | source_file="res://icon.svg"
14 | dest_files=["res://.godot/imported/icon.svg-218a8f2b3041327d8a5756f3a245f83b.ctex"]
15 |
16 | [params]
17 |
18 | compress/mode=0
19 | compress/high_quality=false
20 | compress/lossy_quality=0.7
21 | compress/hdr_compression=1
22 | compress/normal_map=0
23 | compress/channel_pack=0
24 | mipmaps/generate=false
25 | mipmaps/limit=-1
26 | roughness/mode=0
27 | roughness/src_normal=""
28 | process/fix_alpha_border=true
29 | process/premult_alpha=false
30 | process/normal_map_invert_y=false
31 | process/hdr_as_srgb=false
32 | process/hdr_clamp_exposure=false
33 | process/size_limit=0
34 | detect_3d/compress_to=1
35 | svg/scale=1.0
36 | editor/scale_with_editor_scale=false
37 | editor/convert_colors_with_editor_theme=false
38 |
--------------------------------------------------------------------------------
/7-map-transitions/icon.svg.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="CompressedTexture2D"
5 | uid="uid://hm31mdvjsuxu"
6 | path="res://.godot/imported/icon.svg-218a8f2b3041327d8a5756f3a245f83b.ctex"
7 | metadata={
8 | "vram_texture": false
9 | }
10 |
11 | [deps]
12 |
13 | source_file="res://icon.svg"
14 | dest_files=["res://.godot/imported/icon.svg-218a8f2b3041327d8a5756f3a245f83b.ctex"]
15 |
16 | [params]
17 |
18 | compress/mode=0
19 | compress/high_quality=false
20 | compress/lossy_quality=0.7
21 | compress/hdr_compression=1
22 | compress/normal_map=0
23 | compress/channel_pack=0
24 | mipmaps/generate=false
25 | mipmaps/limit=-1
26 | roughness/mode=0
27 | roughness/src_normal=""
28 | process/fix_alpha_border=true
29 | process/premult_alpha=false
30 | process/normal_map_invert_y=false
31 | process/hdr_as_srgb=false
32 | process/hdr_clamp_exposure=false
33 | process/size_limit=0
34 | detect_3d/compress_to=1
35 | svg/scale=1.0
36 | editor/scale_with_editor_scale=false
37 | editor/convert_colors_with_editor_theme=false
38 |
--------------------------------------------------------------------------------
/8-saving-progress/icon.svg.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="CompressedTexture2D"
5 | uid="uid://hm31mdvjsuxu"
6 | path="res://.godot/imported/icon.svg-218a8f2b3041327d8a5756f3a245f83b.ctex"
7 | metadata={
8 | "vram_texture": false
9 | }
10 |
11 | [deps]
12 |
13 | source_file="res://icon.svg"
14 | dest_files=["res://.godot/imported/icon.svg-218a8f2b3041327d8a5756f3a245f83b.ctex"]
15 |
16 | [params]
17 |
18 | compress/mode=0
19 | compress/high_quality=false
20 | compress/lossy_quality=0.7
21 | compress/hdr_compression=1
22 | compress/normal_map=0
23 | compress/channel_pack=0
24 | mipmaps/generate=false
25 | mipmaps/limit=-1
26 | roughness/mode=0
27 | roughness/src_normal=""
28 | process/fix_alpha_border=true
29 | process/premult_alpha=false
30 | process/normal_map_invert_y=false
31 | process/hdr_as_srgb=false
32 | process/hdr_clamp_exposure=false
33 | process/size_limit=0
34 | detect_3d/compress_to=1
35 | svg/scale=1.0
36 | editor/scale_with_editor_scale=false
37 | editor/convert_colors_with_editor_theme=false
38 |
--------------------------------------------------------------------------------
/9-game-hud/project.godot:
--------------------------------------------------------------------------------
1 | ; Engine configuration file.
2 | ; It's best edited using the editor UI and not directly,
3 | ; since the parameters that go here are not all obvious.
4 | ;
5 | ; Format:
6 | ; [section] ; section goes between []
7 | ; param=value ; assign values to parameters
8 |
9 | config_version=5
10 |
11 | [application]
12 |
13 | config/name="True Top-Down 2D"
14 | config/version="9.0"
15 | run/main_scene="uid://bk1rkxiuhfn52"
16 | config/features=PackedStringArray("4.4", "Forward Plus")
17 | config/icon="res://icon.svg"
18 |
19 | [autoload]
20 |
21 | Main="*res://main.gd"
22 | MapTransition="*res://map_transition.tscn"
23 | HUD="*res://hud.tscn"
24 |
25 | [display]
26 |
27 | window/size/viewport_width=400
28 | window/size/viewport_height=240
29 | window/size/mode=4
30 | window/stretch/mode="viewport"
31 | window/stretch/scale_mode="integer"
32 | window/snap/snap_2d_transforms_to_pixel=false
33 |
34 | [filesystem]
35 |
36 | import/blender/enabled=false
37 |
38 | [physics]
39 |
40 | 2d/default_gravity=0.0
41 |
--------------------------------------------------------------------------------
/11-showing-best-scores/icon.svg.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="CompressedTexture2D"
5 | uid="uid://hm31mdvjsuxu"
6 | path="res://.godot/imported/icon.svg-218a8f2b3041327d8a5756f3a245f83b.ctex"
7 | metadata={
8 | "vram_texture": false
9 | }
10 |
11 | [deps]
12 |
13 | source_file="res://icon.svg"
14 | dest_files=["res://.godot/imported/icon.svg-218a8f2b3041327d8a5756f3a245f83b.ctex"]
15 |
16 | [params]
17 |
18 | compress/mode=0
19 | compress/high_quality=false
20 | compress/lossy_quality=0.7
21 | compress/hdr_compression=1
22 | compress/normal_map=0
23 | compress/channel_pack=0
24 | mipmaps/generate=false
25 | mipmaps/limit=-1
26 | roughness/mode=0
27 | roughness/src_normal=""
28 | process/fix_alpha_border=true
29 | process/premult_alpha=false
30 | process/normal_map_invert_y=false
31 | process/hdr_as_srgb=false
32 | process/hdr_clamp_exposure=false
33 | process/size_limit=0
34 | detect_3d/compress_to=1
35 | svg/scale=1.0
36 | editor/scale_with_editor_scale=false
37 | editor/convert_colors_with_editor_theme=false
38 |
--------------------------------------------------------------------------------
/12-teleporters/project.godot:
--------------------------------------------------------------------------------
1 | ; Engine configuration file.
2 | ; It's best edited using the editor UI and not directly,
3 | ; since the parameters that go here are not all obvious.
4 | ;
5 | ; Format:
6 | ; [section] ; section goes between []
7 | ; param=value ; assign values to parameters
8 |
9 | config_version=5
10 |
11 | [application]
12 |
13 | config/name="True Top-Down 2D"
14 | config/version="12.0"
15 | run/main_scene="uid://bk1rkxiuhfn52"
16 | config/features=PackedStringArray("4.5", "Forward Plus")
17 | config/icon="res://icon.svg"
18 |
19 | [autoload]
20 |
21 | Main="*res://main.gd"
22 | MapTransition="*res://map_transition.tscn"
23 | HUD="*res://hud.tscn"
24 |
25 | [display]
26 |
27 | window/size/viewport_width=400
28 | window/size/viewport_height=240
29 | window/size/mode=4
30 | window/stretch/mode="viewport"
31 | window/stretch/scale_mode="integer"
32 | window/snap/snap_2d_transforms_to_pixel=false
33 |
34 | [filesystem]
35 |
36 | import/blender/enabled=false
37 |
38 | [physics]
39 |
40 | 2d/default_gravity=0.0
41 |
--------------------------------------------------------------------------------
/10-extra-map-info/project.godot:
--------------------------------------------------------------------------------
1 | ; Engine configuration file.
2 | ; It's best edited using the editor UI and not directly,
3 | ; since the parameters that go here are not all obvious.
4 | ;
5 | ; Format:
6 | ; [section] ; section goes between []
7 | ; param=value ; assign values to parameters
8 |
9 | config_version=5
10 |
11 | [application]
12 |
13 | config/name="True Top-Down 2D"
14 | config/version="10.0"
15 | run/main_scene="uid://bk1rkxiuhfn52"
16 | config/features=PackedStringArray("4.4", "Forward Plus")
17 | config/icon="res://icon.svg"
18 |
19 | [autoload]
20 |
21 | Main="*res://main.gd"
22 | MapTransition="*res://map_transition.tscn"
23 | HUD="*res://hud.tscn"
24 |
25 | [display]
26 |
27 | window/size/viewport_width=400
28 | window/size/viewport_height=240
29 | window/size/mode=4
30 | window/stretch/mode="viewport"
31 | window/stretch/scale_mode="integer"
32 | window/snap/snap_2d_transforms_to_pixel=false
33 |
34 | [filesystem]
35 |
36 | import/blender/enabled=false
37 |
38 | [physics]
39 |
40 | 2d/default_gravity=0.0
41 |
--------------------------------------------------------------------------------
/11-showing-best-scores/project.godot:
--------------------------------------------------------------------------------
1 | ; Engine configuration file.
2 | ; It's best edited using the editor UI and not directly,
3 | ; since the parameters that go here are not all obvious.
4 | ;
5 | ; Format:
6 | ; [section] ; section goes between []
7 | ; param=value ; assign values to parameters
8 |
9 | config_version=5
10 |
11 | [application]
12 |
13 | config/name="True Top-Down 2D"
14 | config/version="11.0"
15 | run/main_scene="uid://bk1rkxiuhfn52"
16 | config/features=PackedStringArray("4.5", "Forward Plus")
17 | config/icon="res://icon.svg"
18 |
19 | [autoload]
20 |
21 | Main="*res://main.gd"
22 | MapTransition="*res://map_transition.tscn"
23 | HUD="*res://hud.tscn"
24 |
25 | [display]
26 |
27 | window/size/viewport_width=400
28 | window/size/viewport_height=240
29 | window/size/mode=4
30 | window/stretch/mode="viewport"
31 | window/stretch/scale_mode="integer"
32 | window/snap/snap_2d_transforms_to_pixel=false
33 |
34 | [filesystem]
35 |
36 | import/blender/enabled=false
37 |
38 | [physics]
39 |
40 | 2d/default_gravity=0.0
41 |
--------------------------------------------------------------------------------
/3-movable-objects/movable_object.gd:
--------------------------------------------------------------------------------
1 | class_name MovableObject
2 | extends CharacterBody2D
3 |
4 | @export_range(0.0, 10.0) var drag := 5.0
5 | @export_range(0.0, 1.0) var impact_response := 0.5
6 | @export var initial_velocity := Vector2.ZERO
7 |
8 |
9 | func _ready() -> void:
10 | velocity = initial_velocity
11 |
12 |
13 | func apply_impact(impact_velocity: Vector2) -> void:
14 | velocity += (impact_velocity - velocity) * impact_response
15 |
16 |
17 | func _physics_process(delta: float) -> void:
18 | if velocity.length_squared() > 1.0:
19 | velocity *= 1.0 - drag * delta
20 | if move_and_slide():
21 | resolve_collisions()
22 |
23 |
24 | func resolve_collisions() -> void:
25 | var current_velocity := velocity
26 | for i in get_slide_collision_count():
27 | var collision := get_slide_collision(i)
28 | var body := collision.get_collider() as MovableObject
29 | if body:
30 | apply_impact(body.velocity)
31 | body.apply_impact(current_velocity)
32 | else:
33 | velocity -= velocity.project(collision.get_normal())
34 |
--------------------------------------------------------------------------------
/5-detectors/lively_light.tscn:
--------------------------------------------------------------------------------
1 | [gd_scene load_steps=4 format=3 uid="uid://c42eiotc23vsq"]
2 |
3 | [ext_resource type="Script" path="res://lively_light.gd" id="1_tpdam"]
4 |
5 | [sub_resource type="Gradient" id="Gradient_k8ld2"]
6 | colors = PackedColorArray(1, 1, 1, 1, 0, 0, 0, 1)
7 |
8 | [sub_resource type="GradientTexture2D" id="GradientTexture2D_mhsb8"]
9 | gradient = SubResource("Gradient_k8ld2")
10 | width = 192
11 | height = 192
12 | fill = 1
13 | fill_from = Vector2(0.5, 0.5)
14 | fill_to = Vector2(1, 0.5)
15 |
16 | [node name="LivelyLight" type="Node2D" node_paths=PackedStringArray("light_a", "light_b")]
17 | script = ExtResource("1_tpdam")
18 | light_a = NodePath("LightA")
19 | light_b = NodePath("LightB")
20 |
21 | [node name="LightA" type="PointLight2D" parent="."]
22 | shadow_enabled = true
23 | texture = SubResource("GradientTexture2D_mhsb8")
24 |
25 | [node name="LightB" type="PointLight2D" parent="."]
26 | range_item_cull_mask = 2
27 | shadow_enabled = true
28 | shadow_item_cull_mask = 2
29 | texture = SubResource("GradientTexture2D_mhsb8")
30 |
--------------------------------------------------------------------------------
/11-showing-best-scores/player_character.gd:
--------------------------------------------------------------------------------
1 | class_name PlayerCharacter
2 | extends CharacterBody2D
3 |
4 | ## Speed in pixels per second.
5 | @export_range(0, 1000) var speed := 60
6 |
7 | var last_position: Vector2
8 | var travel_distance := 0.0
9 |
10 |
11 | func _ready() -> void:
12 | last_position = position
13 |
14 |
15 | func _process(_delta: float) -> void:
16 | HUD.show_travel_distance(travel_distance)
17 |
18 |
19 | func _physics_process(_delta: float) -> void:
20 | get_player_input()
21 | if move_and_slide():
22 | resolve_collisions()
23 |
24 | travel_distance += last_position.distance_to(position)
25 | last_position = position
26 |
27 |
28 | func resolve_collisions() -> void:
29 | for i in get_slide_collision_count():
30 | var collision := get_slide_collision(i)
31 | var body := collision.get_collider() as MovableObject
32 | if body:
33 | body.apply_impact(velocity)
34 |
35 |
36 | func get_player_input() -> void:
37 | var vector := Input.get_vector("ui_left", "ui_right", "ui_up", "ui_down")
38 | velocity = vector * speed
39 |
--------------------------------------------------------------------------------
/4-light-and-shadow/lively_light.tscn:
--------------------------------------------------------------------------------
1 | [gd_scene load_steps=4 format=3 uid="uid://c42eiotc23vsq"]
2 |
3 | [ext_resource type="Script" path="res://lively_light.gd" id="1_tpdam"]
4 |
5 | [sub_resource type="Gradient" id="Gradient_k8ld2"]
6 | colors = PackedColorArray(1, 1, 1, 1, 0, 0, 0, 1)
7 |
8 | [sub_resource type="GradientTexture2D" id="GradientTexture2D_mhsb8"]
9 | gradient = SubResource("Gradient_k8ld2")
10 | width = 192
11 | height = 192
12 | fill = 1
13 | fill_from = Vector2(0.5, 0.5)
14 | fill_to = Vector2(1, 0.5)
15 |
16 | [node name="LivelyLight" type="Node2D" node_paths=PackedStringArray("light_a", "light_b")]
17 | script = ExtResource("1_tpdam")
18 | light_a = NodePath("LightA")
19 | light_b = NodePath("LightB")
20 |
21 | [node name="LightA" type="PointLight2D" parent="."]
22 | shadow_enabled = true
23 | texture = SubResource("GradientTexture2D_mhsb8")
24 |
25 | [node name="LightB" type="PointLight2D" parent="."]
26 | range_item_cull_mask = 2
27 | shadow_enabled = true
28 | shadow_item_cull_mask = 2
29 | texture = SubResource("GradientTexture2D_mhsb8")
30 |
--------------------------------------------------------------------------------
/6-multiple-maps/lively_light.tscn:
--------------------------------------------------------------------------------
1 | [gd_scene load_steps=4 format=3 uid="uid://c42eiotc23vsq"]
2 |
3 | [ext_resource type="Script" path="res://lively_light.gd" id="1_tpdam"]
4 |
5 | [sub_resource type="Gradient" id="Gradient_k8ld2"]
6 | colors = PackedColorArray(1, 1, 1, 1, 0, 0, 0, 1)
7 |
8 | [sub_resource type="GradientTexture2D" id="GradientTexture2D_mhsb8"]
9 | gradient = SubResource("Gradient_k8ld2")
10 | width = 192
11 | height = 192
12 | fill = 1
13 | fill_from = Vector2(0.5, 0.5)
14 | fill_to = Vector2(1, 0.5)
15 |
16 | [node name="LivelyLight" type="Node2D" node_paths=PackedStringArray("light_a", "light_b")]
17 | script = ExtResource("1_tpdam")
18 | light_a = NodePath("LightA")
19 | light_b = NodePath("LightB")
20 |
21 | [node name="LightA" type="PointLight2D" parent="."]
22 | shadow_enabled = true
23 | texture = SubResource("GradientTexture2D_mhsb8")
24 |
25 | [node name="LightB" type="PointLight2D" parent="."]
26 | range_item_cull_mask = 2
27 | shadow_enabled = true
28 | shadow_item_cull_mask = 2
29 | texture = SubResource("GradientTexture2D_mhsb8")
30 |
--------------------------------------------------------------------------------
/7-map-transitions/lively_light.tscn:
--------------------------------------------------------------------------------
1 | [gd_scene load_steps=4 format=3 uid="uid://c42eiotc23vsq"]
2 |
3 | [ext_resource type="Script" path="res://lively_light.gd" id="1_tpdam"]
4 |
5 | [sub_resource type="Gradient" id="Gradient_k8ld2"]
6 | colors = PackedColorArray(1, 1, 1, 1, 0, 0, 0, 1)
7 |
8 | [sub_resource type="GradientTexture2D" id="GradientTexture2D_mhsb8"]
9 | gradient = SubResource("Gradient_k8ld2")
10 | width = 192
11 | height = 192
12 | fill = 1
13 | fill_from = Vector2(0.5, 0.5)
14 | fill_to = Vector2(1, 0.5)
15 |
16 | [node name="LivelyLight" type="Node2D" node_paths=PackedStringArray("light_a", "light_b")]
17 | script = ExtResource("1_tpdam")
18 | light_a = NodePath("LightA")
19 | light_b = NodePath("LightB")
20 |
21 | [node name="LightA" type="PointLight2D" parent="."]
22 | shadow_enabled = true
23 | texture = SubResource("GradientTexture2D_mhsb8")
24 |
25 | [node name="LightB" type="PointLight2D" parent="."]
26 | range_item_cull_mask = 2
27 | shadow_enabled = true
28 | shadow_item_cull_mask = 2
29 | texture = SubResource("GradientTexture2D_mhsb8")
30 |
--------------------------------------------------------------------------------
/9-game-hud/lively_light.tscn:
--------------------------------------------------------------------------------
1 | [gd_scene load_steps=4 format=3 uid="uid://c42eiotc23vsq"]
2 |
3 | [ext_resource type="Script" uid="uid://cgoe12geigody" path="res://lively_light.gd" id="1_tpdam"]
4 |
5 | [sub_resource type="Gradient" id="Gradient_k8ld2"]
6 | colors = PackedColorArray(1, 1, 1, 1, 0, 0, 0, 1)
7 |
8 | [sub_resource type="GradientTexture2D" id="GradientTexture2D_mhsb8"]
9 | gradient = SubResource("Gradient_k8ld2")
10 | width = 192
11 | height = 192
12 | fill = 1
13 | fill_from = Vector2(0.5, 0.5)
14 | fill_to = Vector2(1, 0.5)
15 |
16 | [node name="LivelyLight" type="Node2D" node_paths=PackedStringArray("light_a", "light_b")]
17 | script = ExtResource("1_tpdam")
18 | light_a = NodePath("LightA")
19 | light_b = NodePath("LightB")
20 |
21 | [node name="LightA" type="PointLight2D" parent="."]
22 | shadow_enabled = true
23 | texture = SubResource("GradientTexture2D_mhsb8")
24 |
25 | [node name="LightB" type="PointLight2D" parent="."]
26 | range_item_cull_mask = 2
27 | shadow_enabled = true
28 | shadow_item_cull_mask = 2
29 | texture = SubResource("GradientTexture2D_mhsb8")
30 |
--------------------------------------------------------------------------------
/10-extra-map-info/lively_light.tscn:
--------------------------------------------------------------------------------
1 | [gd_scene load_steps=4 format=3 uid="uid://c42eiotc23vsq"]
2 |
3 | [ext_resource type="Script" uid="uid://cgoe12geigody" path="res://lively_light.gd" id="1_tpdam"]
4 |
5 | [sub_resource type="Gradient" id="Gradient_k8ld2"]
6 | colors = PackedColorArray(1, 1, 1, 1, 0, 0, 0, 1)
7 |
8 | [sub_resource type="GradientTexture2D" id="GradientTexture2D_mhsb8"]
9 | gradient = SubResource("Gradient_k8ld2")
10 | width = 192
11 | height = 192
12 | fill = 1
13 | fill_from = Vector2(0.5, 0.5)
14 | fill_to = Vector2(1, 0.5)
15 |
16 | [node name="LivelyLight" type="Node2D" node_paths=PackedStringArray("light_a", "light_b")]
17 | script = ExtResource("1_tpdam")
18 | light_a = NodePath("LightA")
19 | light_b = NodePath("LightB")
20 |
21 | [node name="LightA" type="PointLight2D" parent="."]
22 | shadow_enabled = true
23 | texture = SubResource("GradientTexture2D_mhsb8")
24 |
25 | [node name="LightB" type="PointLight2D" parent="."]
26 | range_item_cull_mask = 2
27 | shadow_enabled = true
28 | shadow_item_cull_mask = 2
29 | texture = SubResource("GradientTexture2D_mhsb8")
30 |
--------------------------------------------------------------------------------
/12-teleporters/lively_light.tscn:
--------------------------------------------------------------------------------
1 | [gd_scene load_steps=4 format=3 uid="uid://c42eiotc23vsq"]
2 |
3 | [ext_resource type="Script" uid="uid://cgoe12geigody" path="res://lively_light.gd" id="1_tpdam"]
4 |
5 | [sub_resource type="Gradient" id="Gradient_k8ld2"]
6 | colors = PackedColorArray(1, 1, 1, 1, 0, 0, 0, 1)
7 |
8 | [sub_resource type="GradientTexture2D" id="GradientTexture2D_mhsb8"]
9 | gradient = SubResource("Gradient_k8ld2")
10 | width = 192
11 | height = 192
12 | fill = 1
13 | fill_from = Vector2(0.5, 0.5)
14 | fill_to = Vector2(1, 0.5)
15 |
16 | [node name="LivelyLight" type="Node2D" node_paths=PackedStringArray("light_a", "light_b")]
17 | script = ExtResource("1_tpdam")
18 | light_a = NodePath("LightA")
19 | light_b = NodePath("LightB")
20 |
21 | [node name="LightA" type="PointLight2D" parent="."]
22 | shadow_enabled = true
23 | texture = SubResource("GradientTexture2D_mhsb8")
24 |
25 | [node name="LightB" type="PointLight2D" parent="."]
26 | range_item_cull_mask = 2
27 | shadow_enabled = true
28 | shadow_item_cull_mask = 2
29 | texture = SubResource("GradientTexture2D_mhsb8")
30 |
--------------------------------------------------------------------------------
/8-saving-progress/lively_light.tscn:
--------------------------------------------------------------------------------
1 | [gd_scene load_steps=4 format=3 uid="uid://c42eiotc23vsq"]
2 |
3 | [ext_resource type="Script" uid="uid://cgoe12geigody" path="res://lively_light.gd" id="1_tpdam"]
4 |
5 | [sub_resource type="Gradient" id="Gradient_k8ld2"]
6 | colors = PackedColorArray(1, 1, 1, 1, 0, 0, 0, 1)
7 |
8 | [sub_resource type="GradientTexture2D" id="GradientTexture2D_mhsb8"]
9 | gradient = SubResource("Gradient_k8ld2")
10 | width = 192
11 | height = 192
12 | fill = 1
13 | fill_from = Vector2(0.5, 0.5)
14 | fill_to = Vector2(1, 0.5)
15 |
16 | [node name="LivelyLight" type="Node2D" node_paths=PackedStringArray("light_a", "light_b")]
17 | script = ExtResource("1_tpdam")
18 | light_a = NodePath("LightA")
19 | light_b = NodePath("LightB")
20 |
21 | [node name="LightA" type="PointLight2D" parent="."]
22 | shadow_enabled = true
23 | texture = SubResource("GradientTexture2D_mhsb8")
24 |
25 | [node name="LightB" type="PointLight2D" parent="."]
26 | range_item_cull_mask = 2
27 | shadow_enabled = true
28 | shadow_item_cull_mask = 2
29 | texture = SubResource("GradientTexture2D_mhsb8")
30 |
--------------------------------------------------------------------------------
/11-showing-best-scores/lively_light.tscn:
--------------------------------------------------------------------------------
1 | [gd_scene load_steps=4 format=3 uid="uid://c42eiotc23vsq"]
2 |
3 | [ext_resource type="Script" uid="uid://cgoe12geigody" path="res://lively_light.gd" id="1_tpdam"]
4 |
5 | [sub_resource type="Gradient" id="Gradient_k8ld2"]
6 | colors = PackedColorArray(1, 1, 1, 1, 0, 0, 0, 1)
7 |
8 | [sub_resource type="GradientTexture2D" id="GradientTexture2D_mhsb8"]
9 | gradient = SubResource("Gradient_k8ld2")
10 | width = 192
11 | height = 192
12 | fill = 1
13 | fill_from = Vector2(0.5, 0.5)
14 | fill_to = Vector2(1, 0.5)
15 |
16 | [node name="LivelyLight" type="Node2D" node_paths=PackedStringArray("light_a", "light_b")]
17 | script = ExtResource("1_tpdam")
18 | light_a = NodePath("LightA")
19 | light_b = NodePath("LightB")
20 |
21 | [node name="LightA" type="PointLight2D" parent="."]
22 | shadow_enabled = true
23 | texture = SubResource("GradientTexture2D_mhsb8")
24 |
25 | [node name="LightB" type="PointLight2D" parent="."]
26 | range_item_cull_mask = 2
27 | shadow_enabled = true
28 | shadow_item_cull_mask = 2
29 | texture = SubResource("GradientTexture2D_mhsb8")
30 |
--------------------------------------------------------------------------------
/10-extra-map-info/player_character.gd:
--------------------------------------------------------------------------------
1 | class_name PlayerCharacter
2 | extends CharacterBody2D
3 |
4 | ## Speed in pixels per second.
5 | @export_range(0, 1000) var speed := 60
6 |
7 | var last_position: Vector2
8 | var travel_distance := 0.0
9 |
10 |
11 | func _ready() -> void:
12 | last_position = position
13 | HUD.show_travel_distance(travel_distance)
14 |
15 |
16 | func _process(_delta: float) -> void:
17 | HUD.show_travel_distance(travel_distance)
18 |
19 |
20 | func _physics_process(_delta: float) -> void:
21 | get_player_input()
22 | if move_and_slide():
23 | resolve_collisions()
24 |
25 | travel_distance += last_position.distance_to(position)
26 | last_position = position
27 |
28 |
29 | func resolve_collisions() -> void:
30 | for i in get_slide_collision_count():
31 | var collision := get_slide_collision(i)
32 | var body := collision.get_collider() as MovableObject
33 | if body:
34 | body.apply_impact(velocity)
35 |
36 |
37 | func get_player_input() -> void:
38 | var vector := Input.get_vector("ui_left", "ui_right", "ui_up", "ui_down")
39 | velocity = vector * speed
40 |
--------------------------------------------------------------------------------
/5-detectors/movable_object.gd:
--------------------------------------------------------------------------------
1 | class_name MovableObject
2 | extends CharacterBody2D
3 |
4 | @export_range(0.0, 10.0) var drag := 5.0
5 | @export_range(0.0, 1.0) var impact_response := 0.5
6 | @export var initial_velocity := Vector2.ZERO
7 |
8 |
9 | func _ready() -> void:
10 | velocity = initial_velocity
11 |
12 |
13 | func apply_impact(impact_velocity: Vector2) -> void:
14 | velocity += (impact_velocity - velocity) * impact_response
15 |
16 |
17 | func _physics_process(delta: float) -> void:
18 | if velocity.length_squared() > 1.0:
19 | velocity *= 1.0 - drag * delta
20 | if move_and_slide():
21 | resolve_collisions()
22 | else:
23 | position = round(position)
24 | velocity = Vector2.ZERO
25 |
26 |
27 | func resolve_collisions() -> void:
28 | var current_velocity := velocity
29 | for i in get_slide_collision_count():
30 | var collision := get_slide_collision(i)
31 | var body := collision.get_collider() as MovableObject
32 | if body:
33 | apply_impact(body.velocity)
34 | body.apply_impact(current_velocity)
35 | else:
36 | velocity -= velocity.project(collision.get_normal())
37 |
--------------------------------------------------------------------------------
/9-game-hud/movable_object.gd:
--------------------------------------------------------------------------------
1 | class_name MovableObject
2 | extends CharacterBody2D
3 |
4 | @export_range(0.0, 10.0) var drag := 5.0
5 | @export_range(0.0, 1.0) var impact_response := 0.5
6 | @export var initial_velocity := Vector2.ZERO
7 |
8 |
9 | func _ready() -> void:
10 | velocity = initial_velocity
11 |
12 |
13 | func apply_impact(impact_velocity: Vector2) -> void:
14 | velocity += (impact_velocity - velocity) * impact_response
15 |
16 |
17 | func _physics_process(delta: float) -> void:
18 | if velocity.length_squared() > 1.0:
19 | velocity *= 1.0 - drag * delta
20 | if move_and_slide():
21 | resolve_collisions()
22 | else:
23 | position = round(position)
24 | velocity = Vector2.ZERO
25 |
26 |
27 | func resolve_collisions() -> void:
28 | var current_velocity := velocity
29 | for i in get_slide_collision_count():
30 | var collision := get_slide_collision(i)
31 | var body := collision.get_collider() as MovableObject
32 | if body:
33 | apply_impact(body.velocity)
34 | body.apply_impact(current_velocity)
35 | else:
36 | velocity -= velocity.project(collision.get_normal())
37 |
--------------------------------------------------------------------------------
/10-extra-map-info/movable_object.gd:
--------------------------------------------------------------------------------
1 | class_name MovableObject
2 | extends CharacterBody2D
3 |
4 | @export_range(0.0, 10.0) var drag := 5.0
5 | @export_range(0.0, 1.0) var impact_response := 0.5
6 | @export var initial_velocity := Vector2.ZERO
7 |
8 |
9 | func _ready() -> void:
10 | velocity = initial_velocity
11 |
12 |
13 | func apply_impact(impact_velocity: Vector2) -> void:
14 | velocity += (impact_velocity - velocity) * impact_response
15 |
16 |
17 | func _physics_process(delta: float) -> void:
18 | if velocity.length_squared() > 1.0:
19 | velocity *= 1.0 - drag * delta
20 | if move_and_slide():
21 | resolve_collisions()
22 | else:
23 | position = round(position)
24 | velocity = Vector2.ZERO
25 |
26 |
27 | func resolve_collisions() -> void:
28 | var current_velocity := velocity
29 | for i in get_slide_collision_count():
30 | var collision := get_slide_collision(i)
31 | var body := collision.get_collider() as MovableObject
32 | if body:
33 | apply_impact(body.velocity)
34 | body.apply_impact(current_velocity)
35 | else:
36 | velocity -= velocity.project(collision.get_normal())
37 |
--------------------------------------------------------------------------------
/12-teleporters/movable_object.gd:
--------------------------------------------------------------------------------
1 | class_name MovableObject
2 | extends InteractiveObject
3 |
4 | @export_range(0.0, 10.0) var drag := 5.0
5 | @export_range(0.0, 1.0) var impact_response := 0.5
6 | @export var initial_velocity := Vector2.ZERO
7 |
8 |
9 | func _ready() -> void:
10 | velocity = initial_velocity
11 |
12 |
13 | func apply_impact(impact_velocity: Vector2) -> void:
14 | velocity += (impact_velocity - velocity) * impact_response
15 |
16 |
17 | func _physics_process(delta: float) -> void:
18 | if velocity.length_squared() > 1.0:
19 | velocity *= 1.0 - drag * delta
20 | if move_and_slide():
21 | resolve_collisions()
22 | else:
23 | position = round(position)
24 | velocity = Vector2.ZERO
25 |
26 |
27 | func resolve_collisions() -> void:
28 | var current_velocity := velocity
29 | for i in get_slide_collision_count():
30 | var collision := get_slide_collision(i)
31 | var body := collision.get_collider() as MovableObject
32 | if body:
33 | apply_impact(body.velocity)
34 | body.apply_impact(current_velocity)
35 | else:
36 | velocity -= velocity.project(collision.get_normal())
37 |
--------------------------------------------------------------------------------
/4-light-and-shadow/movable_object.gd:
--------------------------------------------------------------------------------
1 | class_name MovableObject
2 | extends CharacterBody2D
3 |
4 | @export_range(0.0, 10.0) var drag := 5.0
5 | @export_range(0.0, 1.0) var impact_response := 0.5
6 | @export var initial_velocity := Vector2.ZERO
7 |
8 |
9 | func _ready() -> void:
10 | velocity = initial_velocity
11 |
12 |
13 | func apply_impact(impact_velocity: Vector2) -> void:
14 | velocity += (impact_velocity - velocity) * impact_response
15 |
16 |
17 | func _physics_process(delta: float) -> void:
18 | if velocity.length_squared() > 1.0:
19 | velocity *= 1.0 - drag * delta
20 | if move_and_slide():
21 | resolve_collisions()
22 | else:
23 | position = round(position)
24 | velocity = Vector2.ZERO
25 |
26 |
27 | func resolve_collisions() -> void:
28 | var current_velocity := velocity
29 | for i in get_slide_collision_count():
30 | var collision := get_slide_collision(i)
31 | var body := collision.get_collider() as MovableObject
32 | if body:
33 | apply_impact(body.velocity)
34 | body.apply_impact(current_velocity)
35 | else:
36 | velocity -= velocity.project(collision.get_normal())
37 |
--------------------------------------------------------------------------------
/6-multiple-maps/movable_object.gd:
--------------------------------------------------------------------------------
1 | class_name MovableObject
2 | extends CharacterBody2D
3 |
4 | @export_range(0.0, 10.0) var drag := 5.0
5 | @export_range(0.0, 1.0) var impact_response := 0.5
6 | @export var initial_velocity := Vector2.ZERO
7 |
8 |
9 | func _ready() -> void:
10 | velocity = initial_velocity
11 |
12 |
13 | func apply_impact(impact_velocity: Vector2) -> void:
14 | velocity += (impact_velocity - velocity) * impact_response
15 |
16 |
17 | func _physics_process(delta: float) -> void:
18 | if velocity.length_squared() > 1.0:
19 | velocity *= 1.0 - drag * delta
20 | if move_and_slide():
21 | resolve_collisions()
22 | else:
23 | position = round(position)
24 | velocity = Vector2.ZERO
25 |
26 |
27 | func resolve_collisions() -> void:
28 | var current_velocity := velocity
29 | for i in get_slide_collision_count():
30 | var collision := get_slide_collision(i)
31 | var body := collision.get_collider() as MovableObject
32 | if body:
33 | apply_impact(body.velocity)
34 | body.apply_impact(current_velocity)
35 | else:
36 | velocity -= velocity.project(collision.get_normal())
37 |
--------------------------------------------------------------------------------
/7-map-transitions/movable_object.gd:
--------------------------------------------------------------------------------
1 | class_name MovableObject
2 | extends CharacterBody2D
3 |
4 | @export_range(0.0, 10.0) var drag := 5.0
5 | @export_range(0.0, 1.0) var impact_response := 0.5
6 | @export var initial_velocity := Vector2.ZERO
7 |
8 |
9 | func _ready() -> void:
10 | velocity = initial_velocity
11 |
12 |
13 | func apply_impact(impact_velocity: Vector2) -> void:
14 | velocity += (impact_velocity - velocity) * impact_response
15 |
16 |
17 | func _physics_process(delta: float) -> void:
18 | if velocity.length_squared() > 1.0:
19 | velocity *= 1.0 - drag * delta
20 | if move_and_slide():
21 | resolve_collisions()
22 | else:
23 | position = round(position)
24 | velocity = Vector2.ZERO
25 |
26 |
27 | func resolve_collisions() -> void:
28 | var current_velocity := velocity
29 | for i in get_slide_collision_count():
30 | var collision := get_slide_collision(i)
31 | var body := collision.get_collider() as MovableObject
32 | if body:
33 | apply_impact(body.velocity)
34 | body.apply_impact(current_velocity)
35 | else:
36 | velocity -= velocity.project(collision.get_normal())
37 |
--------------------------------------------------------------------------------
/8-saving-progress/movable_object.gd:
--------------------------------------------------------------------------------
1 | class_name MovableObject
2 | extends CharacterBody2D
3 |
4 | @export_range(0.0, 10.0) var drag := 5.0
5 | @export_range(0.0, 1.0) var impact_response := 0.5
6 | @export var initial_velocity := Vector2.ZERO
7 |
8 |
9 | func _ready() -> void:
10 | velocity = initial_velocity
11 |
12 |
13 | func apply_impact(impact_velocity: Vector2) -> void:
14 | velocity += (impact_velocity - velocity) * impact_response
15 |
16 |
17 | func _physics_process(delta: float) -> void:
18 | if velocity.length_squared() > 1.0:
19 | velocity *= 1.0 - drag * delta
20 | if move_and_slide():
21 | resolve_collisions()
22 | else:
23 | position = round(position)
24 | velocity = Vector2.ZERO
25 |
26 |
27 | func resolve_collisions() -> void:
28 | var current_velocity := velocity
29 | for i in get_slide_collision_count():
30 | var collision := get_slide_collision(i)
31 | var body := collision.get_collider() as MovableObject
32 | if body:
33 | apply_impact(body.velocity)
34 | body.apply_impact(current_velocity)
35 | else:
36 | velocity -= velocity.project(collision.get_normal())
37 |
--------------------------------------------------------------------------------
/11-showing-best-scores/movable_object.gd:
--------------------------------------------------------------------------------
1 | class_name MovableObject
2 | extends CharacterBody2D
3 |
4 | @export_range(0.0, 10.0) var drag := 5.0
5 | @export_range(0.0, 1.0) var impact_response := 0.5
6 | @export var initial_velocity := Vector2.ZERO
7 |
8 |
9 | func _ready() -> void:
10 | velocity = initial_velocity
11 |
12 |
13 | func apply_impact(impact_velocity: Vector2) -> void:
14 | velocity += (impact_velocity - velocity) * impact_response
15 |
16 |
17 | func _physics_process(delta: float) -> void:
18 | if velocity.length_squared() > 1.0:
19 | velocity *= 1.0 - drag * delta
20 | if move_and_slide():
21 | resolve_collisions()
22 | else:
23 | position = round(position)
24 | velocity = Vector2.ZERO
25 |
26 |
27 | func resolve_collisions() -> void:
28 | var current_velocity := velocity
29 | for i in get_slide_collision_count():
30 | var collision := get_slide_collision(i)
31 | var body := collision.get_collider() as MovableObject
32 | if body:
33 | apply_impact(body.velocity)
34 | body.apply_impact(current_velocity)
35 | else:
36 | velocity -= velocity.project(collision.get_normal())
37 |
--------------------------------------------------------------------------------
/6-multiple-maps/map.gd:
--------------------------------------------------------------------------------
1 | extends Node
2 |
3 | var registered_detector_count := 0
4 | var valid_detector_count := 0
5 |
6 |
7 | func _ready() -> void:
8 | for child_node in get_children():
9 | var detector := child_node as Detector
10 | if detector:
11 | registered_detector_count += 1
12 | detector.validity_changed.connect(_on_detector_validity_changed)
13 |
14 |
15 | func _on_detector_validity_changed(valid: bool) -> void:
16 | if valid:
17 | valid_detector_count += 1
18 | if valid_detector_count == registered_detector_count:
19 | load_next_map.call_deferred()
20 | else:
21 | valid_detector_count -= 1
22 |
23 |
24 | func load_next_map() -> void:
25 | var current_map_path := get_tree().current_scene.scene_file_path
26 | var split_path := current_map_path.split(".")
27 | var next_map_number := split_path[1].to_int() + 1
28 | split_path[1] = str(next_map_number).pad_zeros(3)
29 | var next_map_path = ".".join(split_path)
30 |
31 | if not ResourceLoader.exists(next_map_path):
32 | split_path[1] = "001"
33 | next_map_path = ".".join(split_path)
34 |
35 | get_tree().change_scene_to_file(next_map_path)
36 |
--------------------------------------------------------------------------------
/12-teleporters/player_character.gd:
--------------------------------------------------------------------------------
1 | class_name PlayerCharacter
2 | extends InteractiveObject
3 |
4 | ## Speed in pixels per second.
5 | @export_range(0, 1000) var speed := 60
6 |
7 | var last_position: Vector2
8 | var travel_distance := 0.0
9 |
10 |
11 | func displace(offset: Vector2) -> void:
12 | super(offset)
13 | last_position = position
14 |
15 |
16 | func _ready() -> void:
17 | last_position = position
18 |
19 |
20 | func _process(_delta: float) -> void:
21 | HUD.show_travel_distance(travel_distance)
22 |
23 |
24 | func _physics_process(_delta: float) -> void:
25 | get_player_input()
26 | if move_and_slide():
27 | resolve_collisions()
28 |
29 | travel_distance += last_position.distance_to(position)
30 | last_position = position
31 |
32 |
33 | func resolve_collisions() -> void:
34 | for i in get_slide_collision_count():
35 | var collision := get_slide_collision(i)
36 | var body := collision.get_collider() as MovableObject
37 | if body:
38 | body.apply_impact(velocity)
39 |
40 |
41 | func get_player_input() -> void:
42 | var vector := Input.get_vector("ui_left", "ui_right", "ui_up", "ui_down")
43 | velocity = vector * speed
44 |
--------------------------------------------------------------------------------
/12-teleporters/teleporters/teleporter_source.png.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="CompressedTexture2D"
5 | uid="uid://blq78ijp12vd1"
6 | path="res://.godot/imported/teleporter_source.png-bab27449a8e4b7df3f31f0d7e6abf57f.ctex"
7 | metadata={
8 | "vram_texture": false
9 | }
10 |
11 | [deps]
12 |
13 | source_file="res://teleporters/teleporter_source.png"
14 | dest_files=["res://.godot/imported/teleporter_source.png-bab27449a8e4b7df3f31f0d7e6abf57f.ctex"]
15 |
16 | [params]
17 |
18 | compress/mode=0
19 | compress/high_quality=false
20 | compress/lossy_quality=0.7
21 | compress/uastc_level=0
22 | compress/rdo_quality_loss=0.0
23 | compress/hdr_compression=1
24 | compress/normal_map=0
25 | compress/channel_pack=0
26 | mipmaps/generate=false
27 | mipmaps/limit=-1
28 | roughness/mode=0
29 | roughness/src_normal=""
30 | process/channel_remap/red=0
31 | process/channel_remap/green=1
32 | process/channel_remap/blue=2
33 | process/channel_remap/alpha=3
34 | process/fix_alpha_border=true
35 | process/premult_alpha=false
36 | process/normal_map_invert_y=false
37 | process/hdr_as_srgb=false
38 | process/hdr_clamp_exposure=false
39 | process/size_limit=0
40 | detect_3d/compress_to=1
41 |
--------------------------------------------------------------------------------
/12-teleporters/teleporters/teleporter_destination.png.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="CompressedTexture2D"
5 | uid="uid://cpc3pnpy5ytd2"
6 | path="res://.godot/imported/teleporter_destination.png-f26c94633810de79ddc236a06be64563.ctex"
7 | metadata={
8 | "vram_texture": false
9 | }
10 |
11 | [deps]
12 |
13 | source_file="res://teleporters/teleporter_destination.png"
14 | dest_files=["res://.godot/imported/teleporter_destination.png-f26c94633810de79ddc236a06be64563.ctex"]
15 |
16 | [params]
17 |
18 | compress/mode=0
19 | compress/high_quality=false
20 | compress/lossy_quality=0.7
21 | compress/uastc_level=0
22 | compress/rdo_quality_loss=0.0
23 | compress/hdr_compression=1
24 | compress/normal_map=0
25 | compress/channel_pack=0
26 | mipmaps/generate=false
27 | mipmaps/limit=-1
28 | roughness/mode=0
29 | roughness/src_normal=""
30 | process/channel_remap/red=0
31 | process/channel_remap/green=1
32 | process/channel_remap/blue=2
33 | process/channel_remap/alpha=3
34 | process/fix_alpha_border=true
35 | process/premult_alpha=false
36 | process/normal_map_invert_y=false
37 | process/hdr_as_srgb=false
38 | process/hdr_clamp_exposure=false
39 | process/size_limit=0
40 | detect_3d/compress_to=1
41 |
--------------------------------------------------------------------------------
/4-light-and-shadow/movable_object.tscn:
--------------------------------------------------------------------------------
1 | [gd_scene load_steps=6 format=3 uid="uid://bqy67mam7pouu"]
2 |
3 | [ext_resource type="Script" path="res://movable_object.gd" id="1_hxfrg"]
4 |
5 | [sub_resource type="OccluderPolygon2D" id="OccluderPolygon2D_irncw"]
6 | polygon = PackedVector2Array(-4, -4, 4, -4, 4, 4, -4, 4)
7 |
8 | [sub_resource type="RectangleShape2D" id="RectangleShape2D_obpkd"]
9 | size = Vector2(8, 8)
10 |
11 | [sub_resource type="Gradient" id="Gradient_mld41"]
12 |
13 | [sub_resource type="GradientTexture2D" id="GradientTexture2D_l17ur"]
14 | gradient = SubResource("Gradient_mld41")
15 | width = 8
16 | height = 8
17 | fill = 2
18 | fill_from = Vector2(0.5, 0.5)
19 | fill_to = Vector2(1, 0.5)
20 |
21 | [node name="MovableObject" type="CharacterBody2D"]
22 | motion_mode = 1
23 | script = ExtResource("1_hxfrg")
24 |
25 | [node name="LightOccluder2D" type="LightOccluder2D" parent="."]
26 | occluder = SubResource("OccluderPolygon2D_irncw")
27 |
28 | [node name="CollisionShape2D" type="CollisionShape2D" parent="."]
29 | shape = SubResource("RectangleShape2D_obpkd")
30 |
31 | [node name="Sprite2D" type="Sprite2D" parent="."]
32 | light_mask = 2
33 | texture_filter = 1
34 | texture = SubResource("GradientTexture2D_l17ur")
35 |
--------------------------------------------------------------------------------
/5-detectors/detector.gd:
--------------------------------------------------------------------------------
1 | extends Area2D
2 |
3 | ## Color for when no objects are on the detector.
4 | @export_color_no_alpha var invalid_color := Color.RED
5 | ## Color for when objects are on the detector.
6 | @export_color_no_alpha var valid_color := Color.GREEN
7 |
8 | ## How fast the detector's color pulses.
9 | @export_range(0.1, 1.0) var pulse_frequency := 0.25
10 |
11 | @export var sprite: Sprite2D
12 |
13 | var object_count := 0
14 |
15 | var pulse_progress := 0.0
16 |
17 |
18 | func _init() -> void:
19 | pulse_progress = randf()
20 |
21 |
22 | func _process(delta: float) -> void:
23 | if object_count == 0:
24 | pulse_progress += delta * pulse_frequency
25 | if pulse_progress >= 1.0:
26 | pulse_progress -= 1.0
27 |
28 | var brightness := cos(pulse_progress * TAU) * 0.25 + 0.75
29 | sprite.modulate = Color(
30 | invalid_color.r * brightness,
31 | invalid_color.g * brightness,
32 | invalid_color.b * brightness
33 | )
34 |
35 |
36 | func _on_body_entered(_body: Node2D) -> void:
37 | if object_count == 0:
38 | sprite.modulate = valid_color
39 | object_count += 1
40 |
41 |
42 | func _on_body_exited(_body: Node2D) -> void:
43 | object_count -= 1
44 | if object_count == 0:
45 | pulse_progress = 0.0
46 |
--------------------------------------------------------------------------------
/5-detectors/movable_object.tscn:
--------------------------------------------------------------------------------
1 | [gd_scene load_steps=6 format=3 uid="uid://bqy67mam7pouu"]
2 |
3 | [ext_resource type="Script" path="res://movable_object.gd" id="1_hxfrg"]
4 |
5 | [sub_resource type="OccluderPolygon2D" id="OccluderPolygon2D_irncw"]
6 | polygon = PackedVector2Array(-4, -4, 4, -4, 4, 4, -4, 4)
7 |
8 | [sub_resource type="RectangleShape2D" id="RectangleShape2D_obpkd"]
9 | size = Vector2(7.9, 7.9)
10 |
11 | [sub_resource type="Gradient" id="Gradient_mld41"]
12 |
13 | [sub_resource type="GradientTexture2D" id="GradientTexture2D_l17ur"]
14 | gradient = SubResource("Gradient_mld41")
15 | width = 8
16 | height = 8
17 | fill = 2
18 | fill_from = Vector2(0.5, 0.5)
19 | fill_to = Vector2(1, 0.5)
20 |
21 | [node name="MovableObject" type="CharacterBody2D"]
22 | collision_layer = 3
23 | motion_mode = 1
24 | script = ExtResource("1_hxfrg")
25 |
26 | [node name="LightOccluder2D" type="LightOccluder2D" parent="."]
27 | occluder = SubResource("OccluderPolygon2D_irncw")
28 |
29 | [node name="CollisionShape2D" type="CollisionShape2D" parent="."]
30 | shape = SubResource("RectangleShape2D_obpkd")
31 |
32 | [node name="Sprite2D" type="Sprite2D" parent="."]
33 | light_mask = 2
34 | texture_filter = 1
35 | texture = SubResource("GradientTexture2D_l17ur")
36 |
--------------------------------------------------------------------------------
/6-multiple-maps/movable_object.tscn:
--------------------------------------------------------------------------------
1 | [gd_scene load_steps=6 format=3 uid="uid://bqy67mam7pouu"]
2 |
3 | [ext_resource type="Script" path="res://movable_object.gd" id="1_hxfrg"]
4 |
5 | [sub_resource type="OccluderPolygon2D" id="OccluderPolygon2D_irncw"]
6 | polygon = PackedVector2Array(-4, -4, 4, -4, 4, 4, -4, 4)
7 |
8 | [sub_resource type="RectangleShape2D" id="RectangleShape2D_obpkd"]
9 | size = Vector2(7.9, 7.9)
10 |
11 | [sub_resource type="Gradient" id="Gradient_mld41"]
12 |
13 | [sub_resource type="GradientTexture2D" id="GradientTexture2D_l17ur"]
14 | gradient = SubResource("Gradient_mld41")
15 | width = 8
16 | height = 8
17 | fill = 2
18 | fill_from = Vector2(0.5, 0.5)
19 | fill_to = Vector2(1, 0.5)
20 |
21 | [node name="MovableObject" type="CharacterBody2D"]
22 | collision_layer = 3
23 | motion_mode = 1
24 | script = ExtResource("1_hxfrg")
25 |
26 | [node name="LightOccluder2D" type="LightOccluder2D" parent="."]
27 | occluder = SubResource("OccluderPolygon2D_irncw")
28 |
29 | [node name="CollisionShape2D" type="CollisionShape2D" parent="."]
30 | shape = SubResource("RectangleShape2D_obpkd")
31 |
32 | [node name="Sprite2D" type="Sprite2D" parent="."]
33 | light_mask = 2
34 | texture_filter = 1
35 | texture = SubResource("GradientTexture2D_l17ur")
36 |
--------------------------------------------------------------------------------
/7-map-transitions/movable_object.tscn:
--------------------------------------------------------------------------------
1 | [gd_scene load_steps=6 format=3 uid="uid://bqy67mam7pouu"]
2 |
3 | [ext_resource type="Script" path="res://movable_object.gd" id="1_hxfrg"]
4 |
5 | [sub_resource type="OccluderPolygon2D" id="OccluderPolygon2D_irncw"]
6 | polygon = PackedVector2Array(-4, -4, 4, -4, 4, 4, -4, 4)
7 |
8 | [sub_resource type="RectangleShape2D" id="RectangleShape2D_obpkd"]
9 | size = Vector2(7.9, 7.9)
10 |
11 | [sub_resource type="Gradient" id="Gradient_mld41"]
12 |
13 | [sub_resource type="GradientTexture2D" id="GradientTexture2D_l17ur"]
14 | gradient = SubResource("Gradient_mld41")
15 | width = 8
16 | height = 8
17 | fill = 2
18 | fill_from = Vector2(0.5, 0.5)
19 | fill_to = Vector2(1, 0.5)
20 |
21 | [node name="MovableObject" type="CharacterBody2D"]
22 | collision_layer = 3
23 | motion_mode = 1
24 | script = ExtResource("1_hxfrg")
25 |
26 | [node name="LightOccluder2D" type="LightOccluder2D" parent="."]
27 | occluder = SubResource("OccluderPolygon2D_irncw")
28 |
29 | [node name="CollisionShape2D" type="CollisionShape2D" parent="."]
30 | shape = SubResource("RectangleShape2D_obpkd")
31 |
32 | [node name="Sprite2D" type="Sprite2D" parent="."]
33 | light_mask = 2
34 | texture_filter = 1
35 | texture = SubResource("GradientTexture2D_l17ur")
36 |
--------------------------------------------------------------------------------
/9-game-hud/hud.tscn:
--------------------------------------------------------------------------------
1 | [gd_scene load_steps=2 format=3 uid="uid://cw4q2habmqtk8"]
2 |
3 | [ext_resource type="Script" uid="uid://cv3i66vvgu2ra" path="res://hud.gd" id="1_37p78"]
4 |
5 | [node name="HUD" type="CanvasLayer" node_paths=PackedStringArray("map_name_label", "map_time_label", "new_best_map_time_label")]
6 | layer = 3
7 | script = ExtResource("1_37p78")
8 | map_name_label = NodePath("MapName")
9 | map_time_label = NodePath("MapTime")
10 | new_best_map_time_label = NodePath("NewBestMapTime")
11 |
12 | [node name="MapName" type="Label" parent="."]
13 | offset_left = 16.0
14 | offset_right = 75.0
15 | offset_bottom = 16.0
16 | theme_override_font_sizes/font_size = 11
17 | text = "Map Name"
18 |
19 | [node name="MapTime" type="Label" parent="."]
20 | offset_left = 324.0
21 | offset_right = 384.0
22 | offset_bottom = 16.0
23 | theme_override_font_sizes/font_size = 11
24 | text = "0s"
25 | horizontal_alignment = 2
26 |
27 | [node name="NewBestMapTime" type="Label" parent="."]
28 | anchors_preset = 8
29 | anchor_left = 0.5
30 | anchor_top = 0.5
31 | anchor_right = 0.5
32 | anchor_bottom = 0.5
33 | offset_left = -0.5
34 | offset_top = -11.5
35 | offset_right = 0.5
36 | offset_bottom = 11.5
37 | grow_horizontal = 2
38 | grow_vertical = 2
39 | text = "New Best Time"
40 |
--------------------------------------------------------------------------------
/9-game-hud/movable_object.tscn:
--------------------------------------------------------------------------------
1 | [gd_scene load_steps=6 format=3 uid="uid://bqy67mam7pouu"]
2 |
3 | [ext_resource type="Script" uid="uid://on8oe1ncp37d" path="res://movable_object.gd" id="1_hxfrg"]
4 |
5 | [sub_resource type="OccluderPolygon2D" id="OccluderPolygon2D_irncw"]
6 | polygon = PackedVector2Array(-4, -4, 4, -4, 4, 4, -4, 4)
7 |
8 | [sub_resource type="RectangleShape2D" id="RectangleShape2D_obpkd"]
9 | size = Vector2(7.9, 7.9)
10 |
11 | [sub_resource type="Gradient" id="Gradient_mld41"]
12 |
13 | [sub_resource type="GradientTexture2D" id="GradientTexture2D_l17ur"]
14 | gradient = SubResource("Gradient_mld41")
15 | width = 8
16 | height = 8
17 | fill = 2
18 | fill_from = Vector2(0.5, 0.5)
19 | fill_to = Vector2(1, 0.5)
20 |
21 | [node name="MovableObject" type="CharacterBody2D"]
22 | collision_layer = 3
23 | motion_mode = 1
24 | script = ExtResource("1_hxfrg")
25 |
26 | [node name="LightOccluder2D" type="LightOccluder2D" parent="."]
27 | occluder = SubResource("OccluderPolygon2D_irncw")
28 |
29 | [node name="CollisionShape2D" type="CollisionShape2D" parent="."]
30 | shape = SubResource("RectangleShape2D_obpkd")
31 |
32 | [node name="Sprite2D" type="Sprite2D" parent="."]
33 | light_mask = 2
34 | texture_filter = 1
35 | texture = SubResource("GradientTexture2D_l17ur")
36 |
--------------------------------------------------------------------------------
/10-extra-map-info/movable_object.tscn:
--------------------------------------------------------------------------------
1 | [gd_scene load_steps=6 format=3 uid="uid://bqy67mam7pouu"]
2 |
3 | [ext_resource type="Script" uid="uid://on8oe1ncp37d" path="res://movable_object.gd" id="1_hxfrg"]
4 |
5 | [sub_resource type="OccluderPolygon2D" id="OccluderPolygon2D_irncw"]
6 | polygon = PackedVector2Array(-4, -4, 4, -4, 4, 4, -4, 4)
7 |
8 | [sub_resource type="RectangleShape2D" id="RectangleShape2D_obpkd"]
9 | size = Vector2(7.9, 7.9)
10 |
11 | [sub_resource type="Gradient" id="Gradient_mld41"]
12 |
13 | [sub_resource type="GradientTexture2D" id="GradientTexture2D_l17ur"]
14 | gradient = SubResource("Gradient_mld41")
15 | width = 8
16 | height = 8
17 | fill = 2
18 | fill_from = Vector2(0.5, 0.5)
19 | fill_to = Vector2(1, 0.5)
20 |
21 | [node name="MovableObject" type="CharacterBody2D"]
22 | collision_layer = 3
23 | motion_mode = 1
24 | script = ExtResource("1_hxfrg")
25 |
26 | [node name="LightOccluder2D" type="LightOccluder2D" parent="."]
27 | occluder = SubResource("OccluderPolygon2D_irncw")
28 |
29 | [node name="CollisionShape2D" type="CollisionShape2D" parent="."]
30 | shape = SubResource("RectangleShape2D_obpkd")
31 |
32 | [node name="Sprite2D" type="Sprite2D" parent="."]
33 | light_mask = 2
34 | texture_filter = 1
35 | texture = SubResource("GradientTexture2D_l17ur")
36 |
--------------------------------------------------------------------------------
/8-saving-progress/movable_object.tscn:
--------------------------------------------------------------------------------
1 | [gd_scene load_steps=6 format=3 uid="uid://bqy67mam7pouu"]
2 |
3 | [ext_resource type="Script" uid="uid://on8oe1ncp37d" path="res://movable_object.gd" id="1_hxfrg"]
4 |
5 | [sub_resource type="OccluderPolygon2D" id="OccluderPolygon2D_irncw"]
6 | polygon = PackedVector2Array(-4, -4, 4, -4, 4, 4, -4, 4)
7 |
8 | [sub_resource type="RectangleShape2D" id="RectangleShape2D_obpkd"]
9 | size = Vector2(7.9, 7.9)
10 |
11 | [sub_resource type="Gradient" id="Gradient_mld41"]
12 |
13 | [sub_resource type="GradientTexture2D" id="GradientTexture2D_l17ur"]
14 | gradient = SubResource("Gradient_mld41")
15 | width = 8
16 | height = 8
17 | fill = 2
18 | fill_from = Vector2(0.5, 0.5)
19 | fill_to = Vector2(1, 0.5)
20 |
21 | [node name="MovableObject" type="CharacterBody2D"]
22 | collision_layer = 3
23 | motion_mode = 1
24 | script = ExtResource("1_hxfrg")
25 |
26 | [node name="LightOccluder2D" type="LightOccluder2D" parent="."]
27 | occluder = SubResource("OccluderPolygon2D_irncw")
28 |
29 | [node name="CollisionShape2D" type="CollisionShape2D" parent="."]
30 | shape = SubResource("RectangleShape2D_obpkd")
31 |
32 | [node name="Sprite2D" type="Sprite2D" parent="."]
33 | light_mask = 2
34 | texture_filter = 1
35 | texture = SubResource("GradientTexture2D_l17ur")
36 |
--------------------------------------------------------------------------------
/11-showing-best-scores/movable_object.tscn:
--------------------------------------------------------------------------------
1 | [gd_scene load_steps=6 format=3 uid="uid://bqy67mam7pouu"]
2 |
3 | [ext_resource type="Script" uid="uid://on8oe1ncp37d" path="res://movable_object.gd" id="1_hxfrg"]
4 |
5 | [sub_resource type="OccluderPolygon2D" id="OccluderPolygon2D_irncw"]
6 | polygon = PackedVector2Array(-4, -4, 4, -4, 4, 4, -4, 4)
7 |
8 | [sub_resource type="RectangleShape2D" id="RectangleShape2D_obpkd"]
9 | size = Vector2(7.9, 7.9)
10 |
11 | [sub_resource type="Gradient" id="Gradient_mld41"]
12 |
13 | [sub_resource type="GradientTexture2D" id="GradientTexture2D_l17ur"]
14 | gradient = SubResource("Gradient_mld41")
15 | width = 8
16 | height = 8
17 | fill = 2
18 | fill_from = Vector2(0.5, 0.5)
19 | fill_to = Vector2(1, 0.5)
20 |
21 | [node name="MovableObject" type="CharacterBody2D"]
22 | collision_layer = 3
23 | motion_mode = 1
24 | script = ExtResource("1_hxfrg")
25 |
26 | [node name="LightOccluder2D" type="LightOccluder2D" parent="."]
27 | occluder = SubResource("OccluderPolygon2D_irncw")
28 |
29 | [node name="CollisionShape2D" type="CollisionShape2D" parent="."]
30 | shape = SubResource("RectangleShape2D_obpkd")
31 |
32 | [node name="Sprite2D" type="Sprite2D" parent="."]
33 | light_mask = 2
34 | texture_filter = 1
35 | texture = SubResource("GradientTexture2D_l17ur")
36 |
--------------------------------------------------------------------------------
/9-game-hud/map.gd:
--------------------------------------------------------------------------------
1 | class_name GameMap
2 | extends Node
3 |
4 | const KEY_BEST_TIME := "best_time"
5 |
6 | @export var map_name := "Map"
7 |
8 | var registered_detector_count := 0
9 | var valid_detector_count := 0
10 | var current_map_time := 0.0
11 | var map_save_data: Dictionary
12 |
13 |
14 | func _process(delta: float) -> void:
15 | current_map_time += delta
16 | HUD.show_map_time(current_map_time)
17 |
18 |
19 | func _ready() -> void:
20 | for child_node in get_children():
21 | var detector := child_node as Detector
22 | if detector:
23 | registered_detector_count += 1
24 | detector.validity_changed.connect(_on_detector_validity_changed)
25 |
26 | Main.map_loaded(self)
27 | HUD.show_map_info(self)
28 |
29 |
30 | func _on_detector_validity_changed(valid: bool) -> void:
31 | if valid:
32 | valid_detector_count += 1
33 | if valid_detector_count == registered_detector_count:
34 | _update_best_time()
35 | Main.load_next_map()
36 | else:
37 | valid_detector_count -= 1
38 |
39 |
40 | func _update_best_time() -> void:
41 | var new_time := floori(current_map_time)
42 | if (
43 | not map_save_data.has(KEY_BEST_TIME)
44 | or new_time < map_save_data[KEY_BEST_TIME]
45 | ):
46 | map_save_data[KEY_BEST_TIME] = new_time
47 | HUD.show_new_best_map_time(new_time)
48 |
--------------------------------------------------------------------------------
/12-teleporters/movable_object.tscn:
--------------------------------------------------------------------------------
1 | [gd_scene load_steps=6 format=3 uid="uid://bqy67mam7pouu"]
2 |
3 | [ext_resource type="Script" uid="uid://on8oe1ncp37d" path="res://movable_object.gd" id="1_hxfrg"]
4 |
5 | [sub_resource type="OccluderPolygon2D" id="OccluderPolygon2D_irncw"]
6 | polygon = PackedVector2Array(-4, -4, 4, -4, 4, 4, -4, 4)
7 |
8 | [sub_resource type="RectangleShape2D" id="RectangleShape2D_obpkd"]
9 | size = Vector2(7.9, 7.9)
10 |
11 | [sub_resource type="Gradient" id="Gradient_mld41"]
12 |
13 | [sub_resource type="GradientTexture2D" id="GradientTexture2D_l17ur"]
14 | gradient = SubResource("Gradient_mld41")
15 | width = 8
16 | height = 8
17 | fill = 2
18 | fill_from = Vector2(0.5, 0.5)
19 | fill_to = Vector2(1, 0.5)
20 |
21 | [node name="MovableObject" type="CharacterBody2D" node_paths=PackedStringArray("colission_shape")]
22 | collision_layer = 3
23 | motion_mode = 1
24 | script = ExtResource("1_hxfrg")
25 | colission_shape = NodePath("CollisionShape2D")
26 |
27 | [node name="LightOccluder2D" type="LightOccluder2D" parent="."]
28 | occluder = SubResource("OccluderPolygon2D_irncw")
29 |
30 | [node name="CollisionShape2D" type="CollisionShape2D" parent="."]
31 | shape = SubResource("RectangleShape2D_obpkd")
32 |
33 | [node name="Sprite2D" type="Sprite2D" parent="."]
34 | light_mask = 2
35 | texture_filter = 1
36 | texture = SubResource("GradientTexture2D_l17ur")
37 |
--------------------------------------------------------------------------------
/9-game-hud/detector.gd:
--------------------------------------------------------------------------------
1 | class_name Detector
2 | extends Area2D
3 |
4 | signal validity_changed(valid: bool)
5 |
6 | ## Color for when no objects are on the detector.
7 | @export_color_no_alpha var invalid_color := Color.RED
8 | ## Color for when objects are on the detector.
9 | @export_color_no_alpha var valid_color := Color.GREEN
10 |
11 | ## How fast the detector's color pulses.
12 | @export_range(0.1, 1.0) var pulse_frequency := 0.25
13 |
14 | @export var sprite: Sprite2D
15 |
16 | var object_count := 0
17 |
18 | var pulse_progress := 0.0
19 |
20 |
21 | func _init() -> void:
22 | pulse_progress = randf()
23 |
24 |
25 | func _process(delta: float) -> void:
26 | if object_count == 0:
27 | pulse_progress += delta * pulse_frequency
28 | if pulse_progress >= 1.0:
29 | pulse_progress -= 1.0
30 |
31 | var brightness := cos(pulse_progress * TAU) * 0.25 + 0.75
32 | sprite.modulate = Color(
33 | invalid_color.r * brightness,
34 | invalid_color.g * brightness,
35 | invalid_color.b * brightness
36 | )
37 |
38 |
39 | func _on_body_entered(_body: Node2D) -> void:
40 | if object_count == 0:
41 | sprite.modulate = valid_color
42 | validity_changed.emit(true)
43 | object_count += 1
44 |
45 |
46 | func _on_body_exited(_body: Node2D) -> void:
47 | object_count -= 1
48 | if object_count == 0:
49 | pulse_progress = 0.0
50 | validity_changed.emit(false)
51 |
--------------------------------------------------------------------------------
/12-teleporters/detector.gd:
--------------------------------------------------------------------------------
1 | class_name Detector
2 | extends Area2D
3 |
4 | signal validity_changed(valid: bool)
5 |
6 | ## Color for when no objects are on the detector.
7 | @export_color_no_alpha var invalid_color := Color.RED
8 | ## Color for when objects are on the detector.
9 | @export_color_no_alpha var valid_color := Color.GREEN
10 |
11 | ## How fast the detector's color pulses.
12 | @export_range(0.1, 1.0) var pulse_frequency := 0.25
13 |
14 | @export var sprite: Sprite2D
15 |
16 | var object_count := 0
17 |
18 | var pulse_progress := 0.0
19 |
20 |
21 | func _init() -> void:
22 | pulse_progress = randf()
23 |
24 |
25 | func _process(delta: float) -> void:
26 | if object_count == 0:
27 | pulse_progress += delta * pulse_frequency
28 | if pulse_progress >= 1.0:
29 | pulse_progress -= 1.0
30 |
31 | var brightness := cos(pulse_progress * TAU) * 0.25 + 0.75
32 | sprite.modulate = Color(
33 | invalid_color.r * brightness,
34 | invalid_color.g * brightness,
35 | invalid_color.b * brightness
36 | )
37 |
38 |
39 | func _on_body_entered(_body: Node2D) -> void:
40 | if object_count == 0:
41 | sprite.modulate = valid_color
42 | validity_changed.emit(true)
43 | object_count += 1
44 |
45 |
46 | func _on_body_exited(_body: Node2D) -> void:
47 | object_count -= 1
48 | if object_count == 0:
49 | pulse_progress = 0.0
50 | validity_changed.emit(false)
51 |
--------------------------------------------------------------------------------
/6-multiple-maps/detector.gd:
--------------------------------------------------------------------------------
1 | class_name Detector
2 | extends Area2D
3 |
4 | signal validity_changed(valid: bool)
5 |
6 | ## Color for when no objects are on the detector.
7 | @export_color_no_alpha var invalid_color := Color.RED
8 | ## Color for when objects are on the detector.
9 | @export_color_no_alpha var valid_color := Color.GREEN
10 |
11 | ## How fast the detector's color pulses.
12 | @export_range(0.1, 1.0) var pulse_frequency := 0.25
13 |
14 | @export var sprite: Sprite2D
15 |
16 | var object_count := 0
17 |
18 | var pulse_progress := 0.0
19 |
20 |
21 | func _init() -> void:
22 | pulse_progress = randf()
23 |
24 |
25 | func _process(delta: float) -> void:
26 | if object_count == 0:
27 | pulse_progress += delta * pulse_frequency
28 | if pulse_progress >= 1.0:
29 | pulse_progress -= 1.0
30 |
31 | var brightness := cos(pulse_progress * TAU) * 0.25 + 0.75
32 | sprite.modulate = Color(
33 | invalid_color.r * brightness,
34 | invalid_color.g * brightness,
35 | invalid_color.b * brightness
36 | )
37 |
38 |
39 | func _on_body_entered(_body: Node2D) -> void:
40 | if object_count == 0:
41 | sprite.modulate = valid_color
42 | validity_changed.emit(true)
43 | object_count += 1
44 |
45 |
46 | func _on_body_exited(_body: Node2D) -> void:
47 | object_count -= 1
48 | if object_count == 0:
49 | pulse_progress = 0.0
50 | validity_changed.emit(false)
51 |
--------------------------------------------------------------------------------
/10-extra-map-info/detector.gd:
--------------------------------------------------------------------------------
1 | class_name Detector
2 | extends Area2D
3 |
4 | signal validity_changed(valid: bool)
5 |
6 | ## Color for when no objects are on the detector.
7 | @export_color_no_alpha var invalid_color := Color.RED
8 | ## Color for when objects are on the detector.
9 | @export_color_no_alpha var valid_color := Color.GREEN
10 |
11 | ## How fast the detector's color pulses.
12 | @export_range(0.1, 1.0) var pulse_frequency := 0.25
13 |
14 | @export var sprite: Sprite2D
15 |
16 | var object_count := 0
17 |
18 | var pulse_progress := 0.0
19 |
20 |
21 | func _init() -> void:
22 | pulse_progress = randf()
23 |
24 |
25 | func _process(delta: float) -> void:
26 | if object_count == 0:
27 | pulse_progress += delta * pulse_frequency
28 | if pulse_progress >= 1.0:
29 | pulse_progress -= 1.0
30 |
31 | var brightness := cos(pulse_progress * TAU) * 0.25 + 0.75
32 | sprite.modulate = Color(
33 | invalid_color.r * brightness,
34 | invalid_color.g * brightness,
35 | invalid_color.b * brightness
36 | )
37 |
38 |
39 | func _on_body_entered(_body: Node2D) -> void:
40 | if object_count == 0:
41 | sprite.modulate = valid_color
42 | validity_changed.emit(true)
43 | object_count += 1
44 |
45 |
46 | func _on_body_exited(_body: Node2D) -> void:
47 | object_count -= 1
48 | if object_count == 0:
49 | pulse_progress = 0.0
50 | validity_changed.emit(false)
51 |
--------------------------------------------------------------------------------
/7-map-transitions/detector.gd:
--------------------------------------------------------------------------------
1 | class_name Detector
2 | extends Area2D
3 |
4 | signal validity_changed(valid: bool)
5 |
6 | ## Color for when no objects are on the detector.
7 | @export_color_no_alpha var invalid_color := Color.RED
8 | ## Color for when objects are on the detector.
9 | @export_color_no_alpha var valid_color := Color.GREEN
10 |
11 | ## How fast the detector's color pulses.
12 | @export_range(0.1, 1.0) var pulse_frequency := 0.25
13 |
14 | @export var sprite: Sprite2D
15 |
16 | var object_count := 0
17 |
18 | var pulse_progress := 0.0
19 |
20 |
21 | func _init() -> void:
22 | pulse_progress = randf()
23 |
24 |
25 | func _process(delta: float) -> void:
26 | if object_count == 0:
27 | pulse_progress += delta * pulse_frequency
28 | if pulse_progress >= 1.0:
29 | pulse_progress -= 1.0
30 |
31 | var brightness := cos(pulse_progress * TAU) * 0.25 + 0.75
32 | sprite.modulate = Color(
33 | invalid_color.r * brightness,
34 | invalid_color.g * brightness,
35 | invalid_color.b * brightness
36 | )
37 |
38 |
39 | func _on_body_entered(_body: Node2D) -> void:
40 | if object_count == 0:
41 | sprite.modulate = valid_color
42 | validity_changed.emit(true)
43 | object_count += 1
44 |
45 |
46 | func _on_body_exited(_body: Node2D) -> void:
47 | object_count -= 1
48 | if object_count == 0:
49 | pulse_progress = 0.0
50 | validity_changed.emit(false)
51 |
--------------------------------------------------------------------------------
/8-saving-progress/detector.gd:
--------------------------------------------------------------------------------
1 | class_name Detector
2 | extends Area2D
3 |
4 | signal validity_changed(valid: bool)
5 |
6 | ## Color for when no objects are on the detector.
7 | @export_color_no_alpha var invalid_color := Color.RED
8 | ## Color for when objects are on the detector.
9 | @export_color_no_alpha var valid_color := Color.GREEN
10 |
11 | ## How fast the detector's color pulses.
12 | @export_range(0.1, 1.0) var pulse_frequency := 0.25
13 |
14 | @export var sprite: Sprite2D
15 |
16 | var object_count := 0
17 |
18 | var pulse_progress := 0.0
19 |
20 |
21 | func _init() -> void:
22 | pulse_progress = randf()
23 |
24 |
25 | func _process(delta: float) -> void:
26 | if object_count == 0:
27 | pulse_progress += delta * pulse_frequency
28 | if pulse_progress >= 1.0:
29 | pulse_progress -= 1.0
30 |
31 | var brightness := cos(pulse_progress * TAU) * 0.25 + 0.75
32 | sprite.modulate = Color(
33 | invalid_color.r * brightness,
34 | invalid_color.g * brightness,
35 | invalid_color.b * brightness
36 | )
37 |
38 |
39 | func _on_body_entered(_body: Node2D) -> void:
40 | if object_count == 0:
41 | sprite.modulate = valid_color
42 | validity_changed.emit(true)
43 | object_count += 1
44 |
45 |
46 | func _on_body_exited(_body: Node2D) -> void:
47 | object_count -= 1
48 | if object_count == 0:
49 | pulse_progress = 0.0
50 | validity_changed.emit(false)
51 |
--------------------------------------------------------------------------------
/11-showing-best-scores/detector.gd:
--------------------------------------------------------------------------------
1 | class_name Detector
2 | extends Area2D
3 |
4 | signal validity_changed(valid: bool)
5 |
6 | ## Color for when no objects are on the detector.
7 | @export_color_no_alpha var invalid_color := Color.RED
8 | ## Color for when objects are on the detector.
9 | @export_color_no_alpha var valid_color := Color.GREEN
10 |
11 | ## How fast the detector's color pulses.
12 | @export_range(0.1, 1.0) var pulse_frequency := 0.25
13 |
14 | @export var sprite: Sprite2D
15 |
16 | var object_count := 0
17 |
18 | var pulse_progress := 0.0
19 |
20 |
21 | func _init() -> void:
22 | pulse_progress = randf()
23 |
24 |
25 | func _process(delta: float) -> void:
26 | if object_count == 0:
27 | pulse_progress += delta * pulse_frequency
28 | if pulse_progress >= 1.0:
29 | pulse_progress -= 1.0
30 |
31 | var brightness := cos(pulse_progress * TAU) * 0.25 + 0.75
32 | sprite.modulate = Color(
33 | invalid_color.r * brightness,
34 | invalid_color.g * brightness,
35 | invalid_color.b * brightness
36 | )
37 |
38 |
39 | func _on_body_entered(_body: Node2D) -> void:
40 | if object_count == 0:
41 | sprite.modulate = valid_color
42 | validity_changed.emit(true)
43 | object_count += 1
44 |
45 |
46 | func _on_body_exited(_body: Node2D) -> void:
47 | object_count -= 1
48 | if object_count == 0:
49 | pulse_progress = 0.0
50 | validity_changed.emit(false)
51 |
--------------------------------------------------------------------------------
/2-player-character/tile_set.tres:
--------------------------------------------------------------------------------
1 | [gd_resource type="TileSet" load_steps=3 format=3 uid="uid://ct1sg2j0vfyxf"]
2 |
3 | [ext_resource type="Texture2D" uid="uid://brq3awcnk4gep" path="res://tile_set.png" id="1_yp80t"]
4 |
5 | [sub_resource type="TileSetAtlasSource" id="TileSetAtlasSource_6asb7"]
6 | texture = ExtResource("1_yp80t")
7 | 0:0/animation_columns = 2
8 | 0:0/0 = 0
9 | 0:0/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
10 | 1:0/0 = 0
11 | 1:0/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
12 | 2:0/0 = 0
13 | 2:0/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
14 | 0:1/0 = 0
15 | 1:1/0 = 0
16 | 2:1/0 = 0
17 | 0:2/0 = 0
18 | 1:2/0 = 0
19 | 2:2/0 = 0
20 | 0:3/0 = 0
21 | 1:3/0 = 0
22 | 2:3/0 = 0
23 | 0:4/0 = 0
24 | 1:4/0 = 0
25 | 2:4/0 = 0
26 | 0:5/animation_mode = 1
27 | 0:5/animation_frame_0/duration = 1.0
28 | 0:5/animation_frame_1/duration = 1.0
29 | 0:5/0 = 0
30 | 0:5/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
31 | 0:6/animation_mode = 1
32 | 0:6/animation_frame_0/duration = 1.0
33 | 0:6/animation_frame_1/duration = 1.0
34 | 0:6/0 = 0
35 | 0:6/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
36 |
37 | [resource]
38 | physics_layer_0/collision_layer = 1
39 | sources/0 = SubResource("TileSetAtlasSource_6asb7")
40 |
--------------------------------------------------------------------------------
/3-movable-objects/tile_set.tres:
--------------------------------------------------------------------------------
1 | [gd_resource type="TileSet" load_steps=3 format=3 uid="uid://ct1sg2j0vfyxf"]
2 |
3 | [ext_resource type="Texture2D" uid="uid://brq3awcnk4gep" path="res://tile_set.png" id="1_yp80t"]
4 |
5 | [sub_resource type="TileSetAtlasSource" id="TileSetAtlasSource_6asb7"]
6 | texture = ExtResource("1_yp80t")
7 | 0:0/animation_columns = 2
8 | 0:0/0 = 0
9 | 0:0/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
10 | 1:0/0 = 0
11 | 1:0/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
12 | 2:0/0 = 0
13 | 2:0/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
14 | 0:1/0 = 0
15 | 1:1/0 = 0
16 | 2:1/0 = 0
17 | 0:2/0 = 0
18 | 1:2/0 = 0
19 | 2:2/0 = 0
20 | 0:3/0 = 0
21 | 1:3/0 = 0
22 | 2:3/0 = 0
23 | 0:4/0 = 0
24 | 1:4/0 = 0
25 | 2:4/0 = 0
26 | 0:5/animation_mode = 1
27 | 0:5/animation_frame_0/duration = 1.0
28 | 0:5/animation_frame_1/duration = 1.0
29 | 0:5/0 = 0
30 | 0:5/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
31 | 0:6/animation_mode = 1
32 | 0:6/animation_frame_0/duration = 1.0
33 | 0:6/animation_frame_1/duration = 1.0
34 | 0:6/0 = 0
35 | 0:6/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
36 |
37 | [resource]
38 | physics_layer_0/collision_layer = 1
39 | sources/0 = SubResource("TileSetAtlasSource_6asb7")
40 |
--------------------------------------------------------------------------------
/5-detectors/detector.tscn:
--------------------------------------------------------------------------------
1 | [gd_scene load_steps=6 format=3 uid="uid://by76vb4rt7pue"]
2 |
3 | [ext_resource type="Script" path="res://detector.gd" id="1_nqra2"]
4 |
5 | [sub_resource type="RectangleShape2D" id="RectangleShape2D_wgkqt"]
6 | size = Vector2(12, 12)
7 |
8 | [sub_resource type="CanvasItemMaterial" id="CanvasItemMaterial_q0aho"]
9 | light_mode = 1
10 |
11 | [sub_resource type="Gradient" id="Gradient_qyhe4"]
12 | offsets = PackedFloat32Array(0.571429, 1)
13 | colors = PackedColorArray(1, 1, 1, 1, 0, 0, 0, 1)
14 |
15 | [sub_resource type="GradientTexture2D" id="GradientTexture2D_1jt0t"]
16 | gradient = SubResource("Gradient_qyhe4")
17 | width = 12
18 | height = 12
19 | fill = 2
20 | fill_from = Vector2(0.5, 0.5)
21 | fill_to = Vector2(1, 0.5)
22 |
23 | [node name="Detector" type="Area2D" node_paths=PackedStringArray("sprite")]
24 | collision_mask = 2
25 | monitorable = false
26 | script = ExtResource("1_nqra2")
27 | sprite = NodePath("Sprite2D")
28 |
29 | [node name="CollisionShape2D" type="CollisionShape2D" parent="."]
30 | shape = SubResource("RectangleShape2D_wgkqt")
31 |
32 | [node name="Sprite2D" type="Sprite2D" parent="."]
33 | modulate = Color(1, 0, 0, 1)
34 | texture_filter = 1
35 | material = SubResource("CanvasItemMaterial_q0aho")
36 | texture = SubResource("GradientTexture2D_1jt0t")
37 |
38 | [connection signal="body_entered" from="." to="." method="_on_body_entered"]
39 | [connection signal="body_exited" from="." to="." method="_on_body_exited"]
40 |
--------------------------------------------------------------------------------
/6-multiple-maps/detector.tscn:
--------------------------------------------------------------------------------
1 | [gd_scene load_steps=6 format=3 uid="uid://by76vb4rt7pue"]
2 |
3 | [ext_resource type="Script" path="res://detector.gd" id="1_nqra2"]
4 |
5 | [sub_resource type="RectangleShape2D" id="RectangleShape2D_wgkqt"]
6 | size = Vector2(12, 12)
7 |
8 | [sub_resource type="CanvasItemMaterial" id="CanvasItemMaterial_q0aho"]
9 | light_mode = 1
10 |
11 | [sub_resource type="Gradient" id="Gradient_qyhe4"]
12 | offsets = PackedFloat32Array(0.571429, 1)
13 | colors = PackedColorArray(1, 1, 1, 1, 0, 0, 0, 1)
14 |
15 | [sub_resource type="GradientTexture2D" id="GradientTexture2D_1jt0t"]
16 | gradient = SubResource("Gradient_qyhe4")
17 | width = 12
18 | height = 12
19 | fill = 2
20 | fill_from = Vector2(0.5, 0.5)
21 | fill_to = Vector2(1, 0.5)
22 |
23 | [node name="Detector" type="Area2D" node_paths=PackedStringArray("sprite")]
24 | collision_mask = 2
25 | monitorable = false
26 | script = ExtResource("1_nqra2")
27 | sprite = NodePath("Sprite2D")
28 |
29 | [node name="CollisionShape2D" type="CollisionShape2D" parent="."]
30 | shape = SubResource("RectangleShape2D_wgkqt")
31 |
32 | [node name="Sprite2D" type="Sprite2D" parent="."]
33 | modulate = Color(1, 0, 0, 1)
34 | texture_filter = 1
35 | material = SubResource("CanvasItemMaterial_q0aho")
36 | texture = SubResource("GradientTexture2D_1jt0t")
37 |
38 | [connection signal="body_entered" from="." to="." method="_on_body_entered"]
39 | [connection signal="body_exited" from="." to="." method="_on_body_exited"]
40 |
--------------------------------------------------------------------------------
/7-map-transitions/detector.tscn:
--------------------------------------------------------------------------------
1 | [gd_scene load_steps=6 format=3 uid="uid://by76vb4rt7pue"]
2 |
3 | [ext_resource type="Script" path="res://detector.gd" id="1_nqra2"]
4 |
5 | [sub_resource type="RectangleShape2D" id="RectangleShape2D_wgkqt"]
6 | size = Vector2(12, 12)
7 |
8 | [sub_resource type="CanvasItemMaterial" id="CanvasItemMaterial_q0aho"]
9 | light_mode = 1
10 |
11 | [sub_resource type="Gradient" id="Gradient_qyhe4"]
12 | offsets = PackedFloat32Array(0.571429, 1)
13 | colors = PackedColorArray(1, 1, 1, 1, 0, 0, 0, 1)
14 |
15 | [sub_resource type="GradientTexture2D" id="GradientTexture2D_1jt0t"]
16 | gradient = SubResource("Gradient_qyhe4")
17 | width = 12
18 | height = 12
19 | fill = 2
20 | fill_from = Vector2(0.5, 0.5)
21 | fill_to = Vector2(1, 0.5)
22 |
23 | [node name="Detector" type="Area2D" node_paths=PackedStringArray("sprite")]
24 | collision_mask = 2
25 | monitorable = false
26 | script = ExtResource("1_nqra2")
27 | sprite = NodePath("Sprite2D")
28 |
29 | [node name="CollisionShape2D" type="CollisionShape2D" parent="."]
30 | shape = SubResource("RectangleShape2D_wgkqt")
31 |
32 | [node name="Sprite2D" type="Sprite2D" parent="."]
33 | modulate = Color(1, 0, 0, 1)
34 | texture_filter = 1
35 | material = SubResource("CanvasItemMaterial_q0aho")
36 | texture = SubResource("GradientTexture2D_1jt0t")
37 |
38 | [connection signal="body_entered" from="." to="." method="_on_body_entered"]
39 | [connection signal="body_exited" from="." to="." method="_on_body_exited"]
40 |
--------------------------------------------------------------------------------
/9-game-hud/detector.tscn:
--------------------------------------------------------------------------------
1 | [gd_scene load_steps=6 format=3 uid="uid://by76vb4rt7pue"]
2 |
3 | [ext_resource type="Script" uid="uid://cva53g77vgubi" path="res://detector.gd" id="1_nqra2"]
4 |
5 | [sub_resource type="RectangleShape2D" id="RectangleShape2D_wgkqt"]
6 | size = Vector2(12, 12)
7 |
8 | [sub_resource type="CanvasItemMaterial" id="CanvasItemMaterial_q0aho"]
9 | light_mode = 1
10 |
11 | [sub_resource type="Gradient" id="Gradient_qyhe4"]
12 | offsets = PackedFloat32Array(0.571429, 1)
13 | colors = PackedColorArray(1, 1, 1, 1, 0, 0, 0, 1)
14 |
15 | [sub_resource type="GradientTexture2D" id="GradientTexture2D_1jt0t"]
16 | gradient = SubResource("Gradient_qyhe4")
17 | width = 12
18 | height = 12
19 | fill = 2
20 | fill_from = Vector2(0.5, 0.5)
21 | fill_to = Vector2(1, 0.5)
22 |
23 | [node name="Detector" type="Area2D" node_paths=PackedStringArray("sprite")]
24 | collision_mask = 2
25 | monitorable = false
26 | script = ExtResource("1_nqra2")
27 | sprite = NodePath("Sprite2D")
28 |
29 | [node name="CollisionShape2D" type="CollisionShape2D" parent="."]
30 | shape = SubResource("RectangleShape2D_wgkqt")
31 |
32 | [node name="Sprite2D" type="Sprite2D" parent="."]
33 | modulate = Color(1, 0, 0, 1)
34 | texture_filter = 1
35 | material = SubResource("CanvasItemMaterial_q0aho")
36 | texture = SubResource("GradientTexture2D_1jt0t")
37 |
38 | [connection signal="body_entered" from="." to="." method="_on_body_entered"]
39 | [connection signal="body_exited" from="." to="." method="_on_body_exited"]
40 |
--------------------------------------------------------------------------------
/12-teleporters/detector.tscn:
--------------------------------------------------------------------------------
1 | [gd_scene load_steps=6 format=3 uid="uid://by76vb4rt7pue"]
2 |
3 | [ext_resource type="Script" uid="uid://cva53g77vgubi" path="res://detector.gd" id="1_nqra2"]
4 |
5 | [sub_resource type="RectangleShape2D" id="RectangleShape2D_wgkqt"]
6 | size = Vector2(12, 12)
7 |
8 | [sub_resource type="CanvasItemMaterial" id="CanvasItemMaterial_q0aho"]
9 | light_mode = 1
10 |
11 | [sub_resource type="Gradient" id="Gradient_qyhe4"]
12 | offsets = PackedFloat32Array(0.571429, 1)
13 | colors = PackedColorArray(1, 1, 1, 1, 0, 0, 0, 1)
14 |
15 | [sub_resource type="GradientTexture2D" id="GradientTexture2D_1jt0t"]
16 | gradient = SubResource("Gradient_qyhe4")
17 | width = 12
18 | height = 12
19 | fill = 2
20 | fill_from = Vector2(0.5, 0.5)
21 | fill_to = Vector2(1, 0.5)
22 |
23 | [node name="Detector" type="Area2D" node_paths=PackedStringArray("sprite")]
24 | collision_mask = 2
25 | monitorable = false
26 | script = ExtResource("1_nqra2")
27 | sprite = NodePath("Sprite2D")
28 |
29 | [node name="CollisionShape2D" type="CollisionShape2D" parent="."]
30 | shape = SubResource("RectangleShape2D_wgkqt")
31 |
32 | [node name="Sprite2D" type="Sprite2D" parent="."]
33 | modulate = Color(1, 0, 0, 1)
34 | texture_filter = 1
35 | material = SubResource("CanvasItemMaterial_q0aho")
36 | texture = SubResource("GradientTexture2D_1jt0t")
37 |
38 | [connection signal="body_entered" from="." to="." method="_on_body_entered"]
39 | [connection signal="body_exited" from="." to="." method="_on_body_exited"]
40 |
--------------------------------------------------------------------------------
/10-extra-map-info/detector.tscn:
--------------------------------------------------------------------------------
1 | [gd_scene load_steps=6 format=3 uid="uid://by76vb4rt7pue"]
2 |
3 | [ext_resource type="Script" uid="uid://cva53g77vgubi" path="res://detector.gd" id="1_nqra2"]
4 |
5 | [sub_resource type="RectangleShape2D" id="RectangleShape2D_wgkqt"]
6 | size = Vector2(12, 12)
7 |
8 | [sub_resource type="CanvasItemMaterial" id="CanvasItemMaterial_q0aho"]
9 | light_mode = 1
10 |
11 | [sub_resource type="Gradient" id="Gradient_qyhe4"]
12 | offsets = PackedFloat32Array(0.571429, 1)
13 | colors = PackedColorArray(1, 1, 1, 1, 0, 0, 0, 1)
14 |
15 | [sub_resource type="GradientTexture2D" id="GradientTexture2D_1jt0t"]
16 | gradient = SubResource("Gradient_qyhe4")
17 | width = 12
18 | height = 12
19 | fill = 2
20 | fill_from = Vector2(0.5, 0.5)
21 | fill_to = Vector2(1, 0.5)
22 |
23 | [node name="Detector" type="Area2D" node_paths=PackedStringArray("sprite")]
24 | collision_mask = 2
25 | monitorable = false
26 | script = ExtResource("1_nqra2")
27 | sprite = NodePath("Sprite2D")
28 |
29 | [node name="CollisionShape2D" type="CollisionShape2D" parent="."]
30 | shape = SubResource("RectangleShape2D_wgkqt")
31 |
32 | [node name="Sprite2D" type="Sprite2D" parent="."]
33 | modulate = Color(1, 0, 0, 1)
34 | texture_filter = 1
35 | material = SubResource("CanvasItemMaterial_q0aho")
36 | texture = SubResource("GradientTexture2D_1jt0t")
37 |
38 | [connection signal="body_entered" from="." to="." method="_on_body_entered"]
39 | [connection signal="body_exited" from="." to="." method="_on_body_exited"]
40 |
--------------------------------------------------------------------------------
/8-saving-progress/detector.tscn:
--------------------------------------------------------------------------------
1 | [gd_scene load_steps=6 format=3 uid="uid://by76vb4rt7pue"]
2 |
3 | [ext_resource type="Script" uid="uid://cva53g77vgubi" path="res://detector.gd" id="1_nqra2"]
4 |
5 | [sub_resource type="RectangleShape2D" id="RectangleShape2D_wgkqt"]
6 | size = Vector2(12, 12)
7 |
8 | [sub_resource type="CanvasItemMaterial" id="CanvasItemMaterial_q0aho"]
9 | light_mode = 1
10 |
11 | [sub_resource type="Gradient" id="Gradient_qyhe4"]
12 | offsets = PackedFloat32Array(0.571429, 1)
13 | colors = PackedColorArray(1, 1, 1, 1, 0, 0, 0, 1)
14 |
15 | [sub_resource type="GradientTexture2D" id="GradientTexture2D_1jt0t"]
16 | gradient = SubResource("Gradient_qyhe4")
17 | width = 12
18 | height = 12
19 | fill = 2
20 | fill_from = Vector2(0.5, 0.5)
21 | fill_to = Vector2(1, 0.5)
22 |
23 | [node name="Detector" type="Area2D" node_paths=PackedStringArray("sprite")]
24 | collision_mask = 2
25 | monitorable = false
26 | script = ExtResource("1_nqra2")
27 | sprite = NodePath("Sprite2D")
28 |
29 | [node name="CollisionShape2D" type="CollisionShape2D" parent="."]
30 | shape = SubResource("RectangleShape2D_wgkqt")
31 |
32 | [node name="Sprite2D" type="Sprite2D" parent="."]
33 | modulate = Color(1, 0, 0, 1)
34 | texture_filter = 1
35 | material = SubResource("CanvasItemMaterial_q0aho")
36 | texture = SubResource("GradientTexture2D_1jt0t")
37 |
38 | [connection signal="body_entered" from="." to="." method="_on_body_entered"]
39 | [connection signal="body_exited" from="." to="." method="_on_body_exited"]
40 |
--------------------------------------------------------------------------------
/11-showing-best-scores/detector.tscn:
--------------------------------------------------------------------------------
1 | [gd_scene load_steps=6 format=3 uid="uid://by76vb4rt7pue"]
2 |
3 | [ext_resource type="Script" uid="uid://cva53g77vgubi" path="res://detector.gd" id="1_nqra2"]
4 |
5 | [sub_resource type="RectangleShape2D" id="RectangleShape2D_wgkqt"]
6 | size = Vector2(12, 12)
7 |
8 | [sub_resource type="CanvasItemMaterial" id="CanvasItemMaterial_q0aho"]
9 | light_mode = 1
10 |
11 | [sub_resource type="Gradient" id="Gradient_qyhe4"]
12 | offsets = PackedFloat32Array(0.571429, 1)
13 | colors = PackedColorArray(1, 1, 1, 1, 0, 0, 0, 1)
14 |
15 | [sub_resource type="GradientTexture2D" id="GradientTexture2D_1jt0t"]
16 | gradient = SubResource("Gradient_qyhe4")
17 | width = 12
18 | height = 12
19 | fill = 2
20 | fill_from = Vector2(0.5, 0.5)
21 | fill_to = Vector2(1, 0.5)
22 |
23 | [node name="Detector" type="Area2D" node_paths=PackedStringArray("sprite")]
24 | collision_mask = 2
25 | monitorable = false
26 | script = ExtResource("1_nqra2")
27 | sprite = NodePath("Sprite2D")
28 |
29 | [node name="CollisionShape2D" type="CollisionShape2D" parent="."]
30 | shape = SubResource("RectangleShape2D_wgkqt")
31 |
32 | [node name="Sprite2D" type="Sprite2D" parent="."]
33 | modulate = Color(1, 0, 0, 1)
34 | texture_filter = 1
35 | material = SubResource("CanvasItemMaterial_q0aho")
36 | texture = SubResource("GradientTexture2D_1jt0t")
37 |
38 | [connection signal="body_entered" from="." to="." method="_on_body_entered"]
39 | [connection signal="body_exited" from="." to="." method="_on_body_exited"]
40 |
--------------------------------------------------------------------------------
/10-extra-map-info/hud.gd:
--------------------------------------------------------------------------------
1 | extends CanvasLayer
2 |
3 | @export var map_name_label: Label
4 | @export var map_time_label: Label
5 | @export var map_detector_count_label: Label
6 | @export var map_travel_distance: Label
7 | @export var new_best_map_scores_label: Label
8 |
9 |
10 | func _ready() -> void:
11 | visible = false
12 | new_best_map_scores_label.visible = false
13 |
14 |
15 | func show_map_info(map: GameMap) -> void:
16 | map_name_label.text = map.map_name
17 | show_map_time(0.0)
18 | visible = true
19 | new_best_map_scores_label.visible = false
20 |
21 |
22 | func show_map_time(time: float) -> void:
23 | map_time_label.text = "%ds" % time
24 |
25 |
26 | ## Show new best scores, supply -1 to indicate no new best score.
27 | func show_new_best_map_scores(time: int, travel_distance: int) -> void:
28 | var s: String
29 | if time >= 0:
30 | if travel_distance >= 0:
31 | s = (
32 | "New best time: %ds\nNew best travel distance: %dpx" %
33 | [time, travel_distance]
34 | )
35 | else:
36 | s = "New best time: %ds" % time
37 | elif travel_distance >= 0:
38 | s = "New best travel distance: %dpx" % travel_distance
39 | else:
40 | return
41 |
42 | new_best_map_scores_label.text = s
43 | new_best_map_scores_label.visible = true
44 |
45 |
46 | func show_map_detector_count(valid: int, total: int) -> void:
47 | map_detector_count_label.text = "%d / %d" % [valid, total]
48 |
49 |
50 | func show_travel_distance(distance: float) -> void:
51 | map_travel_distance.text = "%dpx" % distance
52 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Changelog
2 |
3 | All notable changes to this project will be documented in this file.
4 |
5 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7 |
8 | ## [1.12.0] - 2025-11-29
9 |
10 | ### Added
11 |
12 | - *12-teleporters*
13 |
14 | ## [1.11.0] - 2025-10-24
15 |
16 | ### Added
17 |
18 | - *11-showing-best-scores*
19 |
20 | ## [1.10.0] - 2025-09-05
21 |
22 | ### Added
23 |
24 | - *10-extra-map-info*
25 |
26 | ## [1.9.0] - 2025-08-22
27 |
28 | ### Added
29 |
30 | - *9-game-hud*
31 |
32 | ## [1.8.0] - 2025-6-28
33 |
34 | ### Added
35 |
36 | - *8-saving-progress*
37 |
38 | ## [1.7.0] - 2025-04-30
39 |
40 | ### Added
41 |
42 | - *7-map-transitions*
43 |
44 | ## Fixed
45 |
46 | - Added missing void function types to *6-multiple-maps*.
47 |
48 | ## [1.6.0] - 2025-02-27
49 |
50 | ### Added
51 |
52 | - *6-multiple-maps*
53 |
54 | ## [1.5.0] - 2024-12-24
55 |
56 | ### Added
57 |
58 | - *5-detectors*
59 |
60 | ## [1.4.0] - 2024-10-24
61 |
62 | ### Added
63 |
64 | - *4-light-and-shadow*
65 |
66 | ## [1.3.0] - 2024-08-28
67 |
68 | ### Added
69 |
70 | - *3-movable-objects*
71 |
72 | ## [1.2.1] - 2024-08-21
73 |
74 | ### Changed
75 |
76 | - Upgraded to Godot 4.3.
77 | - Replaced `TileMap` with `TileMapLayer`.
78 |
79 | ## [1.2.0] - 2024-06-27
80 |
81 | ### Added
82 |
83 | - *2-player-character*
84 |
85 | ## [1.1.0] - 2024-04-30
86 |
87 | ### Added
88 |
89 | - *1-tile-map*.
90 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # True Top-Down 2D
2 |
3 | [This is a tutorial series](https://catlikecoding.com/godot/true-top-down-2d/) that goes through the process of creating a simple true top-down 2D game with Godot Engine 4.
4 |
5 | This series is aimed at beginners who are completely new to game development, but more advanced developers that are new to Godot will also find it useful.
6 |
7 | It is assumed that you went through the [Introduction series](https://catlikecoding.com/godot/introduction) or are familiar with Godot Engine 4.
8 |
9 | Each Individual tutorial has its own numbered folder.
10 |
11 | ## Tutorials
12 |
13 | 1. [Tile Map](https://catlikecoding.com/godot/true-top-down-2d/1-tile-map/)
14 | 2. [Player Character](https://catlikecoding.com/godot/true-top-down-2d/2-player-character/)
15 | 3. [Movable Objects](https://catlikecoding.com/godot/true-top-down-2d/3-movable-objects/)
16 | 4. [Light and Shadow](https://catlikecoding.com/godot/true-top-down-2d/4-light-and-shadow/)
17 | 5. [Detectors](https://catlikecoding.com/godot/true-top-down-2d/5-detectors/)
18 | 6. [Multiple Maps](https://catlikecoding.com/godot/true-top-down-2d/6-multiple-maps/)
19 | 7. [Map Transitions](https://catlikecoding.com/godot/true-top-down-2d/7-map-transitions/)
20 | 8. [Saving Progress](https://catlikecoding.com/godot/true-top-down-2d/8-saving-progress/)
21 | 9. [Game HUD](https://catlikecoding.com/godot/true-top-down-2d/9-game-hud/)
22 |
23 | This is a work in progress. More parts will be added in due time.
24 |
25 | ## Giving Credit
26 |
27 | If you want to credit me in your work you can do so by mentioning [Jasper Flick](https://catlikecoding.com/jasper-flick/) and/or [Catlike Coding](https://catlikecoding.com).
28 |
--------------------------------------------------------------------------------
/5-detectors/tile_set.tres:
--------------------------------------------------------------------------------
1 | [gd_resource type="TileSet" load_steps=5 format=3 uid="uid://ct1sg2j0vfyxf"]
2 |
3 | [ext_resource type="Texture2D" uid="uid://brq3awcnk4gep" path="res://tile_set.png" id="1_yp80t"]
4 |
5 | [sub_resource type="OccluderPolygon2D" id="OccluderPolygon2D_7ogig"]
6 | polygon = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
7 |
8 | [sub_resource type="OccluderPolygon2D" id="OccluderPolygon2D_co04c"]
9 | polygon = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
10 |
11 | [sub_resource type="TileSetAtlasSource" id="TileSetAtlasSource_6asb7"]
12 | texture = ExtResource("1_yp80t")
13 | 0:0/animation_columns = 2
14 | 0:0/0 = 0
15 | 0:0/0/occlusion_layer_0/polygon = SubResource("OccluderPolygon2D_7ogig")
16 | 0:0/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
17 | 1:0/0 = 0
18 | 1:0/0/occlusion_layer_0/polygon = SubResource("OccluderPolygon2D_co04c")
19 | 1:0/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
20 | 2:0/0 = 0
21 | 2:0/0/occlusion_layer_0/polygon = SubResource("OccluderPolygon2D_co04c")
22 | 2:0/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
23 | 0:1/0 = 0
24 | 1:1/0 = 0
25 | 2:1/0 = 0
26 | 0:2/0 = 0
27 | 1:2/0 = 0
28 | 2:2/0 = 0
29 | 0:3/0 = 0
30 | 1:3/0 = 0
31 | 2:3/0 = 0
32 | 0:4/0 = 0
33 | 1:4/0 = 0
34 | 2:4/0 = 0
35 | 0:5/animation_mode = 1
36 | 0:5/animation_frame_0/duration = 1.0
37 | 0:5/animation_frame_1/duration = 1.0
38 | 0:5/0 = 0
39 | 0:5/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
40 | 0:6/animation_mode = 1
41 | 0:6/animation_frame_0/duration = 1.0
42 | 0:6/animation_frame_1/duration = 1.0
43 | 0:6/0 = 0
44 | 0:6/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
45 |
46 | [resource]
47 | occlusion_layer_0/light_mask = 3
48 | physics_layer_0/collision_layer = 1
49 | sources/0 = SubResource("TileSetAtlasSource_6asb7")
50 |
--------------------------------------------------------------------------------
/6-multiple-maps/tile_set.tres:
--------------------------------------------------------------------------------
1 | [gd_resource type="TileSet" load_steps=5 format=3 uid="uid://ct1sg2j0vfyxf"]
2 |
3 | [ext_resource type="Texture2D" uid="uid://brq3awcnk4gep" path="res://tile_set.png" id="1_yp80t"]
4 |
5 | [sub_resource type="OccluderPolygon2D" id="OccluderPolygon2D_7ogig"]
6 | polygon = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
7 |
8 | [sub_resource type="OccluderPolygon2D" id="OccluderPolygon2D_co04c"]
9 | polygon = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
10 |
11 | [sub_resource type="TileSetAtlasSource" id="TileSetAtlasSource_6asb7"]
12 | texture = ExtResource("1_yp80t")
13 | 0:0/animation_columns = 2
14 | 0:0/0 = 0
15 | 0:0/0/occlusion_layer_0/polygon = SubResource("OccluderPolygon2D_7ogig")
16 | 0:0/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
17 | 1:0/0 = 0
18 | 1:0/0/occlusion_layer_0/polygon = SubResource("OccluderPolygon2D_co04c")
19 | 1:0/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
20 | 2:0/0 = 0
21 | 2:0/0/occlusion_layer_0/polygon = SubResource("OccluderPolygon2D_co04c")
22 | 2:0/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
23 | 0:1/0 = 0
24 | 1:1/0 = 0
25 | 2:1/0 = 0
26 | 0:2/0 = 0
27 | 1:2/0 = 0
28 | 2:2/0 = 0
29 | 0:3/0 = 0
30 | 1:3/0 = 0
31 | 2:3/0 = 0
32 | 0:4/0 = 0
33 | 1:4/0 = 0
34 | 2:4/0 = 0
35 | 0:5/animation_mode = 1
36 | 0:5/animation_frame_0/duration = 1.0
37 | 0:5/animation_frame_1/duration = 1.0
38 | 0:5/0 = 0
39 | 0:5/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
40 | 0:6/animation_mode = 1
41 | 0:6/animation_frame_0/duration = 1.0
42 | 0:6/animation_frame_1/duration = 1.0
43 | 0:6/0 = 0
44 | 0:6/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
45 |
46 | [resource]
47 | occlusion_layer_0/light_mask = 3
48 | physics_layer_0/collision_layer = 1
49 | sources/0 = SubResource("TileSetAtlasSource_6asb7")
50 |
--------------------------------------------------------------------------------
/7-map-transitions/tile_set.tres:
--------------------------------------------------------------------------------
1 | [gd_resource type="TileSet" load_steps=5 format=3 uid="uid://ct1sg2j0vfyxf"]
2 |
3 | [ext_resource type="Texture2D" uid="uid://brq3awcnk4gep" path="res://tile_set.png" id="1_yp80t"]
4 |
5 | [sub_resource type="OccluderPolygon2D" id="OccluderPolygon2D_7ogig"]
6 | polygon = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
7 |
8 | [sub_resource type="OccluderPolygon2D" id="OccluderPolygon2D_co04c"]
9 | polygon = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
10 |
11 | [sub_resource type="TileSetAtlasSource" id="TileSetAtlasSource_6asb7"]
12 | texture = ExtResource("1_yp80t")
13 | 0:0/animation_columns = 2
14 | 0:0/0 = 0
15 | 0:0/0/occlusion_layer_0/polygon = SubResource("OccluderPolygon2D_7ogig")
16 | 0:0/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
17 | 1:0/0 = 0
18 | 1:0/0/occlusion_layer_0/polygon = SubResource("OccluderPolygon2D_co04c")
19 | 1:0/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
20 | 2:0/0 = 0
21 | 2:0/0/occlusion_layer_0/polygon = SubResource("OccluderPolygon2D_co04c")
22 | 2:0/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
23 | 0:1/0 = 0
24 | 1:1/0 = 0
25 | 2:1/0 = 0
26 | 0:2/0 = 0
27 | 1:2/0 = 0
28 | 2:2/0 = 0
29 | 0:3/0 = 0
30 | 1:3/0 = 0
31 | 2:3/0 = 0
32 | 0:4/0 = 0
33 | 1:4/0 = 0
34 | 2:4/0 = 0
35 | 0:5/animation_mode = 1
36 | 0:5/animation_frame_0/duration = 1.0
37 | 0:5/animation_frame_1/duration = 1.0
38 | 0:5/0 = 0
39 | 0:5/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
40 | 0:6/animation_mode = 1
41 | 0:6/animation_frame_0/duration = 1.0
42 | 0:6/animation_frame_1/duration = 1.0
43 | 0:6/0 = 0
44 | 0:6/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
45 |
46 | [resource]
47 | occlusion_layer_0/light_mask = 3
48 | physics_layer_0/collision_layer = 1
49 | sources/0 = SubResource("TileSetAtlasSource_6asb7")
50 |
--------------------------------------------------------------------------------
/4-light-and-shadow/tile_set.tres:
--------------------------------------------------------------------------------
1 | [gd_resource type="TileSet" load_steps=5 format=3 uid="uid://ct1sg2j0vfyxf"]
2 |
3 | [ext_resource type="Texture2D" uid="uid://brq3awcnk4gep" path="res://tile_set.png" id="1_yp80t"]
4 |
5 | [sub_resource type="OccluderPolygon2D" id="OccluderPolygon2D_7ogig"]
6 | polygon = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
7 |
8 | [sub_resource type="OccluderPolygon2D" id="OccluderPolygon2D_co04c"]
9 | polygon = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
10 |
11 | [sub_resource type="TileSetAtlasSource" id="TileSetAtlasSource_6asb7"]
12 | texture = ExtResource("1_yp80t")
13 | 0:0/animation_columns = 2
14 | 0:0/0 = 0
15 | 0:0/0/occlusion_layer_0/polygon = SubResource("OccluderPolygon2D_7ogig")
16 | 0:0/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
17 | 1:0/0 = 0
18 | 1:0/0/occlusion_layer_0/polygon = SubResource("OccluderPolygon2D_co04c")
19 | 1:0/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
20 | 2:0/0 = 0
21 | 2:0/0/occlusion_layer_0/polygon = SubResource("OccluderPolygon2D_co04c")
22 | 2:0/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
23 | 0:1/0 = 0
24 | 1:1/0 = 0
25 | 2:1/0 = 0
26 | 0:2/0 = 0
27 | 1:2/0 = 0
28 | 2:2/0 = 0
29 | 0:3/0 = 0
30 | 1:3/0 = 0
31 | 2:3/0 = 0
32 | 0:4/0 = 0
33 | 1:4/0 = 0
34 | 2:4/0 = 0
35 | 0:5/animation_mode = 1
36 | 0:5/animation_frame_0/duration = 1.0
37 | 0:5/animation_frame_1/duration = 1.0
38 | 0:5/0 = 0
39 | 0:5/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
40 | 0:6/animation_mode = 1
41 | 0:6/animation_frame_0/duration = 1.0
42 | 0:6/animation_frame_1/duration = 1.0
43 | 0:6/0 = 0
44 | 0:6/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
45 |
46 | [resource]
47 | occlusion_layer_0/light_mask = 3
48 | physics_layer_0/collision_layer = 1
49 | sources/0 = SubResource("TileSetAtlasSource_6asb7")
50 |
--------------------------------------------------------------------------------
/9-game-hud/main_menu.tscn:
--------------------------------------------------------------------------------
1 | [gd_scene load_steps=3 format=3 uid="uid://bk1rkxiuhfn52"]
2 |
3 | [ext_resource type="Script" uid="uid://b53qr6le0v04" path="res://main_menu.gd" id="1_06t4h"]
4 | [ext_resource type="PackedScene" uid="uid://df6uf8hq8mdjn" path="res://maps/map.001.tscn" id="2_7vrkn"]
5 |
6 | [node name="MainMenu" type="Control" node_paths=PackedStringArray("continue_button")]
7 | custom_minimum_size = Vector2(100, 80)
8 | layout_mode = 3
9 | anchors_preset = 8
10 | anchor_left = 0.5
11 | anchor_top = 0.5
12 | anchor_right = 0.5
13 | anchor_bottom = 0.5
14 | offset_left = -50.0
15 | offset_top = -40.0
16 | offset_right = 50.0
17 | offset_bottom = 40.0
18 | grow_horizontal = 2
19 | grow_vertical = 2
20 | script = ExtResource("1_06t4h")
21 | first_map = ExtResource("2_7vrkn")
22 | continue_button = NodePath("MenuButtons/ContinueButton")
23 |
24 | [node name="MenuButtons" type="Control" parent="."]
25 | custom_minimum_size = Vector2(100, 80)
26 | layout_mode = 1
27 | anchors_preset = 8
28 | anchor_left = 0.5
29 | anchor_top = 0.5
30 | anchor_right = 0.5
31 | anchor_bottom = 0.5
32 | offset_left = -50.0
33 | offset_top = -40.0
34 | offset_right = 50.0
35 | offset_bottom = 40.0
36 | grow_horizontal = 2
37 | grow_vertical = 2
38 |
39 | [node name="NewGameButton" type="Button" parent="MenuButtons"]
40 | layout_mode = 1
41 | anchors_preset = 10
42 | anchor_right = 1.0
43 | offset_bottom = 31.0
44 | grow_horizontal = 2
45 | text = "New Game"
46 |
47 | [node name="ContinueButton" type="Button" parent="MenuButtons"]
48 | layout_mode = 1
49 | anchors_preset = 12
50 | anchor_top = 1.0
51 | anchor_right = 1.0
52 | anchor_bottom = 1.0
53 | offset_top = -31.0
54 | grow_horizontal = 2
55 | grow_vertical = 0
56 | text = "Continue"
57 |
58 | [connection signal="pressed" from="MenuButtons/NewGameButton" to="." method="_on_new_game_button_pressed"]
59 | [connection signal="pressed" from="MenuButtons/ContinueButton" to="." method="_on_continue_button_pressed"]
60 |
--------------------------------------------------------------------------------
/10-extra-map-info/main_menu.tscn:
--------------------------------------------------------------------------------
1 | [gd_scene load_steps=3 format=3 uid="uid://bk1rkxiuhfn52"]
2 |
3 | [ext_resource type="Script" uid="uid://b53qr6le0v04" path="res://main_menu.gd" id="1_06t4h"]
4 | [ext_resource type="PackedScene" uid="uid://df6uf8hq8mdjn" path="res://maps/map.001.tscn" id="2_7vrkn"]
5 |
6 | [node name="MainMenu" type="Control" node_paths=PackedStringArray("continue_button")]
7 | custom_minimum_size = Vector2(100, 80)
8 | layout_mode = 3
9 | anchors_preset = 8
10 | anchor_left = 0.5
11 | anchor_top = 0.5
12 | anchor_right = 0.5
13 | anchor_bottom = 0.5
14 | offset_left = -50.0
15 | offset_top = -40.0
16 | offset_right = 50.0
17 | offset_bottom = 40.0
18 | grow_horizontal = 2
19 | grow_vertical = 2
20 | script = ExtResource("1_06t4h")
21 | first_map = ExtResource("2_7vrkn")
22 | continue_button = NodePath("MenuButtons/ContinueButton")
23 |
24 | [node name="MenuButtons" type="Control" parent="."]
25 | custom_minimum_size = Vector2(100, 80)
26 | layout_mode = 1
27 | anchors_preset = 8
28 | anchor_left = 0.5
29 | anchor_top = 0.5
30 | anchor_right = 0.5
31 | anchor_bottom = 0.5
32 | offset_left = -50.0
33 | offset_top = -40.0
34 | offset_right = 50.0
35 | offset_bottom = 40.0
36 | grow_horizontal = 2
37 | grow_vertical = 2
38 |
39 | [node name="NewGameButton" type="Button" parent="MenuButtons"]
40 | layout_mode = 1
41 | anchors_preset = 10
42 | anchor_right = 1.0
43 | offset_bottom = 31.0
44 | grow_horizontal = 2
45 | text = "New Game"
46 |
47 | [node name="ContinueButton" type="Button" parent="MenuButtons"]
48 | layout_mode = 1
49 | anchors_preset = 12
50 | anchor_top = 1.0
51 | anchor_right = 1.0
52 | anchor_bottom = 1.0
53 | offset_top = -31.0
54 | grow_horizontal = 2
55 | grow_vertical = 0
56 | text = "Continue"
57 |
58 | [connection signal="pressed" from="MenuButtons/NewGameButton" to="." method="_on_new_game_button_pressed"]
59 | [connection signal="pressed" from="MenuButtons/ContinueButton" to="." method="_on_continue_button_pressed"]
60 |
--------------------------------------------------------------------------------
/12-teleporters/main_menu.tscn:
--------------------------------------------------------------------------------
1 | [gd_scene load_steps=3 format=3 uid="uid://bk1rkxiuhfn52"]
2 |
3 | [ext_resource type="Script" uid="uid://b53qr6le0v04" path="res://main_menu.gd" id="1_06t4h"]
4 | [ext_resource type="PackedScene" uid="uid://df6uf8hq8mdjn" path="res://maps/map.001.tscn" id="2_7vrkn"]
5 |
6 | [node name="MainMenu" type="Control" node_paths=PackedStringArray("continue_button")]
7 | custom_minimum_size = Vector2(100, 80)
8 | layout_mode = 3
9 | anchors_preset = 8
10 | anchor_left = 0.5
11 | anchor_top = 0.5
12 | anchor_right = 0.5
13 | anchor_bottom = 0.5
14 | offset_left = -50.0
15 | offset_top = -40.0
16 | offset_right = 50.0
17 | offset_bottom = 40.0
18 | grow_horizontal = 2
19 | grow_vertical = 2
20 | script = ExtResource("1_06t4h")
21 | first_map = ExtResource("2_7vrkn")
22 | continue_button = NodePath("MenuButtons/ContinueButton")
23 |
24 | [node name="MenuButtons" type="Control" parent="."]
25 | custom_minimum_size = Vector2(100, 80)
26 | layout_mode = 1
27 | anchors_preset = 8
28 | anchor_left = 0.5
29 | anchor_top = 0.5
30 | anchor_right = 0.5
31 | anchor_bottom = 0.5
32 | offset_left = -50.0
33 | offset_top = -40.0
34 | offset_right = 50.0
35 | offset_bottom = 40.0
36 | grow_horizontal = 2
37 | grow_vertical = 2
38 |
39 | [node name="NewGameButton" type="Button" parent="MenuButtons"]
40 | layout_mode = 1
41 | anchors_preset = 10
42 | anchor_right = 1.0
43 | offset_bottom = 31.0
44 | grow_horizontal = 2
45 | text = "New Game"
46 |
47 | [node name="ContinueButton" type="Button" parent="MenuButtons"]
48 | layout_mode = 1
49 | anchors_preset = 12
50 | anchor_top = 1.0
51 | anchor_right = 1.0
52 | anchor_bottom = 1.0
53 | offset_top = -31.0
54 | grow_horizontal = 2
55 | grow_vertical = 0
56 | text = "Continue"
57 |
58 | [connection signal="pressed" from="MenuButtons/NewGameButton" to="." method="_on_new_game_button_pressed"]
59 | [connection signal="pressed" from="MenuButtons/ContinueButton" to="." method="_on_continue_button_pressed"]
60 |
--------------------------------------------------------------------------------
/11-showing-best-scores/main_menu.tscn:
--------------------------------------------------------------------------------
1 | [gd_scene load_steps=3 format=3 uid="uid://bk1rkxiuhfn52"]
2 |
3 | [ext_resource type="Script" uid="uid://b53qr6le0v04" path="res://main_menu.gd" id="1_06t4h"]
4 | [ext_resource type="PackedScene" uid="uid://df6uf8hq8mdjn" path="res://maps/map.001.tscn" id="2_7vrkn"]
5 |
6 | [node name="MainMenu" type="Control" node_paths=PackedStringArray("continue_button")]
7 | custom_minimum_size = Vector2(100, 80)
8 | layout_mode = 3
9 | anchors_preset = 8
10 | anchor_left = 0.5
11 | anchor_top = 0.5
12 | anchor_right = 0.5
13 | anchor_bottom = 0.5
14 | offset_left = -50.0
15 | offset_top = -40.0
16 | offset_right = 50.0
17 | offset_bottom = 40.0
18 | grow_horizontal = 2
19 | grow_vertical = 2
20 | script = ExtResource("1_06t4h")
21 | first_map = ExtResource("2_7vrkn")
22 | continue_button = NodePath("MenuButtons/ContinueButton")
23 |
24 | [node name="MenuButtons" type="Control" parent="."]
25 | custom_minimum_size = Vector2(100, 80)
26 | layout_mode = 1
27 | anchors_preset = 8
28 | anchor_left = 0.5
29 | anchor_top = 0.5
30 | anchor_right = 0.5
31 | anchor_bottom = 0.5
32 | offset_left = -50.0
33 | offset_top = -40.0
34 | offset_right = 50.0
35 | offset_bottom = 40.0
36 | grow_horizontal = 2
37 | grow_vertical = 2
38 |
39 | [node name="NewGameButton" type="Button" parent="MenuButtons"]
40 | layout_mode = 1
41 | anchors_preset = 10
42 | anchor_right = 1.0
43 | offset_bottom = 31.0
44 | grow_horizontal = 2
45 | text = "New Game"
46 |
47 | [node name="ContinueButton" type="Button" parent="MenuButtons"]
48 | layout_mode = 1
49 | anchors_preset = 12
50 | anchor_top = 1.0
51 | anchor_right = 1.0
52 | anchor_bottom = 1.0
53 | offset_top = -31.0
54 | grow_horizontal = 2
55 | grow_vertical = 0
56 | text = "Continue"
57 |
58 | [connection signal="pressed" from="MenuButtons/NewGameButton" to="." method="_on_new_game_button_pressed"]
59 | [connection signal="pressed" from="MenuButtons/ContinueButton" to="." method="_on_continue_button_pressed"]
60 |
--------------------------------------------------------------------------------
/9-game-hud/tile_set.tres:
--------------------------------------------------------------------------------
1 | [gd_resource type="TileSet" load_steps=5 format=3 uid="uid://ct1sg2j0vfyxf"]
2 |
3 | [ext_resource type="Texture2D" uid="uid://brq3awcnk4gep" path="res://tile_set.png" id="1_yp80t"]
4 |
5 | [sub_resource type="OccluderPolygon2D" id="OccluderPolygon2D_7ogig"]
6 | polygon = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
7 |
8 | [sub_resource type="OccluderPolygon2D" id="OccluderPolygon2D_co04c"]
9 | polygon = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
10 |
11 | [sub_resource type="TileSetAtlasSource" id="TileSetAtlasSource_6asb7"]
12 | texture = ExtResource("1_yp80t")
13 | 0:0/animation_columns = 2
14 | 0:0/0 = 0
15 | 0:0/0/occlusion_layer_0/polygon_0/polygon = SubResource("OccluderPolygon2D_7ogig")
16 | 0:0/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
17 | 1:0/0 = 0
18 | 1:0/0/occlusion_layer_0/polygon_0/polygon = SubResource("OccluderPolygon2D_co04c")
19 | 1:0/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
20 | 2:0/0 = 0
21 | 2:0/0/occlusion_layer_0/polygon_0/polygon = SubResource("OccluderPolygon2D_co04c")
22 | 2:0/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
23 | 0:1/0 = 0
24 | 1:1/0 = 0
25 | 2:1/0 = 0
26 | 0:2/0 = 0
27 | 1:2/0 = 0
28 | 2:2/0 = 0
29 | 0:3/0 = 0
30 | 1:3/0 = 0
31 | 2:3/0 = 0
32 | 0:4/0 = 0
33 | 1:4/0 = 0
34 | 2:4/0 = 0
35 | 0:5/animation_mode = 1
36 | 0:5/animation_frame_0/duration = 1.0
37 | 0:5/animation_frame_1/duration = 1.0
38 | 0:5/0 = 0
39 | 0:5/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
40 | 0:6/animation_mode = 1
41 | 0:6/animation_frame_0/duration = 1.0
42 | 0:6/animation_frame_1/duration = 1.0
43 | 0:6/0 = 0
44 | 0:6/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
45 |
46 | [resource]
47 | occlusion_layer_0/light_mask = 3
48 | physics_layer_0/collision_layer = 1
49 | sources/0 = SubResource("TileSetAtlasSource_6asb7")
50 |
--------------------------------------------------------------------------------
/10-extra-map-info/tile_set.tres:
--------------------------------------------------------------------------------
1 | [gd_resource type="TileSet" load_steps=5 format=3 uid="uid://ct1sg2j0vfyxf"]
2 |
3 | [ext_resource type="Texture2D" uid="uid://brq3awcnk4gep" path="res://tile_set.png" id="1_yp80t"]
4 |
5 | [sub_resource type="OccluderPolygon2D" id="OccluderPolygon2D_7ogig"]
6 | polygon = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
7 |
8 | [sub_resource type="OccluderPolygon2D" id="OccluderPolygon2D_co04c"]
9 | polygon = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
10 |
11 | [sub_resource type="TileSetAtlasSource" id="TileSetAtlasSource_6asb7"]
12 | texture = ExtResource("1_yp80t")
13 | 0:0/animation_columns = 2
14 | 0:0/0 = 0
15 | 0:0/0/occlusion_layer_0/polygon_0/polygon = SubResource("OccluderPolygon2D_7ogig")
16 | 0:0/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
17 | 1:0/0 = 0
18 | 1:0/0/occlusion_layer_0/polygon_0/polygon = SubResource("OccluderPolygon2D_co04c")
19 | 1:0/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
20 | 2:0/0 = 0
21 | 2:0/0/occlusion_layer_0/polygon_0/polygon = SubResource("OccluderPolygon2D_co04c")
22 | 2:0/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
23 | 0:1/0 = 0
24 | 1:1/0 = 0
25 | 2:1/0 = 0
26 | 0:2/0 = 0
27 | 1:2/0 = 0
28 | 2:2/0 = 0
29 | 0:3/0 = 0
30 | 1:3/0 = 0
31 | 2:3/0 = 0
32 | 0:4/0 = 0
33 | 1:4/0 = 0
34 | 2:4/0 = 0
35 | 0:5/animation_mode = 1
36 | 0:5/animation_frame_0/duration = 1.0
37 | 0:5/animation_frame_1/duration = 1.0
38 | 0:5/0 = 0
39 | 0:5/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
40 | 0:6/animation_mode = 1
41 | 0:6/animation_frame_0/duration = 1.0
42 | 0:6/animation_frame_1/duration = 1.0
43 | 0:6/0 = 0
44 | 0:6/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
45 |
46 | [resource]
47 | occlusion_layer_0/light_mask = 3
48 | physics_layer_0/collision_layer = 1
49 | sources/0 = SubResource("TileSetAtlasSource_6asb7")
50 |
--------------------------------------------------------------------------------
/12-teleporters/tile_set.tres:
--------------------------------------------------------------------------------
1 | [gd_resource type="TileSet" load_steps=5 format=3 uid="uid://ct1sg2j0vfyxf"]
2 |
3 | [ext_resource type="Texture2D" uid="uid://brq3awcnk4gep" path="res://tile_set.png" id="1_yp80t"]
4 |
5 | [sub_resource type="OccluderPolygon2D" id="OccluderPolygon2D_7ogig"]
6 | polygon = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
7 |
8 | [sub_resource type="OccluderPolygon2D" id="OccluderPolygon2D_co04c"]
9 | polygon = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
10 |
11 | [sub_resource type="TileSetAtlasSource" id="TileSetAtlasSource_6asb7"]
12 | texture = ExtResource("1_yp80t")
13 | 0:0/animation_columns = 2
14 | 0:0/0 = 0
15 | 0:0/0/occlusion_layer_0/polygon_0/polygon = SubResource("OccluderPolygon2D_7ogig")
16 | 0:0/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
17 | 1:0/0 = 0
18 | 1:0/0/occlusion_layer_0/polygon_0/polygon = SubResource("OccluderPolygon2D_co04c")
19 | 1:0/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
20 | 2:0/0 = 0
21 | 2:0/0/occlusion_layer_0/polygon_0/polygon = SubResource("OccluderPolygon2D_co04c")
22 | 2:0/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
23 | 0:1/0 = 0
24 | 1:1/0 = 0
25 | 2:1/0 = 0
26 | 0:2/0 = 0
27 | 1:2/0 = 0
28 | 2:2/0 = 0
29 | 0:3/0 = 0
30 | 1:3/0 = 0
31 | 2:3/0 = 0
32 | 0:4/0 = 0
33 | 1:4/0 = 0
34 | 2:4/0 = 0
35 | 0:5/animation_mode = 1
36 | 0:5/animation_frame_0/duration = 1.0
37 | 0:5/animation_frame_1/duration = 1.0
38 | 0:5/0 = 0
39 | 0:5/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
40 | 0:6/animation_mode = 1
41 | 0:6/animation_frame_0/duration = 1.0
42 | 0:6/animation_frame_1/duration = 1.0
43 | 0:6/0 = 0
44 | 0:6/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
45 |
46 | [resource]
47 | occlusion_layer_0/light_mask = 3
48 | physics_layer_0/collision_layer = 1
49 | sources/0 = SubResource("TileSetAtlasSource_6asb7")
50 |
--------------------------------------------------------------------------------
/8-saving-progress/main_menu.tscn:
--------------------------------------------------------------------------------
1 | [gd_scene load_steps=3 format=3 uid="uid://bk1rkxiuhfn52"]
2 |
3 | [ext_resource type="Script" uid="uid://b53qr6le0v04" path="res://main_menu.gd" id="1_06t4h"]
4 | [ext_resource type="PackedScene" uid="uid://df6uf8hq8mdjn" path="res://maps/map.001.tscn" id="2_7vrkn"]
5 |
6 | [node name="Main Menu" type="Control" node_paths=PackedStringArray("continue_button")]
7 | custom_minimum_size = Vector2(100, 80)
8 | layout_mode = 3
9 | anchors_preset = 8
10 | anchor_left = 0.5
11 | anchor_top = 0.5
12 | anchor_right = 0.5
13 | anchor_bottom = 0.5
14 | offset_left = -50.0
15 | offset_top = -40.0
16 | offset_right = 50.0
17 | offset_bottom = 40.0
18 | grow_horizontal = 2
19 | grow_vertical = 2
20 | script = ExtResource("1_06t4h")
21 | first_map = ExtResource("2_7vrkn")
22 | continue_button = NodePath("Menu Buttons/Continue Button")
23 |
24 | [node name="Menu Buttons" type="Control" parent="."]
25 | custom_minimum_size = Vector2(100, 80)
26 | layout_mode = 1
27 | anchors_preset = 8
28 | anchor_left = 0.5
29 | anchor_top = 0.5
30 | anchor_right = 0.5
31 | anchor_bottom = 0.5
32 | offset_left = -50.0
33 | offset_top = -40.0
34 | offset_right = 50.0
35 | offset_bottom = 40.0
36 | grow_horizontal = 2
37 | grow_vertical = 2
38 |
39 | [node name="New Game Button" type="Button" parent="Menu Buttons"]
40 | layout_mode = 1
41 | anchors_preset = 10
42 | anchor_right = 1.0
43 | offset_bottom = 31.0
44 | grow_horizontal = 2
45 | text = "New Game"
46 |
47 | [node name="Continue Button" type="Button" parent="Menu Buttons"]
48 | layout_mode = 1
49 | anchors_preset = 12
50 | anchor_top = 1.0
51 | anchor_right = 1.0
52 | anchor_bottom = 1.0
53 | offset_top = -31.0
54 | grow_horizontal = 2
55 | grow_vertical = 0
56 | text = "Continue"
57 |
58 | [connection signal="pressed" from="Menu Buttons/New Game Button" to="." method="_on_new_game_button_pressed"]
59 | [connection signal="pressed" from="Menu Buttons/Continue Button" to="." method="_on_continue_button_pressed"]
60 |
--------------------------------------------------------------------------------
/8-saving-progress/tile_set.tres:
--------------------------------------------------------------------------------
1 | [gd_resource type="TileSet" load_steps=5 format=3 uid="uid://ct1sg2j0vfyxf"]
2 |
3 | [ext_resource type="Texture2D" uid="uid://brq3awcnk4gep" path="res://tile_set.png" id="1_yp80t"]
4 |
5 | [sub_resource type="OccluderPolygon2D" id="OccluderPolygon2D_7ogig"]
6 | polygon = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
7 |
8 | [sub_resource type="OccluderPolygon2D" id="OccluderPolygon2D_co04c"]
9 | polygon = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
10 |
11 | [sub_resource type="TileSetAtlasSource" id="TileSetAtlasSource_6asb7"]
12 | texture = ExtResource("1_yp80t")
13 | 0:0/animation_columns = 2
14 | 0:0/0 = 0
15 | 0:0/0/occlusion_layer_0/polygon_0/polygon = SubResource("OccluderPolygon2D_7ogig")
16 | 0:0/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
17 | 1:0/0 = 0
18 | 1:0/0/occlusion_layer_0/polygon_0/polygon = SubResource("OccluderPolygon2D_co04c")
19 | 1:0/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
20 | 2:0/0 = 0
21 | 2:0/0/occlusion_layer_0/polygon_0/polygon = SubResource("OccluderPolygon2D_co04c")
22 | 2:0/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
23 | 0:1/0 = 0
24 | 1:1/0 = 0
25 | 2:1/0 = 0
26 | 0:2/0 = 0
27 | 1:2/0 = 0
28 | 2:2/0 = 0
29 | 0:3/0 = 0
30 | 1:3/0 = 0
31 | 2:3/0 = 0
32 | 0:4/0 = 0
33 | 1:4/0 = 0
34 | 2:4/0 = 0
35 | 0:5/animation_mode = 1
36 | 0:5/animation_frame_0/duration = 1.0
37 | 0:5/animation_frame_1/duration = 1.0
38 | 0:5/0 = 0
39 | 0:5/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
40 | 0:6/animation_mode = 1
41 | 0:6/animation_frame_0/duration = 1.0
42 | 0:6/animation_frame_1/duration = 1.0
43 | 0:6/0 = 0
44 | 0:6/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
45 |
46 | [resource]
47 | occlusion_layer_0/light_mask = 3
48 | physics_layer_0/collision_layer = 1
49 | sources/0 = SubResource("TileSetAtlasSource_6asb7")
50 |
--------------------------------------------------------------------------------
/11-showing-best-scores/tile_set.tres:
--------------------------------------------------------------------------------
1 | [gd_resource type="TileSet" load_steps=5 format=3 uid="uid://ct1sg2j0vfyxf"]
2 |
3 | [ext_resource type="Texture2D" uid="uid://brq3awcnk4gep" path="res://tile_set.png" id="1_yp80t"]
4 |
5 | [sub_resource type="OccluderPolygon2D" id="OccluderPolygon2D_7ogig"]
6 | polygon = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
7 |
8 | [sub_resource type="OccluderPolygon2D" id="OccluderPolygon2D_co04c"]
9 | polygon = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
10 |
11 | [sub_resource type="TileSetAtlasSource" id="TileSetAtlasSource_6asb7"]
12 | texture = ExtResource("1_yp80t")
13 | 0:0/animation_columns = 2
14 | 0:0/0 = 0
15 | 0:0/0/occlusion_layer_0/polygon_0/polygon = SubResource("OccluderPolygon2D_7ogig")
16 | 0:0/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
17 | 1:0/0 = 0
18 | 1:0/0/occlusion_layer_0/polygon_0/polygon = SubResource("OccluderPolygon2D_co04c")
19 | 1:0/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
20 | 2:0/0 = 0
21 | 2:0/0/occlusion_layer_0/polygon_0/polygon = SubResource("OccluderPolygon2D_co04c")
22 | 2:0/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
23 | 0:1/0 = 0
24 | 1:1/0 = 0
25 | 2:1/0 = 0
26 | 0:2/0 = 0
27 | 1:2/0 = 0
28 | 2:2/0 = 0
29 | 0:3/0 = 0
30 | 1:3/0 = 0
31 | 2:3/0 = 0
32 | 0:4/0 = 0
33 | 1:4/0 = 0
34 | 2:4/0 = 0
35 | 0:5/animation_mode = 1
36 | 0:5/animation_frame_0/duration = 1.0
37 | 0:5/animation_frame_1/duration = 1.0
38 | 0:5/0 = 0
39 | 0:5/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
40 | 0:6/animation_mode = 1
41 | 0:6/animation_frame_0/duration = 1.0
42 | 0:6/animation_frame_1/duration = 1.0
43 | 0:6/0 = 0
44 | 0:6/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
45 |
46 | [resource]
47 | occlusion_layer_0/light_mask = 3
48 | physics_layer_0/collision_layer = 1
49 | sources/0 = SubResource("TileSetAtlasSource_6asb7")
50 |
--------------------------------------------------------------------------------
/12-teleporters/hud.gd:
--------------------------------------------------------------------------------
1 | extends CanvasLayer
2 |
3 | @export var map_name_label: Label
4 | @export var map_time_label: Label
5 | @export var map_detector_count_label: Label
6 | @export var map_travel_distance: Label
7 | @export var new_best_map_scores_label: Label
8 |
9 | var map_time_text: String
10 | var map_travel_distance_text: String
11 |
12 |
13 | func _ready() -> void:
14 | visible = false
15 | new_best_map_scores_label.visible = false
16 |
17 |
18 | func show_map_info(map: GameMap) -> void:
19 | if map.has_best_time():
20 | map_time_text = "%%ds (%ds)" % map.get_best_time()
21 | else:
22 | map_time_text = "%ds"
23 |
24 | if map.has_best_travel_distance():
25 | map_travel_distance_text = (
26 | "%%dpx (%dpx)" % map.get_best_travel_distance()
27 | )
28 | else:
29 | map_travel_distance_text = "%dxp"
30 |
31 | map_name_label.text = map.map_name
32 | show_map_time(0.0)
33 | show_travel_distance(0.0)
34 | visible = true
35 | new_best_map_scores_label.visible = false
36 |
37 |
38 | func show_map_time(time: float) -> void:
39 | map_time_label.text = map_time_text % time
40 |
41 |
42 | ## Show new best scores, supply -1 to indicate no new best score.
43 | func show_new_best_map_scores(time: int, travel_distance: int) -> void:
44 | var s: String
45 | if time >= 0:
46 | if travel_distance >= 0:
47 | s = (
48 | "New best time: %ds\nNew best travel distance: %dpx" %
49 | [time, travel_distance]
50 | )
51 | else:
52 | s = "New best time: %ds" % time
53 | elif travel_distance >= 0:
54 | s = "New best travel distance: %dpx" % travel_distance
55 | else:
56 | return
57 |
58 | new_best_map_scores_label.text = s
59 | new_best_map_scores_label.visible = true
60 |
61 |
62 | func show_map_detector_count(valid: int, total: int) -> void:
63 | map_detector_count_label.text = "%d / %d" % [valid, total]
64 |
65 |
66 | func show_travel_distance(distance: float) -> void:
67 | map_travel_distance.text = map_travel_distance_text % distance
68 |
--------------------------------------------------------------------------------
/11-showing-best-scores/hud.gd:
--------------------------------------------------------------------------------
1 | extends CanvasLayer
2 |
3 | @export var map_name_label: Label
4 | @export var map_time_label: Label
5 | @export var map_detector_count_label: Label
6 | @export var map_travel_distance: Label
7 | @export var new_best_map_scores_label: Label
8 |
9 | var map_time_text: String
10 | var map_travel_distance_text: String
11 |
12 |
13 | func _ready() -> void:
14 | visible = false
15 | new_best_map_scores_label.visible = false
16 |
17 |
18 | func show_map_info(map: GameMap) -> void:
19 | if map.has_best_time():
20 | map_time_text = "%%ds (%ds)" % map.get_best_time()
21 | else:
22 | map_time_text = "%ds"
23 |
24 | if map.has_best_travel_distance():
25 | map_travel_distance_text = (
26 | "%%dpx (%dpx)" % map.get_best_travel_distance()
27 | )
28 | else:
29 | map_travel_distance_text = "%dxp"
30 |
31 | map_name_label.text = map.map_name
32 | show_map_time(0.0)
33 | show_travel_distance(0.0)
34 | visible = true
35 | new_best_map_scores_label.visible = false
36 |
37 |
38 | func show_map_time(time: float) -> void:
39 | map_time_label.text = map_time_text % time
40 |
41 |
42 | ## Show new best scores, supply -1 to indicate no new best score.
43 | func show_new_best_map_scores(time: int, travel_distance: int) -> void:
44 | var s: String
45 | if time >= 0:
46 | if travel_distance >= 0:
47 | s = (
48 | "New best time: %ds\nNew best travel distance: %dpx" %
49 | [time, travel_distance]
50 | )
51 | else:
52 | s = "New best time: %ds" % time
53 | elif travel_distance >= 0:
54 | s = "New best travel distance: %dpx" % travel_distance
55 | else:
56 | return
57 |
58 | new_best_map_scores_label.text = s
59 | new_best_map_scores_label.visible = true
60 |
61 |
62 | func show_map_detector_count(valid: int, total: int) -> void:
63 | map_detector_count_label.text = "%d / %d" % [valid, total]
64 |
65 |
66 | func show_travel_distance(distance: float) -> void:
67 | map_travel_distance.text = map_travel_distance_text % distance
68 |
--------------------------------------------------------------------------------
/10-extra-map-info/map.gd:
--------------------------------------------------------------------------------
1 | class_name GameMap
2 | extends Node
3 |
4 | const KEY_BEST_TIME := "best_time"
5 | const KEY_BEST_TRAVEL_DISTANCE := "best_travel_distance"
6 |
7 | @export var map_name := "Map"
8 |
9 | var player_character: PlayerCharacter
10 | var registered_detector_count := 0
11 | var valid_detector_count := 0
12 | var current_map_time := 0.0
13 | var map_save_data: Dictionary
14 |
15 |
16 | func _process(delta: float) -> void:
17 | current_map_time += delta
18 | HUD.show_map_time(current_map_time)
19 |
20 |
21 | func _ready() -> void:
22 | for child_node in get_children():
23 | var detector := child_node as Detector
24 | if detector:
25 | registered_detector_count += 1
26 | detector.validity_changed.connect(_on_detector_validity_changed)
27 | else:
28 | var pc := child_node as PlayerCharacter
29 | if pc:
30 | player_character = pc
31 |
32 | Main.map_loaded(self)
33 | HUD.show_map_info(self)
34 | HUD.show_map_detector_count(
35 | valid_detector_count, registered_detector_count
36 | )
37 |
38 |
39 | func _on_detector_validity_changed(valid: bool) -> void:
40 | if valid:
41 | valid_detector_count += 1
42 | if valid_detector_count == registered_detector_count:
43 | _update_best_scores()
44 | Main.load_next_map()
45 | else:
46 | valid_detector_count -= 1
47 |
48 | HUD.show_map_detector_count(
49 | valid_detector_count, registered_detector_count
50 | )
51 |
52 |
53 | func _update_best_scores() -> void:
54 | var new_time := floori(current_map_time)
55 | if (
56 | not map_save_data.has(KEY_BEST_TIME)
57 | or new_time < map_save_data[KEY_BEST_TIME]
58 | ):
59 | map_save_data[KEY_BEST_TIME] = new_time
60 | else:
61 | new_time = -1
62 |
63 | var new_travel_distance := floori(player_character.travel_distance)
64 | if (
65 | not map_save_data.has(KEY_BEST_TRAVEL_DISTANCE)
66 | or new_travel_distance < map_save_data[KEY_BEST_TRAVEL_DISTANCE]
67 | ):
68 | map_save_data[KEY_BEST_TRAVEL_DISTANCE] = new_travel_distance
69 | else:
70 | new_travel_distance = -1
71 |
72 | HUD.show_new_best_map_scores(new_time, new_travel_distance)
73 |
--------------------------------------------------------------------------------
/12-teleporters/hud.tscn:
--------------------------------------------------------------------------------
1 | [gd_scene load_steps=2 format=3 uid="uid://cw4q2habmqtk8"]
2 |
3 | [ext_resource type="Script" uid="uid://cv3i66vvgu2ra" path="res://hud.gd" id="1_37p78"]
4 |
5 | [node name="HUD" type="CanvasLayer" node_paths=PackedStringArray("map_name_label", "map_time_label", "map_detector_count_label", "map_travel_distance", "new_best_map_scores_label")]
6 | layer = 3
7 | script = ExtResource("1_37p78")
8 | map_name_label = NodePath("MapName")
9 | map_time_label = NodePath("MapTime")
10 | map_detector_count_label = NodePath("MapDetectorCount")
11 | map_travel_distance = NodePath("MapTravelDistance")
12 | new_best_map_scores_label = NodePath("NewBestMapScores")
13 |
14 | [node name="MapName" type="Label" parent="."]
15 | offset_left = 16.0
16 | offset_right = 76.0
17 | offset_bottom = 16.0
18 | theme_override_font_sizes/font_size = 11
19 | text = "Map Name"
20 |
21 | [node name="MapTime" type="Label" parent="."]
22 | offset_left = 324.0
23 | offset_right = 384.0
24 | offset_bottom = 16.0
25 | theme_override_font_sizes/font_size = 11
26 | text = "0s"
27 | horizontal_alignment = 2
28 |
29 | [node name="MapDetectorCount" type="Label" parent="."]
30 | anchors_preset = 2
31 | anchor_top = 1.0
32 | anchor_bottom = 1.0
33 | offset_left = 324.0
34 | offset_top = -16.0
35 | offset_right = 384.0
36 | grow_vertical = 0
37 | theme_override_font_sizes/font_size = 11
38 | text = "00 / 00"
39 | horizontal_alignment = 2
40 |
41 | [node name="MapTravelDistance" type="Label" parent="."]
42 | anchors_preset = 2
43 | anchor_top = 1.0
44 | anchor_bottom = 1.0
45 | offset_left = 16.0
46 | offset_top = -16.0
47 | offset_right = 76.0
48 | grow_vertical = 0
49 | theme_override_font_sizes/font_size = 11
50 | text = "0px"
51 |
52 | [node name="NewBestMapScores" type="Label" parent="."]
53 | anchors_preset = 8
54 | anchor_left = 0.5
55 | anchor_top = 0.5
56 | anchor_right = 0.5
57 | anchor_bottom = 0.5
58 | offset_left = -0.5
59 | offset_top = -11.5
60 | offset_right = 0.5
61 | offset_bottom = 11.5
62 | grow_horizontal = 2
63 | grow_vertical = 2
64 | text = "New Best Time
65 | New Best Travel Distance"
66 | horizontal_alignment = 1
67 |
--------------------------------------------------------------------------------
/10-extra-map-info/hud.tscn:
--------------------------------------------------------------------------------
1 | [gd_scene load_steps=2 format=3 uid="uid://cw4q2habmqtk8"]
2 |
3 | [ext_resource type="Script" uid="uid://cv3i66vvgu2ra" path="res://hud.gd" id="1_37p78"]
4 |
5 | [node name="HUD" type="CanvasLayer" node_paths=PackedStringArray("map_name_label", "map_time_label", "map_detector_count_label", "map_travel_distance", "new_best_map_scores_label")]
6 | layer = 3
7 | script = ExtResource("1_37p78")
8 | map_name_label = NodePath("MapName")
9 | map_time_label = NodePath("MapTime")
10 | map_detector_count_label = NodePath("MapDetectorCount")
11 | map_travel_distance = NodePath("MapTravelDistance")
12 | new_best_map_scores_label = NodePath("NewBestMapScores")
13 |
14 | [node name="MapName" type="Label" parent="."]
15 | offset_left = 16.0
16 | offset_right = 76.0
17 | offset_bottom = 16.0
18 | theme_override_font_sizes/font_size = 11
19 | text = "Map Name"
20 |
21 | [node name="MapTime" type="Label" parent="."]
22 | offset_left = 324.0
23 | offset_right = 384.0
24 | offset_bottom = 16.0
25 | theme_override_font_sizes/font_size = 11
26 | text = "0s"
27 | horizontal_alignment = 2
28 |
29 | [node name="MapDetectorCount" type="Label" parent="."]
30 | anchors_preset = 2
31 | anchor_top = 1.0
32 | anchor_bottom = 1.0
33 | offset_left = 324.0
34 | offset_top = -16.0
35 | offset_right = 384.0
36 | grow_vertical = 0
37 | theme_override_font_sizes/font_size = 11
38 | text = "00 / 00"
39 | horizontal_alignment = 2
40 |
41 | [node name="MapTravelDistance" type="Label" parent="."]
42 | anchors_preset = 2
43 | anchor_top = 1.0
44 | anchor_bottom = 1.0
45 | offset_left = 16.0
46 | offset_top = -16.0
47 | offset_right = 76.0
48 | grow_vertical = 0
49 | theme_override_font_sizes/font_size = 11
50 | text = "0px"
51 |
52 | [node name="NewBestMapScores" type="Label" parent="."]
53 | anchors_preset = 8
54 | anchor_left = 0.5
55 | anchor_top = 0.5
56 | anchor_right = 0.5
57 | anchor_bottom = 0.5
58 | offset_left = -0.5
59 | offset_top = -11.5
60 | offset_right = 0.5
61 | offset_bottom = 11.5
62 | grow_horizontal = 2
63 | grow_vertical = 2
64 | text = "New Best Time
65 | New Best Travel Distance"
66 | horizontal_alignment = 1
67 |
--------------------------------------------------------------------------------
/11-showing-best-scores/hud.tscn:
--------------------------------------------------------------------------------
1 | [gd_scene load_steps=2 format=3 uid="uid://cw4q2habmqtk8"]
2 |
3 | [ext_resource type="Script" uid="uid://cv3i66vvgu2ra" path="res://hud.gd" id="1_37p78"]
4 |
5 | [node name="HUD" type="CanvasLayer" node_paths=PackedStringArray("map_name_label", "map_time_label", "map_detector_count_label", "map_travel_distance", "new_best_map_scores_label")]
6 | layer = 3
7 | script = ExtResource("1_37p78")
8 | map_name_label = NodePath("MapName")
9 | map_time_label = NodePath("MapTime")
10 | map_detector_count_label = NodePath("MapDetectorCount")
11 | map_travel_distance = NodePath("MapTravelDistance")
12 | new_best_map_scores_label = NodePath("NewBestMapScores")
13 |
14 | [node name="MapName" type="Label" parent="."]
15 | offset_left = 16.0
16 | offset_right = 76.0
17 | offset_bottom = 16.0
18 | theme_override_font_sizes/font_size = 11
19 | text = "Map Name"
20 |
21 | [node name="MapTime" type="Label" parent="."]
22 | offset_left = 324.0
23 | offset_right = 384.0
24 | offset_bottom = 16.0
25 | theme_override_font_sizes/font_size = 11
26 | text = "0s"
27 | horizontal_alignment = 2
28 |
29 | [node name="MapDetectorCount" type="Label" parent="."]
30 | anchors_preset = 2
31 | anchor_top = 1.0
32 | anchor_bottom = 1.0
33 | offset_left = 324.0
34 | offset_top = -16.0
35 | offset_right = 384.0
36 | grow_vertical = 0
37 | theme_override_font_sizes/font_size = 11
38 | text = "00 / 00"
39 | horizontal_alignment = 2
40 |
41 | [node name="MapTravelDistance" type="Label" parent="."]
42 | anchors_preset = 2
43 | anchor_top = 1.0
44 | anchor_bottom = 1.0
45 | offset_left = 16.0
46 | offset_top = -16.0
47 | offset_right = 76.0
48 | grow_vertical = 0
49 | theme_override_font_sizes/font_size = 11
50 | text = "0px"
51 |
52 | [node name="NewBestMapScores" type="Label" parent="."]
53 | anchors_preset = 8
54 | anchor_left = 0.5
55 | anchor_top = 0.5
56 | anchor_right = 0.5
57 | anchor_bottom = 0.5
58 | offset_left = -0.5
59 | offset_top = -11.5
60 | offset_right = 0.5
61 | offset_bottom = 11.5
62 | grow_horizontal = 2
63 | grow_vertical = 2
64 | text = "New Best Time
65 | New Best Travel Distance"
66 | horizontal_alignment = 1
67 |
--------------------------------------------------------------------------------
/8-saving-progress/main.gd:
--------------------------------------------------------------------------------
1 | extends Node
2 |
3 | const GAME_SAVE_PATH := "user://game.save"
4 | const KEY_MAP_PATH := "map_path"
5 | const GAME_SAVE_VERSION := 1
6 | const KEY_GAME_SAVE_VERSION := "version"
7 | const MAP_PATH_PREFIX := "res://maps/"
8 |
9 | var current_map_path: String
10 |
11 |
12 | func can_continue() -> bool:
13 | return FileAccess.file_exists(GAME_SAVE_PATH)
14 |
15 |
16 | func load_continue_map() -> void:
17 | if not can_continue():
18 | print("Tried to continue without save file!")
19 | return
20 |
21 | var game_save_file := FileAccess.open(GAME_SAVE_PATH, FileAccess.READ)
22 | var game_save_data := game_save_file.get_var() as Dictionary
23 | if game_save_data[KEY_GAME_SAVE_VERSION] > GAME_SAVE_VERSION:
24 | print("Tried to load unknown future save file format!")
25 | return
26 |
27 | var map_path := game_save_data[KEY_MAP_PATH] as String
28 | if (
29 | not map_path.begins_with(MAP_PATH_PREFIX)
30 | or map_path.contains("..")
31 | ):
32 | print("Invalid map path!")
33 | return
34 | load_map(map_path)
35 |
36 |
37 | func load_next_map() -> void:
38 | var split_path := current_map_path.split(".")
39 | var next_map_number := split_path[1].to_int() + 1
40 | split_path[1] = str(next_map_number).pad_zeros(3)
41 | var next_map_path = ".".join(split_path)
42 |
43 | if not ResourceLoader.exists(next_map_path):
44 | split_path[1] = "001"
45 | next_map_path = ".".join(split_path)
46 | load_map(next_map_path)
47 |
48 |
49 | func load_map(map_path: String) -> void:
50 | ResourceLoader.load_threaded_request(map_path)
51 |
52 | get_tree().paused = true
53 | await MapTransition.play_exit_map()
54 |
55 | get_tree().change_scene_to_packed(
56 | ResourceLoader.load_threaded_get(map_path)
57 | )
58 |
59 | await MapTransition.play_enter_map()
60 | get_tree().paused = false
61 |
62 |
63 | func map_loaded(map_path: String) -> void:
64 | current_map_path = map_path
65 |
66 | var game_save_file := FileAccess.open(GAME_SAVE_PATH, FileAccess.WRITE)
67 | game_save_file.store_var({
68 | KEY_MAP_PATH: map_path,
69 | KEY_GAME_SAVE_VERSION: GAME_SAVE_VERSION,
70 | })
71 |
--------------------------------------------------------------------------------
/12-teleporters/teleporters/teleporter_source.gd:
--------------------------------------------------------------------------------
1 | class_name TeleporterSource
2 | extends Area2D
3 |
4 | ## Color for when the teleporter is free.
5 | @export var valid_color := Color(Color.CYAN, 0.5)
6 | ## Color for when the teleporter is occupied.
7 | @export var invalid_color := Color(Color.MAGENTA, 0.5)
8 |
9 | @export var sprite: Sprite2D
10 |
11 | @export var line: Line2D
12 |
13 | @export var colissionShape: CollisionShape2D
14 |
15 | @export var particles: GPUParticles2D
16 |
17 | @export var destination: TeleporterDestination
18 |
19 | var is_active := true
20 |
21 | var objects: Array[InteractiveObject] = []
22 |
23 |
24 | func _ready() -> void:
25 | if not destination:
26 | is_active = false
27 | sprite.modulate = invalid_color
28 | set_physics_process(false)
29 | else:
30 | destination.validity_changed.connect(_on_detector_validity_changed)
31 | sprite.modulate = valid_color
32 | destination.sprite.modulate = valid_color
33 | particles.modulate = valid_color
34 | destination.particles.modulate = valid_color
35 | line.modulate = valid_color
36 | line.add_point(Vector2.ZERO)
37 | line.add_point(destination.position - position)
38 |
39 |
40 | func _physics_process(_delta: float) -> void:
41 | if not is_active or objects.is_empty():
42 | set_physics_process(false)
43 | return
44 | objects.is_empty()
45 | var own_rect := colissionShape.shape.get_rect()
46 | own_rect.position += position
47 |
48 | for object in objects:
49 | if own_rect.encloses(object.get_current_rect()):
50 | object.displace(destination.position - position)
51 | particles.emitting = true
52 | destination.particles.emitting = true
53 |
54 |
55 | func _on_detector_validity_changed(valid: bool) -> void:
56 | is_active = valid
57 | set_physics_process(valid)
58 | var color := valid_color if valid else invalid_color
59 | sprite.modulate = color
60 | destination.sprite.modulate = color
61 | line.modulate = color
62 |
63 |
64 | func _on_body_entered(body: Node2D) -> void:
65 | var object := body as InteractiveObject
66 | if object:
67 | objects.push_back(object)
68 | set_physics_process(true)
69 |
70 |
71 | func _on_body_exited(body: Node2D) -> void:
72 | var index_to_remove := objects.find(body as InteractiveObject)
73 | if index_to_remove >= 0:
74 | objects.remove_at(index_to_remove)
75 |
--------------------------------------------------------------------------------
/12-teleporters/teleporters/teleporter_destination.tscn:
--------------------------------------------------------------------------------
1 | [gd_scene load_steps=9 format=3 uid="uid://da4l644boage6"]
2 |
3 | [ext_resource type="Script" uid="uid://dwu02xxnacil7" path="res://teleporters/teleporter_destination.gd" id="1_a8g44"]
4 | [ext_resource type="Texture2D" uid="uid://cpc3pnpy5ytd2" path="res://teleporters/teleporter_destination.png" id="2_jq1q4"]
5 |
6 | [sub_resource type="RectangleShape2D" id="RectangleShape2D_wgkqt"]
7 | size = Vector2(16, 16)
8 |
9 | [sub_resource type="CanvasItemMaterial" id="CanvasItemMaterial_q0aho"]
10 | light_mode = 1
11 |
12 | [sub_resource type="CanvasItemMaterial" id="CanvasItemMaterial_qlgbt"]
13 | blend_mode = 1
14 | light_mode = 1
15 |
16 | [sub_resource type="Gradient" id="Gradient_1t2jy"]
17 | offsets = PackedFloat32Array(0, 0.5, 1)
18 | colors = PackedColorArray(1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1)
19 |
20 | [sub_resource type="GradientTexture2D" id="GradientTexture2D_h7m5w"]
21 | gradient = SubResource("Gradient_1t2jy")
22 | width = 8
23 | height = 8
24 | fill = 1
25 | fill_from = Vector2(0.5, 0.5)
26 | fill_to = Vector2(1, 0.5)
27 |
28 | [sub_resource type="ParticleProcessMaterial" id="ParticleProcessMaterial_8soqw"]
29 | particle_flag_disable_z = true
30 | emission_shape = 3
31 | emission_box_extents = Vector3(6, 6, 0)
32 | gravity = Vector3(0, 0, 0)
33 |
34 | [node name="Teleporter Destination" type="Area2D" node_paths=PackedStringArray("sprite", "particles")]
35 | collision_mask = 3
36 | monitorable = false
37 | script = ExtResource("1_a8g44")
38 | sprite = NodePath("Sprite2D")
39 | particles = NodePath("GPUParticles2D")
40 |
41 | [node name="CollisionShape2D" type="CollisionShape2D" parent="."]
42 | shape = SubResource("RectangleShape2D_wgkqt")
43 |
44 | [node name="Sprite2D" type="Sprite2D" parent="."]
45 | modulate = Color(1, 1, 1, 0.5019608)
46 | texture_filter = 1
47 | material = SubResource("CanvasItemMaterial_q0aho")
48 | texture = ExtResource("2_jq1q4")
49 |
50 | [node name="GPUParticles2D" type="GPUParticles2D" parent="."]
51 | material = SubResource("CanvasItemMaterial_qlgbt")
52 | emitting = false
53 | amount = 30
54 | texture = SubResource("GradientTexture2D_h7m5w")
55 | lifetime = 0.25
56 | one_shot = true
57 | fixed_fps = 60
58 | interpolate = false
59 | fract_delta = false
60 | process_material = SubResource("ParticleProcessMaterial_8soqw")
61 |
62 | [connection signal="body_entered" from="." to="." method="_on_body_entered"]
63 | [connection signal="body_exited" from="." to="." method="_on_body_exited"]
64 |
--------------------------------------------------------------------------------
/12-teleporters/map.gd:
--------------------------------------------------------------------------------
1 | class_name GameMap
2 | extends Node
3 |
4 | const KEY_BEST_TIME := "best_time"
5 | const KEY_BEST_TRAVEL_DISTANCE := "best_travel_distance"
6 |
7 | @export var map_name := "Map"
8 |
9 | var player_character: PlayerCharacter
10 | var registered_detector_count := 0
11 | var valid_detector_count := 0
12 | var current_map_time := 0.0
13 | var map_save_data: Dictionary
14 |
15 |
16 | ## Only valid if [method has_best_time] returns true.
17 | func get_best_time() -> int:
18 | return map_save_data[KEY_BEST_TIME]
19 |
20 |
21 | func has_best_time() -> bool:
22 | return map_save_data.has(KEY_BEST_TIME)
23 |
24 |
25 | ## Only valid if [method has_best_travel_distance] returns true.
26 | func get_best_travel_distance() -> int:
27 | return map_save_data[KEY_BEST_TRAVEL_DISTANCE]
28 |
29 |
30 | func has_best_travel_distance() -> bool:
31 | return map_save_data.has(KEY_BEST_TRAVEL_DISTANCE)
32 |
33 |
34 | func _process(delta: float) -> void:
35 | current_map_time += delta
36 | HUD.show_map_time(current_map_time)
37 |
38 |
39 | func _ready() -> void:
40 | for child_node in get_children():
41 | var detector := child_node as Detector
42 | if detector:
43 | registered_detector_count += 1
44 | detector.validity_changed.connect(_on_detector_validity_changed)
45 | else:
46 | var pc := child_node as PlayerCharacter
47 | if pc:
48 | player_character = pc
49 |
50 | Main.map_loaded(self)
51 | HUD.show_map_info(self)
52 | HUD.show_map_detector_count(
53 | valid_detector_count, registered_detector_count
54 | )
55 |
56 |
57 | func _on_detector_validity_changed(valid: bool) -> void:
58 | if valid:
59 | valid_detector_count += 1
60 | if valid_detector_count == registered_detector_count:
61 | _update_best_scores()
62 | Main.load_next_map()
63 | else:
64 | valid_detector_count -= 1
65 |
66 | HUD.show_map_detector_count(
67 | valid_detector_count, registered_detector_count
68 | )
69 |
70 |
71 | func _update_best_scores() -> void:
72 | var new_time := floori(current_map_time)
73 | if not has_best_time() or new_time < get_best_time():
74 | map_save_data[KEY_BEST_TIME] = new_time
75 | else:
76 | new_time = -1
77 |
78 | var new_travel_distance := floori(player_character.travel_distance)
79 | if (
80 | not has_best_travel_distance()
81 | or new_travel_distance < get_best_travel_distance()
82 | ):
83 | map_save_data[KEY_BEST_TRAVEL_DISTANCE] = new_travel_distance
84 | else:
85 | new_travel_distance = -1
86 |
87 | HUD.show_new_best_map_scores(new_time, new_travel_distance)
88 |
--------------------------------------------------------------------------------
/11-showing-best-scores/map.gd:
--------------------------------------------------------------------------------
1 | class_name GameMap
2 | extends Node
3 |
4 | const KEY_BEST_TIME := "best_time"
5 | const KEY_BEST_TRAVEL_DISTANCE := "best_travel_distance"
6 |
7 | @export var map_name := "Map"
8 |
9 | var player_character: PlayerCharacter
10 | var registered_detector_count := 0
11 | var valid_detector_count := 0
12 | var current_map_time := 0.0
13 | var map_save_data: Dictionary
14 |
15 |
16 | ## Only valid if [method has_best_time] returns true.
17 | func get_best_time() -> int:
18 | return map_save_data[KEY_BEST_TIME]
19 |
20 |
21 | func has_best_time() -> bool:
22 | return map_save_data.has(KEY_BEST_TIME)
23 |
24 |
25 | ## Only valid if [method has_best_travel_distance] returns true.
26 | func get_best_travel_distance() -> int:
27 | return map_save_data[KEY_BEST_TRAVEL_DISTANCE]
28 |
29 |
30 | func has_best_travel_distance() -> bool:
31 | return map_save_data.has(KEY_BEST_TRAVEL_DISTANCE)
32 |
33 |
34 | func _process(delta: float) -> void:
35 | current_map_time += delta
36 | HUD.show_map_time(current_map_time)
37 |
38 |
39 | func _ready() -> void:
40 | for child_node in get_children():
41 | var detector := child_node as Detector
42 | if detector:
43 | registered_detector_count += 1
44 | detector.validity_changed.connect(_on_detector_validity_changed)
45 | else:
46 | var pc := child_node as PlayerCharacter
47 | if pc:
48 | player_character = pc
49 |
50 | Main.map_loaded(self)
51 | HUD.show_map_info(self)
52 | HUD.show_map_detector_count(
53 | valid_detector_count, registered_detector_count
54 | )
55 |
56 |
57 | func _on_detector_validity_changed(valid: bool) -> void:
58 | if valid:
59 | valid_detector_count += 1
60 | if valid_detector_count == registered_detector_count:
61 | _update_best_scores()
62 | Main.load_next_map()
63 | else:
64 | valid_detector_count -= 1
65 |
66 | HUD.show_map_detector_count(
67 | valid_detector_count, registered_detector_count
68 | )
69 |
70 |
71 | func _update_best_scores() -> void:
72 | var new_time := floori(current_map_time)
73 | if not has_best_time() or new_time < get_best_time():
74 | map_save_data[KEY_BEST_TIME] = new_time
75 | else:
76 | new_time = -1
77 |
78 | var new_travel_distance := floori(player_character.travel_distance)
79 | if (
80 | not has_best_travel_distance()
81 | or new_travel_distance < get_best_travel_distance()
82 | ):
83 | map_save_data[KEY_BEST_TRAVEL_DISTANCE] = new_travel_distance
84 | else:
85 | new_travel_distance = -1
86 |
87 | HUD.show_new_best_map_scores(new_time, new_travel_distance)
88 |
--------------------------------------------------------------------------------