Graphics.py Bouncing Cube - python

I am trying to create a program that "bounces" a cube in a window up and down. Everything is created properly but the cube will not bounce.
The code is as follows:
from graphics import *
import time # Used for slowing animation if needed
i=0
def create_win():
win= GraphWin("Animation",500,500)
cornerB1= Point(235,235)
cornerB2= Point(265,265)
Bob= Rectangle(cornerB1, cornerB2)
Bob.setFill('blue')
Bob.draw(win)
win.getMouse()
win.close()
create_win()
def main():
cornerB1= Point(235,235)
cornerB2= Point(265,265)
Bob= Rectangle(cornerB1, cornerB2)
center= Rectangle.getCenter(Bob)
center_point= Point.getX(center)
for i in range(500):
Bob.move(0,5)
if center_point<15:
dy= -dy
elif center_point>485:
dy= -dy
main()
Any input would be greatly appreciated.

This seems to be too much code with too little planning. Specific issues: you create Bob twice, once in each function -- the blue Bob you see isn't the Bob you're moving; too many numbers -- figure out your base dimensions and calculate everything else from them; you extract the center outside the loop so it never changes -- do it inside the loop so it's changing as Bob moves.
Below is a rework of your code that bounces Bob up and down as intended:
from graphics import *
WIDTH, HEIGHT = 500, 500
BOB_SIZE = 30
BOB_DISTANCE = 5
def main():
win = GraphWin("Animation", WIDTH, HEIGHT)
# Create Bob in the middle of the window
cornerB1 = Point(WIDTH/2 + BOB_SIZE/2, HEIGHT/2 + BOB_SIZE/2)
cornerB2 = Point(WIDTH/2 - BOB_SIZE/2, HEIGHT/2 - BOB_SIZE/2)
Bob = Rectangle(cornerB1, cornerB2)
Bob.setFill('blue')
Bob.draw(win)
dy = BOB_DISTANCE
for _ in range(500):
Bob.move(0, dy)
center = Rectangle.getCenter(Bob)
centerY = Point.getY(center)
# If too close to edge, reverse direction
if centerY < BOB_SIZE/2 or centerY > HEIGHT - BOB_SIZE/2:
dy = -dy
win.close()
main()

Related

In the turtle module, how to find the maximum values of coordinates?

import turtle as t
from random import randint, random
def draw_star(points, size, col, x, y):
t.penup()
t.goto(x, y)
t.pendown()
angle = 180 - (180 / points)
t.color(col)
t.begin_fill()
for i in range(points):
t.forward(size)
t.right(angle)
t.end_fill()
# Main code
while True:
ranPts = randint(2, 5) * 2 + 1
ranSize = randint(10, 50)
ranCol = (random(), random(), random())
ranX = randint(-350, 300)
ranY = randint(-250, 250)
draw_star(ranPts, ranSize, ranCol, ranX, ranY)
Question:
How could I know the maximum values of coordinates of my screen? So I can have a better idea on how to set the values of ranX and ranY?
Thanks.
You could use t.setworldcoordinates(llx, lly, urx, ury)
The parameters:
llx = x of lower left corner
lly = y of lower left corner
urx= x of upper right corner
ury = y of upper right corner
You can create a function and find the values of coordinates yourself by clicking on the screen like this:
# turtle library
import turtle
#This to make turtle object
tess=turtle.Turtle()
# self defined function to print coordinate
def buttonclick(x,y):
print("You clicked at this coordinate({0},{1})".format(x,y))
#onscreen function to send coordinate
turtle.onscreenclick(buttonclick,1)
turtle.listen() # listen to incoming connections
turtle.speed(10) # set the speed
turtle.done() # hold the screen
This will print everytime you click on the screen and print the coordinates out.
The screensize() function returns the canvas width and the canvas height as a tuple.
You can use this to find the max coordinates of the canvas.
screenSize = t.screensize() #returns (width, height)
# Main code
while True:
ranPts = randint(2, 5) * 2 + 1
ranSize = randint(10, 50)
ranCol = (random(), random(), random())
ranX = randint(50-screenSize[0], screenSize[0] - 100)
ranY = randint(50-screenSize[1], screenSize[1] - 100)
draw_star(ranPts, ranSize, ranCol, ranX, ranY)
I found out this is what I need: t.window_width() and t.window_height().

is there something up with my python turtle code that stops it from continuing the stamping?

at the moment i am trying to port a scratch game to python turtle program to make it more sophisticated.
my main problem with the code is that to begin with, the games gravity doesnt work in the slightest, the rendering function to render the blocks dont work, and controlling meat man himself doesnt work.
if someone could help me point out the issue, i could fix it
the original scratch game is the original scratch game is https://scratch.mit.edu/projects/480779617/ and phasing in the block is part of the game to jump to the other blocks
import random
import math
#this is the window
wn = turtle.Screen()
wn.title("Super Meat Man")
wn.bgcolor("#87ceff")
wn.setup(width=1200, height=600)
wn.tracer(1)
score = -1
#meat man
meat_man = turtle.Turtle()
meat_man.shape("square")
meat_man.penup()
meat_man.goto(-500,200)
turtle.pos()
meat_man.speed(10)
xv = meat_man.xcor()
yv = meat_man.ycor()
xv = xv*0.9
yv = yv*-1
#block meat man stands on
block = turtle.Turtle()
block.color('yellow')
block.shape('square')
block.penup()
block.speed(0)
block.hideturtle()
#random length and height between the blocks
length = random.randint(1, 7)
height = random.randint(2, 6)
#this is the number of blocks rendered at the moment, it changes every render function
block_number = 0
#coordinates cuz i cannot use the direct xcor and ycor in a math statement
block_xcor = block.xcor()
block_ycor = block.ycor()
#this is the list of coordinates i will use for the stamped blocks, to detect if meat man will colide with one of the blocks that was stamped
block_coords_list = set()
#this is the bad block that kills you if you touch it
bad_block = turtle.Turtle()
bad_block.penup()
bad_block.color('red')
bad_block.shape("square")
bad_block.shapesize(5,1200)
bad_block.goto(0, -290)
#the controls
def goright():
xv = 5*0.9
def goleft():
xv = -5*0.9
def jump():
yv = 15-1
wn.onkey(jump, "w")
wn.onkey(goleft, "a")
wn.onkey(goright, "d")
#this is the rendering on the blocks
def render():
global block_coords_list
global block_xcor
global block_ycor
global score
#this sets the turtle into the corect position to start rendering
turtle.clearstamp(block)
block.showturtle()
block.goto(-500,-200)
#this sets the block that meat man will fall ontop of and start the platformer
block.stamp()
block_xcor = block_xcor + 20
#this is the score update, because the render inishiates every new level, so if i start the score at -1, it will render to zero to start
score = score + 1
#this its the rendering itself
while block_number < 25:
#this is the random chance of length and height for the block to start on
block_xcor = block_xcor * length * 20
block_xcor = -500
block_ycor = block_ycor * height * 20
block.stamp()
#this adds the coordinates to the list that compares coordinates
block_coords_list.add((block_xcor, block_ycor))
#colisions
if meat_man.pos() in block_coords_list:
yv = 0
if meat_man.pos() == bad_block.pos():
score = 0
render()
render()
you did not import turtle you have to import turtle
import turtle
and it stops because of the "render"
if you take the last line = render() it works and finishes

Close window when graphics.py object has reached the edge of window

Referring to John Zelle's graphics.py, I want the GraphWin to close right after the Circle object has reached the edge of the window and is out of sight.
Following code creates a circle and moves it:
win = GraphWin("My Circle", 100, 100)
c = Circle(Point(50,50), 10)
c.draw(win)
for i in range(40):
c.move(30, 0) #speed=30
time.sleep(1)
#c should move until the end of the windows(100),
win.close() # then windows of title "My Circle" should close immediately
Is there any way to do this instead of using range and counting its exact number of 'steps'?
Compare the x position of the left side of the circle against the right side of the window:
from graphics import *
WIDTH, HEIGHT = 300, 300
RADIUS = 10
SPEED = 30
win = GraphWin("My Circle", WIDTH, HEIGHT)
c = Circle(Point(50, 50), RADIUS)
c.draw(win)
while c.getCenter().x - RADIUS < WIDTH:
c.move(SPEED, 0)
time.sleep(1)
win.close() # then windows of title "My Circle" should close immediately
In a speedier loop, we might move RADIUS to the other side of the equation and make a new constant of WIDTH + RADIUS.
If it was an Image object, how would you suggest to get the leftmost
position of the object to compare it to the width of the window?
An Image object would work similarly, using it's anchor, instead of center, and using its width instead of its radius:
from graphics import *
WIDTH, HEIGHT = 300, 300
SPEED = 30
win = GraphWin("My Image", WIDTH, HEIGHT)
image = Image(Point(50, 50), "file.gif")
image.draw(win)
image_half_width = image.getWidth() / 2
while image.getAnchor().x - image_half_width < WIDTH:
image.move(SPEED, 0)
time.sleep(1)
win.close() # the window of title "My Image" should close immediately

still having trouble New Code trying to make rectangle move across screen [duplicate]

This question already has an answer here:
Making rectangle move across screen with graphics file
(1 answer)
Closed 9 years ago.
okay what is wrong?
I want a rectangle to move across the screen
I want to change the x coordinates that make that the opposite points of the rectangle
if you have a better way im open to suggestions
I added in the word 'Point' in front of the coordinates that didn't do anything
from graphics import *
def main():
win = GraphWin("Polygon", 500, 500)
r= Rectangle(Point(10,500),Point(150,450))
r.draw(win)
while r.getP1()<=450 is False:
rectMaker(r)
time.sleep(1)
def rectMaker(r):
r.undraw(win)
r=Rectangle((r.getP1.getY(),r.getP1().getX()+1),(r.getP2.getY,r.getP2().getX()+1))
r.draw(win)
return r
main()
NEW CODE
from graphics import *
def main():
win = GraphWin("Polygon", 500, 500)
r= Rectangle(Point(10,500),Point(150,450))
r.draw(win)
for i in range (0,345,1):
r.undraw()
r= Rectangle(Point(10+i,500),Point(150+i,450))
r.draw(win)
main()
Okay NEW CODE again so sorry I have the full sail boat. I want the line to start at the top of the boat and not at the bottom and the triangle is a little messed up. I thought my coordinates were right but I think they must be wrong.
from graphics import *
def main():
win = GraphWin("Polygon", 500, 500)
r= Rectangle(Point(10,500),Point(150,450))
r.draw(win)
l=Line(Point(70,450),Point(70,400))
l.draw(win)
p=Polygon(Point(10,450),Point(130,400),Point(70,300))
p.draw(win)
for i in range (0,345,1):
r.undraw()
l.undraw()
p.undraw()
l=Line(Point(70+i,500),Point(70+i,400))
r= Rectangle(Point(10+i,500),Point(150+i,450))
p= Polygon(Point(10+i,450),Point(130+i,400),Point(70+i,300))
r.draw(win)
l.draw(win)
p.draw(win)
main()
Now rectangle is moving:
from graphics import *
def main():
win = GraphWin("Polygon", 500, 500)
r = Rectangle(Point(10,500), Point(150,450))
r.draw(win)
while r.getP1().getY() > 150:
r = rectMaker(win, r)
time.sleep(1)
def rectMaker(win, r):
r.undraw() # win
r = Rectangle( Point(r.getP1().getX(), r.getP1().getY()-10), Point(r.getP2().getX(),r.getP2().getY()-10) )
r.draw(win)
return r
main()
you used win in two function but it wasn't global variable
undraw() don't need argument
r.getP1() is Point not single number - you can't compare it with 450
you used getP1 and getY but should getP1(), getY()
you forgot to use Point in new Rectangle
you used Point(Y,X) but but should Point(X,Y)
seems that rectMarker don't use oryginal r from main but its clone so you forgot to assign result of rectMaker() to oryginal r (r = rectMaker(win, r))
etc.
Better version:
from graphics import *
def main():
win = GraphWin("Polygon", 500, 500)
r = Rectangle(Point(10,500),Point(150,450))
r.setFill('red')
r.setOutline('blue')
r.setWidth(4)
while r.getP1().getY() > 150:
r.draw(win)
time.sleep(0.1)
r.undraw()
r.move(0,-10)
win.getMouse()
main()

Hide Turtle Window?

I am generating diagrams in Turtle, and as part of my program, I identify certain coordinates from my diagrams. I would like to be able to hide the complete turtle window, since I only care about the coordinates, is that possible?
Edit:
QUESTION 2:
This isn't really an answer, but a few other questions.
I got my program working to some extent, if you run it in IDLE and type "l" it will give you the list with the coordinates.
import Tkinter
import turtle
from turtle import rt, lt, fd # Right, Left, Forward
size = 10
root = Tkinter.Tk()
root.withdraw()
c = Tkinter.Canvas(master = root)
t = turtle.RawTurtle(c)
t.speed("Fastest")
# List entire coordinates
l = []
def findAndStoreCoords():
x = t.xcor()
y = t.ycor()
x = round(x, 0) # Round x to the nearest integer
y = round(y, 0) # Round y to the nearest integer
# Integrate coordinates into sub-list
l.append([x, y])
def hilbert(level, angle):
if level == 0:
return
t.rt(angle)
hilbert(level - 1, -angle)
t.fd(size)
findAndStoreCoords()
t.lt(angle)
hilbert(level - 1, angle)
t.fd(size)
findAndStoreCoords()
hilbert(level - 1, angle)
t.lt(angle)
t.fd(size)
findAndStoreCoords()
hilbert(level - 1, -angle)
t.rt(angle)
The problem is that Turtle is so SLOW! Is there any package that is just like Turtle but can do commands much faster?
I reimplemented the turtle class as suggested by thirtyseven. It is consistent with the api. (i.e. when you turn right in this class, it is the same as turning right in turtle.
This does not implement all the methods in the api, only common ones. (And the ones you used).
However, it's short and fairly straightforward to extend. Also, it keeps track of all of the points it has been to. It does this by adding an entry to pointsVisited every time you call forward, backward, or setpos (or any of the aliases for those functions).
import math
class UndrawnTurtle():
def __init__(self):
self.x, self.y, self.angle = 0.0, 0.0, 0.0
self.pointsVisited = []
self._visit()
def position(self):
return self.x, self.y
def xcor(self):
return self.x
def ycor(self):
return self.y
def forward(self, distance):
angle_radians = math.radians(self.angle)
self.x += math.cos(angle_radians) * distance
self.y += math.sin(angle_radians) * distance
self._visit()
def backward(self, distance):
self.forward(-distance)
def right(self, angle):
self.angle -= angle
def left(self, angle):
self.angle += angle
def setpos(self, x, y = None):
"""Can be passed either a tuple or two numbers."""
if y == None:
self.x = x[0]
self.y = y[1]
else:
self.x = x
self.y = y
self._visit()
def _visit(self):
"""Add point to the list of points gone to by the turtle."""
self.pointsVisited.append(self.position())
# Now for some aliases. Everything that's implemented in this class
# should be aliased the same way as the actual api.
fd = forward
bk = backward
back = backward
rt = right
lt = left
setposition = setpos
goto = setpos
pos = position
ut = UndrawnTurtle()
Yes, this is possible. The simplest way is to instantiate a root Tkinter window, withdraw it, and then use it as the master window for a RawTurtle's Canvas instance.
Example:
import Tkinter
import turtle
root=Tkinter.Tk()
root.withdraw()
c=Tkinter.Canvas(master=root)
t=turtle.RawTurtle(c)
t.fd(5)
print t.xcor() # outputs 5.0
Unfortunately, this still initiates the graphics system, but no window will appear.
The problem is that Turtle is so SLOW! Is there any package that is
just like Turtle but can do commands much faster?
Yes, turtle can. If we add a TurtleScreen to the tkinter implementation, and use it's tracer() functionality, we can speed things up more than turtle's speed() method. And we can simplify the code greatly by tossing the customizations and simply use turtle's own begin_poly(), end_poly() and get_poly() methods:
from tkinter import Tk, Canvas
from turtle import TurtleScreen, RawTurtle
SIZE = 10
def hilbert(level, angle):
if level == 0:
return
turtle.right(angle)
hilbert(level - 1, -angle)
turtle.forward(SIZE)
turtle.left(angle)
hilbert(level - 1, angle)
turtle.forward(SIZE)
hilbert(level - 1, angle)
turtle.left(angle)
turtle.forward(SIZE)
hilbert(level - 1, -angle)
turtle.right(angle)
root = Tk()
root.withdraw()
canvas = Canvas(master=root)
screen = TurtleScreen(canvas)
screen.tracer(False) # turn off turtle animation
turtle = RawTurtle(screen)
turtle.begin_poly() # start tracking movements
hilbert(5, 90)
turtle.end_poly() # end tracking movements
print(turtle.get_poly())
This prints all the points in a level 5 Hilbert curve in about 1/3 of a second on my system. Your posted code toke nearly 9 seconds to output a level 4.

Categories