diff --git a/src/community/docsData.jsx b/src/community/docsData.jsx index 6f4ce46..e8da0db 100644 --- a/src/community/docsData.jsx +++ b/src/community/docsData.jsx @@ -2134,29 +2134,64 @@ TweenService:Create(door, TweenInfo.new(1), goal):Play()`}} body: ( <>

Команды для здоровья игрока:

- - - - - - - - - -
game.player.hpтекущее здоровье (можно читать)
game.player.damage(n)нанести урон
game.player.heal(n)вылечить
game.player.kill()мгновенно убить
game.player.respawn()воскресить на спавне
game.player.setSpawn(точка)новая точка возрождения
+ + + game.player.hpтекущее здоровье + game.player.damage(n)нанести урон + game.player.heal(n)вылечить + game.player.kill()мгновенно убить + game.player.respawn()воскресить на спавне + game.player.setSpawn(точка)новая точка возрождения + + } + lua={ + + + + + + + + +
humanoid.Healthтекущее здоровье
humanoid:TakeDamage(n)нанести урон
humanoid.Health = humanoid.Health + nвылечить
humanoid.Health = 0мгновенно убить
player:LoadCharacter()воскресить
player.RespawnLocation = spawnновая точка возрождения
} + />

Пример 1 — шипы наносят урон:

- {`game.self.onTouch(() => { + {`game.self.onTouch(() => { game.player.damage(20); // отнять 20 здоровья game.sound.play('hit'); -});`} +});`}} + lua={{`local part = script.Parent + +part.Touched:Connect(function(hit) + local humanoid = hit.Parent:FindFirstChild("Humanoid") + if humanoid then + humanoid:TakeDamage(20) -- отнять 20 здоровья + end +end)`}} + />

Пример 2 — аптечка лечит:

- {`game.self.onTouch(() => { + {`game.self.onTouch(() => { game.player.heal(50); // добавить 50 здоровья game.ui.showText('+50 HP', 1.5); game.self.delete(); // аптечка исчезает -});`} +});`}} + lua={{`local part = script.Parent + +part.Touched:Connect(function(hit) + local humanoid = hit.Parent:FindFirstChild("Humanoid") + if not humanoid then return end + + -- добавить 50 здоровья, но не выше MaxHealth + humanoid.Health = math.min(humanoid.Health + 50, humanoid.MaxHealth) + print("+50 HP") + part:Destroy() -- аптечка исчезает +end)`}} + /> ), }, @@ -2165,52 +2200,78 @@ TweenService:Create(door, TweenInfo.new(1), goal):Play()`}} title: 'F2. Физика: raycast, импульсы, взрывы', body: ( <> -

- Отдел game.physics отвечает за «настоящую» - физику: -

-
    -
  • - raycast(откуда, куда, опции) — пустить - невидимый луч и узнать, во что он попал. Так делают - стрельбу; -
  • -
  • - applyImpulse(ref, сила) — толкнуть объект - (он должен быть не закреплён); -
  • -
  • - explode(точка, радиус, опции) — взрыв. -
  • -
+ +

Отдел game.physics отвечает за «настоящую» физику:

+
    +
  • raycast(откуда, куда, опции) — луч для стрельбы;
  • +
  • applyImpulse(ref, сила) — толкнуть объект;
  • +
  • explode(точка, радиус, опции) — взрыв.
  • +
+ } + lua={<> +

В Lua для физики используется workspace и стандартный Roblox API:

+
    +
  • workspace:Raycast(origin, dir, params) — луч;
  • +
  • part:ApplyImpulse(Vector3) — толкнуть Part;
  • +
  • Instance.new("Explosion") — создать взрыв.
  • +
+ } + />

Пример — стрельба лучом из камеры игрока:

- {`// При клике мышкой пускаем луч туда, куда смотрит игрок -game.onClick(() => { + {`game.onClick(() => { const p = game.player.position; const hit = game.physics.raycast( { x: p.x, y: p.y + 1.5, z: p.z }, // откуда (от головы) game.player.forward, // куда (взгляд) - { maxDistance: 50 } // как далеко + { maxDistance: 50 } ); if (hit.hit) { game.log('Попал в объект:', hit.ref); game.sound.play('hit'); } -});`} -

- hit.hit — попал ли луч во что-нибудь - (да/нет). hit.ref — адрес объекта, в который - попали. -

+});`}} + lua={{`local UIS = game:GetService("UserInputService") +local Players = game:GetService("Players") +local player = Players.LocalPlayer +local mouse = player:GetMouse() + +UIS.InputBegan:Connect(function(input) + if input.UserInputType ~= Enum.UserInputType.MouseButton1 then return end + + local hrp = player.Character.HumanoidRootPart + local origin = hrp.Position + Vector3.new(0, 1.5, 0) + local direction = (mouse.Hit.Position - origin).Unit * 50 + + local raycastResult = workspace:Raycast(origin, direction) + if raycastResult then + print("Попал в объект:", raycastResult.Instance.Name) + end +end)`}} + /> + + hit.hit — попал ли луч во что-нибудь. + hit.ref — адрес объекта. +

} + lua={

+ raycastResult равно nil если + луч ни во что не попал. Иначе у него есть поля + .Instance (что попало), + .Position (точка попадания), + .Normal (нормаль поверхности). +

} + /> ), }, { id: 'attributes', - title: 'F3. Атрибуты объектов (setData / getData)', + title: 'F3. Атрибуты объектов', body: ( <>

@@ -2219,14 +2280,27 @@ game.onClick(() => { или сколько монет стоит товар.

- {`// При старте игры запоминаем цену прямо на товаре + {`// При старте игры запоминаем цену прямо на товаре game.scene.setData(game.self.ref, 'price', 50); // Когда игрок кликает по товару — читаем цену game.self.onClick(() => { const price = game.scene.getData(game.self.ref, 'price'); game.ui.showText('Этот товар стоит ' + price + ' монет', 2); -});`} +});`}} + lua={{`local part = script.Parent + +-- При старте игры запоминаем цену прямо на товаре +part:SetAttribute("Price", 50) + +-- Когда игрок кликает — читаем цену +local clickDetector = Instance.new("ClickDetector", part) +clickDetector.MouseClick:Connect(function(player) + local price = part:GetAttribute("Price") + print("Этот товар стоит " .. price .. " монет") +end)`}} + />

Чем атрибут лучше обычной переменной? Переменная одна на весь скрипт. А атрибут — свой у каждого объекта. @@ -2242,36 +2316,61 @@ game.self.onClick(() => { body: ( <>

- Тег — это «ярлык», который можно повесить сразу - на много объектов. Потом одной командой можно найти их все. + Тег — это «ярлык» на объекте. Удобно ставить сразу на + много объектов и потом одной командой находить их все.

- - - - - - - -
tag(ref, 'звезда')повесить тег
untag(ref, 'звезда')снять тег
hasTag(ref, 'звезда')есть ли тег
getTagged('звезда')все объекты с тегом
+ + + game.scene.tag(ref, 'звезда')повесить тег + game.scene.untag(ref, 'звезда')снять тег + game.scene.hasTag(ref, 'звезда')есть ли тег + game.scene.getTagged('звезда')все объекты с тегом + + } + lua={ + + + + + + +
CollectionService:AddTag(part, "звезда")повесить тег
CollectionService:RemoveTag(part, "звезда")снять тег
CollectionService:HasTag(part, "звезда")есть ли тег
CollectionService:GetTagged("звезда")все объекты с тегом
} + />

Пример — игра «собери все звёзды»:

- {`// Этот скрипт висит на звезде. -// При старте помечаем звезду тегом. + {`// Этот скрипт висит на звезде. game.scene.tag(game.self.ref, 'звезда'); -// Когда игрок коснулся — звезда собрана game.self.onTouch(() => { game.self.delete(); game.sound.play('coin'); - // сколько звёзд ещё осталось на сцене? const left = game.scene.getTagged('звезда').length; if (left === 0) { game.ui.showText('Все звёзды собраны! Победа!', 3); } else { game.ui.showText('Осталось звёзд: ' + left, 1.5); } -});`} +});`}} + lua={{`local CS = game:GetService("CollectionService") +local part = script.Parent + +-- Помечаем звезду тегом +CS:AddTag(part, "звезда") + +part.Touched:Connect(function() + part:Destroy() + + local left = #CS:GetTagged("звезда") + if left == 0 then + print("Все звёзды собраны! Победа!") + else + print("Осталось звёзд: " .. left) + end +end)`}} + /> Снятие тега убирает только ярлык. Цвет, размер и другие свойства объекта при этом не меняются. @@ -2281,16 +2380,16 @@ game.self.onTouch(() => { }, { id: 'proximity', - title: 'F5. ProximityPrompt — взаимодействие по клавише E', + title: 'F5. Взаимодействие по клавише E (ProximityPrompt)', body: ( <>

Часто игра просит «подойди и нажми E»: открыть сундук, - поговорить с торговцем, дёрнуть рычаг. Это делается - командой game.self.onInteract: + поговорить с торговцем, дёрнуть рычаг.

- {`game.self.onInteract(() => { + {`game.self.onInteract(() => { game.ui.showText('Сундук открыт!', 2); game.scene.spawnParticles('sparks', game.self.position, { duration: 1 }); @@ -2298,11 +2397,26 @@ game.self.onTouch(() => { }, { text: 'Открыть сундук', // подсказка над объектом distance: 4 // на сколько метров подойти -});`} +});`}} + lua={{`local part = script.Parent + +-- ProximityPrompt — стандартный Roblox-способ +local prompt = Instance.new("ProximityPrompt") +prompt.ActionText = "Открыть" +prompt.ObjectText = "Сундук" +prompt.MaxActivationDistance = 4 +prompt.KeyboardKeyCode = Enum.KeyCode.E +prompt.Parent = part + +prompt.Triggered:Connect(function(player) + print("Сундук открыт!") + -- Можно создать эффект частиц или проиграть звук +end)`}} + />

- Когда игрок подойдёт ближе чем на distance - метров, над объектом появится подсказка с текстом. - Нажатие E запустит функцию. + Когда игрок подойдёт на расстояние взаимодействия, над + объектом появится подсказка с текстом. Нажатие + E запустит функцию.

), @@ -2318,36 +2432,62 @@ game.self.onTouch(() => { Так показывают имена врагов, их HP, названия мест.

- {`// Допустим, npc — это адрес созданного NPC. -// Вешаем над ним табличку с именем. + {`// npc — это адрес созданного NPC. game.scene.setLabel(npc.ref, 'Торговец Боб', { color: '#ffffff', height: 2.5 // на 2.5 метра над объектом }); // Позже можно убрать табличку -game.scene.clearLabel(npc.ref);`} +game.scene.clearLabel(npc.ref);`}} + lua={{`-- BillboardGui в Roblox — это GUI поверх Part +local part = workspace:WaitForChild("NPC") + +local billboard = Instance.new("BillboardGui") +billboard.Size = UDim2.new(4, 0, 1, 0) +billboard.StudsOffset = Vector3.new(0, 2.5, 0) -- над объектом +billboard.Parent = part + +local label = Instance.new("TextLabel") +label.BackgroundTransparency = 1 +label.Size = UDim2.new(1, 0, 1, 0) +label.Text = "Торговец Боб" +label.TextColor3 = Color3.new(1, 1, 1) +label.TextScaled = true +label.Parent = billboard + +-- Позже можно убрать табличку +-- billboard:Destroy()`}} + /> ), }, { id: 'pass-through', - title: 'F7. Проходимость объектов (passThrough)', + title: 'F7. Проходимость объектов', body: ( <>

Иногда стена должна стать проходимой — призрачная стена, - секретный проход, исчезающий мост. Команда - game.physics.passThrough(ref, true) делает - объект «бесплотным»: видно его, но игрок проходит насквозь. + секретный проход, исчезающий мост.

- {`// Когда игрок кликнет по стене — она пропустит сквозь себя -game.self.onClick(() => { + {`game.self.onClick(() => { game.physics.passThrough(game.self.ref, true); game.scene.setOpacity(game.self.ref, 0.3); // полупрозрачная game.ui.showText('Секретный проход открыт!', 2); -});`} +});`}} + lua={{`local part = script.Parent +local clickDetector = Instance.new("ClickDetector", part) + +clickDetector.MouseClick:Connect(function(player) + part.CanCollide = false -- игрок проходит насквозь + part.Transparency = 0.7 -- полупрозрачная (0=видна, 1=невидима) + print("Секретный проход открыт!") +end)`}} + /> Если сделать стену снова твёрдой, пока игрок стоит внутри неё — игра аккуратно вытолкнет его наружу, он не застрянет. @@ -2362,39 +2502,53 @@ game.self.onClick(() => { <>

Связи (constraints) соединяют объекты, чтобы они - двигались вместе или по правилам физики. Отдел — - game.constraints: + двигались вместе или по правилам физики.

    -
  • - Склейка (weld) — намертво приклеивает один - объект к другому; -
  • -
  • - Петля (hinge) — объект вращается вокруг оси, - как дверь на петлях или качели; -
  • -
  • - Пружина (spring) — объект упруго колеблется, - как батут. -
  • +
  • Склейка (weld) — намертво приклеивает один объект к другому;
  • +
  • Петля (hinge) — объект вращается вокруг оси, как дверь или качели;
  • +
  • Пружина (spring) — объект упруго колеблется, как батут.

Пример — качели на петле:

- {`const swing = game.scene.findOne('Качели'); + {`const swing = game.scene.findOne('Качели'); -// делаем качели на петле const h = game.constraints.hinge(swing, { - pivotX: 0, pivotZ: 0, // ось вращения - angle: 30 // наклон на 30 градусов + pivotX: 0, pivotZ: 0, + angle: 30 }); // раскачиваем в другую сторону каждую секунду let dir = -30; game.every(1, () => { h.setAngle(dir); - dir = -dir; // меняем знак: 30 → -30 → 30 ... -});`} + dir = -dir; +});`}} + lua={{`-- В Roblox HingeConstraint — стандартный способ +local swing = workspace:WaitForChild("Качели") +local mount = workspace:WaitForChild("Опора") -- неподвижная точка + +-- Attachment'ы (точки крепления) +local a0 = Instance.new("Attachment", mount) +local a1 = Instance.new("Attachment", swing) + +local hinge = Instance.new("HingeConstraint") +hinge.Attachment0 = a0 +hinge.Attachment1 = a1 +hinge.ActuatorType = Enum.ActuatorType.Servo +hinge.ServoMaxTorque = 10000 +hinge.AngularSpeed = 2 +hinge.Parent = swing + +-- Раскачиваем +local dir = 30 +while true do + hinge.TargetAngle = dir + task.wait(1) + dir = -dir +end`}} + /> ), },