Pygame make a circle rotate around another - python

I would like to make some kind of solar system in pygame. I've managed to do a fixed one but I thought it would be more interesting to do one with planets moving around the sun and moons around planets etc. Is there a way I could do that (using pygame if possible)?
What I would like is :
Sun = pygame.draw.circle(...)
planet1 = pygame.draw.circle(...)
etc.
a = [planet1, planet2, ...]
for p in a:
move p[2] to pos(x, y)
That is what I think would work but I'm not sure how to do it. Also, I've thought about deleting the ancient planet and drawing a new one right next to it, but problem is I'm using random features (like colours, distance to the sun, number of planets in the system etc.) and it would have to keep these same features. Any ideas?
Thanks in advance!

You can implement gravity with Newton's Law of Universal Gravitation and Newton's Second Law to get the accelerations of the planets. Give each planet an initial position, velocity and mass. Acceleration is change in velocity a = v * dt, velocity is change in position v = r * dt, so we can integrate to find velocity and position.
Universal gravitation: F = G * m1 * m2 / r ** 2 where F is the magnitude of the force on the object, G is the gravitational constant, m1 and m2 are the masses of the objects and r is the distance between the two objects.
Newton's Second Law: F = m1 * a where a is the acceleration.
dt = 0.01 # size of time step
G = 100 # gravitational constant
def calcGravity(sun, planet):
'Returns acceleration of planet with respect to the sun'
diff_x = sun.x - planet.x
diff_y = sun.y - planet.y
acceleration = G * sun.mass / (diff_x ** 2 + diff_y ** 2)
accel_x = acceleration * diff_x / (diff_x ** 2 + diff_y ** 2)
accel_y = acceleration * diff_y / (diff_x ** 2 + diff_y ** 2)
return accel_x, accel_y
while True:
# update position based on velocity
planet.x += planet.vel_x * dt
planet.y += planet.vel_y * dt
# update velocity based on acceleration
accel_x, accel_y = calcGravity(sun, planet)
planet.vel_x += accel_x * dt
planet.vel_y += accel_y * dt
This can produce circular and elliptical orbits. Creating an orbiting moon requires a very small timestep (dt) for the numeric integration.
Note: this approach is subtly inaccurate due to the limits of numeric integration.
Sample implementation in pygame here, including three planets revolving around a sun, a moon, and a basic orbital transfer.
https://github.com/c2huc2hu/orbital_mechanics

Coordinates of a planet rotated about the Sun through some angle with respect to the X-axis are , where r is the distance to the Sun, theta is that angle, and (a, b) are the coordinates of the sun. Draw your circle centered at (x, y).
EDIT:
General elliptical orbit:
Where
r0 is the radius of a circular orbit with the same angular momentum, and e is the "eccentricity" of the ellipse

Related

How to move mouse along arc given by 3 points and a length?

I'm currently working on a section of a program that moves the mouse in an arc.
I'm given three points that define the arc: a starting point p1, a intermediate point on the arc p2 , and the end point p3. I'm also given length of the arc. If length is greater than the actual length of the arc subtended by p1 and p3, then p3 will not be the end point of the arc, but the mouse will continue moving in a circle until it has traveled distance length.
I have worked out the center of the circle (x, y), its radius r, and angle sweeped.
To move the mouse, am hoping to divide angle into smaller intervals each with angle dAngle and moving the mouse between its current position and the new position after sweeping dAngle. What I have in mind is in the pseudocode below:
for i in range(intervals):
x = center.x + r * cos(i * dAngle)
y = center.y + r * sin(i * dAngle)
Move mouse to (x, y)
Sleep 1
However, I've encountered some problems while trying to parametrically find the new point on the arc.
My mouse does not start at p1, but at what I assume is at the point where the line from the mouse to the center and the horizontal line subtends 0 degees, as I haven't factored into the parameters the initial angle. How do I find the initial angle of the mouse?
How do I determine whether to rotate clockwise or anticlockwise, i.e. whether x = center.x + r * cos(i * dAngle) or x = center.x - r * cos(i * dAngle)
If there is a more efficient way of moving in an arc please suggest it.
You can calculate starting angle as
a1 = math.atan2(p1.y-center.y, p1.x-center.x)
then use it in
x = center.x + r * cos(a1 + i * dAngle)
y = center.y + r * sin(a1 + i * dAngle)
About direction - perhaps you can determine direction when arc center is calculated. If no, and arc sweep angle is less than Pi (180 degrees), just find sign of expression
sg = math.sign((p1.x-center.x) * (p3.y-center.y) - (p1.y-center.y) * (p3.x-center.x))
and use it with dAngle
x = center.x + r * cos(a1 + i * sg * dAngle)
similar for y
P.S. note that minus in x = center.x - r * cos(i * dAngle) is wrong way to change direction

calculating an intercept point between a straight line and an ellipse - python

Iv'e been trying lately to calculate a point an ellipse
The desired point is the green point , knowing the red dots
and the ellipse equation.
I've used numpy linspace to create an array on points
and iterate them using zip(x axis , y axis)
between the red points , and using the ellipse
equation figure which of the points is the closest to 1.
(which is the outcome of the ellipse equation ).
this concept works most of the time , but in some location
of the red outer dot , this method doesn't seem to give good outcome
long story short, any idea how to calculate the green dot in python?
p.s - ellipse might have angle, both of hes axis are known.
I end up using the ellipse equation from this answer:
and created an in_ellipse function
then Iv'e used the Intermediate value theorem , to get a good estimation
of the point
def in_ellipse(point, ellipse):
return true if point in ellipse
return false
dot_a = ellipse_center
dot_b = dot
for i in range(20):
center_point = ((dot_b.y - dot_a.y)/2, (dot_b.x - dot_a.x)/2)
if in_ellipse(center_point):
dot_a = center_point
else:
dot_b = center_point
return center_point
this system gives the point in 7 (2^20) digits resolution after decimal point
you can increase the range for better resolution.
Let ellipse center is (0,0) (otherwise just subtract center coordinates), semi-axes are a, b and rotation angle is theta. We can build affine tranformation to transform ellipse into circle and apply the same transform to point P.
1) Rotate by -theta
px1 = px * Cos(theta) + py * Sin(theta)
py1 = -px * Sin(theta) + py * Cos(theta)
2) Extend (or shrink) along OY axis by a/b times
px2 = px1
py2 = py1 * a / b
3) Find intersection point
plen = hypot(px2, py2) (length of p2 vector)
if (a > plen), then segment doesn't intersect ellipse - it fully lies inside
ix = a * px2 / plen
iy = a * py2 / plen
4) Make backward shrinking
ix2 = ix
iy2 = iy * b / a
5) Make backward rotation
ixfinal = ix2 * Cos(theta) - iy2 * Sin(theta)
iyfinal = ix2 * Sin(theta) + iy2 * Cos(theta)

Why has this piece of code to be there?

I try to understand this code and I actually understood the whole thing except these 2 line:
f_grav = gravity * sun.mass * earth.mass * (sun.pos - earth.pos).norm() / (sun.pos - earth.pos).mag2
earth.vel = earth.vel + (f_grav/earth.mass) * dt
Why couldn't it just be: f_grav = gravity * sun.mass * earth.mass / (sun.pos-earth.pos)**2
I also dont get the role of .norm() and .mag2
Here is the whole code snippet of the program(GlowScript):
sunRadius = 10 * realSunRadius # the size for our solar system
earthRadius = sunRadius * 0.25 # note: real value would be sunRadius * 0.01, a good choice for sim is * 0.25
astronomicalUnit = 212.7 * realSunRadius # the distance from Sun to Earth - the Sun is about 100 Sun diameters away
gravity = 6.6e-11 # sets the strength of the gravitational constant to 6.6x10-11 Newton x meters squared per kilograms squared
# create the Sun object
sun = sphere( radius = sunRadius, opacity = 0.7, emissive = True, texture = "http://i.imgur.com/yoEzbtg.jpg" )
sun.mass = 2e30 # mass of the Sun in kilograms is 2,000,000,000,000,000,000,000,000,000,000 kg
sun.pos = vec(0,0,0)
sun.vel = vec(0,0,0)
# place a few sources of light at the same position as the Sun to illuminate the Earth and Moon objects
sunlight = local_light( pos = vec(0,0,0), color=color.white )
more_sunlight = local_light( pos = vec(0,0,0), color=color.white ) # I found adding two lights was about right
# create the Earth object
earth = sphere ( radius = earthRadius, texture = "http://i.imgur.com/rhFu01b.jpg",make_trail=True)
earth.mass = 6e24 # mass of Earth in kilograms
earth.pos = vec(astronomicalUnit, 0, 0)
earth.vel = vec(0,0,-30000) # the Earth is moving around 30000 m/s
dt = 10000
# below is the main loop of the program - everything above is "setup" and now we are in the main "loop" where all the action occurs
while (True): # this will make it loop forever
rate(100) # this limits the animation rate so that it won't depend on computer/browser processor speed
# calculate the force of gravity on each object
f_grav = gravity * sun.mass * earth.mass * (sun.pos - earth.pos).norm() / (sun.pos - earth.pos).mag2
earth.vel = earth.vel + (f_grav/earth.mass) * dt
# update the position of the Earth and Moon by using simple circle trigonometry
earth.pos = earth.pos + earth.vel * dt
(sun.pos-earth.pos) is a vector. I don't think you can do (sun.pos-earth.pos)**2 because you can't square a vector. Unless you're trying to do a dot product of the vector with itself? But the result of a dot product is a scalar, so f_grav would be a scalar. Forces are vectors, so it doesn't make sense to use a dot product there.
In comparison, f_grav = gravity * sun.mass * earth.mass * (sun.pos - earth.pos).norm() / (sun.pos - earth.pos).mag2 makes sense because you're multiplying (sun.pos - earth.pos).norm(), a vector, by three scalars, and dividing by one scalar. So the result is a vector as desired.
.norm() returns a unit vector so that the result is a vector not a scalar. This is the vector form of Newtonian gravity. (See Wikipedia)
.mag2 does the same thing as what is expected from **2, however in general, powers of vectors are not defined, so it wouldn't make sense to define the exponentiation operator on the vector class.

Show how a projectile (turtle) travels over time

I am new to Python, and currently having a rough time with turtle graphics. This is what I am trying to solve
On Turtellini (the planet where Python turtles live) the
transportation system propels turtles with a giant slingshot. A
particular turtle's original location (x0, y0) is (-180, -100). He is
then shot upward at an initial vertical velocity (vy) of 88 units per
second and a horizontal velocity (vx) of 20 units per second to the
right. He travels for 16 seconds. The acceleration due to gravity (g)
is 11 units per second squared. The the location of the turtle at a
given second (t) is calculated as follows: x = x0 + vx * t and y = y0
+ vy * t - g/2 * t2 . This program is to show how a turtle travels over this period of time.
The output should be like this:
Here is what I should do;
set up the constants (vertical velocity, horizontal velocity,
gravity) and variables (x and y coordinates) set up the turtle by
giving him a proper shape, putting his tail up, moving him to the
initial position, putting his tail down make a loop that repeats for
seconds 1 through 16 inclusive. in each iteration of the loop display
the the values of the x and y variables (in the shell window), move
the turtle to those coordinates, have the turtle stamp his shape,
calculate the new values for the x and y variables after the loop
terminates, move the turtle to the last calculated coordinates,
change his color, and stamp his shape, then wait for a mouse click
My code so far:
import turtle
def main():
wn = turtle.Screen()
turtellini = turtle.Turtle()
t = int(input("Blab blab blab: "))
x0 = -180
y0 = -100
vx = 20
vy = 88
g = 11
x = (float(x0 + vx * t))
y = (float(y0 + vy * t - g / 2 * t**2))
turtellini.color("black")
turtellini.shape("turtle")
turtellini.up()
turtellini.goto(-180,-100)
turtellini.down()
for i in range(1,16,1):
turtellini.stamp()
turtellini.forward(i)
turtellini.right(i)
print(x)
print(y)
if __name__ == "__main__":
main()
I know I am doing bad; but can anyone help me to solve this problem?
You seem to have most of the parts and pieces. The biggest issue I see is you didn't put your x,y calculation in the loop. The loop iteration variable i is really t in your motion equations. Each time you calculate a new x,y you simply move the turtle to that position:
import turtle
from math import pi, atan
x0, y0 = -180, -100 # initial location
vx, vy = 20.0, 88.0 # initial velocity in units per second
travel_time = 16 # seconds
g = 11.0 # acceleration due to gravity in units per second squared
turtellini = turtle.Turtle(shape='turtle', visible=False)
turtellini.penup()
turtellini.radians() # to make turtle compatible with math.atan()
turtellini.setheading(pi / 2) # straight up
turtellini.goto(x0, y0)
turtellini.pendown()
turtellini.showturtle()
turtellini.stamp()
for t in range(1, travel_time + 1):
x = x0 + vx * t
y = y0 + vy * t - g / 2 * t**2
turtellini.goto(x, y)
print(x, y)
angle = atan((vy * t - g * t**2) / (vx * t)) # a guess!
turtellini.setheading(angle)
turtellini.stamp()
turtle.exitonclick()
Unlike the gold standard image, I assumed the turtle was aerodynamic like a bullet and travelled head first through the flight. I don't know, and couldn't quickly find, the formula for the flight angle of a projectile so I guessed from the existing formulas:

2D Shadow Effect - Points on circle

I am currently trying to implement flat shadow effects to a 2D game that i have written in Python. I have found a great deal of tutorials and methods of doing this online (http://ncase.me/sight-and-light/) however, these all use polygons as the obstructions, where all corner points are known while my game includes circles.
I was wondering if it were possible to calculate either the X and Y coordinates of each of the points of contact (P and Q) or the gradient of the line if the situation of A and O and the radius of the circle are known.
Thanks in advance and apologies if the question is off topic, but i couldn't find the answers anywhere else.
The trick is to notice what is happening at point P. At point P, the line AP is tangent to the circle so in other words the angle APO is 90 degrees. Likewise AQO is 90 degrees.
Now we know that we have a triangle, we know 2 of the lengths and one of the angles (We know AO, OP / OQ (Same thing), and APO / AQO).
We now use the law of sines.
AO/sin(APO) = OP/sin(PAO)
PAO = asin(OP*(sin(APO)/AO))
Remember to be conscious of the units (ie using 90 degrees as an input value and then forgetting that a your library function for sin may return in radians not degrees).
From here, you can find all of the angles by knowing that the sum of all angles in a triangle is 180 degrees. So now you have all three angles.
When you have angle AOP from the above calculation, you can use the law of sines again to calculate the length of AP.
AP = sin(AOP) * AO / sin(APO).
Note that sin(90 degrees) == 1 (And remember that APO and AQO are 90 degrees | pi/2 radians).
Now we have the length of AP. We can now find the coordinates (x, y) of P, assuming that A is at (0, 0). If A is not the origin just add A's coordinates as an offset.
To find the coordinates of P:
PxCoord = AxCoord + AP * cos(PAO)
PyCoord = AyCoord + AP * sin(PAO)
Reminder: Please check if your trig functions (sin / asin) use degrees or radians, and make sure to convert the 90 degrees to radians (it is pi/2 radians) if your function uses radians. Also note that if this is the case, your output will be in radians for the angle, and likewise instead of there being 180 degrees in a triangle you will have pi radians.
Let's vector V = OP (unknown), vector Q = AP, vector U = AO (known)
Note that Q = U + V
Vector V length is radius R, so
VX^2 + VY^2 = R^2 //1
Vectors V and A are perpendicular, so their scalar product is zero
VX * QX + VY * QY = 0
VX * (VX + UX) + VY * (VY + UY) = 0
VX * VX + VX * UX + VY * VY + VY * UY = 0
R^2 + VX * UX + VY * UY = 0 //2
Solve system of equations 1 and 2 and get solutions
LL = U.X^2 + U.Y^2
VY = (R^2 * UY +/- R * UX * Sqrt(LL - R^2)) / LL
VX = (R^2 - VY * UY) / UX
and finally
P.X = O.X + VX
P.Y = O.Y + VY

Categories

Resources