From 5743ecf3132602dd589f212d4510b19da500b4f0 Mon Sep 17 00:00:00 2001 From: ToasterPanic Date: Thu, 14 May 2026 10:41:51 -0400 Subject: [PATCH] Enemy dreamer AI mostly functional, fix player attack knockback oversight, --- scenes/game.tscn | 3 +- scenes/living/dreamer_body.tscn | 36 ++++++++++++++-- scripts/enemies/dreamer.gd | 76 ++++++++++++++++++++++++--------- scripts/player.gd | 7 ++- 4 files changed, 97 insertions(+), 25 deletions(-) diff --git a/scenes/game.tscn b/scenes/game.tscn index 6d623e8..3305f62 100644 --- a/scenes/game.tscn +++ b/scenes/game.tscn @@ -194,10 +194,9 @@ script = ExtResource("12_trtic") [node name="HitCollision" type="Area3D" parent="Dreamer" unique_id=1754593615] transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.1500001, 0) collision_layer = 0 -collision_mask = 2 [node name="Shape" type="CollisionShape3D" parent="Dreamer/HitCollision" unique_id=1642136717] -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.5, 0, 0) +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, -0.5) shape = SubResource("BoxShape3D_trtic") [node name="DreamerBody" parent="Dreamer" unique_id=595793987 instance=ExtResource("4_p57ef")] diff --git a/scenes/living/dreamer_body.tscn b/scenes/living/dreamer_body.tscn index c8042e0..f6748ad 100644 --- a/scenes/living/dreamer_body.tscn +++ b/scenes/living/dreamer_body.tscn @@ -189,6 +189,21 @@ tracks/14/keys = { "values": [Vector3(0, 0, 0)] } +[sub_resource type="Animation" id="Animation_lg4u0"] +resource_name = "charge_weapon" +tracks/0/type = "value" +tracks/0/imported = false +tracks/0/enabled = true +tracks/0/path = NodePath("Body/ArmPivot:rotation") +tracks/0/interp = 1 +tracks/0/loop_wrap = true +tracks/0/keys = { +"times": PackedFloat32Array(0, 1), +"transitions": PackedFloat32Array(1, 1), +"update": 0, +"values": [Vector3(0, 0, 0), Vector3(0, 0, -1.134464)] +} + [sub_resource type="Animation" id="Animation_u5sy4"] resource_name = "fall" length = 0.2 @@ -730,6 +745,7 @@ tracks/0/keys = { [sub_resource type="AnimationLibrary" id="AnimationLibrary_vtaks"] _data = { &"RESET": SubResource("Animation_gee14"), +&"charge_weapon": SubResource("Animation_lg4u0"), &"fall": SubResource("Animation_u5sy4"), &"hold_weapon": SubResource("Animation_yptk5"), &"jump": SubResource("Animation_p57ef"), @@ -757,9 +773,16 @@ animation = &"hold_weapon" [sub_resource type="AnimationNodeAnimation" id="AnimationNodeAnimation_ny5xw"] animation = &"swing_weapon" +[sub_resource type="AnimationNodeAnimation" id="AnimationNodeAnimation_lg4u0"] +animation = &"charge_weapon" + [sub_resource type="AnimationNodeAnimation" id="AnimationNodeAnimation_p57ef"] animation = &"jump" +[sub_resource type="AnimationNodeOneShot" id="AnimationNodeOneShot_1speq"] +filter_enabled = true +filters = ["Body/ArmPivot:rotation"] + [sub_resource type="AnimationNodeBlend2" id="AnimationNodeBlend2_gee14"] [sub_resource type="AnimationNodeAnimation" id="AnimationNodeAnimation_u5sy4"] @@ -791,8 +814,8 @@ filters = ["Body/ArmPivot:rotation"] [sub_resource type="AnimationNodeTimeScale" id="AnimationNodeTimeScale_p57ef"] [sub_resource type="AnimationNodeBlendTree" id="AnimationNodeBlendTree_kvpfn"] -graph_offset = Vector2(242.94073, -68.15653) -nodes/output/position = Vector2(2140, 100) +graph_offset = Vector2(601.4115, -104.36627) +nodes/output/position = Vector2(2500, 60) nodes/jump/node = SubResource("AnimationNodeOneShot_u5sy4") nodes/jump/position = Vector2(860, 100) nodes/reset/node = SubResource("AnimationNodeAnimation_0tnpc") @@ -829,7 +852,11 @@ nodes/swing_weapon/node = SubResource("AnimationNodeOneShot_06ej8") nodes/swing_weapon/position = Vector2(1900, 60) "nodes/Animation 6/node" = SubResource("AnimationNodeAnimation_ny5xw") "nodes/Animation 6/position" = Vector2(1700, 340) -node_connections = [&"output", 0, &"swing_weapon", &"jump", 0, &"leap", &"jump", 1, &"Animation", &"walk", 0, &"reset", &"walk", 1, &"walk_speed", &"walk_speed", 0, &"move", &"fall", 0, &"walk", &"fall", 1, &"fall_anim", &"leap", 0, &"fall", &"leap", 1, &"Animation 2", &"Add2", 0, &"jump", &"Add2", 1, &"layering", &"layering", 0, &"Animation 3", &"layering", 1, &"Animation 4", &"hold_weapon", 0, &"Add2", &"hold_weapon", 1, &"Animation 5", &"swing_weapon", 0, &"hold_weapon", &"swing_weapon", 1, &"Animation 6"] +nodes/charge_weapon/node = SubResource("AnimationNodeOneShot_1speq") +nodes/charge_weapon/position = Vector2(2180, 60) +"nodes/Animation 7/node" = SubResource("AnimationNodeAnimation_lg4u0") +"nodes/Animation 7/position" = Vector2(2000, 340) +node_connections = [&"output", 0, &"charge_weapon", &"jump", 0, &"leap", &"jump", 1, &"Animation", &"walk", 0, &"reset", &"walk", 1, &"walk_speed", &"walk_speed", 0, &"move", &"fall", 0, &"walk", &"fall", 1, &"fall_anim", &"leap", 0, &"fall", &"leap", 1, &"Animation 2", &"Add2", 0, &"jump", &"Add2", 1, &"layering", &"layering", 0, &"Animation 3", &"layering", 1, &"Animation 4", &"hold_weapon", 0, &"Add2", &"hold_weapon", 1, &"Animation 5", &"swing_weapon", 0, &"hold_weapon", &"swing_weapon", 1, &"Animation 6", &"charge_weapon", 0, &"swing_weapon", &"charge_weapon", 1, &"Animation 7"] [node name="DreamerBody" type="Node3D" unique_id=723408850] script = ExtResource("1_54k0m") @@ -913,3 +940,6 @@ parameters/hold_weapon/blend_amount = 0.0 parameters/swing_weapon/active = false parameters/swing_weapon/internal_active = false parameters/swing_weapon/request = 0 +parameters/charge_weapon/active = false +parameters/charge_weapon/internal_active = false +parameters/charge_weapon/request = 0 diff --git a/scripts/enemies/dreamer.gd b/scripts/enemies/dreamer.gd index e97b0fe..ebe65bf 100644 --- a/scripts/enemies/dreamer.gd +++ b/scripts/enemies/dreamer.gd @@ -9,20 +9,25 @@ var face_left = false var combatable = true -var iframes = 0 -var knockback_time = 0 -var health = 100 +var iframes := 0.0 +var knockback_time := 0.0 +var health := 100.0 -var current_weapon = "test_sword" +var current_weapon := "test_sword" enum { STATE_IDLE, STATE_APPROACH_ENEMY, STATE_CHARGE_ATTACK, - STATE_ATTACK + STATE_ATTACK, + STATE_HIT, + STATE_DEAD, } +var state = STATE_APPROACH_ENEMY +var state_timer := 0.0 + @onready var game = get_parent() @onready var player = game.get_node("Player") @@ -41,18 +46,14 @@ func get_weapon_info(weapon: String, value: String): return Global.weapons[weapon][value] else: return null -func on_hit(hitter: Node3D = null) -> void: - iframes = 0.8 - - if hitter: - knockback_time = 0.25 - velocity += hitter.global_position.direction_to(global_position) * 8 - velocity.y = 0 +func on_knockback(hitter: Node3D = null) -> void: + state = STATE_HIT + state_timer = 0.5 func _ready() -> void: - $DreamerBody.look_at(game.get_node("PlayerCamera").global_position) $DreamerBody.rotation.x = 0 - face_rotation = $DreamerBody.rotation.y + face_rotation = player.face_rotation + $DreamerBody/Animator.set("parameters/hold_weapon/blend_amount", 1.0) func _process(delta: float) -> void: if iframes > 0: @@ -82,7 +83,6 @@ func _physics_process(delta: float) -> void: if combatable: #$DreamerBody/Body/ArmPivot.rotation.z = mouse_point_angle - $HitCollision.rotation.y = -mouse_point_angle + face_rotation if abs(rad_to_deg(mouse_point_angle) - (-90)) < 50: $HitCollision/Shape.shape.size.x = 1.5 @@ -110,11 +110,49 @@ func _physics_process(delta: float) -> void: velocity.y = JUMP_VELOCITY $DreamerBody/Animator.set("parameters/jump/request", AnimationNodeOneShot.ONE_SHOT_REQUEST_FIRE) - navigation_agent.set_target_position(player.global_position) - - var next_path_position: Vector3 = navigation_agent.get_next_path_position() + var direction = Vector2.ZERO + + state_timer -= delta + + if state == STATE_APPROACH_ENEMY: + navigation_agent.set_target_position(player.global_position) + + var next_path_position: Vector3 = navigation_agent.get_next_path_position() + direction = global_position.direction_to(next_path_position) - var direction = global_position.direction_to(next_path_position) + if (player.global_position - global_position).length() < 1: + state = STATE_CHARGE_ATTACK + state_timer = 1 + + $DreamerBody/Animator.set("parameters/charge_weapon/request", AnimationNodeOneShot.ONE_SHOT_REQUEST_FIRE) + elif state == STATE_CHARGE_ATTACK: + $HitCollision.look_at(player.global_position) + $HitCollision.rotation.x = 0 + + if state_timer <= 0: + state = STATE_ATTACK + $DreamerBody/Animator.set("parameters/swing_weapon/request", AnimationNodeOneShot.ONE_SHOT_REQUEST_FIRE) + + var slash = load("res://scenes/effects/slash.tscn").instantiate() + game.add_child(slash) + slash.global_position = global_position + slash.global_rotation.y = $HitCollision.global_rotation.y + deg_to_rad(90) + slash.play_effect() + + if player in $HitCollision.get_overlapping_bodies(): + if player.iframes <= 0: + player.health -= 20 + player.on_hit(self) + + state_timer = 0.5 + elif state == STATE_ATTACK: + if state_timer <= 0: + state = STATE_APPROACH_ENEMY + elif state == STATE_HIT: + $DreamerBody/Animator.set("parameters/charge_weapon/request", AnimationNodeOneShot.ONE_SHOT_REQUEST_ABORT) + + if state_timer <= 0: + state = STATE_APPROACH_ENEMY if direction.x > 0: face_left = false diff --git a/scripts/player.gd b/scripts/player.gd index 103419e..bfe4eae 100644 --- a/scripts/player.gd +++ b/scripts/player.gd @@ -174,9 +174,14 @@ func _physics_process(delta: float) -> void: if "health" in body: body.health -= damage + var knockback_pos = global_position + knockback_pos.y = 0 + var knockback_body_pos = body.global_position + knockback_body_pos.y = 0 + body.position.y += 0.2 body.velocity.y = 0.4 - body.velocity += global_position.direction_to(body.global_position) * knockback + body.velocity += knockback_pos.direction_to(knockback_body_pos) * knockback if body.velocity.length() > knockback: body.velocity = body.velocity.normalized() * knockback