diff --git a/scenes/enemy.tscn b/scenes/enemy.tscn index ca4640a..1f00477 100644 --- a/scenes/enemy.tscn +++ b/scenes/enemy.tscn @@ -9,10 +9,9 @@ [sub_resource type="Animation" id="Animation_ouyrp"] length = 0.001 -[sub_resource type="Animation" id="Animation_6vdwd"] -resource_name = "idle" +[sub_resource type="Animation" id="Animation_jt5bg"] +resource_name = "hit_ball" length = 0.4 -loop_mode = 1 tracks/0/type = "value" tracks/0/imported = false tracks/0/enabled = true @@ -23,7 +22,7 @@ tracks/0/keys = { "times": PackedFloat32Array(0), "transitions": PackedFloat32Array(1), "update": 1, -"values": [ExtResource("3_5xsrd")] +"values": [ExtResource("2_5t5q0")] } tracks/1/type = "value" tracks/1/imported = false @@ -50,9 +49,10 @@ tracks/2/keys = { "values": [0, 1, 2, 3] } -[sub_resource type="Animation" id="Animation_jt5bg"] -resource_name = "throw" +[sub_resource type="Animation" id="Animation_6vdwd"] +resource_name = "idle" length = 0.4 +loop_mode = 1 tracks/0/type = "value" tracks/0/imported = false tracks/0/enabled = true @@ -63,7 +63,7 @@ tracks/0/keys = { "times": PackedFloat32Array(0), "transitions": PackedFloat32Array(1), "update": 1, -"values": [ExtResource("2_5t5q0")] +"values": [ExtResource("3_5xsrd")] } tracks/1/type = "value" tracks/1/imported = false @@ -134,8 +134,8 @@ tracks/2/keys = { [sub_resource type="AnimationLibrary" id="AnimationLibrary_gnukq"] _data = { "RESET": SubResource("Animation_ouyrp"), +"hit_ball": SubResource("Animation_jt5bg"), "idle": SubResource("Animation_6vdwd"), -"throw": SubResource("Animation_jt5bg"), "walk": SubResource("Animation_etqki") } @@ -172,6 +172,5 @@ shape = SubResource("RectangleShape2D_rlijp") [node name="EnemyBehaviorTree" parent="." instance=ExtResource("3_jk76t")] -[connection signal="go_to_ball" from="." to="EnemyBehaviorTree" method="_on_enemy_go_to_ball"] [connection signal="body_entered" from="Area2D" to="." method="_on_area_2d_body_entered"] [connection signal="body_exited" from="Area2D" to="." method="_on_area_2d_body_exited"] diff --git a/scenes/enemy_behavior_tree.tscn b/scenes/enemy_behavior_tree.tscn index 3554575..2b4c036 100644 --- a/scenes/enemy_behavior_tree.tscn +++ b/scenes/enemy_behavior_tree.tscn @@ -1,4 +1,4 @@ -[gd_scene load_steps=15 format=3 uid="uid://b51tdt5kunai"] +[gd_scene load_steps=14 format=3 uid="uid://b51tdt5kunai"] [ext_resource type="Script" path="res://addons/beehave/nodes/beehave_tree.gd" id="1_b2pc4"] [ext_resource type="Script" path="res://addons/beehave/nodes/composites/sequence.gd" id="2_80fm4"] @@ -8,7 +8,6 @@ [ext_resource type="Script" path="res://scripts/enemy/behavior_tree/wait_action.gd" id="6_eyknc"] [ext_resource type="Script" path="res://scripts/enemy/behavior_tree/can_throw_ball_condition.gd" id="7_k5qlq"] [ext_resource type="Script" path="res://scripts/enemy/behavior_tree/throw_ball_action.gd" id="8_wytqf"] -[ext_resource type="Script" path="res://scripts/enemy/behavior_tree/get_random_target_action.gd" id="8_y68xp"] [ext_resource type="Script" path="res://scripts/enemy/behavior_tree/can_go_to_ball_condition.gd" id="10_3puvl"] [ext_resource type="Script" path="res://scripts/enemy/behavior_tree/get_ball_destination_action.gd" id="11_bvy6m"] [ext_resource type="Script" path="res://scripts/enemy/behavior_tree/move_to_destination_action.gd" id="11_tjc85"] @@ -29,7 +28,7 @@ script = ExtResource("4_0jr1a") [node name="TimeLimiterDecorator" type="Node" parent="MainSelector/WaitSequence"] script = ExtResource("5_012bh") -wait_time = 2.0 +wait_time = 1.0 [node name="Wait" type="Node" parent="MainSelector/WaitSequence/TimeLimiterDecorator"] script = ExtResource("6_eyknc") @@ -40,9 +39,6 @@ script = ExtResource("2_80fm4") [node name="CanThrowBall" type="Node" parent="MainSelector/ThrowBallSequence"] script = ExtResource("7_k5qlq") -[node name="GetRandomTarget" type="Node" parent="MainSelector/ThrowBallSequence"] -script = ExtResource("8_y68xp") - [node name="ThrowBall" type="Node" parent="MainSelector/ThrowBallSequence"] script = ExtResource("8_wytqf") @@ -64,8 +60,5 @@ script = ExtResource("2_80fm4") [node name="CanReturnBall" type="Node" parent="MainSelector/SequenceComposite"] script = ExtResource("13_lrd2w") -[node name="GetRandomTarget2" type="Node" parent="MainSelector/SequenceComposite"] -script = ExtResource("8_y68xp") - [node name="ReturnBall" type="Node" parent="MainSelector/SequenceComposite"] script = ExtResource("14_qbh47") diff --git a/scripts/enemy/behavior_tree/can_go_to_ball_condition.gd b/scripts/enemy/behavior_tree/can_go_to_ball_condition.gd index 2a34c61..98bd2cc 100644 --- a/scripts/enemy/behavior_tree/can_go_to_ball_condition.gd +++ b/scripts/enemy/behavior_tree/can_go_to_ball_condition.gd @@ -2,6 +2,10 @@ class_name CanGoToBallCondition extends ConditionLeaf func tick(actor, _blackboard): - if actor.next_target != null && actor.has_thrown_ball && !actor.collide_with_ball: + if ( + actor.next_target != null && + actor.ball_in_game() && + !actor.collide_with_ball + ): return SUCCESS return FAILURE diff --git a/scripts/enemy/behavior_tree/can_return_ball_condition.gd b/scripts/enemy/behavior_tree/can_return_ball_condition.gd index c04632a..f1fde18 100644 --- a/scripts/enemy/behavior_tree/can_return_ball_condition.gd +++ b/scripts/enemy/behavior_tree/can_return_ball_condition.gd @@ -3,10 +3,9 @@ extends ConditionLeaf func tick(actor, _blackboard): if ( - actor.has_thrown_ball - && actor.next_target != null - && actor.collide_with_ball - && !actor.current_ball.aim_to_bottom() + actor.ball_in_game() && + actor.next_target != null && + actor.collide_with_ball ): return SUCCESS return FAILURE diff --git a/scripts/enemy/behavior_tree/can_throw_ball_condition.gd b/scripts/enemy/behavior_tree/can_throw_ball_condition.gd index 617d059..6790f97 100644 --- a/scripts/enemy/behavior_tree/can_throw_ball_condition.gd +++ b/scripts/enemy/behavior_tree/can_throw_ball_condition.gd @@ -2,6 +2,6 @@ class_name CanThrowBallCondition extends ConditionLeaf func tick(actor, _blackboard): - if !actor.has_thrown_ball: + if !actor.ball_in_game(): return SUCCESS return FAILURE diff --git a/scripts/enemy/behavior_tree/can_wait_condition.gd b/scripts/enemy/behavior_tree/can_wait_condition.gd index ac9b8e0..4b27811 100644 --- a/scripts/enemy/behavior_tree/can_wait_condition.gd +++ b/scripts/enemy/behavior_tree/can_wait_condition.gd @@ -2,10 +2,9 @@ class_name CanWaitCodition extends ConditionLeaf func tick(actor, _blackboard): - if actor.next_target != null: - return FAILURE - - var num = randi_range(0, 1) - if num == 1: - return FAILURE - return SUCCESS + if ( + actor.next_target == null + ): + + return SUCCESS + return FAILURE diff --git a/scripts/enemy/behavior_tree/get_ball_destination_action.gd b/scripts/enemy/behavior_tree/get_ball_destination_action.gd index 9937487..6dc0170 100644 --- a/scripts/enemy/behavior_tree/get_ball_destination_action.gd +++ b/scripts/enemy/behavior_tree/get_ball_destination_action.gd @@ -2,12 +2,5 @@ class_name GetBallDestinationAction extends ActionLeaf func tick(actor: Node, blackboard: Blackboard): -# var rand_cell: Vector2i = actor.tile_map.get_random_top_cell() -# actor.tile_map.reset_and_set_destination_cell(rand_cell) -# -# var destination = actor.tile_map.map_to_local(rand_cell) -# destination.y += actor.Y_SPAWN_OFFSET -# blackboard.set_value("destination", actor.next_target) - return SUCCESS diff --git a/scripts/enemy/behavior_tree/get_random_target_action.gd b/scripts/enemy/behavior_tree/get_random_target_action.gd deleted file mode 100644 index 77b4712..0000000 --- a/scripts/enemy/behavior_tree/get_random_target_action.gd +++ /dev/null @@ -1,12 +0,0 @@ -class_name GetRandomTargetAction -extends ActionLeaf - -func tick(actor, blackboard): - var rand_cell: Vector2i = actor.tile_map.get_random_bottom_cell() - actor.tile_map.reset_and_set_target_cell(rand_cell) - - var target = actor.tile_map.map_to_local(rand_cell) - - blackboard.set_value("target", target) - - return SUCCESS diff --git a/scripts/enemy/behavior_tree/move_to_destination_action.gd b/scripts/enemy/behavior_tree/move_to_destination_action.gd index 62d6d6d..8926496 100644 --- a/scripts/enemy/behavior_tree/move_to_destination_action.gd +++ b/scripts/enemy/behavior_tree/move_to_destination_action.gd @@ -3,20 +3,19 @@ extends ActionLeaf func before_run(actor, blackboard): var destination = blackboard.get_value("destination") - actor.sprite.flip_h = actor.position.x > destination.x - actor.animation_player.play("walk") + actor.flip_sprite(destination) + actor.play_walk_animation() func tick(actor: Node, blackboard: Blackboard): var destination = blackboard.get_value("destination") - var delta = get_physics_process_delta_time() - actor.position = actor.position.move_toward(destination, delta * actor.speed) + actor.move_to(destination) if actor.position == destination: return SUCCESS return RUNNING func after_run(actor, blackboard): + actor.play_idle_animation() + # Debug var destination = blackboard.get_value("destination") - destination.y -= actor.Y_SPAWN_OFFSET - var cell = actor.tile_map.local_to_map(destination) - actor.tile_map.set_cell(0, cell, 0, Vector2i(0, 0), 0) # debug purpose + actor.reset_tile(destination) diff --git a/scripts/enemy/behavior_tree/return_ball_action.gd b/scripts/enemy/behavior_tree/return_ball_action.gd index a094416..bddac3d 100644 --- a/scripts/enemy/behavior_tree/return_ball_action.gd +++ b/scripts/enemy/behavior_tree/return_ball_action.gd @@ -2,15 +2,13 @@ class_name ReturnBallAction extends ActionLeaf func before_run(actor, _blackboard): - actor.play_throw_animation() + actor.play_hit_ball_animation() -func tick(actor, blackboard): - if !actor.is_throw_animation_finished: +func tick(actor, _blackboard): + if !actor.hit_ball_animation_finished: return RUNNING - else: - var target = blackboard.get_value("target") - actor.return_ball(target) - return SUCCESS + actor.return_ball() + return SUCCESS func after_run(actor, _blackboard): actor.animation_player.play("idle") diff --git a/scripts/enemy/behavior_tree/throw_ball_action.gd b/scripts/enemy/behavior_tree/throw_ball_action.gd index fb62b87..1b0c05c 100644 --- a/scripts/enemy/behavior_tree/throw_ball_action.gd +++ b/scripts/enemy/behavior_tree/throw_ball_action.gd @@ -2,16 +2,13 @@ class_name ThrowBallAction extends ActionLeaf func before_run(actor, _blackboard): - actor.play_throw_animation() + actor.play_hit_ball_animation() func tick(actor, blackboard): - if !actor.is_throw_animation_finished: + if !actor.hit_ball_animation_finished: return RUNNING - else: - var target = blackboard.get_value("target") - actor.throw_ball(target) - actor.has_thrown_ball = true - return SUCCESS + actor.throw_ball() + return SUCCESS func after_run(actor, _blackboard): - actor.animation_player.play("idle") + actor.play_idle_animation() diff --git a/scripts/enemy/behavior_tree/wait_action.gd b/scripts/enemy/behavior_tree/wait_action.gd index 9d3ea7e..56c82ce 100644 --- a/scripts/enemy/behavior_tree/wait_action.gd +++ b/scripts/enemy/behavior_tree/wait_action.gd @@ -2,7 +2,7 @@ class_name WaitAction extends ActionLeaf func before_run(actor, _blackboard): - actor.animation_player.play("idle") + actor.play_idle_animation() func tick(_actor, _blackboard): return RUNNING diff --git a/scripts/enemy/enemy.gd b/scripts/enemy/enemy.gd index 4336ceb..057597d 100644 --- a/scripts/enemy/enemy.gd +++ b/scripts/enemy/enemy.gd @@ -1,50 +1,72 @@ class_name Enemy extends CharacterBody2D -signal go_to_ball -const Y_SPAWN_OFFSET = -8 -@export var speed = 80 -var has_thrown_ball = false -var ball_scene = preload("res://scenes/ball.tscn") -var current_ball: Ball +const ball_scene = preload("res://scenes/ball.tscn") +const ball_name = "Ball" +const y_spawn_offset = -8 +signal hit_ball +var speed = 80 var next_target var collide_with_ball = false -var is_throw_animation_finished = false +var hit_ball_animation_finished = false @onready var tile_map: TileMap = get_parent() @onready var animation_player = $AnimationPlayer @onready var sprite = $Sprite2D func _ready(): - var spawn_cell: Vector2i = tile_map.get_top_spawn_cell() - position = tile_map.map_to_local(spawn_cell) - position.y += Y_SPAWN_OFFSET - animation_player.animation_finished.connect(_on_animation_finished) + var spawn_cell = tile_map.get_top_spawn_cell() + position = tile_map.map_to_local(spawn_cell) + Vector2(0, y_spawn_offset) + animation_player.animation_finished.connect(_on_hit_ball_animation_finished) -func throw_ball(target: Vector2): +func move_to(destination): + var delta = get_physics_process_delta_time() + position = position.move_toward(destination, delta * speed) + +func throw_ball(): var ball = ball_scene.instantiate() + ball.name = ball_name ball.position = position - ball.target = target + ball.notify_enemy.connect(_on_notify_enemy) tile_map.add_child(ball) - current_ball = ball - current_ball.notify_enemy.connect(_on_notify_enemy) + hit_ball.emit() -func play_throw_animation(): - is_throw_animation_finished = false +func return_ball(): + hit_ball.emit() + next_target = null + +func flip_sprite(destination): + sprite.flip_h = position.x > destination.x + +func play_hit_ball_animation(): + hit_ball_animation_finished = false animation_player.speed_scale = 0.8 - animation_player.play("throw") + animation_player.play("hit_ball") animation_player.speed_scale = 1 - -func return_ball(target: Vector2): - current_ball.target = target - -func _on_animation_finished(_anim_name): - is_throw_animation_finished = true -func _on_notify_enemy(): - next_target = current_ball.target +func play_idle_animation(): + animation_player.play("idle") + +func play_walk_animation(): + animation_player.play("walk") + +func _on_hit_ball_animation_finished(_anim_name): + hit_ball_animation_finished = true + +func _on_notify_enemy(new_target): + # TODO: add to new_target an offset depending from where the enemy come from + next_target = tile_map.map_to_local(new_target) func _on_area_2d_body_entered(_body): collide_with_ball = true func _on_area_2d_body_exited(_body): collide_with_ball = false + +func ball_in_game() -> bool: + return tile_map.has_node(ball_name) + +# Debug functions +func reset_tile(destination): + destination.y -= y_spawn_offset + var cell = tile_map.local_to_map(destination) + tile_map.set_cell(0, cell, 0, Vector2i(0, 0), 0)