2025-08-26 11:39:47 +08:00
|
|
|
extends Area2D
|
|
|
|
|
class_name BulletBase
|
|
|
|
|
|
2025-08-26 13:56:12 +08:00
|
|
|
@export var fields = {
|
|
|
|
|
FieldStore.Bullet.SPEED: 10,
|
|
|
|
|
FieldStore.Bullet.DAMAGE: 10,
|
|
|
|
|
FieldStore.Bullet.PENERATE: 0
|
|
|
|
|
}
|
2025-08-26 12:21:09 +08:00
|
|
|
@export var lifeDistance: float = -1 # -1表示无限距离
|
|
|
|
|
@export var lifeTime: float = -1 # -1表示无限时间
|
2025-08-27 08:58:14 +08:00
|
|
|
@export var indisDamage: bool = false # 是否无差别伤害(不区分敌我)
|
|
|
|
|
@export var canDamageSelf: bool = false # 是否可以伤害发射者
|
2025-08-27 12:46:20 +08:00
|
|
|
@export var needEnergy: float = 4.0 # 发射时需要消耗的能量
|
2025-08-26 11:39:47 +08:00
|
|
|
|
2025-08-27 13:30:50 +08:00
|
|
|
@onready var animator = $"%animator"
|
|
|
|
|
@onready var hitbox = $"%hitbox"
|
|
|
|
|
|
2025-08-26 11:39:47 +08:00
|
|
|
var launcher: EntityBase = null
|
2025-08-26 12:21:09 +08:00
|
|
|
var spawnInWhen: float = 0
|
|
|
|
|
var spawnInWhere: Vector2 = Vector2.ZERO
|
2025-08-26 11:39:47 +08:00
|
|
|
|
|
|
|
|
func _ready():
|
|
|
|
|
area_entered.connect(hit)
|
2025-08-26 12:21:09 +08:00
|
|
|
spawnInWhen = Time.get_ticks_msec()
|
|
|
|
|
spawnInWhere = position
|
2025-08-27 13:30:50 +08:00
|
|
|
animator.play("spawn")
|
|
|
|
|
spawn()
|
2025-08-26 12:21:09 +08:00
|
|
|
func _process(_delta: float) -> void:
|
|
|
|
|
if lifeTime > 0:
|
|
|
|
|
if Time.get_ticks_msec() - spawnInWhen >= lifeTime:
|
|
|
|
|
destroy()
|
|
|
|
|
if lifeDistance > 0:
|
|
|
|
|
if position.distance_to(spawnInWhere) >= lifeDistance:
|
|
|
|
|
destroy()
|
|
|
|
|
func _physics_process(_delta: float) -> void:
|
2025-08-27 08:09:47 +08:00
|
|
|
if is_instance_valid(launcher) and (launcher.isPlayer() or is_instance_valid(launcher.currentFocusedBoss)):
|
|
|
|
|
ai()
|
2025-08-26 11:39:47 +08:00
|
|
|
|
|
|
|
|
func hit(target: Node):
|
|
|
|
|
var entity: EntityBase = EntityTool.fromHurtbox(target)
|
|
|
|
|
if !entity || !launcher: return
|
2025-08-27 08:58:14 +08:00
|
|
|
if !canDamageSelf && entity == launcher: return
|
|
|
|
|
if !indisDamage && !GameRule.allowFriendlyFire:
|
2025-08-26 11:39:47 +08:00
|
|
|
if entity.isPlayer() == launcher.isPlayer(): return
|
2025-08-26 13:56:12 +08:00
|
|
|
entity.takeDamage(self, MathTool.rate(launcher.fields.get(FieldStore.Entity.CRIT_RATE)))
|
2025-08-27 12:46:20 +08:00
|
|
|
if MathTool.rate(fullPenerate()):
|
|
|
|
|
fields[FieldStore.Bullet.PENERATE] -= entity.fields[FieldStore.Entity.PENARATION_RESISTANCE]
|
|
|
|
|
else:
|
2025-08-26 13:56:12 +08:00
|
|
|
destroy()
|
2025-08-26 12:21:09 +08:00
|
|
|
func forward(direction: Vector2):
|
2025-08-26 13:56:12 +08:00
|
|
|
position += direction.normalized() * fields.get(FieldStore.Bullet.SPEED) * GameRule.bulletSpeedMultiplier
|
2025-08-27 12:46:20 +08:00
|
|
|
func fullPenerate():
|
|
|
|
|
return fields.get(FieldStore.Bullet.PENERATE) + launcher.fields.get(FieldStore.Entity.PENERATE)
|
2025-08-26 12:21:09 +08:00
|
|
|
|
|
|
|
|
func ai():
|
|
|
|
|
pass
|
|
|
|
|
func destroy():
|
|
|
|
|
queue_free()
|
2025-08-27 13:30:50 +08:00
|
|
|
func spawn():
|
|
|
|
|
pass
|
2025-08-26 11:39:47 +08:00
|
|
|
|
|
|
|
|
static func generate(
|
|
|
|
|
bullet: PackedScene,
|
|
|
|
|
launchBy: EntityBase,
|
|
|
|
|
spawnPosition: Vector2,
|
|
|
|
|
spawnRotation: float,
|
|
|
|
|
addToWorld: bool = true
|
|
|
|
|
):
|
2025-08-27 11:08:11 +08:00
|
|
|
var extraCount = launchBy.fields.get(FieldStore.Entity.EXTRA_BULLET_COUNT)
|
|
|
|
|
var count = 1 + floor(extraCount) + int(MathTool.rate(extraCount - floor(extraCount)))
|
|
|
|
|
var instances = []
|
|
|
|
|
for i in range(count):
|
|
|
|
|
var instance: BulletBase = bullet.instantiate()
|
2025-08-27 12:46:20 +08:00
|
|
|
if launchBy.energy < instance.needEnergy:
|
|
|
|
|
continue
|
|
|
|
|
launchBy.energy -= instance.needEnergy
|
2025-08-27 11:08:11 +08:00
|
|
|
instance.launcher = launchBy
|
|
|
|
|
instance.position = spawnPosition
|
|
|
|
|
instance.rotation = spawnRotation + deg_to_rad(randf_range(-launchBy.fields.get(FieldStore.Entity.OFFSET_SHOOT), launchBy.fields.get(FieldStore.Entity.OFFSET_SHOOT)))
|
|
|
|
|
if addToWorld:
|
|
|
|
|
WorldManager.rootNode.add_child(instance)
|
|
|
|
|
instances.append(instance)
|
2025-08-27 12:46:20 +08:00
|
|
|
return len(instances)
|