delete linked lists and use optimized array impls.
Also removes "suppress" table from collider, use candidate.dead instead because the set of dead ships and the set of non-colliding ships is identical.
This commit is contained in:
		
							
								
								
									
										209
									
								
								vacuum_gambit.p8
									
									
									
									
									
								
							
							
						
						
									
										209
									
								
								vacuum_gambit.p8
									
									
									
									
									
								
							| @@ -59,90 +59,48 @@ function mknew(tt) | |||||||
|  return tt |  return tt | ||||||
| end | end | ||||||
|  |  | ||||||
| -- intrusive singly-linked list. | -- call f on everything on list | ||||||
| -- cannot be nested or crossed! | -- and return a new list of | ||||||
| linked_list = mknew{ | -- items for which f was false. | ||||||
|  is_linked_list=true, | function stripped(list, f) | ||||||
|  init = function(x) |  local ret, n = {}, 0 | ||||||
|   x.next=nil |  for i=1,#list do | ||||||
|   x.tail=x |   local v = list[i] | ||||||
|  end, |   if not f(v) then | ||||||
| } |    n += 1 | ||||||
|  |    ret[n] = v | ||||||
| function linked_list:push_back(x) |   end | ||||||
|  self.tail.next = x |  end | ||||||
|  self.tail = x |  return ret | ||||||
| end | end | ||||||
|  |  | ||||||
| function linked_list:push_front(x) | -- call :move on everything on | ||||||
|  if (not self.next) self.tail = x | -- src and dump everything | ||||||
|  x.next = self.next | -- for which it returned false | ||||||
|  self.next = x | -- onto dest. | ||||||
|  | function appendmove(dest, src) | ||||||
|  |  local n = #dest | ||||||
|  |  for i=1, #src do | ||||||
|  |   local v = src[i] | ||||||
|  |   if not v:move() then | ||||||
|  |    n += 1 | ||||||
|  |    dest[n] = v | ||||||
|   end |   end | ||||||
|  |  | ||||||
| -- vore eats another linked list |  | ||||||
| -- by appending its contents. |  | ||||||
| -- the ingested linked is empty. |  | ||||||
| function linked_list:vore(x) |  | ||||||
|  if (not x.next) return |  | ||||||
|  self.tail.next = x.next |  | ||||||
|  self.tail = x.tail |  | ||||||
|  x.next = nil |  | ||||||
|  x.tail = x |  | ||||||
| end |  | ||||||
|  |  | ||||||
| -- strip calls f(x) for each |  | ||||||
| -- node, removing each node for |  | ||||||
| -- which f(x) returns true. |  | ||||||
| function linked_list:strip(f) |  | ||||||
|  local p, n = self, self.next |  | ||||||
|  while n do |  | ||||||
|   if f(n) then |  | ||||||
|    p.next = n.next |  | ||||||
|   else |  | ||||||
|    p = n |  | ||||||
|   end |  | ||||||
|   n = n.next |  | ||||||
|  end |  | ||||||
|  self.tail = p |  | ||||||
| end |  | ||||||
|  |  | ||||||
| -- stripmove calls x:move() for |  | ||||||
| -- each node, removing each node |  | ||||||
| -- for which x:move() is true. |  | ||||||
| function linked_list:stripmove() |  | ||||||
|  local p, n = self, self.next |  | ||||||
|  while n do |  | ||||||
|   if n:move() then |  | ||||||
|    p.next = n.next |  | ||||||
|   else |  | ||||||
|    p = n |  | ||||||
|   end |  | ||||||
|   n = n.next |  | ||||||
|  end |  | ||||||
|  self.tail = p |  | ||||||
| end |  | ||||||
|  |  | ||||||
| -- optimized special case - |  | ||||||
| -- could be done with strip but |  | ||||||
| -- this avoids extra function |  | ||||||
| -- calls and comparisions since |  | ||||||
| -- draw isn't allowed to kill |  | ||||||
| -- the item |  | ||||||
| function linked_list:draw() |  | ||||||
|  local n = self.next |  | ||||||
|  while n do |  | ||||||
|   n:draw() |  | ||||||
|   n = n.next |  | ||||||
|  end |  end | ||||||
| end | end | ||||||
|  |  | ||||||
|  | -- like stripped, but calls | ||||||
| function linked_list:pop_front() | -- :move on stuff in the list | ||||||
|  local ret = self.next | -- instead of taking a func arg. | ||||||
|  if (not ret) return | function stripmoved(list) | ||||||
|  self.next = ret.next |  local ret, n = {}, 0 | ||||||
|  if (not ret.next) ret.tail = nil |  for i=1,#list do | ||||||
|  |   local v = list[i] | ||||||
|  |   if not v:move() then | ||||||
|  |    n += 1 | ||||||
|  |    ret[n] = v | ||||||
|  |   end | ||||||
|  |  end | ||||||
|  return ret |  return ret | ||||||
| end | end | ||||||
|  |  | ||||||
| @@ -156,12 +114,12 @@ function _init() | |||||||
| end | end | ||||||
|  |  | ||||||
| function once_next_frame(f) | function once_next_frame(f) | ||||||
|  new_events:push_back{ |  add(new_events, { | ||||||
|   move = function() |   move = function() | ||||||
|    f() |    f() | ||||||
|    return true |    return true | ||||||
|   end, |   end, | ||||||
|  } |  }) | ||||||
| end | end | ||||||
|  |  | ||||||
| -- health gradients for 1..5 hp | -- health gradients for 1..5 hp | ||||||
| @@ -182,13 +140,13 @@ function wipe_game() | |||||||
|  xpwhoosh = nil |  xpwhoosh = nil | ||||||
|  primary_ship = player.new() |  primary_ship = player.new() | ||||||
|  init_hpcols() |  init_hpcols() | ||||||
|  eships = linked_list.new() |  eships = {} | ||||||
|  pbullets = linked_list.new() |  pbullets ={} | ||||||
|  ebullets = linked_list.new() |  ebullets ={} | ||||||
|  intangibles_fg = linked_list.new() |  intangibles_fg = {} | ||||||
|  intangibles_bg = linked_list.new() |  intangibles_bg = {} | ||||||
|  events = linked_list.new() |  events = {} | ||||||
|  new_events = linked_list.new() |  new_events = {} | ||||||
| 	primary_ship.main_gun = zap_gun_p.new() | 	primary_ship.main_gun = zap_gun_p.new() | ||||||
|  primary_ship.main_gun:peel() |  primary_ship.main_gun:peel() | ||||||
|  gframe = 0 |  gframe = 0 | ||||||
| @@ -241,10 +199,11 @@ function updategame() | |||||||
|   current_wave = flotilla.new() |   current_wave = flotilla.new() | ||||||
|   current_wave:load(rnd() > 0.5 and 7 or 0, 0, min(ones(waves_complete)\2, 4)) |   current_wave:load(rnd() > 0.5 and 7 or 0, 0, min(ones(waves_complete)\2, 4)) | ||||||
|  end |  end | ||||||
|  events:vore(new_events) |  events = stripmoved(events) | ||||||
|  for _, lst in ipairs{events, intangibles_bg, eships} do |  appendmove(events, new_events) | ||||||
|   lst:stripmove() |  new_events = {} | ||||||
|  end |  intangibles_big = stripmoved(intangibles_bg) | ||||||
|  |  eships = stripmoved(eships) | ||||||
|  |  | ||||||
| 	-- eship collider will be used | 	-- eship collider will be used | ||||||
|  -- both for pship and pbullets. |  -- both for pship and pbullets. | ||||||
| @@ -255,9 +214,9 @@ function updategame() | |||||||
|   local pbox = hurtbox(ps) |   local pbox = hurtbox(ps) | ||||||
|   for es in eship_collider:iterate_collisions(pbox) do |   for es in eship_collider:iterate_collisions(pbox) do | ||||||
|    ps:hitship(es) |    ps:hitship(es) | ||||||
|    if(es:hitship(ps)) eship_collider:yoink(es) |    es:hitship(ps) | ||||||
|   end |   end | ||||||
|   ebullets:strip(function(eb) |   ebullets = stripped(ebullets, function(eb) | ||||||
|    if (eb:move()) return true |    if (eb:move()) return true | ||||||
|    if (not collides(pbox, hurtbox(eb))) return |    if (not collides(pbox, hurtbox(eb))) return | ||||||
|    ps:hitbullet(eb) |    ps:hitbullet(eb) | ||||||
| @@ -267,17 +226,17 @@ function updategame() | |||||||
|   ebullets:stripmove() |   ebullets:stripmove() | ||||||
|  end |  end | ||||||
|  |  | ||||||
|  pbullets:strip(function(pb) |  pbullets = stripped(pbullets, function(pb) | ||||||
|   if (pb:move()) return true |   if (pb:move()) return true | ||||||
|   for es in eship_collider:iterate_collisions(hurtbox(pb)) do |   for es in eship_collider:iterate_collisions(hurtbox(pb)) do | ||||||
|    if (es:hitbullet(pb)) eship_collider:yoink(es) |    es:hitbullet(pb) | ||||||
|    if (pb:hitship(es)) return true |    if (pb:hitship(es)) return true | ||||||
|   end |   end | ||||||
|  end) |  end) | ||||||
|   |   | ||||||
|  intangibles_fg:stripmove() |  intangibles_fg:stripmove() | ||||||
|  |  | ||||||
| 	if waves_complete == 32767 and not eships.next and not ebullets.next and not events.next then | 	if waves_complete == 32767 and #eships == 0 and #ebullets == 0 and #events == 0 then | ||||||
| 	  game_state = win | 	  game_state = win | ||||||
| 	end | 	end | ||||||
| 	if (ps.dead) game_state = lose | 	if (ps.dead) game_state = lose | ||||||
| @@ -345,15 +304,6 @@ function puke(item, indent, seen, hidekey) | |||||||
|  end |  end | ||||||
|  local xpfx = pfx.." " |  local xpfx = pfx.." " | ||||||
|  |  | ||||||
|  if item.is_linked_list then |  | ||||||
|   local ret,n = "linked_list <",0 |  | ||||||
|   item:strip(function(x) |  | ||||||
|    n += 1 |  | ||||||
|    ret ..= xpfx..tostr(n)..": "..puke(x, indent+2, seen, "next") |  | ||||||
|   end) |  | ||||||
|   return ret..pfx..">" |  | ||||||
|  end |  | ||||||
|  |  | ||||||
|  local ret = "{" |  local ret = "{" | ||||||
|  for k, v in pairs(item) do |  for k, v in pairs(item) do | ||||||
|   if (k ~= hidekey) ret ..= xpfx..tostr(k)..": "..puke(v, indent+2, seen) |   if (k ~= hidekey) ret ..= xpfx..tostr(k)..": "..puke(v, indent+2, seen) | ||||||
| @@ -373,8 +323,10 @@ end | |||||||
| function drawgame() | function drawgame() | ||||||
|  clip(0,0,112,128) |  clip(0,0,112,128) | ||||||
|  rectfill(0,0,112,128,0) |  rectfill(0,0,112,128,0) | ||||||
|  for drawable in all{intangibles_bg, pbullets, primary_ship, eships, ebullets, intangibles_fg} do |  for drawables in all{intangibles_bg, pbullets, {primary_ship}, eships, ebullets, intangibles_fg} do | ||||||
|   drawable:draw() |   for item in all(drawables) do | ||||||
|  |    item:draw() | ||||||
|  |   end | ||||||
|  end |  end | ||||||
|  clip(0,0,128,128) |  clip(0,0,128,128) | ||||||
|  drawhud() |  drawhud() | ||||||
| @@ -586,6 +538,7 @@ function ship_m:constrain(p, dp, pmin, pmax, want) | |||||||
| end | end | ||||||
|  |  | ||||||
| function ship_m:move() | function ship_m:move() | ||||||
|  |  if (self.dead) return true; | ||||||
|  self:refresh_shield() |  self:refresh_shield() | ||||||
|  local dx, dy, shoot_spec1, shoot_spec2 = self:act() |  local dx, dy, shoot_spec1, shoot_spec2 = self:act() | ||||||
|  local sg, xm, ym = self.special_guns, self.xmomentum, self.ymomentum |  local sg, xm, ym = self.special_guns, self.xmomentum, self.ymomentum | ||||||
| @@ -842,7 +795,7 @@ end | |||||||
| function bullet_base:spawn_at(x, y) | function bullet_base:spawn_at(x, y) | ||||||
|  self.x = x - self.x_off |  self.x = x - self.x_off | ||||||
|  self.y = y - self.y_off |  self.y = y - self.y_off | ||||||
|  self.category():push_back(self) |  add(self.category(), self) | ||||||
| end | end | ||||||
|  |  | ||||||
| function gun_base:shoot(x, y) | function gun_base:shoot(x, y) | ||||||
| @@ -954,7 +907,7 @@ blast = mknew(bullet_base.new{ | |||||||
|   if self.damage > 0 and not self.awaitcancel then |   if self.damage > 0 and not self.awaitcancel then | ||||||
|    self.awaitcancel = true |    self.awaitcancel = true | ||||||
|    once_next_frame(function() |    once_next_frame(function() | ||||||
|     new_events:push_back{ |     add(new_events, { | ||||||
|      wait = 4, |      wait = 4, | ||||||
|      obj = self, |      obj = self, | ||||||
|      saved_dmg = self.damage, |      saved_dmg = self.damage, | ||||||
| @@ -965,7 +918,7 @@ blast = mknew(bullet_base.new{ | |||||||
|        return true |        return true | ||||||
|       end |       end | ||||||
|      end, |      end, | ||||||
|     } |     }) | ||||||
|     self.damage = 0 |     self.damage = 0 | ||||||
|     self.awaitcancel = false |     self.awaitcancel = false | ||||||
|    end) |    end) | ||||||
| @@ -1418,10 +1371,10 @@ end | |||||||
|  |  | ||||||
| collider = mknew{ | collider = mknew{ | ||||||
|  init = function(x) |  init = function(x) | ||||||
|   x.suppress = {} |   local from = x.from | ||||||
|   local p, n = x.from, x.from.next |   for k=1,#from do | ||||||
|   while n do |  | ||||||
|    -- insert |    -- insert | ||||||
|  |    local n = from[k] | ||||||
|    for i in all(collider_indexes(hurtbox(n))) do |    for i in all(collider_indexes(hurtbox(n))) do | ||||||
|     local a = x[i] |     local a = x[i] | ||||||
|     if not a then |     if not a then | ||||||
| @@ -1430,35 +1383,21 @@ collider = mknew{ | |||||||
|     end |     end | ||||||
|     add(a, n) |     add(a, n) | ||||||
|    end |    end | ||||||
|    -- prepare yoink |  | ||||||
|    n.prev = p |  | ||||||
|    p = n |  | ||||||
|    n = n.next |  | ||||||
|   end |   end | ||||||
|  end, |  end, | ||||||
| } | } | ||||||
|  |  | ||||||
| function collider_indexes(box) | function collider_indexes(box) | ||||||
|  local ret = {} |  local ret,i = {}, 0 | ||||||
|  for x = box.x\8, (box.x+box.width)\8 do |  for x = box.x\8, (box.x+box.width)\8 do | ||||||
|   for y = box.y\8, (box.y+box.height)\8 do |   for y = box.y\8, (box.y+box.height)\8 do | ||||||
|    add(ret, x+256*y) |    i += 1 | ||||||
|  |    ret[i] = x+256*y | ||||||
|   end |   end | ||||||
|  end |  end | ||||||
|  return ret |  return ret | ||||||
| end | end | ||||||
|  |  | ||||||
| function collider:yoink(item) |  | ||||||
|  self.suppress[item]=true |  | ||||||
|  local p,n = item.prev,item.next |  | ||||||
|  p.next = n |  | ||||||
|  if n then |  | ||||||
|   n.prev = p |  | ||||||
|  else |  | ||||||
|   self.from.tail = p |  | ||||||
|  end |  | ||||||
| end |  | ||||||
|  |  | ||||||
| function collider:iterate_collisions(box) | function collider:iterate_collisions(box) | ||||||
|  local seen = { } |  local seen = { } | ||||||
|  local bucket_ids = collider_indexes(box) |  local bucket_ids = collider_indexes(box) | ||||||
| @@ -1474,7 +1413,7 @@ function collider:iterate_collisions(box) | |||||||
|     bi += 1 |     bi += 1 | ||||||
|     if not seen[candidate] then |     if not seen[candidate] then | ||||||
|      seen[candidate] = true |      seen[candidate] = true | ||||||
|      if (not self.suppress[candidate] and collides(box, hurtbox(candidate))) return candidate |      if (not candidate.dead and collides(box, hurtbox(candidate))) return candidate | ||||||
|     end |     end | ||||||
|    end -- done with this bucket |    end -- done with this bucket | ||||||
|    bi=1 |    bi=1 | ||||||
| @@ -1561,7 +1500,7 @@ function flotilla:load(ulc_cx, ulc_cy, lvl) | |||||||
|    for s in all(row) do |    for s in all(row) do | ||||||
|     counts[s.ship_t] += 1 |     counts[s.ship_t] += 1 | ||||||
|     s.x,s.y=rnd_spawn_loc() |     s.x,s.y=rnd_spawn_loc() | ||||||
|     eships:push_back(s) |     add(eships, s) | ||||||
|    end |    end | ||||||
|    add(rows, row) |    add(rows, row) | ||||||
|   end |   end | ||||||
| @@ -1675,7 +1614,7 @@ end | |||||||
| function blip(obj, col) | function blip(obj, col) | ||||||
|  obj.fx_pal = blip_pals[col] |  obj.fx_pal = blip_pals[col] | ||||||
|  if (obj.___fx_pal_event) obj.___fx_pal_event:abort()  |  if (obj.___fx_pal_event) obj.___fx_pal_event:abort()  | ||||||
|  events:push_back(blip_fx.new{frames=3, obj=obj}) |  add(events, blip_fx.new{frames=3, obj=obj}) | ||||||
| end | end | ||||||
|  |  | ||||||
| bossspark = split"7,7,10,10,9,9,9,8,8,8,2,2,5,5" | bossspark = split"7,7,10,10,9,9,9,8,8,8,2,2,5,5" | ||||||
| @@ -1712,14 +1651,14 @@ end | |||||||
| function spark(sprs, x, y, dx, dy, odds, fg) | function spark(sprs, x, y, dx, dy, odds, fg) | ||||||
|  if (sprs==nil or flr(rnd(odds) or (abs(dx) < 0.5 and abs(dy))) ~= 0) return |  if (sprs==nil or flr(rnd(odds) or (abs(dx) < 0.5 and abs(dy))) ~= 0) return | ||||||
|  local target = fg and intangibles_fg or intangibles_bg |  local target = fg and intangibles_fg or intangibles_bg | ||||||
|  target:push_back(spark_particle.new{ |  target[#target+1] = spark_particle.new{ | ||||||
|   x = x + rnd(4) - 2, |   x = x + rnd(4) - 2, | ||||||
|   y = y + rnd(4) - 2, |   y = y + rnd(4) - 2, | ||||||
|   sprs = sprs, |   sprs = sprs, | ||||||
|   sidx = 1, |   sidx = 1, | ||||||
|   dx = dx * rnd(2), |   dx = dx * rnd(2), | ||||||
|   dy = dy * rnd(2), |   dy = dy * rnd(2), | ||||||
|  }) |  } | ||||||
| end | end | ||||||
| -->8 | -->8 | ||||||
| -- powerups | -- powerups | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user