Log In  


I'm trying to get a enemy ship to shoot several bullets out at once in a spread pattern. The bullets aren't being targeted at any specific object or point (not a homing missile)...I just want them to shoot out at various angles, like 180 45 and 225*

Ideally, I'd like to have a function that lets you pass in a origin x/y, an angle and speed...

--shootBullet(x, y, angle, speed)
shootBullet(25,25,45,2)

...then I could put that as part of the a larger collection of functions for my shooting routines. I just

I felt that I had some of the answer in the bullet trajectory math here, but after trying to change different variables and stuff, I just couldn't get it right. This is what I get for not going beyond Algebra I in school ;P

If anyone has a method or can share the math, I'd appreciate it. Thanks!

1


Sounds like you should google up some bullet hell patterns.

For getting an angle into x and y, you want something like
dx=cos(angle)speed
dy=sin(angle)
speed

edit: pico-8 doesn't work in degrees or radians; it uses rotations. (360deg==2pi==1rot)


That's the math I'm using but the Y never changes...X does though. I read through the P8 manual and see that sin() is inverted, so it sounds like I have to convert that? I dunno. I'll keep digging...believe me, I've been Googling...

I don't think it helps that the Lua math library in P8 is limited or missing or whatever. I can't do radians.

speed=2
angle=45
x += speed * cos(angle)
y += speed * sin(angle)

Disclaimer - I still haven't made anything pico yet. (just bought yesterday) This might compile, but no promises

You'll probably want to keep a table just for dumb bullets like these, and use a single update function that runs through them to update since all they need is x,y and dx,dy. (Another point - front loading the sin and cos at creation time means less math on every update, which is usually a good thing)

function makedumbbullet(x,y,a,s)
local newb={}
newb.x=x
newb.y=y
newb.dx=cos(a)s
newb.dy=-sin(a)
s
return newb
end

which you call with a quick "add(dumbbullettable, makedumbbullet(x,y,angle,speed))"

function updatedumbbullets()
for b in all dumbbullettable
b.x+=b.dx
b.y+=b.dy
end
end


function bulletring(x,y,number,speed)
for i=1,number do
add(dumbbullettable, makedumbbullet(x,y,i/number,speed))
end

edited for proper angle value


You can still use degrees, just be sure to plug in
degrees * 3.14159 / 180 = radians
someplace

edit: and the inverted sin is because of the direction y pixels are numbered (top to bottom, I assume like most video functions)

edit edit: Not guaranteeing pi is available, so I'll check... and it isn't. So punch in those digits! (I guess)


Cool, I never thought about having a pre-loaded table...good idea.

Here's how I took your snippets and applied it, it's still not moving the object in the right direction, but I feel I'm missing something. Do I need to convert the angle into something? Is that where the radians come in?

The result here is X changes but Y stays constant, so the ball just moves to the right.

dumbbullettable={}

-- start with ball in the bottom-left corner, try to move it to top-right
x=10
y=120
s=1
angle=45

function makedumbbullet(x,y,a,s)
	local newb={}
	newb.x= x
	newb.y= y
	newb.dx= cos(a)*s
	newb.dy= -sin(a)*s

	return newb
end

-- Shoot at 45* angle (if north is up, this should go northeast)
add(dumbbullettable, makedumbbullet(x,y,angle,s))

--LOOPS

function _update()
	foreach(dumbbullettable, function(obj) 
		obj.x+=obj.dx
		obj.y+=obj.dy
	end)
end

function _draw()
	cls()
	foreach(dumbbullettable, function(obj) 
		print(obj.x.." x "..obj.y,80,5,7)
		circfill(obj.x,obj.y,3,7)
	end)
end

exactly right. Any built in function that expects an angle expects it to be in radians. So just convert it before you get to the sin and cos.

function makedumbbullet(x,y,a,s)
  [b]a=a/360[/b]
  local newb={}
  newb.x= x
  newb.y= y
  newb.dx= cos(a)*s
  newb.dy= sin(a)*s

  return newb
end

should do the trick

edit: and totally change that table and function name. All those repeated letters are just begging for typos... (I keep having to fix it just writing posts)

edit edit - fixed the worst typo on the first line.

final edit - fixed angle value


Gotcha...so I added the radians math and now the X and Y change (yay) but the ball certainly isn't moving at 45 angle. It's more like a 10 angle looks like, very narrow. It's weird.

I'm assuming 0 is straight up, 90 is right, 180 down and 270 is left.

-- start with ball in the middle, try to move it to top-right
x=60
y=60
s=1
angle=45
pi=3.14159265359

function makedumbbullet(x,y,a,s)
	rad=a*pi/180
	local newb={}
	newb.x= x
	newb.y= y
	newb.dx= cos(rad)*s
	newb.dy= -sin(rad)*s

	return newb
end

-- Shoot at 45* angle (if north is up, this should go northeast)
add(dumbbullettable, makedumbbullet(x,y,angle,s))

0 degrees is straight right, and goes ccw as the angle increases.

edit: pico-8 uses "turns": 1 turn == 360 deg


Don't forget that Pico-8 is weird and takes the range [0,1] instead of [0,2PI]. If you have radians, divide by 2PI first.

print(sin(0.25))
-1

print(sin(0.75))
1

for t=0,1,0.1 do print(sin(t)) end
0
-0.5877
-0.9511
-0.9511
-0.588
-0.0003738
0.5877
0.951
0.9512
0.5883
0.0003891

As seen in dddaaannn's example, note that sin() returns an already-inverted value to match screen space, so you don't need to re-invert the y.

The quirks with pico-8's trig functions are documented here: https://www.lexaloffle.com/pico-8.php?page=manual (search for "Quirks")


Instead of thinking of pico-8's sin and cos as being in radians, think of them as being in "turns".


So if I want to provide a function with a "human" angle value, like 45 or 270, I need to convert that into radians before I give it to sin() and cos()...right?

But if I give sin() and cos() a decimal value between 0 and 1, I can skip the extra calculation?

So in decimal world, 0 is right, so .25 is straight up, .50 is left and .75 is down?

I'm at work so I can't test it anything here but tonight I'll try all of these snippets out.


So in decimal world, 0 is right, so .25 is straight up, .50 is left and .75 is down?

Totally.
When you code with pico8 you dont have to bother with degrees or radians.
1 is equal to a full turn.


Here's what I mashed together that got things working in a way I understood and was easy to implement. In short, instead of providing "human" angle numbers, I just give it decimals and everything works fine.

So worst case, I have a little cheat sheet that reminds me which decimals go with which angles. Easy enough.

Thanks to everyone that chimed in. I'm a little smarter and my game will be a little better thanks to everyone's help.

bullets={}

-- settings, start in the center and create an X shot
x=60
y=60
s=2

function createBullet(x,y,a,s)
	local newb={}
	newb.x=x
	newb.y=y
	newb.dx=cos(a)*s
	newb.dy=sin(a)*s

	return newb
end

--LOOPS

function _update()
	foreach(bullets, function(obj) 
		obj.x+=obj.dx
		obj.y+=obj.dy
	end)
end

function _draw()
	cls()
	circfill(x,y,3,1)
	foreach(bullets, function(obj) circfill(obj.x,obj.y,3,7) end)
end

-- Create bullets
-- This will shoot 4 bullets in a X pattern from the center point
-- Angles: 0=right/0*, .25=up/90*, .50=left/180*, .75=down/270*, .125=45*

add(bullets, createBullet(x,y,.125,s)) --45*
add(bullets, createBullet(x,y,.375,s)) --135*
add(bullets, createBullet(x,y,.625,s)) --225*
add(bullets, createBullet(x,y,.875,s)) --315*


[Please log in to post a comment]