9 Commits

Author SHA1 Message Date
c01c3400b7 fix eternal horizontal bullets 2025-06-20 18:51:58 -07:00
0f791b193c more efficient collision iteration, fix eternal shots 2025-06-20 18:50:04 -07:00
d3351d9a05 Use eship_collider for ship collisions, too. 2025-06-20 17:56:57 -07:00
ecddb56d72 loops work better when you increment them 2025-06-20 17:50:03 -07:00
723c0f791c Refactor collider to collaborate with linked_list.
The only use of a collider is intertwined with the ship list, so I can combine the "prepare to yoink" and "populate collider" and "iterate list" steps, and I can combine the "hide" and "yoink" steps. This doesn't save tokens now but it's about to, when I use the eship collider to test pship collision.
2025-06-20 17:48:02 -07:00
e018578754 keep animating bullets while dead 2025-06-20 16:36:18 -07:00
bf8297eb72 prevify eships when setting up collider
I will refactor this next: collider.new will take the linked list to ingest, perform the `insert` and "prevify" loops itself, then replace `hide` with `yoink`, which yoinks the item out of the original list. This pairs the `yoink` operation with the context that makes it possible to do (that is, the context when prevification was implemented); eships therefore cannot be edited in complex ways while the collider is still valid, but we can append to it as long as we don't expect those items to be procesesd correctly this frame. a new_eships+vore plan might be better if we turn out to need it, but presently we don't; flotilla spawning and raider spawning happen at a different point.
2025-06-20 16:31:18 -07:00
1c8bcae44c put ebullet moves inside the collision check loop 2025-06-20 16:01:59 -07:00
325d7444e7 invert eship/pbullet collision
Also mildly trims up linked_list impl.
2025-06-20 15:09:18 -07:00

View File

@ -60,7 +60,7 @@ function mknew(tt)
end
-- intrusive singly-linked list.
-- cannot be nested!
-- cannot be nested or crossed!
linked_list = mknew{
is_linked_list=true,
init = function(x)
@ -93,9 +93,7 @@ end
-- strip calls f(x) for each
-- node, removing each node for
-- which f(x) returns true. it
-- returns the new tail; nil
-- if the list is now empty.
-- which f(x) returns true.
function linked_list:strip(f)
local p, n = self, self.next
while n do
@ -107,7 +105,6 @@ function linked_list:strip(f)
n = n.next
end
self.tail = p
return p
end
-- optimized special case -
@ -237,52 +234,38 @@ function updategame()
end
events:vore(new_events)
events:strip(call_move)
for _, lst in ipairs{intangibles_bg, eships, pbullets, ebullets} do
for _, lst in ipairs{intangibles_bg, eships, pbullets} do
lst:strip(call_move)
end
-- eship collider will be used
-- both for pship and pbullets.
local eship_collider = collider.new{from=eships}
if not ps.dead then
ps:move()
local pbox = hurtbox(ps)
eships:strip(function(es)
if(not collides(pbox, hurtbox(es))) return
for es in eship_collider:iterate_collisions(pbox) do
ps:hitship(es)
return es:hitship(ps)
end)
if(es:hitship(ps)) eship_collider:yoink(es)
end
ebullets:strip(function(eb)
-- loopify this when split moves implemented
if (eb:move()) return true
if (not collides(pbox, hurtbox(eb))) return
ps:hitbullet(eb)
return eb:hitship(ps)
end)
end
-- many bullets and many enemy ships;
-- use bucket collider for efficiency
local pbullet_collider = collider.new()
local p, n = pbullets, pbullets.next
while n do
n.prev = p
pbullet_collider:insert(n)
p = n
n = p.next
end
eships:strip(
function(es)
for pb in all(pbullet_collider:get_collisions(es)) do
if pb:hitship(es) then
pbullet_collider:hide(pb)
pb.prev.next = pb.next
if pb.next then
pb.next.prev = pb.prev
else
pbullets.tail = pb.prev
ebullets:strip(call_move)
end
pbullets:strip(function(pb)
for es in eship_collider:iterate_collisions(hurtbox(pb)) do
if (es:hitbullet(pb)) eship_collider:yoink(es)
if (pb:hitship(es)) return true
end
if (es:hitbullet(pb)) return true
end
end
)
end)
intangibles_fg:strip(call_move)
@ -837,7 +820,7 @@ function bullet_base:move()
self.x += self.dx
self.y += self.dy
if (self.f) self.f -= 1
if (self.y > 145) or (self.y < -8 * self.height) or (self.f and self.f < 0) then
if (self.y > 145) or (self.y < -64) or (self.f and self.f < 0) or (self.x > 256) or (self.x < -128) then
self:die()
return true
end
@ -1445,6 +1428,22 @@ end
collider = mknew{
init = function(x)
x.suppress = {}
local p, n = x.from, x.from.next
while n do
-- insert
for i in all(collider_indexes(hurtbox(n))) do
local a = x[i]
if not a then
a = {}
x[i] = a
end
add(a, n)
end
-- prepare yoink
n.prev = p
p = n
n = n.next
end
end,
}
@ -1458,40 +1457,39 @@ function collider_indexes(box)
return ret
end
function collider:insert(item)
-- todo: separate "big items" list?
local bdx = collider_indexes(hurtbox(item))
for i in all(bdx) do
local x = self[i]
if not x then
x = {}
self[i] = x
end
add(x, item)
end
end
function collider:hide(item)
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:get_collisions(item)
local found = { }
function collider:iterate_collisions(box)
local seen = { }
local box = hurtbox(item)
local bucket_ids = collider_indexes(box)
for b_idx in all(bucket_ids) do
local bucket = self[b_idx]
if bucket then
for candidate in all(bucket) do
if not (seen[candidate] or self.suppress[candidate]) then
local bii, bidl, bucket, bi, blen = 1, #bucket_ids, false, 1, 0
return function()
while bii <= bidl do
if not bucket then
bucket,blen = self[bucket_ids[bii]],0
if (bucket) blen=#bucket
end
while bi <= blen do
local candidate = bucket[bi]
bi += 1
if not seen[candidate] then
seen[candidate] = true
if (collides(box, hurtbox(candidate))) add(found, candidate)
if (not self.suppress[candidate] and collides(box, hurtbox(candidate))) return candidate
end
end -- done with this bucket
bi=1
bii += 1
end
end
end
return found
end -- end of closure def
end
-->8