Jed Rembold & Fred Agbo
February 23, 2024
When the function rev_q
is called, what
happens when the mouse is clicked in the window?
def rev_q():
def act_A(e):
sq.set_filled(True)
def act_B(e):
sq.set_size(
sq.get_width() - 10,
sq.get_height() - 10
)
gw = GWindow(500, 500)
sq = GRect(200, 200, 100, 100)
sq.set_color("blue")
gw.add(sq)
gw.add_event_listener("mousedown", act_B)
gw.add_event_listener("click", act_A)
Many would probably try to approach this doing something like as follows:
def growing_circles():
gw = GWindow(WIDTH, HEIGHT)
for i in range(NUM_CIRCLES):
# Create a new circle
# Animate the circle to grow it
# Wait for the animation to complete
The problem here is that there is no clear way to “wait” for an animation to complete
Instead need an event callback that takes care of both circle creation (when needed) and growing animations
def step():
if """ there is a circle still growing """
"""then increase its size """
elif """ a new circle needs to be created """
""" then create one """
else:
timer.stop()
from pgl import GWindow, GOval
import random
GWIDTH = 500
GHEIGHT = 400
N_CIRCLES = 20
MIN_RADIUS = 15
MAX_RADIUS = 100
DELTA_TIME = 10
DELTA_SIZE = 1
def random_color():
color = "#"
for i in range(6):
color += random.choice("0123456789ABCDEF")
return color
def create_filled_circle(x, y, r, color="black"):
circ = Goval(x-r, y-r, 2*r, 2*r)
circ.set_filled(True)
circ.set_color(color)
return circ
def growing_circles():
def start_new_circle():
r = random.uniform(MIN_RADIUS, MAX_RADIUS)
x = random.uniform(r, GWIDTH - r)
y = random.uniform(r, GHEIGHT - r)
gw.circle = create_filled_circle(
x, y,
0, random_color()
)
gw.desired_size = 2 * r
gw.current_size = 0
gw.circles_created += 1
return gw.circle
def step():
# Grow a circle if needed
if gw.current_size < gw.desired_size:
gw.current_size += DELTA_SIZE
x = gw.circle.get_x() - DELTA_SIZE / 2
y = gw.circle.get_y() - DELTA_SIZE / 2
gw.circle.set_bounds(
x, y,
gw.current_size,
gw.current_size
)
# or add a circle if you can
elif gw.circles_created < N_CIRCLES:
gw.add(start_new_circle())
# or stop
else:
timer.stop()
gw = GWindow(GWIDTH, GHEIGHT)
gw.circles_created = 0
gw.current_size = 0
gw.desired_size = 0
timer = gw.set_interval(step, DELTA_TIME)
from pgl import GWindow, GOval, GLine
from pgl_tools import create_filled_circle
def two_body():
def step():
# Compute forces and accelerations
dx = planet1.get_x() - planet2.get_x()
dy = planet1.get_y() - planet2.get_y()
r3 = (dx ** 2 + dy ** 2) ** (3 / 2)
ax = 1000 / r3 * dx
ay = 1000 / r3 * dy
# Update velocities
gw.vx1 += -ax
gw.vy1 += -ay
gw.vx2 += ax
gw.vy2 += ay
# Augment history paths
path1 = GLine(
planet1.get_x() + 10,
planet1.get_y() + 10,
planet1.get_x() + 10 + gw.vx1,
planet1.get_y() + 10 + gw.vy1,
)
path1.set_color("red")
path1.set_line_width(3)
path2 = GLine(
planet2.get_x() + 10,
planet2.get_y() + 10,
planet2.get_x() + 10 + gw.vx2,
planet2.get_y() + 10 + gw.vy2,
)
path2.set_color("cyan")
path2.set_line_width(3)
# Move planets
planet1.move(gw.vx1, gw.vy1)
planet2.move(gw.vx2, gw.vy2)
gw.add(path1)
gw.add(path2)
gw = GWindow(600, 600)
# Defining state variables
gw.vx1, gw.vy1 = 0, 1
gw.vx2, gw.vy2 = 0, -1
planet1 = create_filled_circle(200, 200, 10, "red")
planet2 = create_filled_circle(400, 200, 10, "cyan")
gw.add(planet1)
gw.add(planet2)
gw.set_interval(step, 30)
if __name__ == '__main__':
two_body()
GArc
class represents an arc formed
by taking a section of the perimeter of an oval.GArc
class is a
GFillableObject
, and so you can call
.set_filled()
on a
GArc
objectdef filled_arc():
gw = GWindow(400, 400)
arc = GArc(50, 50,
350, 350,
90, 135)
arc.set_color("orange")
arc.set_filled(True)
gw.add(arc)