def __init__(self): os.environ['SDL_VIDEO_CENTERED'] = '1' pygame.init() self.screen = pygame.display.set_mode((SCREENWIDTH, SCREENHEIGHT), pygame.DOUBLEBUF) # | pygame.FULLSCREEN) self.background = pygame.Surface(self.screen.get_size()) self.background.fill(BLACK) self.background = self.background.convert() self.window = pygame.Surface((WINDOWWIDTH, WINDOWHEIGHT)) self.window.fill(DARKGRAY) self.window = self.window.convert() self.state = StateMachine() self.running = False self.clock = pygame.time.Clock() self.playtime = 0 self.milliseconds = 0 self.timer = 0 self.debugfont = pygame.font.SysFont('courier', 11) self.titlefont = pygame.font.SysFont('sans', 25, True) self.key_input = None self._init_map() self._init_units() self._init_buttons() self.pointer_sprite = PointerSprite(POINTERLAYER) self.group.add(self.pointer_sprite) self.moverange_sprite = MoveRangeSprite(MOVERANGESIZE, MOVERANGELAYER) self.cu = 0 self.show_grid = False self.show_cbox = False self.show_debug = False self.scroll_timer = 0 self.scroll_step = [0, 0] self.scroll_current = [0, 0] self.start_of_turn()
class BattleScreen(object): """ De grafische weergave van het scherm. """ def __init__(self): os.environ['SDL_VIDEO_CENTERED'] = '1' pygame.init() self.screen = pygame.display.set_mode((SCREENWIDTH, SCREENHEIGHT), pygame.DOUBLEBUF) # | pygame.FULLSCREEN) self.background = pygame.Surface(self.screen.get_size()) self.background.fill(BLACK) self.background = self.background.convert() self.window = pygame.Surface((WINDOWWIDTH, WINDOWHEIGHT)) self.window.fill(DARKGRAY) self.window = self.window.convert() self.state = StateMachine() self.running = False self.clock = pygame.time.Clock() self.playtime = 0 self.milliseconds = 0 self.timer = 0 self.debugfont = pygame.font.SysFont('courier', 11) self.titlefont = pygame.font.SysFont('sans', 25, True) self.key_input = None self._init_map() self._init_units() self._init_buttons() self.pointer_sprite = PointerSprite(POINTERLAYER) self.group.add(self.pointer_sprite) self.moverange_sprite = MoveRangeSprite(MOVERANGESIZE, MOVERANGELAYER) self.cu = 0 self.show_grid = False self.show_cbox = False self.show_debug = False self.scroll_timer = 0 self.scroll_step = [0, 0] self.scroll_current = [0, 0] self.start_of_turn() def _init_map(self): """ Laad de tmx data en maak daaruit een group variabele. Maak een grid aan en een map. Vul bomen, waters en obstacles. """ tmx_data = pytmx.load_pygame(MAPPATH) map_data = pyscroll.data.TiledMapData(tmx_data) map_layer = pyscroll.BufferedRenderer(map_data, (WINDOWWIDTH, WINDOWHEIGHT), clamp_camera=True) self.group = pyscroll.PyscrollGroup(map_layer=map_layer, default_layer=PLAYERLAYER) self.grid_sprite = GridSprite(tmx_data.width * tmx_data.tilewidth, tmx_data.height * tmx_data.tileheight, GRIDSIZE, GRIDLAYER) self.map1 = Map(tmx_data) for rect in tmx_data.get_layer_by_name("trees"): self.map1.add_rect_to_list(rect, self.map1.tree_rects) self.map1.add_rect_to_list(rect, self.map1.obstacle_rects) for rect in tmx_data.get_layer_by_name("water"): self.map1.add_rect_to_list(rect, self.map1.water_rects) self.map1.add_rect_to_list(rect, self.map1.low_obst_rects) for rect in tmx_data.get_layer_by_name("warphole"): self.map1.warphole_rect = pygame.Rect(rect.x, rect.y, rect.width, rect.height) def _init_units(self): """ Maak een lijst van units aan. Zet de party sprites erin. Voeg ze toe aan de view groep. """ self.units = [] i = 0 for hero in data.party: self.units.append(UnitSprite(hero.BMP, [320 + i * 32, 320 + i * 32])) # todo, dit moet nog de echte hero class worden i += 1 self.group.add(self.units) def _init_buttons(self): """ Maak de knoppen aan en zet ze in een lijst. Plaats ook de bijbehorende keys in een lijst. """ button_view = ButtonSprite((SCREENWIDTH-200, SCREENHEIGHT-300), "V", pygame.K_v) button_up = ButtonSprite((SCREENWIDTH-150, SCREENHEIGHT-300), "Up", pygame.K_UP) button_down = ButtonSprite((SCREENWIDTH-150, SCREENHEIGHT-250), "Down", pygame.K_DOWN) button_left = ButtonSprite((SCREENWIDTH-200, SCREENHEIGHT-250), "Left", pygame.K_LEFT) button_right = ButtonSprite((SCREENWIDTH-100, SCREENHEIGHT-250), "Right", pygame.K_RIGHT) button_cancel = ButtonSprite((SCREENWIDTH-100, SCREENHEIGHT-200), "C", pygame.K_c) self.buttons = [button_view, button_up, button_down, button_left, button_right, button_cancel] def run(self): """ Start de game loop. """ self.running = True self.state.push(State.Play) self.state.push(State.Intro) while self.running: self.milliseconds = self.clock.tick(FPS) # limit the redraw speed to 60 frames per second self.playtime += self.milliseconds currentstate = self.state.peek() self.handle_view(currentstate) self.handle_multi_input(currentstate) for event in pygame.event.get(): if event.type == pygame.QUIT: self.running = False self.handle_single_input(event, currentstate) self.handle_triggers(currentstate) pygame.quit() def handle_view(self, currentstate): """ Laat de weergave van de verschillende states zien. :param currentstate: bovenste state van de stack """ if currentstate == State.Intro: self.handle_timer(INTROTIME, currentstate) self.render_intro() if currentstate == State.Play: self.render_play(self.units[self.cu].rect.center) if currentstate == State.Menu: self.render_menu() if currentstate == State.Help: self.render_help() if currentstate == State.Scroll: if self.playtime > self.scroll_timer + SCROLLTIME: self.render_play(self.scroll_current) self.scroll_timer = 0 self.scroll_step = [0, 0] self.scroll_current = [0, 0] self.state.pop(currentstate) else: self.render_play(self.scroll_current) self.scroll_current[0] -= self.scroll_step[0] * self.milliseconds self.scroll_current[1] -= self.scroll_step[1] * self.milliseconds if currentstate == State.View: self.render_play(self.pointer_sprite.rect.center) pygame.display.flip() self.screen.blit(self.background, (0, 0)) def handle_multi_input(self, currentstate): """ Handelt de ingedrukt-houden muis en keyboard input af. :param currentstate: bovenste state van de stack """ self.key_input = pygame.key.get_pressed() if pygame.mouse.get_pressed()[0]: pos = pygame.mouse.get_pos() for button in self.buttons: if button.rect.collidepoint(pos): self.key_input = list(self.key_input) self.key_input[button.key] = 1 if currentstate == State.Play: self.units[self.cu].speed(self.key_input) self.units[self.cu].direction(self.key_input) self.units[self.cu].check_obstacle(self.map1.obstacle_rects, self.map1.low_obst_rects, self.moverange_sprite, self.map1.width, self.map1.height) if currentstate == State.View: self.pointer_sprite.move(self.key_input, self.map1.width, self.map1.height) def handle_single_input(self, event, currentstate): """ Handelt de muis en keyboard input af. :param event: pygame.event.get() :param currentstate: bovenste state van de stack """ key_input = None if event.type == pygame.KEYDOWN: # handle key down events print("Keyboard, key={}, unicode={}".format(event.key, event.unicode)) if event.key == pygame.K_c: key_input = 'c' elif event.key == pygame.K_v: key_input = 'v' if currentstate == State.Menu: if event.key == pygame.K_ESCAPE: self.running = False elif event.key == pygame.K_SPACE: self.state.pop(currentstate) if currentstate == State.Help: if event.key in [pygame.K_ESCAPE, pygame.K_SPACE, pygame.K_RETURN]: self.state.pop(currentstate) if currentstate == State.Play: if event.key == pygame.K_ESCAPE: self.state.push(State.Menu) elif event.key == pygame.K_SPACE: self.units[self.cu].align_to_grid(TILESIZE) elif event.key == pygame.K_F1: self.state.push(State.Help) elif event.key == pygame.K_F10: self.show_grid ^= True elif event.key == pygame.K_F11: self.show_cbox ^= True elif event.key == pygame.K_F12: self.show_debug ^= True # simple boolean swith if event.type == pygame.MOUSEBUTTONDOWN: # handle mouse down events print("Mouse, pos={}, button={}".format(event.pos, event.button)) if event.button == 1: for button in self.buttons: if button.rect.collidepoint(event.pos): if button.key == pygame.K_c: key_input = 'c' elif button.key == pygame.K_v: key_input = 'v' if currentstate == State.View: if key_input == 'c' or key_input == 'v': self.state.pop(currentstate) scroll_begin = list(self.pointer_sprite.rect.center) scroll_end = list(self.units[self.cu].rect.center) self.start_of_scroll(scroll_begin, scroll_end) if currentstate == State.Play: if key_input == 'c': self.end_of_turn() elif key_input == 'v': self.units[self.cu].stand() self.units[self.cu].animate() self.state.push(State.View) def handle_triggers(self, currentstate): """ Handelt de triggers en conditions af. :param currentstate: bovenste state van de stack """ if currentstate == State.Play: if self.units[self.cu].rect.colliderect(self.map1.warphole_rect): self.state.push(State.Menu) import game game.PartyWindow(None).ShowModal() print("Warp!") def handle_timer(self, wait_time, currentstate): """ Laat het spel een bepaalde tijd in de huidige state verblijven. Na de bepaalde tijd, pop de state. :param wait_time: is de ingestelde wachttijd :param currentstate: bovenste state van de stack """ if self.timer == 0: self.timer = self.playtime if self.playtime > self.timer + wait_time: self.timer = 0 self.state.pop(currentstate) def render_intro(self): """ Render the game intro. """ bg_rect = self.background.get_rect() somewords = self.titlefont.render('Battle...!', True, GREEN) text_rect = somewords.get_rect() text_rect.center = bg_rect.width/2, bg_rect.height/2 self.screen.blit(somewords, text_rect.topleft) def render_play(self, center_pixel): """ Render the game play. :param center_pixel: de pixel op de map waar het midden van de window op moet locaten """ def draw_grid(): """ Voeg de grid toe aan de group om hem weer te laten geven. """ if self.show_grid: self.group.add(self.grid_sprite) else: self.group.remove(self.grid_sprite) def draw_cboxes(): """ Voeg de gekleurde rects toe aan de group om ze weer te laten geven. Ga in de group de spritelist langs en bekijk of er ColorBoxSprites tussen zitten. Indien zo, verwijder die. Als F11 aanstaat, voeg de cbox_sprites list weer toe aan de group. """ for sprite in self.group: if isinstance(sprite, ColorBoxSprite): self.group.remove(sprite) if self.show_cbox: self.map1.current_sprite.rect.topleft = self.units[self.cu].rect.topleft self.group.add(self.map1.cbox_sprites) self.group.add(self.map1.current_sprite) def draw_moverange(): """ Als moverange niet in de group zit (en dat gebeurt bij end_of_turn, want daar wordt hij eruit gehaald). En hij is niet aan het scrollen. Update dan de moverange van plaats en voeg hem weer toe aan de group. Dit gebeurt steeds maar eenmalig aan het begin van een beurt. Toch zijn deze twee regels uit start_of_turn gehaald, want anders zou hij de moverange al updaten tijdens het scrollen, en dat is niet de bedoeling. Vandaar deze oplossing. Ik weet nog niet of hij wel netjes is aangezien ik nog een keer op currentstate check, en op scrollen. """ if self.moverange_sprite not in self.group: currentstate = self.state.peek() if currentstate != State.Scroll: self.moverange_sprite.update(self.units[self.cu].rect.center) self.group.add(self.moverange_sprite) def show_window(): """ Tekent alles in de window. """ somewords = self.titlefont.render('This is the play screen. Esc for Menu. F1 for help', True, GREEN) self.pointer_sprite.update(center_pixel) self.group.center(center_pixel) self.group.draw(self.window) self.window.blit(somewords, (0, 0)) self.screen.blit(self.window, WINDOWPOS) def show_buttons(): """ Tekent de knoppen op het scherm. """ for button in self.buttons: button.draw(self.screen, self.key_input) def show_debug(): """ Geeft debug informatie weer linksboven in het scherm. """ if self.show_debug: cu = self.units[self.cu] text = ("FPS: {}".format(int(self.clock.get_fps())), "milliseconds: {}".format(int(self.milliseconds)), "playtime: {}".format(int(self.playtime)), "time_up: {}".format(cu.time_up), "time_down: {}".format(cu.time_down), "time_left: {}".format(cu.time_left), "time_right: {}".format(cu.time_right), "time_delay: {}".format(cu.time_delay), "cu: {}".format(self.cu), "last_direction: {}".format(cu.last_direction), "move_direction: {}".format(cu.move_direction), "movespeed: {}".format(cu.movespeed), "start_position.x: {}".format(self.map1.start_pos_rect.x), "start_position.y: {}".format(self.map1.start_pos_rect.y), "old_position.x: {}".format(cu.old_position[0]), "old_position.y {}".format(cu.old_position[1]), "new_position.x: {}".format(cu.rect.x), "new_position.y {}".format(cu.rect.y), "pointer.x: {}".format(self.pointer_sprite.rect.centerx), "pointer.y: {}".format(self.pointer_sprite.rect.centery), "step_count: {}".format(cu.step_count), "step_animation: {}".format(cu.step_animation), ) for count, line in enumerate(text): self.screen.blit(self.debugfont.render(line, True, WHITE), (0, count * 10)) draw_grid() draw_cboxes() draw_moverange() show_window() show_buttons() show_debug() def render_menu(self): """ Render the game menu. """ somewords = self.titlefont.render('You are in the Menu. Space to play. Esc exits.', True, GREEN) self.screen.blit(somewords, (0, 0)) def render_help(self): """ Render the help screen. """ somewords = self.titlefont.render('Help is here. space, escape or return.', True, GREEN) self.screen.blit(somewords, (0, 0)) def start_of_turn(self): """ Vul de lijst van hero_rects met de actuele rects van de units. Als een unit nog niet in de obstacles staat, voeg hem toe. Verwijder de huidige hero van hero_rects en obstacles. Voeg de start positie toe, voeg de current_spirte toe. Vernieuw de cbox lijst volledig. """ for unit in self.units: if unit.rect not in self.map1.hero_rects: self.map1.add_rect_to_list(unit.rect, self.map1.hero_rects) if unit.rect not in self.map1.obstacle_rects: self.map1.add_rect_to_list(unit.rect, self.map1.obstacle_rects) self.map1.del_rect_from_list(self.units[self.cu].rect, self.map1.hero_rects) self.map1.del_rect_from_list(self.units[self.cu].rect, self.map1.obstacle_rects) self.map1.start_pos_rect = pygame.Rect(self.units[self.cu].rect) self.map1.current_sprite = ColorBoxSprite(self.units[self.cu].rect, 'hero', GRIDLAYER) self.map1.clear_cbox() self.map1.add_all_lists_to_cbox() def end_of_turn(self): """ Laat de huidige unit afronden, kies een volgende unit uit de party. Begin scrollen. """ self.units[self.cu].align_to_grid(TILESIZE) self.units[self.cu].stand() self.units[self.cu].animate() self.group.remove(self.moverange_sprite) scroll_begin = list(self.units[self.cu].rect.center) self.cu += 1 if self.cu > len(data.party) - 1: self.cu = 0 scroll_end = list(self.units[self.cu].rect.center) self.start_of_scroll(scroll_begin, scroll_end) self.start_of_turn() def start_of_scroll(self, begin, end): """ Stel de voorwaarden in om te kunnen scrollen. :param begin: start x en y positie :param end: finish x en y positie """ self.scroll_timer = self.playtime # scroll_step = [10, 15] is het aantal pixels per seconde self.scroll_step = [(begin[0] - end[0]) / SCROLLTIME, (begin[1] - end[1]) / SCROLLTIME] self.scroll_current = list(begin) self.state.push(State.Scroll)