extends CharacterBody3D

const SPEED = 5.0
const JUMP_SPEED = 3.0
const BOOSTED_SPEED = 10.0
const BLEND_TIME = 0.5
const ROTATION_SPEED = 3.0
const STOP_DELAY = 0.5
const SIZE_INCREASE_PER_CANDY = 0.000005
const MAX_SIZE = 5.0
const BASE_PRIORITY_RANGE = 10.0  # Базовый радиус приоритета
const PRIORITY_RANGE_PER_CANDY = 0.0001  # Увеличение радиуса приоритета за каждую конфету

var candy_count = 0
signal player_removed
signal candy_collected

@onready var candy_label = $Label3D
@onready var animation_player: AnimationPlayer = $AnimationPlayer

var is_stopped: bool = false
var collision_handled: bool = false
var current_direction: Vector3 = Vector3.ZERO
var target_direction: Vector3 = Vector3.ZERO

# List of names to choose from
var names = ["Джек-О'-Фонарь", "Леди Вампирша", "Сэр Скелетон", "Барон Бат",
        "Мисс Мумиё", "Кот Баскервилей", "Зомби Захар", "Ведьма Вика", "Призрак Паша",
        "Гаргулья Гена", "Мистер Мрак", "Леди Летающая Тыква", "Чудище Чарли", "Гоблин Гоша",
        "Вурдалак Вова","Pumpkin Pete", "Ghostly Gary", "Witchy Wendy", "Boo Barry",
        "Creepy Carl", "Mystic Mandy", "Spooky Steve", "Haunted Hannah", "Ghoul Greg",
        "Vampire Vicky", "Zombie Zack", "Frankie Frankenstein", "Dracula Dan", "Mummy Mike",
        "Skeleton Sam", "Batty Betty", "Wraith Roger", "Ghastly Gina", "Phantom Phil", "Wicked Will"]

# Global variable or singleton to keep track of used names
var used_names = []

func _ready():
        # Randomly select a name
        var name = get_unique_name()
        
        # Set the initial label text to the name
        if candy_label:
                candy_label.text = name + "\n" + str(candy_count)
        
        # Найдите всех персонажей в группе "players"
        var players = get_tree().get_nodes_in_group("players")
        
        # Найдите персонажа с самым большим количеством конфет
        var max_candy_count = 0
        for player in players:
                if player.candy_count > max_candy_count:
                        max_candy_count = player.candy_count
        
        # Установите случайное количество конфет для нового персонажа
        candy_count = randi_range(0, max_candy_count)
        
        $Area3D.body_entered.connect(_on_body_entered)
        update_candy_count()
        # Initialize the label's scale to counteract the initial character scale
        if candy_label:
                candy_label.scale = Vector3.ONE / scale
        # Add the name to the used names list
        used_names.append(name)
        
func _on_body_entered(body):
        if body.is_in_group("players") and body != self:
                handle_collision(body)
        elif body.is_in_group("candies"):
                collect_candy(body.candy_value)
                body.queue_free()
                emit_signal("candy_collected", body)

func handle_collision(other_player):
        if collision_handled:
                return

        collision_handled = true

        if candy_count > other_player.candy_count:
                var other_candy_count = other_player.candy_count
                collect_candy(other_candy_count)
                
                other_player.remove_from_game()
                
                print("Collision handled: Added ", other_candy_count, " candies. New candy count: ", candy_count)
        else:
                print("Collision handled: No absorption. The other player has more or equal candies.")

        await get_tree().create_timer(0.1).timeout
        collision_handled = false

func update_candy_count():
        if candy_label:
                # Update only the candy count part of the label
                var name = candy_label.text.split("\n")[0]
                candy_label.text = name + "\n" + str(candy_count)
        
func collect_candy(value):
        # Увеличиваем количество конфет на value
        candy_count += value
        update_candy_count()
        update_size()

func update_size():
        var size_increase = candy_count * SIZE_INCREASE_PER_CANDY
        var new_scale = Vector3.ONE + Vector3.ONE * size_increase

        # Проверяем, не превышает ли новый размер максимальный размер
        if new_scale.length() > MAX_SIZE:
                new_scale = new_scale.normalized() * MAX_SIZE

        # Применяем новый масштаб к персонажу
        scale = new_scale

        # Корректируем масштаб метки, чтобы сохранить ее оригинальный размер в мировом пространстве
        if candy_label:
                var label_scale = Vector3.ONE / new_scale
                candy_label.scale = label_scale

func _physics_process(delta: float) -> void:
        if not is_on_floor():
                velocity += get_gravity() * delta

        var candies = get_tree().get_nodes_in_group("candies")
        var players = get_tree().get_nodes_in_group("players")
        var closest_target = null
        var closest_distance = INF
        var target_is_candy = true

        # Вычисляем радиус приоритета на основе количества конфет
        var dynamic_priority_range = BASE_PRIORITY_RANGE + (candy_count * PRIORITY_RANGE_PER_CANDY)

        # Находим ближайшую конфету
        for candy in candies:
                var distance = global_transform.origin.distance_to(candy.global_transform.origin)
                if distance < closest_distance:
                        closest_distance = distance
                        closest_target = candy
                        target_is_candy = true

        # Находим ближайшего игрока для преследования, с учетом приоритета
        for player in players:
                if player != self:
                        var distance = global_transform.origin.distance_to(player.global_transform.origin)
                        
                        # Проверяем, что у игрока меньше конфет и он ближе, чем конфета
                        if distance < closest_distance and player.candy_count < candy_count:
                                closest_distance = distance
                                closest_target = player
                                target_is_candy = false
                        
                        # Проверяем, что игрок находится в пределах радиуса приоритета и у вас больше конфет
                        elif distance < dynamic_priority_range and candy_count > player.candy_count:
                                closest_distance = distance
                                closest_target = player
                                target_is_candy = false

        if closest_target:
                target_direction = (closest_target.global_transform.origin - global_transform.origin).normalized()
                var speed = SPEED if not target_is_candy else SPEED
                
                # Плавно изменяем направление движения
                current_direction = current_direction.lerp(target_direction, ROTATION_SPEED * delta)
                current_direction = current_direction.normalized()

                velocity.x = current_direction.x * speed
                velocity.z = current_direction.z * speed
                
                if current_direction != Vector3.ZERO:
                        look_at(global_transform.origin + Vector3(current_direction.x, 0, current_direction.z), Vector3.UP)
                
                if animation_player.current_animation != "move":
                        animation_player.play("move", BLEND_TIME)
        else:
                # Постепенно уменьшаем скорость, когда нет цели
                velocity.x = move_toward(velocity.x, 0, SPEED * delta)
                velocity.z = move_toward(velocity.z, 0, SPEED * delta)
                if abs(velocity.x) < 0.1 and abs(velocity.z) < 0.1:
                        velocity.x = 0
                        velocity.z = 0
                        if animation_player.current_animation != "stop":
                                animation_player.play("stop", BLEND_TIME)

        move_and_slide()

func remove_from_game():
        remove_from_group("players")
        if animation_player:
                animation_player.stop()
        $Area3D.body_entered.disconnect(_on_body_entered)
        emit_signal("player_removed", self)
        queue_free()

func get_unique_name():
        var name = names[randi() % names.size()]
        while used_names.has(name):
                # If the name is already in use, try another one
                name = names[randi() % names.size()]
        return name
        
func _exit_tree():
        # When the character is removed from the scene, remove its name from the used names list
        if used_names.has(candy_label.text.split("\n")[0]):
                used_names.erase(candy_label.text.split("\n")[0])
проанализируй код ( не описывая мне его) и оптимизируй сохраняя функционал но упростив код убрав мусор