Cache for collision checks
This commit is contained in:
parent
f67b617a78
commit
27692ba208
280
chameleonic.p8
280
chameleonic.p8
@ -112,6 +112,73 @@ function _mnmx(x,y)
|
|||||||
return x,y
|
return x,y
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function _rastn(
|
||||||
|
x0,y0,x1,y1,dx,dy
|
||||||
|
)
|
||||||
|
-- todo: more optimized implementation?
|
||||||
|
local iter=_rast(x0,y0,x1,y1)
|
||||||
|
local prevx,prevy=nil,nil
|
||||||
|
|
||||||
|
local done=false
|
||||||
|
return function()
|
||||||
|
while not done do
|
||||||
|
local x,y=iter()
|
||||||
|
|
||||||
|
if (x==nil) done=true return x1, y1
|
||||||
|
|
||||||
|
local x8 = x\dx
|
||||||
|
local y8 = y\dy
|
||||||
|
if not (x8==prevx and y8==prevy) then
|
||||||
|
prevx,prevy=x8,y8
|
||||||
|
return x,y
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function _rast(
|
||||||
|
x0,y0,x1,y1
|
||||||
|
)
|
||||||
|
local dx=abs(x1-x0)
|
||||||
|
local dy=abs(y1-y0)
|
||||||
|
local x=x0
|
||||||
|
local y=y0
|
||||||
|
|
||||||
|
local sx=-1
|
||||||
|
local sy=-1
|
||||||
|
if (x0<x1) sx=1
|
||||||
|
if (y0<y1) sy=1
|
||||||
|
|
||||||
|
local done=false,err
|
||||||
|
if dx>dy then
|
||||||
|
err=dx/2.0
|
||||||
|
return function()
|
||||||
|
if (done) return
|
||||||
|
if (x==x1) done=true return x1,y1
|
||||||
|
local oldx,oldy=x,y
|
||||||
|
err-=dy
|
||||||
|
if (err<0) y+=sy err+=dx+dy return oldx,y
|
||||||
|
x+=sx
|
||||||
|
return oldx,oldy
|
||||||
|
end
|
||||||
|
else
|
||||||
|
err=dy/2.0
|
||||||
|
return function()
|
||||||
|
if (done) return
|
||||||
|
if (y==y1) done=true return x1,y1
|
||||||
|
local oldx,oldy=x,y
|
||||||
|
err-=dx
|
||||||
|
if (err<0) x+=sx err+=dy+dx return x,oldy
|
||||||
|
y+=sy
|
||||||
|
return oldx,oldy
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function _point_eq(p1,p2)
|
||||||
|
return p1.x==p2.x and p1.y==p2.y
|
||||||
|
end
|
||||||
|
|
||||||
-->8
|
-->8
|
||||||
-- input
|
-- input
|
||||||
kbd={}
|
kbd={}
|
||||||
@ -222,6 +289,7 @@ function level:reinit(n)
|
|||||||
self.todo={}
|
self.todo={}
|
||||||
self.bigx=(n%8)
|
self.bigx=(n%8)
|
||||||
self.bigy=(n\8)
|
self.bigy=(n\8)
|
||||||
|
self.cache_can_stretch=dcache:new()
|
||||||
|
|
||||||
self:load_dynobjs()
|
self:load_dynobjs()
|
||||||
self:recollide()
|
self:recollide()
|
||||||
@ -335,6 +403,7 @@ function level:recollide()
|
|||||||
self._crates[mxy]!=nil
|
self._crates[mxy]!=nil
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
self.cache_can_stretch:clear()
|
||||||
end
|
end
|
||||||
|
|
||||||
function add_adjacent_anchors(tbl,mx,my)
|
function add_adjacent_anchors(tbl,mx,my)
|
||||||
@ -588,6 +657,75 @@ function level:tug_crate(mx0,my0,dmx,dmy)
|
|||||||
self:recollide()
|
self:recollide()
|
||||||
self:reanchor(false)
|
self:reanchor(false)
|
||||||
end
|
end
|
||||||
|
-->8
|
||||||
|
-- collision checks
|
||||||
|
function level:can_stretch(
|
||||||
|
p1,p2
|
||||||
|
)
|
||||||
|
local key=p1.x..","..p1.y..","..p2.x..","..p2.y
|
||||||
|
return self.cache_can_stretch:wrap(key,function()
|
||||||
|
return self:_can_stretch(p1,p2)
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
function level:_can_stretch(
|
||||||
|
p1,p2
|
||||||
|
)
|
||||||
|
-- faster implementation for straight lines
|
||||||
|
if p1.y\8==p2.y\8 then
|
||||||
|
local my=p2.y\8
|
||||||
|
for mx=p1.x\8,p2.x\8 do
|
||||||
|
if (level:mcoll(mx,my)) return false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if p1.x\8==p2.x\8 then
|
||||||
|
local mx=p2.x\8
|
||||||
|
for my=p1.y\8,p2.y\8 do
|
||||||
|
if (level:mcoll(mx,my)) return false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if (level:pcoll(p1.x,p1.y)) return false
|
||||||
|
if (level:pcoll(p2.x,p2.y)) return false
|
||||||
|
|
||||||
|
local res=true
|
||||||
|
for x,y in _rastn(p1.x,p1.y,p2.x,p2.y,8,8) do
|
||||||
|
if level:pcoll(x,y) then
|
||||||
|
res=false
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return res
|
||||||
|
end
|
||||||
|
|
||||||
|
-->8
|
||||||
|
--cache impl for collision checks
|
||||||
|
dcache={}
|
||||||
|
dcache.__index=dcache
|
||||||
|
|
||||||
|
function dcache:new()
|
||||||
|
local d={}
|
||||||
|
setmetatable(d,dcache)
|
||||||
|
d:clear()
|
||||||
|
return d
|
||||||
|
end
|
||||||
|
function dcache:clear()
|
||||||
|
self.old,self.new,self.new_n={},{},0
|
||||||
|
end
|
||||||
|
|
||||||
|
function dcache:wrap(key,f)
|
||||||
|
local el=self.new[key]
|
||||||
|
if (el!=nil) return el
|
||||||
|
local el=self.old[key]
|
||||||
|
if (el==nil) el=f()
|
||||||
|
self.new[key]=el
|
||||||
|
self.new_n+=1
|
||||||
|
if (self.new_n>1000) self.old,self.new,self.new_n=self.new,{},0
|
||||||
|
return el
|
||||||
|
end
|
||||||
|
|
||||||
-->8
|
-->8
|
||||||
--player handling
|
--player handling
|
||||||
player={}
|
player={}
|
||||||
@ -905,7 +1043,7 @@ function rope:continue_cast()
|
|||||||
local x1=x0+dx
|
local x1=x0+dx
|
||||||
local y1=y0+dy
|
local y1=y0+dy
|
||||||
|
|
||||||
for x,y in self:_rast(
|
for x,y in _rast(
|
||||||
x0,y0,x1,y1
|
x0,y0,x1,y1
|
||||||
) do
|
) do
|
||||||
local latch=
|
local latch=
|
||||||
@ -986,14 +1124,14 @@ function rope:draw(artificial_dx,artificial_dy)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
--[[
|
|
||||||
for i=0,#self.ancs+1 do
|
for i=0,#self.ancs+1 do
|
||||||
p=self:_anc(i)
|
p=self:_anc(i)
|
||||||
local c=12
|
local c=12
|
||||||
if (p.dirty) c=13
|
if (p.dirty) c=13
|
||||||
rectfill(p.x-1,p.y-1,p.x+1,p.y+1,c)
|
rectfill(p.x-1,p.y-1,p.x+1,p.y+1,c)
|
||||||
print(tostr(p.id)..":"..p.x..","..p.y..","..#p.todo,0,i*8,9)
|
print(tostr(p.id)..":"..p.x..","..p.y..","..#p.todo,0,i*8,12)
|
||||||
end
|
end
|
||||||
|
--[[
|
||||||
for _,p in pairs(level._anch) do
|
for _,p in pairs(level._anch) do
|
||||||
pset(p.x,p.y,11)
|
pset(p.x,p.y,11)
|
||||||
end
|
end
|
||||||
@ -1029,7 +1167,7 @@ function rope:drag(
|
|||||||
local anc=self:_anc(i())
|
local anc=self:_anc(i())
|
||||||
local busy=self:busy()
|
local busy=self:busy()
|
||||||
|
|
||||||
for x,y in self:_rast(
|
for x,y in _rast(
|
||||||
anc.x,anc.y,x,y
|
anc.x,anc.y,x,y
|
||||||
) do
|
) do
|
||||||
local a=self:_anc(i())
|
local a=self:_anc(i())
|
||||||
@ -1038,8 +1176,6 @@ function rope:drag(
|
|||||||
a.y=y
|
a.y=y
|
||||||
a.dirty=true
|
a.dirty=true
|
||||||
self.dirty=true
|
self.dirty=true
|
||||||
--self:_find_needed_anchors(i())
|
|
||||||
--self:_find_needed_anchors(i()+1)
|
|
||||||
if (not busy) self:_tidy_up_gen()
|
if (not busy) self:_tidy_up_gen()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -1050,7 +1186,7 @@ function rope:make_dirty(only_if_invalid)
|
|||||||
for a=0,#self.ancs do
|
for a=0,#self.ancs do
|
||||||
local a0=self:_anc(a)
|
local a0=self:_anc(a)
|
||||||
local a1=self:_anc(a+1)
|
local a1=self:_anc(a+1)
|
||||||
if not self:_can_stretch(a0,a1) then
|
if not level:can_stretch(a0,a1) then
|
||||||
a0.dirty=true
|
a0.dirty=true
|
||||||
a1.dirty=true
|
a1.dirty=true
|
||||||
invalid=true
|
invalid=true
|
||||||
@ -1075,6 +1211,7 @@ function rope:_tidy_up_gen()
|
|||||||
anc.seen=true
|
anc.seen=true
|
||||||
if self[f](self,a,busy) then
|
if self[f](self,a,busy) then
|
||||||
settled=false anc.changed=true
|
settled=false anc.changed=true
|
||||||
|
a=0
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
a+=1
|
a+=1
|
||||||
@ -1127,7 +1264,7 @@ function rope:_tidy_up_gen()
|
|||||||
for i=0,#self.ancs do
|
for i=0,#self.ancs do
|
||||||
local a0=self:_anc(i)
|
local a0=self:_anc(i)
|
||||||
local a1=self:_anc(i+1)
|
local a1=self:_anc(i+1)
|
||||||
if not self:_can_stretch(a0,a1) then
|
if not level:can_stretch(a0,a1) then
|
||||||
self:destroy()
|
self:destroy()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -1144,7 +1281,7 @@ function rope:_find_needed_anchors(i,busy)
|
|||||||
|
|
||||||
if (level:pcoll(a2.x,a2.y)) return false
|
if (level:pcoll(a2.x,a2.y)) return false
|
||||||
if (level:pcoll(a0.x,a0.y)) return false
|
if (level:pcoll(a0.x,a0.y)) return false
|
||||||
if (self:_can_stretch(a0,a2)) return false
|
if (level:can_stretch(a0,a2)) return false
|
||||||
|
|
||||||
local anchors_bydist={}
|
local anchors_bydist={}
|
||||||
local x0,x2=_mnmx(a0.x,a2.x)
|
local x0,x2=_mnmx(a0.x,a2.x)
|
||||||
@ -1156,8 +1293,8 @@ function rope:_find_needed_anchors(i,busy)
|
|||||||
|
|
||||||
for a1 in all(anchors_bydist) do
|
for a1 in all(anchors_bydist) do
|
||||||
a1=a1.el
|
a1=a1.el
|
||||||
if self:_can_stretch(a0,a1) and
|
if level:can_stretch(a0,a1) and
|
||||||
self:_can_stretch(a1,a2)
|
level:can_stretch(a1,a2)
|
||||||
then
|
then
|
||||||
local id=self.id
|
local id=self.id
|
||||||
add(self.ancs,{id=id,x=a1.x,y=a1.y,dirty=true,todo={}},i)
|
add(self.ancs,{id=id,x=a1.x,y=a1.y,dirty=true,todo={}},i)
|
||||||
@ -1179,12 +1316,11 @@ function rope:_find_touched_anchors(i)
|
|||||||
if (level:pcoll(a0.x,a0.y)) return false
|
if (level:pcoll(a0.x,a0.y)) return false
|
||||||
if (level:pcoll(a2.x,a2.y)) return false
|
if (level:pcoll(a2.x,a2.y)) return false
|
||||||
|
|
||||||
for bx,by in self:_rast(a0.x,a0.y,a2.x,a2.y) do
|
for bx,by in _rast(a0.x,a0.y,a2.x,a2.y) do
|
||||||
local a1=level:point_anchor(bx,by)
|
local a1=level:point_anchor(bx,by)
|
||||||
if
|
if
|
||||||
a1!=nil and not _point_eq(a0,a1) and not _point_eq(a1,a2)
|
a1!=nil and not _point_eq(a0,a1) and not _point_eq(a1,a2)
|
||||||
and _linedist(a0,a1,a2)<ELIDE_POINT
|
and _linedist(a0,a1,a2)<ELIDE_POINT
|
||||||
-- and self:_can_stretch(p,a2)
|
|
||||||
then
|
then
|
||||||
local id=self.id
|
local id=self.id
|
||||||
add(self.ancs,{id=id,x=a1.x,y=a1.y,dirty=true,todo={}},i)
|
add(self.ancs,{id=id,x=a1.x,y=a1.y,dirty=true,todo={}},i)
|
||||||
@ -1212,7 +1348,7 @@ function rope:_elide_point(i,busy)
|
|||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
if not self:_can_stretch(a0,a2) then
|
if not level:can_stretch(a0,a2) then
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -1233,26 +1369,21 @@ function rope:_elide_point(i,busy)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function rope:_can_move_midpoint(a0,a1_0,a1_1,a2)
|
function rope:_can_move_midpoint(a0,a1_0,a1_1,a2)
|
||||||
if (level:pcoll(a0.x,a0.y)) return false
|
if not level:can_stretch(a1_0, a1_1) then
|
||||||
if (level:pcoll(a2.x,a2.y)) return false
|
|
||||||
if (level:pcoll(a1_0.x,a1_0.y)) return false
|
|
||||||
if (level:pcoll(a1_1.x,a1_1.y)) return false
|
|
||||||
|
|
||||||
if not self:_can_stretch(a1_0, a1_1) then
|
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
if not self:_can_stretch(a0,a1_1) then
|
if not level:can_stretch(a0,a1_1) then
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
if not self:_can_stretch(a1_1,a2) then
|
if not level:can_stretch(a1_1,a2) then
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
for x,y in self:_rastn(a1_0.x,a1_0.y,a1_1.x,a1_1.y,8,8) do
|
for x,y in _rastn(a1_0.x,a1_0.y,a1_1.x,a1_1.y,8,8) do
|
||||||
local tm={x=x,y=y}
|
local tm={x=x,y=y}
|
||||||
if not self:_can_stretch(a0,tm) then
|
if not level:can_stretch(a0,tm) then
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
if not self:_can_stretch(tm,a2) then
|
if not level:can_stretch(tm,a2) then
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -1304,105 +1435,6 @@ function _line_line(x1,y1,x2,y2,x3,y3,x4,y4)
|
|||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
function rope:_can_stretch(
|
|
||||||
p1,p2
|
|
||||||
)
|
|
||||||
-- faster implementation for straight lines
|
|
||||||
if p1.y\8==p2.y\8 then
|
|
||||||
local my=p2.y\8
|
|
||||||
for mx=p1.x\8,p2.x\8 do
|
|
||||||
if (level:mcoll(mx,my)) return false
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if p1.x\8==p2.x\8 then
|
|
||||||
local mx=p2.x\8
|
|
||||||
for my=p1.y\8,p2.y\8 do
|
|
||||||
if (level:mcoll(mx,my)) return false
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if (level:pcoll(p1.x,p1.y)) return false
|
|
||||||
if (level:pcoll(p2.x,p2.y)) return false
|
|
||||||
|
|
||||||
local res=true
|
|
||||||
for x,y in self:_rastn(p1.x,p1.y,p2.x,p2.y,8,8) do
|
|
||||||
if level:pcoll(x,y) then
|
|
||||||
res=false
|
|
||||||
break
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
return res
|
|
||||||
end
|
|
||||||
|
|
||||||
function rope:_rastn(
|
|
||||||
x0,y0,x1,y1,dx,dy
|
|
||||||
)
|
|
||||||
-- todo: more optimized implementation?
|
|
||||||
local iter=self:_rast(x0,y0,x1,y1)
|
|
||||||
local prevx,prevy=nil,nil
|
|
||||||
|
|
||||||
local done=false
|
|
||||||
return function()
|
|
||||||
while not done do
|
|
||||||
local x,y=iter()
|
|
||||||
|
|
||||||
if (x==nil) done=true return x1, y1
|
|
||||||
|
|
||||||
local x8 = x\dx
|
|
||||||
local y8 = y\dy
|
|
||||||
if not (x8==prevx and y8==prevy) then
|
|
||||||
prevx,prevy=x8,y8
|
|
||||||
return x,y
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function rope:_rast(
|
|
||||||
x0,y0,x1,y1
|
|
||||||
)
|
|
||||||
local dx=abs(x1-x0)
|
|
||||||
local dy=abs(y1-y0)
|
|
||||||
local x=x0
|
|
||||||
local y=y0
|
|
||||||
|
|
||||||
local sx=-1
|
|
||||||
local sy=-1
|
|
||||||
if (x0<x1) sx=1
|
|
||||||
if (y0<y1) sy=1
|
|
||||||
|
|
||||||
local done=false,err
|
|
||||||
if dx>dy then
|
|
||||||
err=dx/2.0
|
|
||||||
return function()
|
|
||||||
if (done) return
|
|
||||||
if (x==x1) done=true return x1,y1
|
|
||||||
local oldx,oldy=x,y
|
|
||||||
err-=dy
|
|
||||||
if (err<0) y+=sy err+=dx+dy return oldx,y
|
|
||||||
x+=sx
|
|
||||||
return oldx,oldy
|
|
||||||
end
|
|
||||||
else
|
|
||||||
err=dy/2.0
|
|
||||||
return function()
|
|
||||||
if (done) return
|
|
||||||
if (y==y1) done=true return x1,y1
|
|
||||||
local oldx,oldy=x,y
|
|
||||||
err-=dx
|
|
||||||
if (err<0) x+=sx err+=dy+dx return x,oldy
|
|
||||||
y+=sy
|
|
||||||
return oldx,oldy
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function _point_eq(p1,p2)
|
|
||||||
return p1.x==p2.x and p1.y==p2.y
|
|
||||||
end
|
|
||||||
|
|
||||||
function neighbors(p)
|
function neighbors(p)
|
||||||
local r={}
|
local r={}
|
||||||
for dx=-1,1,1 do
|
for dx=-1,1,1 do
|
||||||
|
Loading…
Reference in New Issue
Block a user