class FarmGame(object): def __init__(self): self.screen = pygame.display.get_surface() GLOBALS.UI = UserInterface() GLOBALS.game_running = False GLOBALS.tile_map = TileMap() GLOBALS.tile_map.map_layer.zoom = 2 # pyscroll supports layered rendering. our map has 3 'under' layers # layers begin with 0, so the layers are 0, 1, and 2. # since we want the sprite to be on top of layer 1, we set the default # layer for sprites as 2 self.group = PyscrollGroup(map_layer=GLOBALS.tile_map.map_layer, default_layer=2) GLOBALS.hero = Hero() GLOBALS.hero.position = GLOBALS.tile_map.map_layer.map_rect.center for tree in GLOBALS.trees: self.group.add(tree) for ground in GLOBALS.ground: self.group.add(ground) self.group.add(GLOBALS.hero) # add player last! self.input = Input() def run(self): clock = pygame.time.Clock() GLOBALS.game_running = True try: while GLOBALS.game_running: dt = clock.tick(60)/1000. # limit to 60fps, but also damn milliseconds, you fast self.input.handle() self.update(dt) self.draw(self.screen) GLOBALS.UI.draw(self.screen) pygame.display.flip() except KeyboardInterrupt: GLOBALS.game_running = False def update(self, dt): self.group.update(dt) def draw(self, surface): self.group.center(GLOBALS.hero.rect.center) self.group.draw(surface)
class BinalGame(object): """ This class is a basic game. This class will load data, create a pyscroll group, a hero object. It also reads input and moves the Hero around the map. Finally, it uses a pyscroll group to render the map and Hero. """ filename = get_map(MAP_FILENAME) def __init__(self, filename, oldEntrance=None, oldmap=None, hero=None): self.portalName = '' self.portalsIn = list() self.portalsOut = list() self.olfFilename = None self.filename = get_map(filename) if self.filename in heroStates: self.mode = heroStates[self.filename] else: self.mode = "Peaceful" if oldmap == None: self.oldMap = filename else: self.oldMap = oldmap overworld = 'BinalOverworld2.tmx' self.oldEntrance = oldEntrance self.battleInstance = False # true while running self.running = False # load data from pytmx tmx_data = load_pygame(self.filename) # setup level geometry with simple pygame rects, loaded from pytmx self.walls = list() for object in tmx_data.objects: self.walls.append( pygame.Rect(object.x, object.y, object.width, object.height)) # create new data source for pyscroll map_data = pyscroll.data.TiledMapData(tmx_data) # create new renderer (camera) self.map_layer = pyscroll.BufferedRenderer(map_data, screen.get_size(), clamp_camera=False, tall_sprites=1) self.map_layer.zoom = 2 # pyscroll supports layered rendering. our map has 3 'under' layers # layers begin with 0, so the layers are 0, 1, and 2. # since we want the sprite to be on top of layer 1, we set the default # layer for sprites as 2 self.group = PyscrollGroup(map_layer=self.map_layer, default_layer=2) self.hero = Hero() # put the hero in the center of the map # self.hero.position = self.map_layer.map_rect.center # self.hero._position[0] += 200 # self.hero._position[1] += 400 # add our hero to the group self.group.add(self.hero) # startpoints self.startpoints = [] for object in tmx_data.objects: if object.name == "startpoint": self.startpoints.append((object.x, object.y)) self.hero.position = (self.startpoints[0][0], self.startpoints[0][1]) self.oldPosition = self.hero.position self.group.add(self.hero) self.steps = 0 self.battle = 1 # set default zoom when not in overworld if self.oldMap == overworld and self.filename != "data/" + overworld: self.map_layer.zoom = self.map_layer.zoom - .25 self.portalNames = list() # add portals to collider lists for object in tmx_data.objects: if object.type == "portalIn": self.portalNames.append(object) self.portalsIn.append( pygame.Rect(object.x, object.y, object.width, object.height)) elif object.type == "portalO": self.portalsOut.append( pygame.Rect(object.x, object.y, object.width, object.height)) def draw(self, surface): # center the map/screen on our Hero self.group.center(self.hero.rect.center) # draw the map and all sprites self.group.draw(surface) def nearestPortal(self, trigger=False): (x, y) = self.hero.position for portal in self.portalsIn: if trigger == False: trigger = True self.oldEntrance = (portal.x, portal.y) (p, q) = self.oldEntrance distanceNew = (math.sqrt((x - portal.x)**2 + (y - portal.y)**2)) distanceOld = (math.sqrt((x - p)**2 + (y - q)**2)) if distanceNew < distanceOld: distanceOld = distanceNew self.oldEntrance = (portal.x, portal.y) (p, q) = (portal.x, portal.y) for portal in self.portalNames: if self.almostEqual((p, q), (portal.x, portal.y)): self.portalName = portal.name def handle_input(self): """ Handle pygame input events """ poll = pygame.event.poll clock = pygame.time.Clock() event = poll() while event: ticks = pygame.time.get_ticks() if event.type == QUIT: self.running = False break elif event.type == KEYDOWN: if event.key == K_ESCAPE: self.running = False break elif event.key == K_EQUALS: self.map_layer.zoom += .25 elif event.key == K_MINUS: value = self.map_layer.zoom - .25 if value > 0: self.map_layer.zoom = value # this will be handled if the window is resized elif event.type == VIDEORESIZE: init_screen(event.w, event.h) self.map_layer.set_size((event.w, event.h)) event = poll() # using get_pressed is slightly less accurate than testing for events # but is much easier to use. pressed = pygame.key.get_pressed() # if pressed[K_UP]: # self.hero.velocity[1] = -HERO_MOVE_SPEED # elif pressed[K_DOWN]: # self.hero.velocity[1] = HERO_MOVE_SPEED # else: # self.hero.velocity[1] = 0 # if pressed[K_LEFT]: # self.hero.velocity[0] = -HERO_MOVE_SPEED # elif pressed[K_RIGHT]: # self.hero.velocity[0] = HERO_MOVE_SPEED # else: # self.hero.velocity[0] = 0 # if self.moving != False: ticks = pygame.time.get_ticks() if pressed[K_UP]: self.hero.currImageList = self.hero.downs self.hero.walkAnimation(ticks) self.hero.velocity[1] = -HERO_MOVE_SPEED #self.steps += 1 elif pressed[K_DOWN]: self.hero.currImageList = self.hero.ups self.hero.walkAnimation(ticks) self.hero.velocity[1] = HERO_MOVE_SPEED #self.steps += 1 else: self.hero.velocity[1] = 0 if pressed[K_LEFT]: self.hero.currImageList = self.hero.lefts self.hero.walkAnimation(ticks) self.hero.velocity[0] = -HERO_MOVE_SPEED #self.steps += 1 elif pressed[K_RIGHT]: self.hero.currImageList = self.hero.rights self.hero.walkAnimation(ticks) self.hero.velocity[0] = HERO_MOVE_SPEED #self.steps += 1 else: self.hero.velocity[0] = 0 # sprint if pressed[K_SPACE]: self.hero.velocity[0] *= 1.7 self.hero.velocity[1] *= 1.7 # more likely to battle encounter if sprinting # if self.hero.velocity[0] > 0 or self.hero.velocity[1] > 0: # #self.steps += 2 # if self.hero.velocity[0] >= 1.5 * HERO_MOVE_SPEED: # pass # if self.hero.velocity[1] >= 1.5 * HERO_MOVE_SPEED: # pass # stops character from moving when battlescreen is initiated #if self.mode == "Battle": # (self.hero.velocity[0], self.hero.velocity[1]) = (0, 0) def update(self, dt): """ Tasks that occur over time should be handled here """ self.group.update(dt) # check if the sprite's feet are colliding with wall # sprite must have a rect called feet, and move_back method, # otherwise this will fail for sprite in self.group.sprites(): if sprite.feet.collidelist(self.portalsIn) > -1: if sprite.type == "hero": self.nearestPortal() self.filename = inPortalDict[self.filename + self.portalName] self.hero.position = (self.startpoints[0][0], self.startpoints[0][1]) elif sprite.feet.collidelist(self.portalsOut) > -1: if sprite.type == "hero": filename = outPortalDict[self.filename] self.filename = filename self.hero.position = (self.startpoints[0][0], self.startpoints[0][1]) if sprite.feet.collidelist(self.walls) > -1: sprite.move_back(dt) # plays music based on map file keyed to dictionary # also covers changing map sound effect # def changeMusicAndInstance(self, surface, oldMusic=None): # tmap = self.filename # song = MusicDict[tmap] # # instance change sound, from Zelda stairs sound # playSound("Enter.wav", .15) # if oldMusic == None: # oldMusic = MusicDict[self.oldMap] # if self.mode != "Overworld": # if song == oldMusic: return None # # loops music indefinitely for that map # playMusic(song) # def showStartScreen(self): # self.draw('title_demo') # if checkForKeyPress(): # self.run() @staticmethod def almostEqual(position1, position2): (x1, y1) = position1 (x2, y2) = position2 epsilon = 60 if abs(x1 - x2) < epsilon: if abs(y1 - y2) < epsilon: return True return False def randomBattle(self): # prevents battle from happening right on town portal for sprite in self.group.sprites(): if sprite.feet.collidelist(self.portalsIn) > -1: return None if self.almostEqual(position, self.oldPosition): return None if self.mode == "Peaceful" or self.mode == "Battle": return None diceRoll = random.randint(0, 100) #increased encounter rate when walking without encountering # a single battle for a certain number of steps threshold = 600 if self.steps > threshold: if diceRoll < 50: self.mode = "Battle" self.steps = 0 if self.steps > 200: # lower encounter rate when just beginning to walk if diceRoll < 200: self.mode = "Battle" self.steps = 0 self.oldPosition = position def run(self): """ Run the game loop """ filename = self.filename clock = pygame.time.Clock() self.running = True from collections import deque times = deque(maxlen=30) #idle hero animation ticks = pygame.time.get_ticks() self.hero.walkAnimation(ticks) playMusic('overworld.wav') try: while self.running: dt = clock.tick() / 1000. times.append(clock.get_fps()) # print(sum(times)/len(times))#idle hero animation ticks = pygame.time.get_ticks() self.hero.walkAnimation(ticks) # beginning of random battle # self.randomBattle() # changing map if self.filename != filename: # leaving map toward overworld if self.oldMap == os.path.join(RESOURCES_DIR, self.filename): oldMap = inPortalDict[ str(os.path.join(RESOURCES_DIR, self.filename)) + self.portalName] else: oldMap = outPortalDict[str( os.path.join(RESOURCES_DIR, self.filename))] self.__init__(self.filename, self.oldEntrance, oldMap, self.hero) self.oldEntrance = OldEntranceDict[filename] if os.path.join(RESOURCES_DIR, outPortalDict[filename]) == self.filename: if self.oldEntrance != None: position = (self.oldEntrance[0], self.oldEntrance[1]) self.hero.position = position self.oldPosition = position self.run() self.handle_input() self.update(dt) self.draw(screen) pygame.display.flip() except KeyboardInterrupt: self.running = False
class Map: def __init__(self, game): self.game = game self.screen = game.screen self.datahelper = game.datahelper self.hero = game.hero self.scriptengine = game.scriptengine self.hero.map = self def load(self, data): #loading map to creating group tmx_data = load_pygame( path.join(self.game.dir, "data", self.datahelper.maps[data["mapname"]]["file"])) map_data = pyscroll.data.TiledMapData(tmx_data) self.map_layer = pyscroll.BufferedRenderer( map_data, self.screen.surface.get_size(), clamp_camera=False) #tall_sprites=1) self.map_layer.zoom = 2 self.group = PyscrollGroup(map_layer=self.map_layer, default_layer=5) #data["layer"]) #setting up player self.mapname = data["mapname"] self.hero.position = [data["player"]["x"], data["player"]["y"] - 8] if data["player"]["walking"] == 1: self.hero.walking = True self.hero.movingx, self.hero.movingy = data["player"][ "walkingx"], data["player"]["walkingy"] self.hero.steps = 16 self.group.add(self.hero) self.hero.rect.topleft = self.hero.position #colliditon self.collidable = {} self.interactable = {} self.warps = {} self.npcs = {} i = j = k = l = 0 for id in tmx_data.objects_by_id: #print(tmx_data.objects_by_id[id].name) if tmx_data.objects_by_id[id].name in self.datahelper.interactable: self.interactable[j] = tmx_data.objects_by_id[id] j += 1 if tmx_data.objects_by_id[id].name in self.datahelper.collidable: self.collidable[i] = (tmx_data.objects_by_id[id].x, tmx_data.objects_by_id[id].y) i += 1 if "Warp" in tmx_data.objects_by_id[id].name: self.warps[k] = tmx_data.objects_by_id[id] k += 1 if "npc" in tmx_data.objects_by_id[id].name: self.npcs[l] = self.scriptengine.load_npc( tmx_data.objects_by_id[id]) #self.npcs[l] = NPC(tmx_data.objects_by_id[id].name) #self.npcs[l].position = [tmx_data.objects_by_id[id].x, tmx_data.objects_by_id[id].y-8] self.group.add(self.npcs[l]) self.npcs[l].map = self #self.npcs[l].rect.topleft = self.npcs[l].position #if "dir" in tmx_data.objects_by_id[id].properties.keys(): #self.npcs[l].dir = tmx_data.objects_by_id[id].properties["dir"] #self.scriptengine.load(self.npcs[l]) #self.npcs[l].map = self l += 1 #animations #print(self.warps) self.timer = 0 self.warping = False self.nextmap = {} def draw(self): self.group.update() self.hero.tick() self.group.center(self.hero.rect.topleft) #self.group.draw(screen) #if self.loaded: self.group.draw(self.screen.surface) def change_map(self, data): self.warps = 0 self.scriptengine.clear() self.load(data) def update(self): for key, warp in self.warps.items(): if self.hero.rect.collidepoint(warp.x, warp.y): if not self.screen.state["fade"]: self.screen.drawFade() if self.screen.fadein: self.change_map(self.datahelper.warps[warp.name]) def collide(self, rect, npc=False): for i in self.collidable: if rect.collidepoint(self.collidable[i]): return True for i in self.npcs: if self.npcs[i].walking: if rect.colliderect(self.npcs[i].facing): return True if rect.collidepoint(self.npcs[i].position[0], self.npcs[i].position[1] + 8): return True if npc and rect.collidepoint(self.hero.position[0], self.hero.position[1] + 8): return True return False def interact(self): #print(self.interactable) for i in self.interactable: if self.hero.facing.collidepoint(self.interactable[i].x, self.interactable[i].y): dialogbox = Dialog( self.datahelper.interactable[self.interactable[i].name], self.screen.surface) self.screen.drawDialog(dialogbox) for i in self.npcs: if not self.npcs[i].walking: if self.hero.facing.collidepoint(self.npcs[i].rect.x, self.npcs[i].rect.y + 8): self.scriptengine.run(self.npcs[i])
class QuestGame(object): """ This class is a basic game. This class will load data, create a pyscroll group, a hero object. It also reads input and moves the Hero around the map. Finally, it uses a pyscroll group to render the map and Hero. """ filename = get_map(MAP_FILENAME) def __init__(self, state): if state == False: screenMode = pygame.RESIZABLE # true while running. self.running = False self.clock = pygame.time.Clock() self.direction = "still" self.fps = 180 self.counter = 1 self.counter2 = 1 heroPos1 = False # load data from pytmx tmx_data = load_pygame(self.filename) mapPlay = load_pygame(get_map(stats['map'])) # create new data source for pyscroll map_data = pyscroll.data.TiledMapData(mapPlay) # setup level geometry with simple pygame rects, loaded from pytmx. self.walls = list() for object in mapPlay.objects: self.walls.append(pygame.Rect( object.x, object.y, object.width, object.height)) # create new renderer (camera) self.map_layer = pyscroll.BufferedRenderer(map_data, screen.get_size()) self.map_layer.zoom = 2 self.group = PyscrollGroup(map_layer=self.map_layer, default_layer=4) self.hero = Hero('Tiles/character/character_still.png') self.hero.position = stats['pos'] # add our hero to the group self.group.add(self.hero) def map_change(self, map): mapfile = get_map(map) tmx_data = load_pygame(mapfile) print(tmx_data) map_data = pyscroll.data.TiledMapData(tmx_data) self.walls = list() for object in tmx_data.objects: self.walls.append(pygame.Rect( object.x, object.y, object.width, object.height)) self.map_layer = pyscroll.BufferedRenderer(map_data, screen.get_size()) self.map_layer.zoom = 2 self.group = PyscrollGroup(map_layer=self.map_layer, default_layer=4) self.hero = Hero('Tiles/character/character_still.png') self.hero.position = self.map_layer.map_rect.center def switcher(self): if len(doorX) == len(doorY) == len(targetPosX) == len(targetPosY) == len(currentMap) == len(targetMap) == len(animationDirection) == len(targetMapFile): for i in range(len(doorX)): if self.map == currentMap[i]: if self.hero.position[0] - 15 <= doorX[i] <= self.hero.position[0] + 15: print("OK!") if self.hero.position[1] - 15 <= doorY[i] <= self.hero.position[1] + 15: self.map_change(targetMapFile[i]) self.map = targetMap[i] stats['map'] = targetMapFile[i] heroPos = (targetPosX[i], targetPosY[i]) self.animation(animationDirection[i], 1) self.hero.position = heroPos print("Yeah!") break else: print("Nope!") print(str(doorX[i]) +" " +str(self.hero.position[0])) print(str(doorY[i]) +" " +str(self.hero.position[1])) else: #print("Never!") pass else: print("Error: Invalid number of door entries.") ## elif self.map == "maze1": ## #HOUSE2 ## if self.hero.position[0] >= -20 and self.hero.position[0] <= 20 and self.hero.position[1] <= 20 and self.hero.position[1] >= -15: ## self.map_change(HOUSE1) ## stats['map'] = HOUSE1 ## self.map = "house1" ## heroPos = 206, 48 ## self.animation("down", 1) ## self.hero.position = heroPos ## self.group.remove(self) ## self.group.empty() ## self.group.add(self.hero) def draw(self, surface): self.group.center(self.hero.rect.center) # draw the map and all sprites self.group.draw(surface) def handle_input(self, keyset): """ Handle pygame input events """ poll = pygame.event.poll event = poll() while event: if event.type == QUIT: self.running = False pygame.quit() break elif event.type == KEYDOWN: if keyset == "game": if event.key == K_EQUALS: self.map_layer.zoom += .25 elif event.key == K_MINUS: value = self.map_layer.zoom - .25 if value > 0: self.map_layer.zoom = value elif event.key == K_KP0: self.switcher() pass elif event.key == K_e: self.menu = "inventory" print("Inventory") pass if event.key == K_ESCAPE: pickle.dump(stats, open(os.path.join("data", "saves", "save.dat"), "wb")) pickle.dump(inventory, open(os.path.join("data", "saves", "inventory.dat"), "wb")) self.running = False pygame.quit() print(" ") sleep(0.5) print("Shutdown... Complete") sys.exit() break if keyset == "inventory": if event.key == K_ESCAPE: self.menu = "game" print("Game") pass if event.key == K_r: self.genchests() elif event.key == K_KP1: self.menu = "game" print("Game") pass elif event.key == K_KP2: self.map_change(FOREST) self.map = "forest" elif event.key == K_KP3: self.menu = "inventory" print("Inventory") pass elif event.key == K_KP4: pass elif event.key == K_KP5: pass elif event.key == K_KP6: print("X :" +str(self.hero.position[0]) +", Y: " +str(self.hero.position[1])) pass elif event.key == K_KP7: print(str(pygame.mouse.get_pos())) pass elif event.key == K_KP8: sleep(0.5) elif event.key == K_KP9: self.genchests() pass elif event.key == K_F11: pygame.display.toggle_fullscreen() elif event.type == VIDEORESIZE: self.map_layer.set_size((event.w, event.h)) dispHeight = event.h dispWidth = event.w event = poll() # using get_pressed is slightly less accurate than testing for events # but is much easier to use. if keyset == "game": pressed = pygame.key.get_pressed() if pressed[K_UP]: self.hero.velocity[1] = -HERO_MOVE_SPEED self.direction = "up" self.direction2 = "up" elif pressed[K_DOWN]: self.hero.velocity[1] = HERO_MOVE_SPEED self.direction = "down" self.direction2 = "down" elif pressed[K_w]: self.hero.velocity[1] = -HERO_SPRINT_SPEED self.direction = "up" self.direction2 = "up" elif pressed[K_s]: self.hero.velocity[1] = HERO_SPRINT_SPEED self.direction = "down" self.direction2 = "down" else: self.hero.velocity[1] = 0 self.direction2 = "still" if pressed[K_LEFT]: self.hero.velocity[0] = -HERO_MOVE_SPEED self.direction = "left" self.direction2 = "left" elif pressed[K_RIGHT]: self.hero.velocity[0] = HERO_MOVE_SPEED self.direction = "right" self.direction2 = "right" elif pressed[K_a]: self.hero.velocity[0] = -HERO_SPRINT_SPEED self.direction = "left" self.direction2 = "left" elif pressed[K_d]: self.hero.velocity[0] = HERO_SPRINT_SPEED self.direction = "right" self.direction2 = "right" else: self.hero.velocity[0] = 0 self.direction1 = "still" if self.direction1 == "still" and self.direction2 == "still": self.direction = "still" def update(self, dt): """ Tasks that occur over time should be handled here """ self.group.update(dt) # check if the sprite's feet are colliding with wall # sprite must have a rect called feet, and move_back method, # otherwise this will fail for sprite in self.group.sprites(): if sprite.feet.collidelist(self.walls) > -1: sprite.move_back(dt) def animation(self, direction, number): self.counter += 1 if self.direction1 == "still" and self.direction2 == "still": if self.direction == "left": self.hero = Hero('Tiles/character/walking_left/walking_left1.png') if self.direction == "right": self.hero = Hero('Tiles/character/walking_right/walking_right1.png') if self.direction == "up": self.hero = Hero('Tiles/character/walking_up/walking_up1.png') if self.direction == "down": self.hero = Hero('Tiles/character/walking_down/walking_down1.png') else: self.hero = Hero('Tiles/character/walking_' +direction +'/walking_' +direction +str(number) +'.png') self.group.remove(self) self.group.empty() self.group.add(self.hero) def genchests(self): itm1, itm2, itm3, itm4, itm5, itm6 = "0", "0", "0", "0", "0", "0" numberItems = random.randint(1, 6) for i in range(0, numberItems): item = random.randint(1, 5) if i == 1: itm1 = item if i == 2: itm2 = item if i == 3: itm3 = item if i == 4: itm4 = item if i == 5: itm5 = item if i == 6: itm6 = item print("Found Chest With "+str(numberItems) +" Items: " +str(itm1) +" " +str(itm2) +" " +str(itm3) +" " +str(itm4) +" " +str(itm5) +" " +str(itm6) +" ") if 1 in(itm1, itm2, itm3, itm4, itm5, itm6): inventory['sword'] = True else: inventory['sword'] = False if 2 in(itm1, itm2, itm3, itm4, itm5, itm6): inventory['axe'] = True else: inventory['axe'] = False if 3 in(itm1, itm2, itm3, itm4, itm5, itm6): inventory['shovel'] = True else: inventory['shovel'] = False if 4 in(itm1, itm2, itm3, itm4, itm5, itm6): inventory['bow'] = True else: inventory['bow'] = False def run(self): screenMode = pygame.RESIZABLE self.map = stats['map'][:-4].lower() self.map = self.map.lstrip("maps/") oldPlay = stats['playTime'] clock = pygame.time.Clock() self.running = True debug = True dispWidth, dispHeight = 1024, 768 self.menu = "game" game_time = pygame.time.get_ticks() playTime = font.render("Timer: ", False, pygame.Color('white')) minutes = 0 try: while self.running: dt = (clock.tick() / 500) clock.tick(self.fps) if self.counter2 == 5: heroPos = self.hero.position self.animation(self.direction, self.counter) self.counter += 1 self.counter2 = 0 guiX = (dispWidth / 2) - 175 guiY = (dispHeight / 2) - 165 self.hero.position = heroPos self.counter2 += 1 if self.counter > 9: self.counter = 1 stats['pos'] = self.hero.position currentTime = systime() seconds = currentTime - gameStart + oldPlay dispWidth, dispHeight = pygame.display.get_surface().get_size() stats['playTime'] = seconds self.group.remove(self) self.group.add(self.hero) if debug == True: location = font.render("Position: " + str(round(round(self.hero.position[0], -1) / 10)) + ", " + str(round(round(self.hero.position[1], -1) / 10)), False, pygame.Color('white')) fps = font.render("FPS:" + str(int(clock.get_fps())), False, pygame.Color('white')) mapdebug = font.render("Map Name: " + str(self.map), False, pygame.Color('white')) minutes = seconds // 60 secondsDisp = seconds % 60 if minutes < 1: minutes = 0 if secondsDisp == 60: secondsDisp = 0 minutes += 1 playTime = font.render("Timer: " + str(floor(minutes)) + " : " + str(round(secondsDisp)), True, pygame.Color('white')) screen.blit(playTime, (50,100)) screen.blit(fps, (50, 50)) screen.blit(location, (50,75)) screen.blit(mapdebug, (50, 125)) if self.menu == "inventory": screen.blit(load_image(os.path.join("Images", "transparent.png")),( 0, 0)) screen.blit(load_image(os.path.join("Images", "inventory.png")),(guiX, guiY)) if inventory["sword"] == True: screen.blit(load_image(os.path.join("Images", "sword.png")),( guiX + 16, guiY + 168)) if inventory["axe"] == True: screen.blit(load_image(os.path.join("Images", "axe.png")),( guiX + 52, guiY + 168)) if inventory["bow"] == True: screen.blit(load_image(os.path.join("Images", "bow.png")),( guiX + 88, guiY + 168)) if inventory["shovel"] == True: screen.blit(load_image(os.path.join("Images", "shovel.png")),( guiX + 124, guiY + 168)) pygame.display.update() self.handle_input(self.menu) self.update(dt) self.draw(screen) except KeyboardInterrupt: self.running = False pygame.quit()
class QuestGame(object): """ This class is a basic game. This class will load data, create a pyscroll group, a hero object. It also reads input and moves the Hero around the map. Finally, it uses a pyscroll group to render the map and Hero. """ filename = get_map(MAP_FILENAME) counter = 1 counter2 = 1 def __init__(self, state): if state == False: self.fullscreen = False # true while running. self.running = False self.clock = pygame.time.Clock() # create all the directio variables self.direction = "still" self.EntityDirection = "still" self.EntityDirection1, self.EntityDirection2 = "still", "still" self.fps = 1000 self.bypass = False entityPos1, heroPos1 = False, False # load data from pytmx tmx_data = load_pygame(self.filename) self.tmx_data = tmx_data mapPlay = load_pygame(get_map(stats['map'])) # create new data source for pyscroll map_data = pyscroll.data.TiledMapData(mapPlay) # setup level geometry with simple pygame rects, loaded from pytmx. self.walls = list() for object in mapPlay.objects: self.walls.append( pygame.Rect(object.x, object.y, object.width, object.height)) # create new renderer (camera) self.map_layer = pyscroll.BufferedRenderer(map_data, screen.get_size()) self.map_layer.zoom = 2 self.group = PyscrollGroup(map_layer=self.map_layer, default_layer=4) self.hero = Hero('Tiles/hero/character_still.png') self.entity = Entity('Tiles/hero/character_still.png') self.hero.position = stats['pos'] self.entity.position = stats['pos'] # add our hero to the group self.group.add(self.hero) #self.group.add(self.entity) self.entVel = (0, 0) def deep_thought(self): # The 'AI' function, needs work if self.counter2 % 75 == 0 or self.bypass == True: self.bypass = False if random.randint(0, 1) == 1: self.entity.velocity[0], self.entity.velocity[1] = 0, 0 movement = random.choice([ "self.entity.velocity[0] = -45; self.EntityDirection = 'left'; self.EntityDirection2 = 'left'", "self.entity.velocity[0] = 45; self.EntityDirection = 'right'; self.EntityDirection2 = 'right'", "self.entity.velocity[1] = -45; self.EntityDirection = 'up'; self.EntityDirection1 = 'up'", "self.entity.velocity[1] = 45; self.EntityDirection = 'down'; self.EntityDirection1 = 'down'" ]) exec(movement) def EntityAnimation(self, direction, number, character="hero"): self.entVel = self.entity.velocity self.counter += 1 if self.EntityDirection1 == "still" and self.EntityDirection2 == "still": if self.EntityDirection == "left": self.entity = Entity('Tiles/' + character + '/walking_left/walking_left1.png') if self.EntityDirection == "right": self.entity = Entity('Tiles/' + character + '/walking_right/walking_right1.png') if self.EntityDirection == "up": self.entity = Entity('Tiles/' + character + '/walking_up/walking_up1.png') if self.EntityDirection == "down": self.entity = Entity('Tiles/' + character + '/walking_down/walking_down1.png') else: self.entity = Entity('Tiles/' + character + '/walking_' + direction + '/walking_' + direction + str(number) + '.png') self.entity.velocity = self.entVel def EntMoveBack(self): #self.deep_thought(self, True) # Comment this to disable the 'AI' pass def map_change(self, map, target=False): # Does what it says on the tin mapfile = get_map(map) tmx_data = load_pygame(mapfile) self.tmx_data = tmx_data map_data = pyscroll.data.TiledMapData(tmx_data) self.walls = list() for object in tmx_data.objects: self.walls.append( pygame.Rect(object.x, object.y, object.width, object.height)) # creates new 'camera' self.map_layer = pyscroll.BufferedRenderer(map_data, screen.get_size()) self.map_layer.zoom = 2 self.group = PyscrollGroup(map_layer=self.map_layer, default_layer=4) #creates a new Hero to go on our new camera self.hero = Hero('Tiles/hero/character_still.png') try: self.hero.position = (target) except TypeError: self.hero.position = self.map_layer.map_rect.center self.map = stats['map'][:-4].lower() self.map = self.map.lstrip( "m") # Fix that stupid bug that changes "maze1" to "ze1" self.map = self.map.lstrip("aps/") def switcher( self ): # Bunch of IF statements to decide if we're at a door or not, then changes the map. if len(objectX) == len(objectY) == len(targetPosX) == len(targetPosY) == len(currentMap) == \ len(targetMap) == len(animationDirection) == len(targetMapFile) == len(objectType): heroPos = [0, 0] heroPos[0], heroPos[1] = self.hero.position[0], self.hero.position[ 1] for i in range(len(objectX)): if self.map == currentMap[i]: if self.hero.position[0] - 15 <= int( objectX[i]) <= self.hero.position[0] + 15: if self.hero.position[1] - 15 <= int( objectY[i]) <= self.hero.position[1] + 15: if objectType[i] == "door": used[i] = True self.map_change(targetMapFile[i]) self.map = targetMap[i] stats['map'] = targetMapFile[i] heroPos = (int(targetPosX[i]), int(targetPosY[i])) self.animation(animationDirection[i], 1) self.hero.position = heroPos return False elif objectType[i] == "chest": keyset, self.menu = "chest", "chest" if used[i] == False: if chestContents[i] == None and used[ i] == False: used[i] = True pickle.dump( used, open( os.path.join( "data", "saves", "used.dat"), "wb")) chestContents[i] = self.genchests() pickle.dump( chestContents, open( os.path.join( "data", "saves", "chestContents.dat"), "wb")) self.chestNo = i return False def generate_surrounding_maps(self): heroPos = [0, 0] heroPos = self.hero.position if int(self.hero.position[0]) in range((self.tmx_data.width * 32) - 64, (self.tmx_data.width * 32)): target = (32, heroPos[1]) self.grid[0] = self.grid[0] + 1 try: self.map_change( str(self.grid[0] + 1) + ", " + str(self.grid[1]) + ".tmx", target) self.map = str(self.grid).lstrip("[").rstrip("]") stats['map'] = self.map + ".tmx" self.animation("right", 1) target = (32, heroPos[1]) #self.hero.position = target except FileNotFoundError: self.generate_new_map(4, 16, 2, self.grid, target) elif int(self.hero.position[1]) in range( (self.tmx_data.height * 32) - 64, self.tmx_data.width * 32): target = (heroPos[0], 32) self.grid[1] = self.grid[1] + 1 try: self.map_change( str(self.grid[0]) + ", " + str(self.grid[1] + 1) + ".tmx", target) self.map = str(self.grid).lstrip("[").rstrip("]") stats['map'] = self.map + ".tmx" heroPos[0], heroPos[1] = self.hero.position[ 0], self.hero.position[1] self.animation("up", 1) except FileNotFoundError: self.generate_new_map(4, 16, 2, self.grid, target) elif int(self.hero.position[0]) in range(0, 64): target = (self.tmx_data.width * 32 - 32, heroPos[1]) self.grid[0] = self.grid[0] - 1 try: self.map_change( str(self.grid[0] - 1) + ", " + str(self.grid[1]) + ".tmx", target) self.map = str(self.grid).lstrip("[").rstrip("]") stats['map'] = self.map + ".tmx" heroPos[0], heroPos[1] = self.hero.position[ 0], self.hero.position[1] self.animation("left", 1) #self.hero.position = target except FileNotFoundError: self.generate_new_map(4, 16, 2, self.grid, target) elif int(self.hero.position[1]) in range(0, 64): target = (heroPos[0], self.tmx_data.height * 32 - 32) self.grid[1] = self.grid[1] - 1 try: self.map_change( str(self.grid[0]) + ", " + str(self.grid[1] - 1) + ".tmx", target) self.map = str(self.grid).lstrip("[").rstrip("]") stats['map'] = self.map + ".tmx" heroPos[0], heroPos[1] = self.hero.position[ 0], self.hero.position[1] self.animation("down", 1) #self.hero.position = target except FileNotFoundError: self.generate_new_map(4, 16, 2, self.grid, target) else: pass def generate_new_map(self, octaves, freq, area, target, position): command = "{}/lib/generate/__init__.py".format(os.getcwd()) if sys.platform.startswith('win32'): executeable = ("Python35\python.exe") elif sys.platform.startswith('linux'): executeable = ("python3.5") for y in range(self.grid[1] + eval("-" + str(area)), self.grid[1] + area): for x in range(self.grid[0] + eval("-" + str(area)), self.grid[0] + area): if os.path.isfile("data/maps/" + str(x) + ", " + str(y) + ".tmx"): pass else: p = subprocess.Popen([ executeable, command, ("data/maps/" + str(x) + ", " + str(y) + ".tmx"), str(octaves), str(freq), str(x), str(y) ], close_fds=True) try: if p is not None: disp_width, disp_height = pygame.display.get_surface( ).get_size() #self.blit_inventory("speach", "Generating Map... Please Wait...") self.speach(disp_width, disp_height, "Generating Map... Please Wait...") pygame.display.update() p.wait() self.map_change( (str(target[0]) + ", " + str(target[1]) + ".tmx"), position) self.map = str(self.grid).lstrip("[").rstrip("]") stats['map'] = self.map + ".tmx" except UnboundLocalError: pass def draw(self, surface): self.group.center(self.hero.rect.center) # draw the map and all sprites self.group.draw(surface) def speach(self, dispWidth, dispHeight, text): ## text = "Laudem bonorum salutandi pri te, tollit melius delicata mel cu,\ ## eu mea ullum legimus. Probo debitis te vel. Labores vulputate \ ## argumentum sea id. Cibo vitae vocent eos no, ne odio molestiae\ ## duo." screen.blit( pygame.transform.scale( load_image(os.path.join("images", "gui", "speach.png")), (dispWidth, 150)), (0, dispHeight - 150)) text = textwrap.wrap(text, width=95) for i, line in enumerate(text): text_blit = pixel_font.render(line, False, pygame.Color('white')) screen.blit(text_blit, (60, dispHeight - 110 + 25 * i)) def map_generate(self, output, octaves, freq, x, y): command = "{}/lib/generate/__init__.py".format(os.getcwd()) if sys.platform.startswith('win32'): executeable = ("Python35\python.exe") elif sys.platform.startswith('linux'): executeable = ("python3.5") subprocess.Popen([ executeable, command, output, str(octaves), str(freq), str(x), str(y) ], close_fds=True) def handle_input(self, keyset): """ Handle pygame input events """ poll = pygame.event.poll event = poll() while event: if event.type == QUIT: self.running = False pygame.quit() break elif event.type == KEYDOWN: if keyset == "game": if event.key == K_EQUALS: self.map_layer.zoom += .25 elif event.key == K_MINUS: value = self.map_layer.zoom - .25 if value > 0: self.map_layer.zoom = value else: self.map_layer.zoom = 0.1 elif event.key == K_KP0: try: if self.switcher() == True: self.generate_surrounding_maps() except FileNotFoundError: print("Exception Caught") pass elif event.key == K_e: self.menu = "inventory" pass if event.key == K_ESCAPE: for i in attack_stats_types: stats[i] = attack_stats[i] pickle.dump( stats, open(os.path.join("data", "saves", "save.dat"), "wb")) pickle.dump( inventory, open( os.path.join("data", "saves", "inventory.dat"), "wb")) self.running = False pygame.quit() print(" ") sleep(0.5) print("Shutdown... Complete") sys.exit() break if keyset != "game": if event.key == K_ESCAPE: self.menu = "game" pass if keyset == "inventory": if event.key == K_r: self.genchests() if keyset == "chest": if event.key == K_r: chestContents[self.chestNo] = self.genchests() if event.key == K_t: if taken[self.chestNo] != True: self.takeChest() taken[self.chestNo] = True pickle.dump( taken, open( os.path.join("data", "saves", "taken.dat"), "wb")) if keyset == "attack": pass #Basically just debug keys if event.key == K_KP1: self.menu = "game" pass elif event.key == K_KP2: self.map_change(FOREST) self.map = "forest" elif event.key == K_KP3: self.generate_new_map(4, 16, 3) pass elif event.key == K_KP4: self.map_generate( str(self.grid[0]) + ", " + str(self.grid[1]) + ".tmx", 4, 16.0, self.grid[0], self.grid[1]) pass elif event.key == K_KP5: self.enemy_stats = self.gen_enemy(attack_stats, enemy_stats) self.menu = "attack" pass elif event.key == K_KP6: print("X :" + str(int(self.hero.position[0])) + ", Y: " + str(int(self.hero.position[1])) + ", Map: " + self.map) pass elif event.key == K_KP7: print(str(pygame.mouse.get_pos())) pass elif event.key == K_KP8: sleep(0.5) elif event.key == K_KP9: editor = db_interface.Editor() conn = sqlite3.connect('data/saves/data.db') c = conn.cursor() for var in vars: exec("del " + var + "[:]") for data in c.execute( "SELECT {} FROM csv".format(var)): data = str(data[0]) exec("{}.append(\"{}\")".format(var, data)) pass elif event.key == K_F11: for m in screeninfo.get_monitors(): displ = str(m) w, h, mx, c = displ.split(", ") if self.fullscreen: self.fullscreen = False screen = init_screen( 1024, 700, pygame.HWSURFACE | pygame.FULLSCREEN) else: self.fullscreen = True screen = init_screen( w, h, pygame.HWSURFACE | pygame.RESIZABLE) pygame.display.toggle_fullscreen() elif event.type == VIDEORESIZE: self.map_layer.set_size((event.w, event.h)) dispHeight = event.h dispWidth = event.w event = poll() # using get_pressed is slightly less accurate than testing for events # but is much easier to use. if keyset == "game": pressed = pygame.key.get_pressed() if pressed[K_UP]: self.hero.velocity[1] = -HERO_MOVE_SPEED self.direction = "up" self.direction2 = "up" elif pressed[K_DOWN]: self.hero.velocity[1] = HERO_MOVE_SPEED self.direction = "down" self.direction2 = "down" elif pressed[K_w]: self.hero.velocity[1] = -HERO_SPRINT_SPEED self.direction = "up" self.direction2 = "up" elif pressed[K_s]: self.hero.velocity[1] = HERO_SPRINT_SPEED self.direction = "down" self.direction2 = "down" else: self.hero.velocity[1] = 0 self.direction2 = "still" if pressed[K_LEFT]: self.hero.velocity[0] = -HERO_MOVE_SPEED self.direction = "left" self.direction1 = "left" elif pressed[K_RIGHT]: self.hero.velocity[0] = HERO_MOVE_SPEED self.direction = "right" self.direction1 = "right" elif pressed[K_a]: self.hero.velocity[0] = -HERO_SPRINT_SPEED self.direction = "left" self.direction1 = "left" elif pressed[K_d]: self.hero.velocity[0] = HERO_SPRINT_SPEED self.direction = "right" self.direction1 = "right" else: self.hero.velocity[0] = 0 self.direction1 = "still" if self.direction1 == "still" and self.direction2 == "still": self.direction = "still" def update(self, dt): """ Tasks that occur over time should be handled here """ self.group.update(dt) # check if the sprite's feet are colliding with wall # sprite must have a rect called feet, and move_back method, # otherwise this will fail for sprite in self.group.sprites(): if sprite.feet.collidelist(self.walls) > -1: sprite.move_back(dt) def animation(self, direction, number): if self.direction1 == "still" and self.direction2 == "still": if self.direction == "left": self.hero = Hero('Tiles/hero/walking_left/walking_left1.png') if self.direction == "right": self.hero = Hero('Tiles/hero/walking_right/walking_right1.png') if self.direction == "up": self.hero = Hero('Tileshero/walking_up/walking_up1.png') if self.direction == "down": self.hero = Hero('Tiles/hero/walking_down/walking_down1.png') else: self.hero = Hero('Tiles/hero/walking_' + direction + '/walking_' + direction + str(number) + '.png') def genchests(self): wr = WeightedRandomizer(itemsProbability) self.taken = False chest.clear() numItems = random.randint(1, random.randint(2, 4)) if random.randint(0, 3) < 1: numItems += 1 elif random.randint(0, 9) < 2: numItems += 2 elif random.randint(0, 18) < 2: numItems += 5 for i in range(0, numItems): item = wr.random() while item in chest: item = wr.random() chest.append(item) return chest def gen_enemy(self, player_stats, enemy_stat): stats = attack_stats_types stat = player_stats for i in range(len(player_stats)): j = stats[i] try: enemy_stat[ stats[i]] = int((stat[j] - (stat[j] * 0.2)) + random.randint(0, int(stat[j] * 0.4))) except TypeError: enemy_stat[j] = choice(attack_types) return enemy_stat pass def player_attack(): type = None while type not in attack_types: type = input("[ QUESTION ] Enter attack type. ") if type not in attack_types: print( "[ ERROR ] Attack type {} not found. Must be {}".format( type, attack_types)) else: break return type pass def attack(self, attacker_stats, defender_stats, player_attack_type): fraction = attacker_stats['strength'] / defender_stats['blocking'] print("[ INFO ] Defender attack type: {}".format( defender_stats['attack'])) if player_attack_type != defender_stats['attack']: if fraction > (0.8 + (randint(0, 40) / 100)): attacker_stats['health'] -= int(fraction * 10) pass # Attacker Win else: defender_stats['health'] -= int(fraction * 10) pass # Attacker Loss elif player_attack_type == attacker_stats[ 'attack']: # Better odds here if fraction > (0.9 + (randint(0, 40) / 100)): attacker_stats['health'] -= int(fraction * 10) pass # Attacker Win else: defender_stats['health'] -= int(fraction * 10) pass # Attacker Loss else: if fraction > (0.70 + (randint(0, 40) / 100)): # Odds are worse here attacker_stats['health'] -= int(fraction * 10) pass # Attacker Win else: defender_stats['health'] -= int(fraction * 10) pass # Attacker Loss print("[ INFO ] Attacker: {} Defender: {}".format( attacker_stats['health'], defender_stats['health'])) print("[ INFO ] Health to be lost: {}".format(int(fraction * 10))) return attacker_stats, defender_stats def blit_inventory(self, screenMode, speach=None): if screenMode != "game": xCounter, counter, OverCounter = 0, 0, 0 dispWidth, dispHeight = pygame.display.get_surface().get_size() guiX = (dispWidth / 2) - 175 guiY = (dispHeight / 2) - 165 screen.blit( load_image(os.path.join("images", "gui", "transparent.png")), (0, 0)) screen.blit( load_image(os.path.join("images", "gui", screenMode + ".png")), (guiX, guiY)) if screenMode == "inventory" or screenMode == "chest": dt = (clock.tick() / 500) clock.tick(self.fps) if len(inventory) > 0: for i in range(0, len(inventory)): OverCounter += 1 if xCounter >= 9: counter += 1 xCounter = 0 screen.blit(load_image(os.path.join("images", "items",\ str(items[inventory[i]])+".png")), (guiX + 16 + 36*xCounter, guiY + 168 + 36*counter)) xCounter += 1 if screenMode == "chest" and chestContents[self.chestNo] != None: itemNo = 0 for i in range(0, len(chestContents[self.chestNo])): screen.blit(load_image(os.path.join("images", "items",\ items[str(chestContents[self.chestNo][i])]\ +".png")), (guiX + 123 + 36*itemNo,\ guiY + 34 + int(35 * (i/3)) - int(35 * (i/3)) % 35)) if itemNo < 2: itemNo += 1 else: itemNo = 0 if screenMode == "speach": self.speach(dispWidth, dispHeight, speach) if screenMode == "attack": picture = load_image( os.path.join("Tiles", "hero", "walking_down", "walking_down1.png")) picture = pygame.transform.scale(picture, (100, 100)) rect = picture.get_rect() rect = rect.move((guiX + 50, guiY + 28)) screen.blit(picture, rect) text = font.render("Player : Enemy", True, pygame.Color('black')) screen.blit(text, (guiX + 172, guiY + 45)) text = "Health: " + str( attack_stats['health']) + " Skill: " + str( attack_stats['skill']) + " Attack: " + str( attack_stats['attack']) text_render = pixel_font.render(text, False, pygame.Color('gray27')) screen.blit(text_render, (guiX + 20, guiY + 290)) for i, attack in enumerate(attack_types): text = load_font(30, "data/PixelFont.ttf").render( attack, False, pygame.Color('black')) screen.blit(text, (guiX + 172, guiY + 25 + 28 * (i + 2))) # if pygame.mouse.get_pressed()[0] == 1: #print(pygame.mouse.get_pos()) mouse_pos = pygame.mouse.get_pos() if guiX + 160 < mouse_pos[0] and guiX + 330 > mouse_pos[0]: for i, attack in enumerate(attack_types): if guiY + 25 + 28 * (i + 2) < mouse_pos[1] and ( guiY + 25 + 28 * (i + 2)) + 28 > mouse_pos[1]: print(attack) self.attack(attack_stats, enemy_stats, attack) else: pass pass def takeChest(self): if len(inventory) < 27: if chestContents[self.chestNo] != None: for i in range(0, (len(chestContents[self.chestNo]))): #print(i) inventory.append(chestContents[self.chestNo][i]) chestContents[self.chestNo][:] = [] pickle.dump( chestContents, open(os.path.join("data", "saves", "chestContents.dat"), "wb")) def run(self): screenMode = pygame.RESIZABLE oldPlay = stats['playTime'] clock = pygame.time.Clock() self.running = True self.grid = [0, 0] debug = True dispWidth, dispHeight = 1024, 768 self.menu = "game" game_time = pygame.time.get_ticks() playTime = font.render("Timer: ", False, pygame.Color('white')) minutes = 0 self.map = stats['map'][:-4].lower() self.map = self.map.lstrip( "m") # Fix that stupid bug that changes "maze1" to "ze1" self.map = self.map.lstrip("aps/") try: while self.running: dt = (clock.tick() / 500) clock.tick(self.fps) if self.menu == "game": #self.deep_thought() if self.counter2 % 7 == 0: heroPos = self.hero.position self.animation(self.direction, self.counter) self.hero.position = heroPos #entityPos = self.entity.position #self.EntityAnimation(self.EntityDirection, self.counter, "princess") #self.entity.position = entityPos self.counter += 1 guiX = (dispWidth / 2) - 175 guiY = (dispHeight / 2) - 165 self.group.remove(self.hero) #self.group.remove(self.entity) self.group.empty() self.group.add(self.hero) #self.group.add(self.entity) self.counter2 += 1 if self.counter > 8: self.counter = 1 stats['pos'] = self.hero.position currentTime = systime() seconds = currentTime - gameStart + oldPlay dispWidth, dispHeight = pygame.display.get_surface().get_size() stats['playTime'] = seconds if debug == True and self.counter2 % 1 == 0: location = font.render( "Position: " + str(round(round(self.hero.position[0], -1) / 10)) + ", " + str(round(round(self.hero.position[1], -1) / 10)), False, pygame.Color('white')) mapdebug = font.render("Map Name: " + str(self.map), False, pygame.Color('white')) minutes = seconds // 60 secondsDisp = seconds % 60 if minutes < 1: minutes = 0 if secondsDisp == 60: secondsDisp = 0 minutes += 1 fps = font.render("FPS:" + str(int(clock.get_fps())), False, pygame.Color('white')) screen.blit(fps, (50, 50)) screen.blit(playTime, (50, 100)) screen.blit(location, (50, 75)) screen.blit(mapdebug, (50, 125)) playTime = font.render( "Timer: " + str(floor(minutes)) + " : " + str(round(secondsDisp)), True, pygame.Color('white')) screen.blit(playTime, (50, 100)) self.blit_inventory(str(self.menu)) pygame.display.update() #pygame,display.flip() self.handle_input(self.menu) self.update(dt) self.draw(screen) except KeyboardInterrupt: self.running = False pygame.quit()
class QuestGame: """This class is a basic game. This class will load data, create a pyscroll group, a hero object. It also reads input and moves the Hero around the map. Finally, it uses a pyscroll group to render the map and Hero. """ map_path = RESOURCES_DIR / "grasslands.tmx" def __init__(self, screen: pygame.Surface) -> None: self.screen = screen # true while running self.running = False # load data from pytmx tmx_data = load_pygame(self.map_path) # setup level geometry with simple pygame rects, loaded from pytmx self.walls = [] for obj in tmx_data.objects: self.walls.append(pygame.Rect(obj.x, obj.y, obj.width, obj.height)) # create new data source for pyscroll map_data = pyscroll.data.TiledMapData(tmx_data) # create new renderer (camera) self.map_layer = pyscroll.BufferedRenderer( map_data, screen.get_size(), clamp_camera=False, tall_sprites=1 ) self.map_layer.zoom = 2 # pyscroll supports layered rendering. our map has 3 'under' layers # layers begin with 0, so the layers are 0, 1, and 2. # since we want the sprite to be on top of layer 1, we set the default # layer for sprites as 2 self.group = PyscrollGroup(map_layer=self.map_layer, default_layer=2) self.hero = Hero() # put the hero in the center of the map self.hero.position = self.map_layer.map_rect.center self.hero._position[0] += 200 self.hero._position[1] += 400 # add our hero to the group self.group.add(self.hero) def draw(self) -> None: # center the map/screen on our Hero self.group.center(self.hero.rect.center) # draw the map and all sprites self.group.draw(self.screen) def handle_input(self) -> None: """Handle pygame input events""" poll = pygame.event.poll event = poll() while event: if event.type == QUIT: self.running = False break elif event.type == KEYDOWN: if event.key == K_ESCAPE: self.running = False break elif event.key == K_EQUALS: self.map_layer.zoom += 0.25 elif event.key == K_MINUS: value = self.map_layer.zoom - 0.25 if value > 0: self.map_layer.zoom = value # this will be handled if the window is resized elif event.type == VIDEORESIZE: self.screen = init_screen(event.w, event.h) self.map_layer.set_size((event.w, event.h)) event = poll() # using get_pressed is slightly less accurate than testing for events # but is much easier to use. pressed = pygame.key.get_pressed() if pressed[K_UP]: self.hero.velocity[1] = -HERO_MOVE_SPEED elif pressed[K_DOWN]: self.hero.velocity[1] = HERO_MOVE_SPEED else: self.hero.velocity[1] = 0 if pressed[K_LEFT]: self.hero.velocity[0] = -HERO_MOVE_SPEED elif pressed[K_RIGHT]: self.hero.velocity[0] = HERO_MOVE_SPEED else: self.hero.velocity[0] = 0 def update(self, dt): """Tasks that occur over time should be handled here""" self.group.update(dt) # check if the sprite's feet are colliding with wall # sprite must have a rect called feet, and move_back method, # otherwise this will fail for sprite in self.group.sprites(): if sprite.feet.collidelist(self.walls) > -1: sprite.move_back(dt) def run(self): """Run the game loop""" clock = pygame.time.Clock() self.running = True from collections import deque times = deque(maxlen=30) try: while self.running: dt = clock.tick() / 1000.0 times.append(clock.get_fps()) self.handle_input() self.update(dt) self.draw() pygame.display.flip() except KeyboardInterrupt: self.running = False
class game_scene(object): def __init__(self, manager, engine, map_name, entrance_name): self._manager = manager self.finished = False self._engine = engine # Load images for UI self._ui_spritesheet = spritesheet.spritesheet('ui.png') self._ui_images = self._ui_spritesheet.load_all( (0, 0, DEFAULT_SPRITE_WIDTH, DEFAULT_SPRITE_HEIGHT), ALPHA_COLOUR) # Load the map self.load_map(map_name, entrance_name, self._engine.screen.get_size()) def load_map(self, name, entrance_name, display_size): filename = get_map(name) # load data from pytmx tmx_data = load_pygame(filename) # create new data source for pyscroll map_data = pyscroll.data.TiledMapData(tmx_data) # create new renderer (camera) self.map_layer = pyscroll.BufferedRenderer(map_data, display_size, clamp_camera=True, tall_sprites=1) self.map_layer.zoom = 2 # pyscroll supports layered rendering. our map has 3 'under' layers # layers begin with 0, so the layers are 0, 1, and 2. # since we want the sprite to be on top of layer 1, we set the default # layer for sprites as 2 self.group = PyscrollGroup(map_layer=self.map_layer, default_layer=2) # put the hero in tile with name matching entrance_name player_start = tmx_data.get_object_by_name(entrance_name) self._engine.hero.position = [player_start.x, player_start.y] # add our hero to the group self.group.add(self._engine.hero) # setup level geometry with simple pygame rects, loaded from pytmx self.walls = list() self.npcs = list() self.enemies = list() self.triggers = list() temp_npcs = list() # Also a pathfinding grid self.pathfinding_grid = pathfinding.weighted_grid( tmx_data.width, tmx_data.height) for object in tmx_data.objects: if object.type == 'wall': self.walls.append( pygame.Rect(object.x, object.y, object.width, object.height)) # Add walls to the pathfinding grid grid_x = int(object.x / tmx_data.tilewidth) grid_y = int(object.y / tmx_data.tileheight) grid_width = int(object.width / tmx_data.tilewidth) grid_height = int(object.height / tmx_data.tileheight) for y in range(0, grid_height): for x in range(0, grid_width): self.pathfinding_grid.walls.append( (grid_x + x, grid_y + y)) elif object.type == 'npc' or object.type == 'enemy': # Process NPCs and enemies after walls are determined temp_npcs.append(object) elif object.type == 'trigger': self.triggers.append( trigger.trigger(object.x, object.y, object.width, object.height, object.properties)) # Process NPCs and enemies for object in temp_npcs: target_grid_x = int(object.target_x) target_grid_y = int(object.target_y) target_x = target_grid_x * tmx_data.tilewidth target_y = target_grid_y * tmx_data.tileheight origin_grid_x = int(object.x / tmx_data.tilewidth) origin_grid_y = int(object.y / tmx_data.tileheight) # Pathfinding came_from, cost_so_far = pathfinding.a_star_search( self.pathfinding_grid, (origin_grid_x, origin_grid_y), (target_grid_x, target_grid_y)) path = pathfinding.reconstruct_path(came_from, (origin_grid_x, origin_grid_y), (target_grid_x, target_grid_y)) path = [(t[0] * tmx_data.tilewidth, t[1] * tmx_data.tileheight) for t in path] # Load sprite from JSON if object.type == 'npc': npc = character.npc(object.name, path) self.npcs.append(npc) self.group.add(npc) elif object.type == 'enemy': enemy = character.enemy(object.name, path) self.enemies.append(enemy) self.group.add(enemy) # Play background music if 'background_music' in tmx_data.properties: self._engine.play_music(tmx_data.properties['background_music']) # Initialise map self.update(0) def display_text(self, text): message_box = (0, 1 - DIALOG_HEIGHT, 1, DIALOG_HEIGHT) self._manager.append( text_scene.text_scene(self._manager, text, message_box)) def interaction(self): index = self._engine.hero.interaction_rect.collidelist(self.npcs) # NPC if index > -1: self.display_text(self.npcs[index].name + ': ' + self.npcs[index].dialogue) else: # Events, objects index = self._engine.hero.interaction_rect.collidelist( self.triggers) if index > -1: trigger = self.triggers[index] if not trigger.condition or eval(trigger.condition): if trigger.on_interact == 'message': self.display_text(trigger.message_text) elif trigger.on_interact == 'load_map': new_map = game_scene(self._manager, self._engine, trigger.map_name, trigger.entrance_name) fade = fade_transition.fade_transition( self._manager, FADE_TIME, FADE_COLOUR) self._manager.change(new_map, fade) elif trigger.on_interact == 'set': exec_string = 'self.' + trigger.variable_name \ + ' = ' + trigger.value exec(exec_string) self.display_text(trigger.message_text) else: self.display_text(trigger.error_text) def pause(self): pass def resume(self): pass def end(self): self.finished = True def draw_ui(self, surface): # Health full_count = int(self._engine.hero.health / 2) half_count = self._engine.hero.health % 2 empty_count = int( (self._engine.hero.max_health - self._engine.hero.health) / 2) for i in range(0, full_count): #x = surface.get_width() - ((i / 2 + 1) * self._ui_images[0].get_width()) x = i * self._ui_images[2].get_width() y = 0 surface.blit(self._ui_images[2], (x, y)) for i in range(0, half_count): x = (i + full_count) * self._ui_images[1].get_width() y = 0 surface.blit(self._ui_images[1], (x, y)) for i in range(0, empty_count): x = (i + full_count + half_count) * self._ui_images[0].get_width() y = 0 surface.blit(self._ui_images[0], (x, y)) def pause_menu(self): pause_menu = menu_scene.menu_scene(self._manager, PAUSE_MENU_IMAGE, PAUSE_MENU_RECT) pause_menu.append("Resume Game", True, pause_menu.end) pause_menu.append( "Quit", True, lambda: pygame.event.post(pygame.event.Event(pygame.QUIT))) self._manager.append(pause_menu) def game_over(self): self.end() message_box = (0, 1 - DIALOG_HEIGHT, 1, DIALOG_HEIGHT) self._manager.append( text_scene.text_scene(self._manager, ["GAME OVER", ":[ :[ :[ :["], message_box)) def _button_attack(self): self._engine.hero.attack() def handle_input(self, events, pressed_keys): for event in events: if event.type == R_INPUT_EVENT: if event.button == buttons.R_A: self.interaction() if event.button == buttons.R_B: self._button_attack() if event.button == buttons.R_START: self.pause_menu() # elif event.key == K_EQUALS: # self.map_layer.zoom += .25 # # elif event.key == K_MINUS: # value = self.map_layer.zoom - .25 # if value > 0: # self.map_layer.zoom = value # # # this will be handled if the window is resized # elif event.type == VIDEORESIZE: # scope.resize(event.w, event.h) # self.map_layer.set_size((event.w, event.h)) # # using get_pressed is slightly less accurate than testing for events # but is much easier to use. if pressed_keys[buttons.R_UP]: self._engine.hero.move_up() elif pressed_keys[buttons.R_DOWN]: self._engine.hero.move_down() else: self._engine.hero.stop_moving_vertical() if pressed_keys[buttons.R_LEFT]: self._engine.hero.move_left() elif pressed_keys[buttons.R_RIGHT]: self._engine.hero.move_right() else: self._engine.hero.stop_moving_horizontal() def update(self, dt): """ Tasks that occur over time should be handled here """ self.group.update(dt) # check if the sprite's feet are colliding with wall # sprite must have a rect called feet, and move_back method, # otherwise this will fail for sprite in self.group.sprites(): if sprite.feet.collidelist(self.walls) > -1: sprite.move_back(dt) # Check if NPCs are colliding with the hero for npc in self.npcs: if npc.feet.colliderect(self._engine.hero.feet): npc.move_back(dt) self._engine.hero.move_back(dt) for enemy in self.enemies: if enemy.alive and enemy.rect.colliderect( self._engine.hero.hitbox): enemy.take_damage( self._engine.hero.damage, calculate_knockback(self._engine.hero.position, enemy.position, self._engine.hero.weapon.knockback)) if enemy.dead: enemy.remove(self.group) elif enemy.alive and enemy.feet.colliderect( self._engine.hero.feet): enemy.move_back(dt) self._engine.hero.take_damage( enemy.damage, calculate_knockback(enemy.position, self._engine.hero.position, enemy.knockback)) enemy.threat_target = self._engine.hero.position # If the player is dead, game over if self._engine.hero.dead: self.game_over() def draw(self, surface): # center the map/screen on our Hero self.group.center(self._engine.hero.rect.center) # draw the map and all sprites self.group.draw(surface) # Draw user interface self.draw_ui(surface)
class QuestGame(object): """ This class is a basic game. This class will load resources, create a pyscroll group, a hero object. It also reads input and moves the Hero around the map. Finally, it uses a pyscroll group to render the map and Hero. """ def __init__(self): # true while running self.running = False # create new data source for pyscroll self.map_data = InfiniteMap() # create new renderer (camera) self.map_layer = pyscroll.BufferedRenderer(self.map_data, screen.get_size()) self.map_layer.zoom = 1 # pyscroll supports layered rendering. our map has 3 'under' layers # layers begin with 0, so the layers are 0, 1, and 2. # since we want the sprite to be on top of layer 1, we set the default # layer for sprites as 2 self.group = PyscrollGroup(map_layer=self.map_layer, default_layer=2) self.hero = Hero() self.hero.position = 518 * 32, 560 * 32 # add our hero to the group self.group.add(self.hero) def draw(self, surface): # center the map/screen on our Hero self.group.center(self.hero.rect.center) # draw the map and all sprites self.group.draw(surface) def handle_input(self): """ Handle pygame input events """ poll = pygame.event.poll event = poll() while event: if event.type == QUIT: self.running = False break elif event.type == KEYDOWN: if event.key == K_ESCAPE: self.running = False break elif event.key == K_r: self.map_data.reload() self.map_layer.redraw_tiles(self.map_layer._buffer) elif event.key == K_q: self.map_data.NOISE_SIZE -= .5 self.hero.position = self.hero.position[ 0] * .985, self.hero.position[1] * .985 self.map_data.reload() self.map_layer.redraw_tiles(self.map_layer._buffer) elif event.key == K_w: self.map_data.NOISE_SIZE += .5 self.map_data.reload() self.hero.position = self.hero.position[ 0] * 1.015, self.hero.position[1] * 1.015 self.map_layer.redraw_tiles(self.map_layer._buffer) elif event.key == K_EQUALS: self.map_layer.zoom += .25 elif event.key == K_MINUS: value = self.map_layer.zoom - .25 if value > 0: self.map_layer.zoom = value # this will be handled if the window is resized elif event.type == VIDEORESIZE: init_screen(event.w, event.h) self.map_layer.set_size((event.w, event.h)) event = poll() # using get_pressed is slightly less accurate than testing for events # but is much easier to use. pressed = pygame.key.get_pressed() if pressed[K_UP]: self.hero.velocity[1] = -HERO_MOVE_SPEED elif pressed[K_DOWN]: self.hero.velocity[1] = HERO_MOVE_SPEED else: self.hero.velocity[1] = 0 if pressed[K_LEFT]: self.hero.velocity[0] = -HERO_MOVE_SPEED elif pressed[K_RIGHT]: self.hero.velocity[0] = HERO_MOVE_SPEED else: self.hero.velocity[0] = 0 def update(self, dt): """ Tasks that occur over time should be handled here """ self.group.update(dt) def run(self): """ Run the game loop """ clock = pygame.time.Clock() self.running = True from collections import deque times = deque(maxlen=300) noise = SimplexNoise().noise2 two_pi = 2 * math.pi poll = 1 try: while self.running: dt = clock.tick_busy_loop(60) / 1000. self.handle_input() self.update(dt) begin = time() self.draw(screen) times.append(time() - begin) # if len(times) > 0: # print(len(times), round(sum(times) / len(times), 4)) # # poll -= dt # if poll < 0: # self.map_data._first_draw = True # self.map_data.reload() # self.map_layer.redraw_tiles(self.map_layer._buffer) # xx, yy = self.hero.position # # xx /= 1000 # yy /= 1000 # # for y in range(0, 320, 32): # for x in range(0, 320, 32): # v = (noise(xx + x / 1000, yy + y / 1000) + 1) * 128 # color = v, v, v # print(color) # screen.fill(color, (x, y, 32, 32)) pygame.display.flip() except KeyboardInterrupt: self.running = False
class QuestGame(object): """ This class is a basic game. This class will load data, create a pyscroll group, a hero object. It also reads input and moves the Hero around the map. Finally, it uses a pyscroll group to render the map and Hero. """ filename = get_map(MAP_FILENAME) def __init__(self): # true while running self.running = False # load data from pytmx tmx_data = load_pygame(self.filename) # setup level geometry with simple pygame rects, loaded from pytmx self.walls = list() for object in tmx_data.objects: self.walls.append(pygame.Rect( object.x, object.y, object.width, object.height)) # create new data source for pyscroll map_data = pyscroll.data.TiledMapData(tmx_data) # create new renderer (camera) self.map_layer = pyscroll.BufferedRenderer(map_data, screen.get_size()) self.map_layer.zoom = 2 # pyscroll supports layered rendering. our map has 3 'under' layers # layers begin with 0, so the layers are 0, 1, and 2. # since we want the sprite to be on top of layer 1, we set the default # layer for sprites as 2 self.group = PyscrollGroup(map_layer=self.map_layer, default_layer=2) self.hero = Hero() # put the hero in the center of the map self.hero.position = self.map_layer.map_rect.center # add our hero to the group self.group.add(self.hero) def draw(self, surface): # center the map/screen on our Hero self.group.center(self.hero.rect.center) # draw the map and all sprites self.group.draw(surface) def handle_input(self): """ Handle pygame input events """ poll = pygame.event.poll event = poll() while event: if event.type == QUIT: self.running = False break elif event.type == KEYDOWN: if event.key == K_ESCAPE: self.running = False break elif event.key == K_EQUALS: self.map_layer.zoom += .25 elif event.key == K_MINUS: value = self.map_layer.zoom - .25 if value > 0: self.map_layer.zoom = value # this will be handled if the window is resized elif event.type == VIDEORESIZE: init_screen(event.w, event.h) self.map_layer.set_size((event.w, event.h)) event = poll() # using get_pressed is slightly less accurate than testing for events # but is much easier to use. pressed = pygame.key.get_pressed() if pressed[K_UP]: self.hero.velocity[1] = -HERO_MOVE_SPEED elif pressed[K_DOWN]: self.hero.velocity[1] = HERO_MOVE_SPEED else: self.hero.velocity[1] = 0 if pressed[K_LEFT]: self.hero.velocity[0] = -HERO_MOVE_SPEED elif pressed[K_RIGHT]: self.hero.velocity[0] = HERO_MOVE_SPEED else: self.hero.velocity[0] = 0 def update(self, dt): """ Tasks that occur over time should be handled here """ self.group.update(dt) # check if the sprite's feet are colliding with wall # sprite must have a rect called feet, and move_back method, # otherwise this will fail for sprite in self.group.sprites(): if sprite.feet.collidelist(self.walls) > -1: sprite.move_back(dt) def run(self): """ Run the game loop """ clock = pygame.time.Clock() self.running = True try: while self.running: dt = clock.tick() / 1000. self.handle_input() self.update(dt) self.draw(screen) pygame.display.flip() except KeyboardInterrupt: self.running = False
class Level: """ Class that holds map, and any game object that should be rendered or updated """ def __init__(self, screen_size, logic_manager): self._logic_manager = logic_manager self.screen_size = screen_size self.tmx_data = None self.map_data = None self.map_layer = None self.group = None self.paths = [] self.base = None def load(self, filename): """ Loads map :param filename: :return: """ self.tmx_data = load_pygame(filename) self.map_data = TiledMapData(self.tmx_data) self.map_layer = BufferedRenderer(self.map_data, self.screen_size, alpha=True) self.group = PyscrollGroup(map_layer=self.map_layer) Camera.set_up(self.group, self.map_layer, self.screen_size) for obj in self.tmx_data.get_layer_by_name("paths"): self.paths.append(obj.points) for obstacle in self.obstacle_iterator(): obstacle.rect = Rect(obstacle.x, obstacle.y, obstacle.width, obstacle.height) for actor in self.tmx_data.get_layer_by_name("actors"): if actor.name == 'base': self.base = Base() self.base.position = Vector2(actor.x, actor.y) self.base.team = PLAYER_TEAM self.add(self.base) def add(self, obj): """ Add actor :param obj: :return: """ self.group.add(obj, layer=self.get_layer_index("actors")) self._logic_manager.on_object_added_to_scene(obj) def add_obstacle(self, obstacle): """ Add obstacle :param obstacle: :return: """ self.tmx_data.get_layer_by_name("obstacles").append(obstacle) def actor_iterator(self): """ Returns iterator that goe through actors :return: """ for o in self.group.sprites(): if isinstance(o, Actor): yield o def obstacle_iterator(self): """ Returns iterator that goes through obstacles :return: """ for obstacle in self.tmx_data.get_layer_by_name("obstacles"): yield obstacle def get_layer_index(self, layer_name): """ Returns index of layer by name :param layer_name: :return: """ for i, layer in enumerate(self.tmx_data.layers): if layer.name == layer_name: return i return -1 def is_rectangle_colliding(self, rectangle): """ Checks if rect is colliding with any obstacle :param rectangle: :return: """ for obstacle in self.obstacle_iterator(): if rectangle.colliderect(obstacle.rect): return True return False def get_actor_on_position(self, position, lambda_filter=None): """ Checks if given position collides with any actor and returns it :param position: :param lambda_filter: :return: """ if lambda_filter is not None: for actor in self.actor_iterator(): if actor.rect.collidepoint(position.x, position.y) and lambda_filter(actor): return actor else: for actor in self.actor_iterator(): if actor.rect.collidepoint(position.x, position.y): return actor return None def update(self, dt): """ Updates level :param dt: :return: """ self.group.update(dt) for obj in self.actor_iterator(): if obj.state != ActorState.DEATH: visible = pygame.sprite.spritecollide(obj, self.group.sprites(), False, is_visible) obj.actors_in_attack_range = visible for new_object in GameObject.objects_to_create: self.add(new_object) GameObject.objects_to_create.clear() def draw(self, surface): """ Draw level objects :param surface: :return: """ self.group.draw(surface)
class Game(object): """This class is essentially the Wizard of Oz""" def __init__(self, charactername='Zaxim', username='******', password='******', ip='127.0.0.1', current_room=None): # Client for issuing requests to server and receiving responses self.client = GameClient(charactername=charactername, username=username, password=password, ip=ip) # Remote sprite controller self.rsc = RemoteSpriteController(self) # Rate that chat polls are sent to server self.poll_frequency = POLL_RATE self.poll_timer = self.poll_frequency self.out_going_message = None # true while running self.running = False # load data from pytmx if not current_room: current_room = STARTING_ROOM tmx_data = load_pygame(current_room) self.map_data = tmx_data # create new data source for pyscroll map_data = pyscroll.data.TiledMapData(tmx_data) # create new renderer (camera) self.map_layer = pyscroll.BufferedRenderer(map_data, screen.get_size()) self.map_layer.zoom = MAP_ZOOM # pyscroll supports layered rendering. self.group = PyscrollGroup(map_layer=self.map_layer, default_layer=DEFAULT_LAYER) # GUI ELEMENTS # Create text box text_box_x, text_box_y = self.screen_coords((3, 95)) self.text_box = eztext.Input(maxlength=90, color=(255, 255, 255), x=text_box_x, y=text_box_y, font=pygame.font.Font(FONT, 22), prompt=': ') # Create InputLog self.inputlog = InputLog(coords=self.screen_coords((3, 88)), max_length=10, size=18, spacing=18, font=FONT) # Create Combatlog self.combatlog = InputLog(coords=(1050, 860), max_length=10, size=22, spacing=18, font=FONT) # Login to server: # Get room instance and player object id response = self.client.login() id = response['response']['id'] sprite = response['response']['sprite'] coords = response['response']['coords'] self.hero = Hero(game=self, id=id, sprite=sprite, coords=coords) # Player input module self.input = PlayerController(game=self) # This is late -- ??? TODO This is garbage, current room needs to be discovered way earlier from login() self.current_room = response['response']['current_room'] self.hero.position = STARTING_POSITION self.group.add(self.hero.remotesprite) self.rsc.initialize() @property def screen_size(self): return pygame.display.Info().current_w, pygame.display.Info().current_h @property def map_size(self): return self.map_data.width, self.map_data.height @property def charactername(self): return self.client.charactername def screen_coords(self, coords): """ :param coords: percentage of each axis. i.e. (50, 50) based on MAP position. :return: Actual co-ords per resolution """ screen_x, screen_y = self.screen_size new_x = (coords[0] / 100) * screen_x new_y = (coords[1] / 100) * screen_y return new_x, new_y def poll_server(self, dt=60): """ get remotesprite coordinate updates from server and pass to remotesprite controller """ self.poll_timer -= dt / 50. if self.poll_timer <= 0: self.poll_timer = self.poll_frequency # Interface with RemoteSpriteController and update all lifeform coords self.update_lifeforms() # Update target if hero has one self.hero.tgh.update_target() # Update our Hero's armor equipment_graphics = self.hero.remoteinventory.equipped_graphics() self.hero.remotesprite.visualequipment.update_sprites( equipment_graphics) # TODO: Update remote player's inventory graphics def update_lifeforms(self): """Update co-ordinates of all remote sprites with new information from server, also updates chat que and other important information from the server """ # Update data on all lifeforms in room r = self.client.send('get_roomdata') coords_dict = r['response']['coords'] if coords_dict: self.rsc.update_coords(coords_dict) # Update chat messages messages = r['response']['messages'] for message in messages: self.inputlog.add_line(string=message['message'], color=message['color']) # Update remotesprite visual equipment (for remote players) payloads = r['response']['payloads'] for payload in payloads: if payload['tag'] == 'visualequipment': playerid = payload['data']['playerid'] if playerid == self.hero.id: continue equip_data = payload['data']['visualequipment'] remotesprite = self.rsc.remotesprites[playerid] graphics = [item for item in equip_data] if not remotesprite.visualequipment: remotesprite.visualequipment = VisualEquipment( remotesprite=remotesprite, group=self.group) remotesprite.visualequipment.update_sprites(graphics) def update(self, dt): """ Tasks that occur over time should be handled here""" # self.hero.remotesprite.visualequipment.update() # update all sprites in game world self.group.update(dt) # update camera position (follows player) self.hero.camera.update(dt) # move player (including animation) if we're moving self.move(dt) # perform auto attack if we're autoattacking self.autoattack(dt) def move(self, dt): self.hero.move_timer -= dt / 100. if self.hero.moving: distance_x, distance_y = (self.hero.target_coords[0] - self.hero.x, self.hero.target_coords[1] - self.hero.y) stepx, stepy = (negpos(distance_x), negpos(distance_y)) self.hero.x += stepx self.hero.y += stepy if self.hero.move_timer <= 0: self.hero.moving = False self.hero.position = self.hero.target_coords r = self.client.send('update_coords', [self.hero.x, self.hero.y]) self.hero.move_time = r['response']['move_time'] self.hero.attack_time = r['response']['attack_time'] def autoattack(self, dt): if self.hero.attacking: self.hero.attack_timer -= dt / 100. if self.hero.attack_timer <= 0: self.hero.attack_timer = self.hero.attack_time if self.hero.tgh.target: if point_distance(self.hero.coords, self.hero.tgh.coords) < 14: self.client.send('attack', self.hero.tgh.id) def draw(self, surface): # center the map/screen on our Hero self.group.center(self.hero.camera.rect.center) # draw the Pyscroll map group self.group.draw(surface) def run(self): """ Run the game loop""" clock = pygame.time.Clock() self.running = True pygame.mouse.set_visible(False) from collections import deque times = deque(maxlen=30) try: while self.running: dt = clock.tick(60) times.append(clock.get_fps()) # Update From Server try: self.poll_server(dt) except PacketSizeMismatch: self.inputlog.add_line('Packet size mismatch!! Ignoring') # Handle input and render self.input.handle_input(dt) self.update(dt) self.draw(screen) if self.hero.particle: self.hero.particle.update() # blit GUI objects to screen self.text_box.draw(screen) self.inputlog.draw(screen) self.combatlog.draw(screen) self.hero.tgh.display.draw(screen) # debug draw co-ordinates if DEBUG_MODE: # # pos = [coord/16 for coord in self.hero.position] # draw_text('hero.position:. . . . {0}'.format(str(self.hero.position)), screen, coords=(10, 10)) # draw_text('delta t:. . . . . . . {0}'.format(str(dt)), screen, coords=(10, 40)) # draw_text('server poll:. . . . . {0}'.format(str(self.poll_timer)), screen, coords=(10, 55)) # draw_text('moving: . . . . . . . {0}'.format(str(self.hero.moving)), screen, coords=(10, 70)) # draw_text('target_coords:. . . . {0}'.format(str(self.hero.target_coords)), screen, coords=(10, 85)) # draw_text('map_zoom: . . . . . . {0}'.format(str(self.map_layer.zoom)), screen, coords=(10, 100)) # draw_text('screen size:. . . . . {0}'.format(str(self.screen_size)), screen, coords=(10, 115)) # draw_text(str(pygame.display.Info().current_w), screen, coords=(10, 130)) # # draw_text('Target ID: ', screen, coords=(10, 10)) # draw_text('Name: ', screen, coords=(10, 25)) # draw_text('Stats: ', screen, coords=(10, 40)) # draw_text('Center Offset: {0}'.format(offset), screen, coords=(10, 55)) # draw_text('MousePos: {0}'.format(pygame.mouse.get_pos()), screen, coords=(10, 70)) # draw_text('MousePosC: {0},{1}'.format(new_x, new_y), screen, coords=(10, 85)) # draw_text('PlayerCoords: {0}'.format(self.hero.coords), screen, coords=(10, 100)) # draw_text('CursorCoords: {0}'.format(cursor_coords), screen, coords=(10, 115)) # draw_text('Zoom: {0}'.format(zoom), screen, coords=(10, 130)) #draw_text('Nearby Lifeforms: {0}'.format(self.hero.nearby_lifeforms), screen, coords=(10, 130)) # if self.hero.tgh.target: # distance = point_distance(self.hero.coords, self.hero.tgh.coords) # draw_text('Target Distance: {0}'.format(distance), screen, coords=(10, 145)) # # draw_text('Attacking: {0}'.format(self.hero.attacking), screen, coords=(10, 160)) pass pygame.display.flip() except KeyboardInterrupt: self.running = False
class Game(object): filename = get_map(MAP_FILENAME) def __init__(self): # true while running self.currentAnim = CurrentAnim.RIGHT # load data from pytmx tmx_data = load_pygame(self.filename) # setup level geometry with simple pygame rects, loaded from pytmx self.walls = list() for object in tmx_data.objects: self.walls.append( pygame.Rect(object.x, object.y, object.width, object.height)) # create new data source for pyscroll map_data = pyscroll.data.TiledMapData(tmx_data) # create new renderer (camera) self.map_layer = pyscroll.BufferedRenderer(map_data, screen.get_size(), clamp_camera=False, tall_sprites=0) self.map_layer.zoom = 1.8 # pyscroll supports layered rendering. our map has 3 'under' layers # layers begin with 0, so the layers are 0, 1, and 2. # since we want the sprite to be on top of layer 1, we set the default # layer for sprites as 2 self.group = PyscrollGroup(map_layer=self.map_layer, default_layer=1) self.doorPosX = 157 self.doorPosY = 208 self.offset = 0 for j in range(2): for i in range(39): doors.append(Door(self.doorPosX, self.doorPosY)) self.doorPosY += 113 - self.offset self.offset += 0.06 self.doorPosX = 270 self.offset = 0 self.doorPosY = 208 self.doorPosX = 457 self.doorPosY = 208 self.offset = 0 for j in range(2): for i in range(39): doors.append(Door(self.doorPosX, self.doorPosY)) self.doorPosY += 113 - self.offset self.offset += 0.06 self.doorPosX = 588 self.offset = 0 self.doorPosY = 208 self.elevatorInitX = 350 self.elevatorInitY = 200 for i in range(20): elevator.append( Elevator(ElevatorImage, self.elevatorInitX, self.elevatorInitY)) self.elevatorInitY += 250 for i in elevator: self.group.add(i) self.playerCharacter = Character(PlayerWalkAnimList[0]) #self.playerCharacter._position = self.map_layer.map_rect.center self.playerCharacter._positionX += 300 self.playerCharacter._positionY += 20 self.group.add(self.playerCharacter) #Variables self.animDelay = 50 self.JumpTimer = 1700 self.FireDelay = 2000 self.lastUpdate = 0 self.SpawnlastUpdate = 0 self.JumplastUpdate = 0 self.AttacklastUpdate = 0 self.ScoreIncreaseTimer = 0 self.playerVel = [0, 0] self.velX = 0 self.velY = 0 self.jumpVel = 0.5 self.Gravity = 0 self.bIsJumping = False self.bCanJump = True self.WalkAnimIndex = 0 self.CrouchAnimIndex = 0 self.AttackAnimIndex = 0 self.bIsWalking = False self.bCollided = False self.bCanMoveRight = True self.bCanMoveLeft = True self.bIsFiring = False self.bHasFired = False self.bCanFire = True self.bAddEnemy = False self.facing = 1 self.PlayeBulletOffset = 0 self.bCanSpawnEnemy = True self.WalkSoundTimer = 0 pygame.display.set_caption("Elevator action") self.clock = pygame.time.Clock() self.score = 0 self.health = 10 self.bHealthCheck = True self.bGameOver = False self.bLevelPassed = False def MovementHandle(self): self.keys = pygame.key.get_pressed() if self.keys[pygame.K_LEFT]: self.bIsWalking = True self.currentAnim = CurrentAnim.LEFT elif self.keys[pygame.K_RIGHT]: self.bIsWalking = True self.currentAnim = CurrentAnim.RIGHT if self.bIsWalking == True: if self.currentAnim == CurrentAnim.LEFT: if self.bCanMoveLeft == True: self.velX = -2.5 elif self.currentAnim == CurrentAnim.RIGHT: if self.bCanMoveRight == True: self.velX = 2.5 def AddEnemy_thread(self): count = 0 if count < 1 and len(Enemies) < 50: for i in doors: if self.playerCharacter._positionY >= i.positionY - random.randrange( 20, 200 ) and self.playerCharacter._positionY <= i.positionY + random.randrange( 20, 200 ) and self.playerCharacter._positionX >= i.positionX - random.randrange( 20, 200 ) and self.playerCharacter._positionX <= i.positionX + random.randrange( 20, 200): enemy = Enemy(WalkAnimList[0]) enemy._positionX = i.positionX enemy._positionY = i.positionY Enemies.append(enemy) self.group.add(enemy) count += 1 self.bCanSpawnEnemy = False if count >= 2: count = 0 def Bullet_thread_player(self): if self.currentAnim == CurrentAnim.LEFT: self.facing = -1 self.PlayeBulletOffset = -10 elif self.currentAnim == CurrentAnim.RIGHT: self.facing = 1 self.PlayeBulletOffset = 10 BulletsPlayer.append( Bullet(BulletImage, self.playerCharacter._positionX + self.PlayeBulletOffset, self.playerCharacter._positionY + 20, self.facing)) self.group.add(BulletsPlayer[len(BulletsPlayer) - 1]) def Bullet_thread_enemy(self): for i in Enemies: BulletsEnemy.append( Bullet(BulletImage, i._positionX, i._positionY + 5, i.facing)) self.group.add(BulletsEnemy[len(BulletsEnemy) - 1]) def run(self, done): for event in pygame.event.get(): if event.type == pygame.QUIT: pygame.quit() if self.bIsWalking == True: if pygame.time.get_ticks() - self.WalkSoundTimer > 500: runSound.play(0) self.WalkSoundTimer = pygame.time.get_ticks() self.keys = pygame.key.get_pressed() if self.keys[pygame.K_SPACE]: if self.bCanJump == True: jumpSound.play(0) self.bIsJumping = True self.bCanJump = False if self.keys[pygame.K_z]: if self.bCanFire == True: self.bIsFiring = True self.bHasFired = True self.bCanFire = False pistolFire() else: self.bIsFiring = False else: self.bIsFiring = False self.bCanFire = True if self.bIsWalking == False: self.playerCharacter.setAnim(PlayerIdleAnimList[0], self.currentAnim) if self.keys[pygame.K_x]: pass if self.keys[pygame.K_q]: pass if self.keys[pygame.K_e]: if self.bAddEnemy == False: self.bAddEnemy = True else: self.bIsWalking = False if self.keys[pygame.K_DOWN]: self.playerCharacter.bPlayerCrouching = True else: self.playerCharacter.bPlayerCrouching = False if self.bIsWalking == False: self.velX = 0 if self.bIsJumping == True: self.bIsInAir = True self.bCollided = False if self.jumpVel > 0: self.velY -= self.jumpVel self.jumpVel -= 0.03 else: self.jumpVel = 0.5 self.velY = 0 self.bIsJumping = False self.MovementHandle() for sprite in self.group.sprites(): if sprite.bIsPlayer == ObjectType.PLAYER: for i in elevator: if sprite.feet.collidelist( self.walls) > -1 or i.CollideWithElavator == True: self.bCollided = True if self.bIsJumping == False: self.velY = 0 if self.bCanJump == False: if self.bCollided == True: self.bCanJump = True else: self.bCollided = False elif sprite.bIsPlayer == ObjectType.ENEMY: if sprite.feet.collidelist( self.walls) > -1 and i.CollideWithElavator == False: sprite.bCollided = True else: sprite.bCollided = False for i in elevator: if i.CollideWithElavator == False: if self.bCollided == False: self.velY += 0.1 / len(elevator) else: if i.Dir == ElevatorDir.DOWN: if self.bIsJumping == False: self.velY += 1.0 / len(elevator) + 0.82 else: self.velY -= 1.0 * 1.1 for i in Enemies: if i.bCollided == False: i.velY += 0.1 else: i.velY = 0.0 i.setVelocity() i.result = self.playerCharacter._positionX - i._positionX i.updateDir() #print(i.result) if i.result <= 100 and i.result >= -100 and i._positionY >= self.playerCharacter._positionY - 20 and i._positionY <= self.playerCharacter._positionY + 20: i.AIRotate() i.velocityX = 0 if i.bIsFiring == True and i.result <= 600 and i.result >= -600 and i._positionY >= self.playerCharacter._positionY - 20 and i._positionY <= self.playerCharacter._positionY + 20: thread = threading.Thread(target=self.Bullet_thread_enemy) enemyGun.play(0) thread.start() i.bIsFiring = False if i.bIsFiring == False: if pygame.time.get_ticks( ) - i.FireUpdate > self.FireDelay * random.randrange(2, 8): i.bIsFiring = True i.FireUpdate = pygame.time.get_ticks() i.UpdatePosition() if i.bIsDead == False: if i.velocityX != 0: i.UpdateAnim(self.animDelay) else: i.setAnim(IdleAnimList[0]) else: i.UpdateAnim(self.animDelay) if self.playerCharacter.right.collidelist(self.walls) > -1: self.bCanMoveRight = False else: self.bCanMoveRight = True if self.playerCharacter.left.collidelist(self.walls) > -1: self.bCanMoveLeft = False else: self.bCanMoveLeft = True for i in Enemies: if i.left.collidelist(self.walls) > -1: i.velocityX = 0 i.facing = 1 elif i.right.collidelist(self.walls) > -1: i.velocityX = 0 i.facing = -1 if self.bIsFiring == True: self.playerCharacter.bPlayShootingAnim = True if self.playerCharacter.bPlayShootingAnim == False: if self.playerCharacter.bPlayerCrouching == False: if self.bIsWalking == True: self.playerCharacter.setAnim( PlayerWalkAnimList[self.WalkAnimIndex], self.currentAnim) if self.WalkAnimIndex < len(PlayerWalkAnimList) - 1: if pygame.time.get_ticks( ) - self.lastUpdate > self.animDelay: self.WalkAnimIndex += 1 self.lastUpdate = pygame.time.get_ticks() else: self.WalkAnimIndex = 0 else: self.WalkAnimIndex = 0 else: self.playerCharacter.setAnim( playerCrouchAnimList[self.CrouchAnimIndex], self.currentAnim) if self.CrouchAnimIndex < len(playerCrouchAnimList) - 1: if pygame.time.get_ticks( ) - self.lastUpdate > self.animDelay: self.CrouchAnimIndex += 1 self.lastUpdate = pygame.time.get_ticks() else: self.CrouchAnimIndex = len(playerCrouchAnimList) - 1 else: self.playerCharacter.PlayShootAnim(self.currentAnim) self.playerCharacter.setVelocity(self.velX, self.velY) if self.bCanSpawnEnemy == True: threadAddEnemy = threading.Thread(target=self.AddEnemy_thread) threadAddEnemy.start() if self.bCanSpawnEnemy == False: if pygame.time.get_ticks() - self.SpawnlastUpdate > 8000: self.SpawnlastUpdate = pygame.time.get_ticks() self.bCanSpawnEnemy = True self.group.center(self.playerCharacter.rect.center) self.playerCharacter.UpdatePosition() #print(self.bCanSpawnEnemy) if self.bIsFiring == True: thread = threading.Thread(target=self.Bullet_thread_player) thread.start() if BulletsPlayer: for i in BulletsPlayer: i.UpdatePosition() #print("[ "+str(i.positionX)+", "+str(i.positionY)+" ]") if i.positionX > W or i.positionX < 0: self.group.remove(i) BulletsPlayer.pop(BulletsPlayer.index(i)) if len(BulletsPlayer) > 20: for i in BulletsPlayer: BulletsPlayer.pop(BulletsPlayer.index(i)) if BulletsEnemy: for i in BulletsEnemy: i.UpdatePosition() if i.positionX > W or i.positionX < 0: self.group.remove(i) BulletsEnemy.pop(BulletsEnemy.index(i)) for i in elevator: if self.playerCharacter.rect[ 1] >= i.rect[1] - 20 and self.playerCharacter.rect[ 1] <= i.rect[1] + 20 and self.playerCharacter.rect[ 0] >= i.rect[0] - 50 and self.playerCharacter.rect[ 0] <= i.rect[0] + 50: i.CollideWithElavator = True else: i.CollideWithElavator = False i.setVelocity() i.UpdatePosition() for i in Enemies: if i._positionY >= self.playerCharacter._positionY + 200 or i._positionY <= self.playerCharacter._positionY - 200: self.group.remove(i) Enemies.pop(Enemies.index(i)) if i.velocityY > 20: self.group.remove(i) Enemies.pop(Enemies.index(i)) if i.bDeathAnimCompleted == True: self.group.remove(i) Enemies.pop(Enemies.index(i)) for i in BulletsPlayer: if i.rect.collidelist(self.walls) > -1: self.group.remove(i) BulletsPlayer.pop(BulletsPlayer.index(i)) for i in BulletsEnemy: if i.rect.collidelist(self.walls) > -1: self.group.remove(i) BulletsEnemy.pop(BulletsEnemy.index(i)) for i in BulletsPlayer: for j in Enemies: if (i.rect[1] <= j.rect[1] + 20 and i.rect[1] >= j.rect[1] - 20 ) and (i.rect[0] <= j.rect[0] + 5 and i.rect[0] >= j.rect[0] - 5): j.bIsDead = True if pygame.time.get_ticks( ) - self.ScoreIncreaseTimer > 1000: self.score += 50 self.ScoreIncreaseTimer = pygame.time.get_ticks() self.bHealthCheck = True hitmarkSound.play(0) self.group.remove(i) try: BulletsPlayer.pop(BulletsPlayer.index(i)) except: continue for i in BulletsEnemy: if self.playerCharacter.bPlayerCrouching == False and self.bIsJumping == False: if (i.rect[1] <= self.playerCharacter.rect[1] + 20 and i.rect[1] >= self.playerCharacter.rect[1] - 20 ) and (i.rect[0] <= self.playerCharacter.rect[0] + 5 and i.rect[0] >= self.playerCharacter.rect[0] - 5): #print("PLAYER HIT") self.playerCharacter._positionY -= 4 print(i.facing) if i.facing < 0: self.playerCharacter._positionX -= 5 elif i.facing > 0: self.playerCharacter._positionX += 5 self.health -= 1 self.score -= 75 damageTakenSound.play(0) self.group.remove(i) BulletsEnemy.pop(BulletsEnemy.index(i)) if self.score == 250 and self.bHealthCheck == True: self.health += 1 hpGain.play(0) self.bHealthCheck = False if self.score == 500 and self.bHealthCheck == True: self.health += 1 hpGain.play(0) self.bHealthCheck = False if self.score == 750 and self.bHealthCheck == True: self.health += 1 hpGain.play(0) self.bHealthCheck = False if self.score == 1000 and self.bHealthCheck == True: self.health += 1 hpGain.play(0) self.bHealthCheck = False if self.score == 1500 and self.bHealthCheck == True: self.health += 1 hpGain.play(0) self.bHealthCheck = False if self.score == 2000 and self.bHealthCheck == True: self.health += 2 hpGain.play(0) self.bHealthCheck = False if self.score == 3000 and self.bHealthCheck == True: self.health += 3 hpGain.play(0) self.bHealthCheck = False if self.score == 4000 and self.bHealthCheck == True: self.health += 3 hpGain.play(0) self.bHealthCheck = False if self.score == 5000 and self.bHealthCheck == True: self.health += 3 hpGain.play(0) self.bHealthCheck = False if self.score == 10000 and self.bHealthCheck == True: self.health += 5 hpGain.play(0) self.bHealthCheck = False if self.playerCharacter._positionX >= 687 - 40 and self.playerCharacter._positionX <= 687 + 40 and self.playerCharacter._positionY >= 4657 - 40 and self.playerCharacter._positionY <= 4657 + 40: self.bLevelPassed = True if self.health <= 0: self.bGameOver = True print( str(self.playerCharacter._positionX) + ", " + str(self.playerCharacter._positionY)) self.group.draw(screen) draw_score(screen, 30, 30, self.score) draw_health(screen, 1120, 30, self.health) pygame.display.flip() self.clock.tick(60)
class QuestGame(object): """ This class is a basic game. This class will load data, create a pyscroll group, a hero object. It also reads input and moves the Hero around the map. Finally, it uses a pyscroll group to render the map and Hero. """ filename = get_map(MAP_FILENAME) def __init__(self): # true while running self.running = False # load data from pytmx tmx_data = load_pygame(self.filename) # setup level geometry with simple pygame rects, loaded from pytmx self.walls = list() for object in tmx_data.objects: self.walls.append( pygame.Rect(object.x, object.y, object.width, object.height)) # create new data source for pyscroll map_data = pyscroll.data.TiledMapData(tmx_data) w, h = screen.get_size() # create new renderer (camera) # clamp_camera is used to prevent the map from scrolling past the map's edge self.map_layer = pyscroll.BufferedRenderer(map_data, (w / 2, h / 2), clamp_camera=True) # pyscroll supports layered rendering. our map has 3 'under' layers # layers begin with 0, so the layers are 0, 1, and 2. # since we want the sprite to be on top of layer 1, we set the default # layer for sprites as 2 self.group = PyscrollGroup(map_layer=self.map_layer, default_layer=2) self.hero = Hero() # put the hero in the center of the map self.hero.position = self.map_layer.map_rect.center # add our hero to the group self.group.add(self.hero) def draw(self, surface): # center the map/screen on our Hero self.group.center(self.hero.rect.center) # draw the map and all sprites self.group.draw(surface) def handle_input(self): """ Handle pygame input events """ poll = pygame.event.poll event = poll() while event: if event.type == QUIT: self.running = False break elif event.type == KEYDOWN: if event.key == K_ESCAPE: self.running = False break # this will be handled if the window is resized elif event.type == VIDEORESIZE: init_screen(event.w, event.h) self.map_layer.set_size((event.w / 2, event.h / 2)) event = poll() # using get_pressed is slightly less accurate than testing for events # but is much easier to use. pressed = pygame.key.get_pressed() if pressed[K_UP]: self.hero.velocity[1] = -HERO_MOVE_SPEED elif pressed[K_DOWN]: self.hero.velocity[1] = HERO_MOVE_SPEED else: self.hero.velocity[1] = 0 if pressed[K_LEFT]: self.hero.velocity[0] = -HERO_MOVE_SPEED elif pressed[K_RIGHT]: self.hero.velocity[0] = HERO_MOVE_SPEED else: self.hero.velocity[0] = 0 def update(self, dt): """ Tasks that occur over time should be handled here """ self.group.update(dt) # check if the sprite's feet are colliding with wall # sprite must have a rect called feet, and move_back method, # otherwise this will fail for sprite in self.group.sprites(): if sprite.feet.collidelist(self.walls) > -1: sprite.move_back(dt) def run(self): """ Run the game loop """ clock = pygame.time.Clock() scale = pygame.transform.scale self.running = True try: while self.running: dt = clock.tick() / 1000. self.handle_input() self.update(dt) self.draw(temp_surface) scale(temp_surface, screen.get_size(), screen) pygame.display.flip() except KeyboardInterrupt: self.running = False
class Game: def __init__(self): self.running = False self.file_name = 'map/map.tmx' self.tmx_data = load_pygame(self.file_name) self.map = Map(tmx_data=self.tmx_data) self.font = pygame.font.Font('freesansbold.ttf', 32) self.focus_car = False def init_group(self): map_data = pyscroll.data.TiledMapData(self.tmx_data) self.map_layer = pyscroll.BufferedRenderer(map_data, screen.get_size(), clamp_camera=True) self.map_layer.zoom = 0.3 self.zoomchange = 1 self.group = PyscrollGroup(map_layer=self.map_layer, default_layer=1) def init_world(self): self.car = Car('mymap/car.png', (450, 450), 45) self.render_car() def update(self, dt): self.group.update(dt) def draw(self, surface): if self.focus_car: self.group.center(self.car.rect.center) self.group.draw(surface) def render_car(self): self.focus_car = True self.group.add(self.car) def handle_input(self, event): if event.type == pygame.KEYDOWN: if event.key == pygame.K_EQUALS: self.map_layer.zoom += .25 elif event.key == pygame.K_MINUS: value = self.map_layer.zoom - .25 if value > 0: self.map_layer.zoom = value if event.key == pygame.K_UP: self.car.speed += 1 elif event.key == pygame.K_DOWN: self.car.speed -= 1 elif event.key == pygame.K_LEFT: self.car.angle_speed = -4 elif event.key == pygame.K_RIGHT: self.car.angle_speed = 4 elif event.type == pygame.KEYUP: if event.key == pygame.K_LEFT: self.car.angle_speed = 0 elif event.key == pygame.K_RIGHT: self.car.angle_speed = 0 def run(self): clock = pygame.time.Clock() self.running = True while self.running: dt = clock.tick(60) / 1000 for event in pygame.event.get(): if event.type == pygame.QUIT: sys.exit(0) self.handle_input(event) self.update(dt) self.draw(screen) pygame.display.flip()
class MainGame: filename = load_map(MAP_FILENAME) def __init__(self): # true while running self.running = False # load data from pytmx tmx_data = load_pygame(self.filename) # set the current resolution self.res = get_screen_res() self.up = self.down = self.right = self.left = 0 # set up for declaration for key in config.items('KEY_CONFIG'): # declare config keys exec('self.' + key[0] + ' = K_' + key[1]) # setup level geometry with simple pygame rects, loaded from pytmx self.walls = list() for obj in tmx_data.objects: self.walls.append(pygame.Rect( obj.x, obj.y, obj.width, obj.height)) # create new data source for pyscroll map_data = pyscroll.data.TiledMapData(tmx_data) # create new renderer (camera) self.map_layer = pyscroll.BufferedRenderer(map_data, screen.get_size()) self.map_layer.zoom = 2 # pyscroll supports layered rendering. our map has 3 'under' layers # layers begin with 0, so the layers are 0, 1, and 2. # since we want the sprite to be on top of layer 1, we set the default # layer for sprites as 2 self.group = PyscrollGroup(map_layer=self.map_layer, default_layer=2) # Define characters self.prototype = Prototype(res=self.res) self.enemy = Enemy(enemy_type=enemy.suicide_explode, res=self.res) # Set character positions self.prototype.position = self.map_layer.map_rect.center self.enemy.position = (300, 300) # add our hero to the group self.group.add(self.enemy) self.group.add(self.prototype) def draw(self, surface): # center the map/screen on our Hero self.group.center(self.prototype.rect.center) # draw the map and all sprites self.group.draw(surface) def handle_input(self): # Handle pygame input events poll = pygame.event.poll event = poll() while event: if hasattr(event, "pos"): mx, my = event.pos self.prototype.m_pos = [mx, my] if event.type == QUIT: self.running = False break elif event.type == KEYDOWN: if event.key == K_ESCAPE: self.running = False break elif event.key == K_EQUALS: self.map_layer.zoom += .25 elif event.key == K_MINUS: value = self.map_layer.zoom - .25 if value > 0: self.map_layer.zoom = value event = poll() # using get_pressed is slightly less accurate than testing for events # but is much easier to use. pressed = pygame.key.get_pressed() if pressed[self.up]: self.prototype.velocity[1] = -movement_speed elif pressed[self.down]: self.prototype.velocity[1] = movement_speed else: self.prototype.velocity[1] = 0 if pressed[self.left]: self.prototype.velocity[0] = -movement_speed elif pressed[self.right]: self.prototype.velocity[0] = movement_speed else: self.prototype.velocity[0] = 0 def update(self, dt): """ Tasks that occur over time should be handled here """ self.group.update(dt) global i i += 1 # check if the sprite's feet are colliding with wall # sprite must have a rect called feet, and move_back method, # otherwise this will fail for sprite in self.group.sprites(): if sprite.hit_box.collidelist(self.walls) > -1: sprite.move_back(dt) def run(self): """ Run the game loop """ clock = pygame.time.Clock() self.running = True try: while self.running: dt = clock.tick() / 1000. self.handle_input() self.update(dt) self.draw(screen) pygame.display.flip() except KeyboardInterrupt: self.running = False
class Invertibles(object): filename = get_map(MAP_FILENAME) def __init__(self): pygame.mixer.pre_init(44100, 16, 1, 4096) pygame.init() pygame.font.init() self.screen = init_screen(800, 600) pygame.display.set_caption('Polaria') # Music channel self.music_channel = pygame.mixer.Channel(1) self.sounds = Sounds() # Store projectiles in a group self.projectiles = Group() # true while running self.running = False # load data from pytmx tmx_data = load_pygame(self.filename) # setup level geometry with simple pygame rects, loaded from pytmx self.walls = list() for object in tmx_data.objects: self.walls.append( pygame.Rect(object.x, object.y, object.width, object.height)) # create new data source for pyscroll map_data = pyscroll.data.TiledMapData(tmx_data) # create new renderer (camera) self.map_layer = pyscroll.BufferedRenderer(map_data, self.screen.get_size()) self.map_layer.zoom = 3.75 # pyscroll supports layered rendering. our map has 3 'under' layers # layers begin with 0, so the layers are 0, 1, and 2. # since we want the sprite to be on top of layer 1, we set the default # layer for sprites as 2 self.group = PyscrollGroup(map_layer=self.map_layer, default_layer=3) self.hero = Hero() self.heroes = list() self.heroes.append(self.hero) # Spawn an npc self.npc = NPC() self.npc.position = self.map_layer.map_rect.move(544, 592).topleft self.group.add(self.npc) self.npcs = list() self.npcs.append(self.npc) # Spawn an elemental below the house self.spawn_elementals() # Spawn the hero outside his house self.hero.position = self.map_layer.map_rect.move(528, 592).topleft # add our hero to the group self.group.add(self.hero) self.projectile_skin = 0 # Which spell the user has selected self.clock = pygame.time.Clock() # Dictionary to hold onto what keys are being held down self.movement_keys = { 'UP': False, 'DOWN': False, 'LEFT': False, 'RIGHT': False } def draw(self, surface, text=None): # center the map/screen on our Hero self.group.center(self.hero.rect.center) # draw the map and all sprites self.group.draw(surface) #self.projectiles.draw(self.screen) score = Text(self.screen, str(len(self.elementals)) + " dark elementals remaining", (0, 0, 0), 650, 10) score.blitme() if text: dialogbox = DialogBox(self.screen) dialogbox.blitme() rendered_text = dialogbox.render_textrect(text) if rendered_text: self.screen.blit(rendered_text, dialogbox.textarea_rect) def handle_input(self): """ Handle pygame input events """ poll = pygame.event.poll event = poll() while event: if event.type == QUIT: self.running = False break elif event.type == KEYDOWN: self.check_keydown_events(event) elif event.type == KEYUP: self.check_keyup_events(event) self.move_hero() if not self.running: break # this will be handled if the window is resized elif event.type == VIDEORESIZE: init_screen(event.w, event.h) self.map_layer.set_size((event.w, event.h)) event = poll() def reset_movement_keys(self): """Reset movement keys to False.""" self.movement_keys = { 'UP': False, 'DOWN': False, 'LEFT': False, 'RIGHT': False } def check_keydown_events(self, event): """Check for keypresses and respond to them.""" if event.key == K_ESCAPE or event.key == K_q: self.running = False # Set movement key flags if event.key == K_a: self.reset_movement_keys() self.hero.reset_velocity() self.movement_keys['LEFT'] = True elif event.key == K_d: self.reset_movement_keys() self.hero.reset_velocity() self.movement_keys['RIGHT'] = True elif event.key == K_w: self.reset_movement_keys() self.hero.reset_velocity() self.movement_keys['UP'] = True elif event.key == K_s: self.reset_movement_keys() self.hero.reset_velocity() self.movement_keys['DOWN'] = True # Cast spells if event.key == K_UP: new_projectile = Projectile(self.screen, self.hero, 'UP', self.projectile_skin) self.group.add(new_projectile) self.sounds.fireball.play() elif event.key == K_LEFT: new_projectile = Projectile(self.screen, self.hero, 'LEFT', self.projectile_skin) self.group.add(new_projectile) self.sounds.fireball.play() elif event.key == K_RIGHT: new_projectile = Projectile(self.screen, self.hero, 'RIGHT', self.projectile_skin) self.group.add(new_projectile) self.sounds.fireball.play() elif event.key == K_DOWN: new_projectile = Projectile(self.screen, self.hero, 'DOWN', self.projectile_skin) self.group.add(new_projectile) self.sounds.fireball.play() # Change spells if event.key == K_1: self.projectile_skin = 0 self.sounds.select_spell.play() elif event.key == K_2: self.projectile_skin = 1 self.sounds.select_spell.play() elif event.key == K_3: self.projectile_skin = 2 self.sounds.select_spell.play() elif event.key == K_4: self.projectile_skin = 3 self.sounds.select_spell.play() def check_keyup_events(self, event): """Check for keyreleases and respond to them.""" # Set movement key flags if event.key == K_a: self.movement_keys['LEFT'] = False if event.key == K_d: self.movement_keys['RIGHT'] = False if event.key == K_w: self.movement_keys['UP'] = False if event.key == K_s: self.movement_keys['DOWN'] = False def move_hero(self): """Only move hero if one movement key is being pressed.""" count = 0 key_pressed = '' for key, pressed in self.movement_keys.items(): if pressed: key_pressed = key count += 1 if count == 1: self.hero.set_direction(key_pressed) else: self.hero.set_idle() def update_projectiles(self): """Update position of projectiles and get rid of old bullets.""" # Update projectile positions self.projectiles.update() # Get rid of projectiles that have gone off screen for projectile in self.projectiles.copy(): if projectile.rect.bottom <= 0: self.projectiles.remove(projectile) def update(self, dt): """ Tasks that occur over time should be handled here""" self.group.update(dt) self.update_projectiles() # check if the sprite's feet are colliding with wall # sprite must have a rect called feet, and move_back method, # otherwise this will fail for sprite in self.group.sprites(): if sprite.name == 'hero': if sprite.feet.collidelist(self.walls) > -1: sprite.move_back(dt) elif sprite.feet.collidelist(self.elementals) > -1: sprite.move_back(dt) elif sprite.feet.collidelist(self.npcs) > -1: sprite.move_back(dt) elif sprite.name == 'elemental': if sprite.feet.collidelist(self.walls) > -1: sprite.move_back(dt) elif sprite.feet.collidelist(self.heroes) > -1: sprite.move_back(dt) elif sprite.name == 'projectile': collide_elemental = sprite.rect.collidelist(self.elementals) if sprite.rect.collidelist(self.walls) > -1: self.group.remove(sprite) elif collide_elemental > -1: self.group.remove(sprite) self.group.remove(self.elementals[collide_elemental]) self.elementals.pop(collide_elemental) self.sounds.monster_kill.play() def run(self): """ Run the game loop""" self.running = True self.music_channel.play(self.sounds.town_theme, -1) text = [ 'We, the people of Polaria have summoned thee, the Lord of Light!\n\nPress enter to continue.', 'Our beloved town has been overrun by evil dark elementals! Their dark magic can only be fought with the magic of Light!\n\nPress Enter to continue.', 'Use WASD to move around and the arrow keys to cast your spells. You can switch spells with keys 1-4.\n\nPress Enter to continue.', 'Good luck! And may the power of Light be with you!\n\nPress enter to continue.' ] self.run_dialog(text) while self.running: dt = self.clock.tick(60) / 1000. self.handle_input() self.update(dt) if len(self.elementals) <= 0: self.run_dialog([ "Congratulations! You saved our town! Polaria is safe once more!" ]) self.running = False else: self.draw(self.screen) pygame.display.update() def run_dialog(self, text): self.update(0) while text: self.clock.tick(60) self.draw(self.screen, text[0]) if self.handle_dialog_box_input(): text.remove(text[0]) pygame.display.update() def spawn_elementals(self): """Spawn elementals in random positions on the map.""" self.elementals = list() count = 0 while count < 100: x = randint(0, 1120) y = randint(0, 1120) elemental = Elementals() elemental.position = self.map_layer.map_rect.move(x, y).topleft elemental.set_rect(x, y) if elemental.rect.collidelist(self.walls) == -1: self.elementals.append(elemental) self.group.add(elemental) count += 1 def handle_dialog_box_input(self): for event in pygame.event.get(): if event.type == QUIT: sys.exit() if event.type == pygame.KEYDOWN: if event.key == pygame.K_RETURN: return True if event.key == K_ESCAPE or event.key == K_q: sys.exit() if event.type == VIDEORESIZE: init_screen(event.w, event.h) self.map_layer.set_size((event.w, event.h))
class Hunting(GameState): """The main game state.""" roast_live_time = 10000 roast_fade_time = 1000 def __init__(self): super(Hunting, self).__init__() map_data = MapData() map_layer = BufferedRenderer(map_data, prepare.SCREEN_SIZE) self.all_sprites = PyscrollGroup(map_layer=map_layer) self.colliders = pg.sprite.Group() self.ui = pg.sprite.Group() self.noise_detector = NoiseDetector((10, 80), self.ui) self.animations = pg.sprite.Group() self.hunter = Hunter(map_layer.map_rect.center, 0, self.noise_detector, self.all_sprites) self.leaves = pg.sprite.Group() self.roasts = pg.sprite.Group() self.flocks = pg.sprite.Group() self.turkeys = self.add_turkeys() self.bullets = pg.sprite.Group() self.make_trees() hx, hy = self.hunter.rect.center self.ammo_crate = AmmoCrate((hx - 50, hy - 50), self.colliders, self.all_sprites) self.rustle_sounds = [prepare.SFX["rustle{}".format(x)] for x in range(1, 21)] self.wind_gust() style = {"font_path": prepare.FONTS["pretzel"], "font_size": 24, "text_color": (58, 41, 18)} self.shell_label = Label("{}".format(self.hunter.shells), {"topleft": (50, 10)}, **style) self.roasts_label = Label("{}".format(self.hunter.roasts), {"topleft": (50, 50)}, **style) Icon((20, 3), "shell", self.ui) Icon((10, 45), "roast", self.ui) self.add_flock() def wind_gust(self): """Play wind sound and set up next gust.""" prepare.SFX["wind"].play() task = Task(self.wind_gust, randint(15000, 45000)) self.animations.add(task) def add_turkeys(self): """Spawn turkeys.""" turkeys = pg.sprite.Group() w, h = prepare.WORLD_SIZE for _ in range(35): pos = randint(20, w - 20), randint(20, h - 20) Turkey(pos, turkeys, self.all_sprites) return turkeys def make_trees(self): """Spawn trees.""" self.trees = pg.sprite.Group() w, h = prepare.WORLD_SIZE for _ in range(120): while True: pos = (randint(50, w - 20), randint(20, h - 20)) tree = Tree(pos) collisions = (tree.collider.colliderect(other.collider) for other in self.colliders) if not any(collisions) and not tree.collider.colliderect(self.hunter.collider): break self.trees.add(tree) self.colliders.add(tree) self.all_sprites.add(tree) def add_flock(self): """Add a Flock of birds.""" flock = Flock((self.hunter.collider.centerx, -1500), self.animations, self.all_sprites, self.flocks) next_flock = randint(45000, 150000) #next flock in 45-150 seconds task = Task(self.add_flock, next_flock) self.animations.add(task) def add_roast(self, position): roast = Roast(position, self.roasts, self.all_sprites) task = Task(roast.kill, self.roast_live_time) self.animations.add(task) return roast def update(self, dt): self.animations.update(dt) keys = pg.key.get_pressed() self.hunter.update(dt, keys, self.bullets, self.turkeys, self.colliders, self.all_sprites, self.animations) self.turkeys.update(dt, self.trees) self.bullets.update(dt) for sprite in self.all_sprites: self.all_sprites.change_layer(sprite, sprite.collider.bottom) view_rect = self.all_sprites._map_layer.view_rect for bullet in self.bullets: if not bullet.rect.colliderect(view_rect): bullet.kill() tree_hits = pg.sprite.groupcollide(self.bullets, self.trees, True, False, footprint_collide) for bullet in tree_hits: for tree in tree_hits[bullet]: choice(self.rustle_sounds).play() num = randint(3, 9) for spot_info in sample(leaf_spots[tree.trunk], num): self.add_leaf(tree, spot_info) turkey_hits = pg.sprite.groupcollide(self.bullets, self.turkeys, True, True, footprint_collide) for t_bullet in turkey_hits: for turkey in turkey_hits[t_bullet]: self.add_roast(turkey.pos) if self.hunter.shells < self.hunter.max_shells: if self.hunter.collider.colliderect(self.ammo_crate.rect.inflate(16, 16)): prepare.SFX["gunload"].play() self.hunter.shells = self.hunter.max_shells if self.hunter.state == "move": self.scare_turkeys() self.noise_detector.update(dt) self.shell_label.set_text("{}".format(self.hunter.shells)) self.roasts_label.set_text("{}".format(self.hunter.roasts)) roast_collisions = pg.sprite.spritecollide(self.hunter, self.roasts, True, footprint_collide) if roast_collisions: prepare.SFX["knifesharpener"].play() self.hunter.roasts += len(roast_collisions) self.flocks.update(self.hunter) def scare_turkeys(self): """Make turkeys flee depending on distance and the player's noise level.""" size = self.noise_detector.noise_level scare_rect = self.hunter.collider.inflate(size, size) scared_turkeys = (t for t in self.turkeys if t.collider.colliderect(scare_rect) and t.state.name != "flee") for scared in scared_turkeys: scared.flee(self.hunter) def add_leaf(self, tree, spot_info): """Add a falling leaf.""" fall_time = randint(2000, 2500) leaf = Leaf(tree, spot_info, self.leaves, self.all_sprites) y = leaf.rect.centery + leaf.fall_distance ani = Animation(centery=y, duration=fall_time, round_values=True) ani.callback = leaf.land ani.start(leaf.rect) ani2 = Animation(centery=leaf.collider.centery + leaf.fall_distance, duration=fall_time, round_values=True) ani2.start(leaf.collider) fade = Animation(img_alpha=0, duration=3000, delay=fall_time, round_values=True) fade.callback = leaf.kill fade.update_callback = leaf.set_alpha fade.start(leaf) self.animations.add(ani, ani2, fade) def draw(self, surface): self.all_sprites.center(self.hunter.pos) self.all_sprites.draw(surface) self.shell_label.draw(surface) self.roasts_label.draw(surface) self.ui.draw(surface)
class ScrollMap(object): """Scroll Map object. The implementation is based on [pyscroll](https://github.com/bitcraft/pyscroll) This class provides functionality: - create and manage a pyscroll group - load a collision layers - manage sprites added to the map - allows to detect collisions with loaded collision layers - render the map and the sprites on top """ def __init__(self, screen_size: Tuple[int, int], tmx: pytmx.TiledMap, collision_layers: List[str] = []) -> None: """Create scroll map object. Args: screen_size (Tuple[int, int]): screen resolution will be used to the map rendering tmx (pytmx.TiledMap): loaded `pytmx.TiledMap` object collision_layers (List[str], optional): List of `pytmx.TiledMap` layer names will be used for tiles collision detection. Defaults to []. """ self._tmx = tmx # create new data source for pyscroll map_data = pyscroll.data.TiledMapData(self._tmx) # create new renderer (camera) self.map_layer = pyscroll.BufferedRenderer(map_data, screen_size, clamp_camera=False, tall_sprites=1) self.map_layer.zoom = 1 # pyscroll supports layered rendering. our map has 3 'under' layers # layers begin with 0, so the layers are 0, 1, and 2. # since we want the sprite to be on top of layer 1, we set the default # layer for sprites as 2 self._map_group = PyscrollGroup(map_layer=self.map_layer, default_layer=2) self._map_collision_obj: List[pygame.Rect] = [] self.add_collision_layers(collision_layers) def add_collision_layers(self, collision_layers: List[str]) -> None: """Load `pytmx.TiledMap` layer tiles for collision detection. Some layer in the `pytmx.TiledMap` might be be used for collision detection. For example: the layer includes "island tiles" might be used for collision detection with a "ship" actor. Args: collision_layers (List[str]): List of `pytmx.TiledMap` layer names will be used for tiles collision detection. """ # setup level geometry with simple pygame rects, loaded from pytmx self._map_collision_obj += extract_collision_objects_from_tile_layers( self._tmx, collision_layers) def view(self) -> Any: return self._map_group.view def transform(self, pos: Tuple[int, int]) -> Tuple[int, int]: return (pos[0] + self._map_group.view.left, pos[1] + self._map_group.view.top) def draw(self, screen: Screen) -> None: """Draw method similar to the `pgz.scene.Scene.draw` method. Will draw the map and all actors on top. Args: dt (float): time in milliseconds since the last update """ self._map_group.draw(screen.surface) def update(self, dt: float) -> None: """Update method similar to the `pgz.scene.Scene.update` method. All the actors attached to the map will be updated. Args: dt (float): time in milliseconds since the last update """ self._map_group.update(dt) def add_sprite(self, sprite: pygame.sprite.Sprite) -> None: """Add actor/sprite to the map Args: sprite (pygame.sprite.Sprite): sprite object to add """ self._map_group.add(sprite) def remove_sprite(self, sprite: pygame.sprite.Sprite) -> None: """Remove sprite/actor from the map. Args: sprite (pygame.sprite.Sprite): sprite object to remove """ sprite.remove(self._map_group) def set_center(self, point: Tuple[int, int]) -> None: self._map_group.center(point) def get_center(self) -> Tuple[int, int]: if not self.map_layer.map_rect: raise Exception("Map was not configured properly") return self.map_layer.map_rect.center # type: ignore def change_zoom(self, change: float) -> None: value = self.map_layer.zoom + change if value > 0: self.map_layer.zoom = value def set_size(self, size: Tuple[int, int]) -> None: self.map_layer.set_size(size) def collide_map(self, sprite: pygame.sprite.Sprite) -> bool: """Detect a collision with tiles on the map Args: sprite (pygame.sprite.Sprite): sprite/actor for detection Returns: bool: True is the collision with the colision layers was detected """ if not sprite.rect: return False return bool(sprite.rect.collidelist(self._map_collision_obj) > -1)
class QuestGame(object): """ This class is a basic game. This class will load data, create a pyscroll group, a hero object. It also reads input and moves the Hero around the map. Finally, it uses a pyscroll group to render the map and Hero. """ filename = get_map(MAP_FILENAME) def __init__(self): # true while running self.running = True self.time_step = 0 # load data from pytmx tmx_data = load_pygame(self.filename) # setup level geometry with simple pygame rects, loaded from pytmx self.walls = list() for object in tmx_data.objects: self.walls.append( pygame.Rect(object.x, object.y, object.width, object.height)) # create new data source for pyscroll map_data = pyscroll.data.TiledMapData(tmx_data) # create new renderer (camera) screens = screen.get_size() self.map_layer = pyscroll.BufferedRenderer(map_data, (10, 40), clamp_camera=True, tall_sprites=1) self.map_layer.zoom = 0.75 # pyscroll supports layered rendering. our map has 3 'under' layers # layers begin with 0, so the layers are 0, 1, and 2. # since we want the sprite to be on top of layer 1, we set the defaultmm m,m # layer for sprites as 2 self.group = PyscrollGroup(map_layer=self.map_layer, default_layer=3) self.hero = Hero() # put the hero in the center of the map self.hero.vi_tri[0] += 200 self.hero.vi_tri[1] += 100 # add our hero to the group self.group.add(self.hero) self.map_layer.set_size(screens) def draw(self, surface): # center the map/screen on our Hero self.group.center(self.hero.rect) # draw the map and all sprites self.group.draw(surface) def handle_input(self, dt): """ xỠlý sự kiện nhấn nút """ for event in pygame.event.get(): if event.type == pygame.QUIT: if event.key == pygame.K_ESCAPE: return False elif event.type == pygame.KEYDOWN: if event.key == pygame.K_ESCAPE: return False if event.type == pygame.KEYDOWN: if event.key == pygame.K_LEFT: self.hero.go_left(dt) if event.key == pygame.K_RIGHT: self.hero.go_right(dt) if event.key == pygame.K_UP: for sprite in self.group.sprites(): if sprite.feet.collidelist(self.walls) > -1: self.hero.jump(dt) else: self.hero.stop(dt) def update(self, dt): """ Tasks that occur over time should be handled here """ self.group.update(dt) # check if the sprite's feet are colliding with wall # sprite must have a rect called feet, and move_back method, # otherwise this will fail for sprite in self.group.sprites(): if sprite.feet.collidelist(self.walls) > -1: self.hero.move_back(dt) self.hero.va_cham = True else: self.hero.vi_tri[1] += 2 print(self.hero.direction) def run(self): """ Run the game loop """ clock = pygame.time.Clock() self.running = True from collections import deque times = deque(maxlen=30) try: while self.running: dt = clock.tick() / 1000. times.append(clock.get_fps()) #print(sum(times)/len(times)) self.handle_input(dt) self.update(dt) self.draw(screen) pygame.display.flip() except KeyboardInterrupt: self.running = False
class BaseLevel: def __init__(self, filename, game_loop, **kwargs): self.map_filename = filename self.map_path = os.path.join(resources.TMX_FOLDER, filename) self.name = kwargs.get("name", os.path.splitext(filename)[0]) LOG.debug("Initializing level with map %s", self.map_path) self.game_loop = game_loop self.battles_allowed = kwargs.get("battles_allowed", False) self.exclude_players = kwargs.get("exclude_players", False) self.music = kwargs.get("music", None) self.keydown_only = False self.keydown_orig = self.keydown_only # Stash for flipping back to self.current_dialog = [] self.poster_image = None self.velocity = 2 # Default movement velocity LOG.debug("Populating image cache...") self.image_cache = [] for image in kwargs.get("images", []): # If there is no location data tuple, just blit to the middle if isinstance(image, str): img = get_image(image) self.image_cache.append((img, None, None)) else: # Assuming a data tuple of path, x, y img_path, x, y = image img = get_image(img_path) self.image_cache.append((img, x, y)) LOG.debug("Collecting TMX data...") # Collect tmx_data and a surface self.map_data = TiledMapData(self.tmx_data) self.map_layer = BufferedRenderer( self.map_data, self.game_screen.get_size(), clamp_camera=False, background_color=self.map_data.background_color, alpha=True, ) self.map_layer.zoom = 2 # pyscroll supports layered rendering. Our map has 3 'under' layers # layers begin with 0, so the layers are 0, 1, and 2. # since we want the sprite to be on top of layer 1, we set the default # layer for sprites as 2 self.scroll_group = PyscrollGroup(map_layer=self.map_layer, default_layer=10) if self.player1: self.scroll_group.add(self.player1) objects = self.custom_objects for s_npc in objects["static_npcs"]: if s_npc.image: try: self.scroll_group.add(s_npc) except Exception: LOG.exception("Cannot add static npc") for npc in objects["npcs"]: if npc.image: try: self.scroll_group.add(npc) except Exception: LOG.exception("Cannot add npc") self.game_screen.fill((0, 0, 0)) def __call__(self): self.start() def start(self): self.play_music() self.draw() @cachedproperty def tmx_data(self): return load_pygame(self.map_path) @property def font_15(self): return self.game_loop.font_15 @property def font_20(self): return self.game_loop.font_20 @property def font_25(self): return self.game_loop.font_25 @property def font_40(self): return self.game_loop.font_40 @property def font_60(self): return self.game_loop.font_60 @cachedproperty def music_file(self): """Randomly returns a music file if more than one are specified.""" if not hasattr(self, "_music_files"): # Load all properties starting with "music" music_files = [] for key, value in self.tmx_data.properties.items(): if key.lower().startswith("music"): music_files.append(value) self._music_files = music_files if not self._music_files: LOG.debug("Map %s has no music specified", self.map_filename) return None # No music specified in file # If there is only one, just return it every time if len(self._music_files) == 1: return self._music_files[0] rand_idx = random.randint(1, len(self._music_files)) - 1 return self._music_files[rand_idx] @property def state(self): """Return the state from the parent game loop for convenience.""" return self.game_loop.state @property def game_screen(self): return self.game_loop.surface def play_music(self): if not self.game_loop.sound_enabled: return # Don't play the music pg.mixer.music.fadeout(100) if self.music_file: load_music(self.music_file) pg.mixer.music.set_volume(self.state["volume"]) pg.mixer.music.play(-1) else: pg.mixer.music.fadeout(100) def _simple_draw(self): """Simple draw used in menus and other non-player based levels.""" viewport = self.game_screen.get_rect() surface = pg.Surface((viewport.width, viewport.height)) # Alias so we can avoid an attribute lookup on each loop iteration surface_blit = surface.blit # Draw the map and all sprites self.scroll_group.draw(surface) # If there are any images, draw them for img, x, y in self.image_cache: img_rect = img.get_rect() # If there is no location data tuple, just blit to the middle if x is None or y is None: img_rect.center = viewport.center surface.blit(img, img_rect) else: img_rect.midbottom = self.viewport.midbottom img_rect.y = y img_rect.x = x surface_blit(img, img_rect) # Draw any text on the surface self.draw_text(surface) self.game_screen.blit(surface, (0, 0), viewport) def draw(self): player1 = self.player1 viewport = self.game_screen.get_rect() surface = pg.Surface((viewport.width, viewport.height)) colliders = self.custom_objects["colliders"] portals = self.custom_objects["portals"] static_npcs = self.custom_objects["static_npcs"] npcs = self.custom_objects["npcs"] posters = self.custom_objects["posters"] # Center the viewport on player 1 player1.update() self.scroll_group.center(player1.rect) if player1.state.startswith("move"): orig_x = player1.rect.x orig_y = player1.rect.y check_box = player1.rect.move( player1.x_velocity, player1.y_velocity, ) move_player = True for portal in portals: if portal["rect"].colliderect(check_box): player1.state = "teleporting" player1.teleport_target = portal["teleport_target"] self.state["player1"] = player1.get_state() self.game_loop.current_level = portal["destination"] return for poster in posters: if poster["rect"].colliderect(check_box): self.reset_player1(orig_x, orig_y) move_player = False for item in poster["requires"]: if item not in self.game_loop.quest_inventory: LOG.debug("Player has not completed the quest") break else: self.poster_image = poster["image"] break for s_npc in static_npcs: if s_npc.rect.colliderect(check_box): self.reset_player1(orig_x, orig_y) self.current_dialog = s_npc.dialog[:] # Copy the dialog move_player = False break for npc in npcs: if npc.rect.colliderect(check_box): self.reset_player1(orig_x, orig_y) self.current_dialog = npc.interact() move_player = False break if move_player: for collider in colliders: if collider.colliderect(check_box): self.reset_player1(orig_x, orig_y) break if move_player is True: player1.rect.move_ip(player1.x_velocity, player1.y_velocity) if player1.rect.x % 16 == 0 and player1.rect.y % 16 == 0: player1.state = "resting" self.state["player1"] = player1.get_state() # Collect all images to blit images_to_blit = [] img_blit_append = images_to_blit.append # Alias for performance # If there are any images, draw them for img, x, y in self.image_cache: img_rect = img.get_rect() # If there is no location data tuple, just blit to the middle if x is None or y is None: img_rect.center = viewport.center else: img_rect.midbottom = self.viewport.midbottom img_rect.y = y img_rect.x = x img_blit_append((img, img_rect)) # Draw the main scroll group self.scroll_group.draw(surface) # Draw all collected images to blit surface.blits(images_to_blit, doreturn=False) # If we have encountered a poster, draw it if self.poster_image: if isinstance(self.poster_image, str): self.poster_image = get_image(self.poster_image) poster_rect = self.poster_image.get_rect() poster_rect.center = viewport.center surface.blit(self.poster_image, poster_rect) # Draw any text on the surface self.draw_text(surface) # Draw any dialog self.draw_dialog(surface, viewport) # Draw any notifications self.draw_notifications(surface, viewport) # Draw fps if applicable self.draw_fps(surface, viewport) self.game_screen.blit(surface, (0, 0), viewport) def draw_text(self, surface): pass def draw_fps(self, surface, viewport): """Draw fps if show_fps is set on game loop.""" if getattr(self.game_loop, "show_fps", False) is True: fps = f"{self.game_loop.clock.get_fps():.2f} FPS" text = self.font_15.render(fps, True, (255, 255, 255)) text_rect = text.get_rect() text_rect.bottomleft = viewport.bottomleft text_rect.x += 5 text_rect.y -= 5 surface.blit(text, text_rect) def draw_dialog(self, surface, viewport): """Draw any current dialog.""" if not self.current_dialog: return try: text = self.current_dialog[0] except Exception: LOG.exception("Could not draw dialog text.") return img = self.dialog_image img_rect = img.get_rect() img_rect.bottomright = viewport.bottomright img_rect.x -= 3 img_rect.y -= 3 surface.blit(img, img_rect) dialog_text = self.font_20.render(text, True, (255, 255, 255)) dialog_text_rect = dialog_text.get_rect() dialog_text_rect.center = img_rect.center surface.blit(dialog_text, dialog_text_rect) def draw_notifications(self, surface, viewport): """Draw any current notifications.""" notification = self.game_loop.notification if not notification: return img = self.dialog_image img_rect = img.get_rect() img_rect.topright = viewport.topright img_rect.x -= 3 img_rect.y += 3 surface.blit(img, img_rect) notification_text = self.font_25.render(notification, True, (255, 255, 255)) notification_text_rect = notification_text.get_rect() notification_text_rect.center = img_rect.center surface.blit(notification_text, notification_text_rect) def reset_player1(self, x, y): self.player1.rect.x = x self.player1.rect.y = y self.player1.x_velocity = 0 self.player1.y_velocity = 0 self.player1.state = "resting" self.state["player1"] = self.player1.get_state() @cachedproperty def player1(self): """ Create a player instance. If starting fresh, load at the levels starting point. Otherwise, either restore a previous location or setup a teleport and look for a teleport target. """ player1 = Player(self.game_loop, "player.png") player1.rect.center = self.start_point.center player1.rect.x = self.start_point.x player1.rect.y = self.start_point.y state_data = self.state["player1"] if state_data: is_teleporting = state_data["state"] == "teleporting" teleport_target = state_data.get("teleport_target") state_data["state"] = "resting" state_data["x_velocity"] = 0 state_data["y_velocity"] = 0 state_data["teleport_target"] = None player1.set_state(state_data) # If the player was teleporting, place them at the starting point if is_teleporting: # Try to find a portal with target name if one available if teleport_target: for p_target in self.custom_objects["portal_targets"]: if p_target.get("name") == teleport_target: player1.rect.center = p_target["rect"].center player1.rect.x = p_target["rect"].x player1.rect.y = p_target["rect"].y break else: LOG.warning("Could not find target portal %s", teleport_target) return player1 @cachedproperty def dialog_image(self): return get_image("dialog_box.png") @cachedproperty def custom_objects(self): """ All important data types collected in a single iteration. Gathers colliders, portals, and start points. """ colliders = [] start_point = None portals = [] portal_targets = [] static_npcs = [] npcs = [] posters = [] pg_rect = pg.Rect for obj in self.tmx_data.objects: name = obj.name asset_type = obj.type if asset_type == "blocker" or name == "blocker": colliders.append(pg_rect(obj.x, obj.y, 16, 16)) elif not start_point and any(( asset_type in ("start_point", "start point", "starting point"), name in ("start_point", "start point", "starting point"), )): start_point = pg_rect(obj.x, obj.y, 16, 16) elif asset_type == "portal_target": portal_targets.append({ "name": name, "rect": pg_rect(obj.x, obj.y, 16, 16) }) elif asset_type == "portal" or name == "portal": custom_properties = obj.properties destination = custom_properties.get("destination") teleport_target = custom_properties.get("portal") if not destination: LOG.warning("Portal at %s, %s missing destination.", obj.x, obj.y) else: portals.append({ "name": name, "rect": pg_rect(obj.x, obj.y, 16, 16), "destination": destination, "teleport_target": teleport_target, }) elif asset_type == "static_npc": custom_properties = obj.properties sprite = custom_properties.get("sprite") direction = custom_properties.get("direction", "down") static_npcs.append( StaticNPC( self.game_loop, sprite, pg_rect(obj.x, obj.y, 16, 16), direction=direction, dialog=dialog_from_props(custom_properties), )) elif asset_type == "npc": custom_properties = obj.properties custom_properties["name"] = name # Add name to custom data sprite = custom_properties.get("sprite") npcs.append( NPC(self.game_loop, sprite, pg_rect(obj.x, obj.y, 16, 16), data=custom_properties)) elif asset_type == "poster": custom_properties = obj.properties sprite = custom_properties.get("sprite") requires = custom_properties.get("requires").split(",") posters.append({ "image": custom_properties.get("poster_image"), "requires": [x.strip() for x in requires], "rect": pg_rect(obj.x, obj.y, 16, 16), }) return { "colliders": colliders, "start_point": start_point, "portals": portals, "portal_targets": portal_targets, "static_npcs": static_npcs, "npcs": npcs, "posters": posters, } @cachedproperty def start_point(self): """ Returns rectangle representing the starting point in the level. If more than one is found, the others will be ignored. If none are found a default one will be created at 0, 0 """ start_point = self.custom_objects["start_point"] if not start_point: start_point = pg.Rect(0, 0, 16, 16) LOG.debug("Got start point %s", start_point) return start_point def _pop_dialog(self): try: d = self.current_dialog.pop(0) except IndexError: pass else: LOG.debug("%s dropped from dialog queue", d) def down_pressed(self): if self.current_dialog or self.poster_image: return # Don't do anything while in dialog mode if self.player1.state == "resting": self.player1.state = "move-down" self.player1.y_velocity = self.velocity self.player1.x_velocity = 0 def up_pressed(self): if self.current_dialog or self.poster_image: return # Don't do anything while in dialog mode if self.player1.state == "resting": self.player1.state = "move-up" self.player1.y_velocity = self.velocity * -1 self.player1.x_velocity = 0 def left_pressed(self): if self.current_dialog or self.poster_image: return # Don't do anything while in dialog mode if self.player1.state == "resting": self.player1.state = "move-left" self.player1.y_velocity = 0 self.player1.x_velocity = self.velocity * -1 def right_pressed(self): if self.current_dialog or self.poster_image: return if self.player1.state == "resting": self.player1.state = "move-right" self.player1.y_velocity = 0 self.player1.x_velocity = self.velocity def space_pressed(self): accept_spaces = getattr(self, "accept_spaces", True) if accept_spaces: self.player1.state = "resting" self.player1.y_velocity = 0 self.player1.x_velocity = 0 self._pop_dialog() self.poster_image = None self.accept_spaces = False else: self.accept_spaces = True pg.time.delay(30) pg.event.clear() def escape_pressed(self): self.current_dialog = [] self.accept_spaces = True pass def esc_pressed(self): return self.escape_pressed() def up_released(self): pass def left_released(self): pass def right_released(self): pass def w_released(self): pass def a_released(self): pass def s_released(self): pass def d_released(self): pass def enter_released(self): pass def space_released(self): pass def escape_released(self): pass def w_pressed(self): pass def a_pressed(self): pass def s_pressed(self): pass def d_pressed(self): pass def enter_pressed(self): return self.space_pressed()
class QuestGame(object): """ This class is a basic game. This class will load data, create a pyscroll group, a hero object. It also reads input and moves the Hero around the map. Finally, it uses a pyscroll group to render the map and Hero. """ filename = get_map(MAP_FILENAME) counter = 1 counter2 = 1 def __init__(self, state): if state == False: self.fullscreen = False # true while running. self.running = False self.clock = pygame.time.Clock() # create all the directio variables self.direction = "still" self.EntityDirection = "still" self.EntityDirection1, self.EntityDirection2 = "still", "still" self.fps = 1000 self.bypass = False entityPos1, heroPos1 = False, False # load data from pytmx tmx_data = load_pygame(self.filename) self.tmx_data = tmx_data mapPlay = load_pygame(get_map(stats['map'])) # create new data source for pyscroll map_data = pyscroll.data.TiledMapData(mapPlay) # setup level geometry with simple pygame rects, loaded from pytmx. self.walls = list() for object in mapPlay.objects: self.walls.append(pygame.Rect( object.x, object.y, object.width, object.height)) # create new renderer (camera) self.map_layer = pyscroll.BufferedRenderer(map_data, screen.get_size()) self.map_layer.zoom = 2 self.group = PyscrollGroup(map_layer=self.map_layer, default_layer=4) self.hero = Hero('Tiles/hero/character_still.png') self.entity = Entity('Tiles/hero/character_still.png') self.hero.position = stats['pos'] self.entity.position = stats['pos'] # add our hero to the group self.group.add(self.hero) #self.group.add(self.entity) self.entVel = (0, 0) def deep_thought(self): # The 'AI' function, needs work if self.counter2 % 75 == 0 or self.bypass == True: self.bypass = False if random.randint(0, 1) == 1: self.entity.velocity[0], self.entity.velocity[1] = 0, 0 movement = random.choice(["self.entity.velocity[0] = -45; self.EntityDirection = 'left'; self.EntityDirection2 = 'left'", "self.entity.velocity[0] = 45; self.EntityDirection = 'right'; self.EntityDirection2 = 'right'", "self.entity.velocity[1] = -45; self.EntityDirection = 'up'; self.EntityDirection1 = 'up'", "self.entity.velocity[1] = 45; self.EntityDirection = 'down'; self.EntityDirection1 = 'down'"]) exec(movement) def EntityAnimation(self, direction, number, character="hero"): self.entVel = self.entity.velocity self.counter += 1 if self.EntityDirection1 == "still" and self.EntityDirection2 == "still": if self.EntityDirection == "left": self.entity = Entity('Tiles/' +character +'/walking_left/walking_left1.png') if self.EntityDirection == "right": self.entity = Entity('Tiles/' +character +'/walking_right/walking_right1.png') if self.EntityDirection == "up": self.entity = Entity('Tiles/' +character +'/walking_up/walking_up1.png') if self.EntityDirection == "down": self.entity = Entity('Tiles/' +character +'/walking_down/walking_down1.png') else: self.entity = Entity('Tiles/' +character +'/walking_' +direction +'/walking_' +direction +str(number) +'.png') self.entity.velocity = self.entVel def EntMoveBack(self): #self.deep_thought(self, True) # Comment this to disable the 'AI' pass def map_change(self, map, target=False): # Does what it says on the tin mapfile = get_map(map) tmx_data = load_pygame(mapfile) self.tmx_data = tmx_data map_data = pyscroll.data.TiledMapData(tmx_data) self.walls = list() for object in tmx_data.objects: self.walls.append(pygame.Rect( object.x, object.y, object.width, object.height)) # creates new 'camera' self.map_layer = pyscroll.BufferedRenderer(map_data, screen.get_size()) self.map_layer.zoom = 2 self.group = PyscrollGroup(map_layer=self.map_layer, default_layer=4) #creates a new Hero to go on our new camera self.hero = Hero('Tiles/hero/character_still.png') try: self.hero.position = (target) except TypeError: self.hero.position = self.map_layer.map_rect.center self.map = stats['map'][:-4].lower() self.map = self.map.lstrip("m") # Fix that stupid bug that changes "maze1" to "ze1" self.map = self.map.lstrip("aps/") def switcher(self): # Bunch of IF statements to decide if we're at a door or not, then changes the map. if len(objectX) == len(objectY) == len(targetPosX) == len(targetPosY) == len(currentMap) == \ len(targetMap) == len(animationDirection) == len(targetMapFile) == len(objectType): heroPos = [0, 0] heroPos[0], heroPos[1] = self.hero.position[0], self.hero.position[1] for i in range(len(objectX)): if self.map == currentMap[i]: if self.hero.position[0] - 15 <= int(objectX[i]) <= self.hero.position[0] + 15: if self.hero.position[1] - 15 <= int(objectY[i]) <= self.hero.position[1] + 15: if objectType[i] == "door": used[i] = True self.map_change(targetMapFile[i]) self.map = targetMap[i] stats['map'] = targetMapFile[i] heroPos = (int(targetPosX[i]), int(targetPosY[i])) self.animation(animationDirection[i], 1) self.hero.position = heroPos return False elif objectType[i] == "chest": keyset, self.menu = "chest", "chest" if used[i] == False: if chestContents[i] == None and used[i] == False: used[i] = True pickle.dump(used, open(os.path.join("data", "saves", "used.dat"), "wb")) chestContents[i] = self.genchests() pickle.dump(chestContents, open(os.path.join("data", "saves", "chestContents.dat"), "wb")) self.chestNo = i return False def generate_surrounding_maps(self): heroPos = [0, 0] heroPos = self.hero.position if int(self.hero.position[0]) in range((self.tmx_data.width*32)-64, (self.tmx_data.width*32)): target = (32, heroPos[1]) self.grid[0] = self.grid[0]+1 try: self.map_change(str(self.grid[0]+1) +", "+ str(self.grid[1]) +".tmx", target) self.map = str(self.grid).lstrip("[").rstrip("]") stats['map'] = self.map + ".tmx" self.animation("right", 1) target = (32, heroPos[1]) #self.hero.position = target except FileNotFoundError: self.generate_new_map(4, 16, 2, self.grid, target) elif int(self.hero.position[1]) in range((self.tmx_data.height*32)-64, self.tmx_data.width*32): target = (heroPos[0], 32) self.grid[1] = self.grid[1]+1 try: self.map_change(str(self.grid[0]) +", "+ str(self.grid[1]+1) +".tmx", target) self.map = str(self.grid).lstrip("[").rstrip("]") stats['map'] = self.map + ".tmx" heroPos[0], heroPos[1] = self.hero.position[0], self.hero.position[1] self.animation("up", 1) except FileNotFoundError: self.generate_new_map(4, 16, 2, self.grid, target) elif int(self.hero.position[0]) in range(0, 64): target = (self.tmx_data.width*32 - 32, heroPos[1]) self.grid[0] = self.grid[0]-1 try: self.map_change(str(self.grid[0]-1) +", "+ str(self.grid[1]) +".tmx", target) self.map = str(self.grid).lstrip("[").rstrip("]") stats['map'] = self.map + ".tmx" heroPos[0], heroPos[1] = self.hero.position[0], self.hero.position[1] self.animation("left", 1) #self.hero.position = target except FileNotFoundError: self.generate_new_map(4, 16, 2, self.grid, target) elif int(self.hero.position[1]) in range(0, 64): target = (heroPos[0], self.tmx_data.height*32 - 32) self.grid[1] = self.grid[1]-1 try: self.map_change(str(self.grid[0]) +", "+ str(self.grid[1]-1) +".tmx", target) self.map = str(self.grid).lstrip("[").rstrip("]") stats['map'] = self.map + ".tmx" heroPos[0], heroPos[1] = self.hero.position[0], self.hero.position[1] self.animation("down", 1) #self.hero.position = target except FileNotFoundError: self.generate_new_map(4, 16, 2, self.grid, target) else: pass def generate_new_map(self, octaves, freq, area, target, position): command = "{}/lib/generate/__init__.py".format(os.getcwd()) if sys.platform.startswith('win32'): executeable = ("Python35\python.exe") elif sys.platform.startswith('linux'): executeable = ("python3.5") for y in range(self.grid[1] + eval("-"+ str(area)),self.grid[1] + area): for x in range(self.grid[0] + eval("-"+ str(area)),self.grid[0] + area): if os.path.isfile("data/maps/"+str(x)+", "+str(y)+".tmx"): pass else: p = subprocess.Popen([executeable, command, ("data/maps/"+ str(x)+", "+str(y)+".tmx"), str(octaves), str(freq), str(x), str(y)], close_fds=True) try: if p is not None: disp_width, disp_height = pygame.display.get_surface().get_size() #self.blit_inventory("speach", "Generating Map... Please Wait...") self.speach(disp_width, disp_height, "Generating Map... Please Wait...") pygame.display.update() p.wait() self.map_change((str(target[0])+", "+str(target[1])+".tmx"), position) self.map = str(self.grid).lstrip("[").rstrip("]") stats['map'] = self.map + ".tmx" except UnboundLocalError: pass def draw(self, surface): self.group.center(self.hero.rect.center) # draw the map and all sprites self.group.draw(surface) def speach(self, dispWidth, dispHeight, text): ## text = "Laudem bonorum salutandi pri te, tollit melius delicata mel cu,\ ## eu mea ullum legimus. Probo debitis te vel. Labores vulputate \ ## argumentum sea id. Cibo vitae vocent eos no, ne odio molestiae\ ## duo." screen.blit(pygame.transform.scale(load_image(os.path.join( "images", "gui", "speach.png")), (dispWidth, 150)), (0, dispHeight-150)) text = textwrap.wrap(text, width=95) for i, line in enumerate(text): text_blit = pixel_font.render(line, False, pygame.Color('white')) screen.blit(text_blit, (60, dispHeight-110 + 25*i)) def map_generate(self, output, octaves, freq, x, y): command = "{}/lib/generate/__init__.py".format(os.getcwd()) if sys.platform.startswith('win32'): executeable = ("Python35\python.exe") elif sys.platform.startswith('linux'): executeable = ("python3.5") subprocess.Popen([executeable, command, output, str(octaves), str(freq), str(x), str(y)],close_fds=True) def handle_input(self, keyset): """ Handle pygame input events """ poll = pygame.event.poll event = poll() while event: if event.type == QUIT: self.running = False pygame.quit() break elif event.type == KEYDOWN: if keyset == "game": if event.key == K_EQUALS: self.map_layer.zoom += .25 elif event.key == K_MINUS: value = self.map_layer.zoom - .25 if value > 0: self.map_layer.zoom = value else: self.map_layer.zoom = 0.1 elif event.key == K_KP0: try: if self.switcher() == True: self.generate_surrounding_maps() except FileNotFoundError: print("Exception Caught") pass elif event.key == K_e: self.menu = "inventory" pass if event.key == K_ESCAPE: for i in attack_stats_types: stats[i] = attack_stats[i] pickle.dump(stats, open(os.path.join("data", "saves", "save.dat"), "wb")) pickle.dump(inventory, open(os.path.join("data", "saves", "inventory.dat"), "wb")) self.running = False pygame.quit() print(" ") sleep(0.5) print("Shutdown... Complete") sys.exit() break if keyset != "game": if event.key == K_ESCAPE: self.menu = "game" pass if keyset == "inventory": if event.key == K_r: self.genchests() if keyset == "chest": if event.key == K_r: chestContents[self.chestNo] = self.genchests() if event.key == K_t: if taken[self.chestNo] != True: self.takeChest() taken[self.chestNo] = True pickle.dump(taken, open(os.path.join("data", "saves", "taken.dat"), "wb")) if keyset == "attack": pass #Basically just debug keys if event.key == K_KP1: self.menu = "game" pass elif event.key == K_KP2: self.map_change(FOREST) self.map = "forest" elif event.key == K_KP3: self.generate_new_map(4, 16, 3) pass elif event.key == K_KP4: self.map_generate(str(self.grid[0]) +", "+ str(self.grid[1]) +".tmx", 4, 16.0, self.grid[0], self.grid[1]) pass elif event.key == K_KP5: self.enemy_stats = self.gen_enemy(attack_stats, enemy_stats) self.menu = "attack" pass elif event.key == K_KP6: print("X :" +str(int(self.hero.position[0])) + ", Y: " +str(int(self.hero.position[1])) + ", Map: "+ self.map) pass elif event.key == K_KP7: print(str(pygame.mouse.get_pos())) pass elif event.key == K_KP8: sleep(0.5) elif event.key == K_KP9: editor = db_interface.Editor() conn = sqlite3.connect('data/saves/data.db') c = conn.cursor() for var in vars: exec("del "+var+"[:]") for data in c.execute("SELECT {} FROM csv".format(var)): data = str(data[0]) exec("{}.append(\"{}\")".format(var, data)) pass elif event.key == K_F11: for m in screeninfo.get_monitors(): displ = str(m) w, h, mx, c = displ.split(", ") if self.fullscreen: self.fullscreen = False screen = init_screen(1024, 700, pygame.HWSURFACE | pygame.FULLSCREEN ) else: self.fullscreen = True screen = init_screen(w, h, pygame.HWSURFACE | pygame.RESIZABLE ) pygame.display.toggle_fullscreen() elif event.type == VIDEORESIZE: self.map_layer.set_size((event.w, event.h)) dispHeight = event.h dispWidth = event.w event = poll() # using get_pressed is slightly less accurate than testing for events # but is much easier to use. if keyset == "game": pressed = pygame.key.get_pressed() if pressed[K_UP]: self.hero.velocity[1] = -HERO_MOVE_SPEED self.direction = "up" self.direction2 = "up" elif pressed[K_DOWN]: self.hero.velocity[1] = HERO_MOVE_SPEED self.direction = "down" self.direction2 = "down" elif pressed[K_w]: self.hero.velocity[1] = -HERO_SPRINT_SPEED self.direction = "up" self.direction2 = "up" elif pressed[K_s]: self.hero.velocity[1] = HERO_SPRINT_SPEED self.direction = "down" self.direction2 = "down" else: self.hero.velocity[1] = 0 self.direction2 = "still" if pressed[K_LEFT]: self.hero.velocity[0] = -HERO_MOVE_SPEED self.direction = "left" self.direction1 = "left" elif pressed[K_RIGHT]: self.hero.velocity[0] = HERO_MOVE_SPEED self.direction = "right" self.direction1 = "right" elif pressed[K_a]: self.hero.velocity[0] = -HERO_SPRINT_SPEED self.direction = "left" self.direction1 = "left" elif pressed[K_d]: self.hero.velocity[0] = HERO_SPRINT_SPEED self.direction = "right" self.direction1 = "right" else: self.hero.velocity[0] = 0 self.direction1 = "still" if self.direction1 == "still" and self.direction2 == "still": self.direction = "still" def update(self, dt): """ Tasks that occur over time should be handled here """ self.group.update(dt) # check if the sprite's feet are colliding with wall # sprite must have a rect called feet, and move_back method, # otherwise this will fail for sprite in self.group.sprites(): if sprite.feet.collidelist(self.walls) > -1: sprite.move_back(dt) def animation(self, direction, number): if self.direction1 == "still" and self.direction2 == "still": if self.direction == "left": self.hero = Hero('Tiles/hero/walking_left/walking_left1.png') if self.direction == "right": self.hero = Hero('Tiles/hero/walking_right/walking_right1.png') if self.direction == "up": self.hero = Hero('Tileshero/walking_up/walking_up1.png') if self.direction == "down": self.hero = Hero('Tiles/hero/walking_down/walking_down1.png') else: self.hero = Hero('Tiles/hero/walking_' +direction +'/walking_' +direction +str(number) +'.png') def genchests(self): wr = WeightedRandomizer(itemsProbability) self.taken = False chest.clear() numItems = random.randint(1, random.randint(2, 4)) if random.randint(0, 3) < 1: numItems += 1 elif random.randint(0, 9) < 2: numItems += 2 elif random.randint(0, 18) < 2: numItems += 5 for i in range(0, numItems): item = wr.random() while item in chest: item = wr.random() chest.append(item) return chest def gen_enemy(self, player_stats, enemy_stat): stats = attack_stats_types stat = player_stats for i in range(len(player_stats)): j = stats[i] try: enemy_stat[stats[i]] = int((stat[j]-(stat[j]*0.2)) + random.randint(0, int(stat[j]*0.4))) except TypeError: enemy_stat[j] = choice(attack_types) return enemy_stat pass def player_attack(): type = None while type not in attack_types: type = input("[ QUESTION ] Enter attack type. ") if type not in attack_types: print("[ ERROR ] Attack type {} not found. Must be {}".format(type, attack_types)) else: break return type pass def attack(self, attacker_stats, defender_stats, player_attack_type): fraction = attacker_stats['strength'] / defender_stats['blocking'] print("[ INFO ] Defender attack type: {}".format(defender_stats['attack'])) if player_attack_type != defender_stats['attack']: if fraction > (0.8 + (randint(0, 40)/100)): attacker_stats['health'] -= int(fraction*10) pass # Attacker Win else: defender_stats['health'] -= int(fraction*10) pass # Attacker Loss elif player_attack_type == attacker_stats['attack']: # Better odds here if fraction > (0.9 + (randint(0, 40)/100)): attacker_stats['health'] -= int(fraction*10) pass # Attacker Win else: defender_stats['health'] -= int(fraction*10) pass # Attacker Loss else: if fraction > (0.70 + (randint(0, 40)/100)): # Odds are worse here attacker_stats['health'] -= int(fraction*10) pass # Attacker Win else: defender_stats['health'] -= int(fraction*10) pass # Attacker Loss print("[ INFO ] Attacker: {} Defender: {}".format(attacker_stats['health'], defender_stats['health'])) print("[ INFO ] Health to be lost: {}".format(int(fraction*10))) return attacker_stats, defender_stats def blit_inventory(self, screenMode, speach=None): if screenMode != "game": xCounter, counter, OverCounter = 0, 0, 0 dispWidth, dispHeight = pygame.display.get_surface().get_size() guiX = (dispWidth / 2) - 175 guiY = (dispHeight / 2) - 165 screen.blit(load_image(os.path.join("images", "gui", "transparent.png")),( 0, 0)) screen.blit(load_image(os.path.join("images", "gui", screenMode +".png")),(guiX, guiY)) if screenMode == "inventory" or screenMode == "chest": dt = (clock.tick() / 500) clock.tick(self.fps) if len(inventory) > 0: for i in range(0, len(inventory)): OverCounter += 1 if xCounter >= 9: counter += 1 xCounter = 0 screen.blit(load_image(os.path.join("images", "items",\ str(items[inventory[i]])+".png")), (guiX + 16 + 36*xCounter, guiY + 168 + 36*counter)) xCounter += 1 if screenMode == "chest" and chestContents[self.chestNo] != None: itemNo = 0 for i in range(0, len(chestContents[self.chestNo])): screen.blit(load_image(os.path.join("images", "items",\ items[str(chestContents[self.chestNo][i])]\ +".png")), (guiX + 123 + 36*itemNo,\ guiY + 34 + int(35 * (i/3)) - int(35 * (i/3)) % 35)) if itemNo < 2: itemNo += 1 else: itemNo = 0 if screenMode == "speach": self.speach(dispWidth, dispHeight, speach) if screenMode == "attack": picture = load_image(os.path.join("Tiles", "hero", "walking_down", "walking_down1.png")) picture = pygame.transform.scale(picture, (100, 100)) rect = picture.get_rect() rect = rect.move((guiX + 50, guiY + 28)) screen.blit(picture, rect) text = font.render("Player : Enemy", True, pygame.Color('black')) screen.blit(text, (guiX + 172, guiY + 45)) text = "Health: "+str(attack_stats['health'])+" Skill: "+str(attack_stats['skill'])+" Attack: "+str(attack_stats['attack']) text_render = pixel_font.render(text, False, pygame.Color('gray27')) screen.blit(text_render, (guiX+20, guiY+290)) for i, attack in enumerate(attack_types): text = load_font(30, "data/PixelFont.ttf").render(attack, False, pygame.Color('black')) screen.blit(text, (guiX+172, guiY+25+28*(i+2))) # if pygame.mouse.get_pressed()[0] == 1: #print(pygame.mouse.get_pos()) mouse_pos = pygame.mouse.get_pos() if guiX+160 < mouse_pos[0] and guiX+330 > mouse_pos[0]: for i, attack in enumerate(attack_types): if guiY+25+28*(i+2) < mouse_pos[1] and (guiY+25+28*(i+2))+28 > mouse_pos[1]: print(attack) self.attack(attack_stats, enemy_stats, attack) else: pass pass def takeChest(self): if len(inventory) < 27: if chestContents[self.chestNo] != None: for i in range(0, (len(chestContents[self.chestNo]))): #print(i) inventory.append(chestContents[self.chestNo][i]) chestContents[self.chestNo][:] = [] pickle.dump(chestContents, open(os.path.join("data", "saves", "chestContents.dat"), "wb")) def run(self): screenMode = pygame.RESIZABLE oldPlay = stats['playTime'] clock = pygame.time.Clock() self.running = True self.grid = [0, 0] debug = True dispWidth, dispHeight = 1024, 768 self.menu = "game" game_time = pygame.time.get_ticks() playTime = font.render("Timer: ", False, pygame.Color('white')) minutes = 0 self.map = stats['map'][:-4].lower() self.map = self.map.lstrip("m") # Fix that stupid bug that changes "maze1" to "ze1" self.map = self.map.lstrip("aps/") try: while self.running: dt = (clock.tick() / 500) clock.tick(self.fps) if self.menu == "game": #self.deep_thought() if self.counter2 % 7 == 0: heroPos = self.hero.position self.animation(self.direction, self.counter) self.hero.position = heroPos #entityPos = self.entity.position #self.EntityAnimation(self.EntityDirection, self.counter, "princess") #self.entity.position = entityPos self.counter += 1 guiX = (dispWidth / 2) - 175 guiY = (dispHeight / 2) - 165 self.group.remove(self.hero) #self.group.remove(self.entity) self.group.empty() self.group.add(self.hero) #self.group.add(self.entity) self.counter2 += 1 if self.counter > 8: self.counter = 1 stats['pos'] = self.hero.position currentTime = systime() seconds = currentTime - gameStart + oldPlay dispWidth, dispHeight = pygame.display.get_surface().get_size() stats['playTime'] = seconds if debug == True and self.counter2 % 1 == 0: location = font.render("Position: " + str(round(round(self.hero.position[0], -1) / 10)) + ", " + str(round(round(self.hero.position[1], -1) / 10)), False, pygame.Color('white')) mapdebug = font.render("Map Name: " + str(self.map), False, pygame.Color('white')) minutes = seconds // 60 secondsDisp = seconds % 60 if minutes < 1: minutes = 0 if secondsDisp == 60: secondsDisp = 0 minutes += 1 fps = font.render("FPS:" + str(int(clock.get_fps())), False, pygame.Color('white')) screen.blit(fps, (50, 50)) screen.blit(playTime, (50,100)) screen.blit(location, (50,75)) screen.blit(mapdebug, (50, 125)) playTime = font.render("Timer: " + str(floor(minutes)) + " : " + str(round(secondsDisp)), True, pygame.Color('white')) screen.blit(playTime, (50,100)) self.blit_inventory(str(self.menu)) pygame.display.update() #pygame,display.flip() self.handle_input(self.menu) self.update(dt) self.draw(screen) except KeyboardInterrupt: self.running = False pygame.quit()
class LevelPlay(tools._State): def __init__(self): super(LevelPlay, self).__init__() tmx_data = load_pygame(MAP['map0']) map_data = pyscroll.data.TiledMapData(tmx_data) self.map_rect = pg.Rect(0, 0, map_data.map_size[0] * map_data.tile_size[0], map_data.map_size[1] * map_data.tile_size[1]) self.map_layer = pyscroll.BufferedRenderer(map_data, SCREEN_SIZE) self.map_layer.zoom = 1 self.group = PyscrollGroup(map_layer=self.map_layer, default_layer=2) self.animations = pg.sprite.Group() self.labels = pg.sprite.Group() self.enemies = pg.sprite.Group() self.coins = pg.sprite.Group() self.pos_x = None self.pos_y = None self.pos_x_r = None self.pos_y_r = None self.upper_world = False self.time = 0 self.timer = TIME self.coin_num = 0 self.player_lives = 0 self.hud = Hud() self.walls = list() for object in tmx_data.objects: if object.name == 'collide': self.walls.append( pg.Rect(object.x, object.y, object.width, object.height)) elif object.name == 'playerpos': self.pos_x = object.x self.pos_y = object.y self.player = Player(self.pos_x, self.pos_y, False, self.group) elif object.name == 'playerpos_r': self.pos_x_r = object.x self.pos_y_r = object.y elif object.name == 'enemy': Enemy(object.x, object.y, self.enemies) elif object.name == 'fish': Fish(object.x, object.y, self.enemies) elif object.name == 'fly': Fly(object.x, object.y, self.enemies) elif object.name == 'coin': Coin(object.x, object.y, self.coins) elif object.name == 'bat': Bat(object.x, object.y, self.enemies) elif object.name == 'enimy': Enimy(object.x, object.y, self.enemies) elif object.name == 'f1sh': F1sh(object.x, object.y, self.enemies) elif object.name == 'over_event': self.over_rect = pg.Rect(object.x, object.y, object.width, object.height) elif object.name == 'over_event_r': self.over_rect_r = pg.Rect(object.x, object.y, object.width, object.height) self.player.platform = self.walls def get_event(self, event): self.player.get_event(event) if event.type == pg.QUIT: self.quit = True elif event.type == pg.KEYDOWN: if event.key == pg.K_SPACE: self.map_layer.zoom = 0.5 elif event.type == pg.KEYUP: if event.type == pg.K_ESCAPE: self.quit = True elif event.key == pg.K_SPACE: self.map_layer.zoom = 1 else: pass def startup(self, persist): pg.mixer.init() song = MUSIC['bg'] pg.mixer.music.load(song) pg.mixer.music.set_volume(0.1) pg.mixer.music.play() self.done = False self.persist = persist self.mask = self.persist['surface'] self.transition = Transition(self.mask) self.player_lives = self.persist['lives'] self.coin_num = self.persist['coins'] if self.player.reverse == True: self.fog = pg.Surface(SCREEN_RECT.size, pg.SRCALPHA) self.fog_color = (0, 0, 0, 200) self.fog.fill(self.fog_color) def player_dead(self): sound = SFX['dead0'] sound.play() self.player_lives -= 1 if self.player_lives < 1: self.done = True self.next = 'LOSE' buffer = pg.display.get_surface() self.switch_screen = Transition(buffer) if self.player.reverse == False: self.player.rect.x, self.player.rect.y = self.pos_x, self.pos_y elif self.player.reverse == True: self.player.rect.x, self.player.rect.y = self.pos_x_r, self.pos_y_r def update(self, dt): self.offset_x, self.offset_y = self.group._map_layer.get_center_offset( ) self.time += dt if self.time > self.timer: self.time -= self.timer self.player_dead() self.group.update(dt) self.enemies.update(dt) self.coins.update(dt) self.hud.update(self, dt) self.animations.update(dt) if self.player.rect.colliderect(self.over_rect_r): if self.player.reverse == True: self.done = True self.next = 'WIN' if self.player.rect.colliderect(self.over_rect): self.player.rect.x, self.player.rect.y = self.pos_x_r, self.pos_y_r if self.coin_num >= 30: self.player.kill() self.player = Player(self.pos_x_r, self.pos_y_r, True, self.group) self.player.platform = self.walls self.done = True self.next = 'UPPER' elif self.coin_num < 30: self.player.reverse = False self.done = True self.next = 'BOTUP' if pg.sprite.spritecollide(self.player, self.coins, True): self.coin_num += 1 sound = SFX['coin'] sound.play() self.labels.empty() self.animations.empty() coin_sprite = pg.sprite.Sprite(self.labels) coin_sprite.image = GFX['hud_coins'] x = self.offset_x + self.player.rect.x y = self.offset_y + self.player.rect.y coin_sprite.rect = pg.Rect((x, y), coin_sprite.image.get_size()) ani = Animation(x=50, y=10, duration=100, transition="out_bounce") ani.start(coin_sprite.rect) self.animations.add(ani) if not self.map_rect.contains(self.player.rect): self.player_dead() if pg.sprite.spritecollide(self.player, self.enemies, False): self.player_dead() self.labels.update(dt) def cleanup(self): pg.mixer.quit() self.persist = {} self.persist['coins'] = self.coin_num self.persist['lives'] = self.player_lives self.persist['surface'] = pg.display.get_surface() return self.persist def draw(self, surface): self.group.empty() if self.player.reverse == True: close = (enemy for enemy in self.enemies if get_distance( enemy.rect.center, self.player.rect.center) <= 100) close_enemies = pg.sprite.Group(close) self.group.add(self.player, self.coins, close_enemies) elif self.player.reverse == False: close = (enemy for enemy in self.enemies if get_distance( enemy.rect.center, self.player.rect.center) <= SCREEN_SIZE[0]) close_enemies = pg.sprite.Group(close) self.group.add(self.player, self.coins, close_enemies) self.group.draw(surface) self.group.center(self.player.rect.center) if hasattr(self, 'fog') and self.map_layer.zoom == 1: self.fog.fill(self.fog_color) for i in range(200): pg.draw.circle(self.fog, pg.Color(0, 0, 0, 200 - i), (self.player.rect.centerx + self.offset_x, self.player.rect.centery + self.offset_y), int(100 - i * 0.5)) surface.blit(self.fog, (0, 0)) elif hasattr(self, 'fog') and self.map_layer.zoom == 0.5: self.fog.fill(self.fog_color) surface.blit(self.fog, (0, 0)) self.hud.draw(surface) self.transition.draw(surface) self.labels.draw(surface) if hasattr(self, 'switch_screen'): self.switch_screen.draw(surface)
class TravelGame(object): filename = get_map('testing.tmx') def __init__(self, *args, **kwargs): self.running = False tilemap_data = load_pygame(self.filename) map_data = pyscroll.data.TiledMapData(tilemap_data) self.map_layer = pyscroll.BufferedRenderer(map_data, screen.get_size(), clamp_camera=False) self.map_layer.zoom = 5 self.group = PyscrollGroup(map_layer=self.map_layer, default_layer=4) self.player = Player() self.player.position = (128, 248) self.group.add(self.player) self.blockers = [] for obj in tilemap_data.get_layer_by_name("collision"): properties = obj.__dict__ if properties['name'] == 'blocker': x = properties['x'] y = properties['y'] width = properties['width'] height = properties['height'] new_rect = pygame.Rect(x, y, width, height) self.blockers.append(new_rect) def draw(self, surface): self.group.center(self.player.rect.center) self.group.draw(surface) def handle_input(self): poll = pygame.event.poll event = poll() while event: if event.type == QUIT: self.running = False break event = poll() pressed = pygame.key.get_pressed() if pressed[K_DOWN]: self.player.vely = SPEED elif pressed[K_UP]: self.player.vely = -SPEED else: self.player.vely = 0 if pressed[K_LEFT]: self.player.velx = -SPEED elif pressed[K_RIGHT]: self.player.velx = SPEED else: self.player.velx = 0 # TODO Fix collision so they player stops when they hit a collider for blocker in self.blockers: if self.player.rect.colliderect(blocker): print("collide") def update(self, dt): self.group.update(dt) def run(self): clock = pygame.time.Clock() self.running = True from collections import deque times = deque(maxlen=30) try: while self.running: dt = clock.tick() / 1000. times.append(clock.get_fps()) self.handle_input() self.update(dt) self.draw(screen) pygame.display.flip() except KeyboardInterrupt: self.running = False