diff --git a/assets/cat/movement/eating_player.png b/assets/cat/movement/eating_player.png new file mode 100644 index 0000000..546d9b2 Binary files /dev/null and b/assets/cat/movement/eating_player.png differ diff --git a/behavior-tree/cat/can_see_player.gd b/behavior-tree/cat/can_see_player.gd index 0364288..f4e36b1 100644 --- a/behavior-tree/cat/can_see_player.gd +++ b/behavior-tree/cat/can_see_player.gd @@ -1,17 +1,27 @@ extends BTCondition @export var player_key: String = "player" -@export var view_distance: float = 200.0 +var player_dummy +var player_in_sight = false func tick(blackboard: Dictionary) -> int: - var actor = blackboard["actor"] var player = blackboard.get(player_key) - - # Check if the player exists and is within the view distance - if player != null and (player.global_position - actor.global_position).length() <= view_distance: + + if blackboard["eating_player"]: + return SUCCESS + elif player_in_sight: blackboard["sees_player"] = true - print("sees the player") + blackboard["player"] = player_dummy return SUCCESS else: blackboard["sees_player"] = false return FAILURE + +func _on_detection_area_body_entered(body: Node2D) -> void: + if body.is_in_group("player"): + player_dummy = body + player_in_sight = true + +func _on_detection_area_body_exited(body: Node2D) -> void: + if body.is_in_group("player"): + player_in_sight = false diff --git a/behavior-tree/cat/cat_mouth.gd b/behavior-tree/cat/cat_mouth.gd new file mode 100644 index 0000000..6ca7ea9 --- /dev/null +++ b/behavior-tree/cat/cat_mouth.gd @@ -0,0 +1,12 @@ +extends Area2D + +@onready var animated_sprite_cat: AnimatedSprite2D = %animated_sprite_cat + +func _on_body_entered(body: Node) -> void: + if body.is_flying or not body.has_method("die"): + return + + animated_sprite_cat.play("eating") + body.animated_sprite_2d.visible = false + + body.die() diff --git a/behavior-tree/cat/chase_player.gd b/behavior-tree/cat/chase_player.gd index d0e5873..1d23dae 100644 --- a/behavior-tree/cat/chase_player.gd +++ b/behavior-tree/cat/chase_player.gd @@ -2,11 +2,16 @@ extends BTAction @export var chase_speed: float = 150.0 @export var stop_distance: float = 10.0 +@onready var cat_mouth: Area2D = %cat_mouth +var eat_range = false func tick(blackboard: Dictionary) -> int: var actor = blackboard["actor"] var player = blackboard.get("player") + if blackboard["eating_player"]: + return SUCCESS + if player == null or not blackboard["sees_player"]: return FAILURE @@ -25,9 +30,16 @@ func tick(blackboard: Dictionary) -> int: # Play the walking animation actor.get_node("animated_sprite_cat").play("walk") + + if eat_range: + return SUCCESS + return RUNNING else: # Stop the actor and play idle animation actor.velocity = Vector2.ZERO actor.get_node("animated_sprite_cat").play("idle") - return SUCCESS + return FAILURE + +func _on_cat_mouth_body_entered(body: Node2D) -> void: + eat_range = true diff --git a/behavior-tree/cat/do_need.gd b/behavior-tree/cat/do_need.gd index 62717b7..fb6d8cb 100644 --- a/behavior-tree/cat/do_need.gd +++ b/behavior-tree/cat/do_need.gd @@ -4,9 +4,12 @@ extends BTAction @export var rate: String @export var action: String @onready var detection_area_polygon: CollisionPolygon2D = %detection_area_polygon +@onready var cat_mouth_area_polygon: CollisionShape2D = %cat_mouth_area_polygon func tick(blackboard: Dictionary) -> int: detection_area_polygon.disabled = true + cat_mouth_area_polygon.disabled = true + blackboard[need] -= blackboard["delta"] * blackboard[rate] # Cat is satisfied with need diff --git a/behavior-tree/cat/eat_player.gd b/behavior-tree/cat/eat_player.gd new file mode 100644 index 0000000..7a02098 --- /dev/null +++ b/behavior-tree/cat/eat_player.gd @@ -0,0 +1,21 @@ +extends BTAction + +@export var need: String +@export var rate: String +@export var action: String +@onready var detection_area_polygon: CollisionPolygon2D = %detection_area_polygon + +func tick(blackboard: Dictionary) -> int: + blackboard["eating_player"] = true + blackboard["hunger_for_player"] -= blackboard["delta"] * blackboard[rate] + + # Cat is satisfied with need + if blackboard[need] < 0: + blackboard[need] = 0 + blackboard[action] = false + return SUCCESS + + var animated_sprite = blackboard["actor"].get_node("animated_sprite_cat") + animated_sprite.play("eating_player") + + return RUNNING diff --git a/behavior-tree/nodes/bt_node.gd b/behavior-tree/nodes/bt_node.gd index a811442..9535e37 100644 --- a/behavior-tree/nodes/bt_node.gd +++ b/behavior-tree/nodes/bt_node.gd @@ -4,5 +4,5 @@ enum { SUCCESS, FAILURE, RUNNING } ## Executes this node and returns a status code. ## This method must be overwritten. -func tick(blackboard: Dictionary) -> int: +func tick(_blackboard: Dictionary) -> int: return SUCCESS diff --git a/behavior-tree/nodes/bt_tree.gd b/behavior-tree/nodes/bt_tree.gd index b3e0fa2..266d7f5 100644 --- a/behavior-tree/nodes/bt_tree.gd +++ b/behavior-tree/nodes/bt_tree.gd @@ -2,8 +2,8 @@ class_name BTTree extends Node enum Status { SUCCESS, FAILURE, RUNNING } -#@onready var detection_area: Area2D = %detection_area @onready var detection_area_polygon: CollisionPolygon2D = %detection_area_polygon +@onready var cat_mouth_area_polygon: CollisionShape2D = %cat_mouth_area_polygon var root: BTSelector var actor: CharacterBody2D @@ -15,6 +15,8 @@ var blackboard: Dictionary = { # Chase "sees_player": false , # Action "chases_player": false , # Action + "eating_player": false , # Condition + "hunger_for_player": 100 , # Hunger "hunger": 0.0, # Need @@ -50,6 +52,7 @@ func _ready(): func _process(delta): blackboard["delta"] = delta detection_area_polygon.disabled = false + cat_mouth_area_polygon.disabled = false if root: root.tick(blackboard) @@ -57,15 +60,3 @@ func _process(delta): blackboard["hunger"] = min(blackboard["hunger"] + blackboard["hunger_increase_rate"] * delta, blackboard["max_hunger"]) blackboard["tiredness"] = min(blackboard["tiredness"] + blackboard["tiredness_increase_rate"] * delta, blackboard["max_tiredness"]) #print("Hunger: %.2f, Tiredness: %.2f" % [blackboard["hunger"], blackboard["tiredness"]]) - -# When a body enters the detection area -func _on_DetectionArea_body_entered(body: Node2D) -> void: - if body.is_in_group("player"): - blackboard["sees_player"] = true - blackboard["player"] = body - -# When a body exits the detection area -func _on_DetectionArea_body_exited(body: Node2D) -> void: - if body.is_in_group("player"): - blackboard["sees_player"] = false - blackboard["player"] = null diff --git a/behavior-tree/nodes/leaves/condition.gd b/behavior-tree/nodes/leaves/condition.gd index 313cb9e..a96722a 100644 --- a/behavior-tree/nodes/leaves/condition.gd +++ b/behavior-tree/nodes/leaves/condition.gd @@ -1,4 +1,4 @@ class_name BTCondition extends BTLeafNode -func tick(blackboard: Dictionary) -> int: +func tick(_blackboard: Dictionary) -> int: return SUCCESS diff --git a/scenes/characters/enemies/cat/cat.tscn b/scenes/characters/enemies/cat/cat.tscn index de70116..1abdf94 100644 --- a/scenes/characters/enemies/cat/cat.tscn +++ b/scenes/characters/enemies/cat/cat.tscn @@ -1,7 +1,8 @@ -[gd_scene load_steps=132 format=3 uid="uid://tspy04gfoqh8"] +[gd_scene load_steps=152 format=3 uid="uid://tspy04gfoqh8"] [ext_resource type="Texture2D" uid="uid://d31nklwcmjbiq" path="res://assets/cat/movement/eating.png" id="2_1nhte"] [ext_resource type="Texture2D" uid="uid://bpbtt7kb345i2" path="res://assets/cat/movement/idle_sit.png" id="2_cmdkj"] +[ext_resource type="Texture2D" uid="uid://4s4ti8jlln4n" path="res://assets/cat/movement/eating_player.png" id="2_d1qbv"] [ext_resource type="Texture2D" uid="uid://cxwvvcbosab42" path="res://assets/cat/movement/sleep.png" id="3_oifql"] [ext_resource type="Texture2D" uid="uid://dowwmkmjj60uf" path="res://assets/cat/movement/stretch.png" id="4_1wgy5"] [ext_resource type="Texture2D" uid="uid://2623xhcrqed7" path="res://assets/cat/movement/walk.png" id="5_wdolk"] @@ -13,10 +14,12 @@ [ext_resource type="Script" path="res://behavior-tree/cat/is_target_available.gd" id="10_1fgmj"] [ext_resource type="Script" path="res://behavior-tree/cat/chase_player.gd" id="10_pxn7j"] [ext_resource type="Script" path="res://behavior-tree/cat/walk_to_target.gd" id="11_j8rw6"] +[ext_resource type="Script" path="res://behavior-tree/cat/eat_player.gd" id="11_xt86y"] [ext_resource type="Script" path="res://behavior-tree/cat/do_need.gd" id="11_ylqhf"] [ext_resource type="Script" path="res://behavior-tree/cat/wander.gd" id="12_sv6u5"] [ext_resource type="Script" path="res://behavior-tree/cat/is_food_on_plate.gd" id="13_4v030"] [ext_resource type="Script" path="res://behavior-tree/cat/remove_food.gd" id="13_rtby5"] +[ext_resource type="Script" path="res://behavior-tree/cat/cat_mouth.gd" id="18_3qynt"] [sub_resource type="AtlasTexture" id="AtlasTexture_wtp3v"] atlas = ExtResource("2_1nhte") @@ -82,6 +85,70 @@ region = Rect2(896, 0, 64, 32) atlas = ExtResource("2_1nhte") region = Rect2(960, 0, 64, 32) +[sub_resource type="AtlasTexture" id="AtlasTexture_u4wjq"] +atlas = ExtResource("2_d1qbv") +region = Rect2(1024, 0, 64, 32) + +[sub_resource type="AtlasTexture" id="AtlasTexture_lnn0d"] +atlas = ExtResource("2_d1qbv") +region = Rect2(1088, 0, 64, 32) + +[sub_resource type="AtlasTexture" id="AtlasTexture_3ykg5"] +atlas = ExtResource("2_d1qbv") +region = Rect2(1152, 0, 64, 32) + +[sub_resource type="AtlasTexture" id="AtlasTexture_poi1j"] +atlas = ExtResource("2_d1qbv") +region = Rect2(1216, 0, 64, 32) + +[sub_resource type="AtlasTexture" id="AtlasTexture_rx4gb"] +atlas = ExtResource("2_d1qbv") +region = Rect2(1280, 0, 64, 32) + +[sub_resource type="AtlasTexture" id="AtlasTexture_cfs12"] +atlas = ExtResource("2_d1qbv") +region = Rect2(1344, 0, 64, 32) + +[sub_resource type="AtlasTexture" id="AtlasTexture_2h1ji"] +atlas = ExtResource("2_d1qbv") +region = Rect2(1408, 0, 64, 32) + +[sub_resource type="AtlasTexture" id="AtlasTexture_4ecye"] +atlas = ExtResource("2_d1qbv") +region = Rect2(1472, 0, 64, 32) + +[sub_resource type="AtlasTexture" id="AtlasTexture_3noy6"] +atlas = ExtResource("2_d1qbv") +region = Rect2(1536, 0, 64, 32) + +[sub_resource type="AtlasTexture" id="AtlasTexture_wlwij"] +atlas = ExtResource("2_d1qbv") +region = Rect2(1600, 0, 64, 32) + +[sub_resource type="AtlasTexture" id="AtlasTexture_iq2ra"] +atlas = ExtResource("2_d1qbv") +region = Rect2(1664, 0, 64, 32) + +[sub_resource type="AtlasTexture" id="AtlasTexture_mqh6q"] +atlas = ExtResource("2_d1qbv") +region = Rect2(1728, 0, 64, 32) + +[sub_resource type="AtlasTexture" id="AtlasTexture_5uuj5"] +atlas = ExtResource("2_d1qbv") +region = Rect2(1792, 0, 64, 32) + +[sub_resource type="AtlasTexture" id="AtlasTexture_lu4ju"] +atlas = ExtResource("2_d1qbv") +region = Rect2(1856, 0, 64, 32) + +[sub_resource type="AtlasTexture" id="AtlasTexture_15g3l"] +atlas = ExtResource("2_d1qbv") +region = Rect2(1920, 0, 64, 32) + +[sub_resource type="AtlasTexture" id="AtlasTexture_24ifv"] +atlas = ExtResource("2_d1qbv") +region = Rect2(1984, 0, 64, 32) + [sub_resource type="AtlasTexture" id="AtlasTexture_3jmpl"] atlas = ExtResource("2_cmdkj") region = Rect2(1024, 0, 64, 32) @@ -523,6 +590,59 @@ animations = [{ }, { "frames": [{ "duration": 1.0, +"texture": SubResource("AtlasTexture_u4wjq") +}, { +"duration": 1.0, +"texture": SubResource("AtlasTexture_lnn0d") +}, { +"duration": 1.0, +"texture": SubResource("AtlasTexture_3ykg5") +}, { +"duration": 1.0, +"texture": SubResource("AtlasTexture_poi1j") +}, { +"duration": 1.0, +"texture": SubResource("AtlasTexture_rx4gb") +}, { +"duration": 1.0, +"texture": SubResource("AtlasTexture_cfs12") +}, { +"duration": 1.0, +"texture": SubResource("AtlasTexture_2h1ji") +}, { +"duration": 1.0, +"texture": SubResource("AtlasTexture_4ecye") +}, { +"duration": 1.0, +"texture": SubResource("AtlasTexture_3noy6") +}, { +"duration": 1.0, +"texture": SubResource("AtlasTexture_wlwij") +}, { +"duration": 1.0, +"texture": SubResource("AtlasTexture_iq2ra") +}, { +"duration": 1.0, +"texture": SubResource("AtlasTexture_mqh6q") +}, { +"duration": 1.0, +"texture": SubResource("AtlasTexture_5uuj5") +}, { +"duration": 1.0, +"texture": SubResource("AtlasTexture_lu4ju") +}, { +"duration": 1.0, +"texture": SubResource("AtlasTexture_15g3l") +}, { +"duration": 1.0, +"texture": SubResource("AtlasTexture_24ifv") +}], +"loop": true, +"name": &"eating_player", +"speed": 5.0 +}, { +"frames": [{ +"duration": 1.0, "texture": SubResource("AtlasTexture_3jmpl") }, { "duration": 1.0, @@ -844,6 +964,9 @@ animations = [{ radius = 6.0 height = 24.0 +[sub_resource type="RectangleShape2D" id="RectangleShape2D_hhibv"] +size = Vector2(8, 8) + [node name="cat" type="CharacterBody2D"] collision_layer = 4 collision_mask = 137 @@ -851,7 +974,7 @@ collision_mask = 137 [node name="animated_sprite_cat" type="AnimatedSprite2D" parent="."] unique_name_in_owner = true sprite_frames = SubResource("SpriteFrames_86umi") -animation = &"walk" +animation = &"eating_player" [node name="collsion_shape_cat" type="CollisionShape2D" parent="."] rotation = 1.5708 @@ -872,6 +995,12 @@ script = ExtResource("9_g6ms1") [node name="chase_player" type="Node" parent="behavior_tree/root/check_mouse"] script = ExtResource("10_pxn7j") +[node name="eat_player" type="Node" parent="behavior_tree/root/check_mouse"] +script = ExtResource("11_xt86y") +need = "hunger_for_player" +rate = "eating_rate" +action = "eating" + [node name="check_tiredness" type="Node" parent="behavior_tree/root"] script = ExtResource("7_k3i1t") @@ -940,5 +1069,18 @@ collision_mask = 2 unique_name_in_owner = true polygon = PackedVector2Array(14, -4, -16, -48, 56, -40, 72, -16, 72, 16, 56, 40, -16, 48, 14, 4) -[connection signal="body_entered" from="detection_area" to="behavior_tree" method="_on_DetectionArea_body_entered"] -[connection signal="body_exited" from="detection_area" to="behavior_tree" method="_on_DetectionArea_body_exited"] +[node name="cat_mouth" type="Area2D" parent="."] +unique_name_in_owner = true +collision_mask = 2 +script = ExtResource("18_3qynt") + +[node name="cat_mouth_area_polygon" type="CollisionShape2D" parent="cat_mouth"] +unique_name_in_owner = true +position = Vector2(17, 0) +shape = SubResource("RectangleShape2D_hhibv") +debug_color = Color(0, 0.636796, 0.400363, 0.42) + +[connection signal="body_entered" from="detection_area" to="behavior_tree/root/check_mouse/can_see_player" method="_on_detection_area_body_entered"] +[connection signal="body_exited" from="detection_area" to="behavior_tree/root/check_mouse/can_see_player" method="_on_detection_area_body_exited"] +[connection signal="body_entered" from="cat_mouth" to="behavior_tree/root/check_mouse/chase_player" method="_on_cat_mouth_body_entered"] +[connection signal="body_entered" from="cat_mouth" to="cat_mouth" method="_on_body_entered"] diff --git a/scenes/characters/enemies/mouse_trap.tscn b/scenes/characters/enemies/mouse_trap.tscn index c835e6a..4eb9a47 100644 --- a/scenes/characters/enemies/mouse_trap.tscn +++ b/scenes/characters/enemies/mouse_trap.tscn @@ -95,7 +95,7 @@ animations = [{ }] [sub_resource type="RectangleShape2D" id="RectangleShape2D_hhibv"] -size = Vector2(10, 20) +size = Vector2(11, 21) [node name="mouse_trap" type="Area2D"] collision_mask = 6 @@ -112,4 +112,5 @@ animation = &"pow" autoplay = "nothing" [node name="collision" type="CollisionShape2D" parent="."] +position = Vector2(-0.5, -0.5) shape = SubResource("RectangleShape2D_hhibv")