class TetrisMainWindow(QMainWindow): """ The main tetris game window. """ def __init__(self, parent=None): super(TetrisMainWindow, self).__init__(parent) self.setWindowTitle('PyQtris v%s' % pyqtris_version) self.setWindowIcon(QIcon(get_icon_pixmap())) self.figurebank = self.make_figure_bank() self.create_main_frame() self.create_menu() self.create_status_bar() self.timer = QTimer() self.timer_interval = 1000 self.timer.timeout.connect(self.on_timer) # self.connect(self.timer, SIGNAL('timeout()'), self.on_timer) self.timer.start(self.timer_interval) self.init_highscores() self.restart_game() def on_restart(self): if self.state == GameState.gameover: self.restart_game() else: saved_state = self.state self.pause_game() reply = QMessageBox.question(self, 'Restart confirmation', 'Are you sure you want to restart the game?', QMessageBox.Yes | QMessageBox.No) if reply == QMessageBox.Yes: self.restart_game() else: self.set_game_state(saved_state) def on_pause(self): if self.state == GameState.paused: self.resume_game() elif self.state == GameState.running: self.pause_game() def on_about(self): saved_state = self.state self.pause_game() dialog = aboutdialog.AboutDialog(self) dialog.exec_() self.set_game_state(saved_state) def on_highscores(self): saved_state = self.state self.pause_game() self.show_highscores() self.set_game_state(saved_state) def set_game_state(self, state): if state == GameState.paused: self.pause_game() elif state == GameState.running: self.resume_game() elif state == GameState.gameover: self.state = GameState.gameover self.status_text.setText('Game over!') self.timer.stop() else: assert False def pause_game(self): self.state = GameState.paused self.status_text.setText('Paused') self.pause_button.setText('Resume') self.timer.stop() def resume_game(self): self.state = GameState.running self.status_text.setText('Playing') self.pause_button.setText('Pause') self.timer.start(self.timer_interval) def game_over(self): self.state = GameState.gameover self.status_text.setText('Game over!') self.timer.stop() if self.game_score > self.highscores.lowest_score(): text, ok = QInputDialog.getText(self, "High score!", 'Your name:') if ok and not text.isEmpty(): self.highscores.add_score(text, self.game_score) self.save_highscores() self.show_highscores() def restart_game(self): self.game_level = 1 self.game_lines = 0 self.game_score = 0 self.timer_interval = 1000 self.resume_game() self.update_stats() self.board_widget.restart(self.figurebank.get_random()) self.preview_figure = self.figurebank.get_random() self.preview_widget.set_figure(self.preview_figure) self.timer.start(self.timer_interval) def on_timer(self): if self.state == GameState.running: result = self.board_widget.timer_tick(self.preview_figure) num_rows = len(result.completed_rows) if result.state == 'gameover': self.game_over() elif result.state == 'newfigure': old_line_count = self.game_lines self.game_lines += num_rows score_bonus = result.drop_height + num_rows ** 2 * 30 score_bonus = int(score_bonus * (1 + 0.1 * (self.game_level - 1))) self.game_score += score_bonus self.preview_figure = self.figurebank.get_random() self.preview_widget.set_figure(self.preview_figure) if num_rows > 0 and old_line_count % 10 + num_rows >= 10: self.game_level += 1 self.timer_interval = 1000 - self.game_level * 100 if self.timer_interval < 100: self.timer_interval = 100 self.timer.stop() self.timer.start(self.timer_interval) self.update_stats() def update_stats(self): self.level_text.setText(str(self.game_level)) self.lines_text.setText(str(self.game_lines)) self.score_text.setText(str(self.game_score)) def create_main_frame(self): self.board_widget = MainTetrisWidget(self, nrows=20, ncols=10, blocksize=25, startfigure=self.figurebank.get_random()) self.board_widget.setFocus() self.control_panel = QFrame(self) self.control_panel.setFrameStyle(QFrame.Panel | QFrame.Sunken) self.control_panel.setFocusPolicy(Qt.NoFocus) self.populate_control_panel() main_layout = QHBoxLayout() main_layout.addWidget(self.board_widget) main_layout.addWidget(self.control_panel) main_layout.setSizeConstraint(QLayout.SetFixedSize) main_frame = QWidget() main_frame.setLayout(main_layout) self.setCentralWidget(main_frame) def populate_control_panel(self): self.preview_widget = TetrisPreviewWidget( self.control_panel, nrows=7, ncols=7, blocksize=10) # preview_group is the group-box for titling the preview # widget. preview_box is its internal layout. # finally, preview_layout is used to add stretchers around # the group box (to keep it slim) # preview_group = QGroupBox('Preview') preview_box = QHBoxLayout() preview_box.addWidget(self.preview_widget) preview_group.setLayout(preview_box) preview_layout = QHBoxLayout() preview_layout.addStretch() preview_layout.addWidget(preview_group) preview_layout.addStretch() text_layout = QGridLayout() level_label = StatsLabel('Level') self.level_text = StatsLabel('1', True) lines_label = StatsLabel('Lines') self.lines_text = StatsLabel('0', True) score_label = StatsLabel('Score') self.score_text = StatsLabel('0', True) text_layout.addWidget(level_label, 0, 0) text_layout.addWidget(self.level_text, 0, 1) text_layout.addWidget(lines_label, 1, 0) text_layout.addWidget(self.lines_text, 1, 1) text_layout.addWidget(score_label, 2, 0) text_layout.addWidget(self.score_text, 2, 1) self.pause_button = SizedButton('&Pause', QSize(90, 40)) self.pause_button.setFocusPolicy(Qt.NoFocus) self.pause_button.clicked.connect(self.on_pause) #self.connect(self.pause_button, SIGNAL('clicked()'), self.on_pause) self.restart_button = SizedButton('&New game', QSize(90, 40)) self.restart_button.setFocusPolicy(Qt.NoFocus) self.restart_button.clicked.connect(self.on_restart) #self.connect(self.restart_button, SIGNAL('clicked()'), self.on_restart) button_layout = QHBoxLayout() button_layout.addWidget(self.pause_button) button_layout.addSpacing(40) button_layout.addWidget(self.restart_button) vbox = QVBoxLayout() vbox.addSpacing(15) vbox.addLayout(preview_layout) vbox.addSpacing(40) vbox.addLayout(text_layout) vbox.addSpacing(40) vbox.addLayout(button_layout) vbox.addStretch() hbox = QHBoxLayout() hbox.addStretch() hbox.addLayout(vbox) hbox.addStretch() self.control_panel.setLayout(hbox) def create_status_bar(self): self.status_text = QLabel('Playing') self.statusBar().addWidget(self.status_text, 1) def create_menu(self): self.game_menu = self.menuBar().addMenu("&Game") self.help_menu = self.menuBar().addMenu("&Help") new_game_action = self.create_action("&New", shortcut='Ctrl+N', slot=self.on_restart, tip='New game') pause_game_action = self.create_action("&Pause", shortcut='Ctrl+P', slot=self.on_pause, tip='Pause game') highscores_action = self.create_action("&High Scores", shortcut='Ctrl+H', slot=self.on_highscores, tip='Pause game') quit_action = self.create_action("&Quit", shortcut='Ctrl+Q', slot=self.close, tip='Quit') about_action = self.create_action("&About", shortcut='F1', slot=self.on_about, tip='About PyQtris') self.add_actions(self.game_menu, ( new_game_action, pause_game_action, None, highscores_action, None, quit_action)) self.add_actions(self.help_menu, (about_action,)) def add_actions(self, target, actions): for action in actions: if action is None: target.addSeparator() else: target.addAction(action) def create_action(self, text, slot=None, shortcut=None, icon=None, tip=None, checkable=False, signal="triggered()"): action = QAction(text, self) if icon is not None: action.setIcon(QIcon(":/%s.png" % icon)) if shortcut is not None: action.setShortcut(shortcut) if tip is not None: action.setToolTip(tip) action.setStatusTip(tip) # if slot is not None: # action.connect(slot) ## self.connect(action, SIGNAL(signal), slot) if checkable: action.setCheckable(True) return action def make_figure_bank(self): # The standard 7 Tetris figures, in the orientation # in which they appear from the top of the screen # # oo # oO S = Figure([(0,0), (-1,0), (0,-1), (-1,1)], color=QColor(122, 197, 205)) # oo # Oo Z = Figure([(0,0), (0,1), (-1,-1), (-1,0)], color=QColor(0, 205, 0)) # oOo # o T = Figure([(0,0), (0,1), (0,-1), (1,0)], color=QColor(238, 238, 0)) # oOoo # I = Figure([(0,0), (0,-1), (0,1), (0,2)], color=QColor(238, 118, 33)) # oo # Oo O = Figure([(0,0), (-1,0), (-1,1), (0,1)], rotatable=False, color=QColor(238, 44, 44)) # oOo # o L = Figure([(0,0), (0,-1), (0,1), (1,-1)], color=QColor(0, 0, 225)) # oOo # o J = Figure([(0,0), (0,-1), (0,1), (1,1)], color=QColor(148, 0, 211)) return FigureBank([S, Z, T, I, O, L, J]) def keyPressEvent(self, event): if self.state == GameState.running: self.board_widget.keyPressEvent(event) HS_FILENAME = 'pyqtris_highscores' def init_highscores(self): self.highscores = HighScores(10) if os.path.exists(self.HS_FILENAME): self.highscores.load_from_file(self.HS_FILENAME) def save_highscores(self): self.highscores.save_to_file(self.HS_FILENAME) def show_highscores(self): dialog = HighscoresDialog(self.highscores.get_list(), self) dialog.exec_()
class TetrisMainWindow(QMainWindow): """ The main tetris game window. """ def __init__(self, parent=None): super(TetrisMainWindow, self).__init__(parent) self.setWindowTitle('PyQtris v%s' % pyqtris_version) self.setWindowIcon(QIcon(get_icon_pixmap())) self.figurebank = self.make_figure_bank() self.create_main_frame() self.create_menu() self.create_status_bar() self.timer = QTimer() self.timer_interval = 1000 self.timer.timeout.connect(self.on_timer) # self.connect(self.timer, SIGNAL('timeout()'), self.on_timer) self.timer.start(self.timer_interval) self.init_highscores() self.restart_game() def on_restart(self): if self.state == GameState.gameover: self.restart_game() else: saved_state = self.state self.pause_game() reply = QMessageBox.question( self, 'Restart confirmation', 'Are you sure you want to restart the game?', QMessageBox.Yes | QMessageBox.No) if reply == QMessageBox.Yes: self.restart_game() else: self.set_game_state(saved_state) def on_pause(self): if self.state == GameState.paused: self.resume_game() elif self.state == GameState.running: self.pause_game() def on_about(self): saved_state = self.state self.pause_game() dialog = aboutdialog.AboutDialog(self) dialog.exec_() self.set_game_state(saved_state) def on_highscores(self): saved_state = self.state self.pause_game() self.show_highscores() self.set_game_state(saved_state) def set_game_state(self, state): if state == GameState.paused: self.pause_game() elif state == GameState.running: self.resume_game() elif state == GameState.gameover: self.state = GameState.gameover self.status_text.setText('Game over!') self.timer.stop() else: assert False def pause_game(self): self.state = GameState.paused self.status_text.setText('Paused') self.pause_button.setText('Resume') self.timer.stop() def resume_game(self): self.state = GameState.running self.status_text.setText('Playing') self.pause_button.setText('Pause') self.timer.start(self.timer_interval) def game_over(self): self.state = GameState.gameover self.status_text.setText('Game over!') self.timer.stop() if self.game_score > self.highscores.lowest_score(): text, ok = QInputDialog.getText(self, "High score!", 'Your name:') if ok and not text.isEmpty(): self.highscores.add_score(text, self.game_score) self.save_highscores() self.show_highscores() def restart_game(self): self.game_level = 1 self.game_lines = 0 self.game_score = 0 self.timer_interval = 1000 self.resume_game() self.update_stats() self.board_widget.restart(self.figurebank.get_random()) self.preview_figure = self.figurebank.get_random() self.preview_widget.set_figure(self.preview_figure) self.timer.start(self.timer_interval) def on_timer(self): if self.state == GameState.running: result = self.board_widget.timer_tick(self.preview_figure) num_rows = len(result.completed_rows) if result.state == 'gameover': self.game_over() elif result.state == 'newfigure': old_line_count = self.game_lines self.game_lines += num_rows score_bonus = result.drop_height + num_rows**2 * 30 score_bonus = int(score_bonus * (1 + 0.1 * (self.game_level - 1))) self.game_score += score_bonus self.preview_figure = self.figurebank.get_random() self.preview_widget.set_figure(self.preview_figure) if num_rows > 0 and old_line_count % 10 + num_rows >= 10: self.game_level += 1 self.timer_interval = 1000 - self.game_level * 100 if self.timer_interval < 100: self.timer_interval = 100 self.timer.stop() self.timer.start(self.timer_interval) self.update_stats() def update_stats(self): self.level_text.setText(str(self.game_level)) self.lines_text.setText(str(self.game_lines)) self.score_text.setText(str(self.game_score)) def create_main_frame(self): self.board_widget = MainTetrisWidget( self, nrows=20, ncols=10, blocksize=25, startfigure=self.figurebank.get_random()) self.board_widget.setFocus() self.control_panel = QFrame(self) self.control_panel.setFrameStyle(QFrame.Panel | QFrame.Sunken) self.control_panel.setFocusPolicy(Qt.NoFocus) self.populate_control_panel() main_layout = QHBoxLayout() main_layout.addWidget(self.board_widget) main_layout.addWidget(self.control_panel) main_layout.setSizeConstraint(QLayout.SetFixedSize) main_frame = QWidget() main_frame.setLayout(main_layout) self.setCentralWidget(main_frame) def populate_control_panel(self): self.preview_widget = TetrisPreviewWidget(self.control_panel, nrows=7, ncols=7, blocksize=10) # preview_group is the group-box for titling the preview # widget. preview_box is its internal layout. # finally, preview_layout is used to add stretchers around # the group box (to keep it slim) # preview_group = QGroupBox('Preview') preview_box = QHBoxLayout() preview_box.addWidget(self.preview_widget) preview_group.setLayout(preview_box) preview_layout = QHBoxLayout() preview_layout.addStretch() preview_layout.addWidget(preview_group) preview_layout.addStretch() text_layout = QGridLayout() level_label = StatsLabel('Level') self.level_text = StatsLabel('1', True) lines_label = StatsLabel('Lines') self.lines_text = StatsLabel('0', True) score_label = StatsLabel('Score') self.score_text = StatsLabel('0', True) text_layout.addWidget(level_label, 0, 0) text_layout.addWidget(self.level_text, 0, 1) text_layout.addWidget(lines_label, 1, 0) text_layout.addWidget(self.lines_text, 1, 1) text_layout.addWidget(score_label, 2, 0) text_layout.addWidget(self.score_text, 2, 1) self.pause_button = SizedButton('&Pause', QSize(90, 40)) self.pause_button.setFocusPolicy(Qt.NoFocus) self.pause_button.clicked.connect(self.on_pause) #self.connect(self.pause_button, SIGNAL('clicked()'), self.on_pause) self.restart_button = SizedButton('&New game', QSize(90, 40)) self.restart_button.setFocusPolicy(Qt.NoFocus) self.restart_button.clicked.connect(self.on_restart) #self.connect(self.restart_button, SIGNAL('clicked()'), self.on_restart) button_layout = QHBoxLayout() button_layout.addWidget(self.pause_button) button_layout.addSpacing(40) button_layout.addWidget(self.restart_button) vbox = QVBoxLayout() vbox.addSpacing(15) vbox.addLayout(preview_layout) vbox.addSpacing(40) vbox.addLayout(text_layout) vbox.addSpacing(40) vbox.addLayout(button_layout) vbox.addStretch() hbox = QHBoxLayout() hbox.addStretch() hbox.addLayout(vbox) hbox.addStretch() self.control_panel.setLayout(hbox) def create_status_bar(self): self.status_text = QLabel('Playing') self.statusBar().addWidget(self.status_text, 1) def create_menu(self): self.game_menu = self.menuBar().addMenu("&Game") self.help_menu = self.menuBar().addMenu("&Help") new_game_action = self.create_action("&New", shortcut='Ctrl+N', slot=self.on_restart, tip='New game') pause_game_action = self.create_action("&Pause", shortcut='Ctrl+P', slot=self.on_pause, tip='Pause game') highscores_action = self.create_action("&High Scores", shortcut='Ctrl+H', slot=self.on_highscores, tip='Pause game') quit_action = self.create_action("&Quit", shortcut='Ctrl+Q', slot=self.close, tip='Quit') about_action = self.create_action("&About", shortcut='F1', slot=self.on_about, tip='About PyQtris') self.add_actions(self.game_menu, (new_game_action, pause_game_action, None, highscores_action, None, quit_action)) self.add_actions(self.help_menu, (about_action, )) def add_actions(self, target, actions): for action in actions: if action is None: target.addSeparator() else: target.addAction(action) def create_action(self, text, slot=None, shortcut=None, icon=None, tip=None, checkable=False, signal="triggered()"): action = QAction(text, self) if icon is not None: action.setIcon(QIcon(":/%s.png" % icon)) if shortcut is not None: action.setShortcut(shortcut) if tip is not None: action.setToolTip(tip) action.setStatusTip(tip) # if slot is not None: # action.connect(slot) ## self.connect(action, SIGNAL(signal), slot) if checkable: action.setCheckable(True) return action def make_figure_bank(self): # The standard 7 Tetris figures, in the orientation # in which they appear from the top of the screen # # oo # oO S = Figure([(0, 0), (-1, 0), (0, -1), (-1, 1)], color=QColor(122, 197, 205)) # oo # Oo Z = Figure([(0, 0), (0, 1), (-1, -1), (-1, 0)], color=QColor(0, 205, 0)) # oOo # o T = Figure([(0, 0), (0, 1), (0, -1), (1, 0)], color=QColor(238, 238, 0)) # oOoo # I = Figure([(0, 0), (0, -1), (0, 1), (0, 2)], color=QColor(238, 118, 33)) # oo # Oo O = Figure([(0, 0), (-1, 0), (-1, 1), (0, 1)], rotatable=False, color=QColor(238, 44, 44)) # oOo # o L = Figure([(0, 0), (0, -1), (0, 1), (1, -1)], color=QColor(0, 0, 225)) # oOo # o J = Figure([(0, 0), (0, -1), (0, 1), (1, 1)], color=QColor(148, 0, 211)) return FigureBank([S, Z, T, I, O, L, J]) def keyPressEvent(self, event): if self.state == GameState.running: self.board_widget.keyPressEvent(event) HS_FILENAME = 'pyqtris_highscores' def init_highscores(self): self.highscores = HighScores(10) if os.path.exists(self.HS_FILENAME): self.highscores.load_from_file(self.HS_FILENAME) def save_highscores(self): self.highscores.save_to_file(self.HS_FILENAME) def show_highscores(self): dialog = HighscoresDialog(self.highscores.get_list(), self) dialog.exec_()