Advertisement
SpacecowboyHX

camera but it can be modified (with tilt)

Nov 19th, 2022 (edited)
99
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 10.97 KB | None | 0 0
  1. --script by boxrum
  2.  
  3. local service = {
  4. uis = game:GetService("UserInputService"),
  5. players = game:GetService("Players"),
  6. userSettings = UserSettings():GetService("UserGameSettings"),
  7. run = game:GetService("RunService"),
  8. tween = game:GetService("TweenService")
  9. }
  10.  
  11. local dynamic = {
  12. cameraData = {
  13. rotation = Vector2.new(0,0),
  14. zoom = 20,
  15. smoothZoom = 0,
  16. currentTilt = 0,
  17. rightClicking = false,
  18. shiftLock = false,
  19. raycast = {
  20. currentCollide = nil,
  21. clipZoom = 0
  22. }
  23. }
  24. }
  25.  
  26. local settings = {
  27. mode = "r6",--will auto set
  28. minZoom = 0,
  29. maxZoom = 2000,
  30. zoomSmoothing = 0.75,-- 0-1
  31. tilt = {
  32. strength = 0.2,
  33. drift = 0.9, -- 0-1
  34. turnTilt = 2--degrees
  35. },
  36. maxAngle = 89,
  37. minAngle = -89,
  38. zoomTransparencyStart = 3,
  39. wallClip = false--camera collisions
  40. }
  41.  
  42. local funcs = {--utility stuff
  43. solveBasedOnMode = function(list)
  44. return list[settings.mode]
  45. end,
  46. getCamera = function()
  47. local camera = workspace.CurrentCamera
  48. if not camera then
  49. camera = Instance.new("Camera")
  50. camera.Parent = workspace
  51. workspace.CurrentCamera = camera
  52. end
  53.  
  54. return camera
  55. end,
  56. lerp = function(a,b,t)
  57. return a*(1-t)+b*t
  58. end,
  59. getSubjectCFrame = function(subject)
  60. local isHumanoid = subject:IsA("Humanoid")
  61. if not isHumanoid then
  62. return CFrame.new(subject.Position)
  63. end
  64.  
  65. local rootPart = subject.RootPart
  66. if not rootPart then
  67. warn("Humanoid has no root part")
  68. return CFrame.new(0,0,0)
  69. end
  70.  
  71. local cframe = CFrame.new(rootPart.Position+subject.CameraOffset)
  72. return cframe
  73. end,
  74. setCharacterTransparency = function(character,transparency)
  75. local all = character:GetDescendants()
  76. for _,v in pairs(all) do
  77. if not v:IsA("BasePart") then
  78. continue
  79. end
  80.  
  81. local goal = transparency-v.Transparency
  82.  
  83. v.LocalTransparencyModifier = goal
  84. end
  85. end,
  86. getFilterList = function(filter)
  87. local list = workspace:GetDescendants()
  88. local newList = {}
  89.  
  90. for i,obj in pairs(list) do
  91. if not filter(obj) then
  92. continue
  93. end
  94.  
  95. table.insert(newList,obj)
  96. end
  97.  
  98. return newList
  99. end,
  100. }
  101.  
  102. local characterData = {
  103. bodyParts = {},
  104. }
  105.  
  106. local player = service.players.LocalPlayer
  107.  
  108. function dynamic.cameraData:GetCharacterTransparencyGoal()--long ass function name
  109. local zoom = self.smoothZoom
  110.  
  111. local amnt = math.clamp(-zoom/settings.zoomTransparencyStart + 1,0,1)
  112.  
  113. local squared = 1-(1-amnt)^2
  114. return squared
  115. end
  116.  
  117. function dynamic.cameraData:getRaycastZoom(origin, dest, exclude)
  118.  
  119. local function filterObject(obj)
  120.  
  121. local checks = {
  122. table.find(exclude,obj),
  123. obj:IsA("BasePart") and obj.Transparency+obj.LocalTransparencyModifier>=1,
  124. obj:IsA("BasePart") and obj.CanCollide == false,
  125. player.Character and obj:IsDescendantOf(player.Character)
  126. }
  127.  
  128. for _,v in pairs(checks) do
  129. if not v then
  130. continue
  131. end
  132.  
  133. return true
  134. end
  135.  
  136. return false
  137. end
  138.  
  139. local filterList = funcs.getFilterList(filterObject)
  140.  
  141. local zoom = self.smoothZoom
  142.  
  143. local params = RaycastParams.new()
  144. params.FilterDescendantsInstances = filterList
  145.  
  146. local info = workspace:Raycast(origin, dest-origin, params)
  147. if not info then
  148.  
  149. self.raycast.currentCollide = nil
  150.  
  151. return zoom
  152. end
  153. --warn(filterList)
  154.  
  155. --warn(info.Instance)
  156.  
  157. local cameraMoving = service.uis:GetMouseDelta().Magnitude>0--mouse delta moving
  158. if (cameraMoving and self.raycast.currentCollide ~= info.Instance) or not settings.wallClip then
  159.  
  160. return zoom--camera is still moving and has hit a new part (return existing zoom instead of colliding), prevents flickering when moving camera fast
  161. end
  162.  
  163. self.raycast.currentCollide = info.Instance
  164.  
  165. local hitPoint = info.Position
  166. local distance = (origin-hitPoint).Magnitude
  167.  
  168. local newZoom = distance
  169.  
  170. return newZoom
  171. end
  172.  
  173. local function getCharacterParts(player)
  174.  
  175. local character = player.Character or player.CharacterAdded:Wait()
  176.  
  177. local humanoid = character:FindFirstChildOfClass("Humanoid") or character:WaitForChild("Humanoid")
  178.  
  179. settings.mode = humanoid.RigType.Name
  180.  
  181. local torso = funcs.solveBasedOnMode({
  182. R15 = character:FindFirstChild("UpperTorso"),
  183. R6 = character:FindFirstChild("Torso")
  184. })
  185.  
  186. local head = character:WaitForChild("Head")
  187.  
  188. return character,torso,head,humanoid--this is tilt im doing
  189. end
  190.  
  191. function characterData:SetHumanoidProperty(property,value)
  192. local humanoid = self.bodyParts[4]
  193. if not humanoid then
  194. warn("Humanoid not found; cant set properties")
  195. end
  196.  
  197. humanoid[property] = value
  198. end
  199. function characterData:GetHumanoidValue(property)
  200. local humanoid = self.bodyParts[4]
  201. if not humanoid then
  202. warn("Humanoid not found; cant get properties")
  203. end
  204.  
  205. return humanoid[property]
  206. end
  207.  
  208. function dynamic.cameraData:BuildCFrame(Z)--z is the tilt basically
  209.  
  210. local function buildRaw(zoom)
  211. local frame = CFrame.Angles(0,-self.rotation.X,0)*CFrame.Angles(-self.rotation.Y,0,0)*CFrame.new(0,0,zoom)*CFrame.Angles(0,0,math.rad(Z))
  212.  
  213. return frame
  214. end
  215. local subject = funcs.getCamera().CameraSubject
  216. local origin = subject and funcs.getSubjectCFrame(subject) or CFrame.new(0,0,0)
  217. local dest = origin.Position + buildRaw(self.smoothZoom).Position
  218.  
  219. local newZoom = dynamic.cameraData:getRaycastZoom(origin.Position,dest,{player.Character})
  220.  
  221. local finalFrame = buildRaw(newZoom)
  222.  
  223. return finalFrame
  224. end
  225.  
  226. function dynamic.cameraData:GetCameraFrame()--gets the camera cframe which can then be offset by a cframe of any object later
  227.  
  228. local camera = funcs.getCamera()
  229. camera.CameraType = Enum.CameraType.Scriptable
  230.  
  231. local zoom = self.zoom
  232. local firstPerson = zoom == 0
  233.  
  234. if firstPerson or self.shiftLock then
  235. service.uis.MouseBehavior = Enum.MouseBehavior.LockCenter
  236. elseif self.rightClicking then
  237. service.uis.MouseBehavior = Enum.MouseBehavior.LockCurrentPosition
  238. else
  239. service.uis.MouseBehavior = Enum.MouseBehavior.Default
  240. end
  241.  
  242. local sensitivity = service.uis.MouseDeltaSensitivity
  243.  
  244. local rotation = self.rotation
  245. local delta = service.uis:GetMouseDelta()--lemme check it
  246.  
  247. local tiltA = service.uis:IsKeyDown(Enum.KeyCode.A) and -settings.tilt.turnTilt or 0
  248. local tiltD = service.uis:IsKeyDown(Enum.KeyCode.D) and settings.tilt.turnTilt or 0
  249.  
  250. local tiltS = service.uis:IsKeyDown(Enum.KeyCode.S) and settings.tilt.turnTilt or 0
  251. local tiltW = service.uis:IsKeyDown(Enum.KeyCode.W) and -settings.tilt.turnTilt or 0
  252.  
  253. local addedTilt = tiltA + tiltD
  254. local addedTiltX = tiltS+tiltW
  255.  
  256. local newTilt = delta.X*settings.tilt.strength/sensitivity + addedTilt
  257. self.currentTilt = funcs.lerp(self.currentTilt,newTilt,(1-settings.tilt.drift)/2)
  258.  
  259. local newRotation = rotation+Vector2.new(math.rad(delta.X),math.rad(delta.y)) * (sensitivity/2)
  260. self.rotation = Vector2.new(
  261. newRotation.X%(math.pi*2),--loop over if rotation exceeds 360 degrees (2*pi in radians)
  262. math.clamp(newRotation.Y,math.rad(settings.minAngle),math.rad(settings.maxAngle))-- limit the vertical angle
  263. )
  264.  
  265. return self:BuildCFrame(-self.currentTilt), firstPerson, self.shiftLock
  266. end
  267.  
  268. function characterData.StopCamera()
  269. service.run:UnbindFromRenderStep("CameraControl")
  270. end
  271.  
  272. function characterData:StartCamera(offset)
  273.  
  274. local character,torso,head,humanoid = table.unpack(self.bodyParts)
  275.  
  276. service.run:BindToRenderStep("CameraControl",1,function()
  277. --funcs.getCamera().CameraSubject = torso--doing constantly
  278.  
  279. dynamic.cameraData.smoothZoom = funcs.lerp(dynamic.cameraData.smoothZoom,dynamic.cameraData.zoom,1-settings.zoomSmoothing)
  280.  
  281. local subject = funcs.getCamera().CameraSubject
  282. local origin = subject and funcs.getSubjectCFrame(subject) or CFrame.new(0,0,0)
  283.  
  284. local cameraFrame, firstPerson, shiftLock = dynamic.cameraData:GetCameraFrame()
  285.  
  286. local shiftLockOffset = CFrame.new((shiftLock and not firstPerson and character and character.PrimaryPart) and 3 or 0,0,0)
  287. local newFrame = origin*CFrame.new(offset)*cameraFrame*shiftLockOffset
  288.  
  289. local camOrient = Vector3.new(newFrame:ToOrientation())
  290.  
  291. funcs.getCamera().CFrame = newFrame
  292.  
  293. local autoOn = characterData:GetHumanoidValue("AutoRotate")
  294. if dynamic.cameraData.shiftLock then--"only setting the value when needed and not constantly" - my only excuse for branch
  295. if autoOn then
  296.  
  297. characterData:SetHumanoidProperty("AutoRotate",false)
  298. end
  299. else
  300. if not autoOn then
  301.  
  302. characterData:SetHumanoidProperty("AutoRotate",true)
  303. end
  304. end
  305.  
  306. if character then
  307. local characterTransparency = dynamic.cameraData:GetCharacterTransparencyGoal()
  308. funcs.setCharacterTransparency(character,characterTransparency)
  309. end
  310.  
  311. local character = player.Character
  312. if not character or not character.PrimaryPart then
  313. return
  314. end
  315.  
  316. if not shiftLock and not firstPerson then
  317. return
  318. end
  319.  
  320. local charFrame = character:GetPrimaryPartCFrame()
  321. local charRot = Vector3.new(charFrame:ToOrientation())
  322. local rotation = CFrame.Angles(charRot.X,camOrient.Y,charRot.Z)
  323.  
  324. character:SetPrimaryPartCFrame(CFrame.new(charFrame.Position)*rotation)
  325. end)
  326.  
  327. local run1,run2 = nil,nil
  328.  
  329. local function endProcesses()
  330. warn("Ending processes")
  331.  
  332. characterData.StopCamera()
  333.  
  334. if run1 then
  335. run1:Disconnect()
  336. run1 = nil
  337. end
  338. if run2 then
  339. run2:Disconnect()
  340. run2 = nil
  341. end
  342. end
  343.  
  344. local run1 = humanoid.Destroying:Connect(endProcesses)
  345. local run2 = humanoid.Died:Connect(endProcesses)
  346. end
  347.  
  348. function characterData:Init()
  349. self.bodyParts = {getCharacterParts(player)}
  350. --funcs.getCamera().CameraSubject = self.bodyParts.torso--lock on
  351.  
  352. service.uis.InputBegan:Connect(function(input)
  353.  
  354. local inputTypes = {
  355. MouseButton2 = function()
  356. dynamic.cameraData.rightClicking = true
  357. end,
  358. Keyboard = function()--roblox forever
  359. local keycode = input.KeyCode
  360.  
  361. local isShift = keycode == Enum.KeyCode.LeftShift or keycode == Enum.KeyCode.RightShift
  362. if isShift then
  363. dynamic.cameraData.shiftLock = not dynamic.cameraData.shiftLock--invert
  364. end
  365. end,
  366. }
  367.  
  368. local func = inputTypes[input.UserInputType.Name]
  369. if type(func)~="function" then
  370. return
  371. end
  372.  
  373. func()
  374. end)
  375. service.uis.InputChanged:Connect(function(input)
  376.  
  377. local inputTypes = {
  378. MouseWheel = function()
  379.  
  380. local direction = -input.Position.Z * ((dynamic.cameraData.zoom+4)/4)--scroll increment -1 or 1
  381. local newZoom = math.clamp(dynamic.cameraData.zoom+direction, settings.minZoom, settings.maxZoom)
  382.  
  383. dynamic.cameraData.zoom = (dynamic.cameraData.zoom<3 and direction<0) and 0 or newZoom--player is zooming in and is already very close to being fully zoomed in
  384.  
  385. end,
  386. }
  387.  
  388. local func = inputTypes[input.UserInputType.Name]
  389. if type(func)~="function" then
  390. return
  391. end
  392.  
  393. func()
  394. end)
  395. service.uis.InputEnded:Connect(function(input)
  396. local inputTypes = {
  397. MouseButton2 = function()
  398. dynamic.cameraData.rightClicking = false
  399. end,
  400. }
  401.  
  402. local func = inputTypes[input.UserInputType.Name]
  403. if type(func)~="function" then
  404. return
  405. end
  406.  
  407. func()
  408. end)
  409. end
  410.  
  411. characterData:Init()
  412. characterData:StartCamera(Vector3.new(0,1.5,0))
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement