import pygame, logging import math, random log = logging.getLogger( 'horse.game' ) log.setLevel( logging.DEBUG ) class Game(): game_running = True # tuple for horse location horse_loc = (0,0) # array of (image,location) for apple/carrot/etc locations objects = [] # keep track of the mouse pointer mouse_pos = (200,200) # tuple size screen_size = (0,0) grass_size = (0,0) horse_size = (0,0) apple_size = (0,0) # images / (type pygame Surface) grass_image = None horse_image = None horse_image_l = None moving_left = False apple_image = None carrot_image = None hay_image = None # other parameters horse_speed = 8 # pixels per tick; at 25 ticks/second, this is approx 200 pixels per second horse_reach = 20 # pixels from cener of horse where he can reach target_loc = None def setup(self,screen): self.screen_size = screen.get_size() # tuple # put the horse in the center of the screen self.horse_loc = (100,100) # load the images and convert to screen format self.grass_image = pygame.image.load('horse/grass.png','grass') self.grass_image.convert(screen) self.grass_size = self.grass_image.get_size() self.horse_image = pygame.image.load('horse/horse.png','horse') self.horse_image.convert(screen) self.horse_size = self.horse_image.get_size() # Make a copy for the left-facing image self.horse_image_l=pygame.transform.flip(self.horse_image,True,False) # Make the edibles self.apple_size = (10,10) self.apple_image = pygame.Surface(self.apple_size,0,screen) self.apple_image.fill((0xff,0,0)) self.carrot_size = (7,20) self.carrot_image = pygame.Surface(self.carrot_size,0,screen) self.carrot_image.fill((0xff,0x99,0)) self.hay_size = (20,20) self.hay_image = pygame.Surface(self.hay_size,0,screen) self.hay_image.fill((0x99,0x66,0x33)) self.update(screen) def update(self,screen): """updates the screen image""" self.screen_size = screen.get_size() # tuple # paint background image # TODO: there is probably a better way to tile the background image # (and perhaps to tile it only once, and save the base image) tilex=int(math.ceil(self.screen_size[0]/self.grass_size[0])) tiley=int(math.ceil(self.screen_size[1]/self.grass_size[1])) for x in range(0,tilex): for y in range(0,tiley): screen.blit(self.grass_image,(x*self.grass_size[0],y*self.grass_size[1])) # paint horse image on screen # TODO: flip horse image left or right, depending on the direction she is moving #screen.blit(self.horse_image,self.horse_loc) if self.moving_left: self.drawObject(screen,(self.horse_image_l, self.horse_loc)) else: self.drawObject(screen,(self.horse_image, self.horse_loc)) # draw apples and other objects for o in self.objects: self.drawObject(screen,o) # flip display buffer pygame.display.flip() def drawObject(self,screen,object): # unpack the object (image, loc) = object object_size = image.get_size() # adjust the upper left corner so that the center of object is at the recorded location adj_loc = (loc[0]-object_size[0]/2,loc[1]-object_size[1]/2) screen.blit(image, adj_loc) def placeObject(self,image,location): #adj_loc = self.adjust_loc(location, image.get_size()) adj_loc = location self.objects.append((image,adj_loc)) def adjust_loc(self,loc,object_size): """adjust the given location by half the object size. Thus the center of the object will be at loc""" adj_loc = (loc[0]-object_size[0]/2,loc[1]-object_size[1]/2) return adj_loc def handleEvent(self,event): if event.type == pygame.QUIT: self.game_running = False elif event.type == pygame.KEYDOWN: #log.debug("event keydown: %s", event) # TODO: keys are not a localized if event.key in (27,113): # esc or q=quit log.debug('quit key pressed') self.game_running = False elif event.key == 97: # a=apple self.placeObject(self.apple_image, self.mouse_pos) elif event.key == 99: # c=carrot self.placeObject(self.carrot_image, self.mouse_pos) elif event.key == 104: # h=hay self.placeObject(self.hay_image, self.mouse_pos) elif event.type == pygame.KEYUP: pass elif event.type == pygame.MOUSEBUTTONDOWN: #log.debug("event mousedown: %s", event) # place apples self.placeObject(self.apple_image, self.mouse_pos) elif event.type == pygame.MOUSEMOTION: #log.debug("event mousemove: %s", event) # Remember mouse location, because we need it in KEYDOWN events self.mouse_pos = event.pos else: #log.debug("event other: %s", event) pass def tick(self,millis): """updates the game state for a tick""" # millis is ignored if len(self.objects)>0: # move the horse toward the first object in the queue, at full speed (target_image,target_loc) = self.objects[0] horse_speed = self.horse_speed else: # the horse might feel inclined to wander slowly toward a random target #if self.target_loc is None: # self.target_loc = (self.screen_size[0]*random.random(), self.screen_size[1]*random.random()) #target_loc = self.target_loc # wander toward mouse target_loc = self.mouse_pos horse_speed = 2 (distx, disty) = (target_loc[0] - self.horse_loc[0], target_loc[1] - self.horse_loc[1]) # TODO: there is probably a library function to scale this for me # move the horse approx horse_speed pixels in the indicated direction dist = math.sqrt(distx*distx+disty*disty) (movex, movey) = (horse_speed*distx/dist, horse_speed*disty/dist) # "eat" the object if we are close enough # (so that we will get a new target next tick) # TODO: perhaps colision detection would be better here if dist < self.horse_speed*2: if len(self.objects)>0: self.objects.pop(0) else: self.target_loc = None # dont move the horse (causes bounce) return # move the horse, but check that the horse has not wandered off the screen (horsex, horsey) = (self.horse_loc[0] + movex, self.horse_loc[1] + movey) # TODO: check for a library function to determine out of bounds if (horsex < 0): horsex = 0 if (horsey < 0): horsey = 0 if (horsex > self.screen_size[0]): horsex = self.screen_size[0] if (horsey > self.screen_size[1]): horsey = self.screen_size[1] self.horse_loc = (horsex,horsey) if movex<0 and abs(distx)>horse_speed: self.moving_left = True else: self.moving_left = False def isRunning(self): return self.game_running