Changelog

Π˜ΡΡ‚ΠΎΡ€ΠΈΡ ΠΈΠ·ΠΌΠ΅Π½Π΅Π½ΠΈΠΉ

Π‘Π²ΠΎΠ΄Π½Ρ‹ΠΉ DevLog ΠΏΠΎ Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚ΠΊΠ΅ Π΄Π²ΠΈΠΆΠΊΠ° Wudgine

Changelog / DevLog

НиТС β€” ΠΎΠ±ΡŠΠ΅Π΄ΠΈΠ½Ρ‘Π½Π½Ρ‹ΠΉ ΠΆΡƒΡ€Π½Π°Π» Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ Π΄Π²ΠΈΠΆΠΊΠ° ΠΈ инфраструктуры. Записи отсортированы ΠΏΠΎ Π΄Π°Ρ‚Π΅.

23.07.2025

Π― Π½Π°Ρ‡Π°Π» Π΄Π΅Π»Π°Ρ‚ΡŒ свой Π΄Π²ΠΈΠΆΠΎΠΊ для MMORPG Π½Π° C++ Π½Π° ΠΏΠ°Ρ‚Ρ‚Π΅Ρ€Π½Π΅ ECS.

04.08.2025

Написал нСсколько Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊ. ΠŸΡ€ΠΈΠΌΠ΅Π½ΡΡŽ ΡΡ‚Ρ€ΠΎΠ³ΡƒΡŽ Ρ‡ΠΈΡΡ‚ΡƒΡŽ Π°Ρ€Ρ…ΠΈΡ‚Π΅ΠΊΡ‚ΡƒΡ€Ρƒ (Onion Architecture) с максимальной ΠΊΠΎΠ³Π΅Π·ΠΈΠ΅ΠΉ.

ΠžΡΠ½ΠΎΠ²Π½Ρ‹Π΅ Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠΈ:

  1. CallStack β€” ΠΏΠΎΠ΄Π΄Π΅Ρ€ΠΆΠΊΠ° отобраТСния стСка Π²Ρ‹Π·ΠΎΠ²ΠΎΠ² Π² Π»ΠΎΠ³Π΅.
  2. Debug β€” Сдиная систСма Π»ΠΎΠ³ΠΎΠ². Для Godot ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΡŽΡ‚ΡΡ собствСнныС ΠΌΠ΅Ρ‚ΠΎΠ΄Ρ‹ ΠΈ ΠΎΡ‚ΡΡƒΡ‚ΡΡ‚Π²ΡƒΡŽΡ‚ ΠΈΡΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΡ, поэтому Ρƒ ΠΊΠ°ΠΆΠ΄ΠΎΠΉ Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠΈ Π΅ΡΡ‚ΡŒ вСрсия для Godot с Π°Π΄Π°ΠΏΡ‚ΠΈΡ€ΠΎΠ²Π°Π½Π½Ρ‹ΠΌ Π²Ρ‹Π²ΠΎΠ΄ΠΎΠΌ.
  3. DI β€” ΠΊΠΎΠ½Ρ‚Π΅ΠΉΠ½Π΅Ρ€ внСдрСния зависимостСй для ECS-ΠΌΠΈΡ€Π°.
  4. Core β€” Π±Π°Π·ΠΎΠ²Ρ‹ΠΉ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΎΠ½Π°Π» ECS: ΠΌΠΈΡ€Ρ‹, ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚Ρ‹, сущности.
  5. JsonSerialization β€” сСриализация/дСсСриализация Π΄Π°Π½Π½Ρ‹Ρ… ΠΌΠΈΡ€Π° Π² JSON ΠΈ ΠΎΠ±Ρ€Π°Ρ‚Π½ΠΎ.
  6. Network β€” клиСнт–сСрвСрная Π»ΠΎΠ³ΠΈΠΊΠ° ΠΈ синхронизация Π΄Π°Π½Π½Ρ‹Ρ… сущностСй.
  7. Multiplayer β€” ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅ ΠΊΠ»ΠΈΠ΅Π½Ρ‚ΠΎΠ², созданиС гСроя ΠΏΠΎ Π΄Π°Π½Π½Ρ‹ΠΌ Π‘Π”, Π²Ρ‹Π±ΠΎΡ€ ΠΌΠΈΡ€Π°.
  8. Engine β€” сСрдцСвина Π΄Π²ΠΈΠΆΠΊΠ°, базовая инициализация.
  9. Gameplay β€” игровая Π»ΠΎΠ³ΠΈΠΊΠ°.

БСриализация:

  • Π Π΅Π°Π»ΠΈΠ·ΠΎΠ²Π°Π½Π° сСриализация/дСсСриализация систСм ΠΈ сущностСй ΠΌΠΈΡ€Π°.
  • Из сцСны Godot ΠΏΡ€ΠΈ сохранСнии автоматичСски гСнСрируСтся Π²ΡΠΏΠΎΠΌΠΎΠ³Π°Ρ‚Π΅Π»ΡŒΠ½Π°Ρ сцСна с Π΄Π°Π½Π½Ρ‹ΠΌΠΈ ECS, ΠΊΠΎΡ‚ΠΎΡ€ΡƒΡŽ Π·Π°Ρ‚Π΅ΠΌ ΠΌΠΎΠΆΠ½ΠΎ Π·Π°Π³Ρ€ΡƒΠ·ΠΈΡ‚ΡŒ Π² ECS-ΠΌΠΈΡ€. Π­Ρ‚ΠΎ ΠΌΠΎΠΆΠ½ΠΎ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ ΠΈ для сохранСний Π² ΠΎΠ΄ΠΈΠ½ΠΎΡ‡Π½ΠΎΠΉ ΠΈΠ³Ρ€Π΅.
  • Π Π΅Π°Π»ΠΈΠ·ΠΎΠ²Π°Π½Π° сСриализация ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚ для сСтСвой Ρ€Π΅ΠΏΠ»ΠΈΠΊΠ°Ρ†ΠΈΠΈ.

Π˜Π½Ρ‚Π΅Π³Ρ€Π°Ρ†ΠΈΡ с Godot:

Под ΠΊΠ°ΠΆΠ΄ΡƒΡŽ Π²Π½ΡƒΡ‚Ρ€Π΅Π½Π½ΡŽΡŽ Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΡƒ Π΄Π²ΠΈΠΆΠΊΠ° ΠΏΡ€ΠΈ нСобходимости сущСствуСт ΡΠ²ΡΠ·ΡƒΡŽΡ‰Π°Ρ Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠ° для ΠΈΠ½Ρ‚Π΅Π³Ρ€Π°Ρ†ΠΈΠΈ с Godot.

  • CoreGodotEditor β€” связываСт Ρ€Π΅Π΄Π°ΠΊΡ‚ΠΎΡ€ Godot с Core для отобраТСния Π΄Π°Π½Π½Ρ‹Ρ… сущности Π² инспСкторС Ρƒ Π²Ρ‹Π±Ρ€Π°Π½Π½ΠΎΠ³ΠΎ Node.
  • CoreGodotRuntime β€” связываСт Ρ€Π°Π½Ρ‚Π°ΠΉΠΌ Godot с Core: Π΄Π°Π½Π½Ρ‹Π΅ сущностСй маппятся Π½Π° свойства Node (позиция, анимация ΠΈ Ρ‚. ΠΏ.), ΠΏΠΎΠ²Π΅Π΄Π΅Π½ΠΈΠ΅ настраиваСмо.

Π‘Π΅Ρ€Π²Π΅Ρ€ ΠΈ Π½Π°Π³Ρ€ΡƒΠ·ΠΎΡ‡Π½ΠΎΠ΅ тСстированиС:

Π Π΅Π°Π»ΠΈΠ·ΠΎΠ²Π°Π½Ρ‹ Π±Π΅Π·Π³ΠΎΠ»ΠΎΠ²Ρ‹ΠΉ сСрвСр ΠΈ ΠΊΠ»ΠΈΠ΅Π½Ρ‚ для Π½Π°Π³Ρ€ΡƒΠ·ΠΎΡ‡Π½Ρ‹Ρ… тСстов. Π‘Π΅Ρ€Π²Π΅Ρ€ с Π½ΡƒΠΆΠ½Ρ‹ΠΌΠΈ Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠ°ΠΌΠΈ вСсит ~700 ΠšΠ‘ ΠΈ потрСбляСт ~1.4 ΠœΠ‘ ΠžΠ—Π£.

Бтатус:

Π˜Π½Ρ‚Π΅Π³Ρ€Π°Ρ†ΠΈΡ Π΄Π²ΠΈΠΆΠΊΠ° Π² Godot Π·Π°ΠΊΠΎΠ½Ρ‡Π΅Π½Π°. Π”Π°Π»Π΅Π΅ β€” синхронизация Π΄Π°Π½Π½Ρ‹Ρ… сущностСй ΠΌΠ΅ΠΆΠ΄Ρƒ Π΄Π²ΠΈΠΆΠΊΠ°ΠΌΠΈ.

21.08.2025 β€” Debug: v1.0.0

πŸš€ Π“ΠΎΡ‚ΠΎΠ²Π° собствСнная Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠ° ΠΎΡ‚Π»Π°Π΄ΠΊΠΈ с Π»ΠΎΠ³Π³ΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠ΅ΠΌ ΠΈ автоматичСским Ρ‚Ρ€Π΅ΠΊΠΈΠ½Π³ΠΎΠΌ стСка Π²Ρ‹Π·ΠΎΠ²ΠΎΠ².

ΠšΠ»ΡŽΡ‡Π΅Π²Ρ‹Π΅ особСнности:

  • ΠœΡƒΠ»ΡŒΡ‚ΠΈΠΏΠ»Π°Ρ‚Ρ„ΠΎΡ€ΠΌΠ΅Π½Π½ΠΎΡΡ‚ΡŒ: вСрсия для Godot (UtilityFunctions::print) ΠΈ standalone (stdout).
  • НулСвыС Π½Π°ΠΊΠ»Π°Π΄Π½Ρ‹Π΅ расходы Π² Ρ€Π΅Π»ΠΈΠ·Π΅: ΠΎΡ‚Π»Π°Π΄ΠΎΡ‡Π½Ρ‹Π΅ макросы Π²Ρ‹Ρ€Π΅Π·Π°ΡŽΡ‚ΡΡ ΠΈΠ· Π±ΠΈΠ»Π΄Π°.
  • Π’ΠΈΠΏΡ‹ сообщСний: Log, Warning, Error; настраиваСмыС Π·Π°Π³ΠΎΠ»ΠΎΠ²ΠΊΠΈ ΠΈ Ρ†Π²Π΅Ρ‚Π°.
  • Π“ΠΈΠ±ΠΊΠΎΠ΅ Ρ„ΠΎΡ€ΠΌΠ°Ρ‚ΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠ΅: Π°Ρ€Π³ΡƒΠΌΠ΅Π½Ρ‚Ρ‹ (printf-ΡΡ‚ΠΈΠ»ΡŒ), ΠΏΠΎΡ‚ΠΎΠΊΠΎΠ²Ρ‹ΠΉ Π²Ρ‹Π²ΠΎΠ΄ (std::cout) ΠΈΠ»ΠΈ ΠΈΡ… комбинация.
  • Автоматизация: макросы ΡƒΠΊΠ°Π·Ρ‹Π²Π°ΡŽΡ‚ Ρ„Π°ΠΉΠ» ΠΈ строку, Π²Ρ‹Ρ€Π°Π²Π½ΠΈΠ²Π°Π½ΠΈΠ΅ стСка ΠΏΠΎ строкам, Π²ΠΈΠ·ΡƒΠ°Π»ΡŒΠ½Ρ‹ΠΉ Β«Π³Ρ€Π°Π΄ΠΈΠ΅Π½Ρ‚Β» ΠΈ отступы для читаСмости.

ΠœΠ°ΠΊΡ€ΠΎΡ _w() ΠΈ ΠΏΡ€ΠΈΠΌΠ΅Ρ€ использования:

#include "Debug/Debug.hpp"
using namespace Debug;

namespace Debug_Tests {
    class DebuggingTest {
    public:
        void runAllTests() {
            _w();
            _w(_testBasicLogging());
            _w(_testMessageCustomization());
            _w(_testAssertAndThrow());
            _w(_testCallStackTracing());
            _w(_testCombinedFormatting());
            std::cout << "All tests completed successfully." << std::endl;
        }
    private:
        void _testBasicLogging() {
            _w();
            DEBUG::Log("This is a standard log message.") << "qwe";
            DEBUG::Warning("This is a warning message.") << "";
            DEBUG::Error("This is an error message.");
        }
        void _testMessageCustomization() {
            _w();
            DEBUG::Message(
                LogStream::Message("Custom message with sub title and other color.")
                    .SetTitle("[SUB_TITLE]")
                    .SetColor(Colors::TEXT_COLOR_CYAN_SOFT)
                    .ToString()
            );
            DEBUG::Message(
                LogStream::Message("Message without a title.")
                    .NoTitle()
                    .ToString()
            ).NoTitle();
        }
        void _testAssertAndThrow() {
            _w();
            DEBUG::Assert(true, "This assert should pass.");
        }
        void _testCallStackTracing() { _w(); _innerFunction(); }
        void _innerFunction() {
            _w();
            DEBUG::Log("Call stack tracing test: inside inner function.");
        }
        void _testCombinedFormatting() {
            _w();
            int p_score = 100; std::string p_player = "Player_One"; float p_speed = 15.5f;
            DEBUG::Log("Player: ", p_player, ", Score: ", p_score, ", Speed: ", p_speed);
            DEBUG::Log("Game_State: ") << "Running" << ", Level: " << 5 << ", Time: " << 120.5f;
            DEBUG::Log("Combined Log. Level: ", 5) << " and " << "Score: " << 200;
        }
    };
}

26.08.2025 β€” DI: v1.0.0

πŸš€ Π’Π½Π΅Π΄Ρ€Π΅Π½ΠΈΠ΅ зависимостСй (Dependency Injection) для чистого ΠΈ Π³ΠΈΠ±ΠΊΠΎΠ³ΠΎ ΠΊΠΎΠ΄Π°.

Как Ρ€Π°Π±ΠΎΡ‚Π°Π΅Ρ‚ ΠΊΠΎΠ½Ρ‚Π΅ΠΉΠ½Π΅Ρ€:

  1. РСгистрация (registerSingleton) β€” Ρ…Ρ€Π°Π½ΠΈΡ‚ экзСмпляры ΠΊΠ°ΠΊ синглтоны (ΠΏΡ€ΠΈΠ½ΠΈΠΌΠ°Π΅Ρ‚ shared_ptr ΠΈΠ»ΠΈ ссылку Π½Π° внСшний ΠΎΠ±ΡŠΠ΅ΠΊΡ‚, Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€ std::stringstream).
  2. ΠŸΠΎΠ»ΡƒΡ‡Π΅Π½ΠΈΠ΅ (get/getRaw) β€” Π²ΠΎΠ·Π²Ρ€Π°Ρ‰Π°Π΅Ρ‚ shared_ptr ΠΈΠ»ΠΈ ссылку/ΡƒΠΊΠ°Π·Π°Ρ‚Π΅Π»ΡŒ Π½Π° зарСгистрированный ΠΎΠ±ΡŠΠ΅ΠΊΡ‚.
  3. Π‘ΠΎΠ·Π΄Π°Π½ΠΈΠ΅ с Ρ€Π°Π·Ρ€Π΅ΡˆΠ΅Π½ΠΈΠ΅ΠΌ (ResolveAndConstruct) β€” Π°Π½Π°Π»ΠΈΠ·ΠΈΡ€ΡƒΠ΅Ρ‚ конструктор ΠΈ автоматичСски подставляСт зарСгистрированныС зависимости, ΠΏΠΎΠ΄Π΄Π΅Ρ€ΠΆΠΈΠ²Π°Π΅Ρ‚ Π΄ΠΎΠΏΠΎΠ»Π½ΠΈΡ‚Π΅Π»ΡŒΠ½Ρ‹Π΅ Π°Ρ€Π³ΡƒΠΌΠ΅Π½Ρ‚Ρ‹.

ΠšΠΎΠ½Ρ‚Π΅ΠΉΠ½Π΅Ρ€ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ DEBUG::Throw для Π΄Π΅Ρ‚Π°Π»ΡŒΠ½Ρ‹Ρ… ошибок ΠΏΡ€ΠΈ отсутствии зависимостСй.

ΠŸΠ»ΡŽΡΡ‹: ΠΌΠΎΠ΄ΡƒΠ»ΡŒΠ½ΠΎΡΡ‚ΡŒ, ΡƒΠ΄ΠΎΠ±Π½ΠΎΠ΅ тСстированиС (mock-Ρ€Π΅Π°Π»ΠΈΠ·Π°Ρ†ΠΈΠΈ), Π³ΠΈΠ±ΠΊΠΎΡΡ‚ΡŒ ΠΏΠΎΠ΄ΠΌΠ΅Π½Ρ‹, чистая инициализация прилоТСния.

БистСма сборки (Builder): v1.0.0

Π‘ΠΎΠ·Π΄Π°Π½Π° кроссплатформСнная систСма сборки (C++/Python/CMake/Shell), интСгрированная с Godot.

АрхитСктура:

  • ОбъявлСниС Ρ†Π΅Π»Π΅ΠΉ сначала Π²ΠΎ Π²Π½ΡƒΡ‚Ρ€Π΅Π½Π½ΠΈΡ… структурах, Π·Π°Ρ‚Π΅ΠΌ β€” Π·Π°Π³Ρ€ΡƒΠ·ΠΊΠ° зависимостСй ΠΈ гСнСрация Ρ†Π΅Π»Π΅ΠΉ CMake.
  • Выборочная компиляция: Π²ΠΊΠ»ΡŽΡ‡Π°ΡŽΡ‚ΡΡ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ Π½ΡƒΠΆΠ½Ρ‹Π΅ Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠΈ с автоматичСским подтягиваниСм зависимостСй.

Π”Π΅ΠΊΠ»Π°Ρ€Π°Ρ‚ΠΈΠ²Π½Ρ‹Π΅ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ CMake:

Library(ECS default
        SOURCES src/**/*.cpp
        PUBLIC_DIRS ./include
        PUBLIC_LIBS tp::entt
        DI:SHARED Debug:SHARED Utils:SHARED)

Library(ECS Godot
        SOURCES src/**/*.cpp
        PUBLIC_DIRS ./include
        PUBLIC_LIBS tp::entt
        DI:STATIC Debug:STATIC Utils:STATIC)

Executable(ECS_Tests default
        SOURCES tests/Tests.cpp
        PUBLIC_DIRS
        PRIVATE_LIBS ECS:SHARED)

CLI ΠΈ IDE:

  • АргумСнты: --rebuild, --rebuild_dependencies, --release, --ninja.
  • Π’ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎΡΡ‚ΡŒ ΡΠΎΠ±ΠΈΡ€Π°Ρ‚ΡŒ Π²Ρ‹Π±ΠΎΡ€ΠΎΡ‡Π½ΠΎ: WudgineBuilder ECS DI DEBUG.
  • Π‘Π΅ΡΡˆΠΎΠ²Π½Π°Ρ интСграция с Godot: Cmd+R Π² Ρ€Π΅Π΄Π°ΠΊΡ‚ΠΎΡ€Π΅ запускаСт ΠΏΠΎΠ»Π½ΡƒΡŽ сборку, Π»ΠΎΠ³ΠΈ выводятся Π² Output, GDExtension автоматичСски ΠΏΠΎΠΏΠ°Π΄Π°Π΅Ρ‚ Π² addons.

27.08.2025 β€” Jobs: v1.0.0

πŸš€ Полная рСализация API Unity Jobs Π½Π° C++.

ΠžΡΠ½ΠΎΠ²Ρ‹: iJob, iJobParallelFor.

Π£ΠΏΡ€Π°Π²Π»Π΅Π½ΠΈΠ΅: JobHandle (зависимости, ΠΎΠΆΠΈΠ΄Π°Π½ΠΈΠ΅, статус), Π³Ρ€Π°Ρ„ зависимостСй, ΠΏΡƒΠ» ΠΏΠΎΡ‚ΠΎΠΊΠΎΠ² = числу ядСр, потокобСзопасная ΠΎΡ‡Π΅Ρ€Π΅Π΄ΡŒ, Π°Π²Ρ‚ΠΎΡ€Π°Π·Π±ΠΈΠ΅Π½ΠΈΠ΅ ParallelFor.

Π‘Π΅Π·ΠΎΠΏΠ°ΡΠ½ΠΎΡΡ‚ΡŒ Π΄Π°Π½Π½Ρ‹Ρ…: Π°Ρ‚ΠΎΠΌΠ°Ρ€Π½Ρ‹Π΅ Ρ‚ΠΈΠΏΡ‹, ΠΊΠΎΠ½Ρ‚Π΅ΠΉΠ½Π΅Ρ€Ρ‹ с бСзопасным доступом (Π°Π½Π°Π»ΠΎΠ³ NativeContainer/NativeArray).

ΠŸΡ€ΠΈΠΌΠ΅Ρ€Ρ‹:

#include "Jobs/JobSystem.hpp"
#include "Jobs/JobHandle.hpp"

class MyJob : public Jobs::iJob {
public:
    void Execute() override {}
    std::vector<Jobs::JobHandle> GetDependencies() override { return {}; }
};

void runMassiveJobSchedulingExample() {
    auto& jobSystem = Jobs::JobSystem::GetInstance();
    std::vector<Jobs::JobHandle> handles; handles.reserve(100000);
    for (int i = 0; i < 100000; ++i) {
        auto job = std::make_unique<MyJob>();
        handles.push_back(jobSystem.Schedule(std::move(job)));
    }
    for (const auto& h : handles) { h.Complete(); }
}

Глубокая Ρ†Π΅ΠΏΠΎΡ‡ΠΊΠ° зависимостСй:

void testDeepDependencyChain(int depth) {
    Jobs::JobHandle lastHandle;
    for (int i = 0; i < depth; ++i) {
        auto job = std::make_unique<MyJob>();
        lastHandle = Jobs::JobSystem::GetInstance().Schedule(std::move(job), lastHandle);
    }
    lastHandle.Complete();
}

ParallelFor:

class MyParallelForJob : public Jobs::iJobParallelFor {
public:
    std::vector<int> data; MyParallelForJob(size_t size) : data(size) {}
    void Execute(int p_index) override { data[p_index] = p_index * 2; }
};

void runParallelForExample() {
    auto job = std::make_unique<MyParallelForJob>(100000);
    auto& js = Jobs::JobSystem::GetInstance();
    Jobs::JobHandle h = js.Schedule(std::move(job));
    h.Complete();
}

03.09.2025 β€” ECS: v1.0.0

πŸš€ ECS-Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠ° β€” ΠΊΠ»ΠΎΠ½ API Unity DOTS Π½Π° чистом C++.

Core: сущности (ΠΈΠ΄Π΅Π½Ρ‚ΠΈΡ„ΠΈΠΊΠ°Ρ‚ΠΎΡ€Ρ‹), ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚Ρ‹ (структуры), систСмы (Π»ΠΎΠ³ΠΈΠΊΠ° Π½Π°Π΄ ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚Π°ΠΌΠΈ).

Π“Ρ€ΡƒΠΏΠΏΡ‹ ΠΈ Π΄Π΅ΠΊΠ»Π°Ρ€Π°Ρ†ΠΈΠΈ:

  • UpdateInGroup<...> для порядка выполнСния, Any<...>, Frequency<...>.
  • АвтоматичСскоС Ρ€Π΅Π·ΠΎΠ»Π²ΠΈΠ½Π³ Π°Ρ€Π³ΡƒΠΌΠ΅Π½Ρ‚ΠΎΠ² Update(...) ΠΏΠΎΠ΄ Π½ΡƒΠΆΠ½Ρ‹Π΅ ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚Ρ‹ ΠΈ ΠΏΠ΅Ρ€Π΅Π³Ρ€ΡƒΠ·ΠΊΠΈ.
  • Π˜ΡΠΊΠ»ΡŽΡ‡Π°ΡŽΡ‰ΠΈΠ΅ запросы Ρ‡Π΅Ρ€Π΅Π· Exclude<...>.

EntityQuery: Π΄Π΅ΠΊΠ»Π°Ρ€Π°Ρ‚ΠΈΠ²Π½Ρ‹Π΅ запросы с With/Without, итСрация ΠΈ Each(...).

Π Π°ΡΡˆΠΈΡ€Π΅Π½Π½Ρ‹Π΅ возмоТности: DynamicBuffer<T>, EntityCommandBuffer, SharedComponent<T>, Ρ€Π΅Π°ΠΊΡ‚ΠΈΠ²Π½Ρ‹Π΅ систСмы, LinkedEntityGroup.

Π˜Π½Ρ‚Π΅Π³Ρ€Π°Ρ†ΠΈΡ с Godot:

Полная синхронизация Π΄Π°Π½Π½Ρ‹Ρ… ΠΌΠ΅ΠΆΠ΄Ρƒ ECS-ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚Π°ΠΌΠΈ (позиция, Π²Ρ€Π°Ρ‰Π΅Π½ΠΈΠ΅, ΠΌΠ°ΡΡˆΡ‚Π°Π± ΠΈ Ρ‚. ΠΏ.) ΠΈ ΡƒΠ·Π»Π°ΠΌΠΈ Godot. Godot β€” визуализация (UI/Ρ€Π΅Π½Π΄Π΅Ρ€/Π°ΡƒΠ΄ΠΈΠΎ), ECS (C++) β€” Π»ΠΎΠ³ΠΈΠΊΠ°/Π΄Π°Π½Π½Ρ‹Π΅.

24.09.2025 β€” Π Π΅Π½Π΄Π΅Ρ€, ассСты, UI ΠΈ Π°Ρ€Ρ…ΠΈΡ‚Π΅ΠΊΡ‚ΡƒΡ€Π°

ГрафичСский ΠΏΠ°ΠΉΠΏΠ»Π°ΠΉΠ½ Π½Π° Vulkan

  • Π‘ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠΈ: Render ΠΈ RenderGraph.
  • БоврСмСнная, быстрая ΠΈ гибкая основа для тяТёлых сцСн.

ΠœΠΎΠ΄ΡƒΠ»ΡŒΠ½Π°Ρ систСма ассСтов

  • TextureAsset, ShaderAsset, MaterialAsset, MeshAsset (.gltf). Π Π°ΡΡˆΠΈΡ€ΡΠ΅ΠΌΠ°Ρ Π°Ρ€Ρ…ΠΈΡ‚Π΅ΠΊΡ‚ΡƒΡ€Π° для ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΡΠΊΠΈΡ… Ρ‚ΠΈΠΏΠΎΠ².

UI Π½Π° Π²Π΅Π±-тСхнологиях ΠΈ мост C++ ↔ TypeScript

  • ΠŸΠ΅Ρ€Π΅Ρ…ΠΎΠ΄ с CEF Π½Π° Ultralight (Π»Ρ‘Π³ΠΊΠΈΠΉ ΠΈ быстрый).
  • Π—Π΅Ρ€ΠΊΠ°Π»ΡŒΠ½Ρ‹ΠΉ ECS API: ΠΊΠΎΠ΄ Π½Π° TS повторяСт C++ ΠΏΠΎΡ‡Ρ‚ΠΈ 1-Π²-1 (Π²ΠΊΠ»ΡŽΡ‡Π°Ρ EntityQuery).
  • Единая экосистСма: ΠΎΠ±Ρ‰ΠΈΠΉ стСк для Ρ€Π΅Π΄Π°ΠΊΡ‚ΠΎΡ€Π°, ΠΈΠ³Ρ€Ρ‹ ΠΈ сайта (Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€, Nuxt 4 + TypeScript).

Врёхслойная Π°Ρ€Ρ…ΠΈΡ‚Π΅ΠΊΡ‚ΡƒΡ€Π°

ΠžΡ‚Π΄Π΅Π»ΡŒΠ½Ρ‹Π΅ Ρ€Π΅ΠΏΠΎΠ·ΠΈΡ‚ΠΎΡ€ΠΈΠΈ Π½Π° Ρ‚Ρ€ΠΈ слоя:

  1. НизкоуровнСвый: ΠΎΠΊΠ½Π° ОБ, графичСский API (Vulkan ΠΈ Π°Π»ΡŒΡ‚Π΅Ρ€Π½Π°Ρ‚ΠΈΠ²Π°).
  2. Π―Π΄Ρ€ΠΎ: ECS, ассСты ΠΈ Π±Π°Π·ΠΎΠ²Ρ‹Π΅ ΠΌΠΎΠ΄ΡƒΠ»ΠΈ.
  3. ΠŸΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΡΠΊΠΈΠΉ ΠΏΡ€ΠΎΠ΅ΠΊΡ‚: ΠΈΠ³Ρ€ΠΎΠ²ΠΎΠΉ ΠΊΠΎΠ΄.

Ѐокус дальшС β€” Ρ€Π΅Π΄Π°ΠΊΡ‚ΠΎΡ€ Π² Π΄ΡƒΡ…Π΅ интСрфСйса Blender (ΠΌΠΎΠ΄ΡƒΠ»ΡŒΠ½ΠΎΡΡ‚ΡŒ, Ρ€Π°Π±ΠΎΡ‡ΠΈΠ΅ области/Workspaces, Ρ€Π°ΡΡˆΠΈΡ€ΡΠ΅ΠΌΠΎΡΡ‚ΡŒ).

ДороТная ΠΊΠ°Ρ€Ρ‚Π° Ρ€Π΅Π½Π΄Π΅Ρ€Π°

  • Anti-aliasing, Ρ‚Π΅Π½ΠΈ, стСк пост-эффСктов (Bloom, Color Grading, SSAO ΠΈ Π΄Ρ€.).
  • GPU-Ρ€Π΅Π½Π΄Π΅Ρ€ΠΈΠ½Π³ UI Π½Π°ΠΏΡ€ΡΠΌΡƒΡŽ Π½Π° Vulkan (идСально Π³Π»Π°Π΄ΠΊΠΈΠΉ тСкст, Ρ€Π°Π·Π³Ρ€ΡƒΠ·ΠΊΠ° CPU).
  • ΠŸΠ°Ρ€Π°Π»Π»Π΅Π»ΡŒΠ½Ρ‹ΠΉ Π΄Π°Ρ‚Π°-ΠΎΡ€ΠΈΠ΅Π½Ρ‚ΠΈΡ€ΠΎΠ²Π°Π½Π½Ρ‹ΠΉ ΠΏΠ°ΠΉΠΏΠ»Π°ΠΉΠ½ Ρ€Π΅Π½Π΄Π΅Ρ€Π° ΠΊΠ°ΠΊ Π°Π»ΡŒΡ‚Π΅Ρ€Π½Π°Ρ‚ΠΈΠ²Π° ООП-Ρ€Π΅Π½Π΄Π΅Ρ€Ρƒ.

ΠŸΡ€ΠΈΠΌΠ΅Ρ€Ρ‹ Π·Π΅Ρ€ΠΊΠ°Π»ΡŒΠ½ΠΎΠ³ΠΎ API систСм C++ ↔ TS

SpinSystem (Π²Ρ€Π°Ρ‰Π΅Π½ΠΈΠ΅ сущности):

class SpinSystem : public iSystem<
            Sorting<UpdateInGroup<DrawRenderSystemGroup>, UpdateAfter<RenderSystem>>,
            Filter<With<AngularVelocity, Rotation>>,
            Fps<30>> {
public:
    void Update(double dt, const SystemState& s, Entity e,
                const AngularVelocity& av, Rotation& r) {
        Math::quat dq = Math::quat(av.value * static_cast<float>(dt));
        r.value = glm::normalize(r.value * dq);
    }
};
class SpinSystem extends iSystem(
    Sorting(UpdateInGroup(DrawRenderSystemGroup), UpdateAfter(RenderSystem)),
    Filter(With(AngularVelocity, Rotation)),
    Fps(30)
) {
  override Update(dt: number, s: SystemState, e: Entity,
                  av: AngularVelocity, r: Rotation): void {
    const delta = glm.quat.create();
    const axis = glm.vec3.create();
    glm.vec3.normalize(axis, av.value);
    const angle = glm.vec3.length(av.value) * dt;
    glm.quat.setAxisAngle(delta, axis, angle);
    glm.quat.multiply(r.value, r.value, delta);
    glm.quat.normalize(r.value, r.value);
  }
}

UI-ΠΏΡ€ΠΈΠΌΠ΅Ρ€ (UnitBarsSystem):

const BAR_CONTAINER_ID = 'unit-bar-container';
export class UnitBarsSystem extends iSystem(
  Sorting(UpdateInGroup(UISystemGroup)),
  Filter(With()),
  Frequency(30)
) {
  private m_barsMap = new Map<Entity, HTMLElement>();
  private m_container: HTMLElement | null = null;
  private m_entityBarsQueryFilter: EntityQueryFilter | null = null;
  override OnCreate(systemState: SystemState): void {
    this.m_container = document.getElementById(BAR_CONTAINER_ID);
    this.m_entityBarsQueryFilter = new EntityQuery().With(ScreenPosition).Build();
  }
  override Update(deltaTime: number, systemState: SystemState): void {
    const view = new EntityView(systemState.entityManager, this.m_entityBarsQueryFilter!);
    const it: EntityIterator = view.getIterator();
    const active = new Set<Entity>();
    while (it.next()) {
      const id = it.entity; active.add(id);
      if (!this.m_barsMap.has(id)) {
        const bar = document.createElement('div');
        bar.className = 'unit-bar';
        this.m_container?.appendChild(bar);
        this.m_barsMap.set(id, bar);
      }
      const bar = this.m_barsMap.get(id)!;
      const screenPos = it.components[0];
      bar.style.transform = `translate(${screenPos.x}px, ${screenPos.y}px)`;
    }
    for (const [id, bar] of this.m_barsMap.entries()) {
      if (!active.has(id)) { bar.remove(); this.m_barsMap.delete(id); }
    }
  }
  override OnDestroy(): void {
    if (this.m_container) this.m_container.innerHTML = '';
    this.m_barsMap.clear();
  }
}

Wudgine β€’ Β© 2025