Інструменти – це простий спосіб керування предметами, які гравець може тримати в руці та використовувати в грі. Вони можуть варіюватися від зброї, наприклад мечів, до продуктів харчування.
У цьому підручнику ви дізнаєтеся, як створити інструмент у формі лазерного бластера.

Вставте інструмент у робочу область і назвіть його Blaster .

Вставте MeshPart в інструмент.

Установіть для властивості MeshId значення rbxassetid://92656610 .
Встановіть для властивості TextureId значення rbxassetid://92658105 .


Змініть назву MeshPart на Handle .

Якщо ви не перейменуєте інструмент в «Handle», він впаде на землю, коли гравець спробує її спорядити.
Інструменти можна зберігати в ігровому світі як колекційні інструменти або роздавати всім гравцям як початкові інструменти .
Під час гри інструменти зберігаються в ієрархії гравця в рюкзаку, а потім переміщуються до моделі персонажа, коли вони є. Будь-який інструмент, який стане дочірнім персонажем, буде автоматично оснащений.

Вставте LocalScript в інструмент і назвіть його ToolController .

Створіть ModuleScript під назвою LaserRenderer , наділений StarterPlayerScripts у StarterPlayer.

Відкрийте скрипт і перейменуйте на ім'я сценарію LaserRenderer, добавте наступний код:
Клієнти можуть використовувати RemoteEvent , щоб повідомити серверу, що персонажа вдарили. Вони повинні зберігатися в ReplicatedStorage , де вони видимі як для клієнта, так і для сервера.
Створіть папку в ReplicatedStorage під назвою Events .

Вставте RemoteEvent у папку Events і назвіть його DamageCharacter .

Клієнт повинен повідомити серверу, що він випустив лазер, і надати кінцеву позицію.
Вставте RemoteEvent у папку Events у ReplicatedStorage та назвіть її LaserFired .


У цьому підручнику ви дізнаєтеся, як створити інструмент у формі лазерного бластера.

Створення інструменту
Об’єкт Tool є основою будь-якого інструменту в Roblox, тому вам потрібно його створити. Простіше змінити вигляд інструментів, додавши такі об’єкти, як Parts і MeshParts, до інструменту в робочій області, де вони видимі.Вставте інструмент у робочу область і назвіть його Blaster .

Вставте MeshPart в інструмент.

Установіть для властивості MeshId значення rbxassetid://92656610 .
Встановіть для властивості TextureId значення rbxassetid://92658105 .


Змініть назву MeshPart на Handle .

Якщо ви не перейменуєте інструмент в «Handle», він впаде на землю, коли гравець спробує її спорядити.
Інструменти можна зберігати в ігровому світі як колекційні інструменти або роздавати всім гравцям як початкові інструменти .
Колекційний інструмент
Наразі бластер є дочірнім для Workspace , тому його можна буде колекціонувати. Гравець може підняти інструмент, торкнувшись його, в результаті чого він стане дочірнім елементом моделі персонажа; інструмент буде оснащено та розміщено на їхній гарячій панелі.Під час гри інструменти зберігаються в ієрархії гравця в рюкзаку, а потім переміщуються до моделі персонажа, коли вони є. Будь-який інструмент, який стане дочірнім персонажем, буде автоматично оснащений.

Tripmine без спорядження


Tripmine оснащений
Перемістіть Blaster у StarterPack у Провіднику.

Грайте в гру, щоб перевірити інструмент. Натисніть на гарячу панель унизу екрана або натисніть 1 на клавіатурі, щоб оснастити інструмент.
Положення та орієнтацію інструмента можна змінити за допомогою властивостей ручки . GripPos змінює положення ручки, тоді як GripForward , GripRight і GripUp впливають на обертання.
Зараз гравець тримає центр бластера замість рукоятки.
Встановіть для властивості GripPos інструмента значення 0, -0.4, 1.1 .

Натисніть кнопку «Відтворити» , щоб перевірити інструмент. Зверніть увагу, як інструмент тепер захоплюється в іншому положенні.

Початковий інструмент
Зберігання інструменту в StarterPack помістить його в рюкзак гравця, коли він приєднається до гри або відродиться.Перемістіть Blaster у StarterPack у Провіднику.

Грайте в гру, щоб перевірити інструмент. Натисніть на гарячу панель унизу екрана або натисніть 1 на клавіатурі, щоб оснастити інструмент.
Положення та орієнтацію інструмента можна змінити за допомогою властивостей ручки . GripPos змінює положення ручки, тоді як GripForward , GripRight і GripUp впливають на обертання.
Зараз гравець тримає центр бластера замість рукоятки.
Встановіть для властивості GripPos інструмента значення 0, -0.4, 1.1 .

Натисніть кнопку «Відтворити» , щоб перевірити інструмент. Зверніть увагу, як інструмент тепер захоплюється в іншому положенні.

Раніше


Після

Піктограма гарячої панелі
За замовчуванням назва інструмента буде відображатися на піктограмі гарячої панелі. Рекомендується змінити піктограму на зображення інструмента. Установіть для властивості TextureId інструмента значення rbxassetid://92628145 .
Раніше


Після
Спливаюча підказка — це невеликий текстовий опис, який з’являється, коли миша наводиться на інструмент на гарячій панелі. Зазвичай вони містять назву інструменту та/або короткий опис його функції. Змініть властивість ToolTip на Blaster .

Спливаюча підказка — це невеликий текстовий опис, який з’являється, коли миша наводиться на інструмент на гарячій панелі. Зазвичай вони містять назву інструменту та/або короткий опис його функції. Змініть властивість ToolTip на Blaster .

Додавання коду
Наведений нижче приклад коду відтворює звук «Одягання» , коли інструмент споряджено, і звук «Вогонь» , коли він активований.Вставте LocalScript в інструмент і назвіть його ToolController .

Вставте наступні рядки коду в сценарій:
local UserInputService = game:GetService("UserInputService")
local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local LaserRenderer = require(Players.LocalPlayer.PlayerScripts.LaserRenderer)
local tool = script.Parent
local eventsFolder = ReplicatedStorage.Events
local MAX_MOUSE_DISTANCE = 1000
local MAX_LASER_DISTANCE = 500
local FIRE_RATE = 0.3
local timeOfPreviousShot = 0
-- Check if enough time has passed since previous shot was fired
local function canShootWeapon()
local currentTime = tick()
if currentTime - timeOfPreviousShot < FIRE_RATE then
return false
end
return true
end
local function getWorldMousePosition()
local mouseLocation = UserInputService:GetMouseLocation()
-- Create a ray from the 2D mouse location
local screenToWorldRay = workspace.CurrentCamera:ViewportPointToRay(mouseLocation.X, mouseLocation.Y)
-- The unit direction vector of the ray multiplied by a maximum distance
local directionVector = screenToWorldRay.Direction * MAX_MOUSE_DISTANCE
-- Raycast from the roy's origin towards its direction
local raycastResult = workspace:Raycast(screenToWorldRay.Origin, directionVector)
if raycastResult then
-- Return the 3D point of intersection
return raycastResult.Position
else
-- No object was hit so calculate the position at the end of the ray
return screenToWorldRay.Origin + directionVector
end
end
local function fireWeapon()
local mouseLocation = getWorldMousePosition()
-- Calculate a normalised direction vector and multiply by laser distance
local targetDirection = (mouseLocation - tool.Handle.Position).Unit
-- The direction to fire the weapon, multiplied by a maximum distance
local directionVector = targetDirection * MAX_LASER_DISTANCE
-- Ignore the player's character to prevent them from damaging themselves
local weaponRaycastParams = RaycastParams.new()
weaponRaycastParams.FilterDescendantsInstances = {Players.LocalPlayer.Character}
local weaponRaycastResult = workspace:Raycast(tool.Handle.Position, directionVector, weaponRaycastParams)
-- Check if any objects were hit between the start and end position
local hitPosition
if weaponRaycastResult then
hitPosition = weaponRaycastResult.Position
-- The instance hit will be a child of a character model
-- If a humanoid is found in the model then it's likely a player's character
local characterModel = weaponRaycastResult.Instance:FindFirstAncestorOfClass("Model")
if characterModel then
local humanoid = characterModel:FindFirstChildWhichIsA("Humanoid")
if humanoid then
eventsFolder.DamageCharacter:FireServer(characterModel, hitPosition)
end
end
else
-- Calculate the end position based on maximum laser distance
hitPosition = tool.Handle.Position + directionVector
end
timeOfPreviousShot = tick()
eventsFolder.LaserFired:FireServer(hitPosition)
LaserRenderer.createLaser(tool.Handle, hitPosition)
end
local function toolEquipped()
tool.Handle.Equip:Play()
end
local function toolActivated()
if canShootWeapon() then
fireWeapon()
end
end
tool.Equipped:Connect(toolEquipped)
tool.Activated:Connect(toolActivated)
Пошук позиції лазера
Бластер повинен випустити в ціль червоний промінь світла. Функція для цього буде всередині ModuleScript , тому її можна буде повторно використовувати в інших сценаріях пізніше. По-перше, сценарій повинен буде знайти позицію, куди має відобразитися лазерний промінь.Створіть ModuleScript під назвою LaserRenderer , наділений StarterPlayerScripts у StarterPlayer.

Відкрийте скрипт і перейменуйте на ім'я сценарію LaserRenderer, добавте наступний код:
local LaserRenderer = {}
local Debris = game:GetService("Debris")
local SHOT_DURATION = 0.15 -- Time that the laser is visible for
-- Create a laser beam from a start position towards an end position
function LaserRenderer.createLaser(toolHandle, endPosition)
local startPosition = toolHandle.Position
local laserDistance = (startPosition - endPosition).Magnitude
local laserCFrame = CFrame.lookAt(startPosition, endPosition) * CFrame.new(0, 0, -laserDistance / 2)
local laserPart = Instance.new("Part")
laserPart.Size = Vector3.new(0.2, 0.2, laserDistance)
laserPart.CFrame = laserCFrame
laserPart.Anchored = true
laserPart.CanCollide = false
laserPart.Color = Color3.fromRGB(255, 0, 0)
laserPart.Material = Enum.Material.Neon
laserPart.Parent = workspace
-- Add laser beam to the Debris service to be removed & cleaned up
Debris:AddItem(laserPart, SHOT_DURATION)
-- Play the weapon's shooting sound
local shootingSound = toolHandle:FindFirstChild("Activate")
if shootingSound then
shootingSound:Play()
end
end
return LaserRenderer
Пошкодження гравця
Клієнти не можуть завдати шкоди іншим клієнтам безпосередньо; сервер повинен нести відповідальність за завдання шкоди, коли гравець отримує удар.Клієнти можуть використовувати RemoteEvent , щоб повідомити серверу, що персонажа вдарили. Вони повинні зберігатися в ReplicatedStorage , де вони видимі як для клієнта, так і для сервера.
Створіть папку в ReplicatedStorage під назвою Events .

Вставте RemoteEvent у папку Events і назвіть його DamageCharacter .

Клієнт повинен повідомити серверу, що він випустив лазер, і надати кінцеву позицію.
Вставте RemoteEvent у папку Events у ReplicatedStorage та назвіть її LaserFired .

Сервер
Сервер тепер має отримати подію, яку запустив клієнт, і повідомити всім клієнтам початкове та кінцеве положення лазерного променя, щоб вони також могли його відобразити.Сервер повинен завдати шкоди гравцеві, який отримав удар, коли відбувається подія.
Вставте сценарій у ServerScriptService і назвіть його ServerLaserManager .

Створіть LocalScript у StarterPlayerScript під назвою ClientLaserManager .

local Players = game:GetService("Players")
Вставте сценарій у ServerScriptService і назвіть його ServerLaserManager .

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local eventsFolder = ReplicatedStorage.Events
local LASER_DAMAGE = 10
local MAX_HIT_PROXIMITY = 10
-- Find the handle of the tool the player is holding
local function getPlayerToolHandle(player)
local weapon = player.Character:FindFirstChildOfClass("Tool")
if weapon then
return weapon:FindFirstChild("Handle")
end
end
local function isHitValid(playerFired, characterToDamage, hitPosition)
-- Validate distance between the character hit and the hit position
local characterHitProximity = (characterToDamage.HumanoidRootPart.Position - hitPosition).Magnitude
if characterHitProximity > MAX_HIT_PROXIMITY then
return false
end
-- Check if shooting through walls
local toolHandle = getPlayerToolHandle(playerFired)
if toolHandle then
local rayLength = (hitPosition - toolHandle.Position).Magnitude
local rayDirection = (hitPosition - toolHandle.Position).Unit
local raycastParams = RaycastParams.new()
raycastParams.FilterDescendantsInstances = {playerFired.Character}
local rayResult = workspace:Raycast(toolHandle.Position, rayDirection * rayLength, raycastParams)
-- If an instance was hit that was not the character then ignore the shot
if rayResult and not rayResult.Instance:IsDescendantOf(characterToDamage) then
return false
end
end
return true
end
-- Notify all clients that a laser has been fired so they can display the laser
local function playerFiredLaser(playerFired, endPosition)
local toolHandle = getPlayerToolHandle(playerFired)
if toolHandle then
eventsFolder.LaserFired:FireAllClients(playerFired, toolHandle, endPosition)
end
end
function damageCharacter(playerFired, characterToDamage, hitPosition)
local humanoid = characterToDamage:FindFirstChildWhichIsA("Humanoid")
local validShot = isHitValid(playerFired, characterToDamage, hitPosition)
if humanoid and validShot then
-- Remove health from character
humanoid.Health -= LASER_DAMAGE
end
end
-- Connect events to appropriate functions
eventsFolder.DamageCharacter.OnServerEvent:Connect(damageCharacter)
eventsFolder.LaserFired.OnServerEvent:Connect(playerFiredLaser)
Рендеринг на клієнтах
Тепер FireAllClients викликано, кожен клієнт отримає подію від сервера для відтворення лазерного променя. Кожен клієнт може повторно використовувати попередній модуль LaserRenderer для візуалізації лазерного променя за допомогою позиції маркера інструменту та значення кінцевої позиції, надісланого сервером. Гравець, який першим випустив лазерний промінь, повинен ігнорувати цю подію, інакше він побачить 2 лазери.Створіть LocalScript у StarterPlayerScript під назвою ClientLaserManager .

local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local LaserRenderer = require(Players.LocalPlayer.PlayerScripts:WaitForChild("LaserRenderer"))
local eventsFolder = ReplicatedStorage.Events
-- Display another player's laser
local function createPlayerLaser(playerWhoShot, toolHandle, endPosition)
if playerWhoShot ~= Players.LocalPlayer then
LaserRenderer.createLaser(toolHandle, endPosition)
end
end
eventsFolder.LaserFired.OnClientEvent:Connect(createPlayerLaser)
Всередині сценарію потрібен модуль LaserRenderer:

local LaserRenderer = {}
local Debris = game:GetService("Debris")
local SHOT_DURATION = 0.15 -- Time that the laser is visible for
-- Create a laser beam from a start position towards an end position
function LaserRenderer.createLaser(toolHandle, endPosition)
local startPosition = toolHandle.Position
local laserDistance = (startPosition - endPosition).Magnitude
local laserCFrame = CFrame.lookAt(startPosition, endPosition) * CFrame.new(0, 0, -laserDistance / 2)
local laserPart = Instance.new("Part")
laserPart.Size = Vector3.new(0.2, 0.2, laserDistance)
laserPart.CFrame = laserCFrame
laserPart.Anchored = true
laserPart.CanCollide = false
laserPart.Color = Color3.fromRGB(255, 0, 0)
laserPart.Material = Enum.Material.Neon
laserPart.Parent = workspace
-- Add laser beam to the Debris service to be removed & cleaned up
Debris:AddItem(laserPart, SHOT_DURATION)
-- Play the weapon's shooting sound
local shootingSound = toolHandle:FindFirstChild("Activate")
if shootingSound then
shootingSound:Play()
end
end
return LaserRenderer