diff --git a/src/community/docsLessons.jsx b/src/community/docsLessons.jsx index 66d563f..6261197 100644 --- a/src/community/docsLessons.jsx +++ b/src/community/docsLessons.jsx @@ -1,5 +1,24 @@ import React from 'react'; import { Code, ScriptKind, Step, Note, Try, Shot } from './docsData'; +import { LangTabs } from './docsLang'; +import { LUA_OVERRIDES } from './docsGamesBuildersLua'; + +/** + * Хелпер: оборачивает JS-код в LangTabs с Lua-параллелью из LUA_OVERRIDES. + * {`// JS код...`} + * → если открыт JS — показывает JS код + * → если открыт Lua — показывает Lua-код из LUA_OVERRIDES[game][script] + */ +function CodeBoth({ game, script, children }) { + const luaCode = LUA_OVERRIDES[game]?.[script]; + const luaResolved = typeof luaCode === 'function' ? luaCode({ id: script }) : luaCode; + return ( + {children}} + lua={luaResolved ? {luaResolved} : null} + /> + ); +} /** * docsLessons.jsx — тексты уроков для 50 мини-игр (раздел K вики). @@ -104,7 +123,7 @@ export const LESSONS = { Главный скрипт считает монетки и проверяет победу.

- {`// === ИГРА «СОБЕРИ МОНЕТКИ» — главный скрипт === + {`// === ИГРА «СОБЕРИ МОНЕТКИ» — главный скрипт === // Этот скрипт глобальный: считает собранные монетки и проверяет победу. let score = 0; // сколько монеток собрано @@ -131,7 +150,7 @@ game.onMessage('coin', () => { { x: p.x, y: p.y + 3, z: p.z }, { duration: 3, count: 3 }); } -});`} +});`}

Разберём построчно:

@@ -154,14 +173,14 @@ game.onMessage('coin', () => { касание и сообщает главному скрипту: меня собрали.

- {`// === Скрипт монетки === + {`// === Скрипт монетки === // game.self — это сама монетка, на которой висит скрипт. game.self.onTouch(() => { // игрок коснулся монетки — сообщаем главному скрипту game.broadcast('coin'); game.self.delete(); // монетка исчезает со сцены -});`} +});`}

Что происходит: onTouch срабатывает, когда игрок дотронулся до монетки. Внутри мы шлём @@ -274,7 +293,7 @@ game.self.onTouch(() => { Главный скрипт следит за падением и обрабатывает победу.

- {`// === ИГРА «ПРЫГАЙ ПО ПЛАТФОРМАМ» — главный скрипт === + {`// === ИГРА «ПРЫГАЙ ПО ПЛАТФОРМАМ» — главный скрипт === let won = false; // победа уже была? @@ -304,7 +323,7 @@ game.onMessage('finish', () => { game.scene.spawnParticles('confetti', { x: p.x, y: p.y + 3, z: p.z }, { duration: 3, count: 3 }); -});`} +});`}

Что тут важно:

  • game.onTick(...) — функция внутри @@ -320,13 +339,13 @@ game.onMessage('finish', () => {

    Шаг 4. Скрипт финиша

    - {`// === Скрипт финиша === + {`// === Скрипт финиша === // Висит на невидимой зоне над зелёной площадкой. // Игрок встал на площадку — его тело внутри зоны — победа. game.self.onTouch(() => { game.broadcast('finish'); // сообщаем главному скрипту о победе -});`} +});`}

    Когда игрок касается финиша, скрипт шлёт game.broadcast('finish'). Главный скрипт ловит @@ -401,7 +420,7 @@ game.self.onTouch(() => {

    Шаг 2. Главный скрипт

    Следит за падением и победой — как в уроке 2.

    - {`// === ИГРА «НЕ УПАДИ» — главный скрипт === + {`// === ИГРА «НЕ УПАДИ» — главный скрипт === let won = false; @@ -428,7 +447,7 @@ game.onMessage('finish', () => { const p = game.player.position; game.scene.spawnParticles('confetti', { x: p.x, y: p.y + 3, z: p.z }, { duration: 3, count: 3 }); -});`} +});`}

    Шаг 3. Скрипт исчезающей плитки

    @@ -436,7 +455,7 @@ game.onMessage('finish', () => { который убирает её через секунду после касания.

    - {`// === Скрипт исчезающей плитки === + {`// === Скрипт исчезающей плитки === let triggered = false; // плитка уже запущена на исчезновение? @@ -448,7 +467,7 @@ game.self.onTouch(() => { game.after(1.2, () => { game.self.delete(); }); -});`} +});`}

    Разберём:

    • triggered — флажок-защёлка. Игрок может @@ -532,7 +551,7 @@ game.self.onTouch(() => {

      Шаг 3. Главный скрипт

      - {`// === ИГРА «КНОПКА-ОТКРЫВАШКА» — главный скрипт === + {`// === ИГРА «КНОПКА-ОТКРЫВАШКА» — главный скрипт === game.ui.showText('Подойди к красной кнопке и нажми E', 4); @@ -544,7 +563,7 @@ game.onMessage('win', () => { const p = game.player.position; game.scene.spawnParticles('confetti', { x: p.x, y: p.y + 3, z: p.z }, { duration: 3, count: 3 }); -});`} +});`}

      Шаг 4. Скрипт кнопки — главное

      @@ -552,7 +571,7 @@ game.onMessage('win', () => { открывает дверь.

      - {`// === Скрипт кнопки === + {`// === Скрипт кнопки === let opened = false; @@ -570,7 +589,7 @@ game.self.onInteract(() => { }, { text: 'Открыть дверь', // подсказка над кнопкой distance: 4 // на сколько метров подойти -});`} +});`}

      Разберём:

      • game.self.onInteract(fn, опции) — это @@ -592,10 +611,10 @@ game.self.onInteract(() => {

        Шаг 5. Скрипт финиша и проверка

        - {`// === Скрипт финиша === + {`// === Скрипт финиша === game.self.onTouch(() => { game.broadcast('win'); // сообщаем главному скрипту о победе -});`} +});`}

        Запусти игру:

        • подойди к кнопке — появится подсказка «Открыть дверь»;
        • @@ -688,7 +707,7 @@ game.self.onTouch(() => {

          Шаг 5. Скрипты

          Скрипты совсем простые — лабиринт держится на постройке.

          - {`// === ИГРА «ЛАБИРИНТ» — главный скрипт === + {`// === ИГРА «ЛАБИРИНТ» — главный скрипт === game.ui.showText('Найди выход из лабиринта!', 3); @@ -700,12 +719,12 @@ game.onMessage('win', () => { const p = game.player.position; game.scene.spawnParticles('confetti', { x: p.x, y: p.y + 3, z: p.z }, { duration: 3, count: 3 }); -});`} +});`} - {`// === Скрипт финиша === + {`// === Скрипт финиша === game.self.onTouch(() => { game.broadcast('win'); // сообщаем главному скрипту о победе -});`} +});`}

          Шаг 6. Проверка

            @@ -764,7 +783,7 @@ game.self.onTouch(() => {

            Шаг 2. Главный скрипт

            - {`// === ИГРА «ЦВЕТНЫЕ ПЛИТКИ» — главный скрипт === + {`// === ИГРА «ЦВЕТНЫЕ ПЛИТКИ» — главный скрипт === let painted = 0; // сколько плиток раскрашено const TOTAL = 36; // всего плиток (6×6) @@ -785,7 +804,7 @@ game.onMessage('paint', () => { game.scene.spawnParticles('confetti', { x: p.x, y: p.y + 3, z: p.z }, { duration: 3, count: 3 }); } -});`} +});`} Замени число 36 на столько плиток, сколько реально поставил. Если сетка 5×5 — будет 25. @@ -793,7 +812,7 @@ game.onMessage('paint', () => {

            Шаг 3. Скрипт плитки

            - {`// === Скрипт цветной плитки === + {`// === Скрипт цветной плитки === let painted = false; // плитка уже раскрашена? @@ -803,7 +822,7 @@ game.self.onTouch(() => { // меняем цвет плитки на ярко-зелёный game.scene.setColor(game.self.ref, '#33dd55'); game.broadcast('paint'); // сообщаем главному скрипту о покраске -});`} +});`}

            Главное здесь:

            • game.scene.setColor(ref, цвет) — меняет @@ -874,7 +893,7 @@ game.self.onTouch(() => {

              Шаг 2. Главный скрипт

              - {`// === ИГРА «ПОЙМАЙ ПАДАЮЩЕЕ» — главный скрипт === + {`// === ИГРА «ПОЙМАЙ ПАДАЮЩЕЕ» — главный скрипт === let score = 0; const GOAL = 15; // сколько кубов нужно поймать @@ -922,7 +941,7 @@ game.onPlayerTouch((e) => { game.scene.spawnParticles('confetti', { x: p.x, y: p.y + 3, z: p.z }, { duration: 3, count: 3 }); } -});`} +});`}

              Разберём по частям:

              • game.every(1.5, fn) — каждые 1.5 секунды @@ -1005,7 +1024,7 @@ game.onPlayerTouch((e) => {

                Шаг 2. Главный скрипт

                - {`// === ИГРА «БЕГИ К ФИНИШУ» — главный скрипт === + {`// === ИГРА «БЕГИ К ФИНИШУ» — главный скрипт === let finished = false; let time = 0; // прошло секунд @@ -1032,7 +1051,7 @@ game.onMessage('finish', () => { const p = game.player.position; game.scene.spawnParticles('confetti', { x: p.x, y: p.y + 3, z: p.z }, { duration: 3, count: 3 }); -});`} +});`}

                Главное здесь — измерение времени:

                • game.onTick((dt) => {'{...}'}) — @@ -1048,10 +1067,10 @@ game.onMessage('finish', () => {

                  Шаг 3. Скрипт финиша

                  - {`// === Скрипт финиша === + {`// === Скрипт финиша === game.self.onTouch(() => { game.broadcast('finish'); // сообщаем главному скрипту о финише -});`} +});`}

                  Шаг 4. Проверка