diff --git a/components/Bullets/ParryBall.tscn b/components/Bullets/ParryBall.tscn new file mode 100644 index 0000000..4c16bd7 --- /dev/null +++ b/components/Bullets/ParryBall.tscn @@ -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") diff --git a/scripts/Contents/Bullets/Parrier.gd b/scripts/Contents/Bullets/Parrier.gd index beb96c5..957e151 100644 --- a/scripts/Contents/Bullets/Parrier.gd +++ b/scripts/Contents/Bullets/Parrier.gd @@ -10,3 +10,13 @@ func hitBullet(bullet: BulletBase): eff.modulate = bullet.modulate.blend(bullet.texture.modulate) eff.shot() 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 diff --git a/scripts/Contents/Bullets/ParryBall.gd b/scripts/Contents/Bullets/ParryBall.gd new file mode 100644 index 0000000..28ac3cb --- /dev/null +++ b/scripts/Contents/Bullets/ParryBall.gd @@ -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 diff --git a/scripts/Contents/Bullets/ParryBall.gd.uid b/scripts/Contents/Bullets/ParryBall.gd.uid new file mode 100644 index 0000000..489358c --- /dev/null +++ b/scripts/Contents/Bullets/ParryBall.gd.uid @@ -0,0 +1 @@ +uid://6to3ptrfe6dr diff --git a/scripts/Statemachine/CycleTimer.gd b/scripts/Statemachine/CycleTimer.gd new file mode 100644 index 0000000..8c7c042 --- /dev/null +++ b/scripts/Statemachine/CycleTimer.gd @@ -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) diff --git a/scripts/Statemachine/CycleTimer.gd.uid b/scripts/Statemachine/CycleTimer.gd.uid new file mode 100644 index 0000000..7f4055e --- /dev/null +++ b/scripts/Statemachine/CycleTimer.gd.uid @@ -0,0 +1 @@ +uid://b3k5h2vs6uwi2 diff --git a/scripts/Statemachine/EntityBase.gd b/scripts/Statemachine/EntityBase.gd index 22347cd..37a39b2 100644 --- a/scripts/Statemachine/EntityBase.gd +++ b/scripts/Statemachine/EntityBase.gd @@ -112,6 +112,7 @@ var weaponBag: Array[String] = [] var canRunAi: bool = true var currentStage: int = 0 var spawnTime: float = 0 +var cycleTimers: Dictionary = {} func _ready(): if useStatic: @@ -199,8 +200,19 @@ func _physics_process(_delta: float) -> void: move_and_slide() storeEnergy(randf_range(0.01, 0.05 + fields.get(FieldStore.Entity.ENERGY_REGENERATION) - 1), true) 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): fields[FieldStore.Entity.MAX_HEALTH] = maxHealth health = maxHealth @@ -276,7 +288,7 @@ func bulletHit(bullet: BulletBase, crit: bool): healthChanged.emit(health) DamageLabel.create(damage, crit || perfectMiss, damageAnchor.global_position + MathTool.sampleInCircle(GameRule.damageLabelSpawnOffset)) if isBoss and bullet.launcher.isPlayer(): - bullet.launcher.setBoss(self) + bullet.launcher.setBoss(self ) if health <= 0: if isBoss: 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() charginup = false if isPlayer() and !isSummon(): - if await weapon.tryAttack(self): + if await weapon.tryAttack(self ): weapon.playSound("attack") else: if await attack(type):