Skip to content

Instantly share code, notes, and snippets.

@gambala
Created February 1, 2026 09:37
Show Gist options
  • Select an option

  • Save gambala/7bcecc96539056123ae9234dac078495 to your computer and use it in GitHub Desktop.

Select an option

Save gambala/7bcecc96539056123ae9234dac078495 to your computer and use it in GitHub Desktop.

Инструкция: Декомпозиция GDScript через Mixin-классы

Философия

Вместо того чтобы раздувать основной класс (Godot Node) до "Божественного объекта", мы разделяем его на ответственности. Основной класс остается "Контроллером/Хранилищем данных", а вся логика выносится в специализированные Mixin-классы.

1. Базовый класс Mixin

Все миксины наследуются от Mixin.gd (на базе RefCounted). Он хранит ссылку на родителя для доступа к его данным и методам.

class_name Mixin
extends RefCounted

var parent: Node

func _init(_parent: Node) -> void:
	parent = _parent
	post_init.call_deferred()

func post_init() -> void:
	pass

2. Правила выноса кода

  1. Определение ответственности: Выдели логически связанный блок (Физика, Спавнер, Отрисовка, AI, Логика входа).
  2. Создание файла: Называй файл по шаблону ParentClass_Responsibility.gd.
  3. Перенос констант: Если константа используется только внутри этой ответственности, она должна переехать в миксин.
  4. Перенос приватных переменных: Если _приватная переменная используется только внутри этой ответственности, она должна переехать в миксин.
  5. Доступ к данным: Миксин обращается к переменным, сигналам и другим миксинам родителя через префикс parent..
  6. Делегирование: В основном классе создается экземпляр миксина, и вызовы из _process, _physics_process или _input перенаправляются в него.

3. Пример структуры (SnakeMover)

Основной класс (SnakeMover.gd)

class_name SnakeMover
extends Node

# Данные остаются здесь
@export var speed: float = 100.0
var _followers: Array[PathFollow2D] = []

# Инициализация миксинов
var physics := SnakeMover_Physics.new(self)
var spawner := SnakeMover_Spawner.new(self)

func _physics_process(delta: float) -> void:
	# Только делегирование
	physics.step(delta)

func spawn() -> void:
	spawner.run()

Миксин (SnakeMover_Physics.gd)

class_name SnakeMover_Physics
extends Mixin

const FRICTION: float = 0.9 # Локальная константа, перенесенная из родителя

func step(delta: float) -> void:
	for f in parent._followers:
		f.progress += parent.speed * delta * FRICTION

4. Чек-лист для рефакторинга

  • Приватные переменные: _vars, которые нужны нескольким миксинам, остаются в родителе.
  • Константы: Перенесены ли специфичные для логики константы в миксин?
  • Делегирование: Есть ли в родителе вызов метода миксина (например, в _ready, _process или по событию)?
  • Сигналы: Все ли вызовы сигналов заменены на parent.signal_name.emit()?
  • Связи миксинов: Если миксин А должен вызвать метод миксина Б, используй parent.mixin_b.method().
  • Стиль: Используются табы для отступов и явная типизация.

Преимущества подхода

  1. Чистота: Основной файл сокращается в несколько раз.
  2. Навигация: Легко найти нужную логику по названию файла миксина.
  3. Изоляция: Изменение физики не может случайно затронуть отрисовку или спавн.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment