Log In  


I have a foe taking damage from multiple bullet types on the same frame. I'm able to inflict 'impact' movement to the foe via the bullets update function (i.e. the foe jiggles when struck and still alive). The problem though is the death movement. I want to send the foe flying a certain amount depending on what kills them. Instead of doing calculations inside the bullet update like I had for the jiggles... I had been sending an id of the last struck bullet type to the foe's update, where it could then do the operations. This works fine for single shot deaths. However this doesn't look great when they get hit by like 10 things at once on a frame and they do the kinetic animation for the wimpiest bullet they r hit with. So I need a system of identifying basically the bullets (the type and number of each type) from the last 10 frames that have hit...and define that into some kind of kinetic energy multiplier to determine how far the body flies.
Question is how do I go about this, and is there a better method?

Another method would be I could potentially do this in the bullet updates....but that seems messey cause I'd have multiple bullets surviving and checking eachother out in what seems like costly back and forth ways for extra frames after they r supposed to be dead. Maybe I'm missing something here though.

In Summary, my setup is like this, and I need some way of passing 'how many bullets of each type 1/2/3' have hit the foe over the last 10 frames or so. Presently only the last bullet info, calculated on the final frame of life, is passed over. I could just create a var x=0 and add +10 for type 1, +20 for type 2 etc over 30 frames...giving me a kinetic multiplier. But I endup with just a number that works fine for the 10 frames...but then there's no way on the 11th frame to remove the 1st frames data and repeat the process so I'm always the latest 10 frames of data. I need some kind of table setup.

function _update()
for all obj in bullets do obj:update end
for all obj in foes do obj:update end
end

bullets={{update=function() ... end},{..},..{..}}
foes={{update=function() ... end},{..},..{..}}


2
function bullet_collided(f,b)
  f.impact_list=f.impact_list or {}
  b.itime = time()
  add(f.impact_list,b,1)
end

function remove_impacts(f)
  local currtime = time()
  if not f.impact_list then return end
  for i=1,#f.impact_list do
    if (f.impact_list[i].itime >= time()-.333) break
    deli(f.impact_list)
  end
end

For keeping track of the bullets that each foe, would something like this work?


1

the answer above looks good to me. I just want to suggest that you can also just take the maximum instead of accumulating them. if the problem is you need to select the highest impact to use.

function player.get_hit(new_impact)
 player.impact = max(player.impact, new_impact)
end

if they should accumulate a little, then:

player.impact = min(player.impact + new_impact, 3)


I think I'd do it like this then... let's assume I created a timer=0;_update()timer+=1 to count frames.
And that every {bullet} in {bullets} updates before every {foe} in {foes}, and every foe has a self.{impact_list}

--lets say I'm working in the update func of each {bullet}:
for i=#foes,1,-1 do --I iterate over all the foes
	if collision then --if there's a collision between the bullet and the foe[i]...
		add(foe[i].impact_list,timer)--I added the current framenumber to the foe's impact list.

--lets say I'm working in the update function of each foe now:
for i=#self.impact_list,1,-1 do
 if self.impact_list[i]<timer-1 then --if the entry value is not timer-1 or higher then...delete it
	del(self.impact_list,self.impact_list[i]) 

So in a simplified ex: if my impact list added an entry every frame for 5 frames, with multiple impacts on the 4th:
impact_list={1,2,3,4,4,4,5}
And if I then applied the deletion check on the 5th frame to start storing only the last 2 most current frames:
impact_list={4,4,4,5}

Since I would need the bullet type, 2 array mbe would be better. So impact_frames={} impact_types={}. Then impact_types is the meat of how I determine the kinetic multiplier, with impact_frames determing which entries to delete in both as time goes on.

impact_frames={4,4,4,5}
impact_types={1,1,2,3} --where I have 3 types of bullets.

local k=0
for obj in all(impact_types) do
 if obj ==1 then k+=4 elseif obj==2 then k+=1 elseif obj==3 then k+=5 end
end
--k=min(15,4+4+1+5)

Then k is my multiplier for how hard the body flies. I already have a custom multiplier for the 'jittering' when each foe gets hit by each bullet type, so I'd just pass that instead of a bullet_id-like type.


This is a matter of preference, but I'll clarify in case it's not obvious. In my code example, I was assuming the lists would contain references to the individual bullets themselves with the extra data just added to the relevant bullet. This is not a good idea if you have a pool of bullets, such as if the table for bullets doesn't change size, using a flag to tell when a spot is available. However, if you're adding and deleting the bullets from the main list all the time, then adding the bullets to the impact lists directly would only have the side effect that the memory used by the bullet would stay in use until all the impact lists that reference it clear that frame. That's why my example puts the impact timestamp on the bullet itself.

If you'd prefer to use numbers instead, that's just as good. It'd make your code easier to read without in-depth understanding of tables just at the cost of being longer. In that case, then the type number you're looking at would be the better way.


kimi makes some valid points. you don't want to have a sparse array necessarily. I guess it should be a queue.

as we have another thread talking about coroutines, and, I sort of felt like coding, so I gave it a quick and dirty run just to see how it would go. the intrigue comes from the idea that a foe can be shot on every frame. at that point, its like a laser or something!

Cart #dowepazeze-2 | 2022-07-20 | Code ▽ | Embed ▽ | No License


X / O buttons to shoot.

sorry for ninja edit!


Okay, I got things working now. The method you outlined let me create a variable kinetic multiplier which is working nicely...the foe goes flying in cool dynamic ways when dmg types are stacked or spaced out over time. And grabbing the maximum value from that table with the max() suggestion will replace the former method of sending 'last bullet to hit you on this frame was bullet type 1' method, as a reliable way to identify when the foe hp hits 0 in a special way without the data being overwritten by the dozen other things hitting it to 0 hp... which allows for the scripted components to reliably occur.
Goodwork, thankyou both!

*edit: in terms of the cart above and usage of coroutines, it's interesting. I have a low opinion of coroutines, in pico8 anyways, as in my experience they can always be rewritten using switches to become ~50% faster. Not sure if its just pico8, or whatever, just...its what happens when I rewrite cool things I find on the bbs that use coroutines in terms of switches. Still waiting to be proven wrong, since they are pretty cool in how they function....and its a different way of doing things in general. But agree to disagree, someone reading this disagrees, noted!, shelved for some other thread discussion.


By switches, do you mean big old sequence of if/else testing some global variables?



[Please log in to post a comment]