Reputation: 345
Using this function to draw a "Circle", I really come up with something of an oval. This is because of malformed pixels I am working with that aren't really relevant other than they make this function necessary.
local function drawCircle( centerX, centerY, radius, col, solid )
solid = solid or false
local isAdvanced = term.isColor and term.isColor()
local char = isAdvanced and " " or "|"
if isAdvanced then term.setBackgroundColor( col ) end
local radStep = 1/(1.5*radius)
for angle = 1, math.pi+radStep, radStep do
local pX = math.cos( angle ) * radius * 1.5
local pY = math.sin( angle ) * radius
if solid then
local chord = 2*math.abs(pX)
term.setCursorPos( centerX - chord/2, centerY - pY )
write( char:rep( chord ) )
term.setCursorPos( centerX - chord/2, centerY + pY )
write( char:rep( chord ) )
else
for i=-1,1,2 do
for j=-1,1,2 do
term.setCursorPos( centerX + i*pX, centerY + j*pY )
write( char )
end
end
end
end
end
Now, I'm making a game that involves planets (ei the circle), but because of limitations I can only run it at 10 FPS. I end up with so much acceleration in the game that the ship can move faster per 10th of a second than the diameter of the "circle", so I'm looking for a simple (and hopefully fast) way to calculate if the ship will hit the planet when it magically teleports between point A and point B.
As an example, lets say I have my ship at 75, 100 and it's momentum will move it +80, -50. It'll end up at 155, 50. Between those two points is my planet, but how do I detect it?
I've googled a bit, but didn't come up with anything I could comprehend. I'm in 11th grade math, just solving systems of equations, although I'm also in engineering classes, where I learned force vectors.
If it helps, the planet doesn't move.
Upvotes: 0
Views: 464
Reputation: 3413
You have two equations:
(1) The circle:
(k*x)^2 + y^2 = r^2
(The 'k' squeezes the graph to achieve an oval. In your case k = 2/3. There's a site "Purple Math" with a chapter on "Transformations". Read it.)
(2) The line:
a*x + b*y = c
Now, you'll notice that, for simplicity, I assumed the circle's center is at the origin. In your case it usually isn't, so you'll simply shift the line's start and end points to match it. (It doesn't matter where objects are: it only matters where they're in relation to each other. So we're allowed to move objects as a group up/down right/left however we want.)
So we have two equations. "Solving them" = "finding the points where they touch" = "collision". So we need to solve them. To solve them you find y from equation (2) and replace it in equation (1). You get an equation with only x (and x^2):
.... x ... x^2 .... = ....
You arrange ("factor") this equation on x:
x^2(b^2 k^2 + a^2) + x(-2ac) + c^2 - r^2 b^2 = 0
That's a quadratic formula.
Now, you're asking whether the oval and line intersect ("calculate if the ship will hit the planet"). In other words, you're asking whether there's any solution to this equation (you're not asking for the solutions themselves). There's a solution if the discriminant is greater/equal to zero. The discriminant is "B^2 - 4AC", where:
A = b^2 k^2 + a^2
B = -2ac
C = c^2 - r^2 b^2
So "B^2 - 4AC" is:
4*b^2*(a^2*r^2+b^2*r^2*k^2-k^2*c^2)
That's all!
It's a simple expression.
You know b,a,r,k,c, so you put them in that expression and if it's greater/equal to zero you know there's a collision.
If you don't understand my explanation, install GeoGebra, then type into it:
k = 0.5
r = 1
circ: (k x)² + y² = r²
a = 5
b = -2.5
c = 4
line: a x + b y = c
dis = 4a² b² r² + 4b⁴ k² r² - 4b² c² k²
Now, make k/r/a/b/c sliders and change their values with your mouse. You'll notice that when there's a collision, "dis" (the discriminant) is negative.
Finally, what you've left to do:
You need to write a function that gets the circle and line and tells if there's a collision:
function do_collide(
-- the circle:
centerX, centerY, radius,
-- the line:
x1, y1, x2, y2)
-- Step 1:
-- You already know r and k.
-- Step 2:
-- Shift the coordinates (x1,x2) and (x2,y2) by (centerX, centerY).
-- Find the line equation and you have a,b,c.
-- Step 3:
return 4*b^2*(a^2*r^2+b^2*r^2*k^2-k^2*c^2) >= 0
end
Upvotes: 2