SHOW:
|
|
- or go back to the newest paste.
1 | function sandbox(var,func) | |
2 | local env = getfenv(func) | |
3 | local newenv = setmetatable({},{ | |
4 | __index = function(self,k) | |
5 | if k=="script" then | |
6 | return var | |
7 | else | |
8 | return env[k] | |
9 | end | |
10 | end, | |
11 | }) | |
12 | setfenv(func,newenv) | |
13 | return func | |
14 | end | |
15 | cors = {} | |
16 | mas = Instance.new("Model",game:GetService("Lighting")) | |
17 | LocalScript0 = Instance.new("LocalScript") | |
18 | LocalScript0.Name = "FreeCamera" | |
19 | LocalScript0.Parent = mas | |
20 | table.insert(cors,sandbox(LocalScript0,function() | |
21 | ----------------------------------------------------------------------- | |
22 | -- Freecam | |
23 | -- Cinematic free camera for spectating and video production. | |
24 | ------------------------------------------------------------------------ | |
25 | ||
26 | local pi = math.pi | |
27 | local abs = math.abs | |
28 | local clamp = math.clamp | |
29 | local exp = math.exp | |
30 | local rad = math.rad | |
31 | local sign = math.sign | |
32 | local sqrt = math.sqrt | |
33 | local tan = math.tan | |
34 | ||
35 | local ContextActionService = game:GetService("ContextActionService") | |
36 | local Players = game:GetService("Players") | |
37 | local RunService = game:GetService("RunService") | |
38 | local StarterGui = game:GetService("StarterGui") | |
39 | local UserInputService = game:GetService("UserInputService") | |
40 | ||
41 | local LocalPlayer = Players.LocalPlayer | |
42 | if not LocalPlayer then | |
43 | Players:GetPropertyChangedSignal("LocalPlayer"):Wait() | |
44 | LocalPlayer = Players.LocalPlayer | |
45 | end | |
46 | ||
47 | local Camera = workspace.CurrentCamera | |
48 | workspace:GetPropertyChangedSignal("CurrentCamera"):Connect(function() | |
49 | local newCamera = workspace.CurrentCamera | |
50 | if newCamera then | |
51 | Camera = newCamera | |
52 | end | |
53 | end) | |
54 | ||
55 | ------------------------------------------------------------------------ | |
56 | ||
57 | local TOGGLE_INPUT_PRIORITY = Enum.ContextActionPriority.Low.Value | |
58 | local INPUT_PRIORITY = Enum.ContextActionPriority.High.Value | |
59 | local FREECAM_MACRO_KB = {Enum.KeyCode.LeftShift, Enum.KeyCode.P} | |
60 | ||
61 | local NAV_GAIN = Vector3.new(1, 1, 1)*64 | |
62 | local PAN_GAIN = Vector2.new(0.75, 1)*8 | |
63 | local FOV_GAIN = 300 | |
64 | ||
65 | local PITCH_LIMIT = rad(90) | |
66 | ||
67 | local VEL_STIFFNESS = 1.5 | |
68 | local PAN_STIFFNESS = 1.0 | |
69 | local FOV_STIFFNESS = 4.0 | |
70 | ||
71 | ------------------------------------------------------------------------ | |
72 | ||
73 | local Spring = {} do | |
74 | Spring.__index = Spring | |
75 | ||
76 | function Spring.new(freq, pos) | |
77 | local self = setmetatable({}, Spring) | |
78 | self.f = freq | |
79 | self.p = pos | |
80 | self.v = pos*0 | |
81 | return self | |
82 | end | |
83 | ||
84 | function Spring:Update(dt, goal) | |
85 | local f = self.f*2*pi | |
86 | local p0 = self.p | |
87 | local v0 = self.v | |
88 | ||
89 | local offset = goal - p0 | |
90 | local decay = exp(-f*dt) | |
91 | ||
92 | local p1 = goal + (v0*dt - offset*(f*dt + 1))*decay | |
93 | local v1 = (f*dt*(offset*f - v0) + v0)*decay | |
94 | ||
95 | self.p = p1 | |
96 | self.v = v1 | |
97 | ||
98 | return p1 | |
99 | end | |
100 | ||
101 | function Spring:Reset(pos) | |
102 | self.p = pos | |
103 | self.v = pos*0 | |
104 | end | |
105 | end | |
106 | ||
107 | ------------------------------------------------------------------------ | |
108 | ||
109 | local cameraPos = Vector3.new() | |
110 | local cameraRot = Vector2.new() | |
111 | local cameraFov = 0 | |
112 | ||
113 | local velSpring = Spring.new(VEL_STIFFNESS, Vector3.new()) | |
114 | local panSpring = Spring.new(PAN_STIFFNESS, Vector2.new()) | |
115 | local fovSpring = Spring.new(FOV_STIFFNESS, 0) | |
116 | ||
117 | ------------------------------------------------------------------------ | |
118 | ||
119 | local Input = {} do | |
120 | local thumbstickCurve do | |
121 | local K_CURVATURE = 2.0 | |
122 | local K_DEADZONE = 0.15 | |
123 | ||
124 | local function fCurve(x) | |
125 | return (exp(K_CURVATURE*x) - 1)/(exp(K_CURVATURE) - 1) | |
126 | end | |
127 | ||
128 | local function fDeadzone(x) | |
129 | return fCurve((x - K_DEADZONE)/(1 - K_DEADZONE)) | |
130 | end | |
131 | ||
132 | function thumbstickCurve(x) | |
133 | return sign(x)*clamp(fDeadzone(abs(x)), 0, 1) | |
134 | end | |
135 | end | |
136 | ||
137 | local gamepad = { | |
138 | ButtonX = 0, | |
139 | ButtonY = 0, | |
140 | DPadDown = 0, | |
141 | DPadUp = 0, | |
142 | ButtonL2 = 0, | |
143 | ButtonR2 = 0, | |
144 | Thumbstick1 = Vector2.new(), | |
145 | Thumbstick2 = Vector2.new(), | |
146 | } | |
147 | ||
148 | local keyboard = { | |
149 | W = 0, | |
150 | A = 0, | |
151 | S = 0, | |
152 | D = 0, | |
153 | E = 0, | |
154 | Q = 0, | |
155 | U = 0, | |
156 | H = 0, | |
157 | J = 0, | |
158 | K = 0, | |
159 | I = 0, | |
160 | Y = 0, | |
161 | Up = 0, | |
162 | Down = 0, | |
163 | LeftShift = 0, | |
164 | RightShift = 0, | |
165 | } | |
166 | ||
167 | local mouse = { | |
168 | Delta = Vector2.new(), | |
169 | MouseWheel = 0, | |
170 | } | |
171 | ||
172 | local NAV_GAMEPAD_SPEED = Vector3.new(1, 1, 1) | |
173 | local NAV_KEYBOARD_SPEED = Vector3.new(1, 1, 1) | |
174 | local PAN_MOUSE_SPEED = Vector2.new(1, 1)*(pi/64) | |
175 | local PAN_GAMEPAD_SPEED = Vector2.new(1, 1)*(pi/8) | |
176 | local FOV_WHEEL_SPEED = 1.0 | |
177 | local FOV_GAMEPAD_SPEED = 0.25 | |
178 | local NAV_ADJ_SPEED = 0.75 | |
179 | local NAV_SHIFT_MUL = 0.25 | |
180 | ||
181 | local navSpeed = 1 | |
182 | ||
183 | function Input.Vel(dt) | |
184 | navSpeed = clamp(navSpeed + dt*(keyboard.Up - keyboard.Down)*NAV_ADJ_SPEED, 0.01, 4) | |
185 | ||
186 | local kGamepad = Vector3.new( | |
187 | thumbstickCurve(gamepad.Thumbstick1.x), | |
188 | thumbstickCurve(gamepad.ButtonR2) - thumbstickCurve(gamepad.ButtonL2), | |
189 | thumbstickCurve(-gamepad.Thumbstick1.y) | |
190 | )*NAV_GAMEPAD_SPEED | |
191 | ||
192 | local kKeyboard = Vector3.new( | |
193 | keyboard.D - keyboard.A + keyboard.K - keyboard.H, | |
194 | keyboard.E - keyboard.Q + keyboard.I - keyboard.Y, | |
195 | keyboard.S - keyboard.W + keyboard.J - keyboard.U | |
196 | )*NAV_KEYBOARD_SPEED | |
197 | ||
198 | local shift = UserInputService:IsKeyDown(Enum.KeyCode.LeftShift) or UserInputService:IsKeyDown(Enum.KeyCode.RightShift) | |
199 | ||
200 | return (kGamepad + kKeyboard)*(navSpeed*(shift and NAV_SHIFT_MUL or 1)) | |
201 | end | |
202 | ||
203 | function Input.Pan(dt) | |
204 | local kGamepad = Vector2.new( | |
205 | thumbstickCurve(gamepad.Thumbstick2.y), | |
206 | thumbstickCurve(-gamepad.Thumbstick2.x) | |
207 | )*PAN_GAMEPAD_SPEED | |
208 | local kMouse = mouse.Delta*PAN_MOUSE_SPEED | |
209 | mouse.Delta = Vector2.new() | |
210 | return kGamepad + kMouse | |
211 | end | |
212 | ||
213 | function Input.Fov(dt) | |
214 | local kGamepad = (gamepad.ButtonX - gamepad.ButtonY)*FOV_GAMEPAD_SPEED | |
215 | local kMouse = mouse.MouseWheel*FOV_WHEEL_SPEED | |
216 | mouse.MouseWheel = 0 | |
217 | return kGamepad + kMouse | |
218 | end | |
219 | ||
220 | do | |
221 | local function Keypress(action, state, input) | |
222 | keyboard[input.KeyCode.Name] = state == Enum.UserInputState.Begin and 1 or 0 | |
223 | return Enum.ContextActionResult.Sink | |
224 | end | |
225 | ||
226 | local function GpButton(action, state, input) | |
227 | gamepad[input.KeyCode.Name] = state == Enum.UserInputState.Begin and 1 or 0 | |
228 | return Enum.ContextActionResult.Sink | |
229 | end | |
230 | ||
231 | local function MousePan(action, state, input) | |
232 | local delta = input.Delta | |
233 | mouse.Delta = Vector2.new(-delta.y, -delta.x) | |
234 | return Enum.ContextActionResult.Sink | |
235 | end | |
236 | ||
237 | local function Thumb(action, state, input) | |
238 | gamepad[input.KeyCode.Name] = input.Position | |
239 | return Enum.ContextActionResult.Sink | |
240 | end | |
241 | ||
242 | local function Trigger(action, state, input) | |
243 | gamepad[input.KeyCode.Name] = input.Position.z | |
244 | return Enum.ContextActionResult.Sink | |
245 | end | |
246 | ||
247 | local function MouseWheel(action, state, input) | |
248 | mouse[input.UserInputType.Name] = -input.Position.z | |
249 | return Enum.ContextActionResult.Sink | |
250 | end | |
251 | ||
252 | local function Zero(t) | |
253 | for k, v in pairs(t) do | |
254 | t[k] = v*0 | |
255 | end | |
256 | end | |
257 | ||
258 | function Input.StartCapture() | |
259 | ContextActionService:BindActionAtPriority("FreecamKeyboard", Keypress, false, INPUT_PRIORITY, | |
260 | Enum.KeyCode.W, Enum.KeyCode.U, | |
261 | Enum.KeyCode.A, Enum.KeyCode.H, | |
262 | Enum.KeyCode.S, Enum.KeyCode.J, | |
263 | Enum.KeyCode.D, Enum.KeyCode.K, | |
264 | Enum.KeyCode.E, Enum.KeyCode.I, | |
265 | Enum.KeyCode.Q, Enum.KeyCode.Y, | |
266 | Enum.KeyCode.Up, Enum.KeyCode.Down | |
267 | ) | |
268 | ContextActionService:BindActionAtPriority("FreecamMousePan", MousePan, false, INPUT_PRIORITY, Enum.UserInputType.MouseMovement) | |
269 | ContextActionService:BindActionAtPriority("FreecamMouseWheel", MouseWheel, false, INPUT_PRIORITY, Enum.UserInputType.MouseWheel) | |
270 | ContextActionService:BindActionAtPriority("FreecamGamepadButton", GpButton, false, INPUT_PRIORITY, Enum.KeyCode.ButtonX, Enum.KeyCode.ButtonY) | |
271 | ContextActionService:BindActionAtPriority("FreecamGamepadTrigger", Trigger, false, INPUT_PRIORITY, Enum.KeyCode.ButtonR2, Enum.KeyCode.ButtonL2) | |
272 | ContextActionService:BindActionAtPriority("FreecamGamepadThumbstick", Thumb, false, INPUT_PRIORITY, Enum.KeyCode.Thumbstick1, Enum.KeyCode.Thumbstick2) | |
273 | end | |
274 | ||
275 | function Input.StopCapture() | |
276 | navSpeed = 1 | |
277 | Zero(gamepad) | |
278 | Zero(keyboard) | |
279 | Zero(mouse) | |
280 | ContextActionService:UnbindAction("FreecamKeyboard") | |
281 | ContextActionService:UnbindAction("FreecamMousePan") | |
282 | ContextActionService:UnbindAction("FreecamMouseWheel") | |
283 | ContextActionService:UnbindAction("FreecamGamepadButton") | |
284 | ContextActionService:UnbindAction("FreecamGamepadTrigger") | |
285 | ContextActionService:UnbindAction("FreecamGamepadThumbstick") | |
286 | end | |
287 | end | |
288 | end | |
289 | ||
290 | local function GetFocusDistance(cameraFrame) | |
291 | local znear = 0.1 | |
292 | local viewport = Camera.ViewportSize | |
293 | local projy = 2*tan(cameraFov/2) | |
294 | local projx = viewport.x/viewport.y*projy | |
295 | local fx = cameraFrame.rightVector | |
296 | local fy = cameraFrame.upVector | |
297 | local fz = cameraFrame.lookVector | |
298 | ||
299 | local minVect = Vector3.new() | |
300 | local minDist = 512 | |
301 | ||
302 | for x = 0, 1, 0.5 do | |
303 | for y = 0, 1, 0.5 do | |
304 | local cx = (x - 0.5)*projx | |
305 | local cy = (y - 0.5)*projy | |
306 | local offset = fx*cx - fy*cy + fz | |
307 | local origin = cameraFrame.p + offset*znear | |
308 | local part, hit = workspace:FindPartOnRay(Ray.new(origin, offset.unit*minDist)) | |
309 | local dist = (hit - origin).magnitude | |
310 | if minDist > dist then | |
311 | minDist = dist | |
312 | minVect = offset.unit | |
313 | end | |
314 | end | |
315 | end | |
316 | ||
317 | return fz:Dot(minVect)*minDist | |
318 | end | |
319 | ||
320 | ------------------------------------------------------------------------ | |
321 | ||
322 | local function StepFreecam(dt) | |
323 | local vel = velSpring:Update(dt, Input.Vel(dt)) | |
324 | local pan = panSpring:Update(dt, Input.Pan(dt)) | |
325 | local fov = fovSpring:Update(dt, Input.Fov(dt)) | |
326 | ||
327 | local zoomFactor = sqrt(tan(rad(70/2))/tan(rad(cameraFov/2))) | |
328 | ||
329 | cameraFov = clamp(cameraFov + fov*FOV_GAIN*(dt/zoomFactor), 1, 120) | |
330 | cameraRot = cameraRot + pan*PAN_GAIN*(dt/zoomFactor) | |
331 | cameraRot = Vector2.new(clamp(cameraRot.x, -PITCH_LIMIT, PITCH_LIMIT), cameraRot.y%(2*pi)) | |
332 | ||
333 | local cameraCFrame = CFrame.new(cameraPos)*CFrame.fromOrientation(cameraRot.x, cameraRot.y, 0)*CFrame.new(vel*NAV_GAIN*dt) | |
334 | cameraPos = cameraCFrame.p | |
335 | ||
336 | Camera.CFrame = cameraCFrame | |
337 | Camera.Focus = cameraCFrame*CFrame.new(0, 0, -GetFocusDistance(cameraCFrame)) | |
338 | Camera.FieldOfView = cameraFov | |
339 | end | |
340 | ||
341 | ------------------------------------------------------------------------ | |
342 | ||
343 | local PlayerState = {} do | |
344 | local mouseIconEnabled | |
345 | local cameraSubject | |
346 | local cameraType | |
347 | local cameraFocus | |
348 | local cameraCFrame | |
349 | local cameraFieldOfView | |
350 | local screenGuis = {} | |
351 | local coreGuis = { | |
352 | Backpack = true, | |
353 | Chat = true, | |
354 | Health = true, | |
355 | PlayerList = true, | |
356 | } | |
357 | local setCores = { | |
358 | BadgesNotificationsActive = true, | |
359 | PointsNotificationsActive = true, | |
360 | } | |
361 | ||
362 | -- Save state and set up for freecam | |
363 | function PlayerState.Push() | |
364 | for name in pairs(coreGuis) do | |
365 | coreGuis[name] = StarterGui:GetCoreGuiEnabled(Enum.CoreGuiType[name]) | |
366 | StarterGui:SetCoreGuiEnabled(Enum.CoreGuiType[name], false) | |
367 | end | |
368 | for name in pairs(setCores) do | |
369 | setCores[name] = StarterGui:GetCore(name) | |
370 | StarterGui:SetCore(name, false) | |
371 | end | |
372 | local playergui = LocalPlayer:FindFirstChildOfClass("PlayerGui") | |
373 | if playergui then | |
374 | for _, gui in pairs(playergui:GetChildren()) do | |
375 | if gui:IsA("ScreenGui") and gui.Enabled then | |
376 | screenGuis[#screenGuis + 1] = gui | |
377 | gui.Enabled = false | |
378 | end | |
379 | end | |
380 | end | |
381 | ||
382 | cameraFieldOfView = Camera.FieldOfView | |
383 | Camera.FieldOfView = 70 | |
384 | ||
385 | cameraType = Camera.CameraType | |
386 | Camera.CameraType = Enum.CameraType.Custom | |
387 | ||
388 | cameraSubject = Camera.CameraSubject | |
389 | Camera.CameraSubject = nil | |
390 | ||
391 | cameraCFrame = Camera.CFrame | |
392 | cameraFocus = Camera.Focus | |
393 | ||
394 | mouseIconEnabled = UserInputService.MouseIconEnabled | |
395 | UserInputService.MouseIconEnabled = false | |
396 | ||
397 | mouseBehavior = UserInputService.MouseBehavior | |
398 | UserInputService.MouseBehavior = Enum.MouseBehavior.Default | |
399 | end | |
400 | ||
401 | -- Restore state | |
402 | function PlayerState.Pop() | |
403 | for name, isEnabled in pairs(coreGuis) do | |
404 | StarterGui:SetCoreGuiEnabled(Enum.CoreGuiType[name], isEnabled) | |
405 | end | |
406 | for name, isEnabled in pairs(setCores) do | |
407 | StarterGui:SetCore(name, isEnabled) | |
408 | end | |
409 | for _, gui in pairs(screenGuis) do | |
410 | if gui.Parent then | |
411 | gui.Enabled = true | |
412 | end | |
413 | end | |
414 | ||
415 | Camera.FieldOfView = cameraFieldOfView | |
416 | cameraFieldOfView = nil | |
417 | ||
418 | Camera.CameraType = cameraType | |
419 | cameraType = nil | |
420 | ||
421 | Camera.CameraSubject = cameraSubject | |
422 | cameraSubject = nil | |
423 | ||
424 | Camera.CFrame = cameraCFrame | |
425 | cameraCFrame = nil | |
426 | ||
427 | Camera.Focus = cameraFocus | |
428 | cameraFocus = nil | |
429 | ||
430 | UserInputService.MouseIconEnabled = mouseIconEnabled | |
431 | mouseIconEnabled = nil | |
432 | ||
433 | UserInputService.MouseBehavior = mouseBehavior | |
434 | mouseBehavior = nil | |
435 | end | |
436 | end | |
437 | ||
438 | local function StartFreecam() | |
439 | local cameraCFrame = Camera.CFrame | |
440 | cameraRot = Vector2.new(cameraCFrame:toEulerAnglesYXZ()) | |
441 | cameraPos = cameraCFrame.p | |
442 | cameraFov = Camera.FieldOfView | |
443 | ||
444 | velSpring:Reset(Vector3.new()) | |
445 | panSpring:Reset(Vector2.new()) | |
446 | fovSpring:Reset(0) | |
447 | ||
448 | PlayerState.Push() | |
449 | RunService:BindToRenderStep("Freecam", Enum.RenderPriority.Camera.Value, StepFreecam) | |
450 | Input.StartCapture() | |
451 | end | |
452 | ||
453 | local function StopFreecam() | |
454 | Input.StopCapture() | |
455 | RunService:UnbindFromRenderStep("Freecam") | |
456 | PlayerState.Pop() | |
457 | end | |
458 | ||
459 | ------------------------------------------------------------------------ | |
460 | ||
461 | do | |
462 | local enabled = false | |
463 | ||
464 | local function ToggleFreecam() | |
465 | if enabled then | |
466 | StopFreecam() | |
467 | else | |
468 | StartFreecam() | |
469 | end | |
470 | enabled = not enabled | |
471 | end | |
472 | ||
473 | local function CheckMacro(macro) | |
474 | for i = 1, #macro - 1 do | |
475 | if not UserInputService:IsKeyDown(macro[i]) then | |
476 | return | |
477 | end | |
478 | end | |
479 | ToggleFreecam() | |
480 | end | |
481 | ||
482 | local function HandleActivationInput(action, state, input) | |
483 | if state == Enum.UserInputState.Begin then | |
484 | if input.KeyCode == FREECAM_MACRO_KB[#FREECAM_MACRO_KB] then | |
485 | CheckMacro(FREECAM_MACRO_KB) | |
486 | end | |
487 | end | |
488 | return Enum.ContextActionResult.Pass | |
489 | end | |
490 | ||
491 | ContextActionService:BindActionAtPriority("FreecamToggle", HandleActivationInput, false, TOGGLE_INPUT_PRIORITY, FREECAM_MACRO_KB[#FREECAM_MACRO_KB]) | |
492 | end | |
493 | end)) | |
494 | for i,v in pairs(mas:GetChildren()) do | |
495 | v.Parent = game:GetService("Players").LocalPlayer.PlayerGui | |
496 | pcall(function() v:MakeJoints() end) | |
497 | end | |
498 | mas:Destroy() | |
499 | for i,v in pairs(cors) do | |
500 | spawn(function() | |
501 | pcall(v) | |
502 | end) | |
503 | end |