Я только начинаю писать код, он у меня не аккуратный и странный, проект писать на luaJIT love 2d, а заголовок правдивый, оно смогло запустить на одном ядре слабого ноутбука 12300 потоков в которых были блоки IF, ROTATE и WHILE TRUE и стабильные 30 fps. https://t.me/Turbo_Scratch/63 Там если что демонстрация и версия для windows если кому надо. Также github.
Движок я выбрал не случайно, мне понравился синтаксис lua, этот язык и библиотеку love 2d подсказала ии, на этой же библиотеке написан Pocket Up(аналог pocket code, тоже визуальное программирование), также этот язык использует байт-код и jit компиляцию что по словам ии должно сильно увеличивать скорость. Также love 2d собирается под многие платформы Windows, macos, вроде даже linux, android, ios. Читал офф сайт и нашёл упоминание игры Balatro, я эту игру до этого только раз слышал, но про что она не знаю.
Писал я всё в VS Code, это очень удобный редактор кода, я на нём и другие свои проекты писал. С lua я уже был знаком, так как я уже делал игру на roblox studio, и не так давно, осенью 25 года.
Я сразу хотел писать свой редактор так чтобы он работал на Windows, и собирал проекты в EXE(уже реализовано), apk и html. И чтобы отделить в будущем редактор и интерпретатор игры я разделил проект на части Main.lua - редактор, Micropaint.lua - редактор спрайтов, ну и по мелочи GameLoader.lua - загрузчик игр, BlockList.lua - список доступных блоков, не хотел его лепить в main.lua тк там 518 строк, + я туда ещё добавил функцию отрисовки блоков и удобнее когда функционал разделён на отдельные файлы.
Сначала я сделал простенькое окно загрузки и создания игры, GUI библиотеку не использовал и кодом рисовал все линии у кнопок.

--КНОПКА: Загрузить love.graphics.rectangle("line", 230, 10, 120, 40) love.graphics.print("Загрузить", 240, 10) --КНОПКА: Создать love.graphics.rectangle("line", 360, 10, 100, 40) love.graphics.print("Создать", 370, 10)
Также я весь код связанный с кнопками старался комментировать, чтобы потом понять для чего какой код, если в отображении кнопки можно по print(“Создать”) понять что это за кнопка, то в коде обработки нажатий не понятно ничего
--КНОПКА Создать if x > 360 and x < 460 and y > 10 and y < 50 then createNewGame() end --КНОПКА ЗАГРУЗИТЬ if x > 230 and x < 350 and y > 10 and y < 50 then if gload[3](gload[2]()) == "suc" then GameLoaded = true love.window.showMessageBox( "ГОТОВО!","Игра с именем "..game.name.." загружена") else love.window.showMessageBox( "ОШИБКА","Во время загрузки возникла ошибка") end end
Конечно всё равно по функциям понятно что за что отвечает, но с комментариями проще. А ещё проще было бы если бы я использовал готовую GUI библиотеку
Дальше я писал остальные функции выбора спрайтов, сами спрайты, на блоках подробно останавливаться не буду лишь могу показать пример как я в коде выглядит блок случайного числа
t[#t+1] = { type = 3, --ТИП БЛОКА 1 - ОБЫЧНЫЙ 2 - ИСПОЛНЕНИЯ 3 - ДАННЫХ isStarter = false, --ЭТО БЛОК НАЧАЛА СКРИПТА??? DisplayName = "Случайное значение (от, до)", -- ОТОБРАЖАЕМОЕ ИМЯ name = "random", -- СИСТЕМНОЕ ИМЯ args = 2, -- КОЛИЧЕСТВО АРГУМЕНТОВ containBlocksIn = false, -- ИМЕЕТ БЛОКИ ВНУТРИ color = {0, 0, 0} }
И получится из этого

(белые квадратики это поля для ввода чисел)
Также в блоки можно вставлять другие блоки, я пытался сделать это через рекурсию моей функции RenderBlock() которая отображает блок(я хотел чтобы она вызывала саму себя) но у меня это нормально не вышло

Если вдруг кто не понял оно выберет случайное число от (5*5) до (25+100)
Интерпретатор блоков писать было интереснее всего, я его сделал в одном потоке(чтобы было проще) ну и разделил там же блоки на 3 типа, они интерпретируются по разному
if name == "getX" then --Получить X return sprite.pos.x elseif name == "getY" then --Получить Y return sprite.pos.y elseif name == "random" then --Рандом return love.math.random(tonumber(args[1].data),tonumber(args[2].data)) elseif name == "getrotation" then --Поворот return sprite.rotation elseif name == "getcostume" then --Костюм return sprite.costumeNumber elseif name == "getsize" then --Размер return sprite.size elseif name == "mathplus" then --Плюс return tonumber(args[1].data) + tonumber(args[2].data) elseif name == "mathminus" then --Минус return tonumber(args[1].data) - tonumber(args[2].data) elseif name == "mathmultiply" then --Умножить return tonumber(args[1].data) * tonumber(args[2].data) elseif name == "mathdivide" then --Делить return tonumber(args[1].data) / tonumber(args[2].data)
Тут представлен код интерпретации блоков данных, name это системное имя, а args[*].data это аргументы, уже переведённые из блоков (тк в блок можно сувать другой блок, и те блоки уже были выполнены) в нормальный текст. А ещё в lua массивы начинаются с 1, а не с 0 как в других языках
По умолчанию LOVE не поддерживает русский язык, я взял из папки C:\windows\fonts шрифт comis sans и сделал его шрифтом по умолчанию, ну и я ещё взял другой шрифт, но как уже не вспомню, сделал его шрифтом для блоков
Когда пришло время собирать проект в EXE файл я решил сначала собрать файлы через Love Fusion (нашёл на github) который положил мне все dll файлы в одну папку, а файлы редактора запаковал в EXE файл, после через Enigma Virtual Box я собрал все dll и exe в один другой exe файл.
