1
1
mirror of https://github.com/Rundll86/Dog-Lynx-And-HCN.git synced 2026-05-27 22:41:56 +08:00

feat(战斗系统): 添加小鸡冲刺攻击技能及相关特效

实现小鸡的冲刺攻击能力,包括:
1. 新增ChickSprint子弹类型及场景
2. 为EntityBase添加拖尾粒子效果
3. 添加攻击蓄力特效和音效
4. 调整小鸡的攻击冷却时间和冲刺倍率
5. 优化TickTool工具类添加until方法
6. 修改世界背景z-index避免遮挡

调整战斗平衡性:
1. 降低默认冲刺倍率
2. 修改测试波次配置
3. 增加新的攻击方式选项
This commit is contained in:
2025-08-29 13:56:31 +08:00
parent 5525bcd7bc
commit 327afcc721
14 changed files with 195 additions and 11 deletions
+5
View File
@@ -7,6 +7,11 @@
[node name="EffectBase" type="Node2D"]
script = ExtResource("1_pt2rk")
[node name="sounds" type="Node2D" parent="."]
unique_name_in_owner = true
[node name="spawn" type="AudioStreamPlayer2D" parent="sounds"]
[node name="particles" type="GPUParticles2D" parent="."]
unique_name_in_owner = true
amount = 30
+50 -1
View File
@@ -1,4 +1,4 @@
[gd_scene load_steps=18 format=3 uid="uid://cvogxi7mktumf"]
[gd_scene load_steps=27 format=3 uid="uid://cvogxi7mktumf"]
[ext_resource type="Script" path="res://scripts/Statemachine/EntityBase.gd" id="1_mvol6"]
[ext_resource type="Texture2D" uid="uid://dwwpkn4q07ja2" path="res://icon.svg" id="2_7lpu0"]
@@ -169,6 +169,49 @@ _data = {
"hurt": SubResource("Animation_wl2we")
}
[sub_resource type="Curve" id="Curve_cs3iy"]
_data = [Vector2(0, 1), 0.0, 0.0, 0, 0, Vector2(1, 0), 0.0, 0.0, 0, 0]
point_count = 2
[sub_resource type="CurveTexture" id="CurveTexture_r5gvu"]
curve = SubResource("Curve_cs3iy")
[sub_resource type="Curve" id="Curve_uf1fy"]
_data = [Vector2(0, 1), 0.0, 0.0, 0, 0, Vector2(1, 0), 0.0, 0.0, 0, 0]
point_count = 2
[sub_resource type="CurveTexture" id="CurveTexture_cofpe"]
curve = SubResource("Curve_uf1fy")
[sub_resource type="Gradient" id="Gradient_nkkgg"]
colors = PackedColorArray(1, 0, 0, 1, 1, 0.84375, 0, 1)
[sub_resource type="GradientTexture1D" id="GradientTexture1D_j74g5"]
gradient = SubResource("Gradient_nkkgg")
[sub_resource type="Gradient" id="Gradient_m6h1v"]
colors = PackedColorArray(1, 1, 1, 1, 0, 0, 0, 1)
[sub_resource type="GradientTexture1D" id="GradientTexture1D_j8vyx"]
gradient = SubResource("Gradient_m6h1v")
[sub_resource type="ParticleProcessMaterial" id="ParticleProcessMaterial_kndb2"]
particle_flag_disable_z = true
emission_shape = 1
emission_sphere_radius = 50.0
angle_min = 1.07288e-05
angle_max = 360.0
angle_curve = SubResource("CurveTexture_cofpe")
direction = Vector3(-1, 0, 0)
spread = 15.0
initial_velocity_max = 100.0
gravity = Vector3(0, 0, 0)
scale_min = 5.0
scale_max = 15.0
color_ramp = SubResource("GradientTexture1D_j8vyx")
color_initial_ramp = SubResource("GradientTexture1D_j74g5")
alpha_curve = SubResource("CurveTexture_r5gvu")
[sub_resource type="CircleShape2D" id="CircleShape2D_34h7q"]
[node name="EntityBase" type="CharacterBody2D"]
@@ -225,6 +268,12 @@ libraries = {
[node name="weapons" type="Node2D" parent="texture"]
unique_name_in_owner = true
[node name="trailParticle" type="GPUParticles2D" parent="texture"]
unique_name_in_owner = true
z_index = -1
amount = 300
process_material = SubResource("ParticleProcessMaterial_kndb2")
[node name="statebar" parent="." instance=ExtResource("2_uje1g")]
unique_name_in_owner = true
position = Vector2(0, -100)
+13
View File
@@ -0,0 +1,13 @@
[gd_scene load_steps=4 format=3 uid="uid://dpww053pxchsb"]
[ext_resource type="PackedScene" uid="uid://crtdkysmnkith" path="res://components/Abstracts/BulletBase.tscn" id="1_hvhrf"]
[ext_resource type="Script" path="res://scripts/Contents/Bullets/ChickSprint.gd" id="2_fecvj"]
[sub_resource type="CircleShape2D" id="CircleShape2D_rirs4"]
radius = 63.1269
[node name="ChickSprint" instance=ExtResource("1_hvhrf")]
script = ExtResource("2_fecvj")
[node name="hitbox" parent="." index="1"]
shape = SubResource("CircleShape2D_rirs4")
-1
View File
@@ -48,7 +48,6 @@ volume_db = -10.0
[node name="texture" parent="." index="1"]
position = Vector2(0, -37)
sprite_frames = SubResource("SpriteFrames_xji3d")
animation = &"walk"
[node name="normal" type="Node2D" parent="texture/weapons" index="0"]
position = Vector2(30, -12)
+40
View File
@@ -0,0 +1,40 @@
[gd_scene load_steps=9 format=3 uid="uid://bkwy3rwkihf4m"]
[ext_resource type="PackedScene" uid="uid://bcvuuy2m0pke0" path="res://components/Abstracts/EffectBase.tscn" id="1_gbycc"]
[ext_resource type="Texture2D" uid="uid://chqmaeivt84b5" path="res://components/UI/attackstar.svg" id="2_2ws80"]
[ext_resource type="AudioStream" uid="uid://cn876dtp1ypqx" path="res://resources/sounds/effect/Collect.wav" id="2_nxkfo"]
[sub_resource type="Curve" id="Curve_2biku"]
_data = [Vector2(0, 0), 0.0, 0.0, 0, 0, Vector2(0.2, 1), 0.0, 0.0, 0, 0, Vector2(0.8, 1), 0.0, 0.0, 0, 0, Vector2(1, 0), 0.0, 0.0, 0, 0]
point_count = 4
[sub_resource type="CurveTexture" id="CurveTexture_77moo"]
curve = SubResource("Curve_2biku")
[sub_resource type="Curve" id="Curve_e8ols"]
_data = [Vector2(0, 0), 0.0, 0.0, 0, 0, Vector2(0.2, 1), 0.0, 0.0, 0, 0, Vector2(0.8, 1), 0.0, 0.0, 0, 0, Vector2(1, 0), 0.0, 0.0, 0, 0]
point_count = 4
[sub_resource type="CurveTexture" id="CurveTexture_3oeed"]
curve = SubResource("Curve_e8ols")
[sub_resource type="ParticleProcessMaterial" id="ParticleProcessMaterial_bt5eu"]
particle_flag_disable_z = true
direction = Vector3(0, -1, 0)
initial_velocity_min = 10.0
initial_velocity_max = 50.0
gravity = Vector3(0, 0, 0)
scale_curve = SubResource("CurveTexture_3oeed")
alpha_curve = SubResource("CurveTexture_77moo")
[node name="AttackStar" instance=ExtResource("1_gbycc")]
spawnSound = "spawn"
[node name="spawn" parent="sounds" index="0"]
stream = ExtResource("2_nxkfo")
volume_db = 10.0
[node name="particles" parent="." index="1"]
amount = 1
process_material = SubResource("ParticleProcessMaterial_bt5eu")
texture = ExtResource("2_2ws80")
+1 -1
View File
@@ -85,7 +85,7 @@ libraries = {
}
[node name="background" type="Sprite2D" parent="."]
z_index = -1
z_index = -100
texture = ExtResource("6_p0nkj")
[node name="rooster" parent="." groups=["players"] instance=ExtResource("3_5ui6q")]
+1
View File
@@ -0,0 +1 @@
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="81.9" height="81.9" viewBox="0,0,81.9,81.9"><g transform="translate(-199.05,-139.05)"><g stroke="none" stroke-width="0" stroke-linecap="round" stroke-miterlimit="10"><g><g fill="#ffba47"><path d="M250.00785,180.01989h-20.03499l10.05558,-40.96989l9.9987,40.73811"/><path d="M250.02714,180.21189l-9.9987,40.73811l-10.05558,-40.96989h20.03499"/><path d="M239.98011,190.00785v-20.03499l40.96989,10.05558l-40.73811,9.9987"/><path d="M239.78811,190.02714l-40.73811,-9.9987l40.96989,-10.05558v20.03499"/></g><g fill="#fff06c"><path d="M247.09152,180.01409h-14.19672l7.12535,-29.03112l7.08504,28.86688"/><path d="M247.10519,180.15015l-7.08504,28.86688l-7.12535,-29.03112h14.19672"/><path d="M239.98591,187.09152v-14.19672l29.03112,7.12535l-28.86688,7.08504"/><path d="M239.84985,187.10519l-28.86688,-7.08504l29.03112,-7.12535v14.19672"/></g><g fill="#ffffff"><path d="M241.36303,180.00271h-2.7287l1.36954,-5.57996l1.36179,5.54839"/><path d="M241.36566,180.02886l-1.36179,5.54839l-1.36954,-5.57996h2.7287"/><path d="M239.99729,181.36303v-2.7287l5.57996,1.36954l-5.54839,1.36179"/><path d="M239.97114,181.36566l-5.54839,-1.36179l5.57996,-1.36954v2.7287"/></g></g></g></g></svg><!--rotationCenter:40.950000000000074:40.94999999999999-->

After

Width:  |  Height:  |  Size: 1.3 KiB

+37
View File
@@ -0,0 +1,37 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://chqmaeivt84b5"
path="res://.godot/imported/attackstar.svg-b1221cbc7b9ccfacea37ada0859e9b08.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://components/UI/attackstar.svg"
dest_files=["res://.godot/imported/attackstar.svg-b1221cbc7b9ccfacea37ada0859e9b08.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1
svg/scale=1.0
editor/scale_with_editor_scale=false
editor/convert_colors_with_editor_theme=false
+11
View File
@@ -0,0 +1,11 @@
extends BulletBase
class_name ChickSprint
func register():
speed = 0
damage = 30
penerate = 1
func ai():
PresetsAI.lockLauncher(self, launcher, true)
if !launcher.sprinting:
tryDestroy()
+12 -2
View File
@@ -8,9 +8,11 @@ const laserCount = 4
func register():
fields[FieldStore.Entity.MAX_HEALTH] = 2000
fields[FieldStore.Entity.MOVEMENT_SPEED] = 0.35
attackCooldownMap[0] = 2000
attackCooldownMap[0] = 500
attackCooldownMap[1] = 6000
attackCooldownMap[2] = 100
attackCooldownMap[3] = 500
sprintMultiplier = 60
func spawn():
texture.play("walk")
@@ -21,7 +23,8 @@ func ai():
elif currentFocusedBoss.position.distance_to(position) < 700:
tryAttack(1)
else:
tryAttack(0)
var method = MathTool.randc_from([0, 3])
tryAttack(method, method == 3)
func attack(type):
if type == 0:
var weaponPos = findWeaponAnchor("normal")
@@ -36,4 +39,11 @@ func attack(type):
firepot.global_rotation = target
firepot.shot()
BulletBase.generate(preload("res://components/Bullets/FireScan.tscn"), self, weaponPos, target)
elif type == 3:
trailing = true
BulletBase.generate(preload("res://components/Bullets/ChickSprint.tscn"), self, position, 0)
await trySprint()
trailing = false
return true
func sprint():
move((currentFocusedBoss.position - position).normalized() * sprintMultiplier, true)
+3 -2
View File
@@ -11,8 +11,9 @@ var per: int = 0
static var current: int = 0
static var data: Array[Wave] = [
# entity, minCount, maxCount, isBoss, from, to, per
create(preload("res://components/Characters/Hen.tscn"), 1, 5, false, 0, INF, 1),
create(preload("res://components/Characters/Chick.tscn"), 0, 0, true, 8, INF, 6),
# create(preload("res://components/Characters/Hen.tscn"), 1, 5, false, 0, INF, 1),
# create(preload("res://components/Characters/Chick.tscn"), 0, 0, true, 8, INF, 6),
create(preload("res://components/Characters/Chick.tscn"), 1, 1, true, 0, INF, 1),
]
static func create(
+5
View File
@@ -2,12 +2,17 @@ extends Node2D
class_name EffectController
@export var oneShot: bool = true
@export var spawnSound: String = ""
@onready var particles: GPUParticles2D = $"%particles"
@onready var sounds = $"%sounds"
func _ready():
particles.emitting = false
particles.one_shot = oneShot
var sound = sounds.get_node_or_null(spawnSound)
if sound and sound.stream:
sound.play()
func shot():
var cloned = particles.duplicate() as GPUParticles2D
cloned.emitting = true
+14 -4
View File
@@ -55,7 +55,7 @@ var inventoryMax = {
@export var defaultCooldownUnit: float = 100
@export var isBoss: bool = false
@export var displayName: String = "未知实体"
@export var sprintMultiplier: float = 4
@export var sprintMultiplier: float = 3
@export var drops: Array[ItemStore.ItemType] = []
@export var dropCounts: Array[Vector2] = []
@export var appleCount: Vector2i = Vector2(0, 2) # 死亡后掉落的苹果数量
@@ -67,15 +67,18 @@ var inventoryMax = {
@onready var sounds: Node2D = $"%sounds"
@onready var hurtAnimator: AnimationPlayer = $"%hurtAnimator"
@onready var damageAnchor: Node2D = $"%damageAnchor"
@onready var trailParticle: GPUParticles2D = $"%trailParticle"
var statebar: EntityStateBar
var health: float = 0
var energy: float = 0
var sprinting: bool = false
var trailing: bool = false
var lastDirection: int = 1
var lastAttack: int = 0
var currentFocusedBoss: EntityBase = null
var charginup: bool = false
func _ready():
register()
@@ -127,10 +130,11 @@ func _physics_process(_delta: float) -> void:
sprinting = false
else:
velocity = Vector2.ZERO
if isPlayer() or is_instance_valid(currentFocusedBoss):
if (isPlayer() or is_instance_valid(currentFocusedBoss)) and not charginup:
ai()
move_and_slide()
storeEnergy(0.01 * fields.get(FieldStore.Entity.ENERGY_REGENERATION))
trailParticle.emitting = trailing
# 通用方法
func applyLevel():
@@ -187,16 +191,22 @@ func startCooldown(type: int):
if state:
lastAttack = WorldManager.getTime()
return state
func tryAttack(type: int):
func tryAttack(type: int, needChargeUp: bool = false):
var state = startCooldown(type)
if state:
if attack(type):
if needChargeUp:
charginup = true
await EffectController.create(preload("res://components/Effects/AttackStar.tscn"), damageAnchor.global_position).shot()
charginup = false
else:
playSound("attack" + str(type))
attack(type)
return state
func trySprint():
playSound("sprint")
sprint()
sprinting = true
await TickTool.until(func(): return !sprinting)
func tryDie(by: BulletBase):
for drop in range(min(len(drops), len(dropCounts))):
var item = drops[drop]
+3
View File
@@ -5,3 +5,6 @@ static func millseconds(ms: int):
static func frame(count: int = 1):
for i in range(count):
await WorldManager.tree.physics_frame
static func until(predicate: Callable):
while not predicate.call():
await frame()