Очки, здоровье и состояние игры
Состояние игры — это её память: сколько очков, сколько здоровья, какой уровень. Его удобно хранить в одном месте.
Суть: общие данные (счёт, жизни) выносят в один глобальный узел-автозагрузку, чтобы к ним был доступ из любой сцены.
Очки и здоровье нужны многим частям игры: их показывает интерфейс, их меняют монетки и враги, по ним игра решает, не пора ли показать экран проигрыша. Если хранить эти данные внутри сцены уровня, то при переходе на следующий уровень они потеряются. Решение — автозагрузка (autoload), часто называемая синглтоном: специальный узел, который существует в единственном экземпляре и доступен из любой сцены по имени, например GameState.
extends Node # автозагрузка GameState
signal score_changed(value: int)
signal game_over
var score: int = 0
var health: int = 100
func add_score(amount: int) -> void:
score += amount
score_changed.emit(score)
func take_damage(amount: int) -> void:
health = max(health - amount, 0)
if health == 0:
game_over.emit()Теперь любая монетка зовёт GameState.add_score(10), любой враг — GameState.take_damage(20), а интерфейс слушает score_changed и обновляет надпись. Состояние в одном месте, все общаются через него и через сигналы.
Полезно увидеть в автозагрузке единый источник правды. Когда счёт хранится в одном месте, не бывает ситуации «интерфейс показывает 100 очков, а логика думает, что их 80». Все смотрят на одну и ту же переменную и узнают о её изменении через один и тот же сигнал. Этот принцип — «одно состояние, много наблюдателей» — лежит в основе не только игр, но и больших приложений вообще. Освоив его на маленькой игре, ты получаешь привычку, которая пригодится в любом серьёзном проекте: данные живут в одном месте, а все остальные части лишь подписываются на их изменения.
Как работает под капотом
Автозагрузка — это узел, который движок создаёт один раз при старте игры и держит на самом верху дерева, выше всех сцен. При смене уровня сцена уровня выгружается, а автозагрузка остаётся жить, сохраняя данные. Доступ по имени GameState работает потому, что движок регистрирует автозагрузку как глобально видимое имя.
class GameState:
def __init__(self):
self.score = 0
self.health = 100
def add_score(self, amount):
self.score += amount
print(f"Очки: {self.score}")
def take_damage(self, amount):
self.health = max(self.health - amount, 0)
print(f"Здоровье: {self.health}")
if self.health == 0:
print("ИГРА ОКОНЧЕНА")
game = GameState() # один на всю игру
game.add_score(10)
game.add_score(25)
game.take_damage(60)
game.take_damage(50) # уводит здоровье в 0Та же логика на Python ▶. Один объект GameState хранит счёт и здоровье; все части игры зовут его методы. Заметь max(..., 0) — он не даёт здоровью уйти в минус. Запусти и проследи путь до «Игра окончена».
Стоит добавить осторожности: автозагрузка — мощный, но коварный инструмент. Поскольку к ней есть доступ отовсюду, велик соблазн складывать туда всё подряд, и со временем она превращается в свалку, от которой зависит вся игра. Поэтому держи там только по-настоящему общее: счёт, здоровье, текущий уровень, глобальные настройки. Всё, что относится к конкретной сцене, пусть живёт в этой сцене. Хорошее правило: если данные нужны лишь одному уровню — им не место в автозагрузке. Так глобальное состояние остаётся маленьким, понятным и не превращается в источник запутанных ошибок.
Частые ошибки
Первая ошибка — копировать состояние в каждую сцену: при переходе данные рассинхронизируются, счёт «прыгает». Держи одно состояние в автозагрузке. Вторая — давать здоровью уходить в минус: всегда ограничивай через max(health, 0). Третья — забыть эмитить сигнал об изменении, и тогда интерфейс не обновляется: меняешь данные — шли сигнал. Четвёртая — пихать в автозагрузку вообще всё подряд: туда кладут только по-настоящему глобальное состояние, а не каждую мелочь уровня.
Best practices
Выноси в автозагрузку только общие данные: счёт, здоровье, текущий уровень, настройки. Меняй состояние через методы (add_score, take_damage), а не правь переменные снаружи напрямую — так логика в одном месте. На каждое значимое изменение эмить сигнал, чтобы интерфейс и звук реагировали. Ограничивай значения (здоровье не ниже нуля, очки не отрицательные) прямо в методах.
Итоги: состояние игры — это её память (счёт, здоровье, уровень), и его держат в одной автозагрузке-синглтоне, доступной из любой сцены. Меняй данные через методы и эмить сигналы об изменениях. Автозагрузка переживает смену сцен. Ограничивай значения (max(health, 0)) и не дублируй состояние по сценам.