class Game: COLUMNS = 8 ROWS = 12 # Top header for score header_height = 60 def __init__(self): random.seed() self.draw_count = 0 def init(self): flags = 0 if not ANDROID: os.environ['SDL_VIDEO_CENTERED'] = '1' WINSIZE = 480, 800 else: WINSIZE = 0, 0 flags |= pygame.FULLSCREEN pygame.init() mixer.init() # Map the back button to the escape key. if ANDROID: android.init() android.map_key(android.KEYCODE_BACK, pygame.K_b) self.clock = pygame.time.Clock() if not ANDROID: self.icon = pygame.image.load(get_resource('android-icon.png')) pygame.display.set_icon(self.icon) screen = self.screen = pygame.display.set_mode(WINSIZE, flags) self.width, self.height = screen.get_width(), screen.get_height() pygame.display.set_caption('Mazenum') self.score_font = pygame.font.Font(get_resource(join("fonts", "FreeSans.ttf")), 25) self.completed_font = pygame.font.Font(get_resource(join("fonts", "FreeSans.ttf")), 40) self.start_button = Button("Start game") self.playboard = PlayBoard(screen, self.COLUMNS, self.ROWS, self.header_height) self._set_background() self.is_game_over = False def start(self, debug=False): self.score = 0 self.is_game_over = False self.level = 1 self._start_level(DEBUG) def _start_level(self, debug=False): self.playboard.start(self.level) self.is_level_complete = False def _config_file(self, fname): """ Return full filename for a config file based on the platform """ if ANDROID: full_fname = fname else: config_dir = os.getenv('XDG_CONFIG_HOME', expanduser('~/.config')) config_dir = join(config_dir, 'mazenum') if not exists(config_dir): os.makedirs(config_dir, 0750) full_fname = join(config_dir, fname) return full_fname def _check_high_scores(self): """ Check if the current score is an high score. Update the highscore if required.""" # Read the higshcore file and check min fields are found high_score_fn = self._config_file('highscore.list') hs_list = self._high_scores = [] if exists(high_score_fn): with open(high_score_fn, 'r') as hs_file: for line in hs_file.readlines(): fields = line.strip('\r\n').split(';') if len(fields) == 3: hs_list.append(fields) # Search our score position score_pos = len(hs_list) for i in range(len(hs_list)): if self.score >= int(hs_list[i][0]): score_pos = i break # If we have a score pos, rebuild the score table and save it if score_pos < 10 : lower_scores = hs_list[score_pos:] higher_scores = hs_list[:score_pos] hs_list = higher_scores+[[str(self.score), str(self.level), str(date.today())]]+lower_scores hs_list = hs_list[:10] self._high_scores = hs_list with open(high_score_fn+'.new', 'w') as hs_file: for score in self._high_scores: hs_file.write(';'.join(score)+"\n") if exists(high_score_fn): os.unlink(high_score_fn) os.rename(high_score_fn+".new", high_score_fn) self.score_pos = score_pos def menu(self): screen = self.screen self.start_button.setCords((screen.get_width()/2) - (self.start_button.rect.width/2), 100) action = None while True: for event in pygame.event.get(): if event.type == MOUSEBUTTONDOWN: mouse_pos = pygame.mouse.get_pos() if self.start_button.is_pressed(event.pos): self.run() self.start_button.setCords((screen.get_width()/2) - (self.start_button.rect.width/2), 100) if event.type == QUIT or (event.type == KEYDOWN and event.key in [K_ESCAPE, pygame.K_b]): return False screen.blit(self.background, (0, 0)) screen.blit(self.start_button.image, self.start_button.rect) pygame.display.flip() self.clock.tick(TARGET_FPS) def _set_background(self): WINSIZE = self.width, self.height fn = join('gfx', 'background.jpg') background = pygame.image.load(get_resource(fn)) self.background = pygame.transform.scale(background, (WINSIZE)) self.playboard.set_background(self.background) def run(self): # The target frames per second is used to "sleep" the main loop between # screen redraws self.start() # The Main Event Loop while self._check_events(): self._draw() self.clock.tick(TARGET_FPS) def _check_events(self): playboard = self.playboard events = pygame.event.get() # Android-specific: if ANDROID and android.check_pause(): android.wait_for_resume() # Handle events for e in events: if e.type == QUIT or (e.type == KEYDOWN and e.key == K_ESCAPE): return False elif e.type == KEYDOWN and e.key == pygame.K_b: if self.is_game_over: return False else: self.is_game_over = True self._check_high_scores() elif e.type == MOUSEBUTTONDOWN: if self.is_level_complete: self.level += 1 self._start_level() elif self.is_game_over and e.type == MOUSEBUTTONDOWN: if self.start_button.is_pressed(e.pos): self.start() else: self._on_touch(e.pos) return True def _on_touch(self, pos): """ A position was touched """ touch_pos = self.playboard.get_board_pos(pos) if not touch_pos: # Out of the board return touch_x, touch_y = touch_pos # Revert last played ? if touch_pos == self.playboard.get_last_pos() and \ len(self.playboard._play_path) > 1: self.playboard.remove_last() if touch_pos in self.playboard.touched_goals: self.playboard.touched_goals.remove(touch_pos) return current_x, current_y = self.playboard.get_last_pos() # Ignore touches which are not adjacent if abs(touch_x - current_x) > 1 or abs(touch_y - current_y) > 1: return current_value = self.playboard.get_piece((current_x, current_y)) touch_value = self.playboard.get_piece(touch_pos) diff = touch_value - current_value if touch_value < 10 else touch_value if not diff in (1, -8): # Ignore non consecutive sequence -8=1-9 return self.score += 1 self.playboard.place_at((touch_x, touch_y)) if touch_pos in self.playboard.goals: self.playboard.touched_goals.append(touch_pos) if len(self.playboard.touched_goals) == len(self.playboard.goals): self.is_level_complete = True def _draw(self): screen = self.screen self.draw_count += 1 if self.draw_count == 1: self.first_draw = time.clock() self.playboard.draw(screen) # Header screen.blit(self.background, (0,0), (0, 0, self.width, self.header_height)) # Score text text = self.score_font.render(' Score: %d ' % self.score, True, THECOLORS["white"]) screen.blit(text, (10,0)) # Level text text = self.score_font.render(' Level: %d ' % self.level, True, THECOLORS["white"]) screen.blit(text, (self.width-text.get_width()-5,0)) # Level progress box #rect = pygame.Rect(20, 3+text.get_height(), self.width-40, 20) #rectangle(screen, rect, THECOLORS["white"]) # Level progress indicator (fill) #filled = (float(self.level_score)/self.level_score_goal)*(self.width-40) #white_rect = pygame.Rect(20, 3+text.get_height(), filled, 20) #black_rect = pygame.Rect(20+filled, 3+text.get_height(), self.width-40-filled, 20) #screen.fill(THECOLORS["white"], white_rect) #screen.fill(THECOLORS["black"], black_rect) #rectangle(screen, rect, THECOLORS["white"]) # Game over label when required if self.is_game_over: text = self.score_font.render(' GAME OVER ', True, THECOLORS["yellow"], THECOLORS["red"]) screen.blit(text, ((screen.get_width()/2) - (text.get_width()/2), self.header_height + 20)) #high score table i = 0 ypos = self.header_height + 10 + text.get_height() + 30 for score in self._high_scores: if i == self.score_pos: fg_color = THECOLORS["black"] bg_color = THECOLORS["white"] else: fg_color = THECOLORS["white"] bg_color = THECOLORS["gray"] text = self.score_font.render(' %6s - Level %2s (%s) ' % (score[0], score[1], score[2]), True , fg_color, bg_color) screen.blit(text, ((screen.get_width()/2) - (text.get_width()/2), ypos)) ypos += text.get_height()+10 i += 1 ypos += 20 self.start_button.setCords((screen.get_width()/2) - (self.start_button.rect.width/2), ypos) screen.blit(self.start_button.image, self.start_button.rect) if self.is_level_complete and not self.is_game_over: text = self.completed_font.render(' LEVEL COMPLETED ', True, THECOLORS["blue"], THECOLORS["yellow"]) screen.blit(text, ((screen.get_width()/2) - (text.get_width()/2), self.height/2-text.get_height()/2)) pygame.display.flip() if DEBUG and self.draw_count == 100: print "Playboard draw CPU time=", time.clock()-self.first_draw self.draw_count = 0