From ddfa8d4f453fa909dde6918cdb8eb37f99b25f95 Mon Sep 17 00:00:00 2001 From: Kellan KOZUME Date: Sun, 19 Apr 2026 13:11:22 -0400 Subject: [PATCH] feat(puzzle): add pushable box mechanic and unlock zone --- assets/sprites/engrenage.png | Bin 0 -> 821 bytes assets/sprites/engrenage.png.import | 40 ++++++++++++++++++ assets/tilesets/etagere.png | Bin 0 -> 1822 bytes assets/tilesets/etagere.png.import | 40 ++++++++++++++++++ entities/items/engrenage/engrenage.gd | 10 +++++ entities/items/engrenage/engrenage.gd.uid | 1 + entities/items/engrenage/engrenage.tscn | 23 ++++++++++ entities/items/item.gd | 2 +- entities/items/pushable box/pushable_box.gd | 13 ++++++ .../items/pushable box/pushable_box.gd.uid | 1 + entities/items/pushable box/pushable_box.tscn | 21 +++++++++ entities/npcs/vrac7/vrac7.gd | 2 +- entities/player/player.gd | 26 ++++++++++++ entities/player/player.tscn | 7 ++- levels/entrepot/entrepot.tscn | 21 +++++++-- levels/unlock_zone.gd | 26 ++++++++++++ levels/unlock_zone.gd.uid | 1 + levels/unlock_zone.tscn | 13 ++++++ ui/hud.tscn | 2 + 19 files changed, 242 insertions(+), 7 deletions(-) create mode 100755 assets/sprites/engrenage.png create mode 100644 assets/sprites/engrenage.png.import create mode 100755 assets/tilesets/etagere.png create mode 100644 assets/tilesets/etagere.png.import create mode 100644 entities/items/engrenage/engrenage.gd create mode 100644 entities/items/engrenage/engrenage.gd.uid create mode 100644 entities/items/engrenage/engrenage.tscn create mode 100644 entities/items/pushable box/pushable_box.gd create mode 100644 entities/items/pushable box/pushable_box.gd.uid create mode 100644 entities/items/pushable box/pushable_box.tscn create mode 100644 levels/unlock_zone.gd create mode 100644 levels/unlock_zone.gd.uid create mode 100644 levels/unlock_zone.tscn diff --git a/assets/sprites/engrenage.png b/assets/sprites/engrenage.png new file mode 100755 index 0000000000000000000000000000000000000000..8289d5dc96c57817fab97cf75a2714b7523e9c66 GIT binary patch literal 821 zcmV-51Iqk~P)Px%?@2^KR9J0jiqR1fomJthm(L>;-RcU1@f>{q>Us$PD3=O~g1v(oro%Q|-xhQI zP6aRCepE1J1H$RBt-a$-2pxpuDp%n8HsEImCy#KEy~901vL#QPoLyuF;$Y=cL5wuI z6$5DDU0SK&I>qw0tLtUN(0-?4JeW2JTg?Ul;OUdcT7YhKrEHph`Ktv0faRYX0Kmfg zs$gn^5C*cL(|ntKR_2``hj*`=Vh_)fey4)pKfVJRwxlZvDaVVoI$YmY6w%2?6Aw<1 zQ@{aWH1ULY_;u_bp2GEQ6l-MkP z*qEV|RDzIBtRor*Zs~?>m{yo!iLVu5+YkLfRmw6acD- zp>F6prEYa4SkMV_Vvyw5(W~@$I};QaVfDYxZP zLG%c`Pv~v`i!>ngy%7cqP`A3mhsCdC0{}!8@@8T*@i3Zr+7tFW6^tgHDAjUPqXX9& zAh?`^LP{fDw?yIuIgk$8OS;lDBqR}bWE(>O`1JmbXfQ}z-zJuXj$uuOEUvPdUNu57 zr&g&{C+QFp_cTjPx**hxe|RCt{2TTMt@R}}t~qJv?ulnG>Eg^>nf5{2g~i7N@jl5C`<#frOZgsh~{ zm2@Gti$D+x1)*eTC8X54Nr?e*Wz$s#)D%iW1v`sCW+Oue$IWyxbKabL-nsYPH~wVQ zeh@mockaFCJNMr6-u=!iaL&<|(7t-e_Q!>${YpZhdVA(R03bU!h@H(%{66Pwq6gEDa<+0VW=Gc~F7(#& z&z~>LPCEd2Qn%@zm+tOhGX#cO9_l?ISy$KSMym1{PeEbR@gT#~2PCw}JH!`;n?vt~G?uluP%q;+n zD|i6pjk5~LF_HsZLC6jchQE`(b00UjZ#HP$A_0(lgkxuOGaSfgz>|W{#1JnTgm!6o z8dm`K#WgWrE5K)Ll^0j8IB5*!`osKW z^NVxhHi=dM*fMLSM<)5w%oYf9fG?rX$G?!an%HpSaLv91_uoi@wnv3*OeaSEem&fC zfQ>>&L>1!TXLKoa@H2i~A2b$${CP1k?F@p(FVUMICr?fe_Z%2x^80Dz_tWUgbfPQM zY5Xm*QRq;`4cU(WP2l5_FMCV#UK}_QJqGud<|B#=*Xx2*#URSbNuo*aakAxN1!d!; z+kyOky5U!Sf_&i{fKU|Wvk;_8QHiWj`wuy7(*(ivKkXVJDuYE8Xt_Ej$40TZvRd^y zsj4|ZpgK7=8V^cz?O9;kq;Oj?!R5jvi03;^I zMv>pI|4}gSX+;VfG1m0u!a|^QW(H6-8 zMBb(fbK&tCvx!rN2hv4vVU*j(DZ&s!sm=b$%QDtyri>s!YJzf)#5rs#znNI+TRIm< zQubx^FBD;y&%A$L9Krvpu<{r@x2iCKtEV=!k`_RS^U0=mM`ZEy0PA7sJR;FysMRI0 zW_*gQ0NX30M60U8Hps^xA(1TJN;;qoE*}pqi}NV9(h7j5nx&zsB-n~ijAng`9EW|E zIZHV2T@>|6ezp~&7Drt{`1R2*0DzmXS0b;Mn$RhQ6gWO|k~Ugft$p9}EY?05GisL_ zVsk*;KBD`5%d-*3rNBu}(|O$#EKE6#|K@%0v%VxP^@p3USMbkg-#QB;8o$UFB5@${ zd}gE^E)`&IrwJLhAjyDo0d}Ln$FIp^eao{z?&nwz&eNbPnXJ!DAxJ@y$HYg9h1#_s zRnrYQvAAytrA?43pDS{YJSgQ*G^8qP^YmV>Tq zqUNpZmkd>y%V2y3aLF5r1jYj)WH3Vzr58MB5_GA;u*u*Sxb`oE?#F*?wn;v?CLe7< zfX`t_+XlQ6B#R?d1CUiBZRVwo&vj|TZFwS(pAMskhOiP*8w#WApxfOQ@;?E zB{+_@6}VKlD`a9EGSTcwP5F~erZ3n%=OcIw+T zp4rx|^}Bp*^r;tatgph~|L~Kw)6)oBGK~8|r0tCSvvQ1V0oo&rE7?QFytSZxDGseJ z(28o$Q9 void: + GameState.add_item(item_id) + print("Ramassé : ", item_name) + queue_free() # supprime l'item de la scène diff --git a/entities/items/engrenage/engrenage.gd.uid b/entities/items/engrenage/engrenage.gd.uid new file mode 100644 index 0000000..a76d508 --- /dev/null +++ b/entities/items/engrenage/engrenage.gd.uid @@ -0,0 +1 @@ +uid://dqijs5dhcpahu diff --git a/entities/items/engrenage/engrenage.tscn b/entities/items/engrenage/engrenage.tscn new file mode 100644 index 0000000..972809e --- /dev/null +++ b/entities/items/engrenage/engrenage.tscn @@ -0,0 +1,23 @@ +[gd_scene format=3 uid="uid://cge56ob5tt4o6"] + +[ext_resource type="Script" uid="uid://ps4bl4k552ia" path="res://entities/items/item.gd" id="1_m0k53"] +[ext_resource type="Texture2D" uid="uid://b1f05yx168iat" path="res://assets/sprites/engrenage.png" id="2_0b3f0"] + +[sub_resource type="CircleShape2D" id="CircleShape2D_l3fek"] +radius = 8.0 + +[node name="Item" type="Node2D" unique_id=1691516870] + +[node name="Area2D" type="Area2D" parent="." unique_id=260230698] +collision_layer = 8 +collision_mask = 0 +script = ExtResource("1_m0k53") + +[node name="Sprite2D" type="Sprite2D" parent="Area2D" unique_id=1835094462] +scale = Vector2(0.5, 0.5) +texture = ExtResource("2_0b3f0") +region_enabled = true +region_rect = Rect2(0, 0, 32, 32) + +[node name="CollisionShape2D" type="CollisionShape2D" parent="Area2D" unique_id=1351590810] +shape = SubResource("CircleShape2D_l3fek") diff --git a/entities/items/item.gd b/entities/items/item.gd index c82518a..5657c7b 100644 --- a/entities/items/item.gd +++ b/entities/items/item.gd @@ -7,4 +7,4 @@ extends Area2D func interact() -> void: GameState.add_item(item_id) print("Ramassé : ", item_name) - queue_free() # supprime l'item de la scène + queue_free() diff --git a/entities/items/pushable box/pushable_box.gd b/entities/items/pushable box/pushable_box.gd new file mode 100644 index 0000000..c66cf4d --- /dev/null +++ b/entities/items/pushable box/pushable_box.gd @@ -0,0 +1,13 @@ +class_name PushableBox +extends CharacterBody2D + +func _ready() -> void: + add_to_group("pushable") + +func try_push(direction: Vector2, tile_size: float) -> bool: + var motion := direction * tile_size + var collision := move_and_collide(motion) + if collision: + move_and_collide(-motion) + return false + return true diff --git a/entities/items/pushable box/pushable_box.gd.uid b/entities/items/pushable box/pushable_box.gd.uid new file mode 100644 index 0000000..3dae953 --- /dev/null +++ b/entities/items/pushable box/pushable_box.gd.uid @@ -0,0 +1 @@ +uid://ghp173k2ioey diff --git a/entities/items/pushable box/pushable_box.tscn b/entities/items/pushable box/pushable_box.tscn new file mode 100644 index 0000000..ecfd7c3 --- /dev/null +++ b/entities/items/pushable box/pushable_box.tscn @@ -0,0 +1,21 @@ +[gd_scene format=3 uid="uid://1x65ioo8tdro"] + +[ext_resource type="Texture2D" uid="uid://bbr6t3088svah" path="res://assets/tilesets/entrepot-tilesets.png" id="1_1rdxk"] +[ext_resource type="Script" uid="uid://ghp173k2ioey" path="res://entities/items/pushable box/pushable_box.gd" id="1_cwr2g"] + +[sub_resource type="RectangleShape2D" id="RectangleShape2D_cwr2g"] +size = Vector2(26, 28) + +[node name="PushableBox" type="CharacterBody2D" unique_id=418482729] +collision_layer = 32 +collision_mask = 33 +script = ExtResource("1_cwr2g") + +[node name="Sprite2D" type="Sprite2D" parent="." unique_id=1829584255] +texture = ExtResource("1_1rdxk") +region_enabled = true +region_rect = Rect2(128, 64, 32, 32) + +[node name="CollisionShape2D" type="CollisionShape2D" parent="." unique_id=330974052] +position = Vector2(0, -2) +shape = SubResource("RectangleShape2D_cwr2g") diff --git a/entities/npcs/vrac7/vrac7.gd b/entities/npcs/vrac7/vrac7.gd index 025c0da..d855a89 100644 --- a/entities/npcs/vrac7/vrac7.gd +++ b/entities/npcs/vrac7/vrac7.gd @@ -118,7 +118,7 @@ func _on_repair_done() -> void: var hud: HUD = get_tree().get_first_node_in_group("hud") if hud: hud.show_log("Unité VRAC-7 : réparation complète. Statut : opérationnel.") - await get_tree().create_timer(0.5).timeout + await get_tree().create_timer(3).timeout hud.show_log("Clé magnétique obtenue. Accès atelier déverrouillé.") # Dialogue post-réparation diff --git a/entities/player/player.gd b/entities/player/player.gd index d5fe6e0..ad33b07 100644 --- a/entities/player/player.gd +++ b/entities/player/player.gd @@ -1,9 +1,11 @@ extends CharacterBody2D const SPEED := 120 +const TILE_SIZE := 16 @onready var sprite := $AnimatedSprite2D @onready var interaction_area := $InteractionArea +@onready var push_ray := $PushRay @onready var hud : HUD = get_tree().get_first_node_in_group("hud") @@ -20,16 +22,40 @@ func _ready() -> void: add_to_group("player") interaction_area.area_entered.connect(_on_interaction_area_area_entered) interaction_area.area_exited.connect(_on_interaction_area_area_exited) + if push_ray: + push_ray.target_position = Vector2(17, 0) func _physics_process(_delta: float) -> void: + if is_locked: + velocity = Vector2.ZERO + move_and_slide() + return + var direction := Input.get_vector( "move_left", "move_right", "move_up", "move_down" ) + + if push_ray and direction != Vector2.ZERO: + var dominant := _dominant_direction(direction) + push_ray.target_position = dominant * (TILE_SIZE / 2.0 + 1) + push_ray.force_raycast_update() + + if push_ray.is_colliding(): + var collider = push_ray.get_collider() + if collider is PushableBox: + collider.try_push(dominant, TILE_SIZE) + velocity = direction * SPEED move_and_slide() position = position.round() _update_animation(direction) +func _dominant_direction(dir: Vector2) -> Vector2: + if abs(dir.x) > abs(dir.y): + return Vector2(sign(dir.x), 0) + else: + return Vector2(0, sign(dir.y)) + func _unhandled_input(event: InputEvent) -> void: if event.is_action_pressed("interact") and interactable: interactable.interact() diff --git a/entities/player/player.tscn b/entities/player/player.tscn index 6dd9a42..97274ef 100644 --- a/entities/player/player.tscn +++ b/entities/player/player.tscn @@ -509,7 +509,8 @@ animations = [{ size = Vector2(45.375, 42.84375) [node name="CharacterBody2D" type="CharacterBody2D" unique_id=1424887591] -collision_layer = 3 +collision_layer = 2 +collision_mask = 33 script = ExtResource("1_fkugw") [node name="CollisionShape2D" type="CollisionShape2D" parent="." unique_id=2097287881] @@ -534,3 +535,7 @@ collision_mask = 12 position = Vector2(1, 9) shape = SubResource("RectangleShape2D_bectd") debug_color = Color(0.9411765, 0, 0.29411766, 0.19607843) + +[node name="PushRay" type="RayCast2D" parent="." unique_id=121926408] +target_position = Vector2(32, 0) +collision_mask = 32 diff --git a/levels/entrepot/entrepot.tscn b/levels/entrepot/entrepot.tscn index 0e7c310..7a9d8af 100644 --- a/levels/entrepot/entrepot.tscn +++ b/levels/entrepot/entrepot.tscn @@ -6,7 +6,9 @@ [ext_resource type="PackedScene" uid="uid://bb3olg2rlygdc" path="res://entities/npcs/vrac7/vrac7.tscn" id="3_jr8qv"] [ext_resource type="PackedScene" uid="uid://jrjxu1xfx0ud" path="res://ui/dialogue_box.tscn" id="5_s155k"] [ext_resource type="PackedScene" uid="uid://o7qrmpywwhu8" path="res://ui/hud.tscn" id="6_kejd5"] -[ext_resource type="PackedScene" uid="uid://grs5ypwkxv3x" path="res://entities/items/item.tscn" id="6_srx2q"] +[ext_resource type="PackedScene" uid="uid://cge56ob5tt4o6" path="res://entities/items/engrenage/engrenage.tscn" id="7_1p1pm"] +[ext_resource type="PackedScene" uid="uid://1x65ioo8tdro" path="res://entities/items/pushable box/pushable_box.tscn" id="7_dm063"] +[ext_resource type="PackedScene" uid="uid://c52luh50w8hi2" path="res://levels/unlock_zone.tscn" id="8_dm063"] [sub_resource type="TileSetAtlasSource" id="TileSetAtlasSource_n70cd"] texture = ExtResource("1_qvgxo") @@ -149,7 +151,6 @@ sources/0 = SubResource("TileSetAtlasSource_n70cd") script = ExtResource("1_ptc2q") [node name="Hud" parent="." unique_id=1774402684 instance=ExtResource("6_kejd5")] -position = Vector2(199, 301) [node name="DialogueBox" parent="." unique_id=1374394268 instance=ExtResource("5_s155k")] position = Vector2(-118, 137) @@ -196,8 +197,20 @@ tile_set = SubResource("TileSet_jr8qv") [node name="Other" type="TileMapLayer" parent="Map" unique_id=985720640] tile_set = SubResource("TileSet_jr8qv") -[node name="Item" parent="Map" unique_id=1691516870 instance=ExtResource("6_srx2q")] -position = Vector2(136, 263) +[node name="Engrenage" parent="Map" unique_id=46489013 instance=ExtResource("7_1p1pm")] +position = Vector2(167, 263) + +[node name="HiddenEngrenage" parent="Map" unique_id=1691516870 instance=ExtResource("7_1p1pm")] +visible = false +position = Vector2(455, 328) + +[node name="PushableBox" parent="Map" unique_id=418482729 instance=ExtResource("7_dm063")] +position = Vector2(392, 420) + +[node name="UnlockZone" parent="Map" unique_id=448954065 instance=ExtResource("8_dm063")] +position = Vector2(458, 376) +scale = Vector2(5, 6.5) +node_to_reveal = NodePath("../HiddenEngrenage") [node name="Player" parent="." unique_id=628518902 instance=ExtResource("2_n70cd")] z_index = 1 diff --git a/levels/unlock_zone.gd b/levels/unlock_zone.gd new file mode 100644 index 0000000..a1db370 --- /dev/null +++ b/levels/unlock_zone.gd @@ -0,0 +1,26 @@ +class_name UnlockZone +extends Area2D + +@export var flag_to_set: String = "" +@export var node_to_reveal: NodePath = NodePath("") + +var _triggered := false + +func _ready() -> void: + body_entered.connect(_on_body_entered) + +func _on_body_entered(body: Node) -> void: + if _triggered: + return + if not body.is_in_group("pushable"): + return + + _triggered = true + + if flag_to_set != "": + GameState.set_flag(flag_to_set, true) + + if not node_to_reveal.is_empty(): + var node = get_node_or_null(node_to_reveal) + if node: + node.show() diff --git a/levels/unlock_zone.gd.uid b/levels/unlock_zone.gd.uid new file mode 100644 index 0000000..838120e --- /dev/null +++ b/levels/unlock_zone.gd.uid @@ -0,0 +1 @@ +uid://bp7xyba18cvpj diff --git a/levels/unlock_zone.tscn b/levels/unlock_zone.tscn new file mode 100644 index 0000000..88a7220 --- /dev/null +++ b/levels/unlock_zone.tscn @@ -0,0 +1,13 @@ +[gd_scene format=3 uid="uid://c52luh50w8hi2"] + +[ext_resource type="Script" uid="uid://bp7xyba18cvpj" path="res://levels/unlock_zone.gd" id="1_s6vo7"] + +[sub_resource type="RectangleShape2D" id="RectangleShape2D_ucfsg"] + +[node name="UnlockZone" type="Area2D" unique_id=448954065] +collision_layer = 16 +collision_mask = 32 +script = ExtResource("1_s6vo7") + +[node name="CollisionShape2D" type="CollisionShape2D" parent="." unique_id=1908169056] +shape = SubResource("RectangleShape2D_ucfsg") diff --git a/ui/hud.tscn b/ui/hud.tscn index be12a01..3981c94 100644 --- a/ui/hud.tscn +++ b/ui/hud.tscn @@ -1,6 +1,7 @@ [gd_scene format=3 uid="uid://o7qrmpywwhu8"] [ext_resource type="Script" uid="uid://bmqknwqr5mtd6" path="res://ui/hud.gd" id="1_rbyyf"] +[ext_resource type="Texture2D" uid="uid://b1f05yx168iat" path="res://assets/sprites/engrenage.png" id="2_276te"] [sub_resource type="StyleBoxFlat" id="StyleBoxFlat_rbyyf"] bg_color = Color(0.101960786, 0.101960786, 0.101960786, 0.84705883) @@ -37,6 +38,7 @@ layout_mode = 2 [node name="Icon" type="TextureRect" parent="InventoryBar/ItemRow/EngrenageSlot" unique_id=1231030010] layout_mode = 2 +texture = ExtResource("2_276te") [node name="Count" type="Label" parent="InventoryBar/ItemRow/EngrenageSlot" unique_id=1232241990] layout_mode = 2