From fa804f3f6db8fc2d20ab46d7ea4a3fbda092cfe6 Mon Sep 17 00:00:00 2001 From: Serhii Snitsaruk Date: Thu, 1 Feb 2024 19:33:22 +0100 Subject: [PATCH] Demo: Implement basic knockback --- demo/demo/agents/agent_base.tscn | 46 +++++++++++++++++--- demo/demo/agents/player/player.tscn | 5 +++ demo/demo/agents/player/states/move_state.gd | 4 +- demo/demo/agents/scripts/agent_base.gd | 20 ++++++--- demo/demo/agents/scripts/health.gd | 6 +-- demo/demo/agents/scripts/hitbox.gd | 18 +++++--- demo/demo/agents/scripts/hurtbox.gd | 7 +-- demo/demo/ai/tasks/arrive_pos.gd | 4 +- demo/demo/ai/tasks/leap_forward.gd | 4 +- demo/demo/ai/tasks/pursue.gd | 4 +- 10 files changed, 90 insertions(+), 28 deletions(-) diff --git a/demo/demo/agents/agent_base.tscn b/demo/demo/agents/agent_base.tscn index 70681a1..e8aa20e 100644 --- a/demo/demo/agents/agent_base.tscn +++ b/demo/demo/agents/agent_base.tscn @@ -38,10 +38,10 @@ scale_max = 1.2 scale_curve = SubResource("CurveTexture_sb0wp") [sub_resource type="RectangleShape2D" id="RectangleShape2D_2k81i"] -size = Vector2(100, 35) +size = Vector2(130, 35) [sub_resource type="RectangleShape2D" id="RectangleShape2D_26abe"] -size = Vector2(70, 35) +size = Vector2(80, 35) [sub_resource type="CircleShape2D" id="CircleShape2D_0c228"] @@ -359,6 +359,18 @@ tracks/25/keys = { "update": 1, "values": [false] } +tracks/26/type = "value" +tracks/26/imported = false +tracks/26/enabled = true +tracks/26/path = NodePath("Root/Hitbox:knockback_enabled") +tracks/26/interp = 1 +tracks/26/loop_wrap = true +tracks/26/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 1, +"values": [false] +} [sub_resource type="Animation" id="Animation_8wj70"] resource_name = "attack_1" @@ -1142,6 +1154,18 @@ tracks/19/keys = { "update": 1, "values": [true, false, true] } +tracks/20/type = "value" +tracks/20/imported = false +tracks/20/enabled = true +tracks/20/path = NodePath("Root/Hitbox:knockback_enabled") +tracks/20/interp = 1 +tracks/20/loop_wrap = true +tracks/20/keys = { +"times": PackedFloat32Array(0.2, 0.35), +"transitions": PackedFloat32Array(1, 1), +"update": 1, +"values": [true, false] +} [sub_resource type="Animation" id="Animation_wei72"] resource_name = "death" @@ -1704,6 +1728,18 @@ tracks/21/keys = { "update": 1, "values": [false, false] } +tracks/22/type = "value" +tracks/22/imported = false +tracks/22/enabled = true +tracks/22/path = NodePath("Root/Hitbox:knockback_enabled") +tracks/22/interp = 1 +tracks/22/loop_wrap = true +tracks/22/keys = { +"times": PackedFloat32Array(0, 0.25), +"transitions": PackedFloat32Array(1, 1), +"update": 1, +"values": [false, false] +} [sub_resource type="Animation" id="Animation_gnqgt"] resource_name = "idle" @@ -3509,9 +3545,8 @@ fixed_fps = 60 [node name="WeaponNinjaStar" type="Sprite2D" parent="Root"] visible = false -position = Vector2(-71.6739, -72.9077) -rotation = 0.204683 -scale = Vector2(0.999983, 0.999976) +position = Vector2(-55, -76) +scale = Vector2(0.999982, 0.999976) texture = ExtResource("4_1c5xq") [node name="Hitbox" type="Area2D" parent="Root"] @@ -3519,6 +3554,7 @@ position = Vector2(50, 0) collision_layer = 0 collision_mask = 4 script = ExtResource("5_taq6b") +knockback_strength = 1000.0 [node name="CollisionShape2D" type="CollisionShape2D" parent="Root/Hitbox"] shape = SubResource("RectangleShape2D_2k81i") diff --git a/demo/demo/agents/player/player.tscn b/demo/demo/agents/player/player.tscn index 7b24e93..3ae1d03 100644 --- a/demo/demo/agents/player/player.tscn +++ b/demo/demo/agents/player/player.tscn @@ -11,6 +11,11 @@ collision_layer = 0 collision_mask = 1 script = ExtResource("2_24nyi") +[node name="WeaponNinjaStar" parent="Root" index="2"] +position = Vector2(-55, -76) +rotation = 0.0 +scale = Vector2(0.999983, 0.999976) + [node name="Hitbox" parent="Root" index="3"] collision_mask = 8 diff --git a/demo/demo/agents/player/states/move_state.gd b/demo/demo/agents/player/states/move_state.gd index 38e60d7..b3c128b 100644 --- a/demo/demo/agents/player/states/move_state.gd +++ b/demo/demo/agents/player/states/move_state.gd @@ -27,8 +27,10 @@ func _update(_delta: float) -> void: var horizontal_move: float = Input.get_axis(&"move_left", &"move_right") var vertical_move: float = Input.get_axis(&"move_up", &"move_down") - agent.velocity = lerp(agent.velocity, Vector2(horizontal_move, vertical_move * VERTICAL_FACTOR) * speed, 0.2) + var desired_velocity := Vector2(horizontal_move, vertical_move * VERTICAL_FACTOR) * speed + agent.velocity = lerp(agent.velocity, desired_velocity, 0.2) agent.move_and_slide() + agent.update_facing() if horizontal_move == 0.0 and vertical_move == 0.0: get_root().dispatch(EVENT_FINISHED) diff --git a/demo/demo/agents/scripts/agent_base.gd b/demo/demo/agents/scripts/agent_base.gd index 7d86baf..67be03c 100644 --- a/demo/demo/agents/scripts/agent_base.gd +++ b/demo/demo/agents/scripts/agent_base.gd @@ -19,6 +19,7 @@ const NinjaStar := preload("res://demo/agents/ninja_star/ninja_star.tscn") @onready var root: Node2D = $Root @onready var collision_shape_2d: CollisionShape2D = $CollisionShape2D + var _frames_since_facing_update: int = 0 var _is_dead: bool = false @@ -27,11 +28,7 @@ func _ready() -> void: health.death.connect(_die) -func _physics_process(_delta: float) -> void: - _update_facing() - - -func _update_facing() -> void: +func update_facing() -> void: _frames_since_facing_update += 1 if _frames_since_facing_update > 3: face_dir(velocity.x) @@ -57,7 +54,8 @@ func throw_ninja_star() -> void: ninja_star.global_position = global_position + Vector2.RIGHT * 100.0 * get_facing() -func _damaged(_amount: float) -> void: +func _damaged(_amount: float, knockback: Vector2) -> void: + apply_knockback(knockback) animation_player.play(&"hurt") var btplayer := get_node_or_null(^"BTPlayer") as BTPlayer if btplayer: @@ -72,8 +70,18 @@ func _damaged(_amount: float) -> void: hsm.set_active(true) +func apply_knockback(knockback: Vector2, frames: int = 10) -> void: + if knockback.is_zero_approx(): + return + for i in range(frames): + velocity = lerp(velocity, knockback, 0.2) + move_and_slide() + await get_tree().physics_frame + + func _die() -> void: _is_dead = true + root.process_mode = Node.PROCESS_MODE_DISABLED animation_player.play(&"death") collision_shape_2d.set_deferred(&"disabled", true) diff --git a/demo/demo/agents/scripts/health.gd b/demo/demo/agents/scripts/health.gd index a13f605..ca1b9c4 100644 --- a/demo/demo/agents/scripts/health.gd +++ b/demo/demo/agents/scripts/health.gd @@ -14,7 +14,7 @@ extends Node signal death -signal damaged(amount: float) +signal damaged(amount: float, knockback: Vector2) @export var max_health: float = 10.0 @@ -25,7 +25,7 @@ func _ready() -> void: _current = max_health -func take_damage(amount: float) -> void: +func take_damage(amount: float, knockback: Vector2) -> void: if _current <= 0.0: return @@ -35,7 +35,7 @@ func take_damage(amount: float) -> void: if _current <= 0.0: death.emit() else: - damaged.emit(amount) + damaged.emit(amount, knockback) func get_current() -> float: diff --git a/demo/demo/agents/scripts/hitbox.gd b/demo/demo/agents/scripts/hitbox.gd index f0b9942..0a34262 100644 --- a/demo/demo/agents/scripts/hitbox.gd +++ b/demo/demo/agents/scripts/hitbox.gd @@ -12,14 +12,22 @@ class_name Hitbox extends Area2D ## Area that deals damage. - @export var damage: float = 1.0 - +@export var knockback_enabled: bool = false +@export var knockback_strength: float = 500.0 func _ready() -> void: area_entered.connect(_area_entered) -func _area_entered(area: Area2D) -> void: - var hurtbox := area as Hurtbox - hurtbox.take_damage(damage, self) +func _area_entered(hurtbox: Hurtbox) -> void: + if hurtbox.owner == owner: + return + hurtbox.take_damage(damage, get_knockback()) + + +func get_knockback() -> Vector2: + var knockback: Vector2 + if knockback_enabled: + knockback = Vector2.RIGHT.rotated(global_rotation) * knockback_strength + return knockback diff --git a/demo/demo/agents/scripts/hurtbox.gd b/demo/demo/agents/scripts/hurtbox.gd index a10e79b..9c62c6b 100644 --- a/demo/demo/agents/scripts/hurtbox.gd +++ b/demo/demo/agents/scripts/hurtbox.gd @@ -16,8 +16,5 @@ extends Area2D @export var health: Health -func take_damage(amount: float, source: Area2D) -> void: - if source.owner == owner: - # Don't damage yourself. - return - health.take_damage(amount) +func take_damage(amount: float, knockback: Vector2) -> void: + health.take_damage(amount, knockback) diff --git a/demo/demo/ai/tasks/arrive_pos.gd b/demo/demo/ai/tasks/arrive_pos.gd index efdecc6..63b7394 100644 --- a/demo/demo/ai/tasks/arrive_pos.gd +++ b/demo/demo/ai/tasks/arrive_pos.gd @@ -34,6 +34,8 @@ func _tick(_delta: float) -> Status: vertical_factor = clampf(vertical_factor, 0.0, 1.0) var dir: Vector2 = agent.global_position.direction_to(target_pos) dir.y *= vertical_factor - agent.velocity = dir.normalized() * speed + var desired_velocity: Vector2 = dir.normalized() * speed + agent.velocity = lerp(agent.velocity, desired_velocity, 0.2) agent.move_and_slide() + agent.update_facing() return RUNNING diff --git a/demo/demo/ai/tasks/leap_forward.gd b/demo/demo/ai/tasks/leap_forward.gd index 1f86ca3..6ac32fe 100644 --- a/demo/demo/ai/tasks/leap_forward.gd +++ b/demo/demo/ai/tasks/leap_forward.gd @@ -25,8 +25,10 @@ func _generate_name() -> String: # Called each time this task is ticked (aka executed). func _tick(_delta: float) -> Status: var facing: float = agent.get_facing() - agent.velocity = Vector2.RIGHT * facing * force + var desired_velocity: Vector2 = Vector2.RIGHT * facing * force + agent.velocity = lerp(agent.velocity, desired_velocity, 0.2) agent.move_and_slide() + agent.update_facing() if elapsed_time > duration: return SUCCESS return RUNNING diff --git a/demo/demo/ai/tasks/pursue.gd b/demo/demo/ai/tasks/pursue.gd index ede859f..a08b6d2 100644 --- a/demo/demo/ai/tasks/pursue.gd +++ b/demo/demo/ai/tasks/pursue.gd @@ -50,8 +50,10 @@ func _tick(_delta: float) -> Status: var speed: float = blackboard.get_var(speed_var, 200.0) if agent.global_position.distance_to(_waypoint) < TOLERANCE: _select_new_waypoint(desired_pos) - agent.velocity = agent.global_position.direction_to(_waypoint) * speed + var desired_velocity: Vector2 = agent.global_position.direction_to(_waypoint) * speed + agent.velocity = lerp(agent.velocity, desired_velocity, 0.2) agent.move_and_slide() + agent.update_facing() return RUNNING