| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132 |
- local Collision = class()
- Collision.cellSize = 128
- local check = {}
- function Collision:init()
- self.hc = require 'lib/hc'
- ctx.event:on('collision.attach', f.cur(self.attach, self))
- ctx.event:on('collision.detach', f.cur(self.detach, self))
- ctx.event:on('collision.move', f.cur(self.move, self))
- end
- function Collision:attach(data)
- local obj = data.object
- local shape
- if obj.collision.shape == 'rectangle' then
- shape = self.hc.rectangle(obj.x, obj.y, obj.width, obj.height)
- elseif obj.collision.shape == 'circle' then
- shape = self.hc.circle(obj.x, obj.y, obj.radius)
- end
- obj.shape = shape
- shape.owner = obj
- return shape
- end
- function Collision:detach(data)
- self.hc.remove(data.object.shape)
- data.object.shape = nil
- end
- function Collision:move(data)
- local x, y = data.x or data.object.x, data.y or data.object.y
- if not x or not y then return end
- if data.object.collision.shape == 'rectangle' then
- x = x + data.object.width / 2
- y = y + data.object.height / 2
- end
- data.object.shape:moveTo(x, y)
- if data.resolve then
- self:resolve(data.object)
- end
- end
- function Collision:resolve(object)
- local a = object
- local check = {}
- for other, vector in pairs(self.hc.collisions(object.shape)) do
- local b, dx, dy = other.owner, vector.x, vector.y
- f.exe(a.collision.with and a.collision.with[b.collision.tag], a, b, dx, dy)
- f.exe(b.collision.with and b.collision.with[a.collision.tag], b, a, -dx, -dy)
- end
- end
- function Collision:pointTest(x, y, options)
- options = options or {}
- local tag, fn = options.tag, options.fn
- local detector = self.hc.point(x, y)
- for _, shape in pairs(self.hc.collisions(detector)) do
- if not tag or shape.owner.collision.tag == tag then
- if not fn or fn(shape.owner) then
- self.hc.remove(detector)
- return shape.owner
- end
- end
- end
- self.hc.remove(detector)
- return nil
- end
- function Collision:lineTest(x1, y1, x2, y2, options)
- local dis = math.distance(x1, y1, x2, y2)
- local _x1, _y1 = math.min(x1, x2), math.min(y1, y2)
- local _x2, _y2 = math.max(x1, x2), math.max(y1, y2)
- local tag, fn, first, all = options.tag, options.fn, options.first, options.all
- local mindis = first and math.huge or nil
- local res = all and {} or nil
- for shape in pairs(self.hc:hash():shapes()) do
- if (not tag) or shape.owner.collision.tag == tag then
- local intersects, d = shape:intersectsRay(x1, y1, x2 - x1, y2 - y1)
- if intersects and d >= 0 and d <= 1 then
- if (not fn) or fn(shape.owner) then
- if not first then
- if all then
- table.insert(res, shape.owner)
- else
- return shape.owner, d * dis
- end
- elseif d * dis < mindis then
- mindis = d * dis
- res = shape.owner
- end
- end
- end
- end
- end
- return res, first and mindis or nil
- end
- function Collision:circleTest(x, y, r, options)
- local detector = self.hc.circle(x, y, r)
- local tag, fn, all = options.tag, options.fn, options.all
- local res = all and {} or nil
- for shape in pairs(self.hc.collisions(detector)) do
- if (not tag) or shape.owner.collision.tag == tag then
- if (not fn) or fn(shape.owner) then
- if all then
- table.insert(res, shape.owner)
- else
- self.hc.remove(detector)
- return shape.owner
- end
- end
- end
- end
- self.hc.remove(detector)
- return res
- end
- return Collision
|