summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorthe lemons <citrons@mondecitronne.com>2022-12-26 02:43:02 -0600
committerthe lemons <citrons@mondecitronne.com>2022-12-26 02:43:57 -0600
commitb7aca18f4c80426f528bc650e1f6bd01437c8a89 (patch)
tree1b2b7a16eff56e57f916754d89e1928ca170abde
parentede9af54010eab4eb6ee1b81fe9d6a0333846e88 (diff)
improve collision code
-rw-r--r--main.lua2
-rw-r--r--obj.lua52
-rw-r--r--util.lua4
3 files changed, 40 insertions, 18 deletions
diff --git a/main.lua b/main.lua
index 619b5ec..31225fa 100644
--- a/main.lua
+++ b/main.lua
@@ -19,7 +19,7 @@ local selection
for i = 1, 100 do
obj.new("test", {math.random() * 1000 - 500, math.random() * 1000 - 500}, {
avel = math.random() * 0.5 - 0.25,
- vel = {math.random() * 0.5 - 0.25, math.random() * 0.5 - 0.25}
+ vel = {math.random() * 1 - 0.5, math.random() * 1 - 0.5}
})
end
diff --git a/obj.lua b/obj.lua
index c94d504..6f69cb1 100644
--- a/obj.lua
+++ b/obj.lua
@@ -1,4 +1,5 @@
local world = require "world"
+local util = require "util"
local pi = math.pi
local obj = {}
@@ -122,15 +123,35 @@ function obj:tick(...)
local ox, oy = unpack(o.data.pos)
local dx, dy = ox - x, oy - y
if dx*dx + dy*dy < dist*dist then
+ -- local ke = self:energy() + o:energy()
+ self:collision(o)
+ o:collision(self)
+
local angle = math.atan2(dy, dx)
- self:collision(o, angle)
- o:collision(self, pi - angle)
+
-- reposition self outside of collided object
self:set_pos(
self.data.pos[1] - math.cos(angle) * dist + dx,
self.data.pos[2] - math.sin(angle) * dist + dy)
- self:collision_exit(o, angle)
- o:collision_exit(self, pi - angle)
+
+ local av1, av2 = self.data.avel, o.data.avel
+ -- transfer angular velocity conserving energy
+ local avel = math.sqrt((av1*av1 + av2*av2) / 2)
+ self.data.avel = avel * (av1 > av2 and 1 or -1)
+ o.data.avel = avel * (av1 > av2 and -1 or 1)
+
+ local vx, vy = unpack(self.data.vel)
+ local ovx, ovy = unpack(o.data.vel)
+ -- exchange the components of the velocities towards the
+ -- angle of collision
+ local rovx, rvy = util.rot(angle, vx, vy)
+ local rvx, rovy = util.rot(angle, ovx, ovy)
+ self.data.vel[1], self.data.vel[2] = util.rot(-angle, rvx, rvy)
+ o.data.vel[1], o.data.vel[2] = util.rot(-angle, rovx, rovy)
+
+ self:collision_exit(o)
+ o:collision_exit(self)
+ -- assert(ke - (self:energy() + o:energy()) < 0.00001)
end
end
end
@@ -149,21 +170,18 @@ function obj:draw(...)
love.graphics.pop()
end
-function obj:collision(collided, angle)
- self.force = {collided.data.vel[1] * math.cos(angle),
- collided.data.vel[2] * math.sin(angle)}
- self.torque = -collided.data.avel
- return self:overload("collision", collided, angle, self.force)
+function obj:collision(...)
+ return self:overload("collision", ...)
end
-function obj:collision_exit(collided, angle)
- self.data.vel[1] = self.data.vel[1] + self.force[1]
- self.data.vel[2] = self.data.vel[2] + self.force[2]
- collided.data.vel[1] = collided.data.vel[1] - self.force[1]
- collided.data.vel[2] = collided.data.vel[2] - self.force[2]
- self.data.avel = self.data.avel + self.torque
- collided.data.avel = collided.data.avel + self.torque
- return self:overload("collision_exit", collided, angle, self.force)
+function obj:collision_exit(...)
+ return self:overload("collision_exit", ...)
+end
+
+function obj:energy()
+ local vx, vy = unpack(self.data.vel)
+ local avel = self.data.avel
+ return 1 + avel*avel + vx*vx + vy*vy
end
function obj:in_hitbox(px, py)
diff --git a/util.lua b/util.lua
index a639ca2..24b4214 100644
--- a/util.lua
+++ b/util.lua
@@ -27,4 +27,8 @@ function M.deepcopy(t)
return dc(t)
end
+function M.rot(a, x, y)
+ return x*math.cos(a) - y*math.sin(a), x*math.sin(a) + y*math.cos(a)
+end
+
return M