forked from pyrex/chameleonic
Optimize raycast in sweep
This commit is contained in:
parent
0d0a2c41a7
commit
f052186c97
209
chameleonic.p8
209
chameleonic.p8
@ -102,13 +102,6 @@ function _mnmx(x,y)
|
||||
return x,y
|
||||
end
|
||||
|
||||
function _anch_eq(a0,a1)
|
||||
if (a0==nil) return a1==nil
|
||||
if (a1==nil) return false
|
||||
return a0.ax==a1.ax and a0.ay==a1.ay
|
||||
end
|
||||
function _anch_unpack(a0) return a0.ax,a0.ay end
|
||||
|
||||
|
||||
function _rast(
|
||||
xs,ys,x0,y0,x1,y1
|
||||
@ -145,6 +138,41 @@ function _rast(
|
||||
_add()
|
||||
end
|
||||
|
||||
-->8
|
||||
-- anchor operations (for the rope code)
|
||||
|
||||
function _anch_eq(a0,a1)
|
||||
if (a0 and a1) return a0[1]==a1[1] and a0[2]==a1[2]
|
||||
return a0==a1
|
||||
end
|
||||
--[[
|
||||
function _anch_unpack(anch)
|
||||
assert(anch[1])
|
||||
assert(anch[2])
|
||||
return anch[1],anch[2]
|
||||
end
|
||||
]]--
|
||||
_anch_unpack=unpack
|
||||
|
||||
function _anch_new(prev,next,xy)
|
||||
local out={prev=prev,next=next,_anch_unpack(xy)}
|
||||
if (prev) prev.next=out
|
||||
if (next) next.prev=out
|
||||
return out
|
||||
end
|
||||
|
||||
function _anch_del(n1,xy)
|
||||
local n0,n2=n1.prev,n1.next
|
||||
if (n0) n0.next=n2
|
||||
if (n2) n2.prev=n0
|
||||
end
|
||||
|
||||
function _anch_update(a0,a1)
|
||||
a0[1]=a1[1]
|
||||
a0[2]=a1[2]
|
||||
end
|
||||
|
||||
|
||||
|
||||
-->8
|
||||
-- input
|
||||
@ -380,7 +408,7 @@ function level:recollide_reanchor()
|
||||
) then
|
||||
local key="GEOM"..mx0..","..my0..","..dx..","..dy
|
||||
anch_new[key]= {
|
||||
ax=max(mx0,mx1),ay=max(my0,my1),adx=-dx,ady=-dy
|
||||
max(mx0,mx1),max(my0,my1),adx=-dx,ady=-dy
|
||||
}
|
||||
end
|
||||
end
|
||||
@ -391,7 +419,7 @@ function level:recollide_reanchor()
|
||||
local mx0,my0=cr.mx,cr.my
|
||||
local mx1,my1=mx0+dx,my0+dy
|
||||
anch_new[key]={
|
||||
ax=max(mx0,mx1),ay=max(my0,my1),adx=-dx,ady=-dy
|
||||
max(mx0,mx1),max(my0,my1),adx=-dx,ady=-dy
|
||||
}
|
||||
end
|
||||
end
|
||||
@ -406,12 +434,14 @@ function level:recollide_reanchor()
|
||||
end
|
||||
self._anch=anch_new
|
||||
self._anch_keys={}
|
||||
for k,_ in pairs(self._anch) do
|
||||
self._anch_by_position={}
|
||||
for k,v in pairs(self._anch) do
|
||||
add(self._anch_keys,{key=k})
|
||||
local pkey=_mix(_anch_unpack(v))
|
||||
self._anch_by_position[pkey]=self._anch_by_position[pkey] or v
|
||||
end
|
||||
shellsort(self._anch_keys)
|
||||
shellsort(moves)
|
||||
--printh("!!STARTING!!")
|
||||
|
||||
if player.rope then
|
||||
player.rope:experience_anchor_moves(moves)
|
||||
@ -436,9 +466,7 @@ function level:anchor_points()
|
||||
end
|
||||
|
||||
function level:anchor_at(point)
|
||||
for i in self:anchor_points() do
|
||||
if (_anch_eq(point,i)) return i
|
||||
end
|
||||
return self._anch_by_position[_mix(_anch_unpack(point))]
|
||||
end
|
||||
|
||||
function level:get_open_pit(mx,my)
|
||||
@ -492,10 +520,6 @@ function level:_mget(mx,my)
|
||||
)
|
||||
end
|
||||
|
||||
function _amix(ax,ay)
|
||||
return ax..","..ay
|
||||
end
|
||||
|
||||
function _mix(mx,my)
|
||||
return mx..","..my
|
||||
end
|
||||
@ -679,8 +703,8 @@ function player:update()
|
||||
while not level:mcoll(x,y) do x+=dx y+=dy end
|
||||
|
||||
self.rope=rope:new(
|
||||
{ax=x+0.5-dx*0.5,ay=y+0.5-dy*0.5},
|
||||
{ax=self.x+0.5,ay=self.y+0.5},
|
||||
{x+0.5-dx*0.5,y+0.5-dy*0.5},
|
||||
{self.x+0.5,self.y+0.5},
|
||||
level:get_latch(dx,dy,x*8,y*8)
|
||||
)
|
||||
|
||||
@ -707,10 +731,10 @@ function player:update()
|
||||
self.y=latch.rec.my+latch.dy
|
||||
end
|
||||
|
||||
self.rope:drag_dst(
|
||||
self.rope:drag_dst{
|
||||
self.x+self.px/8+0.5,
|
||||
self.y+self.py/8+0.5
|
||||
)
|
||||
}
|
||||
|
||||
local tdx,tdy=self.rope:tug_orientxy()
|
||||
if (tdx) self.orientx=tdx
|
||||
@ -858,10 +882,10 @@ function rope:update()
|
||||
if (not self.latch) wrongbleep:bleep(5) self:destroy() return
|
||||
|
||||
if self.latch.rec then
|
||||
self:drag_src(
|
||||
self:drag_src{
|
||||
self.latch.rec.mx+0.5+self.latch.ax_offset,
|
||||
self.latch.rec.my+0.5+self.latch.ay_offset
|
||||
)
|
||||
}
|
||||
|
||||
if self.latch.rec.dead==true then
|
||||
self:destroy()
|
||||
@ -1035,18 +1059,18 @@ function rope:draw(artificial_px,artificial_py)
|
||||
]]
|
||||
end
|
||||
|
||||
function rope:drag_dst(x,y)
|
||||
self:drag(self.dst,x,y)
|
||||
function rope:drag_dst(xy)
|
||||
self:drag(self.dst,xy)
|
||||
end
|
||||
|
||||
function rope:drag_src(x,y)
|
||||
self:drag(self.src,x,y)
|
||||
function rope:drag_src(xy)
|
||||
self:drag(self.src,xy)
|
||||
end
|
||||
|
||||
function rope:drag(n1,ax_new,ay_new)
|
||||
function rope:drag(n1,axy)
|
||||
self:relax()
|
||||
self:_drag(n1,{ax=ax_new,ay=n1.ay})
|
||||
self:_drag(n1,{ax=ax_new,ay=ay_new})
|
||||
self:_drag(n1,{axy[1],n1[2]})
|
||||
self:_drag(n1,axy)
|
||||
self:relax()
|
||||
end
|
||||
|
||||
@ -1057,8 +1081,7 @@ function rope:relax()
|
||||
if (not n1) break
|
||||
local n2=n1.next
|
||||
if _anch_eq(n0,n1) then
|
||||
n0.next=n2
|
||||
if (n2) n2.prev=n0
|
||||
_anch_del(n1)
|
||||
else
|
||||
n0=n0.next
|
||||
end
|
||||
@ -1072,15 +1095,10 @@ function rope:relax()
|
||||
if (not n2) return
|
||||
|
||||
local anch=level:anchor_at(n1)
|
||||
local wouldstick,axy_new=would_stick(anch,n0,n1,n2)
|
||||
if not (wouldstick or _anch_eq(n1,axy_new)) then
|
||||
self:_drag(n1,axy_new,{ax=n1.ax,ay=n1.ay})
|
||||
n0=n1.prev
|
||||
n2=n1.next
|
||||
n0.next=n2
|
||||
n2.prev=n0
|
||||
n1.next=nil
|
||||
n1.prev=nil
|
||||
local wouldstick,position_new=would_stick(anch,n0,n1,n2)
|
||||
if not (wouldstick or _anch_eq(n1,position_new)) then
|
||||
self:_drag(n1,position_new,{_anch_unpack(n1)})
|
||||
_anch_del(n1)
|
||||
else n0=n0.next end
|
||||
end
|
||||
end
|
||||
@ -1142,7 +1160,6 @@ function rope:_check_sane()
|
||||
|
||||
if dmx==1 and dmy==1 and level:mcoll(mx0,my2) and level:mcoll(mx2,my0) then
|
||||
else
|
||||
--printh("ok! "..tostring({qxs[i-2],qys[i-2]})..tostring({qxs[i],qys[i]})..tostring(m0)..tostring(m2))
|
||||
ok=true
|
||||
end
|
||||
end
|
||||
@ -1184,7 +1201,7 @@ function would_stick(anchor,xy0,xy1,xy2)
|
||||
|
||||
return
|
||||
anchor and anchor.adx==adx and anchor.ady==ady,
|
||||
{ax=x1_new,ay=y1_new}
|
||||
{x1_new,y1_new}
|
||||
end
|
||||
|
||||
function rope:experience_anchor_moves(moves)
|
||||
@ -1197,8 +1214,8 @@ function rope:_be_dragged_by(moves)
|
||||
local n=self.src
|
||||
while n do
|
||||
for t in all(moves) do
|
||||
local axy_old,axy_new=unpack(t)
|
||||
if (_anch_eq(axy_old,n)) n.dest=axy_new break
|
||||
local xy_old,xy_new=unpack(t)
|
||||
if (_anch_eq(xy_old,n)) n.dest=xy_new break
|
||||
end
|
||||
n=n.next
|
||||
end
|
||||
@ -1232,7 +1249,6 @@ function rope:_be_pushed_by1(anch_old,anch_new)
|
||||
local nxmn,nxmx = _mnmx(nx0,nx1)
|
||||
local nymn,nymx = _mnmx(ny0,ny1)
|
||||
|
||||
-- nprinth("has: "..tostring{anch==nil,n0==nil,n1==nil})
|
||||
if
|
||||
(ax_new!=ax_old or (nxmn<ax_new and ax_new<nxmx)) and
|
||||
(ay_new!=ay_old or (nymn<ay_new and ay_new<nymx)) and
|
||||
@ -1250,12 +1266,8 @@ function rope:_be_pushed_by1(anch_old,anch_new)
|
||||
nx05=nx0+(ny05-ny0)/(ny1-ny0) * (nx1-nx0)
|
||||
end
|
||||
|
||||
local n05={ax=nx05,ay=ny05,prev=n0,next=n1}
|
||||
n0.next=n05
|
||||
n1.prev=n05
|
||||
-- printh("creating: "..tostring{anch,{n0.ax,n0.ay},{n05.ax,n05.ay},{n1.ax,n1.ay}})
|
||||
-- printh("dragging: "..tostring{anch,{n05.ax,n05.ay},{ax_new,ay_new}})
|
||||
self:_drag(n05,{ax=ax_new,ay=ay_new})
|
||||
local n05=_anch_new(n0,n1,{nx05,ny05})
|
||||
self:_drag(n05,{ax_new,ay_new})
|
||||
else
|
||||
n0=n0.next
|
||||
end
|
||||
@ -1264,67 +1276,74 @@ end
|
||||
|
||||
function rope:_drag(n1,new,removing)
|
||||
local function _sweep_radar(lhs,rhs,pivot,src,dst)
|
||||
-- printh(tostring{{lhs.ax,lhs.ay},{rhs.ax,rhs.ay},{pivot.ax,pivot.ay},{src.ax,src.ay},{dst.ax,dst.ay}})
|
||||
if (_anch_eq(src,dst)) return
|
||||
|
||||
local function _uncreatable(anchor)
|
||||
return _anch_eq(anchor,lhs) or _anch_eq(anchor,lhs) or _anch_eq(anchor,removing)
|
||||
end
|
||||
|
||||
local function _sweep(extent_old,extent_new,cb_in_bounds,cb_would_stick,cb_side)
|
||||
for extent_new in _stepfrom(extent_old, extent_new) do
|
||||
for anchor in level:anchor_points() do
|
||||
if not _uncreatable(anchor) and cb_in_bounds(anchor) and
|
||||
cb_would_stick(anchor,extent_new) and
|
||||
cb_side(anchor,extent_old)!=cb_side(anchor,extent_new)
|
||||
then
|
||||
return anchor
|
||||
end
|
||||
local function _sweep(extent_orig,extent_final,cb_in_bounds,cb_make_point)
|
||||
local eligible={}
|
||||
local point_orig=cb_make_point(extent_orig)
|
||||
local point_final=cb_make_point(extent_final)
|
||||
|
||||
for anchor in level:anchor_points() do
|
||||
-- figure out which anchors we even can stick to
|
||||
if cb_in_bounds(anchor) and not _uncreatable(anchor) then
|
||||
local side_orig=_which_side(anchor,pivot,point_orig)
|
||||
local side_final=_which_side(anchor,pivot,point_final)
|
||||
|
||||
if (side_orig!=side_final and would_stick(anchor,pivot,nil,point_final)) add(eligible,{anchor,side_final})
|
||||
end
|
||||
end
|
||||
|
||||
-- if no one's in the race, don't raycast
|
||||
if (#eligible==0) return
|
||||
if (#eligible==1) return eligible[1][1]
|
||||
|
||||
-- see who wins the race
|
||||
for extent in _stepfrom(extent_orig,extent_final) do
|
||||
local point = cb_make_point(extent)
|
||||
for anchor_final in all(eligible) do
|
||||
if (_which_side(anchor_final[1],pivot,point)==anchor_final[2]) return anchor_final[1]
|
||||
end
|
||||
extent_old=extent_new
|
||||
end
|
||||
end
|
||||
|
||||
if src.ax==dst.ax then
|
||||
local ax_pivot,ax_dst=pivot.ax,dst.ax
|
||||
local ax_pivot,ay_pivot=_anch_unpack(pivot)
|
||||
local ax_src,ay_src=_anch_unpack(src)
|
||||
local ax_dst,ay_dst=_anch_unpack(dst)
|
||||
|
||||
if ax_src==ax_dst then
|
||||
return _sweep(
|
||||
src.ay,dst.ay,
|
||||
function(anchor) return mid(ax_pivot,anchor.ax,ax_dst)==anchor.ax end,
|
||||
function(anchor,ay) return would_stick(anchor,pivot,nil,{ax=ax_dst,ay=ay}) end,
|
||||
function(anchor,ay) return _which_side(anchor,pivot,{ax=ax_dst,ay=ay}) end
|
||||
ay_src,ay_dst,
|
||||
function(anchor) return mid(ax_pivot,anchor[1],ax_dst)==anchor[1] end,
|
||||
function(ay) return {ax_dst,ay} end
|
||||
)
|
||||
else
|
||||
local ay_pivot,ay_dst=pivot.ay,dst.ay
|
||||
return _sweep(
|
||||
src.ax,dst.ax,
|
||||
function(anchor) return mid(ay_pivot,anchor.ay,ay_dst)==anchor.ay end,
|
||||
function(anchor,ax) return would_stick(anchor,pivot,nil,{ax=ax,ay=ay_dst}) end,
|
||||
function(anchor,ax) return _which_side(anchor,pivot,{ax=ax,ay=ay_dst}) end
|
||||
ax_src,ax_dst,
|
||||
function(anchor) return mid(ay_pivot,anchor[2],ay_dst)==anchor[2] end,
|
||||
function(ax) return {ax,ay_dst} end
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
local old={ax=n1.ax,ay=n1.ay}
|
||||
n1.ax,n1.ay=new.ax,new.ay
|
||||
local old={_anch_unpack(n1)}
|
||||
_anch_update(n1,new)
|
||||
|
||||
local n0=n1.prev
|
||||
while n0 do
|
||||
local anch=_sweep_radar(n0,n1,n0,old,new)
|
||||
if (not anch) break
|
||||
local n05={ax=anch.ax,ay=anch.ay,prev=n0,next=n1}
|
||||
n0.next=n05
|
||||
n1.prev=n05
|
||||
n0=n05
|
||||
n0=_anch_new(n0,n1,anch)
|
||||
end
|
||||
|
||||
local n2=n1.next
|
||||
while n2 do
|
||||
local anch=_sweep_radar(n1,n2,n2,old,new)
|
||||
if (not anch) break
|
||||
local n15={ax=anch.ax,ay=anch.ay,prev=n1,next=n2}
|
||||
n1.next=n15
|
||||
n2.prev=n15
|
||||
n2=n15
|
||||
n2=_anch_new(n1,n2,anch)
|
||||
end
|
||||
end
|
||||
|
||||
@ -1337,9 +1356,7 @@ function _stepfrom(x0,x1)
|
||||
end
|
||||
end
|
||||
|
||||
local mul=0.5
|
||||
x0*=2
|
||||
x1*=2
|
||||
local mul=1
|
||||
if (x0>x1) x0,x1,mul=-x0,-x1,-mul
|
||||
local i=flr(x0)
|
||||
local top=flr(x1)
|
||||
@ -1359,7 +1376,6 @@ function _which_side(xy,x0y0,x1y1)
|
||||
local x,y=_anch_unpack(xy)
|
||||
local x0,y0=_anch_unpack(x0y0)
|
||||
local x1,y1=_anch_unpack(x1y1)
|
||||
-- printh("anchors: "..tostring{x,y,x0,y0,x1,y1})
|
||||
|
||||
return sgn0((x1-x0)*(y-y0) - (y1-y0)*(x-x0))
|
||||
end
|
||||
@ -1388,7 +1404,8 @@ function rope:collide_mrect(mx0,my0,mw,mh,exclude_src,exclude_dst)
|
||||
if (not nd) return
|
||||
end
|
||||
|
||||
local x1,y1,x2,y2=n0.ax,n0.ay,n1.ax,n1.ay
|
||||
local x1,y1=_anch_unpack(n0)
|
||||
local x2,y2=_anch_unpack(n1)
|
||||
local function _line_line(x3,y3,x4,y4)
|
||||
local denom=(y4-y3)*(x2-x1)-(x4-x3)*(y2-y1)
|
||||
|
||||
@ -1418,12 +1435,15 @@ end
|
||||
function rope:tug_orientxy()
|
||||
local a1=self.dst
|
||||
local a0=self.dst.prev
|
||||
local dx=a0.ax-a1.ax
|
||||
local ax0,ay0=_anch_unpack(a0)
|
||||
local ax1,ay1=_anch_unpack(a1)
|
||||
|
||||
local dx=ax0-ax1
|
||||
local tdx
|
||||
if (dx>3/8) tdx=1
|
||||
if (dx<-3/8) tdx=-1
|
||||
|
||||
local dy=a0.ay-a1.ay
|
||||
local dy=ay0-ay1
|
||||
local tdy
|
||||
if abs(dy)>abs(dx)/2 then
|
||||
if (dy>3/8) tdy=1
|
||||
@ -1608,9 +1628,10 @@ function rope:_anchors_simplified()
|
||||
end
|
||||
a=self.src
|
||||
while a do
|
||||
local ax,ay=_anch_unpack(a)
|
||||
local point={
|
||||
x=flr(a.ax*8+0.5),y=flr(a.ay*8+0.5),
|
||||
ax=a.ax,ay=a.ay
|
||||
ax,ay,
|
||||
x=flr(ax*8+0.5),y=flr(ay*8+0.5),
|
||||
}
|
||||
local aw=level:anchor_at(a)
|
||||
local l=self.latch
|
||||
|
Loading…
Reference in New Issue
Block a user