class Tetris(): NORMAL_MODE = 0 BOOZE_MODE = 1 DESIGNATED_DRIVER_MODE = 2 SINGLE_DRINK_MODE = 3 def __init__(self): self._event_handlers = [] self._setup_states() self._state["game_over"] = True self._setup_display() self._joystick = None if pygame.joystick.get_count() > 0: print "FOUND A JOYSTICK!" self._joystick = pygame.joystick.Joystick(0) self._joystick.init() def _setup_states(self, mode = 0): self._params = { "fullscreen" : False, "fullscreen_width" : 1024, "fullscreen_height" : 768, "num_cells_wide" : 10, "num_cells_high" : 20, "cell_width" : 25, "cell_height" : 25, "drink_pouring_time" : 10.0, "starting_cell_x" : 4, "starting_cell_y" : 1, "grid_top_x" : 0, "grid_top_y" : 0, "modes" : ["(N)ormal Mode", "(B)ooze Mode", "(S)ingle Drink Mode", "(D)esignated Driver Mode", "(Q)uit"] } self._level_params = { "moving_rate" : [0.00005,.00004,0.00003,0.00002,0.00001], "rotating_rate" : [0.00009,0.00008,0.00007,0.00006,0.00005], "falling_rate" : [0.00050,0.00035,0.00020,0.00010,0.00005] } self._state = { "last_falling_time" : 0, "falling_rate" : self._level_params["falling_rate"][0], "last_moving_time" : 0, "last_rotating_time" : 0, "level_up_line_count" : 5, "last_num_lines_cleared" : 0, "top_y" : 0, "times_found" : 0, "current_level" : 1, "game_over" : False, "all_finished" : False, "current_y" : 0, "holding_down" : False } if mode in [self.NORMAL_MODE, self.SINGLE_DRINK_MODE]: self._color_dict = {1: COLORS["blue"], 6 : COLORS["brown"], 10: COLORS["darkGrey"]} elif mode == self.BOOZE_MODE: self._color_dict = {3 : COLORS["brown"], 10: COLORS["darkGrey"]} elif mode == self.DESIGNATED_DRIVER_MODE: self._color_dict = {10: COLORS["blue"]} if mode == self.SINGLE_DRINK_MODE or mode == self.BOOZE_MODE: self._level_params = { "moving_rate" : [0.00005], "rotating_rate" : [0.00009], "falling_rate" : [0.00040] } self._params["drink_pouring_time"] = 20.0 self._color_range = 10 self._textBuff = 2 self._grid = Grid( 1, 1, self._params["cell_width"], self._params["cell_height"], self._params["num_cells_wide"], self._params["num_cells_high"], COLORS["black"], self._params["fullscreen"], self._params["fullscreen_width"], self._params["fullscreen_height"]) if self._params["fullscreen"]: self._params["grid_top_x"] = (self._params["fullscreen_width"] / 2) - (self._grid.width / 2) self._params["grid_top_y"] = (self._params["fullscreen_height"] / 2) - (self._grid.height / 2) self._tetrominoList = ['T','I','O','S','Z','L','J'] self._sound = Sound() self._new_tetromino() def _setup_display(self): os.environ['SDL_VIDEO_CENTERED'] = '1' pygame.init() if self._params["fullscreen"]: self._screen = pygame.display.set_mode((1024, 768), pygame.FULLSCREEN, 24) else: self._screen = pygame.display.set_mode((self._grid.width+self._textBuff,self._grid.height+self._textBuff),0,32) if pygame.font: self._font = pygame.font.Font(None, 18) def init_game(self): pygame.display.set_caption("Python Tetris") def run_game(self): time.sleep(0.01) if self._state["game_over"]: self._menu_state() else: self._game_loop() self._render() return def _menu_state(self): current_key = '' for event in pygame.event.get(): if event.type == QUIT: raise QuitException() if event.type == pygame.KEYDOWN: current_key = event.key if current_key == K_q: raise QuitException() elif current_key == K_n: self._setup_states(self.NORMAL_MODE) elif current_key == K_b: self._setup_states(self.BOOZE_MODE) elif current_key == K_d: self._setup_states(self.DESIGNATED_DRIVER_MODE) elif current_key == K_s: self._setup_states(self.SINGLE_DRINK_MODE) def _game_loop(self): # Grab vars if self._tetromino.active: self._move_tetromino() else: #New Tetromino osc.sendMsg("/tetris/piece_down", [0], "localhost", 9001) self._new_tetromino() #Levels and Speedup if self._grid.num_lines_cleared >= (self._state["level_up_line_count"] * self._state["current_level"]) and self._state["last_num_lines_cleared"] != self._grid.num_lines_cleared: self._level_up() def _move_tetromino(self): current_key = '' up_key = '' for event in pygame.event.get(): legal_moves = { "down" : self._tetromino.max_y < self._grid.height, "left" : self._tetromino.min_x > 0 and self._grid.accept(self._tetromino.id,self._tetromino.positions[self._tetromino.currentPosition],-1,0), "right" : self._tetromino.max_x < self._grid.width and self._grid.accept(self._tetromino.id,self._tetromino.positions[self._tetromino.currentPosition],1,0), } if event.type == QUIT: break if event.type == pygame.JOYAXISMOTION: a = event.axis p = event.value #turn joystick into key simulations if a == 0: if p < -0.01: current_key = K_LEFT elif p > 0.01: current_key = K_RIGHT else: if p > 0.01: current_key = K_DOWN elif p < 0.01 and p > -0.01: up_key = K_DOWN if event.type == pygame.JOYBUTTONDOWN: if event.button == 1: current_key = K_z else: current_key = K_x if event.type == pygame.KEYDOWN: current_key = event.key elif event.type == pygame.KEYUP: up_key = event.key if current_key == K_RIGHT and legal_moves["right"]: self._tetromino.move(self._grid,1,0) if current_key == K_LEFT and legal_moves["left"]: self._tetromino.move(self._grid,-1,0) if current_key == K_DOWN: self._state["holding_down"] = True osc.sendMsg("/mario/speed", [40], "localhost", 9001) elif up_key == K_DOWN: osc.sendMsg("/mario/speed", [0], "localhost", 9001) self._state["holding_down"] = False #TODO: Fix rotation states if current_key == K_z and False not in legal_moves.values(): self._tetromino.rotate(self._grid, -1) if current_key == K_x and False not in legal_moves.values(): self._tetromino.rotate(self._grid, 1) #ADDED: quit current_key if current_key == K_q: raise QuitException() legal_moves = { "down" : self._tetromino.max_y < self._grid.height, "left" : self._tetromino.min_x > 0 and self._grid.accept(self._tetromino.id,self._tetromino.positions[self._tetromino.currentPosition],-1,0), "right" : self._tetromino.max_x < self._grid.width and self._grid.accept(self._tetromino.id,self._tetromino.positions[self._tetromino.currentPosition],1,0), } current_time = time.time()/1000.0 falling_time = current_time - self._state["last_falling_time"] #Downward fall if self._state["holding_down"] is True and legal_moves["down"]: self._tetromino.move(self._grid,0,1) self._state["current_y"] += 1 elif falling_time >= self._state["falling_rate"] and legal_moves["down"]: self._state["last_falling_time"] = current_time self._tetromino.move(self._grid,0,1) self._state["current_y"] += 1 elif not legal_moves["down"] and falling_time >= self._state["falling_rate"]: self._tetromino.cluck.play() self._tetromino.active = False def _new_tetromino(self): #ADDED: Set tetromino color to one of our three allowed colors color_index = random.randint(0,self._color_range) color = () for color_probability in sorted(self._color_dict.keys()): if color_index <= color_probability: color = self._color_dict[color_probability] break rand = random.randint(0,len(self._tetrominoList)-1) self._tetromino = Tetromino(self._params["starting_cell_x"], self._params["starting_cell_y"], COLORS["black"],color,self._tetrominoList[rand]) self._state["holding_down"] = False if self._grid.checkForLines(): for e in self._event_handlers: e.on_line_created(self) #Test for GAME OVER top_y = self._grid.topY() if top_y <= 2: self._state["times_found"] += 1 if self._state["times_found"] > 3: self._state["game_over"] = True def _level_up(self): self._state["last_num_lines_cleared"] = self._grid.num_lines_cleared self._state["current_level"] += 1 if self._state["current_level"] < len(self._level_params["falling_rate"]): self._state["falling_rate"] = self._level_params["falling_rate"][self._state["current_level"]] else: self._state["all_finished"] = True self._state["game_over"] = True self._sound.play("../sound/levelup.wav") for e in self._event_handlers: e.on_level_up(self) def _render(self): #render Background pygame.draw.rect(self._screen,(255,255,255),Rect(self._params["grid_top_x"], self._params["grid_top_y"],self._grid.width+2,self._grid.height+2)) #Render Grid self._grid.render(self._screen) self._render_status() pygame.display.update() def _render_status(self): if not self._state["game_over"]: lineText = "Lines: " + str(self._grid.num_lines_cleared) + " Level: " + str(self._state["current_level"]) lines_text = self._font.render(lineText, 1, COLORS["white"]) lines_text_pos = Rect((self._params["grid_top_x"]+1, self._params["grid_top_y"]+1),(self._params["grid_top_x"] + 300, self._params["grid_top_y"] + 20)) self._screen.blit(lines_text, lines_text_pos) else: game_over_text = self._font.render("GAME OVER... LEVEL: "+str( self._state["current_level"])+" LINES: " + str(self._grid.num_lines_cleared),1, COLORS["red"]) if self._state["all_finished"]: game_over_text = self._font.render("ALL LEVELS FINISHED! LEVEL: "+str( self._state["current_level"])+" LINES: " + str(self._grid.num_lines_cleared),1, COLORS["red"]) game_over_text_pos = Rect((self._params["grid_top_x"]+1, self._params["grid_top_y"]+1),(self._params["grid_top_x"] + 300, self._params["grid_top_y"] + 20)) self._screen.blit(game_over_text,game_over_text_pos) for i in range(0, len(self._params["modes"])): pLineText = self._params["modes"][i] p_lines_text = self._font.render(pLineText, 1, COLORS["white"]) p_lines_text_pos = Rect((1+self._params["grid_top_x"],100+(i*25)+self._params["grid_top_y"]),(300,250)) self._screen.blit(p_lines_text, p_lines_text_pos) def add_event_handler(self, eh): self._event_handlers.append(eh)
currentY += 1 if key == K_UP and move_right_ok and move_left_ok and move_down_ok: tetromino.rotate(grid) #Downward fall if falling_time >= fallingRate and move_down_ok: last_falling_time = current_time tetromino.move(grid,0,1) currentY += 1 if not move_down_ok: tetromino.cluck.play() tetromino.active = False else: #New Tetromino tetromino = Tetromino(starting_cell_x,starting_cell_y,black,blue,tetrominoList[rand]) grid.checkForLines() #Test for GAME OVER topY = grid.topY() if topY <= 2: timesFound += 1 if timesFound > 3: gameOver = True #Levels and Speedup if grid.numLinesCleared % level_up_line_count == 0 and lastNumLinesCleared != grid.numLinesCleared: lastNumLinesCleared = grid.numLinesCleared if current_level < len(levels): fallingRate = levels[current_level] current_level += 1 sound.play("../sound/levelup.wav") #Render Background pygame.draw.rect(screen,(255,255,255),Rect(0,0,grid.width+2,grid.height+2))