Advertisement
AlewAlow

collision

Apr 14th, 2024
710
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 5.30 KB | None | 0 0
  1. local ReplicatedStorage = game:GetService("ReplicatedStorage")
  2.  
  3. local Matter = require(ReplicatedStorage.Shared.Libs.Matter)
  4. local Components = require(ReplicatedStorage.Shared.Components)
  5.  
  6. local RotateVector2 = require(ReplicatedStorage.Shared.Utils.RotateVector2)
  7. local GetOverlappingEntities = require(ReplicatedStorage.Shared.Utils.GetOverlappingEntities)
  8. local GetEntityGlobalPosition = require(ReplicatedStorage.Shared.Utils.GetEntityGlobalPosition)
  9. local GetEntityGlobalRotation = require(ReplicatedStorage.Shared.Utils.GetEntityGlobalRotation)
  10. local GetEntityGlobalScale = require(ReplicatedStorage.Shared.Utils.GetEntityGlobalScale)
  11. local GetEntityCanvas = require(ReplicatedStorage.Shared.Utils.GetEntityCanvas)
  12.  
  13. local CheckCollisions = require(ReplicatedStorage.Shared.Systems.CheckCollisions)
  14. local ApplyVelocity = require(ReplicatedStorage.Shared.Systems.ApplyVelocity)
  15.  
  16. local function sweptAABB(
  17.     velocity,
  18.     position1,
  19.     size1,
  20.    
  21.     position2,
  22.     size2
  23. )
  24.     local xInvEntry, yInvEntry
  25.     local xInvExit, yInvExit
  26.    
  27.     if velocity.X > 0 then
  28.         xInvEntry = position2.X - (position1.X + size1.X / 2)
  29.         xInvExit = (position2.X + size2.X / 2) - position1.X
  30.     else
  31.         xInvEntry = (position2.X + size2.X / 2) - position1.X
  32.         xInvExit = position2.X - (position1.X + size1.X / 2)
  33.     end
  34.    
  35.     if velocity.Y > 0 then
  36.         yInvEntry = position2.Y - (position1.Y + size1.Y / 2)
  37.         yInvExit = (position2.Y + size2.Y / 2) - position1.Y
  38.     else
  39.         yInvEntry = (position2.Y + size2.Y / 2) - position1.Y
  40.         yInvExit = position2.Y - (position1.Y + size1.Y / 2)
  41.     end
  42.    
  43.     local xEntry, yEntry
  44.     local xExit, yExit
  45.    
  46.     if velocity.X == 0 then
  47.         xEntry = math.huge
  48.         xExit = math.huge
  49.     else
  50.         xEntry = xInvEntry / velocity.X
  51.         xExit = xInvExit / velocity.X
  52.     end
  53.    
  54.     if velocity.X == 0 then
  55.         yEntry = math.huge
  56.         yExit = math.huge
  57.     else
  58.         yEntry = yInvEntry / velocity.Y
  59.         yExit = yInvExit / velocity.Y
  60.     end
  61.    
  62.     local entryTime = math.max(xEntry, yEntry)
  63.     local exitTime = math.min(xExit, yExit)
  64.    
  65.     if entryTime > exitTime or (xEntry < 0 and yEntry < 0) or xEntry > 1 or yEntry > 1 then
  66.         return 1, Vector2.new(0, 0)
  67.     end
  68.    
  69.     local normal
  70.    
  71.     if xEntry > yEntry then
  72.         if xInvEntry < 0 then
  73.             normal = Vector2.new(1, 0)
  74.         else
  75.             normal = Vector2.new(-1, 0)
  76.         end
  77.     else
  78.         if yInvEntry < 0 then
  79.             normal = Vector2.new(0, 1)
  80.         else
  81.             normal = Vector2.new(0, -1)
  82.         end
  83.     end
  84.    
  85.     return entryTime, normal
  86. end
  87.  
  88. local function globalToLocalPosition(id, position, world)
  89.     local parentRotation = 0
  90.     local parentPosition = Vector2.zero
  91.     local parentScale = Vector2.one
  92.  
  93.     local child = world:get(id, Components.Child)
  94.     if child and world:contains(child.Parent) then
  95.         parentPosition = GetEntityGlobalPosition(child.Parent, world)
  96.         parentRotation = GetEntityGlobalRotation(child.Parent, world)
  97.         parentScale = GetEntityGlobalScale(child.Parent, world)
  98.     end
  99.    
  100.     return RotateVector2(position - parentPosition, -math.rad(parentRotation)) / parentScale
  101. end
  102.  
  103. local function RespondToCollisions(world, state)
  104.     for id1, transform1, velocity1, collider1, physics1 in world:query(Components.Transform, Components.Velocity, Components.Collider, Components.Physics) do
  105.         local colliding = world:get(id1, Components.Colliding)
  106.         local collidingWith = if colliding
  107.             then colliding.CollidingWith
  108.             else {}
  109.        
  110.         local globalPosition1 = GetEntityGlobalPosition(id1, world)
  111.         local globalSize1 = GetEntityGlobalScale(id1, world) * collider1.Size
  112.        
  113.         local lastPosition = physics1.LastPosition or globalPosition1
  114.         local lastChange = globalPosition1 - lastPosition
  115.        
  116.         if #collidingWith == 0 then
  117.             continue
  118.         end
  119.        
  120.         local minCollisionTime = math.huge
  121.         local minCollisionNormal = nil
  122.        
  123.         for _, id2 in collidingWith do
  124.             local sprite2 = world:get(id2, Components.Sprite)
  125.             if sprite2 then
  126.                 world:insert(id2, sprite2:patch({
  127.                     ImageColor = Color3.new(0, 0, 1)
  128.                 }))
  129.             end
  130.            
  131.             local collider2 = world:get(id2, Components.Collider)
  132.             if not collider2 then
  133.                 continue
  134.             end
  135.            
  136.             local transform2 = world:get(id2, Components.Transform)
  137.             if not transform2 then
  138.                 continue
  139.             end
  140.            
  141.             local globalPosition2 = GetEntityGlobalPosition(id2, world)
  142.             local globalSize2 = GetEntityGlobalScale(id2, world) * collider2.Size
  143.             local collisionTime, collisionNormal = sweptAABB(
  144.                 lastChange,
  145.                 lastPosition,
  146.                 globalSize1,
  147.                 globalPosition2,
  148.                 globalSize2
  149.             )
  150.            
  151.             if collisionTime < minCollisionTime then
  152.                 minCollisionTime = collisionTime
  153.                 minCollisionNormal = collisionNormal
  154.             end
  155.         end
  156.        
  157.         local parentRotation = 0
  158.         local parentPosition = Vector2.zero
  159.         local parentScale = Vector2.one
  160.        
  161.         local newGlobalPosition = lastPosition + lastChange * minCollisionTime
  162.         local newLocalPosition = globalToLocalPosition(id1, newGlobalPosition, world)
  163.        
  164.         local dotprod = (lastChange.X * minCollisionNormal.Y + lastChange.Y * minCollisionNormal.X) * (1 - minCollisionTime)
  165.        
  166.         world:insert(id1,
  167.             transform1:patch({
  168.                 Position = newLocalPosition
  169.             }),
  170.             physics1:patch({
  171.                 LastPosition = newGlobalPosition
  172.             }),
  173.             velocity1:patch({
  174.                 Velocity = Vector2.new(
  175.                     dotprod * minCollisionNormal.Y,
  176.                     dotprod * minCollisionNormal.X
  177.                 )
  178.             })
  179.         )
  180.     end
  181. end
  182.  
  183. return {
  184.     system = RespondToCollisions,
  185.     after = {
  186.         CheckCollisions,
  187.         ApplyVelocity,
  188.     },
  189. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement