Presentation is loading. Please wait.

Presentation is loading. Please wait.

Python Programming in Context Chapter 13. Objectives To write an event driven program To understand and write callback functions To practice with lists.

Similar presentations


Presentation on theme: "Python Programming in Context Chapter 13. Objectives To write an event driven program To understand and write callback functions To practice with lists."— Presentation transcript:

1 Python Programming in Context Chapter 13

2 Objectives To write an event driven program To understand and write callback functions To practice with lists of objects To see another pattern for using inheritance To learn about static variables

3 Event Driven Programming Events are placed on a queue While the queue is not empty – Take an event off of the queue – Execute a callback function for that event

4 Figure 13.1

5 Listing 13.1 class EventHandler: def __init__(self): self.queue = [] self.eventKeeper = {} def addEvent(self,eventName): self.queue.append(eventName) def registerCallback(self,event,func): self.eventKeeper[event] = func def run(self): while(True): if len(self.queue) > 0: nextEvent = self.queue.pop(0) self.eventKeeper[nextEvent]() else: print('queue is empty')

6 Multithreading the Event Loop Multiple things can happen at the same time Import Thread from the threading module Define a class that inherits from Thread Implement a run method that will be executed when the thread is started

7 Figure 13.2

8 Listing 13.2 from threading import Thread import time class EventHandler(Thread): def __init__(self): super().__init__() self.queue = [] self.eventKeeper = {} def addEvent(self,eventName): self.queue.append(eventName) def registerCallback(self,event,func): self.eventKeeper[event] = func def run(self): while(True): if len(self.queue) > 0: nextEvent = self.queue.pop(0) callBack = self.eventKeeper[nextEvent] callBack() else: time.sleep(1)

9 Etch-A-Sketch Create a simple event controlled drawing program Model after the Etch-A-Sketch drawing toy Use arrow keys to control a drawing turtle Event controlled since the turtle will only move when a key event occurs

10 Listing 13.3 (Part 1) import turtle class Etch: def __init__(self): self.myT = turtle.Turtle() self.myScreen = turtle.Screen() self.myT.color('blue') self.myT.pensize(2) self.myT.speed(0) self.distance = 5 self.turn = 10 self.myScreen.onkey(self.fwd,"Up") self.myScreen.onkey(self.bkwd,"Down") self.myScreen.onkey(self.left,"Left") self.myScreen.onkey(self.right,"Right") self.myScreen.onkey(self.quit,"q") self.myScreen.listen()

11 Listing 13.3 (Part 2) def fwd(self): self.myT.forward(self.distance) def bkwd(self): self.myT.backward(self.distance) def left(self): self.myT.left(self.turn) def right(self): self.myT.right(self.turn) def quit(self): self.myScreen.bye() def main(self): turtle.mainloop()

12 Redesign Etch-A-Sketch Use Inheritance Class Etch is-a Turtle

13 Listing 13.4 (Part 1) from turtle import Turtle, mainloop class Etch(Turtle): def __init__(self): super().__init__() self.screen = self.getscreen() self.color('blue') self.pensize(2) self.speed(0) self.distance = 5 self.turn = 10 self.screen.onkey(self.fwd,"Up") self.screen.onkey(self.bkwd,"Down") self.screen.onkey(self.left5,"Left") self.screen.onkey(self.right5,"Right") self.screen.onkey(self.quit,"q") self.screen.listen() self.main()

14 Listing 13.4 (Part 2) def fwd(self): self.forward(self.distance) def bkwd(self): self.backward(self.distance) def left5(self): self.left(self.turn) def right5(self): self.right(self.turn) def quit(self): self.screen.bye() def main(self): mainloop() if __name__ == '__main__': etch = Etch()

15 Placing Turtles Use onclick method Place a turtle where the click occurs onclick is a method of the Screen

16 Listing 13.5 (Part 1) from turtle import Turtle, mainloop import random class TurtlePlace: def __init__(self,maxTurtles,hWall=200,vWall=200): self.bigT = Turtle() self.bigTscreen = self.bigT.getscreen() self.bigT.shape('turtle') self.turtleList = [] self.bigTscreen.onclick(self.placeTurtle) self.bigT.hideturtle() self.numTurtles = 0 self.maxTurtles = maxTurtles self.hWall = hWall self.vWall = vWall self.drawField(hWall,vWall) mainloop() def placeTurtle(self,x,y): newT = Turtle()

17 Listing 13.5 (Part 2) newTscreen = newT.getscreen() newTscreen.tracer(0) newT.up() newT.goto(x,y) newT.shape('turtle') newT.setheading(random.randint(1,359)) newTscreen.tracer(1) self.numTurtles = self.numTurtles + 1 self.turtleList.append(newT) if self.numTurtles >= self.maxTurtles: self.bigTscreen.onclick(None) def drawField(self,hWall,vWall): self.bigTscreen.tracer(0) self.bigT.up() self.bigT.goto(-hWall,-vWall) self.bigT.down() for i in range(4): self.bigT.forward(2*hWall) self.bigT.left(90) self.bigTscreen.tracer(1)

18 Animate the Turtles Move the turtles If they hit a wall, turn them around and “bounce” them in the other direction

19 Listing 13.6 (Part 1) class AnimatedTurtle(Turtle): def __init__(self,hWall,vWall): super().__init__() self.scr = self.getscreen() self.xmin = -vWall self.xmax = vWall self.ymin = -hWall self.yMax = hWall self.scr.ontimer(self.__moveOneStep,100) def __moveOneStep(self): self.__computeNewHeading() self.forward(5)

20 Listing 13.6 (Part 2) self.scr.ontimer(self.__moveOneStep,100) def __computeNewHeading(self): xpos,ypos = self.position() oldHead = self.heading() newHead = oldHead if xpos > 190 or xpos < -190: newHead = 180-oldHead if ypos > 190 or ypos < -190: newHead = 360-oldHead if newHead != oldHead: self.setheading(newHead)

21 Listing 13.7 def placeTurtle(self,x,y): newT = AnimatedTurtle(self.hWall,self.vWall) newTscreen = newT.getscreen() newTscreen.tracer(0) newT.up() newT.goto(x,y) newT.shape('turtle') newT.setheading(random.randint(1,359)) newTscreen.tracer(1) self.numTurtles = self.numTurtles + 1 self.turtleList.append(newT) if self.numTurtles >= self.maxTurtles: self.bigTscreen.onclick(None)

22 Collisions If two turtles “collide”, bounce them off one another Need to have a list of all the turtles. List must be available to all other turtles Need it to be Static – One instance, belongs to the class, not an instance – All objects share it

23 Using a Static Variable ClassName.methodname AnimatedTurtle.allTurtles.append(self)

24 Listing 13.8 (Part 1) class AnimatedTurtle(Turtle): allTurtles = [] def __init__(self,hWall,vWall): super().__init__() self.scr = self.getscreen() self.xmin = -vWall+10 self.xmax = vWall-10 self.ymin = -hWall+10 self.ymax = hWall-10 self.scr.ontimer(self.__moveOneStep,100) AnimatedTurtle.allTurtles.append(self) def __moveOneStep(self): self.__computeNewHeading() self.forward(5) self.__checkCollisions() self.scr.ontimer(self.__moveOneStep,100) def __computeNewHeading(self):

25 Listing 13.8 (Part 2) xpos,ypos = self.position() oldHead = self.heading() newHead = oldHead if xpos > self.xmax or xpos < self.xmin: newHead = 180-oldHead if ypos > self.ymax or ypos < self.ymin: newHead = 360-oldHead if newHead != oldHead: self.setheading(newHead) def __checkCollisions(self): for otherT in AnimatedTurtle.allTurtles: if self != otherT: if self.distance(otherT) < 20: tempHeading = self.heading() self.setheading(otherT.heading()) otherT.setheading(tempHeading) while self.distance(otherT) < 20: self.forward(1) otherT.forward(1)

26 Simple Video Game Modeled after space invaders Aliens Laser Cannon, Bombs Aiming the Cannon Bomb moves in the direction it was fired Need to know when a bomb collides with an alien

27 Figure 13.3

28 Figure 13.4

29 Listing 13.9 class LaserCannon(Turtle): def __init__(self,xmin,xmax,ymin,ymax): super().__init__() self.screen = self.getscreen() self.screen.bgcolor('light green') self.screen.setworldcoordinates(xmin,ymin,xmax,ymax) self.screen.onclick(self.aim,1) self.screen.onkey(self.shoot,"s") self.screen.onkey(self.quit,'q') def aim(self,x,y): heading = self.towards(x,y) self.setheading(heading) def shoot(self): Bomb(self.heading(),5) def quit(self): self.screen.bye()

30 Listing 13.10 class BoundedTurtle(Turtle): def __init__(self, speed, xmin=-200,xmax=200,ymin=0,ymax=400): super().__init__() self.xmin = xmin self.xmax = xmax self.ymin = ymin self.ymax = ymax self.speed = speed def outOfBounds(self): xpos,ypos = self.position() out = False if xpos self.xmax: out = True if ypos self.ymax: out = True return out def move(self): self.forward(self.speed) if self.outOfBounds(): self.remove() else: self.getscreen().ontimer(self.move,200) def remove(self): self.hideturtle()

31 Listing 13.11 class Alien(BoundedTurtle): alienList = [] @staticmethod def getAliens(): return [x for x in Alien.alienList if x.alive] def __init__(self,speed,xmin,xmax,ymin,ymax): super().__init__(speed,xmin,xmax,ymin,ymax) self.getscreen().tracer(0) self.up() if 'PurpleAlien.gif' not in self.getscreen().getshapes(): self.getscreen().addshape('PurpleAlien.gif') self.shape('PurpleAlien.gif') self.goto(random.randint(xmin-1,xmax-1),ymax-20) self.setheading(random.randint(250,290)) self.getscreen().tracer(1) Alien.alientList = [x for x in Alien.alienList if x.alive] Alien.alienList.append(self) self.alive = True self.getscreen().ontimer(self.move,200) def remove(self): self.alive = False self.hideturtle()

32 Listing 13.12 (Part 1) class Bomb(BoundedTurtle): def __init__(self, initHeading,speed): super().__init__(speed) self.initHeading = initHeading self.resizemode('user') self.color('red','red') self.shape('circle') self.setheading(initHeading) self.up() self.turtlesize(.25) self.getscreen().ontimer(self.move,100) def move(self): exploded = False self.forward(self.speed) for i in Alien.getAliens():

33 Listing 13.12 (Part 2) if self.distance(i) < 5: i.remove() exploded = True if self.outOfBounds() or exploded: self.remove() else: self.getscreen().ontimer(self.move,100) def distance(self,other): p1 = self.position() p2 = other.position() a = p1[0]-p2[0] b = p1[1]-p2[1] dist = math.sqrt(a**2 + b**2) return dist

34 Listing 13.13 class AlienInvaders: def __init__(self,xmin,xmax,ymin,ymax): super().__init__() self.xmin = xmin self.xmax = xmax self.ymin = ymin self.ymax = ymax def play(self): self.mainWin = LaserCannon(self.xmin,self.xmax,self.ymin,self.ymax).getscreen() self.mainWin.ontimer(self.addAlien,1000) self.mainWin.listen() mainloop() def addAlien(self): if len(Alien.getAliens()) < 7: Alien(1,self.xmin,self.xmax,self.ymin,self.ymax) self.mainWin.ontimer(self.addAlien,1000)


Download ppt "Python Programming in Context Chapter 13. Objectives To write an event driven program To understand and write callback functions To practice with lists."

Similar presentations


Ads by Google