using calculus to determine position

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
wraneus
Prole
Posts: 2
Joined: Mon May 31, 2021 11:33 pm

using calculus to determine position

Post by wraneus »

I'm working on a hammer throwing game using calculus where a circle representing a hammer orbits a circle representing a player. the hammer will orbit the player until the user pushes the "space" key, setting the "thrown" state to true. I'm was hoping to use the derivative of a circle dYdX to determine the slope of the tangent line to the curve at angle ctheta and update the hammer's x value coordinates (kept in a variable called hxpos) by 1 and y value coordinates (hypos) by dYdX. When I say
if hypos < windowwidth/2 and hypos < windowheight/2 then
hxpos = hxpos + 1
hypos = hypos + dYdX
end
I was hoping to increment the y value by dYdX for every unit that hxpos increases, however when I run this code and set the state to "thrown" with the "space" key, the hammer circle does not move at a tangent to the circle at angle ctheta, but rather in a straight horizontal line. Could I have some help to determine why hypos is not being updated by dYdX?
here is my code as it stands. This is my first post here so I'm not sure what the guidelines of posting code are. I've created a pastebin link to my code so this post isn't so cluttered. Is this the way I'm supposed to post code?
https://pastebin.com/Td8ZP83f
I've written my own circle function just so I'd understand how to draw circles without using the circle() function. I've named my circle function which I've named cjrcle() and am keeping in a separate file called cjrcle.lua. here is my cjrcle() function
function cjrcle(r, x, y)
for dtheta = math.pi, 0, -math.pi/512 do
love.graphics.line(r*math.cos(dtheta) + x, r*math.sin(dtheta) + y, r*math.cos(-dtheta) + x, r*math.sin(-dtheta) + y)
end
end
Attachments
main.lua
(8.97 KiB) Downloaded 145 times
cjrcle.lua
(430 Bytes) Downloaded 150 times
User avatar
darkfrei
Party member
Posts: 1169
Joined: Sat Feb 08, 2020 11:09 pm

Re: using calculus to determine position

Post by darkfrei »

Code: Select all

function cjrcle(r, x, y)
    for dtheta = math.pi, 0, -math.pi/512 do
        love.graphics.line(r*math.cos(dtheta) + x, r*math.sin(dtheta) + y, r*math.cos(-dtheta) + x, r*math.sin(-dtheta) + y)
    end
end
Just why?
I can understand if you draw pixels or rectangles, but why lines?

Code: Select all

-- pixilated circle
points = {}
for y = -r, r do -- r is radius, integer
    -- mx is min x and max x for current horizontal line
    --local mx = r*math.cos (math.arcsin(y/r))
    local mx = math.ceil(r*(1-(y/r)^2)^0.5)
    for x = -mx, mx do
        table.insert (points, x)
        table.insert (points, y)
    end
end
-- tested
Last edited by darkfrei on Tue Jun 22, 2021 10:09 am, edited 4 times in total.
:awesome: in Lua we Löve
:awesome: Platformer Guide
:awesome: freebies
wraneus
Prole
Posts: 2
Joined: Mon May 31, 2021 11:33 pm

Re: using calculus to determine position

Post by wraneus »

lines don't have width to them and will thus approximate each point on the circle in π/512 increments. a rectangle would have width to it if it were larger than a pixel so it seemed easier to just use a line directly rather than using many pixels to create the line. Bottom line... it works!
User avatar
darkfrei
Party member
Posts: 1169
Joined: Sat Feb 08, 2020 11:09 pm

Re: using calculus to determine position

Post by darkfrei »

The line is thicker as you think:
https://love2d.org/forums/viewtopic.php?t=88642

Yes, the line (-mx, y, mx, y) must be fast and give full filling. You can also skip some lines and get some hatching.
:awesome: in Lua we Löve
:awesome: Platformer Guide
:awesome: freebies
User avatar
pgimeno
Party member
Posts: 3544
Joined: Sun Oct 18, 2015 2:58 pm

Re: using calculus to determine position

Post by pgimeno »

Seriously, why do people have that fixation of using trigonometry instead of linear algebra for linear algebra problems?

The answer to your question is, because you're not calculating dYdX correctly.

But the thing is, that's not the best way to approach this problem. In this case, the tangent to a circle at a point in the perimeter is a vector that is rotated 90° with respect to the radius that goes from the centre to that point. So, take a unit radius, rotate it 90° and you have a tangent vector. Rotating by 90° is trivial: rotating the vector (x, y) by 90° gives you (-y, x). If (x, y) is a unit vector, like the one you get from the sine and cosine of the angle, then the result will also be a unit vector, letting you multiply it by the desired velocity directly.

I see you're also doing some numeric fiddling in order to always increase one of the coordinates by 1. That's not going to give you a constant speed in all directions, and that's bad.

Proof of concept:

Code: Select all

local px, py = 400, 300

local hradius = 50 -- radius of hammer
local hx, hy       -- hammer position
local hnx, hny     -- normal
local hangle = 0   -- hammer angle with respect to player
local omega = math.rad(60) -- angular velocity = 60 degrees per second

local thrown = false
local first_time = true

local unitx, unity -- unit vector with angle = hangle

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

function love.update(dt)
  -- If it's the first time and the key comes before any variable is assigned,
  -- there will be errors. The variable first_time causes that in this case,
  -- the hammer angle calculations are run at least once.
  if first_time or not thrown then
    unitx = math.cos(hangle)
    unity = math.sin(hangle)
    -- calculate position of hammer in the circle
    hx = unitx * hradius + px
    hy = unity * hradius + py
    -- normal = unit rotated 90 deg
    hnx = -unity
    hny = unitx
    -- increase angle by angular velocity
    hangle = hangle + omega * dt
  end
  if thrown then
    -- Tangential speed is omega * hradius.
    -- Delta speed is tangential speed * delta time.
    local dspeed = omega * hradius * dt

    -- The unit direction vector is the normal, (hnx, hny).
    hx = hx + dspeed * hnx
    hy = hy + dspeed * hny
  end
  first_time = false
end

function love.draw()
  love.graphics.circle("line", px, py, hradius)
  love.graphics.circle("fill", hx, hy, 10)
  local orig_x = px + unitx * hradius
  local orig_y = py + unity * hradius
  love.graphics.line(px, py, orig_x, orig_y)
  love.graphics.line(orig_x, orig_y,
     orig_x + hnx * hradius * omega,
     orig_y + hny * hradius * omega)
end
You also asked how you paste snippets. If they aren't too long, like in this case, you can paste them using [code]...[/code] tags, like I did in the above proof of concept.
Post Reply

Who is online

Users browsing this forum: Ahrefs [Bot], Google [Bot] and 47 guests