Hello, everybody!
Recently, I ran into this one bug, well, rather several ones. I was trying to turn a server-sided AI into a client-sided AI, so I just did the first thing that came to my head, just make all the scripts local-sided, there shouldn’t be anything Server-specific in them, but well. It didn’t work, the NPC doesn’t even bother moving. I’ve checked whether is anything anchored and if I copied all the Values and stuff, I did. So here I am, asking for help on the DevForum. Thanks in advance.
Are you viewing it from the server or from the client?
The client, of course. It doesn’t do anything in either of them.
Can you please provide your code so we can have a look at it? You may have missed something that needed to be modified in moving from server to local
Of course, here:
The AI script (movement and stuff, credits go to the respective owner):
--@ItsBasicallyDenis 2022 (contact me on Discord (Benis#0800) or on Twitter (@basicallyrbx) if you experience any issues!)
--This is a very customizable & easy-to-use pathfinding script, can be used for anything that follows players around!
-------- NOTE: If you changed any of the "IMPORTANT SETTINGS" and want to reset all to default, set resetSettingsToDefault to true!
----- Please don't change any parts of the code unless you know what you're doing!
-- DO NOT COPY THIS SCRIPT AND USE IT AS YOUR OWN!
--[[ Update log V1.01:
- Added stopNearPlayer, moveIfNoPath, waitBeforeStart, requiresSight and createWaypointParts settings;
- Significantly optimised the script by cleaning up threads & more;
- Bug fixes.
]]
local t = tick()
local pathFindingService = game:GetService("PathfindingService")
-- Set-up variables (change them to your custom needs!):
local maxDistance = 1000 -- Max distance that the NPC looks for targets in, if maxDistance is 150 and a player is 151 studs away, it will not target it!
local npc = script.Parent
local hum = npc:WaitForChild("Humanoid")
local hrp = npc:WaitForChild("HumanoidRootPart")
-----------------
-- Character Variables:
local Health = 100 -- default is 100
local WalkSpeed = 12 -- default is 16
local JumpPower = 0 -- default is 50
-----------------
-- IMPORTANT SETTINGS!
local printNotifications = true -- Set to true if you want this script to print when the NPC moves, jumps, etc. (useful for debugging!)
-----------------
local stopNearPlayer = false -- Stops if closer than 3 studs of the target (might stun the NPC for a few seconds when changing directions fast!)
-----------------
local createWaypointParts = true -- Creates a semi-transparent green part for every waypoint (parts are destroyed after 2.5 seconds!)
-----------------
local requiresSight = true -- In order for the NPC to go towards the target, it needs to see it first (also automatically reduces maxDistance!)
-----------------
local moveIfNoPath = true -- Set to true to move 15 studs away if path.Status is not Success (might break movement if npc can't get to target!)
-----------------
local moveToWait = false -- Set to false if you don't want to wait for the MoveTo function to finish everytime (smoother npc movement but broken pathfinding!)
-----------------
local waitBeforeStart = false -- Wait 5-10 seconds before starting the AI (might prevent some start lag!)
-----------------
local resetSettingsToDefault = false -- Set to true to reset all settings to default once the NPC starts!
-----------------
-- Boring part:
-------------------------------------------------------------------------------------
local function CanSeeTarget(target)
local ray = Ray.new(hrp.Position,(target.HumanoidRootPart.Position - hrp.Position).unit * 100) -- create the ray
local hit,pos = workspace:FindPartOnRay(ray,npc) -- find parts that the ray hit
if hit then -- if the ray hit a part then
if hit:IsDescendantOf(target) then -- if the part is part of the target's character then
return true -- return true
end
end
return false -- if no target was found, return false
end
local function FindTarget()
local target
local maxDis = maxDistance
if game.Players.LocalPlayer.Character then
local distance = (hrp.Position - game.Players.LocalPlayer.Character.HumanoidRootPart.Position).Magnitude -- check the distance between npc and player
if requiresSight then
if distance <= maxDis and CanSeeTarget(game.Players.LocalPlayer.Character) then
target = game.Players.LocalPlayer.Character
maxDis = distance
if script.Parent.State.Value ~= "Chasing" then
script.Parent.State.Value = "Chasing"
end
end
else
if distance <= maxDis then -- if the distance is less than the maxDistance variable then
target = game.Players.LocalPlayer.Character -- target acquired
maxDis = distance -- set the new maxDis to the current distance, so if a player is closer than this one, we choose him instead
end
end
return target -- return the target
end
end
if resetSettingsToDefault then
printNotifications = false
stopNearPlayer = false
requiresSight = false
moveToWait = true
createWaypointParts = false
moveIfNoPath = false
waitBeforeStart = false
end
-----------------
hum.UseJumpPower = true
hum.JumpPower = JumpPower
hum.WalkSpeed = WalkSpeed
hum.MaxHealth = Health
hum.Health = Health
npc.PrimaryPart = hrp
-----------------
if waitBeforeStart then task.wait(math.random(5,10)) end
local oldPath
task.spawn(function() -- start the function
while task.wait(.1) do -- every .1 seconds do
local target = FindTarget() -- find the target
if target then -- if there is a target, proceed with following it
if target:FindFirstChild("HumanoidRootPart") then target = target.HumanoidRootPart end
if printNotifications then print("Found target: "..target.Parent.Name) end
local path = pathFindingService:CreatePath() -- create a new path
path:ComputeAsync(hrp.Position,target.Position) -- compute the best path from the NPC to the TARGET
if oldPath then -- if there's an old path, we destroy it and we replace it with the new one
if path ~= oldPath then
oldPath:Destroy()
oldPath = path
if printNotifications then print("Destroyed old path and replaced it with a new one!") end
end
else
oldPath = path -- if this is the first ever path, we set the old path to the current one
end
local waypoints = path:GetWaypoints() -- we get the path's waypoints
local cor
if path and waypoints then -- if we have waypoints then
if path.Status == Enum.PathStatus.Success then -- if the path is a success then
for i, waypoint in pairs(waypoints) do -- loop through the waypoints
cor = coroutine.resume(coroutine.create(function() -- create a seperate thread for each waypoint
-----------------
if createWaypointParts then -- if createWaypointParts is set to true, then we create a part for each waypoint!
local part = Instance.new("Part")
part.Anchored = true
part.CanCollide = false
part.Color = Color3.fromRGB(119, 255, 8)
part.Transparency = .75
part.Position = waypoint.Position
part.Parent = workspace
task.delay(2.5,function()
part:Destroy()
end)
end
-----------------
if waypoint.Action == Enum.PathWaypointAction.Jump then -- if the waypoint requires the NPC to jump
if printNotifications then print("Jumped!") end
hum.Jump = true -- jump
end
if waypoint.Action == Enum.PathWaypointAction.Walk then -- if the waypoint requires the NPC to walk
hum:ChangeState(Enum.HumanoidStateType.Running) -- walk
end
if printNotifications then print("Walking to "..tostring(waypoint.Position).."!") end
if (hrp.Position - target.Position).Magnitude <= 3 and stopNearPlayer then -- if stopNearPlayer is on, then stop the NPC
hum:MoveTo(hrp.Position)
if moveToWait then hum.MoveToFinished:Wait() end
cor = nil -- clean up the thread
else -- else, move the NPC normally towards the target
hum:MoveTo(waypoint.Position)
if moveToWait then hum.MoveToFinished:Wait() end
cor = nil -- clean up the thread
end
end))
end
else -- if path was not a success, and moveIfNoPath is set to true, then we move the NPC 15 studs away
if moveIfNoPath then
if printNotifications then print("Path was not succsessful, moving 15 studs away!") end
hum:MoveTo(target.Position - (hrp.CFrame.LookVector * 15))
end
end
end
else
script.Parent.State.Value = "Idle"
end
end
end)
if printNotifications then print("Benis' Pathfinding AI script has successfully loaded in "..tostring(tick() - t).." seconds!") end
Animate, also doesn’t work, unfortunately:
local Character = script.Parent
local Humanoid = Character:WaitForChild("Humanoid")
local pose = "Standing"
local currentAnim = ""
local currentAnimInstance = nil
local currentAnimTrack = nil
local currentAnimKeyframeHandler = nil
local currentAnimSpeed = 1.0
local runAnimTrack = nil
local runAnimKeyframeHandler = nil
local animTable = {}
local animNames = {
idle = {
{ id = "http://www.roblox.com/asset/?id=507766666", weight = 1 },
{ id = "http://www.roblox.com/asset/?id=507766951", weight = 1 },
{ id = "http://www.roblox.com/asset/?id=507766388", weight = 9 }
},
walk = {
{ id = "http://www.roblox.com/asset/?id=507777826", weight = 10 }
},
run = {
{ id = "http://www.roblox.com/asset/?id=507767714", weight = 10 }
},
swim = {
{ id = "http://www.roblox.com/asset/?id=507784897", weight = 10 }
},
swimidle = {
{ id = "http://www.roblox.com/asset/?id=507785072", weight = 10 }
},
jump = {
{ id = "http://www.roblox.com/asset/?id=507765000", weight = 10 }
},
fall = {
{ id = "http://www.roblox.com/asset/?id=507767968", weight = 10 }
},
climb = {
{ id = "http://www.roblox.com/asset/?id=507765644", weight = 10 }
},
sit = {
{ id = "http://www.roblox.com/asset/?id=507768133", weight = 10 }
},
toolnone = {
{ id = "http://www.roblox.com/asset/?id=507768375", weight = 10 }
},
toolslash = {
{ id = "http://www.roblox.com/asset/?id=522635514", weight = 10 }
},
toollunge = {
{ id = "http://www.roblox.com/asset/?id=522638767", weight = 10 }
},
wave = {
{ id = "http://www.roblox.com/asset/?id=507770239", weight = 10 }
},
point = {
{ id = "http://www.roblox.com/asset/?id=507770453", weight = 10 }
},
dance = {
{ id = "http://www.roblox.com/asset/?id=507771019", weight = 10 },
{ id = "http://www.roblox.com/asset/?id=507771955", weight = 10 },
{ id = "http://www.roblox.com/asset/?id=507772104", weight = 10 }
},
dance2 = {
{ id = "http://www.roblox.com/asset/?id=507776043", weight = 10 },
{ id = "http://www.roblox.com/asset/?id=507776720", weight = 10 },
{ id = "http://www.roblox.com/asset/?id=507776879", weight = 10 }
},
dance3 = {
{ id = "http://www.roblox.com/asset/?id=507777268", weight = 10 },
{ id = "http://www.roblox.com/asset/?id=507777451", weight = 10 },
{ id = "http://www.roblox.com/asset/?id=507777623", weight = 10 }
},
laugh = {
{ id = "http://www.roblox.com/asset/?id=507770818", weight = 10 }
},
cheer = {
{ id = "http://www.roblox.com/asset/?id=507770677", weight = 10 }
},
}
-- Existance in this list signifies that it is an emote, the value indicates if it is a looping emote
local emoteNames = { wave = false, point = false, dance = true, dance2 = true, dance3 = true, laugh = false, cheer = false}
math.randomseed(tick())
function configureAnimationSet(name, fileList)
if (animTable[name] ~= nil) then
for _, connection in pairs(animTable[name].connections) do
connection:disconnect()
end
end
animTable[name] = {}
animTable[name].count = 0
animTable[name].totalWeight = 0
animTable[name].connections = {}
local allowCustomAnimations = true
local AllowDisableCustomAnimsUserFlag = false
local success, msg = pcall(function()
AllowDisableCustomAnimsUserFlag = UserSettings():IsUserFeatureEnabled("UserAllowDisableCustomAnims2")
end)
if (AllowDisableCustomAnimsUserFlag) then
local success, msg = pcall(function() allowCustomAnimations = game:GetService("StarterPlayer").AllowCustomAnimations end)
if not success then
allowCustomAnimations = true
end
end
-- check for config values
local config = script:FindFirstChild(name)
if (allowCustomAnimations and config ~= nil) then
table.insert(animTable[name].connections, config.ChildAdded:connect(function(child) configureAnimationSet(name, fileList) end))
table.insert(animTable[name].connections, config.ChildRemoved:connect(function(child) configureAnimationSet(name, fileList) end))
local idx = 1
for _, childPart in pairs(config:GetChildren()) do
if (childPart:IsA("Animation")) then
table.insert(animTable[name].connections, childPart.Changed:connect(function(property) configureAnimationSet(name, fileList) end))
animTable[name][idx] = {}
animTable[name][idx].anim = childPart
local weightObject = childPart:FindFirstChild("Weight")
if (weightObject == nil) then
animTable[name][idx].weight = 1
else
animTable[name][idx].weight = weightObject.Value
end
animTable[name].count = animTable[name].count + 1
animTable[name].totalWeight = animTable[name].totalWeight + animTable[name][idx].weight
idx = idx + 1
end
end
end
-- fallback to defaults
if (animTable[name].count <= 0) then
for idx, anim in pairs(fileList) do
animTable[name][idx] = {}
animTable[name][idx].anim = Instance.new("Animation")
animTable[name][idx].anim.Name = name
animTable[name][idx].anim.AnimationId = anim.id
animTable[name][idx].weight = anim.weight
animTable[name].count = animTable[name].count + 1
animTable[name].totalWeight = animTable[name].totalWeight + anim.weight
-- print(name .. " [" .. idx .. "] " .. anim.id .. " (" .. anim.weight .. ")")
end
end
end
-- Setup animation objects
function scriptChildModified(child)
local fileList = animNames[child.Name]
if (fileList ~= nil) then
configureAnimationSet(child.Name, fileList)
end
end
script.ChildAdded:connect(scriptChildModified)
script.ChildRemoved:connect(scriptChildModified)
for name, fileList in pairs(animNames) do
configureAnimationSet(name, fileList)
end
-- ANIMATION
-- declarations
local toolAnim = "None"
local toolAnimTime = 0
local jumpAnimTime = 0
local jumpAnimDuration = 0.31
local toolTransitionTime = 0.1
local fallTransitionTime = 0.2
-- functions
function stopAllAnimations()
local oldAnim = currentAnim
-- return to idle if finishing an emote
if (emoteNames[oldAnim] ~= nil and emoteNames[oldAnim] == false) then
oldAnim = "idle"
end
currentAnim = ""
currentAnimInstance = nil
if (currentAnimKeyframeHandler ~= nil) then
currentAnimKeyframeHandler:disconnect()
end
if (currentAnimTrack ~= nil) then
currentAnimTrack:Stop()
currentAnimTrack:Destroy()
currentAnimTrack = nil
end
-- clean up walk if there is one
if (runAnimKeyframeHandler ~= nil) then
runAnimKeyframeHandler:disconnect()
end
if (runAnimTrack ~= nil) then
runAnimTrack:Stop()
runAnimTrack:Destroy()
runAnimTrack = nil
end
return oldAnim
end
function getHeightScale()
if Humanoid then
local bodyHeightScale = Humanoid:FindFirstChild("BodyHeightScale")
if bodyHeightScale and bodyHeightScale:IsA("NumberValue") then
return bodyHeightScale.Value
end
end
return 1
end
local smallButNotZero = 0.0001
function setRunSpeed(speed)
if speed < 0.33 then
currentAnimTrack:AdjustWeight(1.0)
runAnimTrack:AdjustWeight(smallButNotZero)
elseif speed < 0.66 then
local weight = ((speed - 0.33) / 0.33)
currentAnimTrack:AdjustWeight(1.0 - weight + smallButNotZero)
runAnimTrack:AdjustWeight(weight + smallButNotZero)
else
currentAnimTrack:AdjustWeight(smallButNotZero)
runAnimTrack:AdjustWeight(1.0)
end
local speedScaled = speed * 1.25
local heightScale = getHeightScale()
runAnimTrack:AdjustSpeed(speedScaled / heightScale)
currentAnimTrack:AdjustSpeed(speedScaled / heightScale)
end
function setAnimationSpeed(speed)
if speed ~= currentAnimSpeed then
currentAnimSpeed = speed
if currentAnim == "walk" then
setRunSpeed(speed)
else
currentAnimTrack:AdjustSpeed(currentAnimSpeed)
end
end
end
function keyFrameReachedFunc(frameName)
if (frameName == "End") then
if currentAnim == "walk" then
runAnimTrack.TimePosition = 0.0
currentAnimTrack.TimePosition = 0.0
else
local repeatAnim = currentAnim
-- return to idle if finishing an emote
if (emoteNames[repeatAnim] ~= nil and emoteNames[repeatAnim] == false) then
repeatAnim = "idle"
end
local animSpeed = currentAnimSpeed
playAnimation(repeatAnim, 0.15, Humanoid)
setAnimationSpeed(animSpeed)
end
end
end
function rollAnimation(animName)
local roll = math.random(1, animTable[animName].totalWeight)
local origRoll = roll
local idx = 1
while (roll > animTable[animName][idx].weight) do
roll = roll - animTable[animName][idx].weight
idx = idx + 1
end
return idx
end
function playAnimation(animName, transitionTime, humanoid)
local idx = rollAnimation(animName)
local anim = animTable[animName][idx].anim
-- switch animation
if (anim ~= currentAnimInstance) then
if (currentAnimTrack ~= nil) then
currentAnimTrack:Stop(transitionTime)
currentAnimTrack:Destroy()
end
if (runAnimTrack ~= nil) then
runAnimTrack:Stop(transitionTime)
runAnimTrack:Destroy()
end
currentAnimSpeed = 1.0
-- load it to the humanoid; get AnimationTrack
currentAnimTrack = humanoid:LoadAnimation(anim)
currentAnimTrack.Priority = Enum.AnimationPriority.Core
-- play the animation
currentAnimTrack:Play(transitionTime)
currentAnim = animName
currentAnimInstance = anim
-- set up keyframe name triggers
if (currentAnimKeyframeHandler ~= nil) then
currentAnimKeyframeHandler:disconnect()
end
currentAnimKeyframeHandler = currentAnimTrack.KeyframeReached:connect(keyFrameReachedFunc)
-- check to see if we need to blend a walk/run animation
if animName == "walk" then
local runAnimName = "run"
local runIdx = rollAnimation(runAnimName)
runAnimTrack = humanoid:LoadAnimation(animTable[runAnimName][runIdx].anim)
runAnimTrack.Priority = Enum.AnimationPriority.Core
runAnimTrack:Play(transitionTime)
if (runAnimKeyframeHandler ~= nil) then
runAnimKeyframeHandler:disconnect()
end
runAnimKeyframeHandler = runAnimTrack.KeyframeReached:connect(keyFrameReachedFunc)
end
end
end
-------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------
local toolAnimName = ""
local toolAnimTrack = nil
local toolAnimInstance = nil
local currentToolAnimKeyframeHandler = nil
function toolKeyFrameReachedFunc(frameName)
if (frameName == "End") then
playToolAnimation(toolAnimName, 0.0, Humanoid)
end
end
function playToolAnimation(animName, transitionTime, humanoid, priority)
local idx = rollAnimation(animName)
local anim = animTable[animName][idx].anim
if (toolAnimInstance ~= anim) then
if (toolAnimTrack ~= nil) then
toolAnimTrack:Stop()
toolAnimTrack:Destroy()
transitionTime = 0
end
-- load it to the humanoid; get AnimationTrack
toolAnimTrack = humanoid:LoadAnimation(anim)
if priority then
toolAnimTrack.Priority = priority
end
-- play the animation
toolAnimTrack:Play(transitionTime)
toolAnimName = animName
toolAnimInstance = anim
currentToolAnimKeyframeHandler = toolAnimTrack.KeyframeReached:connect(toolKeyFrameReachedFunc)
end
end
function stopToolAnimations()
local oldAnim = toolAnimName
if (currentToolAnimKeyframeHandler ~= nil) then
currentToolAnimKeyframeHandler:disconnect()
end
toolAnimName = ""
toolAnimInstance = nil
if (toolAnimTrack ~= nil) then
toolAnimTrack:Stop()
toolAnimTrack:Destroy()
toolAnimTrack = nil
end
return oldAnim
end
-------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------
-- STATE CHANGE HANDLERS
function onRunning(speed)
if speed > 0.5 then
local scale = 16.0
playAnimation("walk", 0.2, Humanoid)
setAnimationSpeed(speed / scale)
pose = "Running"
else
if emoteNames[currentAnim] == nil then
playAnimation("idle", 0.2, Humanoid)
pose = "Standing"
end
end
end
function onDied()
pose = "Dead"
end
function onJumping()
playAnimation("jump", 0.1, Humanoid)
jumpAnimTime = jumpAnimDuration
pose = "Jumping"
end
function onClimbing(speed)
local scale = 5.0
playAnimation("climb", 0.1, Humanoid)
setAnimationSpeed(speed / scale)
pose = "Climbing"
end
function onGettingUp()
pose = "GettingUp"
end
function onFreeFall()
if (jumpAnimTime <= 0) then
playAnimation("fall", fallTransitionTime, Humanoid)
end
pose = "FreeFall"
end
function onFallingDown()
pose = "FallingDown"
end
function onSeated()
pose = "Seated"
end
function onPlatformStanding()
pose = "PlatformStanding"
end
-------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------
function onSwimming(speed)
if speed > 1.00 then
local scale = 10.0
playAnimation("swim", 0.4, Humanoid)
setAnimationSpeed(speed / scale)
pose = "Swimming"
else
playAnimation("swimidle", 0.4, Humanoid)
pose = "Standing"
end
end
function animateTool()
if (toolAnim == "None") then
playToolAnimation("toolnone", toolTransitionTime, Humanoid, Enum.AnimationPriority.Idle)
return
end
if (toolAnim == "Slash") then
playToolAnimation("toolslash", 0, Humanoid, Enum.AnimationPriority.Action)
return
end
if (toolAnim == "Lunge") then
playToolAnimation("toollunge", 0, Humanoid, Enum.AnimationPriority.Action)
return
end
end
function getToolAnim(tool)
for _, c in ipairs(tool:GetChildren()) do
if c.Name == "toolanim" and c.className == "StringValue" then
return c
end
end
return nil
end
local lastTick = 0
function stepAnimate(currentTime)
local amplitude = 1
local frequency = 1
local deltaTime = currentTime - lastTick
lastTick = currentTime
local climbFudge = 0
local setAngles = false
if (jumpAnimTime > 0) then
jumpAnimTime = jumpAnimTime - deltaTime
end
if (pose == "FreeFall" and jumpAnimTime <= 0) then
playAnimation("fall", fallTransitionTime, Humanoid)
elseif (pose == "Seated") then
playAnimation("sit", 0.5, Humanoid)
return
elseif (pose == "Running") then
playAnimation("walk", 0.2, Humanoid)
elseif (pose == "Dead" or pose == "GettingUp" or pose == "FallingDown" or pose == "Seated" or pose == "PlatformStanding") then
stopAllAnimations()
amplitude = 0.1
frequency = 1
setAngles = true
end
-- Tool Animation handling
local tool = Character:FindFirstChildOfClass("Tool")
local requireHandleCheck = not UserSettings():IsUserFeatureEnabled("UserToolR15Fix")
if tool and ((requireHandleCheck and tool.RequiresHandle) or tool:FindFirstChild("Handle")) then
local animStringValueObject = getToolAnim(tool)
if animStringValueObject then
toolAnim = animStringValueObject.Value
-- message recieved, delete StringValue
animStringValueObject.Parent = nil
toolAnimTime = currentTime + .3
end
if currentTime > toolAnimTime then
toolAnimTime = 0
toolAnim = "None"
end
animateTool()
else
stopToolAnimations()
toolAnim = "None"
toolAnimInstance = nil
toolAnimTime = 0
end
end
-- connect events
Humanoid.Died:connect(onDied)
Humanoid.Running:connect(onRunning)
Humanoid.Jumping:connect(onJumping)
Humanoid.Climbing:connect(onClimbing)
Humanoid.GettingUp:connect(onGettingUp)
Humanoid.FreeFalling:connect(onFreeFall)
Humanoid.FallingDown:connect(onFallingDown)
Humanoid.Seated:connect(onSeated)
Humanoid.PlatformStanding:connect(onPlatformStanding)
Humanoid.Swimming:connect(onSwimming)
-- initialize to idle
playAnimation("idle", 0.1, Humanoid)
pose = "Standing"
-- loop to handle timed state transitions and tool animations
while Character.Parent ~= nil do
local _, currentGameTime = wait(0.1)
stepAnimate(currentGameTime)
end
The State Controller:
local TS = game:GetService("TweenService")
local Shaker = require(game.ReplicatedStorage.CameraShaker)
local ChaseOn = TS:Create(script.Parent.Head.Chase, TweenInfo.new(2, Enum.EasingStyle.Quad), {Volume = .5})
local ChaseOff = TS:Create(script.Parent.Head.Chase, TweenInfo.new(2, Enum.EasingStyle.Quad), {Volume = 0})
local ZoomOut = TS:Create(workspace.Camera, TweenInfo.new(1, Enum.EasingStyle.Quad), {FieldOfView = 90})
local ZoomIn = TS:Create(workspace.Camera, TweenInfo.new(1, Enum.EasingStyle.Quad), {FieldOfView = 70})
local camShake = Shaker.new(Enum.RenderPriority.Camera.Value, function(shakeCFrame)
workspace.CurrentCamera.CFrame = workspace.CurrentCamera.CFrame * shakeCFrame
end)
script.Parent.State.Changed:Connect(function(state)
if state == "Chasing" then
script.Parent.Head.Scream:Play()
camShake:Shake(camShake.Presets.Explosion)
TS:Create(game.Lighting.Blur, TweenInfo.new(.05), {Size = 30}):Play()
ZoomOut:Play()
ChaseOn:Play()
wait(.6)
TS:Create(game.Lighting.Blur, TweenInfo.new(5, Enum.EasingStyle.Sine), {Size = 0}):Play()
end
if state == "Idle" then
print("a")
ZoomOut:Cancel()
ZoomIn:Play()
ChaseOn:Cancel()
ChaseOff:Play()
end
end)
while true do
wait(math.random(10,20))
local number = math.random(1,2)
script.Parent.Head["Help"..number]:Play()
end
1 Like