From 4fa565e0e95e56d80d1e4f9123704a108692a92b Mon Sep 17 00:00:00 2001 From: luke358 Date: Tue, 19 May 2026 17:39:58 +0800 Subject: [PATCH] =?UTF-8?q?feat:=201.=20=E6=B7=BB=E5=8A=A0=E6=AD=A6?= =?UTF-8?q?=E5=99=A8=E5=87=BB=E9=80=80=E5=8A=9F=E8=83=BD=EF=BC=8Cplayer=20?= =?UTF-8?q?=E4=BD=BF=E7=94=A8weapon=5Fbehavior/melee=5Fbehavior(hitbox=20?= =?UTF-8?q?=E4=BC=9A=E8=B0=83=E7=94=A8=20setup=20=E5=88=9D=E5=A7=8B?= =?UTF-8?q?=E5=8C=96)=20=E7=9A=84=20hitbox=20=E5=87=BB=E4=B8=AD=20enemy=5F?= =?UTF-8?q?slow=EF=BC=8Cenemy=5Fslow=E6=8B=BF=E5=88=B0hitbox=E7=9A=84knock?= =?UTF-8?q?back=5Fpower=EF=BC=8C=E4=BB=A5=E5=8F=8Ahitbox=E6=8C=87=E5=90=91?= =?UTF-8?q?enemy=E7=9A=84=E6=96=B9=E5=90=91=EF=BC=8C=E7=84=B6=E5=90=8E?= =?UTF-8?q?=E6=9C=9D=E7=9D=80=E8=AF=A5=E6=96=B9=E5=90=91=EF=BC=8C=E4=BD=BF?= =?UTF-8?q?=E7=94=A8power=E5=87=BB=E9=80=80=EF=BC=9A=E8=B0=83=E7=94=A8enem?= =?UTF-8?q?y.gd=20=E7=9A=84=20apply=5Fknockback=EF=BC=8C=E7=84=B6=E5=90=8E?= =?UTF-8?q?=5Fprocess=E4=B8=AD=E4=BC=9A=E5=AF=B9position=E4=BF=AE=E6=94=B9?= =?UTF-8?q?=EF=BC=8C=E5=90=8C=E6=97=B6=E5=BC=80=E5=90=AF=E5=AE=9A=E6=97=B6?= =?UTF-8?q?=E5=99=A8=EF=BC=8C=E5=AE=9A=E6=97=B6=E5=99=A8=E7=BB=93=E6=9D=9F?= =?UTF-8?q?=E7=9A=84=E6=97=B6=E5=80=99=EF=BC=8C=E4=BD=BF=E7=94=A8=20reset?= =?UTF-8?q?=5Fknockback=20=E9=87=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../weapons/melee/punch/stats_punch_1.tres | 6 +--- scenes/unit/enemy/enemy.gd | 34 +++++++++++++++++-- scenes/unit/enemy/enemy_chaser_slow.tscn | 6 ++++ scenes/unit/unit.gd | 2 ++ scenes/weapons/melee/melee_behavior.gd | 26 ++++++++++++++ scenes/weapons/melee/melee_behavior.gd.uid | 1 + scenes/weapons/melee/weapon_behavior.gd | 27 +++++++++++++++ scenes/weapons/melee/weapon_behavior.gd.uid | 1 + scenes/weapons/melee/weapon_punch.tscn | 6 ++++ scenes/weapons/weapon.gd | 8 +++++ 10 files changed, 110 insertions(+), 7 deletions(-) create mode 100644 scenes/weapons/melee/melee_behavior.gd create mode 100644 scenes/weapons/melee/melee_behavior.gd.uid create mode 100644 scenes/weapons/melee/weapon_behavior.gd create mode 100644 scenes/weapons/melee/weapon_behavior.gd.uid diff --git a/resources/items/weapons/melee/punch/stats_punch_1.tres b/resources/items/weapons/melee/punch/stats_punch_1.tres index 8623761..5d24d5a 100644 --- a/resources/items/weapons/melee/punch/stats_punch_1.tres +++ b/resources/items/weapons/melee/punch/stats_punch_1.tres @@ -4,9 +4,5 @@ [resource] script = ExtResource("1_b0adc") -damage = 4.0 -accurary = 1.0 -cooldown = 1.5 -max_range = 180.0 -knockback = 1.0 +knockback = 1.5 metadata/_custom_type_script = "uid://d3d6rctbb48mk" diff --git a/scenes/unit/enemy/enemy.gd b/scenes/unit/enemy/enemy.gd index 1af4880..62e2f58 100644 --- a/scenes/unit/enemy/enemy.gd +++ b/scenes/unit/enemy/enemy.gd @@ -4,9 +4,12 @@ class_name Enemy @export var flock_push := 20.0 @onready var vision_area: Area2D = $VisionArea +@onready var knockback_timer: Timer = $KnockbackTimer var can_move := true +var knockback_dir: Vector2 +var knockback_power: float # Called when the node enters the scene tree for the first time. func _ready() -> void: @@ -21,8 +24,7 @@ func _process(delta: float) -> void: if not can_move_forwards_player(): return - position += get_move_direction() * stats.speed * delta - + position += (get_move_direction() + knockback_dir * knockback_power) * stats.speed * delta update_rotate() @@ -53,5 +55,33 @@ func can_move_forwards_player() -> bool: return is_instance_valid(Global.player) and\ 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) + + + + + + + diff --git a/scenes/unit/enemy/enemy_chaser_slow.tscn b/scenes/unit/enemy/enemy_chaser_slow.tscn index e031b19..1f491fc 100644 --- a/scenes/unit/enemy/enemy_chaser_slow.tscn +++ b/scenes/unit/enemy/enemy_chaser_slow.tscn @@ -63,3 +63,9 @@ offset_top = -95.0 offset_bottom = -75.0 back_color = Color(0.015686275, 0.05490196, 0.16862746, 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"] diff --git a/scenes/unit/unit.gd b/scenes/unit/unit.gd index d4791cb..89c5caa 100644 --- a/scenes/unit/unit.gd +++ b/scenes/unit/unit.gd @@ -27,6 +27,8 @@ func _on_hurtbox_component_on_damaged(hitbox: HitboxComponent) -> void: Global.on_create_block_text.emit(self) return + + set_flash_material() health_component.take_damage(hitbox.damage) Global.on_create_damage_text.emit(self, hitbox) diff --git a/scenes/weapons/melee/melee_behavior.gd b/scenes/weapons/melee/melee_behavior.gd new file mode 100644 index 0000000..cfad501 --- /dev/null +++ b/scenes/weapons/melee/melee_behavior.gd @@ -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 + ) diff --git a/scenes/weapons/melee/melee_behavior.gd.uid b/scenes/weapons/melee/melee_behavior.gd.uid new file mode 100644 index 0000000..008df28 --- /dev/null +++ b/scenes/weapons/melee/melee_behavior.gd.uid @@ -0,0 +1 @@ +uid://bbqq80eq8fqwn diff --git a/scenes/weapons/melee/weapon_behavior.gd b/scenes/weapons/melee/weapon_behavior.gd new file mode 100644 index 0000000..ddffe5f --- /dev/null +++ b/scenes/weapons/melee/weapon_behavior.gd @@ -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 diff --git a/scenes/weapons/melee/weapon_behavior.gd.uid b/scenes/weapons/melee/weapon_behavior.gd.uid new file mode 100644 index 0000000..0635c22 --- /dev/null +++ b/scenes/weapons/melee/weapon_behavior.gd.uid @@ -0,0 +1 @@ +uid://ww04x180xsa3 diff --git a/scenes/weapons/melee/weapon_punch.tscn b/scenes/weapons/melee/weapon_punch.tscn index 859d774..7cbc7ca 100644 --- a/scenes/weapons/melee/weapon_punch.tscn +++ b/scenes/weapons/melee/weapon_punch.tscn @@ -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://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"] size = Vector2(52, 42) @@ -22,3 +23,8 @@ monitorable = false z_index = 1 shape = SubResource("RectangleShape2D_gq287") 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("..") diff --git a/scenes/weapons/weapon.gd b/scenes/weapons/weapon.gd index 90d7ccc..ff1e12f 100644 --- a/scenes/weapons/weapon.gd +++ b/scenes/weapons/weapon.gd @@ -5,6 +5,7 @@ class_name Weapon @onready var sprite_2d: Sprite2D = $Sprite2D @onready var collision: CollisionShape2D = %CollisionShape2D @onready var cooldown_timer: Timer = $CooldownTimer +@onready var weapon_behavior: WeaponBehavior = $WeaponBehavior var data: ItemWeapon var is_attacking := false @@ -25,6 +26,9 @@ func _process(delta: float) -> void: rotate_to_target() + if can_use_weapon(): + use_weapon() + func setup_weapon(_data: ItemWeapon) -> void: self.data = _data @@ -32,6 +36,10 @@ func setup_weapon(_data: ItemWeapon) -> void: func use_weapon() -> void: calculate_spread() + weapon_behavior.execute_attack() + cooldown_timer.wait_time = data.stats.cooldown + cooldown_timer.start() + func rotate_to_target() -> void: if is_attacking: