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)
|
||||
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")
|
||||
area2d = NodePath("..")
|
||||
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="PackedScene" uid="uid://h60obxmju6mo" path="res://scenes/test.tscn" id="2_bentb"]
|
||||
|
||||
[node name="GameManager" type="Node"]
|
||||
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"]
|
||||
|
||||
[sub_resource type="RectangleShape2D" id="RectangleShape2D_hkd8b"]
|
||||
size = Vector2(12, 17)
|
||||
size = Vector2(38, 22)
|
||||
|
||||
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_lqw6h"]
|
||||
bg_color = Color(0, 0, 0, 1)
|
||||
@@ -18,7 +18,7 @@ ui_root = NodePath("Panel")
|
||||
tooltip_label = NodePath("Panel/PanelContainer/Label")
|
||||
|
||||
[node name="CollisionShape2D" type="CollisionShape2D" parent="."]
|
||||
position = Vector2(0, -0.5)
|
||||
position = Vector2(1, -3)
|
||||
shape = SubResource("RectangleShape2D_hkd8b")
|
||||
|
||||
[node name="Sprite2D" type="Sprite2D" parent="."]
|
||||
|
@@ -5,3 +5,4 @@
|
||||
[resource]
|
||||
script = ExtResource("1_2d5tb")
|
||||
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 collectable_data: CollectableResource
|
||||
@export var sfx: AudioStreamPlayer2D
|
||||
signal collected(amount: int)
|
||||
signal collected(amount: int, type: CollectableResource.CollectableType)
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
@@ -24,7 +24,7 @@ func _ready() -> void:
|
||||
|
||||
func _on_area2d_body_entered(body: Node2D) -> void:
|
||||
if body.has_node("CanPickUpComponent"):
|
||||
collected.emit(collectable_data.amount)
|
||||
collected.emit(collectable_data.amount, collectable_data.type)
|
||||
if sfx:
|
||||
sfx.play()
|
||||
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()
|
||||
else:
|
||||
gm.remove_lives(1)
|
||||
gm.set_coins(0)
|
||||
|
||||
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"
|
||||
|
||||
|
||||
func _ready():
|
||||
await get_tree().process_frame
|
||||
var coins = get_tree().get_nodes_in_group("coins")
|
||||
|
||||
|
||||
for coin in coins:
|
||||
coin.connect("collected", on_collected)
|
||||
|
||||
func on_collected(amount: int) -> void:
|
||||
|
||||
func on_collected(amount: int, type: CollectableResource.CollectableType) -> void:
|
||||
if not game_manager:
|
||||
return
|
||||
|
||||
if type != CollectableResource.CollectableType.COIN:
|
||||
return
|
||||
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
|
||||
extends Node
|
||||
|
||||
var player_state = {
|
||||
"coins": 0,
|
||||
"lives": 3,
|
||||
"unlocked_skills": [],
|
||||
}
|
||||
@export var level_scenes: Array[PackedScene]
|
||||
|
||||
@export var player_state := {
|
||||
"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:
|
||||
@@ -59,4 +116,16 @@ func reset_player_state() -> void:
|
||||
"coins": 0,
|
||||
"lives": 3,
|
||||
"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
|
||||
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/terrain_set = 0
|
||||
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/terrains_peering_bit/right_side = 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/terrain_set = 0
|
||||
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/terrains_peering_bit/right_side = 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/terrain_set = 0
|
||||
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/terrains_peering_bit/right_side = 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/terrain_set = 0
|
||||
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/terrains_peering_bit/right_side = 1
|
||||
3:11/0/terrains_peering_bit/bottom_right_corner = 1
|
||||
|
Reference in New Issue
Block a user