I am creating a program in Python using Zelle graphics package. There is a moving circle that the user clicks on in order to make it return to the center of the screen. I cannot figure out how to identify when the user clicks inside of the circle. Here is the code I have written:
from graphics import *
from time import sleep
import random
Screen = GraphWin("BallFalling", 400 , 400);
Screen.setBackground('green')
ball = Circle(Point(200,200),25);
ball.draw(Screen);
ball.setFill('white')
ballRadius = ball.getRadius()
ballCenter = 0
directionX = (random.random()*40)-20;
directionY = (random.random()*40)-20;
clickx = Screen.getMouse().getX();
clicky = 0
while ball.getCenter().getX() + ball.getRadius() <= 400 and ball.getCenter().getY() + ball.getRadius() <= 400 and ball.getCenter().getX() >= 0 and ball.getCenter().getY() >= 0:
ball.move(ball.getRadius()//directionX,ball.getRadius()//directionY)
ballLocation = ball.getCenter().getX();
ballLocationy = ball.getCenter().getY();
sleep(1/15);
The main problem I am having is identifying the coordinates of the mouse click. I cannot find anything in the Zelle graphics package that says anything about this.
The major issues I see are: you are calling getMouse() before the loop when you should be calling checkMouse() inside the loop; you have no code to compare the distance of the click from the ball; you have no code to return the ball to the center of the screen.
Below is my complete rework of your code addressing the above issues:
from time import sleep
from random import randrange
from graphics import *
WIDTH, HEIGHT = 400, 400
RADIUS = 25
def distance(graphic, point):
x1, y1 = graphic.getCenter().getX(), graphic.getCenter().getY()
x2, y2 = point.getX(), point.getY()
return ((x2 - x1) ** 2 + (y2 - y1) ** 2) ** 0.5
window = GraphWin("Ball Falling", WIDTH, HEIGHT)
window.setBackground('green')
ball = Circle(Point(WIDTH/2, HEIGHT/2), RADIUS)
ball.setFill('white')
ball.draw(window)
directionX = randrange(-4, 4)
directionY = randrange(-4, 4)
while True:
center = ball.getCenter()
x, y = center.getX(), center.getY()
if not (RADIUS < x < WIDTH - RADIUS and RADIUS < y < HEIGHT - RADIUS):
break
point = window.checkMouse()
if point and distance(ball, point) <= RADIUS:
ball.move(WIDTH/2 - x, HEIGHT/2 - y) # recenter
directionX = randrange(-4, 4)
directionY = randrange(-4, 4)
else:
ball.move(directionX, directionY)
sleep(1/30)
There may still be subtle bugs and contants tweaking for you to sort out.
Related
I am trying to make a program that will increase the speed of the moving blue circle by 50% if the yellow square is clicked, and decrease it by 50% if the purple square is clicked. The purple square works fine but the yellow square will not register clicks at all. Interestingly, if the black square is used in place of the yellow square, it will function as necessary. Additionally, the blue circle will register clicks within it but will not close the window as intended. I am a novice in python and am beyond confused here. Any suggestions would be greatly appreciated.
As stated previously, functionality works as intended when the black square is used to carry out the functionality of the yellow square. I have used print statements to test if clicks are being registered in different shapes. Clicks register in the blue circle, black square and purple square, but not in the yellow square.
from graphics import*
from time import sleep
def main():
win,c=make()
yellow=Rectangle(Point(495,200),Point(395,300))
yellow.setFill("yellow")
yellow.draw(win)
purple=Rectangle(Point(5,200),Point(105,300))
purple.setFill("purple")
purple.draw(win)
black=Rectangle(Point(200,5),Point(300,105))
black.setFill("black")
black.draw(win)
z=0.2
dx,dy=3,-6
while True:
c.move(dx,dy)
sleep(z)
center=c.getCenter()
dx,dy=bounce(dx,dy,center)
point=win.checkMouse()
if point != None:
if isClicked(point,yellow):
z=z-0.05
elif isClicked(point,purple):
z=z+0.05
elif isClicked(point,c):
win.close
def bounce(dx,dy,center):
if center.getX()<25 or center.getX()>475:
dx *= -1
if center.getY()<25 or center.getY()>475:
dy *= -1
if (center.getX() > 370 and center.getX() < 470) and (center.getY() >175 and center.getY() < 325):
dx *= -1
dy *= -1
return dx,dy
def isClicked(click, shape):
# verify that click is a Point object otherwise return False
if not click:
return False
# get the X,Y coordinates of the mouse click
x,y = click.getX(), click.getY()
# check if shape is a Circle
if type(shape).__name__ == 'Circle':
center = shape.getCenter()
cx, cy = center.getX(), center.getY()
# if click is within the Circle return True
if ((x-cx)**2 + (y-cy)**2)**.5 <= 25:
return True
# shape must be a Rectangle
else:
x1, y1 = shape.getP1().getX(), shape.getP1().getY()
x2, y2 = shape.getP2().getX(), shape.getP2().getY()
# if click is within the Rectangle
if (x1 < x < x2) and (y1 < y < y2):
return True
# click was not inside the shape
return False
def make():
win = GraphWin('Tester',500,500)
win.setBackground('grey')
c = Circle(Point(250,250),25)
c.setFill('blue')
c.draw(win)
return win, c
main()
As stated previously, the intended function would be that a click in the purple rectangle would slow the circle by 50% and a click in the yellow rectangle should increase speed by 50%. Currently a click in the circle does nothing, as does a click in the yellow square. Additionally, a click in the blue circle should close the circle. Thank you for any advice!
You forgot () in win.close() and it never run this function. You could also add break to exit loop because win.close() only close window but it doesn't end loop which still try to win.checkMouse() but win doesn't exists any more and it gives error.
Problem with yellow rectangle is because first X is bigger then second X (495 > 395) in
yellow = Rectangle(Point(495, 200), Point(395, 300))
and Rectangle doesn't sort these values so finally this is not true
if (x1 < x < x2) and (y1 < y < y2)
If you change it to
yellow = Rectangle(Point(395,200),Point(495,300))
then it works correctly.
BTW:
Instead of type(shape).__name__ == 'Circle' you can use isinstance(shape, Circle)
You could add some spaces and empty lines to make it more readable.
Using import * is not prefered - but this part I didn't change.
PEP 8 -- Style Guide for Python Code
Instead of if point != None: you should rather use if point is not None: or shorter if point:
from graphics import *
from time import sleep
def main():
win, c = make()
yellow = Rectangle(Point(395, 200), Point(495, 300))
yellow.setFill("yellow")
yellow.draw(win)
purple = Rectangle(Point(5, 200), Point(105, 300))
purple.setFill("purple")
purple.draw(win)
black = Rectangle(Point(200, 5), Point(300, 105))
black.setFill("black")
black.draw(win)
z = 0.2
dx, dy = 3, -6
while True:
c.move(dx, dy)
sleep(z)
center = c.getCenter()
dx, dy = bounce(dx, dy, center)
point = win.checkMouse()
#if point is not None:
if point:
if isClicked(point, yellow):
z = z - 0.05
elif isClicked(point, purple):
z = z + 0.05
elif isClicked(point, c):
win.close()
break
def bounce(dx, dy, center):
if center.getX() < 25 or center.getX() > 475:
dx *= -1
if center.getY() < 25 or center.getY() > 475:
dy *= -1
if (center.getX() > 370 and center.getX() < 470) and (center.getY() > 175 and center.getY() < 325):
dx *= -1
dy *= -1
return dx, dy
def isClicked(click, shape):
# verify that click is a Point object otherwise return False
if not click:
return False
# get the X,Y coordinates of the mouse click
x, y = click.getX(), click.getY()
# check if shape is a Circle
if isinstance(shape, Circle):
center = shape.getCenter()
cx, cy = center.getX(), center.getY()
# if click is within the Circle return True
if ((x-cx)**2 + (y-cy)**2)**.5 <= 25:
return True
# shape must be a Rectangle
else:
x1, y1 = shape.getP1().getX(), shape.getP1().getY()
x2, y2 = shape.getP2().getX(), shape.getP2().getY()
# if click is within the Rectangle
if (x1 < x < x2) and (y1 < y < y2):
return True
# click was not inside the shape
return False
def make():
win = GraphWin('Tester', 500, 500)
win.setBackground('grey')
c = Circle(Point(250, 250), 25)
c.setFill('blue')
c.draw(win)
return win, c
main()
So I've been attempting to make some dots not only come towards a circle but also to make them orbit it. To do this I am using cosine and sine, however I'm running into issues with getting the dots to move forward as well as setting their distance. With the code below the dots are able to form a circle around the bigger dot, as well as follow it, but they don't approach the dot nor do they, when having the coordinates scaled by their distance from t1, come to that location, but instead do funky stuff. This is referring specifically to the line
t2.goto(2 * (t1.xcor() + math.degrees(math.cos(math.radians(t1.towards(t2)))) // 1), 2 * (t1.ycor() + math.degrees(math.sin(math.radians(t1.towards(t2)))) // 1))
which I had replaced with:
t2.goto(dist * (t1.xcor() + math.degrees(math.cos(math.radians(t1.towards(t2)))) // 1), dist * (t1.ycor() + math.degrees(math.sin(math.radians(t1.towards(t2)))) // 1))
and that gave me the sporadic view of the dots attempting to follow the bigger dot.
This line is found in the follow() function. Create() makes the smaller dots, move() moves the bigger dot and grow() grows the bigger dot on collision with the smaller dots. Produce() and redraw() are supposed to be a stage 2 of the program, but those functions are irrelevant to the question. Finally, quit() just exits the Screen() and quits the program.
Thanks to cdlane for help with organizing data and updating the screen more efficiently.
Code as of now:
from turtle import Turtle, Screen
import sys
import math
CURSOR_SIZE = 20
def move(x, y):
""" has it follow cursor """
t1.ondrag(None)
t1.goto(x, y)
screen.update()
t1.ondrag(move)
def grow():
""" grows t1 shape """
global t1_size, g
t1_size += 0.1
t1.shapesize(t1_size / CURSOR_SIZE)
g -= .1
t1.color((r/255, g/255, b/255))
screen.update()
def follow():
""" has create()'d dots follow t1 """
global circles, dist
new_circles = []
for (x, y), stamp in circles:
t2.clearstamp(stamp)
t2.goto(x, y)
dist = t2.distance(t1) / 57.29577951308232 // 1
t2.goto(2 * (t1.xcor() + math.degrees(math.cos(math.radians(t1.towards(t2)))) // 1), 2 * (t1.ycor() + math.degrees(math.sin(math.radians(t1.towards(t2)))) // 1))
t2.setheading(t2.towards(t1))
if t2.distance(t1) < t1_size // 1:
if t2.distance(t1) > t1_size * 1.2:
t2.forward(500/t2.distance(t1)//1)
else:
t2.forward(3)
if t2.distance(t1) > t1_size // 2:
new_circles.append((t2.position(), t2.stamp()))
else:
grow() # we ate one, make t1 fatter
screen.update()
circles = new_circles
if circles:
screen.ontimer(follow, 10)
else:
phase = 1
produce()
def create():
""" create()'s dots with t2 """
count = 0
nux, nuy = -400, 300
while nuy > -400:
t2.goto(nux, nuy)
if t2.distance(t1) > t1_size // 2:
circles.append((t2.position(), t2.stamp()))
nux += 20
count += 1
if count == 40:
nuy -= 50
nux = -400
count = 0
screen.update()
def quit():
screen.bye()
sys.exit(0)
def redraw():
t2.color("black")
t2.shapesize((t2_size + 4) / CURSOR_SIZE)
t2.stamp()
t2.shapesize((t2_size + 2) / CURSOR_SIZE)
t2.color("white")
t2.stamp()
def produce():
#create boundary of star
global t2_size, ironmax
t1.ondrag(None)
t1.ht()
t2.goto(t1.xcor(), t1.ycor())
t2.color("black")
t2.shapesize((t1_size + 4) / CURSOR_SIZE)
t2.stamp()
t2.shapesize((t1_size + 2) / CURSOR_SIZE)
t2.color("white")
t2.stamp()
#start producing helium
while t2_size < t1_size:
t2.color("#ffff00")
t2.shapesize(t2_size / 20)
t2.stamp()
t2_size += .1
redraw()
screen.update()
ironmax = t2_size
t2_size = 4
while t2_size < ironmax:
t2.shapesize(t2_size / 20)
t2.color("grey")
t2.stamp()
t2_size += .1
screen.update()
# variables
t1_size = 6
circles = []
phase = 0
screen = Screen()
screen.screensize(900, 900)
#screen.mode("standard")
t2 = Turtle('circle', visible=False)
t2.shapesize(4 / CURSOR_SIZE)
t2.speed('fastest')
t2.color('purple')
t2.penup()
t2_size = 4
t1 = Turtle('circle')
t1.shapesize(t1_size / CURSOR_SIZE)
t1.speed('fastest')
r = 190
g = 100
b = 190
t1.color((r/255, g/255, b/255))
t1.penup()
t1.ondrag(move)
screen.tracer(False)
screen.listen()
screen.onkeypress(quit, "Escape")
create()
follow()
#print(phase)
screen.mainloop()
I took another crack at this, just looking at the problem of meteors swarming around a planet. Or in this case, moon as I chose Deimos as my model. I attempted to work at scale making the coordinate system 1 pixel = 1 kilometer. At the start, Deimos sits in a field of meteors each of which has a random heading but they all have the same size and velocity:
from turtle import Turtle, Screen
from random import random
METEOR_VELOCITY = 0.011 # kilometers per second
METEOR_RADIUS = 0.5 # kilometers
SECONDS_PER_FRAME = 1000 # each updates represents this many seconds passed
UPDATES_PER_SECOND = 100
DEIMOS_RADIUS = 6.2 # kilometers
G = 0.000003 # Deimos gravitational constant in kilometers per second squared
CURSOR_SIZE = 20
def follow():
global meteors
new_meteors = []
t = SECONDS_PER_FRAME
for (x, y), velocity, heading, stamp in meteors:
meteor.clearstamp(stamp)
meteor.goto(x, y)
meteor.setheading(heading)
meteor.forward(velocity * t)
meteor.setheading(meteor.towards(deimos))
meteor.forward(G * t * t)
meteor.setheading(180 + meteor.towards(x, y))
if meteor.distance(deimos) > DEIMOS_RADIUS * 2:
new_meteors.append((meteor.position(), velocity, meteor.heading(), meteor.stamp()))
screen.update()
meteors = new_meteors
if meteors:
screen.ontimer(follow, 1000 // UPDATES_PER_SECOND)
def create():
""" create()'s dots with meteor """
count = 0
nux, nuy = -400, 300
while nuy > -400:
meteor.goto(nux, nuy)
if meteor.distance(deimos) > DEIMOS_RADIUS * 2:
heading = random() * 360
meteor.setheading(heading) # all meteors have random heading but fixed velocity
meteors.append((meteor.position(), METEOR_VELOCITY, meteor.heading(), meteor.stamp()))
nux += 20
count += 1
if count % 40 == 0:
nuy -= 50
nux = -400
screen.update()
meteors = []
screen = Screen()
screen.screensize(1000, 1000)
screen.setworldcoordinates(-500, -500, 499, 499) # 1 pixel = 1 kilometer
meteor = Turtle('circle', visible=False)
meteor.shapesize(2 * METEOR_RADIUS / CURSOR_SIZE)
meteor.speed('fastest')
meteor.color('purple')
meteor.penup()
deimos = Turtle('circle')
deimos.shapesize(2 * DEIMOS_RADIUS / CURSOR_SIZE)
deimos.color("orange")
deimos.penup()
screen.tracer(False)
create()
follow()
screen.mainloop()
The first variable to investigate is METEOR_VELOCITY. At the setting provided, most meteors will crash into the moon but a few obtain orbital velocity. If you halve its value, all meteors will crash into the moon. If you double its value, a few meteors obtain escape velocity, leaving the window; a few may crash into the moon; most will form an orbiting cloud that gets smaller and tighter.
I tossed the trigonometric stuff and reverted back to degrees instead of radians. I use vector addition logic to work out the motion.
In the end, it's just a crude model.
By changing 180 to some other offsets, for example 195, in the def follow() in cdlane's code,
meteor.setheading(195 + meteor.towards(x, y))
then the metors would not go straight (180 degree) towards the Deimos, but instead would show some spiral movement towards the center.
Great example provided!
I'm trying to make a game where you click a bunch of random circles and get a score, however I also want it to deduct from your score when you miss the circle. I've been trying to use screen.onclick() but instead of deducting the score on a misclick it seems to deduct the score every second for no reason. What am I doing wrong?
import turtle
from random import random, randint
import time
CURSOR_SIZE = 20
score=0
def addscore():
global score
score += 1
def deletescore():
global score
score -= 1
def my_circle(color):
radius = (15)
circle = turtle.Turtle('circle', visible=False)
circle.shapesize(radius / CURSOR_SIZE)
circle.color(color)
circle.penup()
while True:
nx = randint(2 * radius - width // 2, width // 2 - radius * 2)
ny = randint(2 * radius - height // 2, height // 2 - radius * 2)
circle.goto(nx, ny)
for other_radius, other_circle in circles:
if circle.distance(other_circle) < 2 * max(radius, other_radius):
break
else:
break
circle.showturtle()
circle.onclick(lambda x,y,t=circle: (circle.hideturtle(), addscore()))
screen.onclick(deletescore())
return radius, circle
username=str(input("Set your username: "))
screen = turtle.Screen()
screen.bgcolor("lightgreen")
screen.title("Speed Clicker")
width, height = screen.window_width(), screen.window_height()
circles = []
gameLength = 30
difficulty = 20
startTime = time.time()
while True:
time.sleep(1/difficulty)
rgb = (random(), random(), random())
timeTaken = time.time() - startTime
circles.append(my_circle(rgb))
screen.title('SCORE: {}, TIME LEFT: {}'.format(score,int(round(gameLength - timeTaken,0))))
if time.time() - startTime > gameLength:
break
screen.title('GG! FINAL SCORE: {}'.format(score))
screen.mainloop()
The problem is this line:
screen.onclick(deletescore())
It's in the wrong place (only needs to be called once, not in a loop) and the argument is incorrect, it should be passing the function not calling it:
screen.onclick(deletescore)
The fix is multifold: first, move the modified statement to just before your while True: statement. Then fix the definition of deletescore() to take x and y arguments that we won't use but are necessary to be a click handler. (Or wrap it in a lambda like the call to addscore())
However, a click on a turtle can also be passed through as a click on the screen. To counter this, we can add 2 in addscore() instead of 1 since deletescore() will get called as well. That should be enough to get things working.
However, we really should eliminate the while True: loop and sleep() call which have no place in an event-driven program. Instead we use ontimer() to keep things moving and not potentially block other events. The reformulated code would be more like:
from turtle import Turtle, Screen
from random import random, randint
from time import time
CURSOR_SIZE = 20
def addscore():
global score
score += 2 # add 2 as this will also count as a -1 screen click!
def deletescore():
global score
score -= 1
def my_circle(color):
circle = Turtle('circle', visible=False)
circle.shapesize(radius / CURSOR_SIZE)
circle.color(color)
circle.penup()
while True:
nx = randint(2 * radius - width // 2, width // 2 - radius * 2)
ny = randint(2 * radius - height // 2, height // 2 - radius * 2)
circle.goto(nx, ny)
for other_radius, other_circle in circles:
if circle.distance(other_circle) < 2 * max(radius, other_radius):
break
else:
break
circle.onclick(lambda x, y: (circle.hideturtle(), addscore()))
circle.showturtle()
return radius, circle
def play():
rgb = (random(), random(), random())
timeTaken = time() - startTime
circles.append(my_circle(rgb))
screen.title('SCORE: {}, TIME LEFT: {}'.format(score, int(round(gameLength - timeTaken, 0))))
if time() - startTime > gameLength:
screen.title('FINAL SCORE: {}'.format(score))
screen.onclick(None)
screen.clear()
else:
screen.ontimer(play, 1000 // difficulty)
screen = Screen()
screen.bgcolor("lightgreen")
screen.title("Speed Clicker")
width, height = screen.window_width(), screen.window_height()
score = 0
circles = []
radius = 15
difficulty = 20
gameLength = 30
screen.onclick(lambda x, y: deletescore())
startTime = time()
play()
screen.mainloop()
I am currently trying to digitalize an boardgame I invented (repo: https://github.com/zutn/King_of_the_Hill). To make it work I need to check if one of the tiles (the arcs) on this board have been clicked. So far I have not been able to figure a way without giving up the pygame.arc function for drawing. If I use the x,y position of the position clicked, I can't figure a way out to determine the exact outline of the arc to compare to. I thought about using a color check, but this would only tell me if any of the tiles have been clicked. So is there a convenient way to test if an arc has been clicked in pygame or do I have to use sprites or something completely different? Additionally in a later step units will be included, that are located on the tiles. This would make the solution with the angle calculation postet below much more diffcult.
This is a simple arc class that will detect if a point is contained in the arc, but it will only work with circular arcs.
import pygame
from pygame.locals import *
import sys
from math import atan2, pi
class CircularArc:
def __init__(self, color, center, radius, start_angle, stop_angle, width=1):
self.color = color
self.x = center[0] # center x position
self.y = center[1] # center y position
self.rect = [self.x - radius, self.y - radius, radius*2, radius*2]
self.radius = radius
self.start_angle = start_angle
self.stop_angle = stop_angle
self.width = width
def draw(self, canvas):
pygame.draw.arc(canvas, self.color, self.rect, self.start_angle, self.stop_angle, self.width)
def contains(self, x, y):
dx = x - self.x # x distance
dy = y - self.y # y distance
greater_than_outside_radius = dx*dx + dy*dy >= self.radius*self.radius
less_than_inside_radius = dx*dx + dy*dy <= (self.radius- self.width)*(self.radius- self.width)
# Quickly check if the distance is within the right range
if greater_than_outside_radius or less_than_inside_radius:
return False
rads = atan2(-dy, dx) # Grab the angle
# convert the angle to match up with pygame format. Negative angles don't work with pygame.draw.arc
if rads < 0:
rads = 2 * pi + rads
# Check if the angle is within the arc start and stop angles
return self.start_angle <= rads <= self.stop_angle
Here's some example usage of the class. Using it requires a center point and radius instead of a rectangle for creating the arc.
pygame.init()
black = ( 0, 0, 0)
width = 800
height = 800
screen = pygame.display.set_mode((width, height))
distance = 100
tile_num = 4
ring_width = 20
arc = CircularArc((255, 255, 255), [width/2, height/2], 100, tile_num*(2*pi/7), (tile_num*(2*pi/7))+2*pi/7, int(ring_width*0.5))
while True:
fill_color = black
for event in pygame.event.get():
# quit if the quit button was pressed
if event.type == pygame.QUIT:
pygame.quit(); sys.exit()
x, y = pygame.mouse.get_pos()
# Change color when the mouse touches
if arc.contains(x, y):
fill_color = (200, 0, 0)
screen.fill(fill_color)
arc.draw(screen)
# screen.blit(debug, (0, 0))
pygame.display.update()
Below is the code I wrote.
The object moves along a circular path when I constantly calculate its position and give the coordinates to the obj.rect.x and object.rect.y.
What I need to know is how to rotate the object by something like below.
obj.rect.x += incrementx
obj.rect.y += incrementy
I implemented this in my code bu then the motion becomes anything but circluar.
Please help.
The two images used are here.
http://s5.postimg.org/fs4adqqib/crate_B.png
http://s5.postimg.org/vevjr44ab/plt0.png
import sys, os, pygame
from math import sin,cos,pi, radians
from pygame.locals import *
from standard_object_creator import *
SCREENW = 800
SCREENH = 700
BLUE = (0, 50, 255)
BLACK = (0, 0, 0)
RED = (255, 0, 0)
PURPLE = (145, 0, 100)
YELLOW = (220,220, 0)
pygame.init()
FPSCLOCK = pygame.time.Clock()
FONT1= "data\Cookie-Regular.ttf"
if sys.platform == 'win32' or sys.platform == 'win64':
#os.environ['SDL_VIDEO_CENTERED'] = '2'# center of screen
os.environ['SDL_VIDEO_WINDOW_POS'] = "%d,%d" % (10,30)#top left corner
SCREEN = pygame.display.set_mode((SCREENW, SCREENH))
## self, imagelist, posx, posy, speedx = 0, speedy = 0, value = 0
plat = pygame.image.load("grfx\plt0.png").convert_alpha()
box = pygame.image.load("grfx\crateB.png").convert_alpha()
FPS = 160 # frames per second
platforms = pygame.sprite.Group()
boxes = pygame.sprite.Group()
def maketext(msg,fontsize, colour = YELLOW, font = FONT1):
mafont = pygame.font.Font(font, fontsize)
matext = mafont.render(msg, True, colour)
matext = matext.convert_alpha()
return matext
box = object_factory ([box], 340, 50, 0, 1)
boxes.add(box)
center_x = 450 # x pos in relation to screen width
center_y = 400 # y pos in relation to screen height
radius = 200
angle = -90 #pi / 4 # starting angle 45 degrees
omega = .001 #Angular velocity
for x in xrange(6):
xpos = radius * cos(angle) #+ center_x #Starting position x
ypos = radius * sin(angle) #+ center_x #Startinh position y
obj = object_factory([plat], xpos, ypos)
obj.angle = angle
obj.omega = omega #angula velocity
obj.radius = radius
platforms.add(obj)
angle += 60
mouseposlist = []
all2gether = [platforms, boxes]
while True:
SCREEN.fill(BLACK)
## MOVE THE SPRITE IN A CIRCLE. Each object is placed by varying the step)
for obj in platforms:
obj.angle = obj.angle + obj.omega
## THE CODE BELOW WORKS
obj.rect.x = center_x + (cos(obj.angle) * obj.radius)
obj.rect.y = center_y + (sin(obj.angle) * obj.radius)
## How can I get the same thing to work in this way? by adding the rate of change to the box objects rect.x and rec.t? Why does this not work?
#obj.rect.x += obj.radius * obj.omega * cos(obj.angle)
#obj.rect.y -= obj.radius * obj.omega * sin(obj.angle)
pygame.draw.line(SCREEN, BLUE, (center_x, center_y), (obj.rect.x, obj.rect.y), 2)
for hp in boxes:
hp.rect.x += hp.speedx
hp.rect.y += hp.speedy
hp.move()
hp.collide(platforms)
for thing in all2gether:
thing.update()
thing.draw(SCREEN)
pygame.draw.line(SCREEN, BLUE, (0, SCREENH / 2), (SCREENW, SCREENH / 2), 2)
pygame.draw.line(SCREEN, BLUE, (SCREENW / 2, 0), (SCREENW / 2, SCREENH), 2)
pygame.display.update()
FPSCLOCK.tick(FPS)
##--------------------------------------------------------------
pygame.event.pump()
keys = pygame.key.get_pressed()
for event in pygame.event.get():
if event.type == MOUSEBUTTONDOWN:
if event.button == 1:
pos = pygame.mouse.get_pos()
val = [pos[0], pos[1], 0, 0]
print val
mouseposlist.append(val)
elif event.button == 3 and mouseposlist != []:
mouseposlist.pop(-1)
if event.type == KEYDOWN and event.key == K_ESCAPE:
print mouseposlist
pygame.quit()
sys.exit()
pygame.time.wait(0)
Your solution for moving the sprite in a circle is the time evaluation of the positional equation. You need to calculate the angle as a function of time. x = r * cos (omega * time). your first solution is a loop on time, incrementing omega by the fractional angle that is provided by the angular velocity. To evaluate a position take the amount of time multiplied by the angular velocity....
I manged to solve my problem and would like to share it. The new code is given below.
This works with Python / Pygame
center_of_rotation_x = SCREENW/2
center_of_rotation_y = SCREENH/2
radius = 200
angle = radians(45) #pi/4 # starting angle 45 degrees
omega = 0.1 #Angular velocity
x = center_of_rotation_x + radius * cos(angle) #Starting position x
y = center_of_rotation_y - radius * sin(angle) #Starting position y
SCREEN.blit(star, (x, y)) # Draw current x,y
angle = angle + omega # New angle, we add angular velocity
x = x + radius * omega * cos(angle + pi / 2) # New x
y = y - radius * omega * sin(angle + pi / 2) # New y
The above code works as it is. But when applied as a class it works differently. I will ask that in another question