mirror of
https://github.com/Rundll86/Dog-Lynx-And-HCN.git
synced 2026-07-02 00:02:13 +08:00
feat(战斗系统): 添加招架球子弹和循环计时器功能
实现新的招架球子弹类型(ParryBallBullet)及其相关行为 新增CycleTimer类用于管理子弹的周期性运动 在EntityBase中添加计时器管理功能,支持创建和应用周期计时器 添加招架球子弹的资源文件和相关配置
This commit is contained in:
@@ -0,0 +1,60 @@
|
|||||||
|
[gd_scene load_steps=11 format=3 uid="uid://cnvaff2nrgj17"]
|
||||||
|
|
||||||
|
[ext_resource type="PackedScene" uid="uid://crtdkysmnkith" path="res://components/Abstracts/BulletBase.tscn" id="1_xeuh5"]
|
||||||
|
[ext_resource type="Texture2D" uid="uid://dk6basvgsbdqn" path="res://resources/bullets/parrier/Effect_ParryCounterPrepare8.png" id="2_3wdex"]
|
||||||
|
[ext_resource type="Script" uid="uid://6to3ptrfe6dr" path="res://scripts/Contents/Bullets/ParryBall.gd" id="2_cc0al"]
|
||||||
|
|
||||||
|
[sub_resource type="SpriteFrames" id="SpriteFrames_cc0al"]
|
||||||
|
animations = [{
|
||||||
|
"frames": [{
|
||||||
|
"duration": 1.0,
|
||||||
|
"texture": ExtResource("2_3wdex")
|
||||||
|
}],
|
||||||
|
"loop": true,
|
||||||
|
"name": &"default",
|
||||||
|
"speed": 5.0
|
||||||
|
}]
|
||||||
|
|
||||||
|
[sub_resource type="Curve" id="Curve_cc0al"]
|
||||||
|
_data = [Vector2(0, 0.5), 0.0, 0.0, 0, 0, Vector2(1, 0), 0.0, 0.0, 0, 0]
|
||||||
|
point_count = 2
|
||||||
|
|
||||||
|
[sub_resource type="CurveTexture" id="CurveTexture_la26q"]
|
||||||
|
curve = SubResource("Curve_cc0al")
|
||||||
|
|
||||||
|
[sub_resource type="Curve" id="Curve_2gp61"]
|
||||||
|
_data = [Vector2(0.5, 0.7), 0.0, 0.0, 0, 0, Vector2(1, 0), 0.0, 0.0, 0, 0]
|
||||||
|
point_count = 2
|
||||||
|
|
||||||
|
[sub_resource type="CurveTexture" id="CurveTexture_yhjlb"]
|
||||||
|
curve = SubResource("Curve_2gp61")
|
||||||
|
|
||||||
|
[sub_resource type="ParticleProcessMaterial" id="ParticleProcessMaterial_h6o5w"]
|
||||||
|
particle_flag_disable_z = true
|
||||||
|
angular_velocity_min = -200.00002
|
||||||
|
angular_velocity_max = 199.99998
|
||||||
|
gravity = Vector3(0, 0, 0)
|
||||||
|
scale_min = 0.5
|
||||||
|
scale_max = 0.5
|
||||||
|
scale_curve = SubResource("CurveTexture_yhjlb")
|
||||||
|
alpha_curve = SubResource("CurveTexture_la26q")
|
||||||
|
|
||||||
|
[sub_resource type="CircleShape2D" id="CircleShape2D_3wdex"]
|
||||||
|
radius = 100.0
|
||||||
|
|
||||||
|
[node name="ParryBall" instance=ExtResource("1_xeuh5")]
|
||||||
|
script = ExtResource("2_cc0al")
|
||||||
|
|
||||||
|
[node name="texture" parent="." index="0"]
|
||||||
|
scale = Vector2(0.5, 0.5)
|
||||||
|
sprite_frames = SubResource("SpriteFrames_cc0al")
|
||||||
|
|
||||||
|
[node name="trail" type="GPUParticles2D" parent="texture" index="1"]
|
||||||
|
z_index = -1
|
||||||
|
amount = 10
|
||||||
|
texture = ExtResource("2_3wdex")
|
||||||
|
lifetime = 0.5
|
||||||
|
process_material = SubResource("ParticleProcessMaterial_h6o5w")
|
||||||
|
|
||||||
|
[node name="hitbox" parent="." index="1"]
|
||||||
|
shape = SubResource("CircleShape2D_3wdex")
|
||||||
@@ -10,3 +10,13 @@ func hitBullet(bullet: BulletBase):
|
|||||||
eff.modulate = bullet.modulate.blend(bullet.texture.modulate)
|
eff.modulate = bullet.modulate.blend(bullet.texture.modulate)
|
||||||
eff.shot()
|
eff.shot()
|
||||||
bullet.tryDestroy()
|
bullet.tryDestroy()
|
||||||
|
var cycler = launcher.getOrCreateCycleTimer("parry", 2000, 100)
|
||||||
|
if len(cycler.bullets) < 5:
|
||||||
|
for b in BulletBase.generate(
|
||||||
|
ComponentManager.getBullet("ParryBall"),
|
||||||
|
launcher,
|
||||||
|
position,
|
||||||
|
0
|
||||||
|
):
|
||||||
|
if b is ParryBallBullet:
|
||||||
|
pass
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
extends BulletBase
|
||||||
|
class_name ParryBallBullet
|
||||||
|
|
||||||
|
var cycler: CycleTimer
|
||||||
|
|
||||||
|
func spawn():
|
||||||
|
cycler = launcher.getOrCreateCycleTimer("parry")
|
||||||
|
cycler.host(self )
|
||||||
|
func ai():
|
||||||
|
PresetBulletAI.selfRotate(self , 5)
|
||||||
|
hitbox.disabled = !launcher.sprinting
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
uid://6to3ptrfe6dr
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
class_name CycleTimer
|
||||||
|
|
||||||
|
@export var period: float = 1
|
||||||
|
|
||||||
|
var startTime: float = 0
|
||||||
|
var running: bool = false
|
||||||
|
var distance: float = 200
|
||||||
|
var bullets: Array[BulletBase] = []
|
||||||
|
|
||||||
|
func start():
|
||||||
|
startTime = Time.get_ticks_msec()
|
||||||
|
running = true
|
||||||
|
func lifetime():
|
||||||
|
return Time.get_ticks_msec() - startTime
|
||||||
|
func periodPercent(count: int):
|
||||||
|
return lifetime() / period * deg_to_rad(360) - deg_to_rad(360.0 * count / len(bullets))
|
||||||
|
func apply():
|
||||||
|
bullets = bullets.filter(is_instance_valid)
|
||||||
|
for index in len(bullets):
|
||||||
|
var bullet = bullets[index]
|
||||||
|
bullet.position = bullet.launcher.position + Vector2.from_angle(periodPercent(index)) * distance
|
||||||
|
func host(bullet: BulletBase):
|
||||||
|
bullets.append(bullet)
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
uid://b3k5h2vs6uwi2
|
||||||
@@ -112,6 +112,7 @@ var weaponBag: Array[String] = []
|
|||||||
var canRunAi: bool = true
|
var canRunAi: bool = true
|
||||||
var currentStage: int = 0
|
var currentStage: int = 0
|
||||||
var spawnTime: float = 0
|
var spawnTime: float = 0
|
||||||
|
var cycleTimers: Dictionary = {}
|
||||||
|
|
||||||
func _ready():
|
func _ready():
|
||||||
if useStatic:
|
if useStatic:
|
||||||
@@ -199,8 +200,19 @@ func _physics_process(_delta: float) -> void:
|
|||||||
move_and_slide()
|
move_and_slide()
|
||||||
storeEnergy(randf_range(0.01, 0.05 + fields.get(FieldStore.Entity.ENERGY_REGENERATION) - 1), true)
|
storeEnergy(randf_range(0.01, 0.05 + fields.get(FieldStore.Entity.ENERGY_REGENERATION) - 1), true)
|
||||||
trailParticle.emitting = trailing
|
trailParticle.emitting = trailing
|
||||||
|
for cycler in cycleTimers.values():
|
||||||
|
if cycler is CycleTimer:
|
||||||
|
cycler.apply()
|
||||||
|
|
||||||
# 通用方法
|
# 通用方法
|
||||||
|
func getOrCreateCycleTimer(timerName: String, period: float = 1000, distance: float = 200, start: bool = true) -> CycleTimer:
|
||||||
|
if !cycleTimers.has(timerName):
|
||||||
|
var newTimer = CycleTimer.new()
|
||||||
|
newTimer.period = period
|
||||||
|
newTimer.distance = distance
|
||||||
|
if start: newTimer.start()
|
||||||
|
cycleTimers[timerName] = newTimer
|
||||||
|
return cycleTimers[timerName]
|
||||||
func initHealth(maxHealth: float):
|
func initHealth(maxHealth: float):
|
||||||
fields[FieldStore.Entity.MAX_HEALTH] = maxHealth
|
fields[FieldStore.Entity.MAX_HEALTH] = maxHealth
|
||||||
health = maxHealth
|
health = maxHealth
|
||||||
@@ -276,7 +288,7 @@ func bulletHit(bullet: BulletBase, crit: bool):
|
|||||||
healthChanged.emit(health)
|
healthChanged.emit(health)
|
||||||
DamageLabel.create(damage, crit || perfectMiss, damageAnchor.global_position + MathTool.sampleInCircle(GameRule.damageLabelSpawnOffset))
|
DamageLabel.create(damage, crit || perfectMiss, damageAnchor.global_position + MathTool.sampleInCircle(GameRule.damageLabelSpawnOffset))
|
||||||
if isBoss and bullet.launcher.isPlayer():
|
if isBoss and bullet.launcher.isPlayer():
|
||||||
bullet.launcher.setBoss(self)
|
bullet.launcher.setBoss(self )
|
||||||
if health <= 0:
|
if health <= 0:
|
||||||
if isBoss:
|
if isBoss:
|
||||||
bullet.launcher.storeEnergy(energy * 0.35)
|
bullet.launcher.storeEnergy(energy * 0.35)
|
||||||
@@ -324,7 +336,7 @@ func tryAttack(type: int, needChargeUp: bool = false):
|
|||||||
await EffectController.create(ComponentManager.getEffect("AttackStar"), damageAnchor.global_position).shot()
|
await EffectController.create(ComponentManager.getEffect("AttackStar"), damageAnchor.global_position).shot()
|
||||||
charginup = false
|
charginup = false
|
||||||
if isPlayer() and !isSummon():
|
if isPlayer() and !isSummon():
|
||||||
if await weapon.tryAttack(self):
|
if await weapon.tryAttack(self ):
|
||||||
weapon.playSound("attack")
|
weapon.playSound("attack")
|
||||||
else:
|
else:
|
||||||
if await attack(type):
|
if await attack(type):
|
||||||
|
|||||||
Reference in New Issue
Block a user