-
-
Save ejmurray/5662656 to your computer and use it in GitHub Desktop.
ball physics form codeskulptor
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# ball physics code for generic 2D domain | |
# the functions inside() and normal() encode the shape of the ennvironment | |
import simplegui | |
import random | |
import math | |
# Canvas size | |
width = 600 | |
height = 400 | |
# Ball traits | |
radius = 20 | |
color = "White" | |
# math helper function | |
def dot(v, w): | |
return v[0] * w[0] + v[1] * w[1] | |
class RectangularDomain: | |
def __init__(self, width, height): | |
self.width = width | |
self.height = height | |
self.border = 2 | |
# return if bounding circle is inside the domain | |
def inside(self, center, radius): | |
in_width = ((radius + self.border) < center[0] < | |
(self.width - self.border - radius)) | |
in_height = ((radius + self.border) < center[1] < | |
(self.height - self.border - radius)) | |
return in_width and in_height | |
# return a unit normal to the domain boundary point nearest center | |
def normal(self, center): | |
left_dist = center[0] | |
right_dist = self.width - center[0] | |
top_dist = center[1] | |
bottom_dist = self.height - center[1] | |
if left_dist < min(right_dist, top_dist, bottom_dist): | |
return (1, 0) | |
elif right_dist < min(left_dist, top_dist, bottom_dist): | |
return (-1, 0) | |
elif top_dist < min(bottom_dist, left_dist, right_dist): | |
return (0, 1) | |
else: | |
return (0, -1) | |
# return random location | |
def random_pos(self, radius): | |
x = random.randrange(radius, self.width - radius - self.border) | |
y = random.randrange(radius, self.height - radius - self.border) | |
return [x, y] | |
# Draw boundary of domain | |
def draw(self, canvas): | |
canvas.draw_polygon([[0, 0], [self.width, 0], | |
[self.width, self.height], [0, self.height]], | |
self.border*2, "Red") | |
class CircularDomain: | |
def __init__(self, center, radius): | |
self.center = center | |
self.radius = radius | |
self.border = 2 | |
# return if bounding circle is inside the domain | |
def inside(self, center, radius): | |
dx = center[0] - self.center[0] | |
dy = center[1] - self.center[1] | |
dr = math.sqrt(dx ** 2 + dy ** 2) | |
return dr < (self.radius - radius - self.border) | |
# return a unit normal to the domain boundary point nearest center | |
def normal(self, center): | |
dx = center[0] - self.center[0] | |
dy = center[1] - self.center[1] | |
dr = math.sqrt(dx ** 2 + dy ** 2) | |
return [dx / dr, dy / dr] | |
# return random location | |
def random_pos(self, radius): | |
r = random.random() * (self.radius - radius - self.border) | |
theta = random.random() * 2 * math.pi | |
x = r * math.cos(theta) + self.center[0] | |
y = r * math.sin(theta) + self.center[1] | |
return [x, y] | |
# Draw boundary of domain | |
def draw(self, canvas): | |
canvas.draw_circle(self.center, self.radius, self.border*2, "Red") | |
class Ball: | |
def __init__(self, radius, color, domain): | |
self.radius = radius | |
self.color = color | |
self.domain = domain | |
self.pos = self.domain.random_pos(self.radius) | |
self.vel = [random.random() + .1, random.random() + .1] | |
# bounce | |
def reflect(self): | |
norm = self.domain.normal(self.pos) | |
norm_length = dot(self.vel, norm) | |
self.vel[0] = self.vel[0] - 2 * norm_length * norm[0] | |
self.vel[1] = self.vel[1] - 2 * norm_length * norm[1] | |
# update ball position | |
def update(self): | |
self.pos[0] += self.vel[0] | |
self.pos[1] += self.vel[1] | |
if not self.domain.inside(self.pos, self.radius): | |
self.reflect() | |
# draw | |
def draw(self, canvas): | |
canvas.draw_circle(self.pos, self.radius, 1, | |
self.color, self.color) | |
# generic update code for ball physics | |
def draw(canvas): | |
ball.update() | |
field.draw(canvas) | |
ball.draw(canvas) | |
field = RectangularDomain(width, height) | |
# field = CircularDomain([width/2, height/2], 180) | |
ball = Ball(radius, color, field) | |
frame = simplegui.create_frame("Ball physics", width, height) | |
frame.set_draw_handler(draw) | |
frame.start() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment