This recipe is designed to show sample usage of the physics module. Once the program is running, the window can be dragged around the screen; and the balls will react accordingly. If an error is displayed on the screen, the window moved to show the rest of the error message.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 | from physics import *
from Tkinter import *
from random import randint
from traceback import format_exc
SCREEN_WIDTH = 400
SCREEN_HEIGHT = 400
BALLS = 10
BALL_RADIUS = 10
WALL_SPACE = 50
WALL_FORCE = 500
SPEED_LIMIT = 250
START_SPACE = 20
FPS = 40
BACKGROUND = 'white'
BALL_COLOR = 'red'
def main():
initialise()
mainloop()
def initialise():
global balls, x, y, screen, lock
space = WALL_SPACE + BALL_RADIUS
balls = []
for ball in xrange(BALLS):
table = randint(0, 3)
if table >> 1:
x = randint(space, SCREEN_WIDTH - space)
y = -START_SPACE if table & 1 else START_SPACE + SCREEN_HEIGHT
else:
x = -START_SPACE if table & 1 else START_SPACE + SCREEN_WIDTH
y = randint(space, SCREEN_HEIGHT - space)
balls.append(Ball(x, y, BALL_RADIUS))
root = Tk()
root.resizable(False, False)
root.title('Space Balls')
x = (root.winfo_screenwidth() - SCREEN_WIDTH) / 2
y = (root.winfo_screenheight() - SCREEN_HEIGHT) / 2
root.geometry('%dx%d+%d+%d' % (SCREEN_WIDTH, SCREEN_HEIGHT, x, y))
root.bind_all('<Escape>', lambda event: event.widget.quit())
root.bind('<Configure>', move)
screen = Canvas(root, width=SCREEN_WIDTH, height=SCREEN_HEIGHT, background=BACKGROUND)
screen.after(1000 / FPS, update)
screen.after(10000 / FPS, unlock)
screen.pack()
lock = True
def move(event):
global x, y
if not lock:
diff = Vector(x - event.x, y - event.y)
screen.move(ALL, diff.x, diff.y)
for ball in balls:
ball.pos += diff
x, y = event.x, event.y
def update():
try:
ident = screen.after(1000 / FPS, update)
for mutate in container, governor:
for ball in balls:
mutate(ball)
for index, ball_1 in enumerate(balls[:-1]):
for ball_2 in balls[index+1:]:
ball_1.crash(ball_2)
for ball in balls:
ball.move(FPS)
screen.delete(ALL)
for ball in balls:
x1 = ball.pos.x - BALL_RADIUS
y1 = ball.pos.y - BALL_RADIUS
x2 = ball.pos.x + BALL_RADIUS
y2 = ball.pos.y + BALL_RADIUS
screen.create_oval(x1, y1, x2, y2, fill=BALL_COLOR)
except:
screen.after_cancel(ident)
screen.delete(ALL)
screen.create_text(SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2, text=format_exc(), font='Courier 10', fill='red')
def container(ball):
space = WALL_SPACE + BALL_RADIUS
force = float(WALL_FORCE) / FPS
if ball.pos.x <= space:
ball.vel.x += force
elif ball.pos.x >= SCREEN_WIDTH - space:
ball.vel.x -= force
if ball.pos.y <= space:
ball.vel.y += force
elif ball.pos.y >= SCREEN_HEIGHT - space:
ball.vel.y -= force
def governor(ball):
if abs(ball.vel) > SPEED_LIMIT:
ball.vel = ball.vel.unit() * SPEED_LIMIT
def unlock():
global lock
lock = False
if __name__ == '__main__':
main()
|
This recipe led to the design of the following two recipes:
(1) Bouncy Balls (2) Explosive Embers
Tags: programs