I'm new to love and I am building a little space shooter. I need to figure out how to get local coords to manipulate a physics body in the game. Basically I need to figure out how to rotate my ship on screen using the mouse, and then I want to dampen the rotation so it feels slow like a ship or tank turret. I thought I may be able to figure this out if I had the local coords but I'm not sure now. I've done some digging and I cannot figure out how to do this. Any help would be greatly appreciated.
If anyone is curious about my project goal or what I am trying to do here, I want to make a game like Battle Stations (PS1) but with space ships. Maybe later add networking then add the ability to raid ships with a friend or something cool that adds another layer of gameplay. My goal for me with this project is to become a better programmer and have something to show for it. I figured that if I made a game that would be the perfect challenge for me, since games do cover a variety of advanced programming topics.
How do I get local coords?
Forum rules
Before you make a thread asking for help, read this.
Before you make a thread asking for help, read this.
How do I get local coords?
Last edited by wburton95 on Mon Dec 17, 2018 11:28 pm, edited 2 times in total.
Re: How do I get local coords?
I'm not sure what you're using for phyics, but physics bodies are almost always in world coordinates. Local coordinates are generally used for attaching child objects (guns, etc) to a body, not for interacting with other bodies or things like the mouse cursor.
You could possibly use the Transform objects to handle transforms, but for this case you probably don't need anything that complicated.
If your body is at a given angle, then you can get the direction as a vector (xFwd, yFwd = math.cos(angle), math.sin(angle)). That will give you a unit vector (length 1) so you can multiply it by the strength of your force and use that for the acceleration.
To rotate, you can get the vector from the body to your mouse and compute its angle with math.atan2(y, x) (note that x and y are swapped here: it's a math function, not a vector function). Then you can subtract the body angle and wrap the result into -PI..PI with
Finding a good function for how much torque to apply to get nice rotation will probably take some experimentation. And you might have to map the mouse from screen coordinates to world coordinates if your view scrolls. That would probably be a function of whatever camera library you're using.
------
Note that since screen coordinates often have the y-coordinate flipped from "math" coordinates, angles will start facing right and go clockwise instead of counter-clockwise. Also some people like to have the zero angle be facing up for spaceships. While you can adjust your coordinates for that by flipping the sign of the y coordinate and/or rotating the whole thing by 90 degrees (in 2D, a 90-degree rotation is x, y = -y, x), I don't recommend it. It's not necessary, and it's a big source of hard-to-diagnose bugs.
I'd highly recommend just accepting that the zero direction is to the right and that angles go clockwise, and mapping your controls and designing your graphics facing right to match that.
You could possibly use the Transform objects to handle transforms, but for this case you probably don't need anything that complicated.
If your body is at a given angle, then you can get the direction as a vector (xFwd, yFwd = math.cos(angle), math.sin(angle)). That will give you a unit vector (length 1) so you can multiply it by the strength of your force and use that for the acceleration.
To rotate, you can get the vector from the body to your mouse and compute its angle with math.atan2(y, x) (note that x and y are swapped here: it's a math function, not a vector function). Then you can subtract the body angle and wrap the result into -PI..PI with
Code: Select all
local function wrapAngle(radians)
return math.pi - (math.pi - radians) % (2 * math.pi)
end
------
Note that since screen coordinates often have the y-coordinate flipped from "math" coordinates, angles will start facing right and go clockwise instead of counter-clockwise. Also some people like to have the zero angle be facing up for spaceships. While you can adjust your coordinates for that by flipping the sign of the y coordinate and/or rotating the whole thing by 90 degrees (in 2D, a 90-degree rotation is x, y = -y, x), I don't recommend it. It's not necessary, and it's a big source of hard-to-diagnose bugs.
I'd highly recommend just accepting that the zero direction is to the right and that angles go clockwise, and mapping your controls and designing your graphics facing right to match that.
Re: How do I get local coords?
Note that 11.2 added Body:setTransform and Body:getTransform. To transform the mouse to local coordinates, you can use something like this:
That assumes that your units are pixels and the origin of the world is at the top left corner of the screen, which may or may not be the case. If not, then you first need to transform the mouse position from screen coordinates to physics world coordinates.
EDIT: I completely forgot about Body:getLocalPoint which obviates the need for getTransform(). Simpler code:
Code: Select all
local x, y, angle = body:getTransform()
local LmouseX, LmouseY = love.mouse.getPosition()
LmouseX, LmouseY = LmouseX - x, LmouseY - y
local c, s = math.cos(angle), math.sin(angle)
LmouseX, LmouseY = c * LmouseX + s * LmouseY, -s * LmouseX + c * LmouseY
EDIT: I completely forgot about Body:getLocalPoint which obviates the need for getTransform(). Simpler code:
Code: Select all
local LmouseX, LmouseY = love.mouse.getPosition()
LmouseX, LmouseY = body:getLocalPoint(LMouseX, LMouseY)
Last edited by pgimeno on Thu Dec 20, 2018 2:14 pm, edited 3 times in total.
Re: How do I get local coords?
Here is my script so far.
Code: Select all
function love.load()
love.graphics.setDefaultFilter('nearest', 'nearest')
world = love.physics.newWorld(0,0,true)
redship = {}
redship['body'] = love.physics.newBody(world, 0, 0, "dynamic")
redship['shape'] = love.physics.newRectangleShape(5,5)
redship['image'] = love.graphics.newImage("/ships/red-ship.png")
redship['fixture'] = love.physics.newFixture(redship.body,redship.shape,10)
end
function love.update(dt)
world:update(dt)
--[[
--What do I do here?
local mx, my = love.mouse.getPosition()
local sx = redship.body:getX()
local sy = redship.body:getY()
local angle = math.atan2((my - sy), (mx - sx))
redship.body:setAngle(angle)
]]
local force = 10
redship.body:setLinearDamping(0.50)
redship.body:setAngularDamping(0.50)
if love.keyboard.isDown("w") then
redship.body:applyForce(0, -force)
elseif love.keyboard.isDown("s") then
redship.body:applyForce(0,force)
elseif love.keyboard.isDown("a") then
redship.body:applyForce(-force,0)
elseif love.keyboard.isDown("d") then
redship.body:applyForce(force,0)
end
end
function love.draw()
love.graphics.push()
love.graphics.scale(3,3)
love.graphics.draw(redship.image, redship.body:getX(), redship.body:getY(), redship.body:getAngle(), 1, 1, redship.image:getWidth()/2, redship.image:getHeight()/2)
love.graphics.pop()
end
Re: How do I get local coords?
You're using love.graphics.scale(3, 3) before drawing, and you're drawing using the body's coordinates. That means the mouse coordinates need to be divided by 3 to transform them to physics world coordinates.
To transform the mouse position to coordinates local to the body (LmouseX and LmouseY), the code would become:
(I've just added the / 3 step to the previous code).
To transform the mouse position to coordinates local to the body (LmouseX and LmouseY), the code would become:
Code: Select all
local LmouseX, LmouseY = love.mouse.getPosition()
LmouseX, LmouseY = body:getLocalPoint(LmouseX / 3, LmouseY / 3)
Last edited by pgimeno on Thu Dec 20, 2018 2:12 pm, edited 1 time in total.
Re: How do I get local coords?
Sorry for the double post. I've read your OP again now. Certainly I wouldn't use local coordinates to do that. An approach that may give decent results is to turn the ships at constant angular velocity. You need the difference between the original angle and the target angle, and the sign of that will let you decide whether to turn left or right at a certain fixed angular speed, which you can do with Body:setAngularVelocity.
The problem is the handling of overshooting. I think that can be done with this method: if the difference between current angle and new angle is bigger than the difference between current angle and target angle, in the same direction you're rotating, then you keep moving; if not, you're overshooting, so you set the angle to the target angle.
The problem is the handling of overshooting. I think that can be done with this method: if the difference between current angle and new angle is bigger than the difference between current angle and target angle, in the same direction you're rotating, then you keep moving; if not, you're overshooting, so you set the angle to the target angle.
Re: How do I get local coords?
Thank you so much for your help! You rock dude! I finally got the ship to point at the mouse now. My ship sprite rotates and follows the mouse as expected. Now I am going to try and figure out how to use physics to spin my object in the way your mentioned above.pgimeno wrote: ↑Mon Dec 17, 2018 10:41 pm Sorry for the double post. I've read your OP again now. Certainly I wouldn't use local coordinates to do that. An approach that may give decent results is to turn the ships at constant angular velocity. You need the difference between the original angle and the target angle, and the sign of that will let you decide whether to turn left or right at a certain fixed angular speed, which you can do with Body:setAngularVelocity.
The problem is the handling of overshooting. I think that can be done with this method: if the difference between current angle and new angle is bigger than the difference between current angle and target angle, in the same direction you're rotating, then you keep moving; if not, you're overshooting, so you set the angle to the target angle.
Re: How do I get local coords? Rotating a sprite with physics. [Solved]
Here is my code. It works! Thank you again for all your help.
Code: Select all
function love.load()
love.graphics.setDefaultFilter('nearest', 'nearest')
world = love.physics.newWorld(0,0,true)
redship = {}
redship['body'] = love.physics.newBody(world, 0, 0, "dynamic")
redship['shape'] = love.physics.newRectangleShape(5,5)
redship['image'] = love.graphics.newImage("/ships/red-ship.png")
redship['fixture'] = love.physics.newFixture(redship.body,redship.shape,10)
end
function love.update(dt)
world:update(dt)
local force = 10
redship.body:setLinearDamping(0.8)
sx, sy, angle = redship.body:getTransform()
mx, my = love.mouse.getPosition()
mx, my = mx / 3, my / 3
pos = math.atan2((mx - sx), (my - sy))
if -pos >= angle + 0.02 then
redship.body:setAngularVelocity(0.5)
elseif -pos <= angle - 0.02 then
redship.body:setAngularVelocity(-0.5)
else
redship.body:setAngularVelocity(0)
end
if love.keyboard.isDown("w") then
redship.body:applyForce(0, -force)
elseif love.keyboard.isDown("s") then
redship.body:applyForce(0,force)
elseif love.keyboard.isDown("a") then
redship.body:applyForce(-force,0)
elseif love.keyboard.isDown("d") then
redship.body:applyForce(force,0)
end
end
function love.draw()
love.graphics.push()
love.graphics.scale(3,3)
love.graphics.draw(redship.image, redship.body:getX(), redship.body:getY(), redship.body:getAngle(), 1, 1, redship.image:getWidth()/2, redship.image:getHeight()/2)
love.graphics.print(angle)
love.graphics.print(pos,0,10)
love.graphics.pop()
end
Who is online
Users browsing this forum: Ahrefs [Bot] and 9 guests