[SOLVED] Math + Spread bullets

Questions about the LÖVE API, installing LÖVE and other support related questions go here.
Forum rules
Before you make a thread asking for help, read this.
User avatar
var77
Citizen
Posts: 52
Joined: Wed May 02, 2018 1:57 pm

[SOLVED] Math + Spread bullets

Post by var77 »

Hi everyone, I'm back here with a little issue with my "spread bullets".
So here is the deal, I try to make some firing (like a shotgun) and spread alls bullets randomly.
My actual result is not spreading like how it should with my rotate gun.
spread_firering.png
spread_firering.png (8.43 KiB) Viewed 4840 times
So if any one got a tips in how to realise this trick ?
Thanks in advance.
Last edited by var77 on Fri Jul 12, 2019 3:35 pm, edited 1 time in total.
User avatar
var77
Citizen
Posts: 52
Joined: Wed May 02, 2018 1:57 pm

Re: Math + Spread bullets

Post by var77 »

ps: files if it's also help ^^
test.zip
(11.45 MiB) Downloaded 248 times
(sorry to post that in a reply buts seems buggy when I post multiple attachement stuff)
TheHUG
Citizen
Posts: 61
Joined: Sun Apr 01, 2018 4:21 pm

Re: Math + Spread bullets

Post by TheHUG »

currently it seems you're spawning the bullets with an offset, while what it seems you want is the spawn at the same point and adjust the velocity

So first decide at what distance you want the set of bullets to look like the shape you have in mind. let's call this distance D
Then, for each bullet with xoffst, yoffst offset from the center of target the shape X, Y (s.t. X, Y is the point in the direction of the shot, at a distance of D), you know the location you want it to be at at time t=D/speed. namely, X+xoffst, y+yoffst Then its a simple matter of calculating the velocity that gets it there - basically the vector connecting the shooter to the bullet's destination divided by t.

I'd suggest making a function that calculates all the velocities for you given a set of offsets and target distance, which you can run at initialization on all the shapes you have in mind to get a 'shot' configuration for every shot type you want.
SPlice
Prole
Posts: 48
Joined: Thu Jul 28, 2011 8:53 am

Re: Math + Spread bullets

Post by SPlice »

something like this will work

NOTE. I did not look at your code so I don't know how you actually set up your projectiles so it may need to be modified a bit to make it work as desired

Code: Select all

function setBulletVelocity(bullet)
	-- first get direction you want to shoot in radians and a speed
	speed = 200
	direction = 0 -- this will need to be set to whatever direction you want to fire
	-- than add in some random spread
	direction = direction + math.rad(math.random(-50,50)/100) -- I divided by 100 to make this number small 

	-- now set the velocity vector for your projectile

	bullet.velocity[0] = math.cos(direction )*speed
	bullet.velocity[1] = math.sin(direction )*speed
end
now add your velocity to your position every frame with dt multiplied in and it should work

Code: Select all

function projectileUpdate(projectile,dt)
	projectile.position[0] = projectile.position[0] + projectile.velocity[0] * dt
	projectile.position[1] = projectile.position[1] + projectile.velocity[1] * dt
end

User avatar
var77
Citizen
Posts: 52
Joined: Wed May 02, 2018 1:57 pm

Re: Math + Spread bullets

Post by var77 »

First of all thanks both a you for aswering me I think I see my issue more clearly.
So I got to add some "offsetX/Y" or "VelocityX/Y" to my projectile to get this effect,
with an other function that will spread my result (position X/Y).
But I guess I don't handle how in my case.

I create my projectile like this:

Code: Select all

local startX = visor.x + (visor.w / 24)
local startY = visor.y + (visor.h / 24)

-- angle rotation that depend of my mouse position --
local angle = math.atan2((mouse.y - startY), (mouse.x - startX))	
local bulletDx = visor.speed*2 * math.cos(angle) -- destination X
local bulletDy = visor.speed*2 * math.sin(angle) -- destination Y

local size = 3.45
table.insert(b, {x = startX, y = startY, dx = bulletDx, dy = bulletDy,r=size})	
table.insert(b, {x = startX, y = startY, dx = bulletDx, dy = bulletDy,r=size})	
table.insert(b, {x = startX, y = startY, dx = bulletDx, dy = bulletDy,r=size})	

Then I update position like this:

Code: Select all

if #bullets1 > 0 then
	for i,v in ipairs(bullets1) do
		v.x = v.x + (v.dx * t)
		v.y = v.y + (v.dy * t)
		if v.x < 0 or v.x > gameWidth or v.y < 0 or v.y > gameHeight then 
			table.remove(bullets1, i) -- if projectile are out from the screen remove them
		end
	end
	if #bullets1 < 1 then user.shoot1 = false end
end
If I following you well I have to add a random "offsetX/Y" or "VelocityX/Y" in:

Code: Select all

v.x = v.x + (v.dx * t) 
v.y = v.y + (v.dy * t)
--like this
v.x = v.x + (v.dx +v.velocityX * t) 
v.y = v.y + (v.dy +v.velocityY * t)
What I exactly don't understand is how I get this "offsetX/Y" or "VelocityX/Y"
with my moving angle getting from my mouse ? or what is the function ?

sorry not that good in math :(
User avatar
pgimeno
Party member
Posts: 3544
Joined: Sun Oct 18, 2015 2:58 pm

Re: Math + Spread bullets

Post by pgimeno »

var77 wrote: Wed Jul 10, 2019 8:40 pm I create my projectile like this:

Code: Select all

...
local bulletDx = visor.speed*2 * math.cos(angle) -- destination X
local bulletDy = visor.speed*2 * math.sin(angle) -- destination Y
...
Wouldn't it suffice to randomize the angle a bit? Something like this:

Code: Select all

angle = angle + love.math.random() * bulletSpreadAngle - bulletSpreadAngle/2
local bulletDx = visor.speed*2 * math.cos(angle) -- destination X
local bulletDy = visor.speed*2 * math.sin(angle) -- destination Y
You would define bulletSpreadAngle to the desired angle, for example:

Code: Select all

local bulletSpreadAngle = math.rad(5) -- 5 degrees spread
TheHUG
Citizen
Posts: 61
Joined: Sun Apr 01, 2018 4:21 pm

Re: Math + Spread bullets

Post by TheHUG »

If you don't want any specific shape you can just add love.math.random() * spread_factor to `angle` to get the angle for the bullet, as pgimeno explained.

Since I saw you were adding/subtracting specific (non-random) amounts from the bullet's position in your code:

Code: Select all

	table.insert(b, {x = startX, y = startY, dx = bulletDx, dy = bulletDy,r=size})	
	table.insert(b, {x = startX-15, y = startY+15, dx = bulletDx, dy = bulletDy,r=size})		
	table.insert(b, {x = startX-20, y = startY+20, dx = bulletDx, dy = bulletDy,r=size})		
	table.insert(b, {x = startX-25, y = startY-20, dx = bulletDx, dy = bulletDy,r=size})		
	table.insert(b, {x = startX-35, y = startY-30, dx = bulletDx, dy = bulletDy,r=size})
	table.insert(b, {x = startX-45, y = startY-40, dx = bulletDx, dy = bulletDy,r=size})
I thought you might want the bullets to form a particular shape, in which case you'll want to set their velocities by deciding what relative position each bullet should have at some (in principle any) time T and setting the amount that puts them there.

Code: Select all

local D = 200 -- number is up to you, play around with it, smaller number means bigger spread
local T = D / visor.speed*2  -- the time it will take to get there
local angle = math.atan2((mouse.y - startY), (mouse.x - startX))
local shape_center_x = D * math.cos(angle) 
local shape_center_y = D * math.sin(angle)

...
-- create the individual bullets
local xoffst, yoffst
xoffst = 0 -- choose numbers for each bullet to make your shape
yoffst = 0 
table.insert(b, {x=startX, y=startY, 
                      dx=((shape_center_x + xoffst) - shape_center_x) /  T,
                      dy=((shape_center_y + yoffst) - shape_center_y) / T,
                      r=size}
xoffst = -15
yoffst = +15
table.insert(b, {x=startX, y=startY, 
                      dx=((shape_center_x + xoffst) - shape_center_x) /  T,
                      dy=((shape_center_y + yoffst) - shape_center_y) / T,
                      r=size}
...
-- and so on
User avatar
var77
Citizen
Posts: 52
Joined: Wed May 02, 2018 1:57 pm

Re: Math + Spread bullets

Post by var77 »

First thanks again all of you. Both aproach gave interesting result.
After post my last reply I found what I was searching with just adding
two var that I may have to random:

Code: Select all

table.insert(b, {x = startX, y = startY, dx = bulletDx, dy = bulletDy,r=size,vx=15,vy=15})
-- and
v.x = v.x + ((v.dx+v.vx) * t)
v.y = v.y + ((v.dy+v.vy) * t)

Even if @pgimeno make a random start spread, what I was looking for is
closer from @TheHUG method. Control the shape of the spread was not that
expected but it make it more efficient in my release.

Unfortunatly after testing your code I guess something went wrong
with this: dx = ((shape_center_x + xoffset)-shape_center_x)/T
For me this is like: dx = xoffset/T if I'm right.
And the result is that it spread only on the left side
(and don't mind about the rotate angle).
So I change it for: dx = (shape_center_x + xoffset)/T and
it fit better but close to my last found. And here is the point.

It spread large on top of screen but line it on side of screen.
spread_firering2.png
spread_firering2.png (4.06 KiB) Viewed 4682 times
so if you got any idea why ? I guess I have to play with
additional var from startX/Y (like x = startX-15, y = startY+15)
it gave me few interesting result.
User avatar
var77
Citizen
Posts: 52
Joined: Wed May 02, 2018 1:57 pm

Re: Math + Spread bullets

Post by var77 »

Why make things easier when you can complex them... I finaly found
exactly the expected result. Sorry @pgimeno you were right (as often
with my issues) just need to add some math.rad() to the angle like this for example:

Code: Select all

table.insert(b, {x = startX, y = startY, dx = visor.speed * math.cos(angle+math.rad(1)), dy = visor.speed * math.sin(angle+math.rad(1)),r=size})		
nevermind thanks all for your answers, good to explore many method.
TheHUG
Citizen
Posts: 61
Joined: Sun Apr 01, 2018 4:21 pm

Re: Math + Spread bullets

Post by TheHUG »

var77 wrote: Thu Jul 11, 2019 4:44 pm First thanks again all of you. Both aproach gave interesting result.
After post my last reply I found what I was searching with just adding
two var that I may have to random:

Code: Select all

table.insert(b, {x = startX, y = startY, dx = bulletDx, dy = bulletDy,r=size,vx=15,vy=15})
-- and
v.x = v.x + ((v.dx+v.vx) * t)
v.y = v.y + ((v.dy+v.vy) * t)

Even if @pgimeno make a random start spread, what I was looking for is
closer from @TheHUG method. Control the shape of the spread was not that
expected but it make it more efficient in my release.

Unfortunatly after testing your code I guess something went wrong
with this: dx = ((shape_center_x + xoffset)-shape_center_x)/T
For me this is like: dx = xoffset/T if I'm right.
And the result is that it spread only on the left side
(and don't mind about the rotate angle).
So I change it for: dx = (shape_center_x + xoffset)/T and
it fit better but close to my last found. And here is the point.

It spread large on top of screen but line it on side of screen.

spread_firering2.png

so if you got any idea why ? I guess I have to play with
additional var from startX/Y (like x = startX-15, y = startY+15)
it gave me few interesting result.
Oops, quite silly of me, it was supposed to be:
dx = ((shape_center_x + xoffst) - start_X)

and I forgot to consider that you might want to rotate the shape by angle. But if pgimeno's solutions does what you want there's no reason to add complexity.
Post Reply

Who is online

Users browsing this forum: Google [Bot] and 48 guests