Demo: Implement basic knockback

This commit is contained in:
Serhii Snitsaruk 2024-02-01 19:33:22 +01:00
parent 79813d57a8
commit fa804f3f6d
10 changed files with 90 additions and 28 deletions

View File

@ -38,10 +38,10 @@ scale_max = 1.2
scale_curve = SubResource("CurveTexture_sb0wp") scale_curve = SubResource("CurveTexture_sb0wp")
[sub_resource type="RectangleShape2D" id="RectangleShape2D_2k81i"] [sub_resource type="RectangleShape2D" id="RectangleShape2D_2k81i"]
size = Vector2(100, 35) size = Vector2(130, 35)
[sub_resource type="RectangleShape2D" id="RectangleShape2D_26abe"] [sub_resource type="RectangleShape2D" id="RectangleShape2D_26abe"]
size = Vector2(70, 35) size = Vector2(80, 35)
[sub_resource type="CircleShape2D" id="CircleShape2D_0c228"] [sub_resource type="CircleShape2D" id="CircleShape2D_0c228"]
@ -359,6 +359,18 @@ tracks/25/keys = {
"update": 1, "update": 1,
"values": [false] "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"] [sub_resource type="Animation" id="Animation_8wj70"]
resource_name = "attack_1" resource_name = "attack_1"
@ -1142,6 +1154,18 @@ tracks/19/keys = {
"update": 1, "update": 1,
"values": [true, false, true] "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"] [sub_resource type="Animation" id="Animation_wei72"]
resource_name = "death" resource_name = "death"
@ -1704,6 +1728,18 @@ tracks/21/keys = {
"update": 1, "update": 1,
"values": [false, false] "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"] [sub_resource type="Animation" id="Animation_gnqgt"]
resource_name = "idle" resource_name = "idle"
@ -3509,9 +3545,8 @@ fixed_fps = 60
[node name="WeaponNinjaStar" type="Sprite2D" parent="Root"] [node name="WeaponNinjaStar" type="Sprite2D" parent="Root"]
visible = false visible = false
position = Vector2(-71.6739, -72.9077) position = Vector2(-55, -76)
rotation = 0.204683 scale = Vector2(0.999982, 0.999976)
scale = Vector2(0.999983, 0.999976)
texture = ExtResource("4_1c5xq") texture = ExtResource("4_1c5xq")
[node name="Hitbox" type="Area2D" parent="Root"] [node name="Hitbox" type="Area2D" parent="Root"]
@ -3519,6 +3554,7 @@ position = Vector2(50, 0)
collision_layer = 0 collision_layer = 0
collision_mask = 4 collision_mask = 4
script = ExtResource("5_taq6b") script = ExtResource("5_taq6b")
knockback_strength = 1000.0
[node name="CollisionShape2D" type="CollisionShape2D" parent="Root/Hitbox"] [node name="CollisionShape2D" type="CollisionShape2D" parent="Root/Hitbox"]
shape = SubResource("RectangleShape2D_2k81i") shape = SubResource("RectangleShape2D_2k81i")

View File

@ -11,6 +11,11 @@ collision_layer = 0
collision_mask = 1 collision_mask = 1
script = ExtResource("2_24nyi") 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"] [node name="Hitbox" parent="Root" index="3"]
collision_mask = 8 collision_mask = 8

View File

@ -27,8 +27,10 @@ func _update(_delta: float) -> void:
var horizontal_move: float = Input.get_axis(&"move_left", &"move_right") var horizontal_move: float = Input.get_axis(&"move_left", &"move_right")
var vertical_move: float = Input.get_axis(&"move_up", &"move_down") 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.move_and_slide()
agent.update_facing()
if horizontal_move == 0.0 and vertical_move == 0.0: if horizontal_move == 0.0 and vertical_move == 0.0:
get_root().dispatch(EVENT_FINISHED) get_root().dispatch(EVENT_FINISHED)

View File

@ -19,6 +19,7 @@ const NinjaStar := preload("res://demo/agents/ninja_star/ninja_star.tscn")
@onready var root: Node2D = $Root @onready var root: Node2D = $Root
@onready var collision_shape_2d: CollisionShape2D = $CollisionShape2D @onready var collision_shape_2d: CollisionShape2D = $CollisionShape2D
var _frames_since_facing_update: int = 0 var _frames_since_facing_update: int = 0
var _is_dead: bool = false var _is_dead: bool = false
@ -27,11 +28,7 @@ func _ready() -> void:
health.death.connect(_die) health.death.connect(_die)
func _physics_process(_delta: float) -> void: func update_facing() -> void:
_update_facing()
func _update_facing() -> void:
_frames_since_facing_update += 1 _frames_since_facing_update += 1
if _frames_since_facing_update > 3: if _frames_since_facing_update > 3:
face_dir(velocity.x) 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() 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") animation_player.play(&"hurt")
var btplayer := get_node_or_null(^"BTPlayer") as BTPlayer var btplayer := get_node_or_null(^"BTPlayer") as BTPlayer
if btplayer: if btplayer:
@ -72,8 +70,18 @@ func _damaged(_amount: float) -> void:
hsm.set_active(true) 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: func _die() -> void:
_is_dead = true _is_dead = true
root.process_mode = Node.PROCESS_MODE_DISABLED
animation_player.play(&"death") animation_player.play(&"death")
collision_shape_2d.set_deferred(&"disabled", true) collision_shape_2d.set_deferred(&"disabled", true)

View File

@ -14,7 +14,7 @@ extends Node
signal death signal death
signal damaged(amount: float) signal damaged(amount: float, knockback: Vector2)
@export var max_health: float = 10.0 @export var max_health: float = 10.0
@ -25,7 +25,7 @@ func _ready() -> void:
_current = max_health _current = max_health
func take_damage(amount: float) -> void: func take_damage(amount: float, knockback: Vector2) -> void:
if _current <= 0.0: if _current <= 0.0:
return return
@ -35,7 +35,7 @@ func take_damage(amount: float) -> void:
if _current <= 0.0: if _current <= 0.0:
death.emit() death.emit()
else: else:
damaged.emit(amount) damaged.emit(amount, knockback)
func get_current() -> float: func get_current() -> float:

View File

@ -12,14 +12,22 @@ class_name Hitbox
extends Area2D extends Area2D
## Area that deals damage. ## Area that deals damage.
@export var damage: float = 1.0 @export var damage: float = 1.0
@export var knockback_enabled: bool = false
@export var knockback_strength: float = 500.0
func _ready() -> void: func _ready() -> void:
area_entered.connect(_area_entered) area_entered.connect(_area_entered)
func _area_entered(area: Area2D) -> void: func _area_entered(hurtbox: Hurtbox) -> void:
var hurtbox := area as Hurtbox if hurtbox.owner == owner:
hurtbox.take_damage(damage, self) 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

View File

@ -16,8 +16,5 @@ extends Area2D
@export var health: Health @export var health: Health
func take_damage(amount: float, source: Area2D) -> void: func take_damage(amount: float, knockback: Vector2) -> void:
if source.owner == owner: health.take_damage(amount, knockback)
# Don't damage yourself.
return
health.take_damage(amount)

View File

@ -34,6 +34,8 @@ func _tick(_delta: float) -> Status:
vertical_factor = clampf(vertical_factor, 0.0, 1.0) vertical_factor = clampf(vertical_factor, 0.0, 1.0)
var dir: Vector2 = agent.global_position.direction_to(target_pos) var dir: Vector2 = agent.global_position.direction_to(target_pos)
dir.y *= vertical_factor 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.move_and_slide()
agent.update_facing()
return RUNNING return RUNNING

View File

@ -25,8 +25,10 @@ func _generate_name() -> String:
# Called each time this task is ticked (aka executed). # Called each time this task is ticked (aka executed).
func _tick(_delta: float) -> Status: func _tick(_delta: float) -> Status:
var facing: float = agent.get_facing() 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.move_and_slide()
agent.update_facing()
if elapsed_time > duration: if elapsed_time > duration:
return SUCCESS return SUCCESS
return RUNNING return RUNNING

View File

@ -50,8 +50,10 @@ func _tick(_delta: float) -> Status:
var speed: float = blackboard.get_var(speed_var, 200.0) var speed: float = blackboard.get_var(speed_var, 200.0)
if agent.global_position.distance_to(_waypoint) < TOLERANCE: if agent.global_position.distance_to(_waypoint) < TOLERANCE:
_select_new_waypoint(desired_pos) _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.move_and_slide()
agent.update_facing()
return RUNNING return RUNNING