extends CharacterBody3D const ENCHANTED_SPHERE_SCENE := preload("res://scenes/EnchantedSphere.tscn") signal destroyed enum State { IDLE, FLYING } const AIR_FRICTION := 0.88 const MIN_SPEED := 0.3 const WALL_BOUNCE := 0.6 const WALL_SELF_DMG := 0.0 var kickable_type: String = "essence" var tier: int = 3 var state: State = State.IDLE var fly_vel: Vector3 = Vector3.ZERO var health: float = 999.0 var dead: bool = false var damage_modifier: float = 0.0 @onready var mesh_node: MeshInstance3D = $EssenceMesh var essence_mat: StandardMaterial3D func _ready() -> void: add_to_group("kickable") essence_mat = mesh_node.material_override.duplicate() as StandardMaterial3D mesh_node.material_override = essence_mat var tw := create_tween().set_loops() tw.tween_property(self, "position:y", 0.35, 0.6) tw.tween_property(self, "position:y", 0.15, 0.6) func apply_collision_damage(_dmg: float) -> void: pass func receive_kick(direction: Vector3, force: float) -> void: fly_vel = direction * force fly_vel.y = 0.0 state = State.FLYING func _physics_process(delta: float) -> void: if state == State.IDLE: mesh_node.rotation.y += delta * 1.5 return _fly(delta) func _fly(delta: float) -> void: var speed_now := Vector2(fly_vel.x, fly_vel.z).length() velocity = fly_vel velocity.y = 0.0 move_and_slide() var handled := false for i in get_slide_collision_count(): var col := get_slide_collision(i) var col3d := col.get_collider() as Node3D if col3d == null: continue if col3d.has_meta("is_enchanting_table"): _hit_table(col3d) return if col3d.has_meta("is_wall"): var normal := col.get_normal() normal.y = 0.0 if normal.length() > 0.01: fly_vel = fly_vel.bounce(normal.normalized()) * WALL_BOUNCE else: fly_vel = Vector3.ZERO handled = true break elif col3d.is_in_group("enemies") or col3d.is_in_group("kickable"): if col3d == self: continue KickSystem.resolve(self, col3d, fly_vel) fly_vel *= 0.4 handled = true break if not handled: fly_vel = velocity fly_vel.y = 0.0 fly_vel *= pow(AIR_FRICTION, delta * 60.0) if Vector2(fly_vel.x, fly_vel.z).length() < MIN_SPEED: fly_vel = Vector3.ZERO velocity = Vector3.ZERO state = State.IDLE mesh_node.rotation.y += delta * speed_now * 0.4 func _hit_table(table: Node3D) -> void: if dead: return dead = true state = State.IDLE set_physics_process(false) var parent := get_parent() var spawn_pos := table.global_position + Vector3(0, 0.5, 0) queue_free() if parent == null: return var sphere := ENCHANTED_SPHERE_SCENE.instantiate() as Node3D parent.add_child(sphere) sphere.global_position = spawn_pos