PageRenderTime 55ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/[editor]/freecam/freecam.lua

https://gitlab.com/yasin3223/mtasa-resources
Lua | 323 lines | 244 code | 46 blank | 33 comment | 36 complexity | a15ea9d88de75397c3dd6ad20209f381 MD5 | raw file
  1. -- state variables
  2. local speed = 0
  3. local strafespeed = 0
  4. local rotX, rotY = 0,0
  5. local velocityX, velocityY, velocityZ
  6. -- configurable parameters
  7. local options = {
  8. invertMouseLook = false,
  9. normalMaxSpeed = 2,
  10. slowMaxSpeed = 0.2,
  11. fastMaxSpeed = 12,
  12. smoothMovement = true,
  13. acceleration = 0.3,
  14. decceleration = 0.15,
  15. mouseSensitivity = 0.3,
  16. maxYAngle = 188,
  17. key_fastMove = "lshift",
  18. key_slowMove = "lalt",
  19. key_forward = "forwards",
  20. key_backward = "backwards",
  21. key_left = "left",
  22. key_right = "right",
  23. key_forward_veh = "accelerate",
  24. key_backward_veh = "brake_reverse",
  25. key_left_veh = "vehicle_left",
  26. key_right_veh = "vehicle_right"
  27. }
  28. local controlToKey = {
  29. ["forwards"] = "w",
  30. ["backwards"] = "s",
  31. ["left"] = "a",
  32. ["right"] = "d",
  33. ["accelerate"] = "w",
  34. ["brake_reverse"] = "s",
  35. ["vehicle_left"] = "a",
  36. ["vehicle_right"] = "d",
  37. }
  38. local mouseFrameDelay = 0
  39. local mta_getKeyState = getKeyState
  40. function getKeyState(key)
  41. if isMTAWindowActive() then
  42. return false
  43. end
  44. if key == "lshift" or key == "lalt" or key == "arrow_u" or key == "arrow_d" or key == "arrow_l" or key == "arrow_r" then
  45. return mta_getKeyState(key)
  46. end
  47. if isPedDead(localPlayer) then
  48. -- We must use getKeyState when dead we also have to hope they're using WASD
  49. return mta_getKeyState(controlToKey[key])
  50. else
  51. -- We can use getControlState
  52. return getControlState(key)
  53. end
  54. end
  55. -- PRIVATE
  56. local function freecamFrame ()
  57. -- work out an angle in radians based on the number of pixels the cursor has moved (ever)
  58. local cameraAngleX = rotX
  59. local cameraAngleY = rotY
  60. local freeModeAngleZ = math.sin(cameraAngleY)
  61. local freeModeAngleY = math.cos(cameraAngleY) * math.cos(cameraAngleX)
  62. local freeModeAngleX = math.cos(cameraAngleY) * math.sin(cameraAngleX)
  63. local camPosX, camPosY, camPosZ = getCameraMatrix()
  64. -- calculate a target based on the current position and an offset based on the angle
  65. local camTargetX = camPosX + freeModeAngleX * 100
  66. local camTargetY = camPosY + freeModeAngleY * 100
  67. local camTargetZ = camPosZ + freeModeAngleZ * 100
  68. -- Calculate what the maximum speed that the camera should be able to move at.
  69. local mspeed = options.normalMaxSpeed
  70. if getKeyState ( options.key_fastMove ) then
  71. mspeed = options.fastMaxSpeed
  72. elseif getKeyState ( options.key_slowMove ) then
  73. mspeed = options.slowMaxSpeed
  74. end
  75. if options.smoothMovement then
  76. local acceleration = options.acceleration
  77. local decceleration = options.decceleration
  78. -- Check to see if the forwards/backwards keys are pressed
  79. local speedKeyPressed = false
  80. if ( getKeyState ( options.key_forward ) or getKeyState ( options.key_forward_veh ) ) and not getKeyState("arrow_u") then
  81. speed = speed + acceleration
  82. speedKeyPressed = true
  83. end
  84. if ( getKeyState ( options.key_backward ) or getControlState ( options.key_backward_veh ) ) and not getKeyState("arrow_d") then
  85. speed = speed - acceleration
  86. speedKeyPressed = true
  87. end
  88. -- Check to see if the strafe keys are pressed
  89. local strafeSpeedKeyPressed = false
  90. if ( getKeyState ( options.key_right ) or getKeyState ( options.key_right_veh ) ) and not getKeyState("arrow_r") then
  91. if strafespeed > 0 then -- for instance response
  92. strafespeed = 0
  93. end
  94. strafespeed = strafespeed - acceleration / 2
  95. strafeSpeedKeyPressed = true
  96. end
  97. if ( getKeyState ( options.key_left ) or getKeyState ( options.key_left_veh ) ) and not getKeyState("arrow_l") then
  98. if strafespeed < 0 then -- for instance response
  99. strafespeed = 0
  100. end
  101. strafespeed = strafespeed + acceleration / 2
  102. strafeSpeedKeyPressed = true
  103. end
  104. -- If no forwards/backwards keys were pressed, then gradually slow down the movement towards 0
  105. if speedKeyPressed ~= true then
  106. if speed > 0 then
  107. speed = speed - decceleration
  108. elseif speed < 0 then
  109. speed = speed + decceleration
  110. end
  111. end
  112. -- If no strafe keys were pressed, then gradually slow down the movement towards 0
  113. if strafeSpeedKeyPressed ~= true then
  114. if strafespeed > 0 then
  115. strafespeed = strafespeed - decceleration
  116. elseif strafespeed < 0 then
  117. strafespeed = strafespeed + decceleration
  118. end
  119. end
  120. -- Check the ranges of values - set the speed to 0 if its very close to 0 (stops jittering), and limit to the maximum speed
  121. if speed > -decceleration and speed < decceleration then
  122. speed = 0
  123. elseif speed > mspeed then
  124. speed = mspeed
  125. elseif speed < -mspeed then
  126. speed = -mspeed
  127. end
  128. if strafespeed > -(acceleration / 2) and strafespeed < (acceleration / 2) then
  129. strafespeed = 0
  130. elseif strafespeed > mspeed then
  131. strafespeed = mspeed
  132. elseif strafespeed < -mspeed then
  133. strafespeed = -mspeed
  134. end
  135. else
  136. speed = 0
  137. strafespeed = 0
  138. if getKeyState ( options.key_forward ) or getKeyState ( options.key_forward_veh ) then
  139. speed = mspeed
  140. end
  141. if getKeyState ( options.key_backward ) or getKeyState ( options.key_backward_veh ) then
  142. speed = -mspeed
  143. end
  144. if getKeyState ( options.key_left ) or getKeyState ( options.key_left_veh ) then
  145. strafespeed = mspeed
  146. end
  147. if getKeyState ( options.key_right ) or getKeyState ( options.key_right_veh ) then
  148. strafespeed = -mspeed
  149. end
  150. end
  151. -- Work out the distance between the target and the camera (should be 100 units)
  152. local camAngleX = camPosX - camTargetX
  153. local camAngleY = camPosY - camTargetY
  154. local camAngleZ = 0 -- we ignore this otherwise our vertical angle affects how fast you can strafe
  155. -- Calulcate the length of the vector
  156. local angleLength = math.sqrt(camAngleX*camAngleX+camAngleY*camAngleY+camAngleZ*camAngleZ)
  157. -- Normalize the vector, ignoring the Z axis, as the camera is stuck to the XY plane (it can't roll)
  158. local camNormalizedAngleX = camAngleX / angleLength
  159. local camNormalizedAngleY = camAngleY / angleLength
  160. local camNormalizedAngleZ = 0
  161. -- We use this as our rotation vector
  162. local normalAngleX = 0
  163. local normalAngleY = 0
  164. local normalAngleZ = 1
  165. -- Perform a cross product with the rotation vector and the normalzied angle
  166. local normalX = (camNormalizedAngleY * normalAngleZ - camNormalizedAngleZ * normalAngleY)
  167. local normalY = (camNormalizedAngleZ * normalAngleX - camNormalizedAngleX * normalAngleZ)
  168. local normalZ = (camNormalizedAngleX * normalAngleY - camNormalizedAngleY * normalAngleX)
  169. -- Update the camera position based on the forwards/backwards speed
  170. camPosX = camPosX + freeModeAngleX * speed
  171. camPosY = camPosY + freeModeAngleY * speed
  172. camPosZ = camPosZ + freeModeAngleZ * speed
  173. -- Update the camera position based on the strafe speed
  174. camPosX = camPosX + normalX * strafespeed
  175. camPosY = camPosY + normalY * strafespeed
  176. camPosZ = camPosZ + normalZ * strafespeed
  177. --Store the velocity
  178. velocityX = (freeModeAngleX * speed) + (normalX * strafespeed)
  179. velocityY = (freeModeAngleY * speed) + (normalY * strafespeed)
  180. velocityZ = (freeModeAngleZ * speed) + (normalZ * strafespeed)
  181. -- Update the target based on the new camera position (again, otherwise the camera kind of sways as the target is out by a frame)
  182. camTargetX = camPosX + freeModeAngleX * 100
  183. camTargetY = camPosY + freeModeAngleY * 100
  184. camTargetZ = camPosZ + freeModeAngleZ * 100
  185. -- Set the new camera position and target
  186. setCameraMatrix ( camPosX, camPosY, camPosZ, camTargetX, camTargetY, camTargetZ )
  187. end
  188. local function freecamMouse (cX,cY,aX,aY)
  189. --ignore mouse movement if the cursor or MTA window is on
  190. --and do not resume it until at least 5 frames after it is toggled off
  191. --(prevents cursor mousemove data from reaching this handler)
  192. if isCursorShowing() or isMTAWindowActive() then
  193. mouseFrameDelay = 5
  194. return
  195. elseif mouseFrameDelay > 0 then
  196. mouseFrameDelay = mouseFrameDelay - 1
  197. return
  198. end
  199. -- how far have we moved the mouse from the screen center?
  200. local width, height = guiGetScreenSize()
  201. aX = aX - width / 2
  202. aY = aY - height / 2
  203. --invert the mouse look if specified
  204. if options.invertMouseLook then
  205. aY = -aY
  206. end
  207. rotX = rotX + aX * options.mouseSensitivity * 0.01745
  208. rotY = rotY - aY * options.mouseSensitivity * 0.01745
  209. local PI = math.pi
  210. if rotX > PI then
  211. rotX = rotX - 2 * PI
  212. elseif rotX < -PI then
  213. rotX = rotX + 2 * PI
  214. end
  215. if rotY > PI then
  216. rotY = rotY - 2 * PI
  217. elseif rotY < -PI then
  218. rotY = rotY + 2 * PI
  219. end
  220. -- limit the camera to stop it going too far up or down - PI/2 is the limit, but we can't let it quite reach that or it will lock up
  221. -- and strafeing will break entirely as the camera loses any concept of what is 'up'
  222. if rotY < -PI / 2.05 then
  223. rotY = -PI / 2.05
  224. elseif rotY > PI / 2.05 then
  225. rotY = PI / 2.05
  226. end
  227. end
  228. -- PUBLIC
  229. function getFreecamVelocity()
  230. return velocityX,velocityY,velocityZ
  231. end
  232. -- params: x, y, z sets camera's position (optional)
  233. function setFreecamEnabled (x, y, z)
  234. if isFreecamEnabled() then
  235. return false
  236. end
  237. if (x and y and z) then
  238. setCameraMatrix ( x, y, z )
  239. end
  240. addEventHandler("onClientRender", root, freecamFrame)
  241. addEventHandler("onClientCursorMove",root, freecamMouse)
  242. setElementData(localPlayer, "freecam:state", true)
  243. return true
  244. end
  245. -- param: dontChangeFixedMode leaves toggleCameraFixedMode alone if true, disables it if false or nil (optional)
  246. function setFreecamDisabled()
  247. if not isFreecamEnabled() then
  248. return false
  249. end
  250. velocityX,velocityY,velocityZ = 0,0,0
  251. speed = 0
  252. strafespeed = 0
  253. removeEventHandler("onClientRender", root, freecamFrame)
  254. removeEventHandler("onClientCursorMove",root, freecamMouse)
  255. setElementData(localPlayer, "freecam:state", false)
  256. return true
  257. end
  258. function isFreecamEnabled()
  259. return getElementData(localPlayer,"freecam:state")
  260. end
  261. function getFreecamOption(theOption, value)
  262. return options[theOption]
  263. end
  264. function setFreecamOption(theOption, value)
  265. if options[theOption] ~= nil then
  266. options[theOption] = value
  267. return true
  268. else
  269. return false
  270. end
  271. end
  272. addEvent("doSetFreecamEnabled", true)
  273. addEventHandler("doSetFreecamEnabled", root, setFreecamEnabled)
  274. addEvent("doSetFreecamDisabled", true)
  275. addEventHandler("doSetFreecamDisabled", root, setFreecamDisabled)
  276. addEvent("doSetFreecamOption")
  277. addEventHandler("doSetFreecamOption", root, setFreecamOption)