[Solved] Shooting towards the mouse with rotated image

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.
Post Reply
User avatar
nikneym
Citizen
Posts: 56
Joined: Sat Mar 09, 2013 1:22 pm
Contact:

[Solved] Shooting towards the mouse with rotated image

Post by nikneym »

Solved! Updated version:

Code: Select all

graphics = love.graphics
graphics.setDefaultFilter("nearest", "nearest")

local gun = {
		img = graphics.newImage("gun.png"),
		x = 100,
		y = 100,
	}

local angle = 0
local half_pi = math.pi / 2

local bul = {
	x = 0,
	y = 0,
	vx = 0,
	vy = 0,

	speed = 500,
}

function love.update(dt)
	bul.x = bul.x + bul.vx * dt
	bul.y = bul.y + bul.vy * dt
end

function love.mousemoved(x, y)
	angle = math.atan2(y - gun.y * 2, x - gun.x * 2)
end

function love.mousepressed(x, y, b)
	if b == 1 then
		bul.x = gun.x + 7 * math.cos(angle)
		bul.y = gun.y + 7 * math.sin(angle)
		bul.vx = bul.speed * math.cos(angle)
		bul.vy = bul.speed * math.sin(angle)
	end
end

function love.keypressed(key)
	if key == "escape" then
		love.event.quit()
	end
end

function love.draw()
	graphics.push()
		graphics.scale(2)

		graphics.draw(gun['img'], gun.x, gun.y, angle, 1, (angle > half_pi or angle < -half_pi) and -1 or 1, 6, 3)
		graphics.circle("line", bul.x, bul.y, 1)
	graphics.pop()
end
Attachments
gun.png
gun.png (131 Bytes) Viewed 4067 times
Last edited by nikneym on Sun Aug 02, 2020 10:57 am, edited 1 time in total.
User avatar
redsled
Prole
Posts: 38
Joined: Wed Jun 04, 2014 6:33 am

Re: Shooting towards the mouse with rotated image

Post by redsled »

Use some trig with the angle instead of integer constants in love.mousepressed. Something like this:

Code: Select all

local radius = 22
local startX = (gun.x + math.cos(angle) * radius) * 2
local startY = (gun.y + math.sin(angle) * radius) * 2
The solution is to find a point on a circle with the angle calculated using a reference point (the gun origin) and the mouse position. Kinda like taking a string that's nailed down at one end and loose at the other, where you can freely pull the open end of the string around in a perfect circle. Where you would hold the string with your fingers would be the starting points for the bullets.

I would also recommend translating the gun image position in love.draw but I'm not quite sure how you specifically want the gun to look. I.e.

Code: Select all

local ox = gun['img']:getWidth() / 2
local oy = gun['img']:getHeight() / 2
if angle > -1.5 and angle < 1.5 then
	graphics.draw(gun['img'], gun.x, gun.y, angle, 1, 1, ox, oy)
else
	graphics.draw(gun['img'], gun.x, gun.y, angle, 1, -1, ox, oy)
end
Note: If the slopes of the bullets aren't parallel with the barrel of the gun, try making the gun barrel parallel with the x-axis when the sprite is drawn.
User avatar
pgimeno
Party member
Posts: 3544
Joined: Sun Oct 18, 2015 2:58 pm

Re: Shooting towards the mouse with rotated image

Post by pgimeno »

Hm, you're in a "chicken and egg" situation there. You need the angle to calculate the starting position of the bullet, but you need the starting position of the bullet to calculate the angle.

This can be dealt with by solving some equations to find out the correct formulas, or more easily, by aligning the origin of the gun image with the trajectory of the bullet, that is, placing the origin at the centre of the gun's barrel. The centre of the barrel is not necessarily the centre of the image, and it doesn't seem to be in this case, which is why getWidth/2 and getHeight/2 are not a good origin position.

Once the origin is at the centre of the barrel, the gun's position and the mouse position can be used to correctly determine the angle of the bullet. Otherwise the angle will be visibly off when the mouse is close to the gun.
User avatar
nikneym
Citizen
Posts: 56
Joined: Sat Mar 09, 2013 1:22 pm
Contact:

Re: Shooting towards the mouse with rotated image

Post by nikneym »

redsled wrote: Fri Jul 31, 2020 12:54 pm Use some trig with the angle instead of integer constants in love.mousepressed. Something like this:
Is it like creating an invisible circle around the gun and getting startX and Y according to it? I changed rad to 8 but because of the gun's origin, it still fires from beneath.

I updated the draw function same as you recommend and it looks a lot well now thanks!
pgimeno wrote: Fri Jul 31, 2020 4:35 pm Once the origin is at the centre of the barrel, the gun's position and the mouse position can be used to correctly determine the angle of the bullet. Otherwise the angle will be visibly off when the mouse is close to the gun.
In order to get the barrel coordinate, should i create a new variable like gun.x + 14 and move on? I know im being an ass with dumb questions but i really want to learn.
User avatar
pgimeno
Party member
Posts: 3544
Joined: Sun Oct 18, 2015 2:58 pm

Re: Shooting towards the mouse with rotated image

Post by pgimeno »

nikneym wrote: Fri Jul 31, 2020 4:55 pm In order to get the barrel coordinate, should i create a new variable like gun.x + 14 and move on? I know im being an ass with dumb questions but i really want to learn.
Look at this example. The image is 100 x 100. The red line marks the centre of the barrel which is at y=24 of the image, so I've picked x=28 y=24 as origin. The choice of x=28 was because it meets the centre of the grip approximately and looked like a good pivot point.

Edit: Forgot to say, 93 is the X coordinate within the image where the bullet should be placed, right past the end of the barrel. Since the origin is at x=28, the relative position of the bullet with respect to the origin is 93-28. Sorry for the magic numbers.

To run the example, save this as main.lua and the image as gun.png:

Code: Select all

local lg = love.graphics

local bullet_spd = 400
local gun
local half_pi = 1.5707963267948966

local gun_x, gun_y, gun_angle = lg.getWidth()/2, lg.getHeight()/2, 0
local bullet_x, bullet_y, bullet_vx, bullet_vy

function love.mousemoved(x, y)
  gun_angle = math.atan2(y - gun_y, x - gun_x)
end

function love.mousepressed(x, y, b)
  if b == 1 then
    bullet_x = gun_x + (93-28) * math.cos(gun_angle)
    bullet_y = gun_y + (93-28) * math.sin(gun_angle)
    bullet_vx = bullet_spd * math.cos(gun_angle)
    bullet_vy = bullet_spd * math.sin(gun_angle)
  end
end

function love.keypressed(k)
  if k == "escape" then return love.event.quit() end
end

function love.load()
  gun = lg.newImage('gun.png')
end

function love.update(dt)
  if bullet_x then
    bullet_x = bullet_x + bullet_vx * dt
    bullet_y = bullet_y + bullet_vy * dt
  end
end

function love.draw()
  lg.draw(gun, gun_x, gun_y, gun_angle,
    1, (gun_angle > half_pi or gun_angle < -half_pi) and -1 or 1,
    28, 24)
  if bullet_x then
    lg.rectangle("fill", bullet_x - 1, bullet_y - 1, 3, 3)
  end
end
gun.png
gun.png (688 Bytes) Viewed 4125 times
User avatar
nikneym
Citizen
Posts: 56
Joined: Sat Mar 09, 2013 1:22 pm
Contact:

Re: Shooting towards the mouse with rotated image

Post by nikneym »

I've worked on your example and was able to accomplish. Thank you so much, another question of mine solved by pgimeno. Well, here is the updated code and gun image:

Code: Select all

graphics = love.graphics
graphics.setDefaultFilter("nearest", "nearest")

local gun = {
		img = graphics.newImage("gun.png"),
		x = 100,
		y = 100,
	}

local angle = 0
local half_pi = math.pi / 2

local bul = {
	x = 0,
	y = 0,
	vx = 0,
	vy = 0,

	speed = 500,
}

function love.update(dt)
	bul.x = bul.x + bul.vx * dt
	bul.y = bul.y + bul.vy * dt
end

function love.mousemoved(x, y)
	angle = math.atan2(y - gun.y * 2, x - gun.x * 2)
end

function love.mousepressed(x, y, b)
	if b == 1 then
		bul.x = gun.x + 7 * math.cos(angle)
		bul.y = gun.y + 7 * math.sin(angle)
		bul.vx = bul.speed * math.cos(angle)
		bul.vy = bul.speed * math.sin(angle)
	end
end

function love.keypressed(key)
	if key == "escape" then
		love.event.quit()
	end
end

function love.draw()
	graphics.push()
		graphics.scale(2)

		graphics.draw(gun['img'], gun.x, gun.y, angle, 1, (angle > half_pi or angle < -half_pi) and -1 or 1, 6, 3)
		graphics.circle("line", bul.x, bul.y, 1)
	graphics.pop()
end
gun.png
gun.png (131 Bytes) Viewed 4067 times
Post Reply

Who is online

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