From 22881f517699ac737877e4b228fc4b195cf3a4d6 Mon Sep 17 00:00:00 2001 From: min Date: Tue, 9 Jun 2026 02:37:00 +0300 Subject: [PATCH] =?UTF-8?q?feat(wiki):=20LangTabs=20=D0=B2=D0=BE=20=D0=92?= =?UTF-8?q?=D0=A1=D0=95=20=D1=81=D1=82=D0=B0=D1=82=D1=8C=D0=B8=20D1-D8=20"?= =?UTF-8?q?=D0=A1=D0=BA=D1=80=D0=B8=D0=BF=D1=82=D1=8B=20=E2=80=94=20=D0=BE?= =?UTF-8?q?=D1=81=D0=BD=D0=BE=D0=B2=D1=8B"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Переключатель JS/Lua теперь реально влияет на содержимое в каждой из 8 статей раздела. Для каждой темы дан рабочий код на обоих языках: - D1 Что такое скрипт: game.log vs print - D2 Глобальный/на объекте: game.self vs script.Parent - D3 Переменные: let vs local - D4 game vs game:GetService/workspace - D5 game.log vs print - D6 События: game.onTick/onClick vs RunService.Heartbeat / ClickDetector - D7 if/else: === vs ==, !== vs ~=, then/end - D8 Таймеры: game.after/every/cancel vs task.delay/wait/spawn Также пояснительные плашки подобраны под язык — указания специфичные для синтаксиса каждого языка. --- src/community/docsData.jsx | 503 +++++++++++++++++++++++++++---------- 1 file changed, 368 insertions(+), 135 deletions(-) diff --git a/src/community/docsData.jsx b/src/community/docsData.jsx index e802e4c..f51c53c 100644 --- a/src/community/docsData.jsx +++ b/src/community/docsData.jsx @@ -1248,9 +1248,11 @@ end)`}} нужен скрипт.

- Скрипты пишут на языке JavaScript — одном из самых - популярных языков в мире. Не пугайся: начнём с простого, - а редактор подсказывает команды по ходу набора. + Скрипты пишут на одном из двух языков: JavaScript + или Lua. Оба работают одинаково. Подробнее про + выбор языка — статья D0 выше. В этом уроке покажем + пример на обоих языках — переключай вкладки, чтобы видеть + нужный.

Как создать первый скрипт:

@@ -1260,9 +1262,13 @@ end)`}} - Откроется окно кода. Напиши в нём одну строку: + Откроется окно кода. Вверху выбери язык (кнопки JS/Lua) + и напиши одну строку: - {`game.log('Привет! Игра запустилась.');`} + {`game.log('Привет! Игра запустилась.');`}} + lua={{`print("Привет! Игра запустилась.")`}} + /> @@ -1270,15 +1276,23 @@ end)`}} открой Консоль — там появится твоё сообщение.

- Это твой первый работающий скрипт. Команда - game.log(...) печатает сообщение в консоль. + Это твой первый работающий скрипт.

- - Каждая команда заканчивается точкой с запятой - ; — как точка в конце предложения. Текст - пишут в кавычках: 'привет'. Забыл кавычки - или точку с запятой — будет ошибка. - + + Команда game.log(...) печатает в консоль. + Каждая команда в JavaScript заканчивается точкой с запятой + ; — как точка в предложении. Текст пишут + в кавычках: 'привет'. +
} + lua={ + Команда print(...) печатает в консоль. + В Lua точку с запятой ставить не нужно. + Текст пишут в кавычках: "привет" или + 'привет'. Lua использует .. + (две точки) для склейки текста: "А=" .. 5. + } + /> ), }, @@ -1303,22 +1317,45 @@ end)`}}

Скрипт на объекте относится к конкретному кубу, модели или кнопке. Внутри такого скрипта работает волшебное слово - game.self — это и есть тот объект, на котором - висит скрипт. Через него ловят клик по объекту или касание - игроком. + (своё для каждого языка):

+ + {`// JS: game.self — это и есть тот объект, на котором висит скрипт +game.self.onClick(() => { + game.log('Кликнули по мне!'); +});`} + } + lua={<> + {`-- Lua: script.Parent — это и есть тот объект, на котором висит скрипт +local part = script.Parent + +part.Touched:Connect(function(hit) + print("Касание объекта " .. part.Name) +end)`} + } + />

Как привязать скрипт к объекту: выдели объект на сцене, потом создай скрипт — он автоматически привяжется к выделенному объекту. Или укажи носителя в настройках скрипта.

- - Простое правило: если в коде урока есть - game.self — это скрипт на объекте. - Если game.self нет — скрипт глобальный. - Плашка в начале каждого урока всегда подскажет. - + + Простое правило: если в коде урока есть + game.self — это скрипт на объекте. + Если game.self нет — скрипт глобальный. + Плашка в начале каждого урока всегда подскажет. + } + lua={ + Простое правило: если в коде есть + script.Parent — это скрипт на объекте. + Если только game — глобальный. + В Lua глобальные скрипты обычно работают со списком + игроков: game:GetService("Players"). + } + /> ), }, @@ -1332,29 +1369,61 @@ end)`}} скрипт хранит значение. Например, количество очков, имя игрока, выбранный уровень.

- {`// Создаём переменную и кладём в неё число + {`// JS: создаём переменную через let let score = 0; // Меняем значение score = score + 10; // теперь в score лежит 10 score = score + 5; // теперь 15 -game.log('Очков:', score); // напечатает: Очков: 15`} -

- let — это слово «создать переменную». Пишут - его только один раз, когда коробочку заводят. Дальше - меняют значение уже без let. -

+game.log('Очков:', score); // напечатает: Очков: 15`}} + lua={{`-- Lua: создаём переменную через local +local score = 0 + +-- Меняем значение +score = score + 10 -- теперь в score лежит 10 +score = score + 5 -- теперь 15 + +print("Очков:", score) -- напечатает: Очков: 15`}} + /> + + let — это слово «создать переменную». Пишут + его только один раз, когда коробочку заводят. Дальше + меняют значение уже без let. +

} + lua={

+ local — это слово «создать переменную внутри + скрипта». Пишут его только один раз. Если опустить + local — переменная станет глобальной (доступна + всем скриптам), это редко нужно. +

} + />

В переменную можно класть не только числа:

- {`let name = 'Герой'; // текст — в кавычках + {`let name = 'Герой'; // текст — в кавычках let isWin = false; // да/нет — true или false -let coinCount = 0; // число — без кавычек`} - - Если значение никогда не меняется — вместо - let можно писать const - («постоянная»). Например, найденную один раз дверь: - const door = game.scene.findOne('Дверь'); - +let coinCount = 0; // число — без кавычек`}} + lua={{`local name = "Герой" -- текст — в кавычках +local isWin = false -- да/нет — true или false +local coinCount = 0 -- число — без кавычек`}} + /> + + Если значение никогда не меняется — вместо + let можно писать const + («постоянная»). Например, найденную один раз дверь: + const door = game.scene.findOne('Дверь'); + } + lua={ + В Lua нет отдельного слова для «не-меняющейся» переменной — + всё через local. Если хочешь явно показать + что значение не меняется, пиши имя ЗАГЛАВНЫМИ: + local DOOR = workspace.Дверь. + Это договорённость, а не правило Lua. + } + /> ), }, @@ -1366,59 +1435,108 @@ let coinCount = 0; // число — без кавычек`}

В каждом скрипте есть одно главное волшебное слово — game. Через него ты управляешь всей игрой. - У game много «отделов»: + Но «отделы» у JS и Lua разные:

- - - - - - - - - - -
game.playerуправление игроком
game.sceneобъекты сцены
game.uiсчётчики и текст на экране
game.guiкнопки и меню
game.soundзвуки
game.physicsлучи, импульсы, взрывы
game.selfобъект-носитель скрипта
+ + + + + + + + + + + +
game.playerуправление игроком
game.sceneобъекты сцены
game.uiсчётчики и текст на экране
game.guiкнопки и меню
game.soundзвуки
game.physicsлучи, импульсы, взрывы
game.selfобъект-носитель скрипта
+

+ Запись через точку читается слева направо. + game.player.teleport(0, 5, 0) читается так: + «у игры, у игрока, выполни телепорт + в точку 0, 5, 0». +

+ } + lua={<> + + + + + + + + + + +
workspace3D-объекты сцены
game:GetService("Players")список игроков
game.Workspaceто же что workspace
script.Parentобъект-носитель скрипта
game:GetService("RunService")каждый кадр (Heartbeat)
game:GetService("UserInputService")клавиши и мышь
game:GetService("TweenService")плавные движения
+

+ Знак : (двоеточие) в Lua — это вызов + метода объекта. game:GetService("Players") + читается так: «у game вызови GetService + и дай ему текст Players». +

+

+ Точка . — это доступ к полю объекта. + workspace.Floor.BrickColor — у workspace + взять Floor, у него взять BrickColor. +

+ } + />

- Запись через точку читается слева направо. - game.player.teleport(0, 5, 0) читается так: - «у игры, у игрока, выполни телепорт - в точку 0, 5, 0». -

-

- Полный список всех команд каждого отдела — в Справочнике - (раздел H). Не нужно его заучивать: при наборе кода - редактор сам показывает подсказки. + Полный список всех команд — в Справочнике (раздел H). Не нужно + его заучивать: при наборе кода редактор сам показывает подсказки.

), }, { id: 'log-console', - title: 'D5. game.log, консоль, отладка', + title: 'D5. log/print, консоль, отладка', body: ( <>

Консоль — окошко в правом нижнем углу редактора. Туда выводятся все сообщения и ошибки скриптов.

-

- Команда game.log(...) печатает в консоль - что угодно. Это главный инструмент отладки — - проверки, что код работает правильно: -

+ + Команда game.log(...) печатает в консоль + что угодно. Это главный инструмент отладки — + проверки, что код работает правильно: +

} + lua={

+ Команда print(...) печатает в консоль + что угодно. Это главный инструмент отладки — + проверки, что код работает правильно: +

} + /> - {`let score = 0; + {`let score = 0; score = score + 10; game.log('Очки сейчас:', score); // Очки сейчас: 10 let pos = game.player.position; -game.log('Игрок стоит в точке:', pos);`} -

- Если игра ведёт себя странно — расставь - game.log по коду и посмотри, какие значения - печатаются. Так ты увидишь, где именно что-то пошло не так. -

+game.log('Игрок стоит в точке:', pos);`}} + lua={{`local score = 0 +score = score + 10 +print("Очки сейчас:", score) -- Очки сейчас: 10 + +local pos = game.Players.LocalPlayer.Character.HumanoidRootPart.Position +print("Игрок стоит в точке:", pos)`}} + /> + + Если игра ведёт себя странно — расставь + game.log по коду и посмотри, какие значения + печатаются. Так ты увидишь, где именно что-то пошло не так. +

} + lua={

+ Если игра ведёт себя странно — расставь + print по коду и посмотри, какие значения + печатаются. Так ты увидишь, где именно что-то пошло не так. +

} + /> Если в скрипте опечатка — текст ошибки появится в Консоли красным, и там же будет написан номер @@ -1429,39 +1547,77 @@ game.log('Игрок стоит в точке:', pos);`} }, { id: 'events', - title: 'D6. События: onTick, onKey, onClick, onTouch', + title: 'D6. События: тик, клавиши, клик, касание', body: ( <>

Событие — это «что-то случилось». Скрипт может ждать событие и реагировать на него. Самые важные:

- - - - - - - -
game.onTick(fn)каждый кадр (60 раз в секунду)
game.onKey('space', fn)игрок нажал клавишу
game.self.onClick(fn)игрок кликнул по объекту
game.self.onTouch(fn)игрок коснулся объекта
+ + + game.onTick(fn)каждый кадр (60 раз в секунду) + game.onKey('space', fn)игрок нажал клавишу + game.self.onClick(fn)игрок кликнул по объекту + game.self.onTouch(fn)игрок коснулся объекта + + } + lua={ + + + + + + +
RunService.Heartbeat:Connect(fn)каждый кадр
UserInputService.InputBegan:Connect(fn)любая клавиша
part.ClickDetector.MouseClick:Connect(fn)клик по объекту
part.Touched:Connect(fn)касание объекта
} + />

Пример — куб, который исчезает по клику:

- {`game.self.onClick(() => { + {`game.self.onClick(() => { game.self.delete(); // удалить сам себя game.log('Куб удалён!'); -});`} -

- Что такое {`() => { ... }`}? Это - «функция» — набор команд, упакованных вместе. Команды - внутри фигурных скобок выполнятся не сразу, а только - когда случится событие. То есть «когда кликнули — тогда - удалить и напечатать». -

- - onTick выполняется ОЧЕНЬ часто — 60 раз - в секунду. Не делай внутри него тяжёлых вещей. Подробнее - об этой ошибке — раздел J4. - +});`}} + lua={{`local part = script.Parent +local clickDetector = Instance.new("ClickDetector") +clickDetector.Parent = part + +clickDetector.MouseClick:Connect(function(player) + part:Destroy() -- удалить сам себя + print("Куб удалён!") +end)`}} + /> + + Что такое {`() => { ... }`}? Это + «функция» — набор команд, упакованных вместе. Команды + внутри фигурных скобок выполнятся не сразу, а только + когда случится событие. То есть «когда кликнули — тогда + удалить и напечатать». +

} + lua={

+ Что такое function() ... end? Это + «функция» — набор команд, упакованных вместе. Команды + между function() и end выполнятся + не сразу, а только когда случится событие. То есть + «когда кликнули — тогда удалить и напечатать». + Метод :Connect «подключает» функцию + к событию. +

} + /> + + onTick выполняется ОЧЕНЬ часто — 60 раз + в секунду. Не делай внутри него тяжёлых вещей. Подробнее + об этой ошибке — раздел J4. +
} + lua={ + Heartbeat выполняется ОЧЕНЬ часто — 60 раз + в секунду. Не делай внутри тяжёлых вычислений. Подробнее + об этой ошибке — раздел J4. + } + /> ), }, @@ -1472,66 +1628,113 @@ game.log('Игрок стоит в точке:', pos);`} <>

Условие — это развилка: «если что-то верно — - сделай одно, иначе — другое». В JavaScript это + сделай одно, иначе — другое». В обоих языках это слова if («если») и else - («иначе»). + («иначе»), но запись чуть отличается.

- {`let coins = 7; + {`let coins = 7; if (coins >= 10) { game.ui.showText('Хватает на покупку!', 2); } else { game.ui.showText('Нужно больше монет', 2); -}`} +}`}} + lua={{`local coins = 7 + +if coins >= 10 then + print("Хватает на покупку!") +else + print("Нужно больше монет") +end`}} + />

Тут проверяется: coins {'>'}= 10 — «монет 10 или больше?». Сейчас монет 7, значит условие неверно, и сработает ветка else.

Знаки сравнения:

- - - - - - - - - -
a === ba равно b
a !== ba не равно b
a {'>'} ba больше b
a {'<'} ba меньше b
a {'>'}= ba больше или равно b
a {'<'}= ba меньше или равно b
- - Для проверки «равно» пишут три знака равенства - ===, а не один. Один знак = — - это «положить значение в переменную», совсем другое - действие. - + + + a === ba равно b + a !== ba не равно b + a {'>'} ba больше b + a {'<'} ba меньше b + a {'>'}= ba больше или равно b + a {'<'}= ba меньше или равно b + + } + lua={ + + + + + + + + +
a == ba равно b
a ~= ba не равно b
a {'>'} ba больше b
a {'<'} ba меньше b
a {'>'}= ba больше или равно b
a {'<'}= ba меньше или равно b
} + /> + + В JS для проверки «равно» пишут три знака равенства + ===, а не один. Один знак = — + это «положить значение в переменную», совсем другое + действие. И не равно — это !==. + } + lua={ + В Lua для проверки «равно» пишут два знака равенства + ==. А «не равно» — это ~= + (тильда + равно). Запомни этот значок — он встречается + только в Lua. + } + /> ), }, { id: 'timers', - title: 'D8. Таймеры: after, every, cancel', + title: 'D8. Таймеры: задержка, повтор, отмена', body: ( <>

Таймеры запускают команды не сразу, а потом:

-
    -
  • - game.after(сек, fn) — выполнить - один раз через несколько секунд; -
  • -
  • - game.every(сек, fn) — выполнять - снова и снова каждые несколько секунд; -
  • -
  • - game.cancel(id) — остановить таймер. -
  • -
+ +
  • + game.after(сек, fn) — выполнить + один раз через несколько секунд; +
  • +
  • + game.every(сек, fn) — выполнять + снова и снова каждые несколько секунд; +
  • +
  • + game.cancel(id) — остановить таймер. +
  • + } + lua={
      +
    • + task.delay(сек, fn) — выполнить + один раз через несколько секунд; +
    • +
    • + task.wait(сек) — приостановить скрипт + на N секунд (внутри цикла или функции); +
    • +
    • + Для повторяющихся таймеров — обычный цикл + while true do task.wait(1); ... end + в отдельной корутине через task.spawn. +
    • +
    } + /> - {`// Через 3 секунды показать текст + {`// Через 3 секунды показать текст game.after(3, () => { game.ui.showText('Игра началась!', 2); }); @@ -1546,12 +1749,42 @@ const ticker = game.every(1, () => { game.after(10, () => { game.cancel(ticker); game.ui.showText('Время вышло!', 2); -});`} -

    - Запись (game.ui.score || 0) читается так: - «возьми счёт, а если его ещё нет — возьми 0». Это защита - от ошибки в самом начале, когда счётчик ещё пустой. -

    +});`}} + lua={{`-- Через 3 секунды показать текст +task.delay(3, function() + print("Игра началась!") +end) + +-- Каждую секунду прибавлять очко. +-- Запускаем в отдельной корутине чтобы не блокировать скрипт. +local score = 0 +local running = true +task.spawn(function() + while running do + task.wait(1) + score = score + 1 + end +end) + +-- Через 10 секунд остановить начисление очков +task.delay(10, function() + running = false + print("Время вышло! Набрано очков:", score) +end)`}} + /> + + Запись (game.ui.score || 0) читается так: + «возьми счёт, а если его ещё нет — возьми 0». Это защита + от ошибки в самом начале, когда счётчик ещё пустой. +

    } + lua={

    + В Lua переменная running — флаг работы цикла. + Когда нужно остановить таймер, ставим running = false, + и цикл сам завершится после task.wait(1). + Это проще, чем хранить номер таймера. +

    } + /> ), },