Add collectable types and implement level unlocking mechanics; enhance player state management
This commit is contained in:
@@ -45,7 +45,7 @@ texture = ExtResource("4_vq1oq")
|
|||||||
position = Vector2(4, -18)
|
position = Vector2(4, -18)
|
||||||
texture = ExtResource("5_m7x6t")
|
texture = ExtResource("5_m7x6t")
|
||||||
|
|
||||||
[node name="CollectableComponent" type="Node" parent="." node_paths=PackedStringArray("area2d", "sfx")]
|
[node name="Collectable" type="Node" parent="." node_paths=PackedStringArray("area2d", "sfx")]
|
||||||
script = ExtResource("5_wc3ym")
|
script = ExtResource("5_wc3ym")
|
||||||
area2d = NodePath("..")
|
area2d = NodePath("..")
|
||||||
collectable_data = ExtResource("6_vmvuo")
|
collectable_data = ExtResource("6_vmvuo")
|
||||||
|
43
objects/exit_level.tscn
Normal file
43
objects/exit_level.tscn
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
[gd_scene load_steps=6 format=3 uid="uid://12jnkdygpxwc"]
|
||||||
|
|
||||||
|
[ext_resource type="Texture2D" uid="uid://djifxc5x0dyrw" path="res://sprites/ppc_tileset.png" id="1_agxwm"]
|
||||||
|
[ext_resource type="Script" uid="uid://cmh8k0rdsyh7j" path="res://scripts/components/requirement_component.gd" id="2_iysc1"]
|
||||||
|
[ext_resource type="Script" uid="uid://c8xhgkg8gcqu6" path="res://scripts/components/unlock_on_requirement_component.gd" id="3_5ktpq"]
|
||||||
|
[ext_resource type="Script" uid="uid://bwamqffvpa452" path="res://scripts/components/exit_door_component.gd" id="4_4jgt0"]
|
||||||
|
|
||||||
|
[sub_resource type="RectangleShape2D" id="RectangleShape2D_yfu6m"]
|
||||||
|
size = Vector2(28, 32)
|
||||||
|
|
||||||
|
[node name="ExitLevel" type="Area2D"]
|
||||||
|
collision_layer = 0
|
||||||
|
collision_mask = 4
|
||||||
|
|
||||||
|
[node name="Sprite2D" type="Sprite2D" parent="."]
|
||||||
|
position = Vector2(0, -8)
|
||||||
|
scale = Vector2(2, 2)
|
||||||
|
texture = ExtResource("1_agxwm")
|
||||||
|
hframes = 12
|
||||||
|
vframes = 12
|
||||||
|
frame = 54
|
||||||
|
|
||||||
|
[node name="CollisionShape2D" type="CollisionShape2D" parent="."]
|
||||||
|
position = Vector2(0, -8)
|
||||||
|
shape = SubResource("RectangleShape2D_yfu6m")
|
||||||
|
|
||||||
|
[node name="RequirementComponent" type="Node" parent="."]
|
||||||
|
script = ExtResource("2_iysc1")
|
||||||
|
requirement_type = 1
|
||||||
|
metadata/_custom_type_script = "uid://cmh8k0rdsyh7j"
|
||||||
|
|
||||||
|
[node name="UnlockOnRequirementComponent" type="Node" parent="." node_paths=PackedStringArray("requirement_component", "unlock_target")]
|
||||||
|
script = ExtResource("3_5ktpq")
|
||||||
|
requirement_component = NodePath("../RequirementComponent")
|
||||||
|
unlock_target = NodePath("../ExitDoorComponent")
|
||||||
|
metadata/_custom_type_script = "uid://c8xhgkg8gcqu6"
|
||||||
|
|
||||||
|
[node name="ExitDoorComponent" type="Node" parent="." node_paths=PackedStringArray("exit_area", "door_sprite")]
|
||||||
|
script = ExtResource("4_4jgt0")
|
||||||
|
exit_area = NodePath("..")
|
||||||
|
door_sprite = NodePath("../Sprite2D")
|
||||||
|
opened_door_frame = 88
|
||||||
|
metadata/_custom_type_script = "uid://bwamqffvpa452"
|
@@ -1,6 +1,15 @@
|
|||||||
[gd_scene load_steps=2 format=3 uid="uid://b4eifkc31jsun"]
|
[gd_scene load_steps=3 format=3 uid="uid://b4eifkc31jsun"]
|
||||||
|
|
||||||
[ext_resource type="Script" uid="uid://dd30bgqiagi25" path="res://scripts/game_manager.gd" id="1_58t7u"]
|
[ext_resource type="Script" uid="uid://dd30bgqiagi25" path="res://scripts/game_manager.gd" id="1_58t7u"]
|
||||||
|
[ext_resource type="PackedScene" uid="uid://h60obxmju6mo" path="res://scenes/test.tscn" id="2_bentb"]
|
||||||
|
|
||||||
[node name="GameManager" type="Node"]
|
[node name="GameManager" type="Node"]
|
||||||
script = ExtResource("1_58t7u")
|
script = ExtResource("1_58t7u")
|
||||||
|
level_scenes = Array[PackedScene]([ExtResource("2_bentb")])
|
||||||
|
player_state = {
|
||||||
|
"coins": 0,
|
||||||
|
"current_level": 0,
|
||||||
|
"lives": 3,
|
||||||
|
"unlocked_levels": [ExtResource("2_bentb")],
|
||||||
|
"unlocked_skills": []
|
||||||
|
}
|
||||||
|
@@ -4,7 +4,7 @@
|
|||||||
[ext_resource type="Texture2D" uid="uid://djifxc5x0dyrw" path="res://sprites/ppc_tileset.png" id="1_yy7uq"]
|
[ext_resource type="Texture2D" uid="uid://djifxc5x0dyrw" path="res://sprites/ppc_tileset.png" id="1_yy7uq"]
|
||||||
|
|
||||||
[sub_resource type="RectangleShape2D" id="RectangleShape2D_hkd8b"]
|
[sub_resource type="RectangleShape2D" id="RectangleShape2D_hkd8b"]
|
||||||
size = Vector2(12, 17)
|
size = Vector2(38, 22)
|
||||||
|
|
||||||
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_lqw6h"]
|
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_lqw6h"]
|
||||||
bg_color = Color(0, 0, 0, 1)
|
bg_color = Color(0, 0, 0, 1)
|
||||||
@@ -18,7 +18,7 @@ ui_root = NodePath("Panel")
|
|||||||
tooltip_label = NodePath("Panel/PanelContainer/Label")
|
tooltip_label = NodePath("Panel/PanelContainer/Label")
|
||||||
|
|
||||||
[node name="CollisionShape2D" type="CollisionShape2D" parent="."]
|
[node name="CollisionShape2D" type="CollisionShape2D" parent="."]
|
||||||
position = Vector2(0, -0.5)
|
position = Vector2(1, -3)
|
||||||
shape = SubResource("RectangleShape2D_hkd8b")
|
shape = SubResource("RectangleShape2D_hkd8b")
|
||||||
|
|
||||||
[node name="Sprite2D" type="Sprite2D" parent="."]
|
[node name="Sprite2D" type="Sprite2D" parent="."]
|
||||||
|
@@ -5,3 +5,4 @@
|
|||||||
[resource]
|
[resource]
|
||||||
script = ExtResource("1_2d5tb")
|
script = ExtResource("1_2d5tb")
|
||||||
amount = 1
|
amount = 1
|
||||||
|
type = 1
|
||||||
|
File diff suppressed because one or more lines are too long
@@ -7,7 +7,7 @@ var has_fade_away: bool = false
|
|||||||
@export var area2d: Area2D
|
@export var area2d: Area2D
|
||||||
@export var collectable_data: CollectableResource
|
@export var collectable_data: CollectableResource
|
||||||
@export var sfx: AudioStreamPlayer2D
|
@export var sfx: AudioStreamPlayer2D
|
||||||
signal collected(amount: int)
|
signal collected(amount: int, type: CollectableResource.CollectableType)
|
||||||
|
|
||||||
|
|
||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
@@ -24,7 +24,7 @@ func _ready() -> void:
|
|||||||
|
|
||||||
func _on_area2d_body_entered(body: Node2D) -> void:
|
func _on_area2d_body_entered(body: Node2D) -> void:
|
||||||
if body.has_node("CanPickUpComponent"):
|
if body.has_node("CanPickUpComponent"):
|
||||||
collected.emit(collectable_data.amount)
|
collected.emit(collectable_data.amount, collectable_data.type)
|
||||||
if sfx:
|
if sfx:
|
||||||
sfx.play()
|
sfx.play()
|
||||||
if not has_fade_away:
|
if not has_fade_away:
|
||||||
|
34
scripts/components/exit_door_component.gd
Normal file
34
scripts/components/exit_door_component.gd
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
class_name ExitDoorComponent
|
||||||
|
extends Node
|
||||||
|
|
||||||
|
@export var locked: bool = true
|
||||||
|
@export var exit_area: Area2D
|
||||||
|
@export var door_sprite: Sprite2D
|
||||||
|
@export var opened_door_sfx: AudioStreamPlayer2D
|
||||||
|
@export var opened_door_frame: int = 0
|
||||||
|
signal exit_triggered
|
||||||
|
@onready var gm: GM = $"/root/GameManager"
|
||||||
|
|
||||||
|
|
||||||
|
func _ready() -> void:
|
||||||
|
if not exit_area:
|
||||||
|
printerr("ExitDoorComponent: exit_area is not set.")
|
||||||
|
return
|
||||||
|
|
||||||
|
exit_area.body_entered.connect(on_exit_area_body_entered)
|
||||||
|
|
||||||
|
|
||||||
|
func unlock() -> void:
|
||||||
|
locked = false
|
||||||
|
if door_sprite:
|
||||||
|
door_sprite.frame = opened_door_frame
|
||||||
|
if opened_door_sfx:
|
||||||
|
opened_door_sfx.play()
|
||||||
|
|
||||||
|
|
||||||
|
func on_exit_area_body_entered(_body: Node2D) -> void:
|
||||||
|
if locked:
|
||||||
|
return
|
||||||
|
|
||||||
|
exit_triggered.emit()
|
||||||
|
gm.try_to_go_to_next_level()
|
1
scripts/components/exit_door_component.gd.uid
Normal file
1
scripts/components/exit_door_component.gd.uid
Normal file
@@ -0,0 +1 @@
|
|||||||
|
uid://bwamqffvpa452
|
@@ -24,5 +24,6 @@ func _on_health_component_on_death() -> void:
|
|||||||
gm.reset_player_state()
|
gm.reset_player_state()
|
||||||
else:
|
else:
|
||||||
gm.remove_lives(1)
|
gm.remove_lives(1)
|
||||||
|
gm.set_coins(0)
|
||||||
|
|
||||||
call_deferred("reset_scene")
|
call_deferred("reset_scene")
|
||||||
|
32
scripts/components/requirement_component.gd
Normal file
32
scripts/components/requirement_component.gd
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
class_name RequirementComponent
|
||||||
|
extends Node
|
||||||
|
|
||||||
|
@export var requirement_type: CollectableResource.CollectableType
|
||||||
|
@export var required_amount: int = 1
|
||||||
|
|
||||||
|
var current_amount: int = 0
|
||||||
|
signal requirement_met(requirement_type: CollectableResource.CollectableType)
|
||||||
|
@onready var gm: GM = $"/root/GameManager"
|
||||||
|
|
||||||
|
|
||||||
|
func _ready() -> void:
|
||||||
|
if not gm:
|
||||||
|
printerr("RequirementComponent: GameManager not found.")
|
||||||
|
return
|
||||||
|
|
||||||
|
var collectables: Array[CollectableComponent] = gm.get_colllectable_nodes()
|
||||||
|
for collectable in collectables:
|
||||||
|
collectable.collected.connect(on_collected)
|
||||||
|
|
||||||
|
|
||||||
|
func on_collected(amount: int, type: CollectableResource.CollectableType) -> void:
|
||||||
|
print("Collected: ", amount, " of type: ", str(type))
|
||||||
|
if type != requirement_type:
|
||||||
|
return
|
||||||
|
add_progress(amount)
|
||||||
|
|
||||||
|
|
||||||
|
func add_progress(amount: int = 1) -> void:
|
||||||
|
current_amount += amount
|
||||||
|
if current_amount >= required_amount:
|
||||||
|
requirement_met.emit(requirement_type)
|
1
scripts/components/requirement_component.gd.uid
Normal file
1
scripts/components/requirement_component.gd.uid
Normal file
@@ -0,0 +1 @@
|
|||||||
|
uid://cmh8k0rdsyh7j
|
@@ -3,17 +3,18 @@ extends Node
|
|||||||
|
|
||||||
@onready var game_manager: GM = $"/root/GameManager"
|
@onready var game_manager: GM = $"/root/GameManager"
|
||||||
|
|
||||||
|
|
||||||
func _ready():
|
func _ready():
|
||||||
await get_tree().process_frame
|
await get_tree().process_frame
|
||||||
var coins = get_tree().get_nodes_in_group("coins")
|
var coins = get_tree().get_nodes_in_group("coins")
|
||||||
|
|
||||||
for coin in coins:
|
for coin in coins:
|
||||||
coin.connect("collected", on_collected)
|
coin.connect("collected", on_collected)
|
||||||
|
|
||||||
func on_collected(amount: int) -> void:
|
|
||||||
|
func on_collected(amount: int, type: CollectableResource.CollectableType) -> void:
|
||||||
if not game_manager:
|
if not game_manager:
|
||||||
return
|
return
|
||||||
|
if type != CollectableResource.CollectableType.COIN:
|
||||||
|
return
|
||||||
game_manager.add_coins(amount)
|
game_manager.add_coins(amount)
|
||||||
# todo: play sound
|
|
||||||
# todo: update ui
|
|
||||||
|
26
scripts/components/unlock_on_requirement_component.gd
Normal file
26
scripts/components/unlock_on_requirement_component.gd
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
class_name UnlockOnRequirementComponent
|
||||||
|
extends Node
|
||||||
|
|
||||||
|
@export var requirement_component: RequirementComponent
|
||||||
|
@export var unlock_target: Node
|
||||||
|
|
||||||
|
|
||||||
|
func _ready() -> void:
|
||||||
|
if not requirement_component:
|
||||||
|
printerr("UnlockOnRequirementComponent: requirement_component is not set.")
|
||||||
|
return
|
||||||
|
|
||||||
|
if not unlock_target:
|
||||||
|
printerr("UnlockOnRequirementComponent: unlock_target is not set.")
|
||||||
|
return
|
||||||
|
|
||||||
|
requirement_component.requirement_met.connect(on_requirement_met)
|
||||||
|
|
||||||
|
|
||||||
|
func on_requirement_met(requirement_type: CollectableResource.CollectableType) -> void:
|
||||||
|
if requirement_type == requirement_component.requirement_type:
|
||||||
|
if unlock_target.has_method("unlock"):
|
||||||
|
unlock_target.unlock()
|
||||||
|
else:
|
||||||
|
printerr("UnlockOnRequirementComponent: unlock_target does not have an unlock method.")
|
||||||
|
|
@@ -0,0 +1 @@
|
|||||||
|
uid://c8xhgkg8gcqu6
|
@@ -1,11 +1,68 @@
|
|||||||
class_name GM
|
class_name GM
|
||||||
extends Node
|
extends Node
|
||||||
|
|
||||||
var player_state = {
|
@export var level_scenes: Array[PackedScene]
|
||||||
"coins": 0,
|
|
||||||
"lives": 3,
|
@export var player_state := {
|
||||||
"unlocked_skills": [],
|
"coins": 0,
|
||||||
}
|
"lives": 3,
|
||||||
|
"unlocked_skills": [],
|
||||||
|
"current_level": 0,
|
||||||
|
"unlocked_levels": [],
|
||||||
|
}
|
||||||
|
|
||||||
|
var nodes_in_scene := []
|
||||||
|
|
||||||
|
|
||||||
|
func _enter_tree() -> void:
|
||||||
|
get_tree().node_added.connect(on_node_added)
|
||||||
|
get_tree().node_removed.connect(on_node_removed)
|
||||||
|
|
||||||
|
|
||||||
|
func on_node_added(node: Node) -> void:
|
||||||
|
nodes_in_scene.append(node)
|
||||||
|
|
||||||
|
|
||||||
|
func on_node_removed(node: Node) -> void:
|
||||||
|
if node in nodes_in_scene:
|
||||||
|
nodes_in_scene.erase(node)
|
||||||
|
|
||||||
|
|
||||||
|
func get_colllectable_nodes() -> Array[CollectableComponent]:
|
||||||
|
var collectable_nodes: Array[CollectableComponent] = []
|
||||||
|
for node in nodes_in_scene:
|
||||||
|
var collectable_component: CollectableComponent = node.get_node_or_null("Collectable")
|
||||||
|
if not collectable_component:
|
||||||
|
collectable_component = node.get_node_or_null("CollectableComponent")
|
||||||
|
if not collectable_component:
|
||||||
|
continue
|
||||||
|
if collectable_component.collectable_data.type == CollectableResource.CollectableType.KID:
|
||||||
|
print("Kid collectable found: ", collectable_component.get_parent().name)
|
||||||
|
|
||||||
|
collectable_nodes.append(collectable_component)
|
||||||
|
return collectable_nodes
|
||||||
|
|
||||||
|
|
||||||
|
func get_coin_nodes() -> Array[CollectableComponent]:
|
||||||
|
var coin_nodes := []
|
||||||
|
for node in nodes_in_scene:
|
||||||
|
var collectable_component: CollectableComponent = node.get_node_or_null("Collectable")
|
||||||
|
if not collectable_component:
|
||||||
|
continue
|
||||||
|
if collectable_component.collectable_data.type == CollectableResource.CollectableType.COIN:
|
||||||
|
coin_nodes.append(collectable_component)
|
||||||
|
return coin_nodes
|
||||||
|
|
||||||
|
|
||||||
|
func get_kid_nodes() -> Array[CollectableComponent]:
|
||||||
|
var kid_nodes := []
|
||||||
|
for node in nodes_in_scene:
|
||||||
|
var collectable_component: CollectableComponent = node.get_node_or_null("Collectable")
|
||||||
|
if not collectable_component:
|
||||||
|
continue
|
||||||
|
if collectable_component.collectable_data.type == CollectableResource.CollectableType.KID:
|
||||||
|
kid_nodes.append(collectable_component)
|
||||||
|
return kid_nodes
|
||||||
|
|
||||||
|
|
||||||
func add_coins(amount: int) -> void:
|
func add_coins(amount: int) -> void:
|
||||||
@@ -59,4 +116,16 @@ func reset_player_state() -> void:
|
|||||||
"coins": 0,
|
"coins": 0,
|
||||||
"lives": 3,
|
"lives": 3,
|
||||||
"unlocked_skills": [],
|
"unlocked_skills": [],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func unlock_level(level_index: int) -> void:
|
||||||
|
if level_index not in player_state["unlocked_levels"]: player_state["unlocked_levels"].append(level_index)
|
||||||
|
|
||||||
|
|
||||||
|
func try_to_go_to_next_level() -> void:
|
||||||
|
if player_state["current_level"] + 1 < level_scenes.size() and player_state["current_level"] + 1 in player_state["unlocked_levels"]:
|
||||||
|
player_state["current_level"] += 1
|
||||||
|
print("Going to next level: ", player_state["current_level"])
|
||||||
|
else:
|
||||||
|
print("No more levels to go to.")
|
||||||
|
@@ -1,4 +1,10 @@
|
|||||||
class_name CollectableResource
|
class_name CollectableResource
|
||||||
extends Resource
|
extends Resource
|
||||||
|
|
||||||
@export var amount: int = 0
|
enum CollectableType {
|
||||||
|
COIN,
|
||||||
|
KID,
|
||||||
|
HEALTH,
|
||||||
|
}
|
||||||
|
@export var amount: int = 0
|
||||||
|
@export var type: CollectableType = CollectableType.COIN
|
Binary file not shown.
Before Width: | Height: | Size: 6.8 KiB After Width: | Height: | Size: 6.9 KiB |
@@ -785,6 +785,7 @@ texture = ExtResource("2_k3fip")
|
|||||||
0:11/0 = 0
|
0:11/0 = 0
|
||||||
0:11/0/terrain_set = 0
|
0:11/0/terrain_set = 0
|
||||||
0:11/0/terrain = 1
|
0:11/0/terrain = 1
|
||||||
|
0:11/0/probability = 0.2
|
||||||
0:11/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
|
0:11/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
|
||||||
0:11/0/terrains_peering_bit/right_side = 1
|
0:11/0/terrains_peering_bit/right_side = 1
|
||||||
0:11/0/terrains_peering_bit/bottom_right_corner = 1
|
0:11/0/terrains_peering_bit/bottom_right_corner = 1
|
||||||
@@ -797,6 +798,7 @@ texture = ExtResource("2_k3fip")
|
|||||||
1:11/0 = 0
|
1:11/0 = 0
|
||||||
1:11/0/terrain_set = 0
|
1:11/0/terrain_set = 0
|
||||||
1:11/0/terrain = 1
|
1:11/0/terrain = 1
|
||||||
|
1:11/0/probability = 0.2
|
||||||
1:11/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
|
1:11/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
|
||||||
1:11/0/terrains_peering_bit/right_side = 1
|
1:11/0/terrains_peering_bit/right_side = 1
|
||||||
1:11/0/terrains_peering_bit/bottom_right_corner = 1
|
1:11/0/terrains_peering_bit/bottom_right_corner = 1
|
||||||
@@ -809,6 +811,7 @@ texture = ExtResource("2_k3fip")
|
|||||||
2:11/0 = 0
|
2:11/0 = 0
|
||||||
2:11/0/terrain_set = 0
|
2:11/0/terrain_set = 0
|
||||||
2:11/0/terrain = 1
|
2:11/0/terrain = 1
|
||||||
|
2:11/0/probability = 0.2
|
||||||
2:11/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
|
2:11/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
|
||||||
2:11/0/terrains_peering_bit/right_side = 1
|
2:11/0/terrains_peering_bit/right_side = 1
|
||||||
2:11/0/terrains_peering_bit/bottom_right_corner = 1
|
2:11/0/terrains_peering_bit/bottom_right_corner = 1
|
||||||
@@ -821,6 +824,7 @@ texture = ExtResource("2_k3fip")
|
|||||||
3:11/0 = 0
|
3:11/0 = 0
|
||||||
3:11/0/terrain_set = 0
|
3:11/0/terrain_set = 0
|
||||||
3:11/0/terrain = 1
|
3:11/0/terrain = 1
|
||||||
|
3:11/0/probability = 0.2
|
||||||
3:11/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
|
3:11/0/physics_layer_0/polygon_0/points = PackedVector2Array(-8, -8, 8, -8, 8, 8, -8, 8)
|
||||||
3:11/0/terrains_peering_bit/right_side = 1
|
3:11/0/terrains_peering_bit/right_side = 1
|
||||||
3:11/0/terrains_peering_bit/bottom_right_corner = 1
|
3:11/0/terrains_peering_bit/bottom_right_corner = 1
|
||||||
|
Reference in New Issue
Block a user