mirror of
https://github.com/Rundll86/Dog-Lynx-And-HCN.git
synced 2026-05-27 22:41:56 +08:00
417ca71de3
- Imported HarmonyOS Sans Regular font with appropriate settings for rendering and fallback. - Created QuickUI script to facilitate the creation of small text labels with optional centering. - Added new theme resources for big bold text and small text, defining font sizes for RichTextLabel and Label respectively.
149 lines
4.3 KiB
GDScript
149 lines
4.3 KiB
GDScript
extends CharacterBody2D
|
|
class_name EntityBase # 这是个抽象类
|
|
|
|
var fields = {
|
|
FieldStore.Entity.MAX_HEALTH: 100,
|
|
FieldStore.Entity.DAMAGE_MULTIPILER: 1,
|
|
FieldStore.Entity.MOVEMENT_SPEED: 1,
|
|
FieldStore.Entity.ATTACK_SPEED: 1,
|
|
FieldStore.Entity.CRIT_RATE: 0.05,
|
|
FieldStore.Entity.CRIT_DAMAGE: 1,
|
|
FieldStore.Entity.PENERATE: 0,
|
|
FieldStore.Entity.OFFSET_SHOOT: 3
|
|
}
|
|
|
|
@export var cooldownUnit: float = 100 # 100毫秒每次攻击
|
|
@export var isBoss: bool = false
|
|
@export var displayName: String = "未知实体"
|
|
@export var sprintMultiplier: float = 7
|
|
@export var inventory = {
|
|
ItemStore.ItemType.BASEBALL: 0,
|
|
ItemStore.ItemType.BASKETBALL: 0
|
|
}
|
|
|
|
@onready var animatree: AnimationTree = $"%animatree"
|
|
@onready var texture: AnimatedSprite2D = $"%texture"
|
|
@onready var hurtbox: Area2D = $"%hurtbox"
|
|
@onready var statebar: EntityStateBar = $"%statebar"
|
|
@onready var sounds: Node2D = $"%sounds"
|
|
@onready var hurtAnimator: AnimationPlayer = $"%hurtAnimator"
|
|
|
|
var health: float = 0
|
|
|
|
var lastDirection: int = 1
|
|
var lastAttack: int = 0
|
|
var currentFocusedBoss: EntityBase = null
|
|
var sprinting: bool = false
|
|
|
|
func _ready():
|
|
health = fields.get(FieldStore.Entity.MAX_HEALTH)
|
|
statebar.visible = !isBoss
|
|
if !isPlayer():
|
|
currentFocusedBoss = get_tree().get_nodes_in_group("players")[0]
|
|
func _process(_delta):
|
|
health = clamp(health, 0, fields.get(FieldStore.Entity.MAX_HEALTH))
|
|
animatree.set("parameters/blend_position", lerpf(animatree.get("parameters/blend_position"), lastDirection, 0.1))
|
|
func _physics_process(_delta: float) -> void:
|
|
if sprinting:
|
|
velocity *= 0.9
|
|
if velocity.length() <= 100:
|
|
sprinting = false
|
|
else:
|
|
velocity = Vector2.ZERO
|
|
if isPlayer() or is_instance_valid(currentFocusedBoss):
|
|
ai()
|
|
move_and_slide()
|
|
|
|
# 通用方法
|
|
func displace(direction: Vector2, isSprinting: bool = false):
|
|
return (direction if isSprinting else direction.normalized()) * fields.get(FieldStore.Entity.MOVEMENT_SPEED) * 400 * abs(animatree.get("parameters/blend_position"))
|
|
func move(direction: Vector2, isSprinting: bool = false):
|
|
velocity = displace(direction, isSprinting)
|
|
var currentDirection = sign(direction.x)
|
|
if currentDirection != 0:
|
|
lastDirection = currentDirection
|
|
func takeDamage(bullet: BulletBase, crit: bool):
|
|
hurtAnimator.play("hurt")
|
|
var baseDamage: float = bullet.fields.get(FieldStore.Bullet.DAMAGE) * randf_range(1 - GameRule.damageOffset, 1 + GameRule.damageOffset)
|
|
var damage = baseDamage + baseDamage * int(crit) * fields.get(FieldStore.Entity.CRIT_DAMAGE)
|
|
if sprinting:
|
|
playSound("miss")
|
|
damage = 0
|
|
else:
|
|
playSound("hurt")
|
|
health -= damage
|
|
DamageLabel.create(damage, crit, $"%damageAnchor".global_position + MathTool.randv2_range(GameRule.damageLabelSpawnOffset))
|
|
if isBoss:
|
|
bullet.launcher.setBoss(self)
|
|
if health <= 0:
|
|
if isBoss:
|
|
bullet.launcher.setBoss(null)
|
|
die()
|
|
func isCooldowned():
|
|
return Time.get_ticks_msec() - lastAttack >= cooldownUnit / fields.get(FieldStore.Entity.ATTACK_SPEED)
|
|
func startCooldown():
|
|
var state = isCooldowned()
|
|
if state:
|
|
lastAttack = Time.get_ticks_msec()
|
|
return state
|
|
func tryAttack(type: int):
|
|
var state = startCooldown()
|
|
if state:
|
|
playSound("attack" + str(type))
|
|
attack(type)
|
|
return state
|
|
func trySprint():
|
|
playSound("sprint")
|
|
sprint()
|
|
sprinting = true
|
|
func findWeaponAnchor(weaponName: String):
|
|
var anchor = $"%weapons".get_node(weaponName)
|
|
if anchor is Node2D:
|
|
return anchor.global_position
|
|
else:
|
|
return Vector2.ZERO
|
|
func setBoss(boss: EntityBase):
|
|
currentFocusedBoss = boss
|
|
if isPlayer():
|
|
UIState.bossbar.entity = boss
|
|
func playSound(type: String):
|
|
var body = sounds.get_node_or_null(type)
|
|
if body is AudioStreamPlayer2D:
|
|
var cloned = body.duplicate() as AudioStreamPlayer2D
|
|
add_child(cloned)
|
|
cloned.play()
|
|
await cloned.finished
|
|
cloned.queue_free()
|
|
|
|
# 关于分组
|
|
func isPlayer():
|
|
return is_in_group("players")
|
|
|
|
# 抽象方法
|
|
func ai():
|
|
pass
|
|
func attack(_type: int):
|
|
pass
|
|
func die():
|
|
queue_free()
|
|
func sprint():
|
|
pass
|
|
|
|
static func generate(
|
|
entity: PackedScene,
|
|
spawnPosition: Vector2,
|
|
isMob: bool = true,
|
|
spawnAsBoss: bool = false,
|
|
addToWorld: bool = true
|
|
):
|
|
var instance: EntityBase = entity.instantiate()
|
|
instance.position = spawnPosition
|
|
instance.isBoss = spawnAsBoss
|
|
if isMob:
|
|
instance.add_to_group("mobs")
|
|
if addToWorld:
|
|
WorldManager.rootNode.add_child(instance)
|
|
return instance
|
|
static func mobCount():
|
|
return len(WorldManager.tree.get_nodes_in_group("mobs"))
|