-- [[ THE ULTIMATE SONIC FORCES 2D EXECUTOR ]] -- local player = game.Players.LocalPlayer local char = player.Character or player.CharacterAdded:Wait() local hum = char:WaitForChild("Humanoid") local hrp = char:WaitForChild("HumanoidRootPart") local CAS = game:GetService("ContextActionService") local RunService = game:GetService("RunService") local TweenService = game:GetService("TweenService") -- 1. SPRITE ASSET DATABASE local spr_Idle = "rbxassetid://75176076420443" local walkFrames = { "rbxassetid://119600556121484", "rbxassetid://97873710759940", "rbxassetid://103217887050572", "rbxassetid://82366656282716", "rbxassetid://139942244949799" } local jumpFrames = { "rbxassetid://124591296933974", "rbxassetid://99646550819635", "rbxassetid://140172695086692", "rbxassetid://114509472621074", "rbxassetid://111459083295979" } -- 2. THE MORPH (Hide Robloxian, Show Sonic) for _, v in pairs(char:GetChildren()) do if v:IsA("BasePart") then v.Transparency = 1 end if v:IsA("Accessory") then v.Handle.Transparency = 1 end end local bb = Instance.new("BillboardGui", hrp) bb.Name = "SonicBillboard" bb.Size = UDim2.new(4.5, 0, 4.5, 0) bb.Adornee = hrp bb.ExtentsOffset = Vector3.new(0, 0.6, 0) local img = Instance.new("ImageLabel", bb) img.Size = UDim2.new(1, 0, 1, 0) img.BackgroundTransparency = 1 img.ScaleType = Enum.ScaleType.Fit img.Image = spr_Idle -- 3. PHYSICS & STATE VARS local currentSpeed = 16 local maxWalkSpeed = 135 local boostSpeed = 260 local accel = 0.5 local isBoosting = false local animTimer = 0 -- 4. HOMING ATTACK LOGIC (NPC TARGETING) local function getTarget() local closest, dist = nil, 60 for _, v in pairs(workspace:GetDescendants()) do if v:IsA("Humanoid") and v.Parent ~= char and v.RootPart then local mag = (hrp.Position - v.RootPart.Position).Magnitude if mag 0 local airborne = hum:GetState() == Enum.HumanoidStateType.Jumping or hum:GetState() == Enum.HumanoidStateType.Freefall -- Speed Logic if moving then currentSpeed = math.min(currentSpeed + accel, isBoosting and boostSpeed or maxWalkSpeed) hum.WalkSpeed = currentSpeed else currentSpeed = 16; hum.WalkSpeed = 16 end -- Sprite Swapping if airborne then animTimer = animTimer + (dt * 30) img.Image = jumpFrames[(math.floor(animTimer) % #jumpFrames) + 1] elseif moving then animTimer = animTimer + (dt * (currentSpeed / (isBoosting and 10 or 7))) img.Image = walkFrames[(math.floor(animTimer) % #walkFrames) + 1] img.Rotation = math.clamp(currentSpeed / 6.5, 0, 15) -- Lean else animTimer = 0; img.Image = spr_Idle; img.Rotation = 0 end -- Boost Visuals img.ImageColor3 = isBoosting and Color3.fromRGB(160, 210, 255) or Color3.new(1, 1, 1) end)