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:
Related
This is my code, I'm trying to figure out how to get the total distance of the entire length that my turtle has traveled and I don't know how to figure it without taking it out of a loop which I can't do because the numsteps is an input. This is for school by the way
for a in range(numsteps):
s = randint(-100,100)
angle = random() * 2 * pi
x = s * cos(angle)
y = s * sin(angle)
walking.goto(x,y)
distance = sqrt(x ** 2 + y ** 2)
finald.goto(x,y)
print("The final distance is {:,.0f}".format(distance))
print("Your total distance traveled is {}")
You have to save your previous position to compute the distance from the current position to it.
Then every time after computing the distance (near the end of the loop) the current position becomes a previous one:
from math import sin, cos, pi, sqrt
from random import random, randint
start_x, start_y = 0, 0 # The starting point coordinates
previous_x, previous_y = start_x, start_y
total_distance = 0 # We will progressively increase it
numsteps = int(input("Number of steps: "))
for __ in range(numsteps):
s = randint(-100, 100)
angle = random() * 2 * pi
x = s * cos(angle)
y = s * sin(angle)
# walking.goto(x, y) # I commented it out for testing
distance = sqrt((x - previous_x) ** 2 + (y - previous_y) ** 2)
total_distance += distance
prev_x, prev_y = x, y
final_distance = sqrt((x - start_x) ** 2 + (y - start_y) ** 2)
print("The final distance is {:,.0f}".format(final_distance))
print("Your total distance traveled is {:,.0f}".format(total_distance))
Note the __ instead of your a (or other regular name) — this special name (one or two underscore characters) indicates that its value is out of our interest.
(Because we use range(numsteps) only as a counter.)
I'd make simplifications based on some observations:
Turtle already knows the distance function, no need to reinvent it
Moving backwards (negative distance) when we can head in any direction is redundant -- it's really no different than moving forward in any direction.
We can more easily calculate how far we did move than measure how far we will move.
This results in code more like:
from math import pi
from random import random
from turtle import Screen, Turtle
numsteps = int(input("Number of steps: "))
screen = Screen()
walking = Turtle()
walking.radians()
total_distance = 0 # sum of all distances traveled
for _ in range(numsteps):
previous = walking.position()
angle = random() * 2 * pi
distance = random() * 100
walking.setheading(angle)
walking.forward(distance)
total_distance += walking.distance(previous)
final_distance = walking.distance(0, 0) # distance from where we started
print("Your final distance traveled is {:,.0f} pixels".format(final_distance))
print("Your total distance traveled is {:,.0f} pixels".format(total_distance))
screen.exitonclick()
OUTPUT
> python3 test.py
Number of steps: 100
Your final distance traveled is 356 pixels
Your total distance traveled is 4,630 pixels
>
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
This might be a more mathematical question, but I'm trying to get my head around how I can program an unbeatable AI for a ping pong game. From what I have read so far, it would be to simulate the trajectory of a ball when it is moving in the direction towards the AI Paddle.
In this game I have a ball and I can read its x and y position on the board, and then read it again in the next iteration which will allow me to calculate the velocity in the x and y direction.
But I'm not sure how to program how and where the ball will reach the AI paddle's goal position, and consider how many times the ball will bounce off the walls will requires me to use some geometry. But I can't get my head around it and how I will be programming it.
So far what I have thought of is the variables I've been given: the size of the table in x and y direction, the position of the ball "currently" and before in order to get its velocity in x and y direction. My first assumption is to find out a way to calculate whether the ball will hit the walls or the AI goal side instead?
There is a more direct way of doing this instead of repeated "raycasting":
def predict(x, y, vx, vy, h, b):
"""
:param x: ball x position
:param y: ball y position
:param vx: ball x velocity
:param vy: ball y velocity
:param h: the field height
:param b: the y position the prediction is for
:return: ball x position at y = b
"""
m = vy / vx # slope
c = -x * m + y # y-intercept
val = (m * b + c) % (2 * h)
return min(val, 2 * h - val)
Now, step by step
m = vy / vx # slope
c = -x * m + y # y-intercept
val = (m * b + c)
A simple linear function showing the ball's current path.
This works, but only if the ball never hits a side wall.
A Model
Imagine there were fields with the same height on both sides of the original one, stretching into infinity.
Now 'the number of bounces' has become 'the number of cells the ball travels'.
Additionally, if the number of bounces is even, the distance from the lower border of the cell it hits to the point of impact is the same as the height the actual ball would hit at in the real cell.
Therefore
(m * b + c) % (2 * h)
To cover odd bounces as well, you need to mirror the graph around h.
Here is a graphic explanation:
And since the irrelevant graph is the one with values above h, you take the minimum.
Possible Problems
In some languages, the % is a remainder operator, though not python.
If the predictions are negative in some cases add this.
val = ((m * b + c) % (2 * h) + 2 * h) % (2 * h)
This function depends on 'accurate' collision.
So if the bounces are handled in a way similar to this,
if y not in range(0, y_max):
vy *= -1
the predictions will be slightly off.
If you can change the core game, use
if y < 0:
y *= -1
vy *= -1
elif y > y_max:
y = 2 * y_max - y
vy *= -1
A divide by zero exception will be thrown if vx is 0, but since the ball will never hit a wall in this case, this should be handled by the ball movement logic.
Snippets are cool, but functions are better. I can't prove this works, but it seems to.
float pong_get_ball_endpoint(float xpos, float ypos, float xspeed, float yspeed)
{
// In the following, the fabs() mirrors it over the bottom wall. The fmod wraps it when it exceeds twice
// the top wall. If the ball ends up in the top half of the double height section, we reflect it back
auto deltaX = (xspeed > 0) ? (BAT2_X - xpos) : -(xpos - BAT1_X); // How far from ball to opponent bat
auto slope = yspeed / xspeed; // Rise over run, ie: deltaY per X
float newY = fmod(fabs(ypos + deltaX * slope), (2 * MATRIX_HEIGHT)); // New Y, but wrappped every 2*height
if (newY > MATRIX_HEIGHT) // If in top half, reflect to bottom
newY = 2 * MATRIX_HEIGHT - newY;
return newY;
}
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
I want to draw a smily using python turtle. Circle extent will be 120.
I am trying following
import turtle
turtle.circle(100)
turtle.up()
turtle.goto(0, 30)
turtle.down()
turtle.circle(40, 120)
Problem is smile part. How to draw a face smile?
You can do the smile (and smiley face) with the commands that the turtle module provides. The key to getting your arc (of a circle) drawn correctly lies in the combination of goto() and setheading(), see below:
import turtle
turtle.up()
turtle.goto(0, -100) # center circle around origin
turtle.down()
turtle.begin_fill()
turtle.fillcolor("yellow") # draw head
turtle.circle(100)
turtle.end_fill()
turtle.up()
turtle.goto(-67, -40)
turtle.setheading(-60)
turtle.width(5)
turtle.down()
turtle.circle(80, 120) # draw smile
turtle.fillcolor("black")
for i in range(-35, 105, 70):
turtle.up()
turtle.goto(i, 35)
turtle.setheading(0)
turtle.down()
turtle.begin_fill()
turtle.circle(10) # draw eyes
turtle.end_fill()
turtle.hideturtle()
turtle.done()
I'm not going to claim to have mastered positioning arcs, I'm still doing too much trial and error, but it is possible if you take the time to learn how the turtle operators work.
The turtle module does not provide advanced methods to drow arcs of circles or parabolas, however it isn't hard to come up with the right equations.
A circle C with origin at (x0, y0) and radius r is described by the equation:
(x-x0)^2 + (y-y0)^2 = r^2
We can expand this to get:
x^2 -2x·x0 + x0^2 + y^2 -2y·y0 + y0^2 - r^2 = 0
Now we can take for example the y as variable and obtain the second degree equation:
y^2 -2y0·y +(x^2-2x0·x+x0^2+y0^2-r^2) = 0
Let d = x^2-2x0·x+x0^2+y0^2-r^2. We can solve this using the usual formula:
y1 = (2y0 + sqrt(4y0^2 - 4d))/2 = y0 + sqrt(y0^2 - d)
y2 = (2y0 - sqrt(4y0^2 - 4d))/2 = y0 - sqrt(y0^2 - d)
So now you can write down a function that, given the coordinates of the center of the circle and the radius, and the value for x it returns the coordinate y and use these coordinates to move the turtle:
def find_circle_coord(x0, y0, r, x):
d = x**2 - 2*x0*x + x0**2 + y0**2 - r**2
D = y0**2 - d
if D < 0:
raise ValueError("Value for x is outside the circle!")
return y0 - D**.5, y0 + D**.5
As in:
>>> # bob is a turtle
>>> bob.pendown()
>>> for x in range(-50, 50):
... y1, _ = find_circle_coord(0, 0, 100, x)
... bob.goto(x, y1)
By choosing one of the two coordinates returned you choose whether to draw the "upper" or "lower" arc.
to draw a smile you simply have to come up with two circles one smaller and a larger one but with the center slightly above the previous one so that they have that kind of intersection.
So you have to choose a circle C1 centered in x0, y0 with radius r and a circle C2 centered in x0, y0+K with radius R > r.
Note that C2's center is vertically aligned with C1 center (hence the same x coordinate for the center) but it is above it (note: I'm not sure of y-axis orientation so the +K might be -K...)
To find the intersections you have to solve the system of their equations:
(x-x0)^2 + (y-y0)^2-r^2 = 0
(x-x0^2) + (y-y0-K)^2-R^2 = 0
Now subtracting the second equation from the first you get:
(y-y0)^2 - (y-y0-K)^2 -r^2 + R^2 = 0
y^2 -2y·y0 +y0^2 - y^2 -y0^2 -K^2 +2y·y0 +2K·y -2K·y0 -r^2 + R^2 = 0
-K^2 +2K·y -2K·y0 -r^2 + R^2 = 0
Where you get:
y = (K^2 +2K·y0 +r^2 -R^2)/(2K)
And you can substitute the y in one of the circle equations to obtain the xs corresponding to such y. Then you know which x to draw using find_circle_coord.
If you want to make the mouth more open you could use a circle and a parabola. To find the y value of a point on a parabole it's easy:
def find_parabola_coord(a, b, c, x):
return a*x**2 + b*x + c
Or you could use the form of equation of a parabola given its vertex V = (xv, yv):
y - yv = a(x - xv)^2
where a controls how steep the parabola is.
import turtle
bob = turtle.Turtle()
bob.circle(100)
bob.penup()
bob.goto(50,100)
bob.pendown()
bob.circle(10)
bob.penup()
bob.goto(-50,100)
bob.pendown()
bob.circle(10)
bob.penup()
bob.goto(0,50)
bob.pendown()
bob.circle(100,30)
bob.penup()
bob.goto(0,50)
bob.pendown()
bob.circle(0,-30)
bob.circle(100,-30)