Advertisement
Thial

Untitled

Apr 16th, 2024
41
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 13.81 KB | None | 0 0
  1. last_gizmo_id = 696969
  2. color_colliding = fcolor():set(1,0,0,1)
  3. color_not_colliding = fcolor():set(0,1,0,1)
  4. color_not_colliding_front = fcolor():set(0,1,0,1)
  5. color_contact = fcolor():set(1,1,0,1)
  6. color_side = fcolor():set(0.5,0.5,0.5,1)
  7.  
  8. -- Generic Class for handling collisions with a bounding shape
  9. -- supposed to be subclassed into a useful shape (see aol_bbox)
  10. class "bshape_collider"
  11.  
  12. function bshape_collider:__init(world_origin, local_origin, rotation)
  13. -- Coordinates of the origin in local space (relative to self.vertices)
  14. self.local_origin = local_origin or vector():set(0,0,0)
  15.  
  16. -- Coordinates of the entire box's origin in world space (relative to game map)
  17. self.world_origin = world_origin or vector():set(0,0,0)
  18.  
  19. self.rotation = rotation
  20.  
  21. self.is_colliding = false
  22.  
  23. -- Coordinates of bbox's vertices in local space
  24. self.vertices = {}
  25.  
  26. -- Coordinates of bbox vertices in world space
  27. self.world_vertices = {}
  28.  
  29. -- Pairs of vertices to perform raycasting between
  30. self.ray_pairs = {}
  31.  
  32. -- Map of ray pair index to it's length
  33. self.ray_pair_i2length = {}
  34. end
  35.  
  36. function bshape_collider:UpdateBBox()
  37. -- Get position of vertices in bounding box in world space
  38. for i, local_vertex in ipairs(self.vertices) do
  39. -- local space
  40. local position = vector():set(local_vertex.x, local_vertex.y, local_vertex.z)
  41.  
  42. -- rotate with quaternion
  43. if self.rotation then
  44. position = self.rotation:rotate_vector(position)
  45. end
  46.  
  47. -- world space
  48. position = position:add(self.world_origin)
  49.  
  50. -- store vertices coordinates in world space of bbox
  51. self.world_vertices[i] = position
  52. end
  53. end
  54.  
  55. function bshape_collider:UpdateLengths()
  56. for i, ray_pair in ipairs(self.ray_pairs) do
  57. local v1 = self.world_vertices[ray_pair[1]]
  58. local v2 = self.world_vertices[ray_pair[2]]
  59.  
  60. local length = v1:distance_to(v2)
  61. self.ray_pair_i2length[i] = length
  62. end
  63. end
  64.  
  65. function bshape_collider:CheckForCollisions()
  66. -- Check for collisions by ray casting between vertex pairs
  67. -- Pairs are specified in ray_pairs
  68. -- Ray cast in both directions in case the ray goes into the world (rays only register collisions when hitting onto a normal plane)
  69. local collision_found = false
  70. for i, ray_pair in ipairs(self.ray_pairs) do
  71. -- Exit early if there is no collision
  72. if not collision_found then
  73. local ray_length = self.ray_pair_i2length[i]
  74. local ray = demonized_geometry_ray.geometry_ray({
  75. ray_range=4,
  76. contact_range=ray_length,
  77. flags=(1+2)})
  78. local ray_direction = vec_sub(self.world_vertices[ray_pair[1]], self.world_vertices[ray_pair[2]])
  79. ray_direction = ray_direction:normalize()
  80.  
  81. -- Perform raycasts
  82. local ray_result_rev = ray:get(vec_set(self.world_vertices[ray_pair[1]]), vec_set(ray_direction):invert())
  83. local ray_result = ray:get(vec_set(self.world_vertices[ray_pair[2]]), vec_set(ray_direction))
  84.  
  85. if ray_result.in_contact or ray_result_rev.in_contact then
  86. collision_found = true
  87. end
  88. end
  89. end
  90.  
  91. self.is_colliding = collision_found
  92.  
  93. return collision_found
  94. end
  95.  
  96. -- Setters
  97.  
  98. function bshape_collider:SetLocalOrigin(new_pos)
  99. self.local_origin = vec_set(new_pos)
  100.  
  101. -- update vertices of bbox in local space
  102. self:UpdateVertices()
  103.  
  104. self:UpdateBBox()
  105. end
  106.  
  107. function bshape_collider:SetWorldOrigin(new_pos)
  108. self.world_origin = vec_set(new_pos)
  109. end
  110.  
  111. -- Functions to be completed by subclasses
  112.  
  113. function bshape_collider:UpdateVertices()
  114. end
  115.  
  116.  
  117.  
  118. -- Class for rendering bounding boxes with particles
  119. class "bshape_renderer"
  120.  
  121. function bshape_renderer:__init()
  122. self.particles = {}
  123. self.gizmos = nil
  124. self.contact_gizmos = {}
  125. self.side_gizmos = nil
  126. --ray for testing distance to walls and drawing distance lines
  127. self.ray = demonized_geometry_ray.geometry_ray({ ray_range=1, contact_range=0.5, flags=(1+2)})
  128. end
  129.  
  130. function bshape_renderer:DrawBShapeCollider(bshape_collider)
  131. if #bshape_collider.world_vertices >= 8 then
  132. self:DrawCube(bshape_collider)
  133. if bshape_collider.is_colliding == false then
  134. self:CheckCubeCollision(bshape_collider)
  135. else
  136. self:StopContactGizmos()
  137. self:StopSideGizmos()
  138. end
  139. else
  140. self:DrawLegacy(bshape_collider)
  141. end
  142. end
  143.  
  144. function bshape_renderer:DrawCube(bshape_collider)
  145. if self.gizmos == nil then
  146. self.gizmos = {
  147. self:AddCubeLine(bshape_collider, 1, 2, true, false),
  148. self:AddCubeLine(bshape_collider, 2, 4, false, false),
  149. self:AddCubeLine(bshape_collider, 3, 4, false, false),
  150. self:AddCubeLine(bshape_collider, 1, 3, false, false),
  151. self:AddCubeLine(bshape_collider, 5, 6, true, false),
  152. self:AddCubeLine(bshape_collider, 6, 8, false, false),
  153. self:AddCubeLine(bshape_collider, 7, 8, false, false),
  154. self:AddCubeLine(bshape_collider, 5, 7, false, false),
  155. self:AddCubeLine(bshape_collider, 1, 5, true, false),
  156. self:AddCubeLine(bshape_collider, 2, 6, true, false),
  157. self:AddCubeLine(bshape_collider, 3, 7, false, false),
  158. self:AddCubeLine(bshape_collider, 4, 8, false, false)
  159. }
  160. end
  161. if self.side_gizmos == nil then
  162. self.side_gizmos = {
  163. ["front"] = {
  164. self:AddCubeLine(bshape_collider, 1, 6, false, true),
  165. self:AddCubeLine(bshape_collider, 2, 5, false, true)
  166. },
  167. ["back"] = {
  168. self:AddCubeLine(bshape_collider, 3, 8, false, true),
  169. self:AddCubeLine(bshape_collider, 4, 7, false, true)
  170. },
  171. ["left"] = {
  172. self:AddCubeLine(bshape_collider, 1, 7, false, true),
  173. self:AddCubeLine(bshape_collider, 3, 5, false, true)
  174. },
  175. ["right"] = {
  176. self:AddCubeLine(bshape_collider, 2, 8, false, true),
  177. self:AddCubeLine(bshape_collider, 4, 6, false, true)
  178. },
  179. ["top"] = {
  180. self:AddCubeLine(bshape_collider, 5, 8, false, true),
  181. self:AddCubeLine(bshape_collider, 6, 7, false, true)
  182. },
  183. ["bottom"] = {
  184. self:AddCubeLine(bshape_collider, 1, 4, false, true),
  185. self:AddCubeLine(bshape_collider, 2, 3, false, true)
  186. }
  187. }
  188. self:StopSideGizmos()
  189. end
  190.  
  191. for i, gizmo in ipairs(self.gizmos) do
  192. gizmo.line.visible = true
  193. gizmo.line.color = bshape_collider.is_colliding and aol_bshape.color_colliding
  194. or (gizmo.is_front and aol_bshape.color_not_colliding_front or aol_bshape.color_not_colliding)
  195. gizmo.line.point_a = bshape_collider.world_vertices[gizmo.vertex_1]
  196. gizmo.line.point_b = bshape_collider.world_vertices[gizmo.vertex_2]
  197. end
  198. end
  199.  
  200. function bshape_renderer:CheckCubeCollision(bshape_collider)
  201. if bshape_collider == nil then
  202. return
  203. end
  204.  
  205. local verts = bshape_collider.world_vertices
  206. local dir_front = vec_sub(verts[3], verts[1]):normalize():invert()
  207. local dir_back = vec_sub(verts[1], verts[3]):normalize():invert()
  208. local dir_left = vec_sub(verts[2], verts[1]):normalize():invert()
  209. local dir_right = vec_sub(verts[1], verts[2]):normalize():invert()
  210. local dir_top = vec_sub(verts[1], verts[5]):normalize():invert()
  211. local dir_bottom = vec_sub(verts[5], verts[1]):normalize():invert()
  212.  
  213. self:CheckSideCollision(bshape_collider, dir_front, "front", 1, 2, 5, 6, 9)
  214. self:CheckSideCollision(bshape_collider, dir_back, "back", 3, 4, 7, 8, 10)
  215. self:CheckSideCollision(bshape_collider, dir_left, "left", 1, 3, 5, 7, 11)
  216. self:CheckSideCollision(bshape_collider, dir_right, "right", 2, 4, 6, 8, 12)
  217. self:CheckSideCollision(bshape_collider, dir_top, "top", 5, 6, 7, 8, 13)
  218. self:CheckSideCollision(bshape_collider, dir_bottom, "bottom", 1, 2, 3, 4, 14)
  219. end
  220.  
  221. function bshape_renderer:CheckSideCollision(bshape_collider, direction, direction_name, vertex_1, vertex_2, vertex_3, vertex_4, vertex_5)
  222. local valid = bshape_collider and direction and direction_name and vertex_1 and vertex_2 and vertex_3 and vertex_4 and vertex_5
  223. if not valid then
  224. return
  225. end
  226.  
  227. local verts = bshape_collider.world_vertices
  228. local center_pos = self:GetSideCenterPosition(bshape_collider, vertex_1, vertex_4)
  229.  
  230. local result_1 = self:CheckRayCollision(bshape_collider, direction, direction_name, verts[vertex_1], vertex_1)
  231. local result_2 = self:CheckRayCollision(bshape_collider, direction, direction_name, verts[vertex_2], vertex_2)
  232. local result_3 = self:CheckRayCollision(bshape_collider, direction, direction_name, verts[vertex_3], vertex_3)
  233. local result_4 = self:CheckRayCollision(bshape_collider, direction, direction_name, verts[vertex_4], vertex_4)
  234. local result_5 = self:CheckRayCollision(bshape_collider, direction, direction_name, center_pos, vertex_5)
  235.  
  236. local in_contact = result_1 or result_2 or result_3 or result_4 or result_5
  237. self.side_gizmos[direction_name][1].line.visible = in_contact
  238. self.side_gizmos[direction_name][1].line.point_a = verts[vertex_1]
  239. self.side_gizmos[direction_name][1].line.point_b = verts[vertex_4]
  240. self.side_gizmos[direction_name][2].line.visible = in_contact
  241. self.side_gizmos[direction_name][2].line.point_a = verts[vertex_2]
  242. self.side_gizmos[direction_name][2].line.point_b = verts[vertex_3]
  243. end
  244.  
  245. function bshape_renderer:GetSideCenterPosition(bshape_collider, vertex_1, vertex_2)
  246. if bshape_collider == nil or vertex_1 == nil or vertex_2 == nil then
  247. return
  248. end
  249.  
  250. local pos1 = bshape_collider.world_vertices[vertex_1]
  251. local pos2 = bshape_collider.world_vertices[vertex_2]
  252. local add = vector():set(pos1):add(pos2)
  253. local div = vector():set(add):div(vector():set(2,2,2))
  254. return div
  255. end
  256.  
  257. function bshape_renderer:CheckRayCollision(bshape_collider, direction, direction_name, position, vertex)
  258. local valid = bshape_collider and direction and direction_name and position and vertex
  259. if not valid then
  260. return
  261. end
  262.  
  263. local gizmo_name = direction_name .. "_" .. vertex
  264. local ray_result = self.ray:get(vec_set(position), vec_set(direction))
  265. if ray_result.distance < 0.5 then
  266. if self.contact_gizmos[gizmo_name] == nil then
  267. self.contact_gizmos[gizmo_name] = self:AddLine(position, ray_result.position, aol_bshape.color_contact)
  268. end
  269. self.contact_gizmos[gizmo_name].visible = true
  270. self.contact_gizmos[gizmo_name].point_a = position
  271. self.contact_gizmos[gizmo_name].point_b = ray_result.position
  272. return true
  273. else
  274. if self.contact_gizmos[gizmo_name] ~= nil then
  275. self.contact_gizmos[gizmo_name].visible = false
  276. end
  277. return false
  278. end
  279. end
  280.  
  281. function bshape_renderer:DrawLegacy(bshape_collider)
  282. for i, position in ipairs(bshape_collider.world_vertices) do
  283. if self.particles[i] == nil then
  284. self.particles[i] = particles_object("_samples_particles_\\place_indicator")
  285. end
  286.  
  287. local particle = self.particles[i]
  288.  
  289. if not particle:playing() then
  290. particle:play()
  291. end
  292. -- Move particles to origin if bbox collides with something
  293. if bshape_collider.is_colliding then
  294. particle:move_to(bshape_collider.world_origin, VEC_Z)
  295. -- Move particles to vertices of bbox if there is no collision
  296. else
  297. particle:move_to(position, VEC_Z)
  298. end
  299. end
  300. end
  301.  
  302. function bshape_renderer:AddCubeLine(bshape_collider, vertex_1, vertex_2, is_front, is_side)
  303. if bshape_collider == nil or vertex_1 == nil or vertex_2 == nil or is_front == nil or is_side == nil then
  304. return
  305. end
  306.  
  307. local pos1 = bshape_collider.world_vertices[vertex_1]
  308. local pos2 = bshape_collider.world_vertices[vertex_2]
  309. local color = aol_bshape.color_not_colliding
  310. if is_front then
  311. color = aol_bshape.color_not_colliding_front
  312. elseif is_side then
  313. color = aol_bshape.color_side
  314. end
  315. local line = self:AddLine(pos1, pos2, color)
  316.  
  317. return {
  318. line = line,
  319. vertex_1 = vertex_1,
  320. vertex_2 = vertex_2,
  321. is_front = is_front
  322. }
  323. end
  324.  
  325. function bshape_renderer:AddLine(position_1, position_2, color)
  326. if position_1 == nil or position_2 == nil or color == nil then
  327. return
  328. end
  329.  
  330. aol_bshape.last_gizmo_id = aol_bshape.last_gizmo_id + 1
  331. local line = debug_render.add_object(aol_bshape.last_gizmo_id, DBG_ScriptObject.line):cast_dbg_line()
  332. line.visible = true
  333. line.color = color
  334. line.point_a = position_1
  335. line.point_b = position_2
  336.  
  337. return line
  338. end
  339.  
  340. function bshape_renderer:Stop()
  341. self:StopParticles()
  342. self:StopGizmos()
  343. self:StopContactGizmos()
  344. self:StopSideGizmos()
  345. end
  346.  
  347. function bshape_renderer:StopParticles()
  348. for i, particle in ipairs(self.particles) do
  349. if particle then
  350. particle:stop_deffered()
  351. end
  352. end
  353. end
  354.  
  355. function bshape_renderer:StopGizmos()
  356. for i, gizmo in ipairs(self.gizmos) do
  357. gizmo.line.visible = false
  358. end
  359. end
  360.  
  361. function bshape_renderer:StopContactGizmos()
  362. for key, gizmo in pairs(self.contact_gizmos) do
  363. gizmo.visible = false
  364. end
  365. end
  366.  
  367. function bshape_renderer:StopSideGizmos()
  368. for side_name, side in pairs(self.side_gizmos) do
  369. for i, gizmo in ipairs(side) do
  370. gizmo.line.visible = false
  371. end
  372. end
  373. end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement