feat: 50 игр на Lua + импорт Roblox для всех + поддержка Lua в плеере #39
@ -2134,29 +2134,64 @@ TweenService:Create(door, TweenInfo.new(1), goal):Play()`}</Code>}
|
|||||||
body: (
|
body: (
|
||||||
<>
|
<>
|
||||||
<p>Команды для здоровья игрока:</p>
|
<p>Команды для здоровья игрока:</p>
|
||||||
<table className="docTable">
|
<LangTabs
|
||||||
<tbody>
|
js={<table className="docTable">
|
||||||
<tr><td><code>game.player.hp</code></td><td>текущее здоровье (можно читать)</td></tr>
|
<tbody>
|
||||||
<tr><td><code>game.player.damage(n)</code></td><td>нанести урон</td></tr>
|
<tr><td><code>game.player.hp</code></td><td>текущее здоровье</td></tr>
|
||||||
<tr><td><code>game.player.heal(n)</code></td><td>вылечить</td></tr>
|
<tr><td><code>game.player.damage(n)</code></td><td>нанести урон</td></tr>
|
||||||
<tr><td><code>game.player.kill()</code></td><td>мгновенно убить</td></tr>
|
<tr><td><code>game.player.heal(n)</code></td><td>вылечить</td></tr>
|
||||||
<tr><td><code>game.player.respawn()</code></td><td>воскресить на спавне</td></tr>
|
<tr><td><code>game.player.kill()</code></td><td>мгновенно убить</td></tr>
|
||||||
<tr><td><code>game.player.setSpawn(точка)</code></td><td>новая точка возрождения</td></tr>
|
<tr><td><code>game.player.respawn()</code></td><td>воскресить на спавне</td></tr>
|
||||||
</tbody>
|
<tr><td><code>game.player.setSpawn(точка)</code></td><td>новая точка возрождения</td></tr>
|
||||||
</table>
|
</tbody>
|
||||||
|
</table>}
|
||||||
|
lua={<table className="docTable">
|
||||||
|
<tbody>
|
||||||
|
<tr><td><code>humanoid.Health</code></td><td>текущее здоровье</td></tr>
|
||||||
|
<tr><td><code>humanoid:TakeDamage(n)</code></td><td>нанести урон</td></tr>
|
||||||
|
<tr><td><code>humanoid.Health = humanoid.Health + n</code></td><td>вылечить</td></tr>
|
||||||
|
<tr><td><code>humanoid.Health = 0</code></td><td>мгновенно убить</td></tr>
|
||||||
|
<tr><td><code>player:LoadCharacter()</code></td><td>воскресить</td></tr>
|
||||||
|
<tr><td><code>player.RespawnLocation = spawn</code></td><td>новая точка возрождения</td></tr>
|
||||||
|
</tbody>
|
||||||
|
</table>}
|
||||||
|
/>
|
||||||
<p><b>Пример 1 — шипы наносят урон:</b></p>
|
<p><b>Пример 1 — шипы наносят урон:</b></p>
|
||||||
<ScriptKind kind="object" on="шипы (конус)" />
|
<ScriptKind kind="object" on="шипы (конус)" />
|
||||||
<Code>{`game.self.onTouch(() => {
|
<LangTabs
|
||||||
|
js={<Code>{`game.self.onTouch(() => {
|
||||||
game.player.damage(20); // отнять 20 здоровья
|
game.player.damage(20); // отнять 20 здоровья
|
||||||
game.sound.play('hit');
|
game.sound.play('hit');
|
||||||
});`}</Code>
|
});`}</Code>}
|
||||||
|
lua={<Code>{`local part = script.Parent
|
||||||
|
|
||||||
|
part.Touched:Connect(function(hit)
|
||||||
|
local humanoid = hit.Parent:FindFirstChild("Humanoid")
|
||||||
|
if humanoid then
|
||||||
|
humanoid:TakeDamage(20) -- отнять 20 здоровья
|
||||||
|
end
|
||||||
|
end)`}</Code>}
|
||||||
|
/>
|
||||||
<p><b>Пример 2 — аптечка лечит:</b></p>
|
<p><b>Пример 2 — аптечка лечит:</b></p>
|
||||||
<ScriptKind kind="object" on="аптечку" />
|
<ScriptKind kind="object" on="аптечку" />
|
||||||
<Code>{`game.self.onTouch(() => {
|
<LangTabs
|
||||||
|
js={<Code>{`game.self.onTouch(() => {
|
||||||
game.player.heal(50); // добавить 50 здоровья
|
game.player.heal(50); // добавить 50 здоровья
|
||||||
game.ui.showText('+50 HP', 1.5);
|
game.ui.showText('+50 HP', 1.5);
|
||||||
game.self.delete(); // аптечка исчезает
|
game.self.delete(); // аптечка исчезает
|
||||||
});`}</Code>
|
});`}</Code>}
|
||||||
|
lua={<Code>{`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)`}</Code>}
|
||||||
|
/>
|
||||||
</>
|
</>
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
@ -2165,52 +2200,78 @@ TweenService:Create(door, TweenInfo.new(1), goal):Play()`}</Code>}
|
|||||||
title: 'F2. Физика: raycast, импульсы, взрывы',
|
title: 'F2. Физика: raycast, импульсы, взрывы',
|
||||||
body: (
|
body: (
|
||||||
<>
|
<>
|
||||||
<p>
|
<LangTabs
|
||||||
Отдел <code>game.physics</code> отвечает за «настоящую»
|
js={<>
|
||||||
физику:
|
<p>Отдел <code>game.physics</code> отвечает за «настоящую» физику:</p>
|
||||||
</p>
|
<ul>
|
||||||
<ul>
|
<li><code>raycast(откуда, куда, опции)</code> — луч для стрельбы;</li>
|
||||||
<li>
|
<li><code>applyImpulse(ref, сила)</code> — толкнуть объект;</li>
|
||||||
<code>raycast(откуда, куда, опции)</code> — пустить
|
<li><code>explode(точка, радиус, опции)</code> — взрыв.</li>
|
||||||
невидимый луч и узнать, во что он попал. Так делают
|
</ul>
|
||||||
стрельбу;
|
</>}
|
||||||
</li>
|
lua={<>
|
||||||
<li>
|
<p>В Lua для физики используется <code>workspace</code> и стандартный Roblox API:</p>
|
||||||
<code>applyImpulse(ref, сила)</code> — толкнуть объект
|
<ul>
|
||||||
(он должен быть не закреплён);
|
<li><code>workspace:Raycast(origin, dir, params)</code> — луч;</li>
|
||||||
</li>
|
<li><code>part:ApplyImpulse(Vector3)</code> — толкнуть Part;</li>
|
||||||
<li>
|
<li><code>Instance.new("Explosion")</code> — создать взрыв.</li>
|
||||||
<code>explode(точка, радиус, опции)</code> — взрыв.
|
</ul>
|
||||||
</li>
|
</>}
|
||||||
</ul>
|
/>
|
||||||
<p><b>Пример — стрельба лучом из камеры игрока:</b></p>
|
<p><b>Пример — стрельба лучом из камеры игрока:</b></p>
|
||||||
<ScriptKind kind="global" />
|
<ScriptKind kind="global" />
|
||||||
<Code>{`// При клике мышкой пускаем луч туда, куда смотрит игрок
|
<LangTabs
|
||||||
game.onClick(() => {
|
js={<Code>{`game.onClick(() => {
|
||||||
const p = game.player.position;
|
const p = game.player.position;
|
||||||
|
|
||||||
const hit = game.physics.raycast(
|
const hit = game.physics.raycast(
|
||||||
{ x: p.x, y: p.y + 1.5, z: p.z }, // откуда (от головы)
|
{ x: p.x, y: p.y + 1.5, z: p.z }, // откуда (от головы)
|
||||||
game.player.forward, // куда (взгляд)
|
game.player.forward, // куда (взгляд)
|
||||||
{ maxDistance: 50 } // как далеко
|
{ maxDistance: 50 }
|
||||||
);
|
);
|
||||||
|
|
||||||
if (hit.hit) {
|
if (hit.hit) {
|
||||||
game.log('Попал в объект:', hit.ref);
|
game.log('Попал в объект:', hit.ref);
|
||||||
game.sound.play('hit');
|
game.sound.play('hit');
|
||||||
}
|
}
|
||||||
});`}</Code>
|
});`}</Code>}
|
||||||
<p>
|
lua={<Code>{`local UIS = game:GetService("UserInputService")
|
||||||
<code>hit.hit</code> — попал ли луч во что-нибудь
|
local Players = game:GetService("Players")
|
||||||
(да/нет). <code>hit.ref</code> — адрес объекта, в который
|
local player = Players.LocalPlayer
|
||||||
попали.
|
local mouse = player:GetMouse()
|
||||||
</p>
|
|
||||||
|
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)`}</Code>}
|
||||||
|
/>
|
||||||
|
<LangTabs
|
||||||
|
js={<p>
|
||||||
|
<code>hit.hit</code> — попал ли луч во что-нибудь.
|
||||||
|
<code> hit.ref</code> — адрес объекта.
|
||||||
|
</p>}
|
||||||
|
lua={<p>
|
||||||
|
<code>raycastResult</code> равно <code>nil</code> если
|
||||||
|
луч ни во что не попал. Иначе у него есть поля
|
||||||
|
<code> .Instance</code> (что попало),
|
||||||
|
<code> .Position</code> (точка попадания),
|
||||||
|
<code> .Normal</code> (нормаль поверхности).
|
||||||
|
</p>}
|
||||||
|
/>
|
||||||
</>
|
</>
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'attributes',
|
id: 'attributes',
|
||||||
title: 'F3. Атрибуты объектов (setData / getData)',
|
title: 'F3. Атрибуты объектов',
|
||||||
body: (
|
body: (
|
||||||
<>
|
<>
|
||||||
<p>
|
<p>
|
||||||
@ -2219,14 +2280,27 @@ game.onClick(() => {
|
|||||||
или сколько монет стоит товар.
|
или сколько монет стоит товар.
|
||||||
</p>
|
</p>
|
||||||
<ScriptKind kind="object" on="товар в магазине" />
|
<ScriptKind kind="object" on="товар в магазине" />
|
||||||
<Code>{`// При старте игры запоминаем цену прямо на товаре
|
<LangTabs
|
||||||
|
js={<Code>{`// При старте игры запоминаем цену прямо на товаре
|
||||||
game.scene.setData(game.self.ref, 'price', 50);
|
game.scene.setData(game.self.ref, 'price', 50);
|
||||||
|
|
||||||
// Когда игрок кликает по товару — читаем цену
|
// Когда игрок кликает по товару — читаем цену
|
||||||
game.self.onClick(() => {
|
game.self.onClick(() => {
|
||||||
const price = game.scene.getData(game.self.ref, 'price');
|
const price = game.scene.getData(game.self.ref, 'price');
|
||||||
game.ui.showText('Этот товар стоит ' + price + ' монет', 2);
|
game.ui.showText('Этот товар стоит ' + price + ' монет', 2);
|
||||||
});`}</Code>
|
});`}</Code>}
|
||||||
|
lua={<Code>{`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)`}</Code>}
|
||||||
|
/>
|
||||||
<p>
|
<p>
|
||||||
Чем атрибут лучше обычной переменной? Переменная одна
|
Чем атрибут лучше обычной переменной? Переменная одна
|
||||||
на весь скрипт. А атрибут — свой у каждого объекта.
|
на весь скрипт. А атрибут — свой у каждого объекта.
|
||||||
@ -2242,36 +2316,61 @@ game.self.onClick(() => {
|
|||||||
body: (
|
body: (
|
||||||
<>
|
<>
|
||||||
<p>
|
<p>
|
||||||
<b>Тег</b> — это «ярлык», который можно повесить сразу
|
<b>Тег</b> — это «ярлык» на объекте. Удобно ставить сразу на
|
||||||
на много объектов. Потом одной командой можно найти их все.
|
много объектов и потом одной командой находить их все.
|
||||||
</p>
|
</p>
|
||||||
<table className="docTable">
|
<LangTabs
|
||||||
<tbody>
|
js={<table className="docTable">
|
||||||
<tr><td><code>tag(ref, 'звезда')</code></td><td>повесить тег</td></tr>
|
<tbody>
|
||||||
<tr><td><code>untag(ref, 'звезда')</code></td><td>снять тег</td></tr>
|
<tr><td><code>game.scene.tag(ref, 'звезда')</code></td><td>повесить тег</td></tr>
|
||||||
<tr><td><code>hasTag(ref, 'звезда')</code></td><td>есть ли тег</td></tr>
|
<tr><td><code>game.scene.untag(ref, 'звезда')</code></td><td>снять тег</td></tr>
|
||||||
<tr><td><code>getTagged('звезда')</code></td><td>все объекты с тегом</td></tr>
|
<tr><td><code>game.scene.hasTag(ref, 'звезда')</code></td><td>есть ли тег</td></tr>
|
||||||
</tbody>
|
<tr><td><code>game.scene.getTagged('звезда')</code></td><td>все объекты с тегом</td></tr>
|
||||||
</table>
|
</tbody>
|
||||||
|
</table>}
|
||||||
|
lua={<table className="docTable">
|
||||||
|
<tbody>
|
||||||
|
<tr><td><code>CollectionService:AddTag(part, "звезда")</code></td><td>повесить тег</td></tr>
|
||||||
|
<tr><td><code>CollectionService:RemoveTag(part, "звезда")</code></td><td>снять тег</td></tr>
|
||||||
|
<tr><td><code>CollectionService:HasTag(part, "звезда")</code></td><td>есть ли тег</td></tr>
|
||||||
|
<tr><td><code>CollectionService:GetTagged("звезда")</code></td><td>все объекты с тегом</td></tr>
|
||||||
|
</tbody>
|
||||||
|
</table>}
|
||||||
|
/>
|
||||||
<p><b>Пример — игра «собери все звёзды»:</b></p>
|
<p><b>Пример — игра «собери все звёзды»:</b></p>
|
||||||
<ScriptKind kind="object" on="каждую звезду" />
|
<ScriptKind kind="object" on="каждую звезду" />
|
||||||
<Code>{`// Этот скрипт висит на звезде.
|
<LangTabs
|
||||||
// При старте помечаем звезду тегом.
|
js={<Code>{`// Этот скрипт висит на звезде.
|
||||||
game.scene.tag(game.self.ref, 'звезда');
|
game.scene.tag(game.self.ref, 'звезда');
|
||||||
|
|
||||||
// Когда игрок коснулся — звезда собрана
|
|
||||||
game.self.onTouch(() => {
|
game.self.onTouch(() => {
|
||||||
game.self.delete();
|
game.self.delete();
|
||||||
game.sound.play('coin');
|
game.sound.play('coin');
|
||||||
|
|
||||||
// сколько звёзд ещё осталось на сцене?
|
|
||||||
const left = game.scene.getTagged('звезда').length;
|
const left = game.scene.getTagged('звезда').length;
|
||||||
if (left === 0) {
|
if (left === 0) {
|
||||||
game.ui.showText('Все звёзды собраны! Победа!', 3);
|
game.ui.showText('Все звёзды собраны! Победа!', 3);
|
||||||
} else {
|
} else {
|
||||||
game.ui.showText('Осталось звёзд: ' + left, 1.5);
|
game.ui.showText('Осталось звёзд: ' + left, 1.5);
|
||||||
}
|
}
|
||||||
});`}</Code>
|
});`}</Code>}
|
||||||
|
lua={<Code>{`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)`}</Code>}
|
||||||
|
/>
|
||||||
<Note>
|
<Note>
|
||||||
Снятие тега убирает только ярлык. Цвет, размер и другие
|
Снятие тега убирает только ярлык. Цвет, размер и другие
|
||||||
свойства объекта при этом не меняются.
|
свойства объекта при этом не меняются.
|
||||||
@ -2281,16 +2380,16 @@ game.self.onTouch(() => {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'proximity',
|
id: 'proximity',
|
||||||
title: 'F5. ProximityPrompt — взаимодействие по клавише E',
|
title: 'F5. Взаимодействие по клавише E (ProximityPrompt)',
|
||||||
body: (
|
body: (
|
||||||
<>
|
<>
|
||||||
<p>
|
<p>
|
||||||
Часто игра просит «подойди и нажми E»: открыть сундук,
|
Часто игра просит «подойди и нажми E»: открыть сундук,
|
||||||
поговорить с торговцем, дёрнуть рычаг. Это делается
|
поговорить с торговцем, дёрнуть рычаг.
|
||||||
командой <code>game.self.onInteract</code>:
|
|
||||||
</p>
|
</p>
|
||||||
<ScriptKind kind="object" on="сундук" />
|
<ScriptKind kind="object" on="сундук" />
|
||||||
<Code>{`game.self.onInteract(() => {
|
<LangTabs
|
||||||
|
js={<Code>{`game.self.onInteract(() => {
|
||||||
game.ui.showText('Сундук открыт!', 2);
|
game.ui.showText('Сундук открыт!', 2);
|
||||||
game.scene.spawnParticles('sparks',
|
game.scene.spawnParticles('sparks',
|
||||||
game.self.position, { duration: 1 });
|
game.self.position, { duration: 1 });
|
||||||
@ -2298,11 +2397,26 @@ game.self.onTouch(() => {
|
|||||||
}, {
|
}, {
|
||||||
text: 'Открыть сундук', // подсказка над объектом
|
text: 'Открыть сундук', // подсказка над объектом
|
||||||
distance: 4 // на сколько метров подойти
|
distance: 4 // на сколько метров подойти
|
||||||
});`}</Code>
|
});`}</Code>}
|
||||||
|
lua={<Code>{`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)`}</Code>}
|
||||||
|
/>
|
||||||
<p>
|
<p>
|
||||||
Когда игрок подойдёт ближе чем на <code>distance</code>
|
Когда игрок подойдёт на расстояние взаимодействия, над
|
||||||
метров, над объектом появится подсказка с текстом.
|
объектом появится подсказка с текстом. Нажатие
|
||||||
Нажатие <kbd className="kbd">E</kbd> запустит функцию.
|
<kbd className="kbd">E</kbd> запустит функцию.
|
||||||
</p>
|
</p>
|
||||||
</>
|
</>
|
||||||
),
|
),
|
||||||
@ -2318,36 +2432,62 @@ game.self.onTouch(() => {
|
|||||||
Так показывают имена врагов, их HP, названия мест.
|
Так показывают имена врагов, их HP, названия мест.
|
||||||
</p>
|
</p>
|
||||||
<ScriptKind kind="global" />
|
<ScriptKind kind="global" />
|
||||||
<Code>{`// Допустим, npc — это адрес созданного NPC.
|
<LangTabs
|
||||||
// Вешаем над ним табличку с именем.
|
js={<Code>{`// npc — это адрес созданного NPC.
|
||||||
game.scene.setLabel(npc.ref, 'Торговец Боб', {
|
game.scene.setLabel(npc.ref, 'Торговец Боб', {
|
||||||
color: '#ffffff',
|
color: '#ffffff',
|
||||||
height: 2.5 // на 2.5 метра над объектом
|
height: 2.5 // на 2.5 метра над объектом
|
||||||
});
|
});
|
||||||
|
|
||||||
// Позже можно убрать табличку
|
// Позже можно убрать табличку
|
||||||
game.scene.clearLabel(npc.ref);`}</Code>
|
game.scene.clearLabel(npc.ref);`}</Code>}
|
||||||
|
lua={<Code>{`-- 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()`}</Code>}
|
||||||
|
/>
|
||||||
</>
|
</>
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'pass-through',
|
id: 'pass-through',
|
||||||
title: 'F7. Проходимость объектов (passThrough)',
|
title: 'F7. Проходимость объектов',
|
||||||
body: (
|
body: (
|
||||||
<>
|
<>
|
||||||
<p>
|
<p>
|
||||||
Иногда стена должна стать проходимой — призрачная стена,
|
Иногда стена должна стать проходимой — призрачная стена,
|
||||||
секретный проход, исчезающий мост. Команда
|
секретный проход, исчезающий мост.
|
||||||
<code> game.physics.passThrough(ref, true)</code> делает
|
|
||||||
объект «бесплотным»: видно его, но игрок проходит насквозь.
|
|
||||||
</p>
|
</p>
|
||||||
<ScriptKind kind="object" on="секретную стену" />
|
<ScriptKind kind="object" on="секретную стену" />
|
||||||
<Code>{`// Когда игрок кликнет по стене — она пропустит сквозь себя
|
<LangTabs
|
||||||
game.self.onClick(() => {
|
js={<Code>{`game.self.onClick(() => {
|
||||||
game.physics.passThrough(game.self.ref, true);
|
game.physics.passThrough(game.self.ref, true);
|
||||||
game.scene.setOpacity(game.self.ref, 0.3); // полупрозрачная
|
game.scene.setOpacity(game.self.ref, 0.3); // полупрозрачная
|
||||||
game.ui.showText('Секретный проход открыт!', 2);
|
game.ui.showText('Секретный проход открыт!', 2);
|
||||||
});`}</Code>
|
});`}</Code>}
|
||||||
|
lua={<Code>{`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)`}</Code>}
|
||||||
|
/>
|
||||||
<Note>
|
<Note>
|
||||||
Если сделать стену снова твёрдой, пока игрок стоит внутри
|
Если сделать стену снова твёрдой, пока игрок стоит внутри
|
||||||
неё — игра аккуратно вытолкнет его наружу, он не застрянет.
|
неё — игра аккуратно вытолкнет его наружу, он не застрянет.
|
||||||
@ -2362,39 +2502,53 @@ game.self.onClick(() => {
|
|||||||
<>
|
<>
|
||||||
<p>
|
<p>
|
||||||
<b>Связи (constraints)</b> соединяют объекты, чтобы они
|
<b>Связи (constraints)</b> соединяют объекты, чтобы они
|
||||||
двигались вместе или по правилам физики. Отдел —
|
двигались вместе или по правилам физики.
|
||||||
<code> game.constraints</code>:
|
|
||||||
</p>
|
</p>
|
||||||
<ul>
|
<ul>
|
||||||
<li>
|
<li><b>Склейка (weld)</b> — намертво приклеивает один объект к другому;</li>
|
||||||
<b>Склейка (weld)</b> — намертво приклеивает один
|
<li><b>Петля (hinge)</b> — объект вращается вокруг оси, как дверь или качели;</li>
|
||||||
объект к другому;
|
<li><b>Пружина (spring)</b> — объект упруго колеблется, как батут.</li>
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<b>Петля (hinge)</b> — объект вращается вокруг оси,
|
|
||||||
как дверь на петлях или качели;
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<b>Пружина (spring)</b> — объект упруго колеблется,
|
|
||||||
как батут.
|
|
||||||
</li>
|
|
||||||
</ul>
|
</ul>
|
||||||
<p><b>Пример — качели на петле:</b></p>
|
<p><b>Пример — качели на петле:</b></p>
|
||||||
<ScriptKind kind="global" />
|
<ScriptKind kind="global" />
|
||||||
<Code>{`const swing = game.scene.findOne('Качели');
|
<LangTabs
|
||||||
|
js={<Code>{`const swing = game.scene.findOne('Качели');
|
||||||
|
|
||||||
// делаем качели на петле
|
|
||||||
const h = game.constraints.hinge(swing, {
|
const h = game.constraints.hinge(swing, {
|
||||||
pivotX: 0, pivotZ: 0, // ось вращения
|
pivotX: 0, pivotZ: 0,
|
||||||
angle: 30 // наклон на 30 градусов
|
angle: 30
|
||||||
});
|
});
|
||||||
|
|
||||||
// раскачиваем в другую сторону каждую секунду
|
// раскачиваем в другую сторону каждую секунду
|
||||||
let dir = -30;
|
let dir = -30;
|
||||||
game.every(1, () => {
|
game.every(1, () => {
|
||||||
h.setAngle(dir);
|
h.setAngle(dir);
|
||||||
dir = -dir; // меняем знак: 30 → -30 → 30 ...
|
dir = -dir;
|
||||||
});`}</Code>
|
});`}</Code>}
|
||||||
|
lua={<Code>{`-- В 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`}</Code>}
|
||||||
|
/>
|
||||||
</>
|
</>
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user