Log In  

I have a stationary object firing bullets at foe(enemy object). The problem is the game is running at 30fps, and the bullets are travelling at a pretty fast speed, so fast that they sometimes endup on the other side of the foe, but not so fast that they passthrough foe. I'm using circular collision and the foe have a circle of radius 4 with origin placed at the center of their circular-sprite. The bullets are small with radius of 1 or 2. Everytime a bullet is colliding within the foe's circle the game takes the angle between the bullet and the foe (the bullet-foe-angle) and applies a force in that direction onto the foe. Normally this would mean any bullets fired at the foe push the foe in a 'general direction away' from the bullet's point of origin but not necessarily in the direction of the bullet's projectory(unless it's a dead-on hit). But a bullet which first appears on the other side of the foe's origin... is going to push it forwards, towards the bullet's point of origin. Also of note is that the last bullet to hit the foe before it hits 0 hp determines the direction of the foe's ragdoll/corpse effect(any small bullet bump basically gets pronounced for a second or two). Each object has a dx,dy variable tabulating all the forces applies on it that frame then added to their x,y.

My main consideration is finding a fix that has a low cpu cost, but don't let it limit the discussion.

So the OP's issue is caused primarily by two things since spd/fps changes are off the table:
a) the bullet first appearing in the wrong side of the foe's circle-Hitbox
b) the fact I use the direction from the bullet to the center of the foe (bullet-foe-angle) to determine the dx+= dy+= that's applied when the bullet hits the foe.

Ideas to remedy:

  1. Since the object firing bullets is stationary I could take the angle from the object to the foe, rather than the bullet to the foe. This works...but it's the same effect regardless of where a stationary foe is hit(dead-center/left/right/etc). And if something is dx+=1 and dy+=0, aka sidestepping a player's position, and they get hit by bullets from that player...should the bullet bump them slightly in the direction of the bullet's projectory? If it's a deadon hit...ya...but if it's grazing their side its usually a bit weird looking to have them be bumped with the bullet projectory a bit. The dx are all added up so the sidestep movement is still the dominant force but still. But with the original bullet-foe-angle method the graze would send them uniquely upwards a bit instead and the deadon hit would send them with the bullet projectory which seems overall better/unique looking from my testing. There's also the consideration of the ragdolling where any seemingly small and weird bump direction gets pronounced via a multiplier for a brief period of time.

  2. I keep the bullet-foe-angle method and give the foe a second circle of larger radius, say 8. Once the bullet enters this larger circle the angle between the two is taken and recorded for that specific bullet-foe relationship. The larger circle then never runs again for that specific relationship, and when the smaller radius 4 circle is triggered I use that recorded angle. This seems to be a best of both worlds approach....it will still suffer a bit from (1)'s methodology...but it would solve the OP. Personally I don't like this method, cause it makes it so every bullet has to have a little bit of the (1) problem as a cost to fix the few bullets that fall under the OP's problem.

  3. If the foe is always facing the player when they are fired at...then I can maybe identify when bullets are 'on the wrong side' of the foe's circle. Then I can maybe do some kind of reflection(like how when u make a circle u make a small ~45 degree arc then reflect it 8 ways to make the full circle) to, in-effect, teleport the bullet a few pixels backwards along it's projectory enough so it sends the foe in generally the correct direction as intended with the bullet-foe angle method.

  4. Something with the dot product I could use....? Not sure. Apparently it can tell when two objects are facing eachother...I made a demo a while back proving to myself it does...maybe something there could help...I'm thinking it would not work right here, but just an idea.

Would appreciate any ideas/methods that could be thought of to help solve this.

P#117726 2022-09-20 21:42 ( Edited 2022-09-20 21:46)

Cart #bodoguwofo-1 | 2022-09-23 | Code ▽ | Embed ▽ | Forks ▽ | License: CC4-BY-NC-SA

Teatime!v2 is a top-down 2-handed-keyboard roguelite shooter featuring experimental controls, 6 weaponTypes, 3 playable characters, and quirky mechanics. Free-to-play inbrowser on itch.io and the pico8 bbs.

Goal: Keep your cupHp and playerHp above 0 for 300s while preventing no-more than 10 leaf from entering your cup. When the timer hits 0, you are given 10s, from times [0,-10], to drink the tea before it spoils.

[LongPlay: Fewer leaf in your Cup will mean a higher score and potential bonuses]

a|d: angle of fire
s: fire; (tap)shotgun/sniper, (hold1)bomb/kinesis, (hold2)mg/poison
f: (tap)grab-nearby/drop cup; (hold)drink from heldCup
e: drop fakeCup
shift*: (tap)toggle altWeapons; (hold) +/- turnrate while using a|d
*spacebar/q added as alts

Right_Hand: arrowKeys movement up/down/left/right
k:return from game to menu(avoid during screenshake; offsets correct on replay)

See the itch page for full-manual/video/tips/releases/etc: https://cerbyo.itch.io/teatime
The machinegun & impact sfx may have an echo on the webbuild. Consider playing from splore(recommended), the.p8.png cart file, or binaries off itch if it's a problem.

+Chippy's Gun & Greg's Blend now hidden unlockable-items for all characters(via menu on unlocked) 
+cupDrop damage changed from -25cupHp to -50cupHp
+'k' ingame returns you to the character-select screen 
+obj-init/function optimizations

P#117549 2022-09-17 04:16 ( Edited 2022-09-23 06:52)

Because there doesn't seem to be a method to specify the audio channels with "\a" I am trying to transfer my sound effects to the sfx editor.

I don't understand how to do this though. Let's take this example:
s16...spd set to 16
no volume is specified so the fourth column is 5 by default
x3...final 5th column set to 3 for all notes
a0...note a(press n cause idk how to type it in manually) and octave 0

In the sfx editor that gets me, with spd=16, this:
a 0053

?"\as16x3a0" does not sound like that at all....so idk what I'm missing here. I need to figureout how to do it for notes like ?"\as9x3a-2i0dd1" which includes "-" being a sharp and idk how to input a sharp at all, # seems to be the keys above n's row.

Would appreciate an explanation on what I am missing here, and if there is a way to transfer it without manually going through it like this.

P#114180 2022-07-11 00:25 ( Edited 2022-07-11 00:28)

I'm trying to setup a new menuitem (i.e. on enter menu) for muting the music. (1) the code below will mute properly but won't display the updated value of the switch i.e. "Music:on" will always display. Putting menuitem() in _draw will fix this...allowing for "Music:off" to display, but not when the callback is true (menu doesnt auto-close).

(2), I'm concerned if I should be calling menuitem() in _draw or not to begin with (if its better cost-wise elsewhere). I am not overly familiar with cartdata and dset/dget but was trying to store a value there and check that in draw instead....not sure if that's the right way, but its not working atm anyways.

How should I ideally set this up such that music:on/off can be seen and toggled within the menu, with the callback returning true (menu not exiting on click)?

switch=true --true is music_on

function _draw() cls(1)
    if dget(1)==0 then switch=true else switch=false end --not working, was trying to update display for menu

function _init()
    menuitem(2,"music"..(switch and ":on" or ":off"),
        switch= not switch
     if switch then
        dset(1,1) end
     return true

(3) Does menuitem() being in _init() allow it to persist throughout the gameloop...so that any change to the enter menu calls it?...but it's not updating the value of switch while I'm in the menu itself....only after I close the menu...I don't understand how this works in relation to the gameloop (normally I expect to have to call the function in _draw/_update to run and update itself each frame). Menuitem() is a callback function that runs on its own loop in the background once first called so its ideally called once in init...? Do I have to store switch somewhere menuitem can access (like outside the gameloop cause the gameloop dont run in menu)...?

Here's the same system as above, but storing the value of switch in cartdata, the end result is the exact same as above though...still no dynamic updating while in menu.


function _draw() cls(1)

function _init()
    (switch==0 and ":on" or ":off"),
     if switch==1 then
     else --switch==0 aka on
        dset(3,1) end
     return true
P#114087 2022-07-08 23:16 ( Edited 2022-07-08 23:45)

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

bullets={{update=function() ... end},{..},..{..}}
foes={{update=function() ... end},{..},..{..}}
P#110811 2022-04-25 04:09

Okay so I'm looking to make an orb animation like this: https://jsfiddle.net/aycn3fzd/
I'm not really sure if the solution is within that post or not, I'm having a hard time converting it.
Regardless, I'll explain what I have and the issue I'm having with completing this task.
Here's what I have atm:

I want an orb that will fill/unfill based on the percent of something left. So the generic red hp orb for example. A player has x hp. That hp as a percent x/100 will influence the percent of which the orb is filled from bottom to top red. You can see in the gif above I have this working for 'part' of the circle. The problem is the other sections.

My method for drawing the circle in this example is drawing the 0->15degrees side arc using sin/cos and reflecting it 8x...I posted earlier 3-4 other circle drawing methods, but I'm using the cos()/sin() one here for accuracy's sake. To fill in the circle I am using the line() method and extending it to the other side so I only need 4 instances. I don't fully understand the rect() method and have had issues getting it to look right (I assume u draw a square right center of the circle but the corners usually stickout and look off...maybe that assumption is the problem).

Anyways, drawing the lines for every y value of the circle I endup with the inverted version of the red picture there, which when reflected again gets the yellow version of itself there. Each of these shapes and their inverted version, when positioned properly will create a nice circfill() mimick:

So the red one is working in the first gif. The problem is the orange ones...when I apply the method they shrink width-wise and i need them shrinking height-wise. Looking at how I derive them, its clear why they are doing that, its cause I'm deriving everything from the original 0->12.5 degree segment and I draw that segment with horizontal lines. One solution might be to redraw it with vertical lines and use that for 2 of the sections and the horizontal for the other 2...but I have no idea how to do that and from my testing question if that is possible. Here we see the problem below:

The effect worked above by deleting the red lines....making it go up/down. If we delete the brown lines we affect the width when we want to affect the height. Maybe I could draw ellipse halves at the top and bottom and draw those using the elipsefill() builtin thing and dynamically change the radius...it would be cheating sorta, but might work.

The third issue is how to determine 'when' one section should be shrinking and the others should be statically fully displayed or fully cleared from the screen. I prefer the idea of doing this with 1 circle such that when the orb is drained...u can see the gameplay behind rather than a second fully displayed 'background' circfill().

percent=100 --how full the circle/orb is as a percent
function _draw()cls()
    if percent>0 then percent-=1 end --orb draining from full
function orbfill(cx,cy,r,c,q)
poke(0x5f25,c) --set color
q=q or (r>15 and .005 or .01) --pixels per arc, .01 default
    for i=0,.125,q do --angle runs from 0->.125 then reflects this arc 8x
        local x,y=r*cos(i),r*sin(i)
        --circ() method
        pset(cx-y,cy-x)--miry=x .5
        pset(cx-y,cy+x)--mir .75
        pset(cx+y,cy-x)--mir .25
        pset(cx+y,cy+x)--mir .625
        pset(cx+x,cy-y) --x flip
        pset(cx-x,cy+y) --y flip
        pset(cx-x,cy-y) --xy flip
        --circfill() method
        -- line(cx-x,cy-y,cx+x,cy-y)
        -- line(cx-x,cy+y,cx+x,cy+y)
        -- line(cx+y,cy-x,cx+y,cy+x)
        -- line(cx-y,cy-x,cx-y,cy+x)
--[[So the above is just the normal circ()/circfill() function. 
My method for the animation is the idea we have zones that activate based on the 'percent' var. 
Then we take a percent of a percent when we are in each section to run through 0 to var*12.5 degrees of arc
....where the var will drain that 12.5 to 0 based on the percentages...which decreases the number of 
horizontal line stacks. This presents problems already as to how to get this working nicely. 
The above loop is just to show the starting point, it can be removed.
--diameter is 2*r=60; r=30
--heights of segments: 8.7868 top; upper 21.2132; lower 21.2132; low is 8.7868
--21.2132*2+8.7868*2=60 --ttl height of circle with r=30

21.2132/60 --0.35355333333333333
8.7868/60 --0.14644666666666667
--lets say its 15%+35%+35%+15%
--top segment decreases
--upper mid decreases
--lower mid decreases
--lower segment decreases

If percent is above a tier, then that tier would need to remain fully displayed at 100%.
@percent==100 all four tiers and segments are 100%.; percent==90 the bottom 3 are full, top 1 draining

--outline for method:
if percent>85 then
    for i=0,k,q do --0->.125 then reflects
        local x,y=r*cos(i),r*sin(i)
--      line(cx-x,cy+y,cx+x,cy+y) --upper mid
--      line(cx-x,cy-y,cx+x,cy-y) --lower mid
--the first gif works based on this:
elseif percent<=85 then--(21.2132*2+8.7868)/60 then --0.8535533333333334
    local rat=(percent-50)/35 
--a percent of a percent: percent=85%->50% transposed on i=0->12.5 degrees
--we make that 30% section of percent into a 100% segment and use to determine the deg out of 12.5
    for i=0,k*rat,q do 
        local x,y=r*cos(i),r*sin(i)

P#109591 2022-04-02 20:05 ( Edited 2022-04-02 21:24)

Cart #jfowobora-1 | 2022-04-01 | Code ▽ | Embed ▽ | Forks ▽ | No License

I've been looking at how to draw circles that mimic the elegance of circ(). From the bbs that led me to

So I tested
Minsky/Midpoint/x,y=sin(),cos() against circ()
The verdict was the midpoint algorithm was the best alt method. But none of them r close to being as efficient as circ()..so I don't understand...how does circ() work? I especially don't understand cause the previous bbs link to the Minsky said it was superior to circ()...my tests say its not...but the posts r 5 years old so...has circ() been updated since maybe? Or what am I missing? All I did in my test is draw 100 circles and look at the values via ctrl+p...and the findings were explicit.

I'm really just looking at how to draw circles that look as good as circ()+efficiently+accuracy, since circ()/elipse() omit some of the custom arc-like shapes u might want to make or more custom circles like dotted etc that I need to use. You can of course, when able, for static circles just do the math calculations 1x outside the gameloop, then draw the coordinates via pset() in the gameloop...but many times you need dynamic circles running each frame looking clear as can be.

I'm also a bit upset by how circ() smooths its coordinates. The sin()/cos() method creates a much much more accurate circle hitbox. With circ() the collisions are always off, particularly in the right-side, when relying on it for the visual representation of where things are...and no you can't blame rounding error. I guess since I use sin()/cos() to make the imaginary hitboxes that would make sense that drawing the circles via sin()/cos() creates a more accurate representation. But u can't use midpoint circle algorithm, or whatever circ() is using, to make an efficient collision detection algorithm...is what I would presume?

P#109489 2022-04-01 01:29 ( Edited 2022-04-01 01:51)

id=stat(31) identifies keypress_q as id="q" and keypress_a as id="a". Btn(5,1) identifies itself as keypress_q and keypress_a. How do I separate keypress_q to work via id=stat(31)="q" and btn(5,1) to work 'only' with keypress_a?

if btn(5,1) and id~="q" then... --input for keypress_a
if id=="q" then... --input for keypress_q

That 'would' work...but the problem is stat(31) works like btnp() when I need it to work like btn()...but the poke methods of making btnp() work like btn() don't seem to apply to stat(31)! So I'm presently stuck in a situation where I can be pressing keypress_q and yet id~="q"! The obvious way around this is to just use id=="a" for keypress_a; id=="q" for keypress_q....but again, they work like btnp, so this doesn't work if I want to use keypress_a for standard smooth wasd player movement.

The intent is to basically utilize the existing buttons of player 0 and player 1....and add the functionality of stat(31) to get even more keys. I don't necessarily need the other keys to have the same functionality as btn(), they can just be 'single tap' style keys...I'll use them as like rpg skills that go on cooldown right when they are used. Player movement via wasd though needs the functionality of btn(). But again, the problem is the overlap....specifically with those btn(4/5) keys since they have more than 1 natural input (seen below), when I want to choose just 1 natural input and use stat(31) to utilize the other.

For the sake of reminder I'll include the keys below to give an idea of the overlap, specifically btn(4/5):

P0: 0left;1right;2up;3down;4zcn;5xvm
p1: 0s/1f/2e/3d/4wtabshift/5aq

Chosen usage for p1: a:btn(5,1)|d:btn(3,1)|w:btn(4,1)|s:btn(0,1)|f:btn(1,1)|e:btn(2,1)

I guess p1:btn(5) is the only case of overlap...since I can't seem to get stat(31) to work for tab/shift/backspace...mainly I don't get anything showing up when I printh(id) with those inputs. I get "9" for backspace...but only keypress_9 activates the 'if id=="9"' case. stat(31) is also sort of weird...not sure if buggy is the right word. Is it single thread or something? If you 'also' print(stat(31)) to the screen it negatively affects id=stat(31), which won't work as reliably....I think stat(31) can only be called directly once per frame? Or something to that effect

P#109207 2022-03-26 18:47 ( Edited 2022-03-26 19:18)

I need some help creating an absolute value function that utilizes bits to work.
My current understanding is pico8 is either 32 or 16 places. I don't quite understand which value I would use here.

If someone can clarify that would be good. For the sake of explanation, lets say its 6 bit.

000 010 --binary form of 2 in 6 bit
111 101 --binary form of -2 in 6 bit 

So my understanding is the formula is something like:

mask=v>>number_of_bits_in_v -1

where number_of_bits_in_v=6 and v=2

And the idea is in the case of v=-2 we are adding one to it..cause all the bits to shift over. So given the above formula is subracting one....I have to know whether the number is positive or negative ahead of time and use either -1 or +1? Not sure if that'll be an issue or not.

This leads to a function like:

function absolute(v,ttl_bits)
local mask=v>>ttl_bits-1
return (v+mask)^mask

--given pico8 is 32...bits? i would use...?
absolute(2,32) --2? only it doesn't...it gives me a 0 if v is negative, 1 if v is positive.

The goal is to make it function like the built-in abs(-2) --2
And if there is a way for this to work like it does for decimals too...like abs(-2.432) --2.432

P#108221 2022-03-08 00:55 ( Edited 2022-03-08 01:00)

Cart #tubisapame-0 | 2022-01-28 | Code ▽ | Embed ▽ | Forks ▽ | No License

I'm trying to figureout how to create parabola/bezier-curve/quadratic (i.e. grenade lobbing) movement based on the player's velocity dx/dy. I'm familiar how to do this for a player's speed, and the cart shows the setup for speed as a functioning baseline. In the cart I defined a player who can move around with the arrow keys. When they hit x they bunny style hop moving to the right using the quad() function. The system freezes the movement of the player while the hop completes, so its always the same movement pattern.

Speed relies on absolute movement and coordinates...with quad() the player will start somewhere defined p0...move along a curve defined by point p1 and endup at p2. The cart math is based on augmenting the x/y player values directly. Velocity is different though, and I can't figureout how to make the same example work for the dx/dy in the cart.

My intent is to make a bunny hop according to the direction of movement defined by dx/dy. So if the player is moving and they press x, the player movement freezes for a time, and the current values of dx/dy will judge the direction and magnitude of movement to be completed according to some general curve outline (bunny hop). And since I'm now dealing with velocity vectors, for this system to allow me to apply other forces onto the movement like gravity etc which should affect the bunny hop movement dynamically rather than scripted like in the cart. Without the quadratic part the effect can be achieved with just straightup multipliers dx*=1.1 (i.e. velocity increases if I press x for a time)..but that's not what I want.

Velocity+quadratics....how to? Would appreciate help with the math here or something to get me started. If there are some search terms of articles to link to, that's good too. I'm having a hard time finding the information online, could use better keywords. I found it hard to create the quad() function to begin with cause I was relying on quadratics tutorials when what I wanted was bezier curves...so I'm hoping I'm just missing a keyword like in that case.

P#105861 2022-01-28 23:24 ( Edited 2022-01-28 23:28)

Nothing I try seems very active. I went through...slack...twitter.....here....stack exchange. And the time delay between getting any answers, if any, is excruciatingly ineffective. Are there more active communities I could get help from that I haven't tried?

Here and there I have little questions I need help with. Mainly syntax related, I don't need somsone to go through ALL my code or anything just 1 liners here and there. For small questions while writing your code, what is the best way to get answers asap? Was hoping for a chatbox or irs or something.

P#66018 2019-07-22 01:34

I'm having a really hard time with initiating if statements using multiple booleans. It seems I initiate one but then it stays and I can't figure out how to write them properly if I'm dealing with multiple.

In this example I'm trying to set 3 gamescreens with a timer for the 2nd.
The default screen is titlescreen; the initated one on button press is titlescreen1; and then i want gamescreen to happen automatically when the timer finishes.

Problem is gamescreen doesn't initiate and I don't understand why.


function _init()

function time_lapse()
if time() - time_diff > 1 and countdown > 0 then

function _update()
if btn(4) then titlescreen1=true end
if titlescreen1==true then time_lapse()
if countdown==0 then gamescreen=true end
elseif gamescreen==true then

function _draw()
print("one is happening",33,33,14)
if titlescreen1==true then cls() print(countdown,15,15,14)
elseif gamescreen==true then
print("gamescreen is active",33,33,14)

P#65997 2019-07-21 08:43

Basic movement can be facilitated through:
if btn(0) then x-=1 end

But when I add sfx:

if btn(0) then x-=1 and sfx(0) end

It always generates an error as soon as that button 0 is pressed. Why is that? If x then y and z end. Is there something wrong with that syntax? Or is it related to sfx not working in this way?

And why is it when I clarify with brackets it doesn't even run!? Am I clarifying that my syntax is wrong before teh game starts? That's funny.
if btn(0) then (x-=1 and sfx(0)) end

P#65973 2019-07-20 14:59 ( Edited 2019-07-20 15:01)

Edit: not sure how I'm expected to display multiplication using the syntax here, but assume there's a X or star or whatever between 15 and i etc.

I was trying to initiate this statement here, which I can do:
for i=1,4 do
print(i, 15i-14, 15i-14, 14)

But then I wanted to move the diagonal array of 4 numbers with the arrow keys around the screen. I tried the code below but keep getting errors. I'm guessing my argument is setup wrong and I can't call i as the same variable in all these statements and make it work...? Can someone help me understand the immediate problems with the code, and then afterwards if viable suggest an alternative method of doing so. I'm still learning so my immediate concern is figuring out what is wrong here specifically.

function _init()
j= {

function _update()
if btn(0) then j.x-=1 end
if btn(1) then j.x+=1 end
if btn(2) then j.y-=1 end
if btn(3) then j.y+=1 end

function _draw()
for i=1,4 do

Even in the API demo I copy the code for the similar statment, but when i run it on its own it doesn't work. I don't understand why this here doesn't work on its own either:

for i=0,15 do
x = x + 6 + flr(i/10)*4

P#65880 2019-07-16 08:50 ( Edited 2019-07-16 09:03)

Follow Lexaloffle:        
Generated 2022-10-04 20:50:16 | 0.088s | Q:29