feat: 1. 添加武器击退功能,player 使用weapon_behavior/melee_behavior(hitbox 会调用 setup 初始化) 的 hitbox 击中 enemy_slow,enemy_slow拿到hitbox的knockback_power,以及hitbox指向enemy的方向,然后朝着该方向,使用power击退:调用enemy.gd 的 apply_knockback,然后_process中会对position修改,同时开启定时器,定时器结束的时候,使用 reset_knockback 重置
This commit is contained in:
@@ -4,9 +4,5 @@
|
|||||||
|
|
||||||
[resource]
|
[resource]
|
||||||
script = ExtResource("1_b0adc")
|
script = ExtResource("1_b0adc")
|
||||||
damage = 4.0
|
knockback = 1.5
|
||||||
accurary = 1.0
|
|
||||||
cooldown = 1.5
|
|
||||||
max_range = 180.0
|
|
||||||
knockback = 1.0
|
|
||||||
metadata/_custom_type_script = "uid://d3d6rctbb48mk"
|
metadata/_custom_type_script = "uid://d3d6rctbb48mk"
|
||||||
|
|||||||
@@ -4,9 +4,12 @@ class_name Enemy
|
|||||||
@export var flock_push := 20.0
|
@export var flock_push := 20.0
|
||||||
|
|
||||||
@onready var vision_area: Area2D = $VisionArea
|
@onready var vision_area: Area2D = $VisionArea
|
||||||
|
@onready var knockback_timer: Timer = $KnockbackTimer
|
||||||
|
|
||||||
var can_move := true
|
var can_move := true
|
||||||
|
|
||||||
|
var knockback_dir: Vector2
|
||||||
|
var knockback_power: float
|
||||||
|
|
||||||
# Called when the node enters the scene tree for the first time.
|
# Called when the node enters the scene tree for the first time.
|
||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
@@ -21,8 +24,7 @@ func _process(delta: float) -> void:
|
|||||||
if not can_move_forwards_player():
|
if not can_move_forwards_player():
|
||||||
return
|
return
|
||||||
|
|
||||||
position += get_move_direction() * stats.speed * delta
|
position += (get_move_direction() + knockback_dir * knockback_power) * stats.speed * delta
|
||||||
|
|
||||||
update_rotate()
|
update_rotate()
|
||||||
|
|
||||||
|
|
||||||
@@ -53,5 +55,33 @@ func can_move_forwards_player() -> bool:
|
|||||||
return is_instance_valid(Global.player) and\
|
return is_instance_valid(Global.player) and\
|
||||||
global_position.distance_to(Global.player.position) > 60
|
global_position.distance_to(Global.player.position) > 60
|
||||||
|
|
||||||
|
func apply_knockback(knock_dir: Vector2, knock_power: float) -> void:
|
||||||
|
knockback_dir = knock_dir
|
||||||
|
knockback_power = knock_power
|
||||||
|
if knockback_timer.time_left > 0:
|
||||||
|
knockback_timer.stop()
|
||||||
|
reset_knockback()
|
||||||
|
|
||||||
|
knockback_timer.start()
|
||||||
|
|
||||||
|
func reset_knockback() -> void:
|
||||||
|
knockback_dir = Vector2.ZERO
|
||||||
|
knockback_power = 0
|
||||||
|
|
||||||
|
|
||||||
|
func _on_knockback_timer_timeout() -> void:
|
||||||
|
reset_knockback()
|
||||||
|
|
||||||
|
func _on_hurtbox_component_on_damaged(hitbox: HitboxComponent) -> void:
|
||||||
|
super._on_hurtbox_component_on_damaged(hitbox)
|
||||||
|
|
||||||
|
if hitbox.knockback_power > 0:
|
||||||
|
var dir := hitbox.source.global_position.direction_to(global_position)
|
||||||
|
apply_knockback(dir, hitbox.knockback_power)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -63,3 +63,9 @@ offset_top = -95.0
|
|||||||
offset_bottom = -75.0
|
offset_bottom = -75.0
|
||||||
back_color = Color(0.015686275, 0.05490196, 0.16862746, 1)
|
back_color = Color(0.015686275, 0.05490196, 0.16862746, 1)
|
||||||
fill_color = Color(0.37254903, 0.5372549, 0.75686276, 1)
|
fill_color = Color(0.37254903, 0.5372549, 0.75686276, 1)
|
||||||
|
|
||||||
|
[node name="KnockbackTimer" type="Timer" parent="." index="9" unique_id=1031574323]
|
||||||
|
wait_time = 0.4
|
||||||
|
one_shot = true
|
||||||
|
|
||||||
|
[connection signal="timeout" from="KnockbackTimer" to="." method="_on_knockback_timer_timeout"]
|
||||||
|
|||||||
@@ -27,6 +27,8 @@ func _on_hurtbox_component_on_damaged(hitbox: HitboxComponent) -> void:
|
|||||||
Global.on_create_block_text.emit(self)
|
Global.on_create_block_text.emit(self)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
set_flash_material()
|
set_flash_material()
|
||||||
health_component.take_damage(hitbox.damage)
|
health_component.take_damage(hitbox.damage)
|
||||||
Global.on_create_damage_text.emit(self, hitbox)
|
Global.on_create_damage_text.emit(self, hitbox)
|
||||||
|
|||||||
@@ -0,0 +1,26 @@
|
|||||||
|
extends WeaponBehavior
|
||||||
|
class_name MeleeBehavior
|
||||||
|
|
||||||
|
@export var hitbox: HitboxComponent
|
||||||
|
|
||||||
|
func execute_attack() -> void:
|
||||||
|
weapon.is_attacking = true
|
||||||
|
|
||||||
|
var tween := create_tween()
|
||||||
|
|
||||||
|
var recoil_pos := Vector2(weapon.atk_start_pos.x - weapon.data.stats.recoil, weapon.atk_start_pos.y)
|
||||||
|
tween.tween_property(weapon.sprite_2d, "position", recoil_pos, weapon.data.stats.recoil_duration)
|
||||||
|
|
||||||
|
hitbox.enable()
|
||||||
|
hitbox.setup(get_damage(), critical, weapon.data.stats.knockback, weapon.get_parent())
|
||||||
|
|
||||||
|
var attack_pos := Vector2(weapon.atk_start_pos.x + weapon.data.stats.max_range, weapon.atk_start_pos.y)
|
||||||
|
tween.tween_property(weapon.sprite_2d, "position", attack_pos, weapon.data.stats.attack_duration)
|
||||||
|
|
||||||
|
tween.tween_property(weapon.sprite_2d, "position", weapon.atk_start_pos, weapon.data.stats.back_duration)
|
||||||
|
|
||||||
|
tween.finished.connect(func():
|
||||||
|
hitbox.disable()
|
||||||
|
weapon.is_attacking = false
|
||||||
|
critical = false
|
||||||
|
)
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
uid://bbqq80eq8fqwn
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
extends Node2D
|
||||||
|
class_name WeaponBehavior
|
||||||
|
|
||||||
|
@export var weapon: Weapon
|
||||||
|
|
||||||
|
var critical := false
|
||||||
|
|
||||||
|
func execute_attack() -> void:
|
||||||
|
pass
|
||||||
|
|
||||||
|
func get_damage() -> float:
|
||||||
|
var damage := weapon.data.stats.damage + Global.player.stats.damage
|
||||||
|
var crit_chance := weapon.data.stats.crit_chance
|
||||||
|
if Global.get_chance_success(crit_chance):
|
||||||
|
crit_chance = true
|
||||||
|
damage = ceil(damage * weapon.data.stats.crit_damage)
|
||||||
|
|
||||||
|
return damage
|
||||||
|
|
||||||
|
# Called when the node enters the scene tree for the first time.
|
||||||
|
func _ready() -> void:
|
||||||
|
pass # Replace with function body.
|
||||||
|
|
||||||
|
|
||||||
|
# Called every frame. 'delta' is the elapsed time since the previous frame.
|
||||||
|
func _process(delta: float) -> void:
|
||||||
|
pass
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
uid://ww04x180xsa3
|
||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
[ext_resource type="PackedScene" uid="uid://dcc7rsdy4j8v6" path="res://scenes/weapons/weapon_base.tscn" id="1_soyvn"]
|
[ext_resource type="PackedScene" uid="uid://dcc7rsdy4j8v6" path="res://scenes/weapons/weapon_base.tscn" id="1_soyvn"]
|
||||||
[ext_resource type="PackedScene" uid="uid://c0fyx8gj5uexl" path="res://scenes/components/hitbox_component.tscn" id="2_gq287"]
|
[ext_resource type="PackedScene" uid="uid://c0fyx8gj5uexl" path="res://scenes/components/hitbox_component.tscn" id="2_gq287"]
|
||||||
|
[ext_resource type="Script" uid="uid://bbqq80eq8fqwn" path="res://scenes/weapons/melee/melee_behavior.gd" id="3_sv013"]
|
||||||
|
|
||||||
[sub_resource type="RectangleShape2D" id="RectangleShape2D_gq287"]
|
[sub_resource type="RectangleShape2D" id="RectangleShape2D_gq287"]
|
||||||
size = Vector2(52, 42)
|
size = Vector2(52, 42)
|
||||||
@@ -22,3 +23,8 @@ monitorable = false
|
|||||||
z_index = 1
|
z_index = 1
|
||||||
shape = SubResource("RectangleShape2D_gq287")
|
shape = SubResource("RectangleShape2D_gq287")
|
||||||
debug_color = Color(0.9556908, 0.042769283, 0.5218647, 0.41960785)
|
debug_color = Color(0.9556908, 0.042769283, 0.5218647, 0.41960785)
|
||||||
|
|
||||||
|
[node name="WeaponBehavior" parent="." index="3" unique_id=1507497844 node_paths=PackedStringArray("hitbox", "weapon")]
|
||||||
|
script = ExtResource("3_sv013")
|
||||||
|
hitbox = NodePath("../Sprite2D/HitboxComponent")
|
||||||
|
weapon = NodePath("..")
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ class_name Weapon
|
|||||||
@onready var sprite_2d: Sprite2D = $Sprite2D
|
@onready var sprite_2d: Sprite2D = $Sprite2D
|
||||||
@onready var collision: CollisionShape2D = %CollisionShape2D
|
@onready var collision: CollisionShape2D = %CollisionShape2D
|
||||||
@onready var cooldown_timer: Timer = $CooldownTimer
|
@onready var cooldown_timer: Timer = $CooldownTimer
|
||||||
|
@onready var weapon_behavior: WeaponBehavior = $WeaponBehavior
|
||||||
|
|
||||||
var data: ItemWeapon
|
var data: ItemWeapon
|
||||||
var is_attacking := false
|
var is_attacking := false
|
||||||
@@ -25,6 +26,9 @@ func _process(delta: float) -> void:
|
|||||||
|
|
||||||
rotate_to_target()
|
rotate_to_target()
|
||||||
|
|
||||||
|
if can_use_weapon():
|
||||||
|
use_weapon()
|
||||||
|
|
||||||
|
|
||||||
func setup_weapon(_data: ItemWeapon) -> void:
|
func setup_weapon(_data: ItemWeapon) -> void:
|
||||||
self.data = _data
|
self.data = _data
|
||||||
@@ -32,6 +36,10 @@ func setup_weapon(_data: ItemWeapon) -> void:
|
|||||||
|
|
||||||
func use_weapon() -> void:
|
func use_weapon() -> void:
|
||||||
calculate_spread()
|
calculate_spread()
|
||||||
|
weapon_behavior.execute_attack()
|
||||||
|
cooldown_timer.wait_time = data.stats.cooldown
|
||||||
|
cooldown_timer.start()
|
||||||
|
|
||||||
|
|
||||||
func rotate_to_target() -> void:
|
func rotate_to_target() -> void:
|
||||||
if is_attacking:
|
if is_attacking:
|
||||||
|
|||||||
Reference in New Issue
Block a user