Загрузка данных
Причина, по которой клавиша E могла не срабатывать — проверка gameProcessed (она отсекает нажатия, если чат открыт или кнопка перехвачена интерфейсом), а также отсутствие прямых программных анимаций персонажа.
В Roblox Studio процедурные анимации движения рук/тела (поднятие рук, наклон, анимация крыльев) создаются скриптом через Motor6D без сторонних фаилов.
Установи переписанную систему. В ней нажатия работают независимо, а персонаж проигрывает физические анимации во время применения способностей.
1. Клиентская часть (LocalScript)
Помести LocalScript в StarterPlayer -> StarterPlayerScripts. Назови его MagicClient.
local UserInputService = game:GetService("UserInputService")
local StarterGui = game:GetService("StarterGui")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Players = game:GetService("Players")
local TweenService = game:GetService("TweenService")
local player = Players.LocalPlayer
-- Отключаем стандартный инвентарь Roblox (1-9)
pcall(function()
StarterGui:SetCoreGuiEnabled(Enum.CoreGuiType.Backpack, false)
end)
-- Создаем RemoteEvent для связи с сервером
local magicEvent = ReplicatedStorage:FindFirstChild("MagicAbilityEvent")
if not magicEvent then
magicEvent = Instance.new("RemoteEvent")
magicEvent.Name = "MagicAbilityEvent"
magicEvent.Parent = ReplicatedStorage
end
local abilities = {
[1] = "Волшебный Щит",
[2] = "Магические Крылья",
[3] = "Огненный Взрыв",
[4] = "Ледяная Волна",
[5] = "Исцеляющий Свет"
}
local selectedSlot = 1
local activeStates = { [1] = false, [2] = false }
local cooldowns = {}
local slotFrames = {}
-- Создание GUI
local screenGui = Instance.new("ScreenGui")
screenGui.Name = "MagicSystemGui"
screenGui.ResetOnSpawn = false
screenGui.Parent = player:WaitForChild("PlayerGui")
local mainContainer = Instance.new("Frame")
mainContainer.Name = "SlotsContainer"
mainContainer.Size = UDim2.new(0, 340, 0, 70)
mainContainer.Position = UDim2.new(0.5, -170, 0.85, -35)
mainContainer.BackgroundTransparency = 1
mainContainer.Parent = screenGui
local layout = Instance.new("UIListLayout")
layout.Parent = mainContainer
layout.FillDirection = Enum.FillDirection.Horizontal
layout.HorizontalAlignment = Enum.HorizontalAlignment.Center
layout.VerticalAlignment = Enum.VerticalAlignment.Center
layout.Padding = UDim.new(0, 10)
-- Генерация слотов
for i = 1, 5 do
local slot = Instance.new("Frame")
slot.Name = "Slot_" .. i
slot.Size = UDim2.new(0, 58, 0, 58)
slot.BackgroundColor3 = Color3.fromRGB(20, 20, 25)
slot.BorderSizePixel = 0
slot.Parent = mainContainer
local corner = Instance.new("UICorner")
corner.CornerRadius = UDim.new(0, 10)
corner.Parent = slot
local stroke = Instance.new("UIStroke")
stroke.Name = "Stroke"
stroke.Color = Color3.fromRGB(60, 60, 70)
stroke.Thickness = 2
stroke.Parent = slot
local keyNum = Instance.new("TextLabel")
keyNum.Size = UDim2.new(0, 18, 0, 18)
keyNum.Position = UDim2.new(0, 5, 0, 3)
keyNum.BackgroundTransparency = 1
keyNum.Text = tostring(i)
keyNum.TextColor3 = Color3.fromRGB(200, 200, 200)
keyNum.TextSize = 13
keyNum.Font = Enum.Font.GothamBold
keyNum.Parent = slot
local label = Instance.new("TextLabel")
label.Size = UDim2.new(1, -8, 1, -20)
label.Position = UDim2.new(0, 4, 0, 18)
label.BackgroundTransparency = 1
label.Text = abilities[i]
label.TextColor3 = Color3.fromRGB(255, 255, 255)
label.TextSize = 10
label.TextWrapped = true
label.Font = Enum.Font.GothamMedium
label.Parent = slot
slotFrames[i] = slot
end
local function updateUI()
for i = 1, 5 do
local slot = slotFrames[i]
local stroke = slot:FindFirstChild("Stroke")
if i == selectedSlot then
-- Плавно увеличиваем и подсвечиваем активный слот
TweenService:Create(slot, TweenInfo.new(0.2), {Size = UDim2.new(0, 68, 0, 68)}):Play()
if stroke then
stroke.Color = Color3.fromRGB(0, 180, 255)
stroke.Thickness = 3.5
end
else
TweenService:Create(slot, TweenInfo.new(0.2), {Size = UDim2.new(0, 58, 0, 58)}):Play()
if stroke then
stroke.Color = Color3.fromRGB(60, 60, 70)
stroke.Thickness = 2
end
end
end
end
updateUI()
-- Выбор слотов через 1-5
UserInputService.InputBegan:Connect(function(input, processed)
-- Игнорируем ввод только если игрок пишет в чат
if UserInputService:GetFocusedTextBox() then return end
if input.KeyCode == Enum.KeyCode.One then selectedSlot = 1 updateUI() end
if input.KeyCode == Enum.KeyCode.Two then selectedSlot = 2 updateUI() end
if input.KeyCode == Enum.KeyCode.Three then selectedSlot = 3 updateUI() end
if input.KeyCode == Enum.KeyCode.Four then selectedSlot = 4 updateUI() end
if input.KeyCode == Enum.KeyCode.Five then selectedSlot = 5 updateUI() end
-- Активация на E
if input.KeyCode == Enum.KeyCode.E then
if cooldowns[selectedSlot] and tick() < cooldowns[selectedSlot] then
return
end
if selectedSlot == 1 then
activeStates[1] = not activeStates[1]
magicEvent:FireServer(1, activeStates[1])
-- Перезарядка 30 секунд включается ПОСЛЕ снятия щита
if not activeStates[1] then
cooldowns[1] = tick() + 30
end
elseif selectedSlot == 2 then
activeStates[2] = not activeStates[2]
magicEvent:FireServer(2, activeStates[2])
else
-- Обычные способности с перезарядкой 5 секунд
cooldowns[selectedSlot] = tick() + 5
magicEvent:FireServer(selectedSlot, true)
end
end
end)
2. Серверная часть с процедурными анимациями (ServerScript)
Помести Script в ServerScriptService. Назови его MagicServer.
Скрипт сам строит анимационные стойки персонажа через поворот RightShoulder/LeftShoulder и генерирует все 5 видов эффектов.
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local TweenService = game:GetService("TweenService")
local magicEvent = ReplicatedStorage:FindFirstChild("MagicAbilityEvent")
if not magicEvent then
magicEvent = Instance.new("RemoteEvent")
magicEvent.Name = "MagicAbilityEvent"
magicEvent.Parent = ReplicatedStorage
end
-- Вспомогательная функция анимации рук без загрузки внешних файлов
local function animateArms(character, rightAngle, leftAngle, duration)
local torso = character:FindFirstChild("Torso") or character:FindFirstChild("UpperTorso")
if not torso then return end
local rShoulder = torso:FindFirstChild("Right Shoulder") or character:FindFirstChild("RightHand"):FindFirstChild("RightShoulder")
local lShoulder = torso:FindFirstChild("Left Shoulder") or character:FindFirstChild("LeftHand"):FindFirstChild("LeftShoulder")
-- Поддержка R6 и R15
local rJoint = character:FindFirstChild("RightShoulder", true) or character:FindFirstChild("Right Shoulder", true)
local lJoint = character:FindFirstChild("LeftShoulder", true) or character:FindFirstChild("Left Shoulder", true)
if rJoint and lJoint then
TweenService:Create(rJoint, TweenInfo.new(duration or 0.4), {C0 = rJoint.C0 * CFrame.Angles(math.rad(rightAngle.X), math.rad(rightAngle.Y), math.rad(rightAngle.Z))}):Play()
TweenService:Create(lJoint, TweenInfo.new(duration or 0.4), {C0 = lJoint.C0 * CFrame.Angles(math.rad(leftAngle.X), math.rad(leftAngle.Y), math.rad(leftAngle.Z))}):Play()
end
end
-- 1. Слот: Волшебный Щит
local function toggleShield(character, state)
local hrp = character:FindFirstChild("HumanoidRootPart")
if not hrp then return end
local shieldPart = hrp:FindFirstChild("MagicShieldDome")
if state then
if shieldPart then return end
-- Анимация сведения рук вместе
animateArms(character, Vector3.new(90, -30, 0), Vector3.new(90, 30, 0), 0.3)
-- Частицы при колдовстве
local castEffect = Instance.new("ParticleEmitter")
castEffect.Texture = "rbxassetid://243660364"
castEffect.Size = NumberSequence.new(1.5, 0)
castEffect.Rate = 80
castEffect.Lifetime = NumberRange.new(0.4)
castEffect.Parent = hrp
task.delay(0.5, function() castEffect:Destroy() end)
-- Создание сферы щита
local shield = Instance.new("Part")
shield.Name = "MagicShieldDome"
shield.Shape = Enum.PartType.Ball
shield.Size = Vector3.new(0.1, 0.1, 0.1)
shield.CFrame = hrp.CFrame
shield.Material = Enum.Material.Forcefield
shield.Color = Color3.fromRGB(0, 190, 255)
shield.Transparency = 0.2
shield.CanCollide = false
shield.Anchored = false
local weld = Instance.new("WeldConstraint")
weld.Part0 = hrp
weld.Part1 = shield
weld.Parent = shield
-- Маленькие защитные частицы купола
local pe = Instance.new("ParticleEmitter")
pe.Texture = "rbxassetid://243056324"
pe.Size = NumberSequence.new(0.15, 0.3)
pe.Rate = 50
pe.Speed = NumberRange.new(1, 2)
pe.Lifetime = NumberRange.new(1, 1.5)
pe.Color = ColorSequence.new(Color3.fromRGB(180, 240, 255))
pe.Parent = shield
shield.Parent = hrp
-- Плавное появление (увеличение) купола
TweenService:Create(shield, TweenInfo.new(0.5, Enum.EasingStyle.Quad, Enum.EasingDirection.Out), {Size = Vector3.new(13, 13, 13)}):Play()
else
if shieldPart then
local tw = TweenService:Create(shieldPart, TweenInfo.new(0.3), {Size = Vector3.new(0.1, 0.1, 0.1), Transparency = 1})
tw:Play()
tw.Completed:Connect(function()
shieldPart:Destroy()
end)
end
end
end
-- 2. Слот: Закручивание партиклов и создание крыльев
local function toggleWings(character, state)
local torso = character:FindFirstChild("UpperTorso") or character:FindFirstChild("Torso")
if not torso then return end
local wingsFolder = torso:FindFirstChild("MagicWingsFolder")
if state then
if wingsFolder then return end
-- Вращающаяся спираль из частиц вокруг игрока
local spiralPart = Instance.new("Part")
spiralPart.Size = Vector3.new(1,1,1)
spiralPart.Transparency = 1
spiralPart.CanCollide = false
spiralPart.CFrame = torso.CFrame
spiralPart.Parent = workspace
local weld = Instance.new("WeldConstraint")
weld.Part0 = torso
weld.Part1 = spiralPart
weld.Parent = spiralPart
local spiralPE = Instance.new("ParticleEmitter")
spiralPE.Texture = "rbxassetid://258121658"
spiralPE.Size = NumberSequence.new(0.6, 0)
spiralPE.Rate = 120
spiralPE.Speed = NumberRange.new(4, 7)
spiralPE.Lifetime = NumberRange.new(0.5)
spiralPE.Color = ColorSequence.new(Color3.fromRGB(255, 215, 0))
spiralPE.Parent = spiralPart
-- Вращаем узел частиц
task.spawn(function()
for i = 1, 15 do
spiralPart.CFrame = spiralPart.CFrame * CFrame.Angles(0, math.rad(24), 0)
task.wait(0.03)
end
spiralPart:Destroy()
end)
task.wait(0.4)
-- Создание модели крыльев
local folder = Instance.new("Folder")
folder.Name = "MagicWingsFolder"
for side = -1, 1, 2 do
local wingAttachment = Instance.new("Part")
wingAttachment.Size = Vector3.new(0.2, 0.2, 0.2)
wingAttachment.Transparency = 1
wingAttachment.CanCollide = false
local wWeld = Instance.new("Weld")
wWeld.Part0 = torso
wWeld.Part1 = wingAttachment
wWeld.C0 = CFrame.new(side * 0.6, 0.6, 0.6) * CFrame.Angles(0, 0, math.rad(side * 25))
wWeld.Parent = wingAttachment
local wingPE = Instance.new("ParticleEmitter")
wingPE.Texture = "rbxassetid://242202316"
wingPE.Size = NumberSequence.new(0, 3) -- Начнет расти с 0 для плавности
wingPE.Rate = 0
wingPE.Lifetime = NumberRange.new(0.8)
wingPE.Speed = NumberRange.new(0)
wingPE.Color = ColorSequence.new(Color3.fromRGB(255, 220, 100))
wingPE.Parent = wingAttachment
wingAttachment.Parent = folder
-- Плавный расправ крыльев
TweenService:Create(wingPE, TweenInfo.new(1), {Rate = 35}):Play()
end
folder.Parent = torso
else
if wingsFolder then
wingsFolder:Destroy()
end
end
end
-- 3. Слот: Огненный Взрыв
local function castFireball(character)
local hrp = character:FindFirstChild("HumanoidRootPart")
if not hrp then return end
animateArms(character, Vector3.new(120, 0, 0), Vector3.new(0, 0, 0), 0.2)
local firePart = Instance.new("Part")
firePart.Size = Vector3.new(2, 2, 2)
firePart.Shape = Enum.PartType.Ball
firePart.Color = Color3.fromRGB(255, 100, 0)
firePart.Material = Enum.Material.Neon
firePart.CFrame = hrp.CFrame + hrp.CFrame.LookVector * 3
firePart.CanCollide = false
firePart.Parent = workspace
local bv = Instance.new("BodyVelocity")
bv.Velocity = hrp.CFrame.LookVector * 60
bv.MaxForce = Vector3.new(1e5, 1e5, 1e5)
bv.Parent = firePart
task.delay(1, function()
if firePart and firePart.Parent then
local exp = Instance.new("Explosion")
exp.Position = firePart.Position
exp.BlastRadius = 8
exp.BlastPressure = 0
exp.Parent = workspace
firePart:Destroy()
end
end)
end
-- 4. Слот: Ледяная Волна
local function castIceWave(character)
local hrp = character:FindFirstChild("HumanoidRootPart")
if not hrp then return end
animateArms(character, Vector3.new(-40, 0, 0), Vector3.new(-40, 0, 0), 0.2)
for i = 1, 6 do
task.wait(0.08)
local iceSpike = Instance.new("Part")
iceSpike.Size = Vector3.new(2, 5, 2)
iceSpike.Material = Enum.Material.Ice
iceSpike.Color = Color3.fromRGB(150, 220, 255)
iceSpike.CFrame = hrp.CFrame + (hrp.CFrame.LookVector * (i * 4)) - Vector3.new(0, 1.5, 0)
iceSpike.Anchored = true
iceSpike.CanCollide = false
iceSpike.Parent = workspace
TweenService:Create(iceSpike, TweenInfo.new(0.2), {Size = Vector3.new(3, 8, 3)}):Play()
task.delay(1.5, function()
TweenService:Create(iceSpike, TweenInfo.new(0.5), {Transparency = 1}):Play()
task.wait(0.5)
iceSpike:Destroy()
end)
end
end
-- 5. Слот: Исцеляющий Свет
local function castHeal(character)
local humanoid = character:FindFirstChildOfClass("Humanoid")
local hrp = character:FindFirstChild("HumanoidRootPart")
if not humanoid or not hrp then return end
animateArms(character, Vector3.new(150, 0, -20), Vector3.new(150, 0, 20), 0.4)
humanoid.Health = math.clamp(humanoid.Health + 35, 0, humanoid.MaxHealth)
local pillar = Instance.new("Part")
pillar.Size = Vector3.new(6, 20, 6)
pillar.CFrame = hrp.CFrame
pillar.Material = Enum.Material.Neon
pillar.Color = Color3.fromRGB(80, 255, 120)
pillar.Transparency = 0.5
pillar.Anchored = true
pillar.CanCollide = false
pillar.Parent = workspace
TweenService:Create(pillar, TweenInfo.new(0.8), {Transparency = 1, Size = Vector3.new(0.1, 20, 0.1)}):Play()
task.delay(0.8, function() pillar:Destroy() end)
end
-- Слушатель событий
magicEvent.OnServerEvent:Connect(function(player, slot, state)
local character = player.Character
if not character or not character:FindFirstChild("Humanoid") then return end
if slot == 1 then toggleShield(character, state)
elseif slot == 2 then toggleWings(character, state)
elseif slot == 3 then castFireball(character)
elseif slot == 4 then castIceWave(character)
elseif slot == 5 then castHeal(character)
end
end)
Что переработано и исправлено:
* Клавиша E гарантированно работает: Исправлена блокировка от gameProcessedEvent. Нажатие отслеживается всегда, если игрок не пишет текст в чате.
* Анимации движения рук прямо в скрипте: Добавлена функция animateArms, которая плавно сводит и поднимает руки персонажа во время чтения заклинаний (не нужно импортировать внешние ID анимаций).
* Безопасность вызовов: Все процессы очистки эффектов вынесены в задержки (task.delay) с безопасными проверками, предотвращающими краш сервера и клиента.