class Grid(QFrame): snekSpeed snekDirection gridSize gridLength = 11 def __init__(self): super().__init__(parent) self.initGrid() def initGrid(self): self.grid = [] self.timer = QBasicTimer() self.resetGrid() self.leSnekHasArrived() self.ateApple = False self.snekHeadX = 5 self.snekHeadY = 4 self.appleX = 0 self.appleY = 0 self.xVelocity = 0 self.yVelocity = 0 self.snekLength = 2 self.snekTailX = 4 self.snekTailY = 4 self.snekTrailX = [] self.snekTrailY = [] def resetGrid(self): for i in range(gridLength): self.grid.append(0) def leSnekHasArrived(self): grid[gridLength*gridLength//2] = 1 leSnek = Snek() def timerEvent(self, event): if event.timerId() = self.timer.timerId(): self.headX += self.xVelocity self.headT += self.yVelocity if snekHeadX in snekTrail[] if self.ateApple: self.ateApple = False self.spawnApple() else:
class Barrel(): def __init__(self, a, b, red, green, blue, size, speed): self.i = a self.j = b # self.type = QGraphicsEllipseItem(self.i*size, self.j*size, size, size) # self.type.setBrush(QColor(red, green, blue)) self.type = QGraphicsPixmapItem(QPixmap('./GResource/barrel.gif')) self.type.setX(self.i * size) self.type.setY(self.j * size) self.spawnTimer = QBasicTimer() self.speed = speed self.movementTimer = QBasicTimer() self.isBarrelThrown = False self.spawnID = self.spawnTimer.timerId() self.mvmID = self.movementTimer.timerId()
class VideoCapture(QObject): """ Class for capturing video from web camera using opencv It used an timer function to emit a Qt slot that contains image data. Class interested in processing this image will need to connect the slot. """ # slot for emitting a frame captured from camera got_image_data_from_camera = pyqtSignal(np.ndarray) def __init__(self, camera_port=0, parent=None): super().__init__(parent) self.camera = cv2.VideoCapture(camera_port) self.timer = QBasicTimer() def start(self): self.timer.start(0, self) def stop(self): self.timer.stop() def timerEvent(self, event): if (event.timerId() != self.timer.timerId()): log.warning("Failed to setup timer for video capture") return read, data = self.camera.read() if read: self.got_image_data_from_camera.emit(data)
class AutoSaver(QObject): """ Class implementing the auto saver. """ AUTOSAVE_IN = 1000 * 3 MAXWAIT = 1000 * 15 def __init__(self, parent, save): """ Constructor @param parent reference to the parent object (QObject) @param save slot to be called to perform the save operation @exception RuntimeError raised, if no parent is given """ super(AutoSaver, self).__init__(parent) if parent is None: raise RuntimeError("AutoSaver: parent must not be None.") self.__save = save self.__timer = QBasicTimer() self.__firstChange = QTime() def changeOccurred(self): """ Public slot handling a change. """ if self.__firstChange.isNull(): self.__firstChange.start() if self.__firstChange.elapsed() > self.MAXWAIT: self.saveIfNeccessary() else: self.__timer.start(self.AUTOSAVE_IN, self) def timerEvent(self, evt): """ Protected method handling timer events. @param evt reference to the timer event (QTimerEvent) """ if evt.timerId() == self.__timer.timerId(): self.saveIfNeccessary() else: super(AutoSaver, self).timerEvent(evt) def saveIfNeccessary(self): """ Public method to activate the save operation. """ if not self.__timer.isActive(): return self.__timer.stop() self.__firstChange = QTime() self.__save()
class ScaleFrame(QFrame): def __init__(self, parent): super(ScaleFrame, self).__init__(parent) self.parent = parent print('ScaleFrame: my parent is',self.parent) self.initFrame() def initFrame(self): self.commaweight = '' self.timer = QBasicTimer() self.myscale = Scale(10202) self.lbl_weight = QLabel(self) self.lbl_weight.setObjectName('lbl_weight') self.lbl_weight.setText("0.000") self.lbl_weight.resize(500, 100) self.lbl_weight.move(50, 50) lbl_unit = QLabel(self) lbl_unit.setObjectName('lbl_unit') lbl_unit.setText("kg") lbl_unit.resize(100, 120) lbl_unit.move(350, 40) self.setObjectName('ScaleFrame') self.setStyleSheet(""" #ScaleFrame { background-color: #cfcfcf; } .QLabel#lbl_weight { font-size:100pt; color: #ff0000; } .QLabel#lbl_unit { font-size:100pt; color: #000000; } .QLabel { font-size:22pt; color: #000000; } """) self.start_timer() def start_timer(self): self.timer.start(100, self) def timerEvent(self, event): '''handles timer event''' if event.timerId() == self.timer.timerId(): time_last_received, weight = self.myscale.return_last_weight() self.window().statusbar.showMessage(F"Last received: {time_last_received}") self.commaweight = str(F"{weight:.2f}").replace('.',',') # HACK HACK self.lbl_weight.setText(F"{weight:.3f}") else: super(Board, self).timerEvent(event)
class TetrisBoard(QFrame): msg_to_statusbar = pyqtSignal(str) Speed = 300 BoardWidth = 10 BoardHeight = 22 def __init__(self, parent): super().__init__(parent) # member variable self.timer = QBasicTimer() self._test_int = 1 def start(self): self.msg_to_statusbar.emit("Hello World") self.timer.start(TetrisBoard.Speed, self) def timerEvent(self, event): if event.timerId() == self.timer.timerId(): self.msg_to_statusbar.emit(str(self._test_int)) self._test_int += 1 self.update() else: super(TetrisBoard, self).timerEvent(event) def paintEvent(self, event): painter = QPainter(self) rect = self.contentsRect() #가장 아랫부분까지 채울 수 있도록 정해진 크기만큼 height를 가지도록 윗부분을 자른다.(특정 윗부분을 사용하지 않겠다는 의미) boardTop = rect.height() - TetrisBoard.BoardHeight * self.squareHeight() for h_index in range(TetrisBoard.BoardHeight): for w_index in range(TetrisBoard.BoardWidth): import random shape = random.randint(1, 7) colorTable = [0x000000, 0xCC6666, 0x66CC66, 0x6666CC, 0xCCCC66, 0xCC66CC, 0x66CCCC, 0xDAAA00] x = rect.left() + w_index * self.squareWidth() y = boardTop + h_index * self.squareHeight() painter.fillRect(x, y, self.squareWidth(), self.squareHeight(), QColor(colorTable[shape])) def squareWidth(self): '''returns the width of one square''' # print(self.contentsRect().width(), TetrisBoard.BoardWidth, self.contentsRect().width() // TetrisBoard.BoardWidth) return self.contentsRect().width() // TetrisBoard.BoardWidth def squareHeight(self): '''returns the height of one square''' # print(self.contentsRect().height(), TetrisBoard.BoardHeight, self.contentsRect().height() // TetrisBoard.BoardHeight) return self.contentsRect().height() // TetrisBoard.BoardHeight
class Canvas( QFrame ): def __init__( self, parent = None): super().__init__( parent ) self.setFocusPolicy( Qt.StrongFocus ) self.model = Model( FIELD_WIDTH, FIELD_HEIGHT, TILE_SIZE ) self.timer = QBasicTimer() self.timer.start( TIMER_DELAY, self ) def keyPressEvent( self, event ): key = event.key() if key == Qt.Key_Space: self.model.reset() self.parent().setWindowTitle(TITLE_OF_PROGRAM) self.update() elif key == Qt.Key_Left or key == Qt.Key_A: self.model.try_to_slide_in_direction( Directions.LEFT ) elif key == Qt.Key_Up or key == Qt.Key_W: self.model.try_to_slide_in_direction( Directions.UP ) elif key == Qt.Key_Right or key == Qt.Key_D: self.model.try_to_slide_in_direction( Directions.RIGHT ) elif key == Qt.Key_Down or key == Qt.Key_S: self.model.try_to_slide_in_direction( Directions.DOWN ) def mouseReleaseEvent( self, event ): x = int(event.x() / TILE_SIZE) * TILE_SIZE y = int(event.y() / TILE_SIZE) * TILE_SIZE self.model.try_to_slide( x, y ) def timerEvent( self, event ): if event.timerId() == self.timer.timerId(): self.model.tick() self.parent().setWindowTitle(TITLE_OF_PROGRAM + ": "+ str(self.model.move_count)) self.update() def paintEvent( self, event ): painter = QPainter( self ) color = QColor("#e74c3c") font = QFont( "Arial" ) font.setPointSize( 40 ) painter.setFont( font ) for tile in self.model.grid: if( tile.value != 0): painter.setBrush( color ) painter.fillRect( tile.x + 2, tile.y + 2, TILE_SIZE - 2, TILE_SIZE - 2, color) painter.setPen(QPen( QColor( 0, 0, 0 ), 5)) painter.drawText( QRectF( tile.x, tile.y, TILE_SIZE, TILE_SIZE ), Qt.AlignCenter | Qt.AlignTop , str(tile.value)) if( self.model.is_game_over ): font = QFont( "Arial" ) font.setPointSize( 80 ) painter.setPen( QPen( QColor( 0, 190, 0 ), 20 ) ) painter.drawText( QRectF( 0, 0, FIELD_WIDTH * TILE_SIZE, FIELD_HEIGHT * TILE_SIZE ), Qt.AlignCenter | Qt.AlignTop , str("Puzzle solved!"))
class WigglyLabel(object): def __init__(self, clazz): self.clazz = clazz # clazz.setBackgroundRole(QPalette.Midlight) # clazz.setAutoFillBackground(True) setattr(clazz, "paintEvent", self.paintEvent) setattr(clazz, "timerEvent", self.timerEvent) # newFont = self.clazz.font() # newFont.setPointSize(newFont.pointSize() + 20) # self.clazz.setFont(newFont) self.timer = QBasicTimer() self.step = 0; self.timer.start(60, self.clazz) def __del__(self): self.timer.stop() def getText(self): return self.clazz.text() def paintEvent(self, event): # 上下跳动 # sineTable = (0, 38, 71, 92, 100, 92, 71, 38, 0, -38, -71, -92, -100, -92, -71, -38) metrics = QFontMetrics(self.clazz.font()) x = (self.clazz.width() - metrics.width(self.getText())) / 2 y = (self.clazz.height() + metrics.ascent() - metrics.descent()) / 2 color = QColor() painter = QPainter(self.clazz) for i, ch in enumerate(self.getText()): index = (self.step + i) % 16 color.setHsv((15 - index) * 16, 255, 191) painter.setPen(color) # 上下跳动 # painter.drawText(x, y - ((sineTable[index] * metrics.height()) / 400), ch) painter.drawText(x, y , ch) x += metrics.width(ch) def timerEvent(self, event): if event.timerId() == self.timer.timerId(): self.step += 1 self.clazz.update() else: super(WigglyLabel, self).timerEvent(event)
class OceanVisualizator(QWidget): def __init__(self, interval, ocean, window_height=1000, window_width=1000): super().__init__() self.ocean = ocean self.window_width = window_width self.window_height = window_height self.cell_width = self.window_width / self.ocean.width self.cell_heigth = self.window_height / self.ocean.height self.timer = QBasicTimer() self.init_ui() self.timer.start(interval * 1000, self) def init_ui(self): self.setGeometry(0, 0, self.window_width, self.window_height) self.setWindowTitle("Ocean visualization") self.show() def paintEvent(self, event): painter = QPainter() painter.begin(self) for y in range(self.ocean.height): for x in range(self.ocean.width): if type(ocean.field[y][x]) != EmptyCell: if type(ocean.field[y][x]) == Obstacle: painter.fillRect(x * self.cell_width, y * self.cell_heigth, self.cell_width, self.cell_heigth, PyQt5.QtCore.Qt.black) elif type(ocean.field[y][x]) == Victim: painter.setBrush(PyQt5.QtCore.Qt.green) painter.drawEllipse(x * self.cell_width, y * self.cell_heigth, self.cell_width, self.cell_heigth) elif type(ocean.field[y][x]) == Predator: color = QColor(255, 0, 0) live_rate = ((ocean.field[y][x].full_health - ocean.field[y][x].health) * 200 / ocean.field[y][x].full_health) painter.setBrush(QBrush(color.darker(100 + live_rate))) painter.drawEllipse(x * self.cell_width, y * self.cell_heigth, self.cell_width, self.cell_heigth) painter.end() def timerEvent(self, event): if event.timerId() == self.timer.timerId(): self.ocean.make_turn() self.update()
class CameraRecord(QWidget): image_data = pyqtSignal(np.ndarray) def __init__(self, camera_port=0): super().__init__() self.camera = cv2.VideoCapture(camera_port) self.timer = QBasicTimer() self.timer.start(0, self) def timerEvent(self, QTimerEvent): if QTimerEvent.timerId() != self.timer.timerId(): return read, data = self.camera.read() if read: self.image_data.emit(data)
class WigglyWidget(QWidget): def __init__(self, parent=None): super(WigglyWidget, self).__init__(parent) self.setBackgroundRole(QPalette.Midlight) self.setAutoFillBackground(True) newFont = self.font() newFont.setPointSize(newFont.pointSize() + 20) self.setFont(newFont) self.timer = QBasicTimer() self.text = '' self.step = 0 self.timer.start(60, self) def paintEvent(self, event): sineTable = (0, 38, 71, 92, 100, 92, 71, 38, 0, -38, -71, -92, -100, -92, -71, -38) metrics = QFontMetrics(self.font()) x = (self.width() - metrics.width(self.text)) / 2 y = (self.height() + metrics.ascent() - metrics.descent()) / 2 color = QColor() painter = QPainter(self) for i, ch in enumerate(self.text): index = (self.step + i) % 16 color.setHsv((15 - index) * 16, 255, 191) painter.setPen(color) painter.drawText(x, y - ((sineTable[index] * metrics.height()) / 400), ch) x += metrics.width(ch) def setText(self, newText): self.text = newText def timerEvent(self, event): if event.timerId() == self.timer.timerId(): self.step += 1 self.update() else: super(WigglyWidget, self).timerEvent(event)
class CaptureVideo(QObject): # Signals image_data = pyqtSignal(ndarray) # Initialize class def __init__(self, camera_port=0): super().__init__() self.camera = cv2.VideoCapture(camera_port) self.timer = QBasicTimer() self.timer.start(1, self) # Period in miliseconds # Update video frame def timerEvent(self, event): if (event.timerId() != self.timer.timerId()): return read, frame = self.camera.read() if read: self.image_data.emit(frame)
class Example(QWidget): def __init__(self): super().__init__() self.initUI() def initUI(self): self.pbar = QProgressBar(self) self.pbar.setGeometry(30, 40, 400, 25) self.startbtn = QPushButton('Start', self) self.startbtn.move(30, 80) self.startbtn.clicked.connect(self.pushStart) self.stopbtn = QPushButton('Stop', self) self.stopbtn.move(320, 80) self.stopbtn.clicked.connect(self.pushStop) self.setGeometry(300, 300, 430, 170) self.setWindowTitle('This is a 5s timer. Press stop to abort') self.show() def timerEvent(self, e): if self.step >= 100: self.timer.stop() self.killTimer(self.timer.timerId()) return self.step = self.step + 1 self.pbar.setValue(self.step) def pushStart(self): self.timer = QBasicTimer() self.step = 0 self.timer.start(50, self) def pushStop(self): self.timer.stop() self.pbar.setValue(0) self.killTimer(self.timer.timerId())
class WigglyWidget(QWidget): def __init__(self, parent=None): super(WigglyWidget, self).__init__(parent) self.setBackgroundRole(QPalette.Midlight) self.setAutoFillBackground(True) newFont = self.font() newFont.setPointSize(newFont.pointSize() + 20) self.setFont(newFont) self.timer = QBasicTimer() self.text = '' self.step = 0; self.timer.start(60, self) def paintEvent(self, event): sineTable = (0, 38, 71, 92, 100, 92, 71, 38, 0, -38, -71, -92, -100, -92, -71, -38) metrics = QFontMetrics(self.font()) x = (self.width() - metrics.width(self.text)) / 2 y = (self.height() + metrics.ascent() - metrics.descent()) / 2 color = QColor() painter = QPainter(self) for i, ch in enumerate(self.text): index = (self.step + i) % 16 color.setHsv((15 - index) * 16, 255, 191) painter.setPen(color) painter.drawText(x, y - ((sineTable[index] * metrics.height()) / 400), ch) x += metrics.width(ch) def setText(self, newText): self.text = newText def timerEvent(self, event): if event.timerId() == self.timer.timerId(): self.step += 1 self.update() else: super(WigglyWidget, self).timerEvent(event)
class Example(QWidget): def __init__(self): super().__init__() self.initUI() def initUI(self): self.pbar = QProgressBar(self) self.pbar.setGeometry(30, 40, 200, 25) self.btn = QPushButton('Start', self) self.btn.move(40, 80) self.btn.clicked.connect(self.doAction) self.timer = QBasicTimer() self.step = 0 self.setGeometry(300, 300, 280, 170) self.setWindowTitle('QProgressBar') self.show() def timerEvent(self, e): if e.timerId() == self.timer.timerId(): if self.step >= 100: self.timer.stop() self.btn.setText('Finished') return self.step = self.step + 1 self.pbar.setValue(self.step) def doAction(self): if self.timer.isActive(): self.timer.stop() self.btn.setText('Start') else: self.timer.start(10, self) self.btn.setText('Stop')
class Example(QWidget): def __init__(self): super().__init__() self.initUI() def initUI(self): self.rot = 0 self.timer = QBasicTimer() self.timer.start(500, self) self.setGeometry(300, 300, 430, 240) self.setWindowTitle('Soulmate') self.show() def paintEvent(self, event): painter = QPainter() painter.begin(self) self.drawDonut(painter) painter.end() def timerEvent(self, event): if event.timerId() == self.timer.timerId(): self.rot += 1 self.repaint() else: super(Example, self).timerEvent(event) def drawDonut(self, painter): brush = QBrush(QColor('#535353')) painter.setPen(QPen(brush, 0.5)) painter.setRenderHint(QPainter.Antialiasing) h = self.height() w = self.width() painter.translate(QPoint(w / 2, h / 2)) for r in range(0, self.rot, 1): painter.rotate(float(r)) painter.drawEllipse(-125, -40, 250, 80)
class LiquidBox(QWidget): # 模拟流体力学程序,盛着液体的盒子 def __init__(self): super().__init__() self.speed = 100 #重绘速度1s self.WindowSize = 50 self.timer = QBasicTimer() self.sim = sm.Stimulator(self.WindowSize) self.initUI() def initUI(self): self.setGeometry(200, 200, 600, 600) self.setFixedSize(400, 400) self.setWindowTitle("流体力学模拟程序") self.timer.start(self.speed, self) self.show() #处理计时器消息 def timerEvent(self, event): if event.timerId() == self.timer.timerId(): self.update() else: super().timerEvent(event) #处理重绘消息 def paintEvent(self, event): qp = QPainter() qp.begin(self) self.Draw(qp) qp.end() #具体绘图函数 def Draw(self, qp): qp.setPen(Qt.blue) points = self.sim.step() for i in range(len(points)): qp.drawPoint(int(points[i][0]), int(points[i][1]))
class Board(QFrame): # 俄罗斯方块的一切逻辑操作在这里(旋转控制/满层消除/gameover判断/定时器判断/图形渲染) msg2status_bar = pyqtSignal(str) def __init__(self, parent): super(Board, self).__init__(parent) self.is_paused = False # 是否被暂停 self.num_lines_removed = 0 # 被删除的行数 self.game_start = True self.waiting_new_shape = False self.cur_x = 0 self.cur_y = 0 self.cur_shape = None self.setFocusPolicy(Qt.StrongFocus) # 界面没有按钮时,设置聚焦 self.timer = QBasicTimer() self.boards = [] self.clear_board() def clear_board(self): self.boards = [0 for i in range(WIDTH_GRID * HEIGHT_GRID)] def start(self): self.new_shape() self.timer.start(SPEED, self) def paintEvent(self, e): self.draw_shape() def new_shape(self): # 新建 shape self.cur_x = WIDTH_GRID // 2 self.cur_y = 0 self.cur_shape = Shape() self.cur_shape.set_random_shape() self.cur_shape.set_shape_coors(self.cur_shape.shape_type) if not self.move_shape(self.cur_shape, 0, 1): self.timer.stop() self.msg2status_bar.emit('Game Over!') self.game_start = False if self.cur_shape_has_repeat(): self.cur_shape = Shape() self.update() def cur_shape_has_repeat(self): for i in range(len(self.cur_shape.coors)): x = self.cur_shape.get_x(i) y = self.cur_shape.get_y(i) if self.get_shape_in_boards(x, y) != ShapeType.No_shape: return True return False def timerEvent(self, e): if e.timerId() == self.timer.timerId(): # time.sleep(1) if self.waiting_new_shape: self.waiting_new_shape = False self.set_shape_in_boards() self.remove_full_lines() else: self.shape_down1line(0, 1) else: return super(Board, self).timerEvent(e) def shape_down1line(self, x_offset, y_offset): # shape 往下移动一行 res = self.move_shape(self.cur_shape, x_offset, y_offset) # if res is False: # self.set_shape_in_boards() # self.remove_full_lines() return res def shape_drop_down(self): # 直接移动到底部 while self.shape_down1line(0, 1): pass def shape_pause(self): if self.is_paused: self.timer.start(SPEED, self) self.msg2status_bar.emit("分数:" + str(self.num_lines_removed)) else: self.timer.stop() self.msg2status_bar.emit("暂停") self.is_paused = not self.is_paused self.update() def keyPressEvent(self, event): key = event.key() if not self.game_start: return super(Board, self).keyPressEvent(event) if self.is_paused and key != Qt.Key_P: return super(Board, self).keyPressEvent(event) if key == Qt.Key_Up: # 上:左转 self.move_shape(self.cur_shape.rotate_left(), 0, 0) elif key == Qt.Key_Down: # 下:右转 self.move_shape(self.cur_shape.rotate_right(), 0, 0) elif key == Qt.Key_Left: # 左移 self.shape_down1line(-1, 0) elif key == Qt.Key_Right: # 右移 self.shape_down1line(1, 0) elif key == Qt.Key_P: # 暂停 self.shape_pause() elif key == Qt.Key_Space: # 空格:直接下到最后一行 self.shape_drop_down() else: return super(Board, self).keyPressEvent(event) def move_shape(self, shape, x_offset, y_offset): for i in range(len(shape.coors)): x = shape.get_x(i) + self.cur_x y = -shape.get_y(i) + self.cur_y if x + x_offset < 0 or x + x_offset >= WIDTH_GRID or y > HEIGHT_GRID - 1: # 设定不能超出边界 return None if y < 0: continue if y == HEIGHT_GRID - 1 or self.boards[self.get_index_in_boards( x, y + 1)] != ShapeType.No_shape: # 接触到了下边界 或 如果 x y 这个坐标在 boards 中不是空形状,返回 False self.waiting_new_shape = True return False self.cur_x += x_offset self.cur_y += y_offset self.cur_shape = shape self.update() return True def remove_full_lines(self): # 删除所有满行 lines = list( set([ self.cur_y - self.cur_shape.get_y(i) for i in range(len(self.cur_shape.coors)) ])) remove_lines = [] for line in lines: for i in range(line * WIDTH_GRID, line * WIDTH_GRID + WIDTH_GRID): if self.boards[i] == ShapeType.No_shape: break else: remove_lines.append(line) if remove_lines: remove_lines.sort() for remove_line in remove_lines: while remove_line > 0: for i in range(remove_line * WIDTH_GRID, remove_line * WIDTH_GRID + WIDTH_GRID): self.boards[i] = self.boards[i - WIDTH_GRID] remove_line -= 1 if len(remove_lines) > 0: self.num_lines_removed += len(remove_lines) self.msg2status_bar.emit("分数:" + str(self.num_lines_removed)) self.new_shape() def get_shape_in_boards(self, x, y): return self.boards[self.get_index_in_boards(x, y)] def set_shape_in_boards(self): for i in range(len(self.cur_shape.coors)): x = self.cur_shape.get_x(i) + self.cur_x y = -self.cur_shape.get_y(i) + self.cur_y if y < 0 or x < 0: continue self.set_boards_shape_type(x, y, self.cur_shape.shape_type) def set_boards_shape_type(self, x, y, shape_type): count = self.get_index_in_boards(x, y) self.boards[count] = shape_type @classmethod def get_index_in_boards(cls, x, y): return y * WIDTH_GRID + x def draw_shape(self): qp = QPainter() qp.begin(self) for i in range(len(self.cur_shape.coors)): if self.cur_shape.shape_type == ShapeType.No_shape: break self.painter_square(qp, self.cur_x + self.cur_shape.get_x(i), self.cur_y - self.cur_shape.get_y(i), 1, 1, self.cur_shape.shape_type) for i in range(WIDTH_GRID): for j in range(HEIGHT_GRID): shape_type = self.get_shape_in_boards(i, j) if shape_type != ShapeType.No_shape: self.painter_square(qp, i, j, 1, 1, shape_type) qp.end() def every_square_per_width(self): return self.contentsRect().width() // WIDTH_GRID def every_square_per_height(self): return self.contentsRect().height() // HEIGHT_GRID def painter_square(self, qp, x, y, width, height, shape_type): # 根据长宽和起始地点画框 x *= self.every_square_per_width() y *= self.every_square_per_height() width *= self.every_square_per_width() height *= self.every_square_per_height() color = QColor(ShapeType.Shape_Colors[shape_type]) qp.fillRect(x + 1, y + 1, width - 1, height - 2, color) qp.setPen(color.lighter()) qp.drawLine(x, y, x + width - 1, y) qp.drawLine(x, y, x, y + height - 1) qp.setPen(color.darker()) qp.drawLine(x + width - 1, y + 1, x + width - 1, y + height - 1) qp.drawLine(x + 1, y + height - 1, x + width - 1, y + height - 1)
class Tetris(QMainWindow): def __init__(self): super().__init__() self.isStarted = False self.isPaused = False self.nextMove = None self.lastShape = Shape.shapeNone self.initUI() def initUI(self): self.gridSize = 22 self.speed = 10 self.timer = QBasicTimer() self.setFocusPolicy(Qt.StrongFocus) hLayout = QHBoxLayout() self.tboard = Board(self, self.gridSize) hLayout.addWidget(self.tboard) self.sidePanel = SidePanel(self, self.gridSize) hLayout.addWidget(self.sidePanel) self.statusbar = self.statusBar() self.tboard.msg2Statusbar[str].connect(self.statusbar.showMessage) self.start() self.center() self.setWindowTitle('Tetris') self.show() self.setFixedSize(self.tboard.width() + self.sidePanel.width(), self.sidePanel.height() + self.statusbar.height()) def center(self): screen = QDesktopWidget().screenGeometry() size = self.geometry() self.move((screen.width() - size.width()) // 2, (screen.height() - size.height()) // 2) def start(self): if self.isPaused: return self.isStarted = True self.tboard.score = 0 BOARD_DATA.clear() self.tboard.msg2Statusbar.emit(str(self.tboard.score)) BOARD_DATA.createNewPiece() self.timer.start(self.speed, self) def pause(self): if not self.isStarted: return self.isPaused = not self.isPaused if self.isPaused: self.timer.stop() self.tboard.msg2Statusbar.emit("paused") else: self.timer.start(self.speed, self) self.updateWindow() def updateWindow(self): self.tboard.updateData() self.sidePanel.updateData() self.update() def timerEvent(self, event): if event.timerId() == self.timer.timerId(): if TETRIS_AI and not self.nextMove: self.nextMove = TETRIS_AI.nextMove() if self.nextMove: k = 0 while BOARD_DATA.currentDirection != self.nextMove[0] and k < 4: BOARD_DATA.rotateRight() k += 1 k = 0 while BOARD_DATA.currentX != self.nextMove[1] and k < 5: if BOARD_DATA.currentX > self.nextMove[1]: BOARD_DATA.moveLeft() elif BOARD_DATA.currentX < self.nextMove[1]: BOARD_DATA.moveRight() k += 1 # lines = BOARD_DATA.dropDown() lines = BOARD_DATA.moveDown() self.tboard.score += lines if self.lastShape != BOARD_DATA.currentShape: self.nextMove = None self.lastShape = BOARD_DATA.currentShape self.updateWindow() else: super(Tetris, self).timerEvent(event) def keyPressEvent(self, event): if not self.isStarted or BOARD_DATA.currentShape == Shape.shapeNone: super(Tetris, self).keyPressEvent(event) return key = event.key() if key == Qt.Key_P: self.pause() return if self.isPaused: return elif key == Qt.Key_Left: BOARD_DATA.moveLeft() elif key == Qt.Key_Right: BOARD_DATA.moveRight() elif key == Qt.Key_Up: BOARD_DATA.rotateLeft() elif key == Qt.Key_Space: self.tboard.score += BOARD_DATA.dropDown() else: super(Tetris, self).keyPressEvent(event) self.updateWindow()
class DownloadManager(QDialog, Ui_DownloadManager): """ Class implementing the download manager. @signal downloadsCountChanged() emitted to indicate a change of the count of download items """ RemoveNever = 0 RemoveExit = 1 RemoveSuccessFullDownload = 2 UpdateTimerTimeout = 1000 downloadsCountChanged = pyqtSignal() def __init__(self, parent=None): """ Constructor @param parent reference to the parent widget (QWidget) """ super(DownloadManager, self).__init__(parent) self.setupUi(self) self.setWindowFlags(Qt.Window) self.__winTaskbarButton = None self.__saveTimer = AutoSaver(self, self.save) self.__model = DownloadModel(self) self.__manager = WebBrowserWindow.networkManager() self.__iconProvider = None self.__downloads = [] self.__downloadDirectory = "" self.__loaded = False self.__rowHeightMultiplier = 1.1 self.setDownloadDirectory(Preferences.getUI("DownloadPath")) self.downloadsView.setShowGrid(False) self.downloadsView.verticalHeader().hide() self.downloadsView.horizontalHeader().hide() self.downloadsView.setAlternatingRowColors(True) self.downloadsView.horizontalHeader().setStretchLastSection(True) self.downloadsView.setModel(self.__model) self.downloadsView.setContextMenuPolicy(Qt.CustomContextMenu) self.downloadsView.customContextMenuRequested.connect( self.__customContextMenuRequested) self.__clearShortcut = QShortcut(QKeySequence("Ctrl+L"), self) self.__clearShortcut.activated.connect(self.on_cleanupButton_clicked) self.__load() self.__updateTimer = QBasicTimer() def __customContextMenuRequested(self, pos): """ Private slot to handle the context menu request for the bookmarks tree. @param pos position the context menu was requested (QPoint) """ menu = QMenu() selectedRowsCount = len( self.downloadsView.selectionModel().selectedRows()) if selectedRowsCount == 1: row = self.downloadsView.selectionModel().selectedRows()[0].row() itm = self.__downloads[row] if itm.downloadedSuccessfully(): menu.addAction(UI.PixmapCache.getIcon("open.png"), self.tr("Open"), self.__contextMenuOpen) elif itm.downloading(): menu.addAction(UI.PixmapCache.getIcon("stopLoading.png"), self.tr("Cancel"), self.__contextMenuCancel) menu.addSeparator() menu.addAction(self.tr("Open Containing Folder"), self.__contextMenuOpenFolder) menu.addSeparator() menu.addAction(self.tr("Go to Download Page"), self.__contextMenuGotoPage) menu.addAction(self.tr("Copy Download Link"), self.__contextMenuCopyLink) menu.addSeparator() menu.addAction(self.tr("Select All"), self.__contextMenuSelectAll) if (selectedRowsCount > 1 or (selectedRowsCount == 1 and not self.__downloads[self.downloadsView.selectionModel( ).selectedRows()[0].row()].downloading())): menu.addSeparator() menu.addAction(self.tr("Remove From List"), self.__contextMenuRemoveSelected) menu.exec_(QCursor.pos()) def shutdown(self): """ Public method to stop the download manager. """ self.save() self.close() def activeDownloadsCount(self): """ Public method to get the number of active downloads. @return number of active downloads (integer) """ count = 0 for download in self.__downloads: if download.downloading(): count += 1 return count def allowQuit(self): """ Public method to check, if it is ok to quit. @return flag indicating allowance to quit (boolean) """ if self.activeDownloadsCount() > 0: res = E5MessageBox.yesNo( self, self.tr(""), self.tr( """There are %n downloads in progress.\n""" """Do you want to quit anyway?""", "", self.activeDownloadsCount()), icon=E5MessageBox.Warning) if not res: self.show() return False self.close() return True def __testWebBrowserView(self, view, url): """ Private method to test a web browser view against an URL. @param view reference to the web browser view to be tested @type WebBrowserView @param url URL to test against @type QUrl @return flag indicating, that the view is the one for the URL @rtype bool """ if view.tabWidget().count() < 2: return False page = view.page() if page.history().count() != 0: return False if (not page.url().isEmpty() and page.url().host() == url.host()): return True requestedUrl = page.requestedUrl() if requestedUrl.isEmpty(): requestedUrl = QUrl(view.tabWidget().urlBarForView(view).text()) return requestedUrl.isEmpty() or requestedUrl.host() == url.host() def __closeDownloadTab(self, url): """ Private method to close an empty tab, that was opened only for loading the download URL. @param url download URL @type QUrl """ if self.__testWebBrowserView( WebBrowserWindow.getWindow().currentBrowser(), url): WebBrowserWindow.getWindow().closeCurrentBrowser() return for window in WebBrowserWindow.mainWindows(): for browser in window.browsers(): if self.__testWebBrowserView(browser, url): window.closeBrowser(browser) return def download(self, downloadItem): """ Public method to download a file. @param downloadItem reference to the download object containing the download data. @type QWebEngineDownloadItem """ url = downloadItem.url() if url.isEmpty(): return self.__closeDownloadTab(url) # Safe Browsing from WebBrowser.SafeBrowsing.SafeBrowsingManager import ( SafeBrowsingManager) if SafeBrowsingManager.isEnabled(): threatLists = ( WebBrowserWindow.safeBrowsingManager().lookupUrl(url)[0]) if threatLists: threatMessages = (WebBrowserWindow.safeBrowsingManager(). getThreatMessages(threatLists)) res = E5MessageBox.warning( WebBrowserWindow.getWindow(), self.tr("Suspicuous URL detected"), self.tr("<p>The URL <b>{0}</b> was found in the Safe" " Browsing database.</p>{1}").format( url.toString(), "".join(threatMessages)), E5MessageBox.StandardButtons(E5MessageBox.Abort | E5MessageBox.Ignore), E5MessageBox.Abort) if res == E5MessageBox.Abort: downloadItem.cancel() return window = WebBrowserWindow.getWindow() if window: pageUrl = window.currentBrowser().url() else: pageUrl = QUrl() from .DownloadItem import DownloadItem itm = DownloadItem(downloadItem=downloadItem, pageUrl=pageUrl, parent=self) self.__addItem(itm) if Preferences.getWebBrowser("DownloadManagerAutoOpen"): self.show() else: self.__startUpdateTimer() def show(self): """ Public slot to show the download manager dialog. """ self.__startUpdateTimer() super(DownloadManager, self).show() self.activateWindow() self.raise_() def __addItem(self, itm, append=False): """ Private method to add a download to the list of downloads. @param itm reference to the download item @type DownloadItem @param append flag indicating to append the item @type bool """ itm.statusChanged.connect(lambda: self.__updateRow(itm)) itm.downloadFinished.connect(self.__finished) # insert at top of window if append: row = self.downloadsCount() else: row = 0 self.__model.beginInsertRows(QModelIndex(), row, row) if append: self.__downloads.append(itm) else: self.__downloads.insert(0, itm) self.__model.endInsertRows() self.downloadsView.setIndexWidget(self.__model.index(row, 0), itm) icon = self.style().standardIcon(QStyle.SP_FileIcon) itm.setIcon(icon) self.downloadsView.setRowHeight( row, itm.sizeHint().height() * self.__rowHeightMultiplier) # just in case the download finished before the constructor returned self.__updateRow(itm) self.changeOccurred() self.downloadsCountChanged.emit() def __updateRow(self, itm): """ Private slot to update a download item. @param itm reference to the download item @type DownloadItem """ if itm not in self.__downloads: return row = self.__downloads.index(itm) if self.__iconProvider is None: self.__iconProvider = QFileIconProvider() icon = self.__iconProvider.icon(QFileInfo(itm.fileName())) if icon.isNull(): icon = self.style().standardIcon(QStyle.SP_FileIcon) itm.setIcon(icon) self.downloadsView.setRowHeight( row, itm.minimumSizeHint().height() * self.__rowHeightMultiplier) remove = False if (itm.downloadedSuccessfully() and self.removePolicy() == DownloadManager.RemoveSuccessFullDownload): remove = True if remove: self.__model.removeRow(row) self.cleanupButton.setEnabled( (self.downloadsCount() - self.activeDownloadsCount()) > 0) # record the change self.changeOccurred() def removePolicy(self): """ Public method to get the remove policy. @return remove policy (integer) """ return Preferences.getWebBrowser("DownloadManagerRemovePolicy") def setRemovePolicy(self, policy): """ Public method to set the remove policy. @param policy policy to be set (DownloadManager.RemoveExit, DownloadManager.RemoveNever, DownloadManager.RemoveSuccessFullDownload) """ assert policy in (DownloadManager.RemoveExit, DownloadManager.RemoveNever, DownloadManager.RemoveSuccessFullDownload) if policy == self.removePolicy(): return Preferences.setWebBrowser("DownloadManagerRemovePolicy", self.policy) def save(self): """ Public method to save the download settings. """ if not self.__loaded: return Preferences.setWebBrowser("DownloadManagerSize", self.size()) Preferences.setWebBrowser("DownloadManagerPosition", self.pos()) if self.removePolicy() == DownloadManager.RemoveExit: return from WebBrowser.WebBrowserWindow import WebBrowserWindow if WebBrowserWindow.isPrivate(): return downloads = [] for download in self.__downloads: downloads.append(download.getData()) Preferences.setWebBrowser("DownloadManagerDownloads", downloads) def __load(self): """ Private method to load the download settings. """ if self.__loaded: return size = Preferences.getWebBrowser("DownloadManagerSize") if size.isValid(): self.resize(size) pos = Preferences.getWebBrowser("DownloadManagerPosition") self.move(pos) from WebBrowser.WebBrowserWindow import WebBrowserWindow if not WebBrowserWindow.isPrivate(): downloads = Preferences.getWebBrowser("DownloadManagerDownloads") for download in downloads: if (not download["URL"].isEmpty() and bool(download["Location"])): from .DownloadItem import DownloadItem itm = DownloadItem(parent=self) itm.setData(download) self.__addItem(itm, append=True) self.cleanupButton.setEnabled( (self.downloadsCount() - self.activeDownloadsCount()) > 0) self.__loaded = True self.downloadsCountChanged.emit() def closeEvent(self, evt): """ Protected event handler for the close event. @param evt reference to the close event @type QCloseEvent """ self.save() def cleanup(self): """ Public slot to cleanup the downloads. """ self.on_cleanupButton_clicked() @pyqtSlot() def on_cleanupButton_clicked(self): """ Private slot to cleanup the downloads. """ if self.downloadsCount() == 0: return self.__model.removeRows(0, self.downloadsCount()) if (self.downloadsCount() == 0 and self.__iconProvider is not None): self.__iconProvider = None self.changeOccurred() self.downloadsCountChanged.emit() def __finished(self, success): """ Private slot to handle a finished download. @param success flag indicating a successful download @type bool """ if self.isVisible(): QApplication.alert(self) self.downloadsCountChanged.emit() if self.activeDownloadsCount() == 0: # all active downloads are done if success and e5App().activeWindow() is not self: if WebBrowserWindow.notificationsEnabled(): WebBrowserWindow.showNotification( UI.PixmapCache.getPixmap("downloads48.png"), self.tr("Downloads finished"), self.tr("All files have been downloaded.")) if not Preferences.getWebBrowser("DownloadManagerAutoClose"): self.raise_() self.activateWindow() self.__stopUpdateTimer() self.infoLabel.clear() self.setWindowTitle(self.tr("Download Manager")) if Globals.isWindowsPlatform(): self.__taskbarButton().progress().hide() if Preferences.getWebBrowser("DownloadManagerAutoClose"): self.close() def setDownloadDirectory(self, directory): """ Public method to set the current download directory. @param directory current download directory (string) """ self.__downloadDirectory = directory if self.__downloadDirectory != "": self.__downloadDirectory += "/" def downloadDirectory(self): """ Public method to get the current download directory. @return current download directory (string) """ return self.__downloadDirectory def downloadsCount(self): """ Public method to get the number of downloads. @return number of downloads @rtype int """ return len(self.__downloads) def downloads(self): """ Public method to get a reference to the downloads. @return reference to the downloads (list of DownloadItem) """ return self.__downloads def changeOccurred(self): """ Public method to signal a change. """ self.__saveTimer.changeOccurred() def __taskbarButton(self): """ Private method to get a reference to the task bar button (Windows only). @return reference to the task bar button @rtype QWinTaskbarButton or None """ if Globals.isWindowsPlatform(): from PyQt5.QtWinExtras import QWinTaskbarButton if self.__winTaskbarButton is None: window = WebBrowserWindow.mainWindow() self.__winTaskbarButton = QWinTaskbarButton( window.windowHandle()) self.__winTaskbarButton.progress().setRange(0, 100) return self.__winTaskbarButton def timerEvent(self, evt): """ Protected event handler for timer events. @param evt reference to the timer event @type QTimerEvent """ if evt.timerId() == self.__updateTimer.timerId(): if self.activeDownloadsCount() == 0: self.__stopUpdateTimer() self.infoLabel.clear() self.setWindowTitle(self.tr("Download Manager")) if Globals.isWindowsPlatform(): self.__taskbarButton().progress().hide() else: progresses = [] for itm in self.__downloads: if (itm is None or itm.downloadCanceled() or not itm.downloading()): continue progresses.append( (itm.downloadProgress(), itm.remainingTime(), itm.currentSpeed())) if not progresses: return remaining = 0 progress = 0 speed = 0.0 for progressData in progresses: if progressData[1] > remaining: remaining = progressData[1] progress += progressData[0] speed += progressData[2] progress = progress / len(progresses) if self.isVisible(): self.infoLabel.setText( self.tr("{0}% of %n file(s) ({1}) {2}", "", len(progresses)).format( progress, speedString(speed), timeString(remaining), )) self.setWindowTitle(self.tr("{0}% - Download Manager")) if Globals.isWindowsPlatform(): self.__taskbarButton().progress().show() self.__taskbarButton().progress().setValue(progress) super(DownloadManager, self).timerEvent(evt) def __startUpdateTimer(self): """ Private slot to start the update timer. """ if self.activeDownloadsCount() and not self.__updateTimer.isActive(): self.__updateTimer.start(DownloadManager.UpdateTimerTimeout, self) def __stopUpdateTimer(self): """ Private slot to stop the update timer. """ self.__updateTimer.stop() ########################################################################### ## Context menu related methods below ########################################################################### def __currentItem(self): """ Private method to get a reference to the current item. @return reference to the current item (DownloadItem) """ index = self.downloadsView.currentIndex() if index and index.isValid(): row = index.row() return self.__downloads[row] return None def __contextMenuOpen(self): """ Private method to open the downloaded file. """ itm = self.__currentItem() if itm is not None: itm.openFile() def __contextMenuOpenFolder(self): """ Private method to open the folder containing the downloaded file. """ itm = self.__currentItem() if itm is not None: itm.openFolder() def __contextMenuCancel(self): """ Private method to cancel the current download. """ itm = self.__currentItem() if itm is not None: itm.cancelDownload() def __contextMenuGotoPage(self): """ Private method to open the download page. """ itm = self.__currentItem() if itm is not None: url = itm.getPageUrl() WebBrowserWindow.mainWindow().openUrl(url, "") def __contextMenuCopyLink(self): """ Private method to copy the download link to the clipboard. """ itm = self.__currentItem() if itm is not None: url = itm.getPageUrl().toDisplayString(QUrl.FullyDecoded) QApplication.clipboard().setText(url) def __contextMenuSelectAll(self): """ Private method to select all downloads. """ self.downloadsView.selectAll() def __contextMenuRemoveSelected(self): """ Private method to remove the selected downloads from the list. """ self.downloadsView.removeSelected()
class Board(QFrame): msg2Statusbar = pyqtSignal(str) BoardWidth = 10 BoardHeight = 22 Speed = 300 # Ну тут как бы итак все понятно - параметры доски - ширина длинна, # и конечно же скорость игры def __init__(self, parent): super().__init__(parent) self.initBoard() def initBoard(self): self.timer = QBasicTimer() self.isWaitingAfterLine = False self.curX = 0 self.curY = 0 self.numLinesRemoved = 0 self.board = [] self.setFocusPolicy(Qt.StrongFocus) self.isStarted = False self.isPaused = False self.clearBoard() # метод initBoard() запускает несколько важных переменных. # Одна из них - self.board – это список чисел от 0 до 7. Она представляет # нахождение на поле различных фигур. def shapeAt(self, x, y): return self.board[(y * Board.BoardWidth) + x] # Метод shapeAt() генерирует вид фигуры в данном отсеке. def setShapeAt(self, x, y, shape): self.board[(y * Board.BoardWidth) + x] = shape def squareWidth(self): return self.contentsRect().width() // Board.BoardWidth # squareWidth() вычисляет ширину простого квадратика в пикселях и возвращает её, # чтобы разрешение было динамическим (если изменить размеры окошка). def squareHeight(self): return self.contentsRect().height() // Board.BoardHeight def start(self): if self.isPaused: return self.isStarted = True self.isWaitingAfterLine = False self.numLinesRemoved = 0 self.clearBoard() self.msg2Statusbar.emit(str(self.numLinesRemoved)) self.newPiece() self.timer.start(Board.Speed, self) def pause(self): if not self.isStarted: return self.isPaused = not self.isPaused if self.isPaused: self.timer.stop() self.msg2Statusbar.emit("На паузе.") # Если игрок останавливает игру на паузу, выводим сообшение # "На паузе." также останавливаем таймер else: self.timer.start(Board.Speed, self) self.msg2Statusbar.emit(str(self.numLinesRemoved)) # А иначе выводим кол-во удалённых линий self.update() def paintEvent(self, event): # Начинается часть рисовки ;) painter = QPainter(self) rect = self.contentsRect() boardTop = rect.bottom() - Board.BoardHeight * self.squareHeight() for i in range(Board.BoardHeight): for j in range(Board.BoardWidth): shape = self.shapeAt(j, Board.BoardHeight - i - 1) if shape != Tetrominoe.NoShape: self.drawSquare(painter, rect.left() + j * self.squareWidth(), boardTop + i * self.squareHeight(), shape) # Первоначально, рисуются все фигуры, которые были сброшены вниз доски. # Все квадратики запоминаются в списке переменных self.board. Доступ к переменной получим, # взяв на вооружение уже известный нам метод shapeAt(). if self.curPiece.shape() != Tetrominoe.NoShape: for i in range(4): x = self.curX + self.curPiece.x(i) y = self.curY - self.curPiece.y(i) self.drawSquare( painter, rect.left() + x * self.squareWidth(), boardTop + (Board.BoardHeight - y - 1) * self.squareHeight(), self.curPiece.shape()) # Рисуем упавшие вниз части. def keyPressEvent(self, event): if not self.isStarted or self.curPiece.shape() == Tetrominoe.NoShape: super(Board, self).keyPressEvent(event) return key = event.key() if key == Qt.Key_P: self.pause() return if self.isPaused: return elif key == Qt.Key_Left: self.tryMove(self.curPiece, self.curX - 1, self.curY) elif key == Qt.Key_Right: self.tryMove(self.curPiece, self.curX + 1, self.curY) elif key == Qt.Key_Down: self.tryMove(self.curPiece.rotateRight(), self.curX, self.curY) elif key == Qt.Key_Up: self.tryMove(self.curPiece.rotateLeft(), self.curX, self.curY) elif key == Qt.Key_Space: self.dropDown() elif key == Qt.Key_D: self.oneLineDown() else: super(Board, self).keyPressEvent(event) # С помощью метода keyPressEvent(), будем отслеживать нажатые клавиши. # Стоит учесть, что если достигнут допустим левый край, то при нажатии # кнопки ничего не произойдёт :\ def timerEvent(self, event): if event.timerId() == self.timer.timerId(): if self.isWaitingAfterLine: self.isWaitingAfterLine = False self.newPiece() else: self.oneLineDown() else: super(Board, self).timerEvent(event) # В timerEvent (переводится как - События Таймера), либо делается новая фигурка после предыдущей упавшей вниз, # либо мы передвигаем падающую часть на одну линию вниз. def clearBoard(self): for i in range(Board.BoardHeight * Board.BoardWidth): self.board.append(Tetrominoe.NoShape) def dropDown(self): newY = self.curY while newY > 0: if not self.tryMove(self.curPiece, self.curX, newY - 1): break newY -= 1 self.pieceDropped() def oneLineDown(self): if not self.tryMove(self.curPiece, self.curX, self.curY - 1): self.pieceDropped() def pieceDropped(self): for i in range(4): x = self.curX + self.curPiece.x(i) y = self.curY - self.curPiece.y(i) self.setShapeAt(x, y, self.curPiece.shape()) self.removeFullLines() if not self.isWaitingAfterLine: self.newPiece() def removeFullLines(self): numFullLines = 0 rowsToRemove = [] for i in range(Board.BoardHeight): n = 0 for j in range(Board.BoardWidth): if not self.shapeAt(j, i) == Tetrominoe.NoShape: n = n + 1 if n == 10: rowsToRemove.append(i) rowsToRemove.reverse() for m in rowsToRemove: for k in range(m, Board.BoardHeight): for l in range(Board.BoardWidth): self.setShapeAt(l, k, self.shapeAt(l, k + 1)) numFullLines = numFullLines + len(rowsToRemove) if numFullLines > 0: self.numLinesRemoved = self.numLinesRemoved + numFullLines self.msg2Statusbar.emit(str(self.numLinesRemoved)) self.isWaitingAfterLine = True self.curPiece.setShape(Tetrominoe.NoShape) self.update() def newPiece(self): self.curPiece = Shape() self.curPiece.setRandomShape() self.curX = Board.BoardWidth // 2 + 1 self.curY = Board.BoardHeight - 1 + self.curPiece.minY() if not self.tryMove(self.curPiece, self.curX, self.curY): self.curPiece.setShape(Tetrominoe.NoShape) self.timer.stop() self.isStarted = False self.msg2Statusbar.emit("Game over") def tryMove(self, newPiece, newX, newY): for i in range(4): x = newX + newPiece.x(i) y = newY - newPiece.y(i) if x < 0 or x >= Board.BoardWidth or y < 0 or y >= Board.BoardHeight: return False if self.shapeAt(x, y) != Tetrominoe.NoShape: return False self.curPiece = newPiece self.curX = newX self.curY = newY self.update() return True def drawSquare(self, painter, x, y, shape): colorTable = [ 0x000000, 0xCC6666, 0x66CC66, 0x6666CC, 0xCCCC66, 0xCC66CC, 0x66CCCC, 0xDAAA00 ] color = QColor(colorTable[shape]) painter.fillRect(x + 1, y + 1, self.squareWidth() - 2, self.squareHeight() - 2, color) painter.setPen(color.lighter()) painter.drawLine(x, y + self.squareHeight() - 1, x, y) painter.drawLine(x, y, x + self.squareWidth() - 1, y) painter.setPen(color.darker()) painter.drawLine(x + 1, y + self.squareHeight() - 1, x + self.squareWidth() - 1, y + self.squareHeight() - 1) painter.drawLine(x + self.squareWidth() - 1, y + self.squareHeight() - 1, x + self.squareWidth() - 1, y + 1)
class TetrixBoard(QFrame): BoardWidth = 10 BoardHeight = 22 scoreChanged = pyqtSignal(int) levelChanged = pyqtSignal(int) linesRemovedChanged = pyqtSignal(int) def __init__(self, parent=None): super(TetrixBoard, self).__init__(parent) self.timer = QBasicTimer() self.nextPieceLabel = None self.isWaitingAfterLine = False self.curPiece = TetrixPiece() self.nextPiece = TetrixPiece() self.curX = 0 self.curY = 0 self.numLinesRemoved = 0 self.numPiecesDropped = 0 self.score = 0 self.level = 0 self.board = None self.setFrameStyle(QFrame.Panel | QFrame.Sunken) self.setFocusPolicy(Qt.StrongFocus) self.isStarted = False self.isPaused = False self.clearBoard() self.nextPiece.setRandomShape() def shapeAt(self, x, y): return self.board[(y * TetrixBoard.BoardWidth) + x] def setShapeAt(self, x, y, shape): self.board[(y * TetrixBoard.BoardWidth) + x] = shape def timeoutTime(self): return 1000 / (1 + self.level) def squareWidth(self): return self.contentsRect().width() / TetrixBoard.BoardWidth def squareHeight(self): return self.contentsRect().height() / TetrixBoard.BoardHeight def setNextPieceLabel(self, label): self.nextPieceLabel = label def sizeHint(self): return QSize(TetrixBoard.BoardWidth * 15 + self.frameWidth() * 2, TetrixBoard.BoardHeight * 15 + self.frameWidth() * 2) def minimumSizeHint(self): return QSize(TetrixBoard.BoardWidth * 5 + self.frameWidth() * 2, TetrixBoard.BoardHeight * 5 + self.frameWidth() * 2) def start(self): if self.isPaused: return self.isStarted = True self.isWaitingAfterLine = False self.numLinesRemoved = 0 self.numPiecesDropped = 0 self.score = 0 self.level = 1 self.clearBoard() self.linesRemovedChanged.emit(self.numLinesRemoved) self.scoreChanged.emit(self.score) self.levelChanged.emit(self.level) self.newPiece() self.timer.start(self.timeoutTime(), self) def pause(self): if not self.isStarted: return self.isPaused = not self.isPaused if self.isPaused: self.timer.stop() else: self.timer.start(self.timeoutTime(), self) self.update() def paintEvent(self, event): super(TetrixBoard, self).paintEvent(event) painter = QPainter(self) rect = self.contentsRect() if self.isPaused: painter.drawText(rect, Qt.AlignCenter, "Pause") return boardTop = rect.bottom() - TetrixBoard.BoardHeight * self.squareHeight() for i in range(TetrixBoard.BoardHeight): for j in range(TetrixBoard.BoardWidth): shape = self.shapeAt(j, TetrixBoard.BoardHeight - i - 1) if shape != NoShape: self.drawSquare(painter, rect.left() + j * self.squareWidth(), boardTop + i * self.squareHeight(), shape) if self.curPiece.shape() != NoShape: for i in range(4): x = self.curX + self.curPiece.x(i) y = self.curY - self.curPiece.y(i) self.drawSquare(painter, rect.left() + x * self.squareWidth(), boardTop + (TetrixBoard.BoardHeight - y - 1) * self.squareHeight(), self.curPiece.shape()) def keyPressEvent(self, event): if not self.isStarted or self.isPaused or self.curPiece.shape() == NoShape: super(TetrixBoard, self).keyPressEvent(event) return key = event.key() if key == Qt.Key_Left: self.tryMove(self.curPiece, self.curX - 1, self.curY) elif key == Qt.Key_Right: self.tryMove(self.curPiece, self.curX + 1, self.curY) elif key == Qt.Key_Down: self.tryMove(self.curPiece.rotatedRight(), self.curX, self.curY) elif key == Qt.Key_Up: self.tryMove(self.curPiece.rotatedLeft(), self.curX, self.curY) elif key == Qt.Key_Space: self.dropDown() elif key == Qt.Key_D: self.oneLineDown() else: super(TetrixBoard, self).keyPressEvent(event) def timerEvent(self, event): if event.timerId() == self.timer.timerId(): if self.isWaitingAfterLine: self.isWaitingAfterLine = False self.newPiece() self.timer.start(self.timeoutTime(), self) else: self.oneLineDown() else: super(TetrixBoard, self).timerEvent(event) def clearBoard(self): self.board = [NoShape for i in range(TetrixBoard.BoardHeight * TetrixBoard.BoardWidth)] def dropDown(self): dropHeight = 0 newY = self.curY while newY > 0: if not self.tryMove(self.curPiece, self.curX, newY - 1): break newY -= 1 dropHeight += 1 self.pieceDropped(dropHeight) def oneLineDown(self): if not self.tryMove(self.curPiece, self.curX, self.curY - 1): self.pieceDropped(0) def pieceDropped(self, dropHeight): for i in range(4): x = self.curX + self.curPiece.x(i) y = self.curY - self.curPiece.y(i) self.setShapeAt(x, y, self.curPiece.shape()) self.numPiecesDropped += 1 if self.numPiecesDropped % 25 == 0: self.level += 1 self.timer.start(self.timeoutTime(), self) self.levelChanged.emit(self.level) self.score += dropHeight + 7 self.scoreChanged.emit(self.score) self.removeFullLines() if not self.isWaitingAfterLine: self.newPiece() def removeFullLines(self): numFullLines = 0 for i in range(TetrixBoard.BoardHeight - 1, -1, -1): lineIsFull = True for j in range(TetrixBoard.BoardWidth): if self.shapeAt(j, i) == NoShape: lineIsFull = False break if lineIsFull: numFullLines += 1 for k in range(TetrixBoard.BoardHeight - 1): for j in range(TetrixBoard.BoardWidth): self.setShapeAt(j, k, self.shapeAt(j, k + 1)) for j in range(TetrixBoard.BoardWidth): self.setShapeAt(j, TetrixBoard.BoardHeight - 1, NoShape) if numFullLines > 0: self.numLinesRemoved += numFullLines self.score += 10 * numFullLines self.linesRemovedChanged.emit(self.numLinesRemoved) self.scoreChanged.emit(self.score) self.timer.start(500, self) self.isWaitingAfterLine = True self.curPiece.setShape(NoShape) self.update() def newPiece(self): self.curPiece = copy.deepcopy(self.nextPiece) self.nextPiece.setRandomShape() self.showNextPiece() self.curX = TetrixBoard.BoardWidth // 2 + 1 self.curY = TetrixBoard.BoardHeight - 1 + self.curPiece.minY() if not self.tryMove(self.curPiece, self.curX, self.curY): self.curPiece.setShape(NoShape) self.timer.stop() self.isStarted = False def showNextPiece(self): if self.nextPieceLabel is None: return dx = self.nextPiece.maxX() - self.nextPiece.minX() + 1 dy = self.nextPiece.maxY() - self.nextPiece.minY() + 1 pixmap = QPixmap(dx * self.squareWidth(), dy * self.squareHeight()) painter = QPainter(pixmap) painter.fillRect(pixmap.rect(), self.nextPieceLabel.palette().window()) for i in range(4): x = self.nextPiece.x(i) - self.nextPiece.minX() y = self.nextPiece.y(i) - self.nextPiece.minY() self.drawSquare(painter, x * self.squareWidth(), y * self.squareHeight(), self.nextPiece.shape()) painter.end() self.nextPieceLabel.setPixmap(pixmap) def tryMove(self, newPiece, newX, newY): for i in range(4): x = newX + newPiece.x(i) y = newY - newPiece.y(i) if x < 0 or x >= TetrixBoard.BoardWidth or y < 0 or y >= TetrixBoard.BoardHeight: return False if self.shapeAt(x, y) != NoShape: return False self.curPiece = newPiece self.curX = newX self.curY = newY self.update() return True def drawSquare(self, painter, x, y, shape): colorTable = [0x000000, 0xCC6666, 0x66CC66, 0x6666CC, 0xCCCC66, 0xCC66CC, 0x66CCCC, 0xDAAA00] color = QColor(colorTable[shape]) painter.fillRect(x + 1, y + 1, self.squareWidth() - 2, self.squareHeight() - 2, color) painter.setPen(color.lighter()) painter.drawLine(x, y + self.squareHeight() - 1, x, y) painter.drawLine(x, y, x + self.squareWidth() - 1, y) painter.setPen(color.darker()) painter.drawLine(x + 1, y + self.squareHeight() - 1, x + self.squareWidth() - 1, y + self.squareHeight() - 1) painter.drawLine(x + self.squareWidth() - 1, y + self.squareHeight() - 1, x + self.squareWidth() - 1, y + 1)
class TetrisGame(QMainWindow): def __init__(self): super().__init__() # 是否暂停ing self.is_paused = False # 是否开始ing self.is_started = False self.initUI() '''界面初始化''' def initUI(self): # 块大小 self.grid_size = 22 # 游戏帧率 self.fps = 100 self.timer = QBasicTimer() # 焦点 self.setFocusPolicy(Qt.StrongFocus) # 水平布局 layout_horizontal = QHBoxLayout() self.inner_board = InnerBoard() self.external_board = ExternalBoard(self, self.grid_size, self.inner_board) layout_horizontal.addWidget(self.external_board) self.side_panel = SidePanel(self, self.grid_size, self.inner_board) layout_horizontal.addWidget(self.side_panel) self.status_bar = self.statusBar() self.external_board.score_signal[str].connect(self.status_bar.showMessage) self.start() self.center() self.setWindowTitle('Tetris-公众号:Charles的皮卡丘') self.show() self.setFixedSize(self.external_board.width() + self.side_panel.width(), self.side_panel.height() + self.status_bar.height()) # AI控制 self.tetris_ai = TetrisAI(self.inner_board) self.next_action = None self.pre_tetris = tetrisShape().shape_empty '''游戏界面移动到屏幕中间''' def center(self): screen = QDesktopWidget().screenGeometry() size = self.geometry() self.move((screen.width() - size.width()) // 2, (screen.height() - size.height()) // 2) '''更新界面''' def updateWindow(self): self.external_board.updateData() self.side_panel.updateData() self.update() '''开始''' def start(self): if self.is_started: return self.is_started = True self.inner_board.createNewTetris() self.timer.start(self.fps, self) '''暂停/不暂停''' def pause(self): if not self.is_started: return self.is_paused = not self.is_paused if self.is_paused: self.timer.stop() self.external_board.score_signal.emit('Paused') else: self.timer.start(self.fps, self) self.updateWindow() '''计时器事件''' def timerEvent(self, event): if event.timerId() == self.timer.timerId(): if not self.next_action: self.next_action = self.tetris_ai.getNextAction() if self.next_action: while self.inner_board.current_direction != self.next_action[0]: self.inner_board.rotateAnticlockwise() count = 0 while self.inner_board.current_coord[0] != self.next_action[1] and count < 5: if self.inner_board.current_coord[0] > self.next_action[1]: self.inner_board.moveLeft() else: self.inner_board.moveRight() count += 1 removed_lines = self.inner_board.moveDown() self.external_board.score += removed_lines if self.pre_tetris != self.inner_board.current_tetris: self.next_action = None self.pre_tetris = self.inner_board.current_tetris self.updateWindow() else: super(TetrisGame, self).timerEvent(event) '''按键事件''' def keyPressEvent(self, event): if not self.is_started or self.inner_board.current_tetris == tetrisShape().shape_empty: super(TetrisGame, self).keyPressEvent(event) return key = event.key() # P键暂停 if key == Qt.Key_P: self.pause() return if self.is_paused: return else: super(TetrisGame, self).keyPressEvent(event) self.updateWindow()
class Tetris(QMainWindow): def __init__(self): super().__init__() self.isStarted = False self.isPaused = False self.nextMove = None self.lastShape = Shape.shapeNone self.initUI() def initUI(self): self.gridSize = 22 self.speed = 1 self.timer = QBasicTimer() self.setFocusPolicy(Qt.StrongFocus) hLayout = QHBoxLayout() self.tboard = Board(self, self.gridSize) hLayout.addWidget(self.tboard) self.sidePanel = SidePanel(self, self.gridSize) hLayout.addWidget(self.sidePanel) self.statusbar = self.statusBar() self.tboard.msg2Statusbar[str].connect(self.statusbar.showMessage) self.start() self.center() self.setWindowTitle('俄罗斯方块') self.show() self.setFixedSize(self.tboard.width() + self.sidePanel.width(), self.sidePanel.height() + self.statusbar.height()) def center(self): screen = QDesktopWidget().screenGeometry() size = self.geometry() self.move((screen.width() - size.width()) // 2, (screen.height() - size.height()) // 2) def start(self): if self.isPaused: return self.isStarted = True self.tboard.score = 0 BOARD_DATA.clear() self.tboard.msg2Statusbar.emit(str(self.tboard.score)) BOARD_DATA.createNewPiece() self.timer.start(self.speed, self) def pause(self): if not self.isStarted: return self.isPaused = not self.isPaused if self.isPaused: self.timer.stop() self.tboard.msg2Statusbar.emit("paused") else: self.timer.start(self.speed, self) self.updateWindow() def updateWindow(self): self.tboard.updateData() self.sidePanel.updateData() self.update() def timerEvent(self, event): if event.timerId() == self.timer.timerId(): # 如果TETRIS_AI存在,则由AI进行下一步操作 if TETRIS_AI and not self.nextMove: self.nextMove = TETRIS_AI.nextMove() if self.nextMove: k = 0 while BOARD_DATA.currentDirection != self.nextMove[0] and k < 4: BOARD_DATA.rotateRight() k += 1 k = 0 while BOARD_DATA.currentX != self.nextMove[1] and k < 5: if BOARD_DATA.currentX > self.nextMove[1]: BOARD_DATA.moveLeft() elif BOARD_DATA.currentX < self.nextMove[1]: BOARD_DATA.moveRight() k += 1 # lines = BOARD_DATA.dropDown() lines = BOARD_DATA.moveDown() self.tboard.score += lines if self.lastShape != BOARD_DATA.currentShape: self.nextMove = None self.lastShape = BOARD_DATA.currentShape self.updateWindow() else: super(Tetris, self).timerEvent(event) def keyPressEvent(self, event): if not self.isStarted or BOARD_DATA.currentShape == Shape.shapeNone: super(Tetris, self).keyPressEvent(event) return key = event.key() # P键暂停 if key == Qt.Key_P: self.pause() return if self.isPaused: return elif key == Qt.Key_Left: BOARD_DATA.moveLeft() elif key == Qt.Key_Right: BOARD_DATA.moveRight() elif key == Qt.Key_Up: BOARD_DATA.rotateLeft() elif key == Qt.Key_Space: self.tboard.score += BOARD_DATA.dropDown() else: super(Tetris, self).keyPressEvent(event) self.updateWindow()
class Board(QFrame): msg2Statusbar = pyqtSignal(str) BoardWidth = 10 BoardHeight = 22 Speed = 300 def __init__(self, parent): super().__init__(parent) self.initBoard() def initBoard(self): self.timer = QBasicTimer() self.isWaitingAfterLine = False self.curX = 0 self.curY = 0 self.numLinesRemoved = 0 self.board = [] self.setFocusPolicy(Qt.StrongFocus) self.isStarted = False self.isPaused = False self.clearBoard() def shapeAt(self, x, y): return self.board[(y * Board.BoardWidth) + x] def setShapeAt(self, x, y, shape): self.board[(y * Board.BoardWidth) + x] = shape def squareWidth(self): return self.contentsRect().width() // Board.BoardWidth def squareHeight(self): return self.contentsRect().height() // Board.BoardHeight def start(self): if self.isPaused: return self.isStarted = True self.isWaitingAfterLine = False self.numLinesRemoved = 0 self.clearBoard() self.msg2Statusbar.emit(str(self.numLinesRemoved)) self.newPiece() self.timer.start(Board.Speed, self) def pause(self): if not self.isStarted: return self.isPaused = not self.isPaused if self.isPaused: self.timer.stop() self.msg2Statusbar.emit("paused") else: self.timer.start(Board.Speed, self) self.msg2Statusbar.emit(str(self.numLinesRemoved)) self.update() def paintEvent(self, event): painter = QPainter(self) rect = self.contentsRect() boardTop = rect.bottom() - Board.BoardHeight * self.squareHeight() for i in range(Board.BoardHeight): for j in range(Board.BoardWidth): shape = self.shapeAt(j, Board.BoardHeight - i - 1) if shape != Tetrominoe.NoShape: self.drawSquare(painter, rect.left() + j * self.squareWidth(), boardTop + i * self.squareHeight(), shape) if self.curPiece.shape() != Tetrominoe.NoShape: for i in range(4): x = self.curX + self.curPiece.x(i) y = self.curY - self.curPiece.y(i) self.drawSquare(painter, rect.left() + x * self.squareWidth(), boardTop + (Board.BoardHeight - y - 1) * self.squareHeight(), self.curPiece.shape()) def keyPressEvent(self, event): if not self.isStarted or self.curPiece.shape() == Tetrominoe.NoShape: super(Board, self).keyPressEvent(event) return key = event.key() if key == Qt.Key_P: self.pause() return if self.isPaused: return elif key == Qt.Key_Left: self.tryMove(self.curPiece, self.curX - 1, self.curY) elif key == Qt.Key_Right: self.tryMove(self.curPiece, self.curX + 1, self.curY) elif key == Qt.Key_Down: self.tryMove(self.curPiece.rotateRight(), self.curX, self.curY) elif key == Qt.Key_Up: self.tryMove(self.curPiece.rotateLeft(), self.curX, self.curY) elif key == Qt.Key_Space: self.dropDown() elif key == Qt.Key_D: self.oneLineDown() else: super(Board, self).keyPressEvent(event) def timerEvent(self, event): if event.timerId() == self.timer.timerId(): if self.isWaitingAfterLine: self.isWaitingAfterLine = False self.newPiece() else: self.oneLineDown() else: super(Board, self).timerEvent(event) def clearBoard(self): for i in range(Board.BoardHeight * Board.BoardWidth): self.board.append(Tetrominoe.NoShape) def dropDown(self): newY = self.curY while newY > 0: if not self.tryMove(self.curPiece, self.curX, newY - 1): break newY -= 1 self.pieceDropped() def oneLineDown(self): if not self.tryMove(self.curPiece, self.curX, self.curY - 1): self.pieceDropped() def pieceDropped(self): for i in range(4): x = self.curX + self.curPiece.x(i) y = self.curY - self.curPiece.y(i) self.setShapeAt(x, y, self.curPiece.shape()) self.removeFullLines() if not self.isWaitingAfterLine: self.newPiece() def removeFullLines(self): numFullLines = 0 rowsToRemove = [] for i in range(Board.BoardHeight): n = 0 for j in range(Board.BoardWidth): if not self.shapeAt(j, i) == Tetrominoe.NoShape: n = n + 1 if n == 10: rowsToRemove.append(i) rowsToRemove.reverse() for m in rowsToRemove: for k in range(m, Board.BoardHeight): for l in range(Board.BoardWidth): self.setShapeAt(l, k, self.shapeAt(l, k + 1)) numFullLines = numFullLines + len(rowsToRemove) if numFullLines > 0: self.numLinesRemoved = self.numLinesRemoved + numFullLines self.msg2Statusbar.emit(str(self.numLinesRemoved)) self.isWaitingAfterLine = True self.curPiece.setShape(Tetrominoe.NoShape) self.update() def newPiece(self): self.curPiece = Shape() self.curPiece.setRandomShape() self.curX = Board.BoardWidth // 2 + 1 self.curY = Board.BoardHeight - 1 + self.curPiece.minY() if not self.tryMove(self.curPiece, self.curX, self.curY): self.curPiece.setShape(Tetrominoe.NoShape) self.timer.stop() self.isStarted = False self.msg2Statusbar.emit("Game over") def tryMove(self, newPiece, newX, newY): for i in range(4): x = newX + newPiece.x(i) y = newY - newPiece.y(i) if x < 0 or x >= Board.BoardWidth or y < 0 or y >= Board.BoardHeight: return False if self.shapeAt(x, y) != Tetrominoe.NoShape: return False self.curPiece = newPiece self.curX = newX self.curY = newY self.update() return True def drawSquare(self, painter, x, y, shape): colorTable = [0x000000, 0xCC6666, 0x66CC66, 0x6666CC, 0xCCCC66, 0xCC66CC, 0x66CCCC, 0xDAAA00] color = QColor(colorTable[shape]) painter.fillRect(x + 1, y + 1, self.squareWidth() - 2, self.squareHeight() - 2, color) painter.setPen(color.lighter()) painter.drawLine(x, y + self.squareHeight() - 1, x, y) painter.drawLine(x, y, x + self.squareWidth() - 1, y) painter.setPen(color.darker()) painter.drawLine(x + 1, y + self.squareHeight() - 1, x + self.squareWidth() - 1, y + self.squareHeight() - 1) painter.drawLine(x + self.squareWidth() - 1, y + self.squareHeight() - 1, x + self.squareWidth() - 1, y + 1)
class Board(QFrame): """ Main board drawing ambulatory room + animation """ emitText = pyqtSignal(str) refreshRate = 300 board_width = 720 board_height = 560 graph_width = int(board_width / 80) graph_height = int(board_height / 80) tile_size = 80 player_size = 80 move_speed = 20 debug_mode = False right_foot = False player_x = 0 player_y = 160 is_operating = False inference_method = "Regułowe" pathFinding = "aStar" def __init__(self, parent): super().__init__(parent) self.parent = parent # self.initBoard() self.loadPixmaps() self.use_this_pixmap = self.nurse_pixmap # setting logical value for information about animation state self.isStopped = False self.isActive = False self.symptoms = [] # creating empty list of points of size board_width x board_height self.board = [ [ '' for x in range(self.board_width) ] for y in range(self.board_height) ] # creating list of static map objects # PIXMAPs are declared in function self.loadPixmaps() self.objects = { Object("curtain1", (0, 0), (80, 160), 7), Object("bed1", (80, 0), (80, 160), 4), Object("curtain2", (240, 0), (80, 160), 7), Object("bed2", (320, 0), (80, 160), 4), Object("curtain3", (480, 0), (80, 160), 7), Object("bed3", (560, 0), (80, 160), 5), # Object("table_top", (640, 240), (80, 80), 8, 90), Object("table", (640, 400), (80, 80), 9, 90), Object("curtain4", (0, 240), (160, 80), 7, 90), Object("bed4", (0, 320), (160, 80), 6, 270), Object("curtain5", (0, 480), (160, 80), 7, 90), # Object } for obj in self.objects: if obj.getName() == 'bed3' or obj.getName() == 'bed4': obj.changePixmap(4) """ Creating graph to get paths """ self.graph = GridWithWeights(self.graph_width, self.graph_height) self.graph.setWalls(*self.objects) self.path = [] # drawing static objects on map # self.fillBoard(80, 0, 40, 80, 'bed') # creating timer self.timer = QBasicTimer() def diagnose(self): self.is_operating = True get_symptoms_disease_relation_from_rows() if self.inference_method == 'Regułowe': diseases_list = [] symptom_list = [] name = str(randint(0, 1000000)) while (True): self.emitText.emit("Nurse: Co Ci dolega?") while not self.symptoms: time.sleep(0.1) if (self.symptoms): symptom_list.append(self.symptoms) symp = check_knowledge(dict, self.symptoms) print(dict) if (check_knowledge(dict, self.symptoms)): result = check_knowledge(dict, self.symptoms) self.emitText.emit("masz %s ?" % result[0]) self.emitText.emit("Jeśli tak to cierpisz na %s" % result[1]) break diseases_list = Diagnosis.perform_diagnosis(name, self.symptoms) if (len(diseases_list) == 1): break else: self.emitText.emit("--Liczba możliwych chorób to: %s--" % len(diseases_list)) self.symptoms = [] if (diseases_list): self.emitText.emit("%s cierpi na: %s" % (name, diseases_list[0])) key = str(diseases_list[0]) dict.setdefault(key, []) dict.update({key: symptom_list}) self.getPatientOufOf(self.current_bed) self.is_operating = False self.symptoms = [] @pyqtSlot(str) def inferenceEmitted(self, method): self.inference_method = method @pyqtSlot(str) def pathMethod(self, method): if method == "A Star": self.pathFinding = "aStar" elif method == "Dijkstra": self.pathFinding = "dijkstra" @pyqtSlot() def newPatient(self): emptyBeds = self.getEmptyBeds() if emptyBeds: index = randint(0, len(emptyBeds) - 1) self.putPatientInto(emptyBeds[index].getName()) else: self.emitText.emit('Brak wolnych lóżek') @pyqtSlot(str) def textEmitted(self, symptoms): self.symptoms = SymptomLoader.scanInput(symptoms) def loadPixmaps(self): base_dir = os.path.dirname(os.path.abspath(__file__)) base_dir = base_dir[:-4] # tiles = QImage(base_dir + r'/images/40_kafelki.gif') # tiles = QImage(base_dir + r'/images/podloga80x80.png') # tiles = QImage(base_dir + r'/images/podloga1_80x80.png') # tiles = QImage(base_dir + r'/images/podloga2_80x80.png') # tiles = QImage(base_dir + r'/images/podloga3_80x80.png') tiles = QImage(base_dir + r'/images/podloga4_80x80.png') # tiles = QImage(base_dir + r'/images/kafelki.gif') self.tiles_brush = QBrush(tiles) """ self.nurse_pixmap = QPixmap(base_dir + r'/images/nurse_standing40x40.png') """ self.nurse_pixmap = QPixmap(base_dir + r'/images/nurse_standing80x80.png') self.nurse_pixmap_base = self.nurse_pixmap """ self.nurse_left_pixmap = QPixmap(base_dir + r'/images/nurse_left40x40.png') """ self.nurse_left_pixmap = QPixmap(base_dir + r'/images/nurse_left80x80.png') self.nurse_left_pixmap_base = self.nurse_left_pixmap """ self.nurse_right_pixmap = QPixmap(base_dir + r'/images/nurse_right40x40.png') """ self.nurse_right_pixmap = QPixmap(base_dir + r'/images/nurse_right80x80.png') # self.nurse_pixmap = QPixmap(base_dir + # r'/images/nurse_standing40x40.png') # self.nurse_pixmap = QPixmap(base_dir + # r'/images/nurse_standing80x80.png') self.nurse_pixmap = QPixmap(base_dir + r'/images/pigula_koczek80x80.png') self.nurse_pixmap_base = self.nurse_pixmap # self.nurse_left_pixmap = QPixmap(base_dir + # r'/images/nurse_left40x40.png') # self.nurse_left_pixmap = QPixmap(base_dir + # r'/images/nurse_left80x80.png') self.nurse_left_pixmap = QPixmap(base_dir + r'/images/pigula_koczek_lewa80x80.png') self.nurse_left_pixmap_base = self.nurse_left_pixmap # self.nurse_right_pixmap = QPixmap(base_dir + # r'/images/nurse_right40x40.png') # self.nurse_right_pixmap = QPixmap(base_dir + # r'/images/nurse_right80x80.png') self.nurse_right_pixmap = QPixmap(base_dir + r'/images/pigula_koczek_prawa80x80.png') self.nurse_right_pixmap_base = self.nurse_right_pixmap """ self.empty_bed_pixmap = QPixmap(base_dir + r'/images/lozko40x80.gif') """ self.empty_bed_pixmap = QPixmap(base_dir + r'/images/lozko80x160.gif') """ self.girl_alarm_pixmap = QPixmap(base_dir + r'/images/girlAlarm40x80.gif') """ self.girl_alarm_pixmap = QPixmap(base_dir + r'/images/girlAlarm80x160.gif') # self.empty_bed_pixmap = QPixmap(base_dir + # r'/images/lozko40x80.gif') # self.empty_bed_pixmap = QPixmap(base_dir + # r'/images/lozko80x160.gif') self.empty_bed_pixmap = QPixmap(base_dir + r'/images/lozko7_80x160.png') """ self.girl_sleeping_pixmap = QPixmap(base_dir + r'/images/girlSleeping40x80.gif') """ self.girl_sleeping_pixmap = QPixmap(base_dir + r'/images/girlSleeping80x160.gif') # self.girl_sleeping_pixmap = QPixmap(base_dir + # r'/images/girlSleeping40x80.gif') # self.girl_sleeping_pixmap = QPixmap(base_dir + # r'/images/girlSleeping80x160.gif') self.girl_sleeping_pixmap = QPixmap(base_dir + r'/images/lozko7_asleep_80x160.png') # self.table_top_pixmap = QPixmap(base_dir + r'/images/blat40x40.png') self.table_top_pixmap = QPixmap(base_dir + r'/images/blat80x80.png') # self.table_pixmap = QPixmap(base_dir + r'/images/szafka40x40.png') self.table_pixmap = QPixmap(base_dir + r'/images/szafka80x80.png') """ self.curtain_pixmap = QPixmap(base_dir + r'/images/CurtainOnly40x80.gif') self.curtain_pixmap = QPixmap(base_dir + r'/images/CurtainOnly40x160.gif') """ self.curtain_pixmap = QPixmap(base_dir + r'/images/CurtainOnly80x160.gif') # creating dictionary of brushes! self.pixmaps = { 1: self.nurse_pixmap, 2: self.nurse_left_pixmap, 3: self.nurse_right_pixmap, 4: self.empty_bed_pixmap, 5: self.girl_alarm_pixmap, 6: self.girl_sleeping_pixmap, 7: self.curtain_pixmap, 8: self.table_top_pixmap, 9: self.table_pixmap } @pyqtSlot() def start(self): """ Function responsible for preparing animation when start button has been pressed """ if self.isActive: return if self.isStopped: self.isStopped = False self.isActive = True self.timer.start(self.refreshRate, self) @pyqtSlot() def stop(self): """ Function responsible for stoping animation when stop button pressed """ if not self.isActive: return self.isStopped = True self.isActive = False self.timer.stop() self.update() @pyqtSlot(str) def move(self, direction): """ Function responsible for moving main character up. """ self.rotatePlayer(direction) self.fillRealBoard(self.player_x, self.player_y, self.player_size, self.player_size, '') if direction == 'up' and not self.collision(direction): self.makeStep(direction, -self.move_speed) elif direction == 'right' and not self.collision(direction): self.makeStep(direction, self.move_speed) elif direction == 'down' and not self.collision(direction): self.makeStep(direction, self.move_speed) elif direction == 'left' and not self.collision(direction): self.makeStep(direction, -self.move_speed) self.fillRealBoard(self.player_x, self.player_y, self.player_size, self.player_size, 'player') def makeStep(self, direction, distance): # print('distance: ' + str(distance) + '\t 1/4th: ' + str(distance/4)) # determining size of first step (can't be float) half_of_distance = int(distance / 2) # determinig which foot now if self.right_foot: foot_pixmap = self.nurse_left_pixmap else: foot_pixmap = self.nurse_right_pixmap # next time it will be another foot self.right_foot = not self.right_foot if direction in ['up', 'down']: # changing POS_Y self.player_y += half_of_distance self.use_this_pixmap = foot_pixmap self.repaint() time.sleep(0.05) self.player_y += half_of_distance self.use_this_pixmap = self.nurse_pixmap self.repaint() elif direction in ['left', 'right']: # changing POS_X self.player_x += half_of_distance self.use_this_pixmap = foot_pixmap self.repaint() time.sleep(0.05) self.player_x += half_of_distance self.use_this_pixmap = self.nurse_pixmap self.repaint() @pyqtSlot() def debug(self): """ PyQt slot for signal to change map-drawing-mode debug - black background & red objects normal - normal :P """ self.debug_mode = not self.debug_mode def getEmptyBeds(self): emptyBeds = [] for obj in self.objects: if ((obj.getName() == 'bed1' or obj.getName() == 'bed2' or obj.getName() == 'bed3' or obj.getName() == 'bed4') and (obj.getPixmap() is 4)): emptyBeds.append(obj) return emptyBeds def getTakenBeds(self): takenBeds = [] for obj in self.objects: if ((obj.getName() == 'bed1' or obj.getName() == 'bed2' or obj.getName() == 'bed3' or obj.getName() == 'bed4') and (obj.getPixmap() is not 4)): takenBeds.append(obj) return takenBeds def putSleepingPatientInto(self, bed_name): for obj in self.objects: if obj.getName() == bed_name and obj.getPixmap() != 6: obj.changePixmap(6) def putPatientInto(self, bed_name): for obj in self.objects: if obj.getName() == bed_name and obj.getPixmap() != 5: obj.changePixmap(5) def getPatientOufOf(self, bed_name): for obj in self.objects: if obj.getName() == bed_name and obj.getPixmap() != 4: obj.changePixmap(4) def rotatePlayer(self, direction): """ Function responsible for rotating players icon. """ rotation = QTransform() if direction == 'up': rotation.rotate(0) elif direction == 'right': rotation.rotate(90) elif direction == 'down': rotation.rotate(180) elif direction == 'left': rotation.rotate(270) self.use_this_pixmap = \ self.nurse_pixmap_base.transformed(rotation) self.nurse_pixmap = \ self.nurse_pixmap_base.transformed(rotation) self.nurse_left_pixmap = \ self.nurse_left_pixmap_base.transformed(rotation) self.nurse_right_pixmap = \ self.nurse_right_pixmap_base.transformed(rotation) """ self.player_left_brush = QBrush(self.player_left_base.transformed(rotation)) self.player_right_brush = QBrush(self.player_right_base.transformed(rotation)) self.player_brush = QBrush(self.player_image_base.transformed(rotation)) """ def collision(self, direction): """ Main function responsible for collision detection. """ # These -/+ 1 comes from the fact, that we aren't checking # corners but pixels diagonally to the inside of player icon # @@@@@@@@@@@@ # @*@@@@@@@@*@ # @@@@@@@@@@@@ # @@@@@@@@@@@@ # @@@@@@@@@@@@ # @*@@@@@@@@*@ # @@@@@@@@@@@@ # (x1, y1) - TOP LEFT # (x2, y2) - TOP RIGHT if direction == 'up': x1 = self.player_x + 1 y1 = self.player_y - self.move_speed + 1 x2 = self.player_x + self.player_size - 1 y2 = y1 # (x1, y1) - TOP RIGHT # (x2, y2) - BOTTOM RIGHT elif direction == 'right': x1 = self.player_x + self.player_size + self.move_speed - 1 y1 = self.player_y + 1 x2 = x1 y2 = self.player_y + self.player_size - 1 # (x1, y1) - BOTTOM LEFT # (x2, y2) - BOTTOM RIGHT elif direction == 'down': x1 = self.player_x + 1 y1 = self.player_y + self.player_size + self.move_speed - 1 x2 = self.player_x + self.player_size - 1 y2 = y1 # (x1, y1) - TOP LEFT # (x2, y2) - BOTTOM LEFT elif direction == 'left': x1 = self.player_x - self.move_speed + 1 y1 = self.player_y + 1 x2 = x1 y2 = self.player_y + self.player_size - 1 try: # no collision if value is "" (empty string) if self.board[y1][x1] or self.board[y2][x2]: print("Collision! There is: {0} or \ {1}".format(self.board[y1][x1], self.board[y2][x2])) return True elif direction == 'up' and y1 < 0: return True elif direction == 'right' and x1 > self.board_width: return True elif direction == 'down' and y1 > self.board_height: return True elif direction == 'left' and x1 < 0: return True else: return False except IndexError: return True def paintEvent(self, event): painter = QPainter(self) if self.debug_mode: self.drawRealBoard(painter) else: self.drawBoard(painter) self.drawPlayer(painter) self.update() def timerEvent(self, event): """ Overwritten function of timer event """ if event.timerId() == self.timer.timerId(): takenBeds = self.getTakenBeds() if not self.is_operating and takenBeds: self.goToPatient(takenBeds) else: super(Board, self).timerEvent(event) def goToPatient(self, takenBeds): if takenBeds: index = randint(0, len(takenBeds) - 1) x, y = takenBeds[index].getPosition() sizeX, sizeY = takenBeds[index].getSize() pointX = int(x / 80) pointY = int(y / 80) if takenBeds[index].getName() == 'bed4': pointY = int(pointY + sizeY / 80) else: pointX = int(pointX + sizeX / 80) self.current_bed = takenBeds[index].getName() playerX = int(self.player_x / 80) playerY = int(self.player_y / 80) if self.pathFinding == "aStar": cameFrom, costSoFar = self.aStarSearch(self.graph, (playerX, playerY), (pointX, pointY)) elif self.pathFinding == "dijkstra": cameFrom, costSoFar = self.dijkstraSearch(self.graph, (playerX, playerY), (pointX, pointY)) self.path = self.reconstructPath(cameFrom, (playerX, playerY), (pointX, pointY)) if playerX is pointX and playerY is pointY: self.is_operating = True diagnoseThread = threading.Thread(target=self.diagnose) diagnoseThread.start() else: self.movePlayer() def movePlayer(self): pathToMove = self.path[1:] for nextPointX, nextPointY in pathToMove: nextPointX = nextPointX * 80 nextPointY = nextPointY * 80 if self.player_x < nextPointX: while self.player_x < nextPointX: self.move('right') elif self.player_x > nextPointX: while self.player_x > nextPointX: self.move('left') elif self.player_y < nextPointY: while self.player_y < nextPointY: self.move('down') elif self.player_y > nextPointY: while self.player_y > nextPointY: self.move('up') def drawBoard(self, painter): """ Main function for QPainter """ # drawing tiles painter.setBrush(self.tiles_brush) painter.drawRect( 0, 0, self.board_width, self.board_height ) self.drawObjects(painter) def drawObjects(self, painter): """ Drawing objects like bed or curtain on map. """ # reminder: # obj = [(pos_x, pos_y), (width, height), PIXMAP, ROTATION_ANGLE] for obj in self.objects: if obj.getAngle() != 0: rotation = QTransform() rotation.rotate(obj.getAngle()) pixmap = self.pixmaps[obj.getPixmap()].transformed(rotation) else: pixmap = self.pixmaps[obj.getPixmap()] state = obj.getState() painter.drawPixmap( state[0], # pos_x state[1], # pos_y state[2], # width state[3], # height pixmap ) # Drawing path - delete when not needed for (x, y) in self.path: painter.setPen(Qt.red) painter.drawRect(x * 80, y * 80, 80, 80) self.fillRealBoard( state[0], # pos_x state[1], # pos_y state[2], # width state[3], # height obj.getName() ) def fillRealBoard(self, start_x, start_y, width, height, content): for y in range(start_y, start_y + height): for x in range(start_x, start_x + width): self.board[y][x] = content """ print('filling board from {0} to {1} and \ from {2} to {3} with {4}'.format(start_x, width, start_y, height, content)) """ def drawRealBoard(self, painter): """ Only for debug, prints self.board pixel by pixel """ for y in range(self.board_height): for x in range(self.board_width): if self.board[y][x] != '': print(str(x) + 'x' + str(y) + ' - ' + str(self.board[y][x])) painter.setPen(Qt.red) painter.drawRect(x, y, 1, 1) else: painter.setPen(Qt.black) painter.drawRect(x, y, 1, 1) self.update() def drawPlayer(self, painter): painter.drawPixmap( self.player_x, self.player_y, self.player_size, self.player_size, self.use_this_pixmap ) def heuristic(self, a, b): (x1, y1) = a (x2, y2) = b return abs(x1 - x2) + abs(y1 - y2) def dijkstraSearch(self, graph, start, goal): """ Algorytm Dijkstry """ steps = PriorityQueue() steps.put(start, 0) cameFrom = {} costSoFar = {} cameFrom[start] = None costSoFar[start] = 0 # dopoki cos w liscie krokow while not steps.empty(): # pozyskaj miejsce, w ktorym jestes current = steps.get() # jesli dotarles do celu, to przerwij if current == goal: break # dla kazdego z sasiadow for next in graph.neighbours(current): # oblicz nowy koszt dojscia (dotychczasowy + do sasiada) newCost = costSoFar[current] + graph.cost(current, next) # jezeli koszt nie istnial wczesniej # lub jest nizszy niz poprzednik # to umiesc go w liscie kosztow do nastepnego kroku if next not in costSoFar or newCost < costSoFar[next]: costSoFar[next] = newCost # jako priorytet ustaw koszt priority = newCost steps.put(next, priority) cameFrom[next] = current # zwroc koszt dojscia i liste krokow (lista od konca) return cameFrom, costSoFar def aStarSearch(self, graph, start, goal): frontier = PriorityQueue() frontier.put(start, 0) came_from = {} cost_so_far = {} came_from[start] = None cost_so_far[start] = 0 while not frontier.empty(): current = frontier.get() if current == goal: break for next in graph.neighbours(current): new_cost = cost_so_far[current] + graph.cost(current, next) if next not in cost_so_far or new_cost < cost_so_far[next]: cost_so_far[next] = new_cost priority = new_cost + self.heuristic(goal, next) frontier.put(next, priority) came_from[next] = current return came_from, cost_so_far def reconstructPath(self, came_from, start, goal): current = goal path = [current] while current != start: current = came_from[current] path.append(current) path.reverse() return path def draw_tile(self, graph, id, style, width): r = "." if 'number' in style and id in style['number']: r = "%d" % style['number'][id] if ('point_to' in style and style['point_to'].get(id, None) is not None): (x1, y1) = id (x2, y2) = style['point_to'][id] if x2 == x1 + 1: r = "\u2192" if x2 == x1 - 1: r = "\u2190" if y2 == y1 + 1: r = "\u2193" if y2 == y1 - 1: r = "\u2191" if 'start' in style and id == style['start']: r = "A" if 'goal' in style and id == style['goal']: r = "Z" if 'path' in style and id in style['path']: r = "@" if id in graph.walls: r = "#" * width return r def draw_grid(self, graph, width=2, **style): for y in range(graph.height): for x in range(graph.width): print("%%-%ds" % width % self.draw_tile(graph, (x, y), style, width), end="") print() @pyqtSlot(str) def goTo(self, position): x, y = position.split() pointX = int(int(x) / 80) pointY = int(int(y) / 80) playerX = int(self.player_x / 80) playerY = int(self.player_y / 80) if self.pathFinding == "aStar": cameFrom, costSoFar = self.aStarSearch(self.graph, (playerX, playerY), (pointX, pointY)) elif self.pathFinding == "dijkstra": cameFrom, costSoFar = self.dijkstraSearch(self.graph, (playerX, playerY), (pointX, pointY)) self.path = self.reconstructPath(cameFrom, (playerX, playerY), (pointX, pointY)) self.movePlayer()
class MouseFollower(QWidget): def __init__(self, *args): super(MouseFollower, self).__init__(*args) self.following = False self.grabbing = False self.cursorTimer = QBasicTimer() def isGrabbing(self): return self.grabbing def isFollowing(self): return self.following mouseMoved = Signal(QPoint) clickWhileGrabbed = Signal() @Slot() def toggleGrab(self): refollow = self.following if refollow: self.endFollow() self.grabbing = not self.grabbing if refollow: self.startFollow() def toggleFollow(self): if self.following: self.endFollow() else: self.startFollow() @Slot() def startFollow(self): if not self.grabbing: self.cursorTimer.start(100, self) else: self.setMouseTracking(True) self.grabMouse() self.following = True @Slot() def endFollow(self): if not self.grabbing: self.cursorTimer.stop() else: self.releaseMouse() self.following = False def timerEvent(self, ev): if ev.timerId() == self.cursorTimer.timerId(): self.mouseMoved.emit(QCursor.pos()) else: super(MouseFollower, self).timerEvent(ev) def mouseMoveEvent(self, ev): self.mouseMoved.emit(QCursor.pos()) return super(MouseFollower, self).mouseMoveEvent(ev) def mousePressEvent(self, ev): if self.grabbing: self.clickWhileGrabbed.emit() return super(MouseFollower, self).mousePressEvent(ev)
class FieldUI(QFrame): def __init__(self, parent, game): super().__init__(parent) self.main_window = parent self.game = game self.rocks = self.game.rocks self.powerups = self.game.powerups self.bullets = self.game.bullets self.width, self.height = self.game.dimensions self.init_timers() self.start_timers() self.player_ui = PlayerUI(self, self.game) self.init_signals() self.setFocusPolicy(Qt.StrongFocus) def init_timers(self): """Initializes the timers in the game.""" self.game_timer = QBasicTimer() self.rock_timer = QBasicTimer() self.level_timer = QBasicTimer() self.powerup_timer = QBasicTimer() self.ticker_timer = QBasicTimer() self.bullet_timer = QBasicTimer() self.player_invincibility_timer = QBasicTimer() self.big_bomb_timer = QBasicTimer() self.slow_down_rocks_timer = QBasicTimer() self.shoot_rocks_timer = QBasicTimer() self.powerup_duration_timer = QTimer() def start_timers(self): """Starts the timers in the game.""" self.game_timer.start(self.game.game_speed, self) self.rock_timer.start(self.game.rock_speed, self) self.level_timer.start(self.game.level_speed, self) self.powerup_timer.start(self.game.rock_speed, self) self.player_invincibility_timer.start(int(PowerupTimeInterval.medium), self) self.big_bomb_timer.start(int(PowerupTimeInterval.big), self) self.slow_down_rocks_timer.start(int(PowerupTimeInterval.medium), self) self.shoot_rocks_timer.start(int(PowerupTimeInterval.very_big), self) self.bullet_timer.start(self.game.bullet_speed, self) def stop_timers(self): """Stops the timers in the game.""" self.game_timer.stop() self.rock_timer.stop() self.level_timer.stop() self.powerup_timer.stop() self.ticker_timer.stop() self.bullet_timer.stop() self.player_invincibility_timer.stop() self.big_bomb_timer.stop() self.slow_down_rocks_timer.stop() self.shoot_rocks_timer.stop() self.powerup_duration_timer.stop() def init_signals(self): """Initializes the signals in the game that connect to a method and calls it after the singnals are emitted. """ self.com = Communicate() self.com.move_left.connect(self.player_ui.move_left) self.com.move_right.connect(self.player_ui.move_right) self.com.restart.connect(self.main_window.restart_game) self.com.exit.connect(UserInterface.close_app) self.com.win.connect(self.win_the_game) def timerEvent(self, event): """Gets the emitted events from the timers and calls the appropriate methods for each of them. """ self.powerups_timer_events(event) self.gameplay_timer_events(event) if event.timerId() == self.ticker_timer.timerId(): self.ticker["value"] -= 1 if self.ticker["type"] == "player_invincibility": self.show_player_invincibility_info(self.ticker["value"]) if self.ticker["type"] == "slow_down_rocks": self.show_slow_down_rocks_info(self.ticker["value"]) if self.ticker["type"] == "shoot_rocks": self.show_shoot_rocks_info(self.ticker["value"]) self.bullet_ui = BulletUI(self, self.game, self.player_ui) self.bullets.append(self.bullet_ui) else: super(FieldUI, self).timerEvent(event) def gameplay_timer_events(self, event): """Gets the emitted events from the timers related to the gameplay and calls the appropriate methods and initializes the appropriate objects for each of them. """ if event.timerId() == self.game_timer.timerId(): self.rock_ui = RockUI(self, self.game) self.rocks.append(self.rock_ui) elif event.timerId() == self.rock_timer.timerId(): self.drop_down_rocks() elif event.timerId() == self.powerup_timer.timerId(): self.drop_down_powerups() elif event.timerId() == self.level_timer.timerId(): self.game.level_up() self.game_level = self.game.level if self.game_level == 21: self.com.win.emit() return self.game.set_speed_after_levelup() self.main_window.communicate.message_statusbar.\ emit("Level " + str(self.game_level)) self.game_timer.start(self.game.game_speed, self) self.rock_timer.start(self.game.rock_speed, self) elif event.timerId() == self.bullet_timer.timerId(): if self.bullets.count != 0: self.shoot_bullets() def powerups_timer_events(self, event): """Gets the emitted events from the timers related to the powerups and calls the appropriate methods and initializes the appropriate objects for each of them. """ if event.timerId() == self.player_invincibility_timer.timerId(): self.powerup_timer.start(self.game.rock_speed, self) self.powerup_ui = PowerupUI(self, self.game, PowerupType. player_invinciblility) self.powerups.append(self.powerup_ui) elif event.timerId() == self.big_bomb_timer.timerId(): self.powerup_timer.start(self.game.rock_speed, self) self.powerup_ui = PowerupUI(self, self.game, PowerupType.big_bomb) self.powerups.append(self.powerup_ui) elif event.timerId() == self.slow_down_rocks_timer.timerId(): self.powerup_timer.start(self.game.rock_speed, self) self.powerup_ui = PowerupUI(self, self.game, PowerupType.slow_down_rocks) self.powerups.append(self.powerup_ui) elif event.timerId() == self.shoot_rocks_timer.timerId(): self.powerup_timer.start(self.game.rock_speed, self) self.powerup_ui = PowerupUI(self, self.game, PowerupType.shoot_rocks) self.powerups.append(self.powerup_ui) def win_the_game(self): """Wins the game and shows an appropriate message to the player.""" self.game.win() self.stop_timers() self.main_window.communicate.message_statusbar.\ emit("You've won the game. You are a survivor. Well done!") def drop_down_powerups(self): """Moves the powerups down and check if the move is out of the game field. If that is true the powerups are removed from the field. """ temp_powerup = None for powerup in self.powerups: if(powerup.y >= self.game.dimensions[1] - powerup.height): temp_powerup = powerup else: powerup.drop_down() self.check_collision_between_player_and_powerup(powerup) if temp_powerup is not None: self.remove_powerup_from_field(temp_powerup) def check_collision_between_player_and_powerup(self, powerup): """Checks for a collision between the player and the powerups. If that is true initializes the powerups' effect according to their type. """ if(self.game.collision_detected(self.player_ui, powerup)): if powerup.type == PowerupType.player_invinciblility: self.init_player_invincibility(powerup) elif powerup.type == PowerupType.big_bomb: self.init_big_bomb() elif powerup.type == PowerupType.slow_down_rocks: self.init_slow_down_rocks(powerup) elif powerup.type == PowerupType.shoot_rocks: self.init_shoot_rocks(powerup) def init_slow_down_rocks(self, powerup): """Initializes the powerup slow_down_rocks and it's effect of the game.""" self.game.set_rock_speed(self.game.rock_speed + 3) self.game.set_speed(self.game.game_speed + 25) self.game_timer.start(self.game.game_speed, self) self.rock_timer.start(self.game.rock_speed, self) self.ticker = {"type": "slow_down_rocks", "value": powerup.duration // 1000} self.show_slow_down_rocks_info(self.ticker["value"]) self.ticker_timer.start(PowerupTimeInterval.second, self) self.powerup_duration_timer.setSingleShot(True) self.powerup_duration_timer.singleShot(powerup.duration, self.stop_slow_down_rocks) def show_slow_down_rocks_info(self, value): """Shows information about the powerup slow_down_rocks to the player. """ self.main_window.communicate.message_statusbar.\ emit("The rock are slowed down for " + str(value) + " seconds") def stop_slow_down_rocks(self): """Stops the effect of the powerup slow_down_rocks and shows a message to the player. """ self.powerup_duration_timer.stop() self.ticker_timer.stop() self.game.set_rock_speed(self.game.rock_speed - 3) self.game.set_speed(self.game.game_speed - 25) self.game_timer.start(self.game.game_speed, self) self.rock_timer.start(self.game.rock_speed, self) self.main_window.communicate.message_statusbar.\ emit("The rock are no longer slowed down. Be careful!") def shoot_bullets(self): """Moves the bullets up (to the target) and check if the move is out of the game field. If that is true the bullets are removed from the field. """ temp_bullet = None for bullet in self.bullets: if(bullet.y <= 1): temp_bullet = bullet else: bullet.move_to_target() self.check_collision_between_bullet_and_rock(bullet) if temp_bullet is not None: self.remove_bullet_from_field(temp_bullet) def check_collision_between_bullet_and_rock(self, bullet): """Checks for a collision between the bullets and the rocks. If that is true removes the rocks from the game field. """ for rock in self.rocks: if self.game.collision_detected(bullet, rock): self.remove_rock_from_field(rock) def init_shoot_rocks(self, powerup): """Initializes the powerup shoot_rocks and it's effect of the game.""" self.ticker = {"type": "shoot_rocks", "value": powerup.duration // 1000} self.show_shoot_rocks_info(self.ticker["value"]) self.ticker_timer.start(PowerupTimeInterval.second, self) self.powerup_duration_timer.setSingleShot(True) self.powerup_duration_timer.singleShot(powerup.duration, self.stop_shoot_rocks) def show_shoot_rocks_info(self, value): """Shows information about the powerup shoot_rocks to the player.""" self.main_window.communicate.message_statusbar.\ emit("You have bullets for " + str(value) + " seconds") def stop_shoot_rocks(self): """Stops the effect of the powerup shoot_rocks and shows a message to the player. """ self.powerup_duration_timer.stop() self.ticker_timer.stop() self.main_window.communicate.message_statusbar.\ emit("No more bullets!") def init_big_bomb(self): """Initializes the powerup big_bomb and it's effect of the game.""" temp_rocks = self.rocks[:] for temp_rock in temp_rocks: self.remove_rock_from_field(temp_rock) self.main_window.communicate.message_statusbar.\ emit("BOOM! The blast totally destroyed everything on the field!") def init_player_invincibility(self, powerup): """Initializes the powerup player_invincibility and it's effect of the game. """ if not self.player_ui.is_player_invincible: self.player_ui.set_player_invinciblity() self.ticker = {"type": "player_invincibility", "value": powerup.duration // 1000} self.show_player_invincibility_info(self.ticker["value"]) self.ticker_timer.start(PowerupTimeInterval.second, self) self.powerup_duration_timer.setSingleShot(True) self.powerup_duration_timer.singleShot( powerup.duration, self.stop_player_invincibility ) def stop_player_invincibility(self): """Stops the effect of the powerup player_invincibility and shows a message to the player. """ self.powerup_duration_timer.stop() self.ticker_timer.stop() self.player_ui.set_player_invinciblity() self.main_window.communicate.message_statusbar.\ emit("The player's invinciblility is off. You are mortal again!") def show_player_invincibility_info(self, value): """Shows information about the powerup player_invincibility_info to the player. """ self.main_window.communicate.message_statusbar.\ emit("The player is invincible for " + str(value) + " seconds") def remove_powerup_from_field(self, powerup): """Removes a powerup from the game field.""" self.powerups.remove(powerup) powerup.remove_shape() if(self.powerups.count == 0): self.powerup_timer.stop() def remove_bullet_from_field(self, bullet): """Removes a bullet from the game field.""" self.bullets.remove(bullet) bullet.remove_shape() if(self.bullets.count == 0): self.bullet_timer.stop() def remove_rock_from_field(self, rock): """Removes a rock from the game field.""" self.rocks.remove(rock) rock.remove_shape() def drop_down_rocks(self): """Moves the rocks down and check if the move is out of the game field. If that is true the rocks are removed from the field. """ temp_rock = None for rock in self.rocks: if(rock.y >= self.game.dimensions[1] - rock.height - 15): temp_rock = rock else: rock.drop_down() self.check_collision_between_rock_and_player(rock) if temp_rock is not None: self.remove_rock_from_field(temp_rock) def check_collision_between_rock_and_player(self, rock): """Checks for a collision between the rock and the player. If that is true the game is over. """ if(not self.player_ui.is_player_invincible and self.game.collision_detected(self.player_ui, rock)): self.stop_timers() self.game.lose() self.main_window.communicate.message_statusbar.\ emit("Game Over") def keyPressEvent(self, event): """Gets the events emitted when the player presses a key on the keyboard and calls the appropriate method. """ super(FieldUI, self).keyPressEvent(event) key = event.key() if key == Qt.Key_Escape: self.com.exit.emit() elif key == Qt.Key_R: self.com.restart.emit() elif self.game.is_lost: return elif key == Qt.Key_P: if self.game.is_running: self.pause_game() else: self.resume_game() return if self.game.is_paused: return elif key == Qt.Key_Left: self.com.move_left.emit() elif key == Qt.Key_Right: self.com.move_right.emit() def pause_game(self): """Pauses the game and shows a message to the player.""" if self.game.is_running: self.game.pause() self.stop_timers() self.main_window.communicate.message_statusbar.emit("Paused") def resume_game(self): """Resumes the game and shows a message to the player.""" if self.game.is_paused: self.game.resume() self.start_timers() self.main_window.communicate.message_statusbar.emit("Running") self.update()
class Login(QWidget, Ui_Login): def __init__(self): super(Login, self).__init__() self.setupUi(self) self.flagMove = False self.setWindowFlags( Qt.FramelessWindowHint) # 去掉标题栏的代码,这种顶部就不会出现空白,但是不能移动,需自己处理 self.movie = QMovie('image/login/0.gif') self.label_2.setMovie(self.movie) self.movie.start() # 用户头像的一系列效果设置 self.myQPushButton = MyQPushButton(self.slot_myQPushButton, self.frameGlobal) # 重写的QPushButton类 self.myQPushButton.setGeometry(234, 142, 16, 16) self.myQPushButton.setObjectName('myQPushButton') self.myQPushButton.setIcon( QIcon('image/login/8.png')) # 默认的icon,可以从数据库中根据条件选择 self.labUserImg_orgin_enterEvent = self.labUserImg.enterEvent # 鼠标移入用户头像 self.labUserImg_orgin_leaveEvent = self.labUserImg.leaveEvent # 鼠标离开用户头像 self.btnAddUser_orgin_enterEvent = self.btnAddUser.enterEvent # 鼠标移入滑出的添加账号按钮 self.btnAddUser_orgin_leaveEvent = self.btnAddUser.leaveEvent # 鼠标离开滑出的添加账号按钮 self.labUserImg.enterEvent = self.labUserImg_EnterEvent # 绑定函数 self.btnAddUser.enterEvent = self.btnAddUser_EnterEvent self.btnAddUser.leaveEvent = self.btnAddUser_LeaveEvent self.labUserImg.leaveEvent = self.labUserImg_LeaveEvent self.timer = QBasicTimer() # 鼠标离开用户头像或者添加账号按钮时的计时器 self.flagTimer = 0 # 鼠标离开用户头像或者添加账号按钮时的计时器的初始值 self.timerBtnAddUserMove = QBasicTimer() # 添加账号按钮移动开始至结束的计时事件 self.btnAddUserX = 203 # 添加账号按钮水平位置x的滑出效果初始标记(这个值原本就是它的x位置) # 账号输入下拉列表的设置 self.comboUserId.setView( QListView()) # 先随便设置一个QListView(),使下拉列表可以设置qss样式 self.actionLeftUserID = QAction(self.comboUserId) self.actionLeftUserID.setIcon(QIcon("image/login/3.png")) self.comboUserId.lineEdit().addAction( self.actionLeftUserID, QLineEdit.LeadingPosition) # 左侧图标 self.comboUserId.lineEdit().setPlaceholderText('账号') # 设置默认提示语 self.comboUserId.addItem(QIcon("image/login/02.jpg"), "1235321111") self.comboUserId.addItem(QIcon("image/login/03.jpg"), "3745634222") # self.comboUserID.setItemData(2, QPixmap('image/login/4.png'), Qt.DecorationRole) # 数据作为图标出现 # self.comboUserID.setItemIcon(1, QIcon("image/login/4.png")) # self.comboUserID.setItemDelegate() # self.comboUserID.setItemData(0, 0, Qt.UserRole - 1) # 锁定第0项。参数3如果是-256,第0项显示空字符 self.comboUserId.setCurrentIndex(-1) # 下拉列表初始设置为空,这样不用添加一个空的下拉项了 self.comboUserId.activated[str].connect(self.slot_comboUserID) self.comboUserID_orgin_focusInEvent = self.comboUserId.focusInEvent # 账号输入下拉列表获得焦点事件 self.comboUserId.focusInEvent = self.comboUserID_FocusInEvent # 账号输入下拉列表获得焦点事件的函数绑定 self.comboUserID_orgin_focusOutEvent = self.comboUserId.focusOutEvent # 账号输入下拉列表失去焦点事件 self.comboUserId.focusOutEvent = self.comboUserID_FocusOutEvent # 账号输入下拉列表失去焦点事件的函数绑定 self.comboUserID_orgin_mousePressEvent = self.comboUserId.mousePressEvent # 账号输入下拉列表鼠标按下事件 self.comboUserId.mousePressEvent = self.comboUserID_MousePressEvent # 账号输入下拉列表鼠标按下事件的函数绑定 self.flagComboUserID = False # 点击下拉箭头需要的标记 # 密码框的设置 self.actionLeftPassword = QAction(self.lEditPassword) self.actionLeftPassword.setIcon(QIcon("image/login/1.png")) self.actionRightPassword = QAction(self.lEditPassword) self.actionRightPassword.setIcon(QIcon("image/login/17.png")) self.actionRightPassword.triggered.connect( self.slot_actionRightPassword) self.menuKeyBoard = MyMenu(self) self.lEditPassword.addAction(self.actionLeftPassword, QLineEdit.LeadingPosition) # 左侧图标 self.lEditPassword.addAction(self.actionRightPassword, QLineEdit.TrailingPosition) # 右侧图标 self.lEditPassword.setPlaceholderText('密码') self.lEditPassword_orgin_focusInEvent = self.lEditPassword.focusInEvent self.lEditPassword.focusInEvent = self.lEditPassword_FocusInEvent self.lEditPassword_orgin_focusOutEvent = self.lEditPassword.focusOutEvent self.lEditPassword.focusOutEvent = self.lEditPassword_FocusOutEvent # 二维码登录界面frame的设置 self.frameQRcodeUpdata_orgin_enterEvent = self.frameQRcodeUpdata.enterEvent # 鼠标滑入更新二维码容器 self.frameQRcodeUpdata.enterEvent = self.frameQRcodeUpdata_EnterEvent self.frameQRcodeUpdata_orgin_leaveEvent = self.frameQRcodeUpdata.leaveEvent # 鼠标离开更新二维码容器 self.frameQRcodeUpdata.leaveEvent = self.frameQRcodeUpdata_LeaveEvent self.timerFrameQRcodeUpdata = QBasicTimer() self.flagTimerFrameQRcodeUpdata = False self.flagTimerFrameQRcodeUpdataX = 115 self.btnFrameQRcodeBack.clicked.connect( self.slot_btnQRcode_btnFrameQRcodeBack) # 一些控件的信号与槽的绑定,以及隐藏初始界面不应该显示的控件 self.btnAddUser.hide() # 先把添加账号按钮隐藏,鼠标移入self.labUserImg时再滑出 self.btnLoginSingle.hide() # 单账号登录按钮在self.btnAddUser被点击时才显示 self.frameAdduser.hide() # 此容器内的控件在self.btnAddUser被点击时才显示 self.frameQRcode.hide() self.btnSignIn.clicked.connect(lambda: QDesktopServices.openUrl( QUrl(("https://ssl.zc.qq.com/v3/index-chs.html")))) self.btnFindBack.clicked.connect(lambda: QDesktopServices.openUrl( QUrl(( "https://aq.qq.com/v2/uv_aq/html/reset_pwd/pc_reset_pwd_input_account.html" )))) self.btnSetting.clicked.connect( lambda: self.timerError.start(10, self)) # 以后再写设置界面 self.btnQRcode.clicked.connect(self.slot_btnQRcode_btnFrameQRcodeBack) # self.btnQRcode.clicked.connect(lambda :self.timerError.start(10, self)) self.btnAddUser.clicked.connect(self.slot_btnAddUser_btnLoginSingle) # self.btnAddUser.clicked.connect(lambda: self.timerError.start(10, self)) self.btnLoginSingle.clicked.connect( self.slot_btnAddUser_btnLoginSingle) self.btnCancel.clicked.connect(self.slot_btnAddUser_btnLoginSingle) self.btnError.clicked.connect(lambda: self.timerError.start(10, self)) self.btnSetting.clicked.connect(self.slot_btnSetting) # 模拟登录需要的一些数据及设置 self.login_test() # # 界面滑出效果,如果y设置为1,界面出现的位置不对,尝试让界面y=330,然后隐藏,再进行滑出试试 # # 同timerEvent事件中,elif e.timerId() == self.timerLoginShow.timerId():一起取消注释调试 # self.setFixedHeight(1) # self.timerLoginShow = QBasicTimer() # self.timerLoginShow.start(1, self) # self.login_test() def slot_btnSetting(self): print(111) def login_test(self): """此函数内是模拟已经登录过此账号,发生的界面变化""" # USER_ID = '165227316' # USER_LOGINED_ON = True self.comboUserId.setEditText(USER_ID) self.lEditPassword.setText('xxxxxxxxxxx') self.checkBoxAotuLogin.click() self.checkBoxKeepPassword.click() # 测试提示信息的显示。self.frameError的位置是(0,330),是看不见的,因为窗口的固定高度就是330,所以这里把窗口的 # 固定高度加上20(self.frameError的固定高度就是20),自然就显示出来了。self.frameGlobal的固定高度是330,没有变化 self.timerError = QBasicTimer() if USER_LOGINED_ON: self.setFixedHeight(self.height() + 20) def slot_actionRightPassword(self): """在槽内setMenu,然后显示,才可以改变menu菜单的位置。 如果在外面setMenu就不用self.menuKeyBoard.exec()方法了,直接点击就显示了。 """ self.actionRightPassword.setMenu(self.menuKeyBoard) pos = QPoint() pos.setX(93) pos.setY(233) self.menuKeyBoard.exec(self.mapToGlobal(pos)) def slot_comboUserID(self, text): """选择下拉项后,重新设置显示为空项,再改变lineEdit的text""" self.comboUserId.setCurrentIndex(-1) self.comboUserId.lineEdit().setText(text) def slot_myQPushButton(self): """状态功能在此设置,因这程序只是一个登录界面,所以没写状态功能""" sender = self.sender() self.myQPushButton.setIcon(sender.icon()) def slot_btnAddUser_btnLoginSingle(self): if self.sender() == self.btnAddUser: flag = True self.timerError.start(10, self) # 如果有已经登录提示,开始计时器 else: flag = False self.setFocus() self.frameAdduser.setVisible(flag) self.btnLoginSingle.setVisible(flag) self.frameLogin.setHidden(flag) self.btnSignIn.setHidden(flag) self.btnQRcode.setHidden(flag) def slot_btnQRcode_btnFrameQRcodeBack(self): if self.sender() == self.btnQRcode: flag = True self.timerError.start(10, self) # 如果有已经登录提示,开始计时器 else: flag = False self.frameGlobal.setHidden(flag) self.frameQRcode.setVisible(flag) self.btnFrameQRcodeUrl.hide() self.labFrameQRcodeErrorImg.hide() def labUserImg_EnterEvent(self, e): self.btnAddUser.show() self.flagTimer = 0 self.timer.stop() self.timerBtnAddUserMove.start(3, Qt.PreciseTimer, self) return self.labUserImg_orgin_enterEvent(e) def labUserImg_LeaveEvent(self, e): self.timer.start(10, Qt.PreciseTimer, self) return self.labUserImg_orgin_leaveEvent(e) def btnAddUser_EnterEvent(self, e): self.flagTimer = 0 self.timer.stop() return self.btnAddUser_orgin_enterEvent(e) def btnAddUser_LeaveEvent(self, e): self.timer.start(10, Qt.PreciseTimer, self) return self.btnAddUser_orgin_leaveEvent(e) def comboUserID_MousePressEvent(self, e): """处理点击下拉箭头后,使封装的lineEdit左侧图标变成蓝色""" self.flagComboUserID = True self.actionLeftUserID.setIcon(QIcon("image/login/4.png")) return self.comboUserID_orgin_mousePressEvent(e) def comboUserID_FocusInEvent(self, e): """ 获得焦点:改变图标,默认字符设置为空,再改变字符尺寸变大和颜色,就不影响视觉效果了(无内容时光标变小, 有输入时光标变大) """ self.actionLeftUserID.setIcon(QIcon("image/login/4.png")) self.comboUserId.lineEdit().setPlaceholderText('') self.comboUserId.setStyleSheet('font-size:17px;color:blank;') return self.comboUserID_orgin_focusInEvent(e) def comboUserID_FocusOutEvent(self, e): """失去焦点:恢复图标,恢复默认字符,再恢复字符尺寸变小和颜色""" self.actionLeftUserID.setIcon(QIcon("image/login/3.png")) self.comboUserId.lineEdit().setPlaceholderText('账号') if self.flagComboUserID: # 如果点击了下拉箭头 self.actionLeftUserID.setIcon(QIcon("image/login/4.png")) self.flagComboUserID = False # 恢复标记,不然会一直判断是True,封装的lineEdit失去焦点时,左侧图标还是蓝色 text = self.comboUserId.lineEdit().text() if text == '': # 这个if,else语段,是处理让默认字符“密码”和有输入以及获得焦点时的字符大小不一样 self.comboUserId.setStyleSheet('font-size:12px;color:#838383;') else: self.comboUserId.setStyleSheet('font-size:17px;color:blank;') return self.comboUserID_orgin_focusOutEvent(e) def lEditPassword_FocusInEvent(self, e): """获得焦点:改变图标,默认字符设置为空,再改变字符尺寸变大和颜色,就不影响视觉效果了""" self.actionLeftPassword.setIcon(QIcon("image/login/2.png")) self.lEditPassword.setPlaceholderText('') self.lEditPassword.setStyleSheet('font-size:16px;color:blank;') return self.lEditPassword_orgin_focusInEvent(e) def lEditPassword_FocusOutEvent(self, e): """失去焦点:恢复图标,恢复默认字符,再恢复字符尺寸变小和颜色""" self.actionLeftPassword.setIcon(QIcon("image/login/1.png")) self.lEditPassword.setPlaceholderText('密码') text = self.lEditPassword.text() if text == '': self.lEditPassword.setStyleSheet('font-size:12px;color:#838383;') else: self.lEditPassword.setStyleSheet('font-size:16px;color:blank;') return self.lEditPassword_orgin_focusOutEvent(e) def frameQRcodeUpdata_EnterEvent(self, e): """鼠标滑入更新二维码容器:""" self.timerFrameQRcodeUpdata.start(1, self) self.btnFrameQRcodeUrl.show() return self.frameQRcodeUpdata_orgin_enterEvent(e) def frameQRcodeUpdata_LeaveEvent(self, e): """鼠标离开更新二维码容器:""" self.timerFrameQRcodeUpdata.start(1, self) self.btnFrameQRcodeUrl.hide() return self.frameQRcodeUpdata_orgin_leaveEvent(e) def mousePressEvent(self, e): if e.button() == Qt.LeftButton: self.setFocus() # 主要处理焦点在账号和密码框内时,左键窗口的焦点位置,让输入框失去焦点 self.flagMove = True self.posMove = e.globalPos() - self.pos() # 获取鼠标相对窗口的位置 e.accept() elif e.button() == Qt.RightButton: # 如果焦点在密码框里,右键窗口的焦点位置,账号框会得到焦点并全选 if self.lEditPassword.hasFocus(): self.comboUserId.setFocus() self.comboUserId.lineEdit().selectAll() def mouseMoveEvent(self, e): if Qt.LeftButton and self.flagMove: self.move(e.globalPos() - self.posMove) # 更改窗口位置 e.accept() def mouseReleaseEvent(self, e): self.flagMove = False def timerEvent(self, e): if e.timerId() == self.timerBtnAddUserMove.timerId(): self.btnAddUser.move(self.btnAddUserX, 102) self.btnAddUserX += 1 if self.btnAddUserX >= 273: self.timerBtnAddUserMove.stop() self.btnAddUserX = 203 elif e.timerId() == self.timer.timerId(): if self.flagTimer >= 40: self.btnAddUser.hide() self.timer.stop() self.flagTimer = 0 self.flagTimer += 1 elif e.timerId() == self.timerError.timerId(): if self.height() == 330: self.timerError.stop() else: self.setFixedHeight(self.height() - 1) elif e.timerId() == self.timerFrameQRcodeUpdata.timerId(): if self.flagTimerFrameQRcodeUpdata: self.flagTimerFrameQRcodeUpdataX += 1 self.btnFrameQRcodeUpdata.move( self.flagTimerFrameQRcodeUpdataX, self.btnFrameQRcodeUpdata.y()) if self.flagTimerFrameQRcodeUpdataX == 115: self.timerFrameQRcodeUpdata.stop() self.flagTimerFrameQRcodeUpdata = False elif not self.flagTimerFrameQRcodeUpdata: self.flagTimerFrameQRcodeUpdataX -= 1 self.btnFrameQRcodeUpdata.move( self.flagTimerFrameQRcodeUpdataX, self.btnFrameQRcodeUpdata.y()) if self.flagTimerFrameQRcodeUpdataX == 20: self.timerFrameQRcodeUpdata.stop() self.flagTimerFrameQRcodeUpdata = True
class Board(QFrame): # 自定义信号,将信息展示在状态栏 msg2Statusbar = pyqtSignal(str) # 定义常量值 BoardWidth = 10 # 块的宽度 BoardHeight = 22 # 块的长度 Speed = 300 # 下落的速度,即timer循环刷新速度 def __init__(self, parent): # noinspection PyArgumentList super().__init__(parent) self.timer = QBasicTimer() self.isWaitingAfterLine = False self.curX = 0 self.curY = 0 self.numLinesRemoved = 0 self.board = [] # 0到7的数字列表,表示面板上的形状和位置 self.setFocusPolicy(Qt.StrongFocus) self.isStarted = False self.isPaused = False self.clear_board() def shape_at(self, x, y): return self.board[(y * Board.BoardWidth) + x] def set_shape_at(self, x, y, shape): self.board[(y * Board.BoardWidth) + x] = shape # 因为界面Board大小可以动态调整,所以方块的大小也要随着改变 def square_width(self): return self.contentsRect().width() // Board.BoardWidth def square_height(self): return self.contentsRect().height() // Board.BoardHeight def start(self): if self.isPaused: return self.isStarted = True self.isWaitingAfterLine = False self.numLinesRemoved = 0 self.clear_board() self.msg2Statusbar.emit(str(self.numLinesRemoved)) self.new_piece() self.timer.start(Board.Speed, self) def pause(self): if not self.isStarted: return self.isPaused = not self.isPaused if self.isPaused: self.timer.stop() self.msg2Statusbar.emit("paused") else: self.timer.start(Board.Speed, self) self.msg2Statusbar.emit(str(self.numLinesRemoved)) self.update() def paintEvent(self, event): painter = QPainter(self) rect = self.contentsRect() board_top = rect.bottom() - Board.BoardHeight * self.square_height() # 首先绘制所有已经落下去的方块 for i in range(Board.BoardHeight): for j in range(Board.BoardWidth): shape = self.shape_at(j, Board.BoardHeight - i - 1) if shape != Tetrominoe.NoShape: self.draw_square(painter, rect.left() + j * self.square_width(), board_top + i * self.square_height(), shape) # 绘制正在下降的方块 if self.curPiece.shape() != Tetrominoe.NoShape: for i in range(4): x = self.curX + self.curPiece.x(i) y = self.curY - self.curPiece.y(i) self.draw_square(painter, rect.left() + x * self.square_width(), board_top + (Board.BoardHeight - y - 1) * self.square_height(), self.curPiece.shape()) def keyPressEvent(self, event): if not self.isStarted or self.curPiece.shape() == Tetrominoe.NoShape: super(Board, self).keyPressEvent(event) return key = event.key() # p键暂停 if key == Qt.Key_P: self.pause() return if self.isPaused: return # 左右移动 elif key == Qt.Key_Left: self.try_move(self.curPiece, self.curX - 1, self.curY) elif key == Qt.Key_Right: self.try_move(self.curPiece, self.curX + 1, self.curY) # 旋转 elif key == Qt.Key_Down: self.try_move(self.curPiece.rotate_right(), self.curX, self.curY) elif key == Qt.Key_Up: self.try_move(self.curPiece.rotate_left(), self.curX, self.curY) # 下降到底部 elif key == Qt.Key_Space: self.drop_down() # 加速 elif key == Qt.Key_D: self.one_line_down() else: super(Board, self).keyPressEvent(event) def timerEvent(self, event): """ 时间事件 当前一个方块降落到底部后,创建一个新的方块 """ if event.timerId() == self.timer.timerId(): if self.isWaitingAfterLine: self.isWaitingAfterLine = False self.new_piece() else: self.one_line_down() else: super(Board, self).timerEvent(event) def clear_board(self): """通过设置Tetrominoe.NoShape清除面板""" for i in range(Board.BoardHeight * Board.BoardWidth): self.board.append(Tetrominoe.NoShape) def drop_down(self): new_y = self.curY while new_y > 0: if not self.try_move(self.curPiece, self.curX, new_y - 1): break new_y -= 1 self.piece_dropped() def one_line_down(self): if not self.try_move(self.curPiece, self.curX, self.curY - 1): self.piece_dropped() def piece_dropped(self): for i in range(4): x = self.curX + self.curPiece.x(i) y = self.curY - self.curPiece.y(i) self.set_shape_at(x, y, self.curPiece.shape()) self.remove_full_lines() if not self.isWaitingAfterLine: self.new_piece() def remove_full_lines(self): """ 如果到达底部,会调用removeFullLines()方法。 我们会检查所有完整的线条然后删除它们。 然后移动所有行高于当前删除整行一行。 请注意,我们反的顺序行被删除。否则,就会出错。 """ num_full_lines = 0 rows_to_remove = [] for i in range(Board.BoardHeight): n = 0 for j in range(Board.BoardWidth): if not self.shape_at(j, i) == Tetrominoe.NoShape: n = n + 1 if n == 10: rows_to_remove.append(i) rows_to_remove.reverse() # 反转 for m in rows_to_remove: for k in range(m, Board.BoardHeight): for l in range(Board.BoardWidth): self.set_shape_at(l, k, self.shape_at(l, k + 1)) num_full_lines = num_full_lines + len(rows_to_remove) if num_full_lines > 0: self.numLinesRemoved = self.numLinesRemoved + num_full_lines self.msg2Statusbar.emit(str(self.numLinesRemoved)) self.isWaitingAfterLine = True self.curPiece.set_shape(Tetrominoe.NoShape) self.update() def new_piece(self): """ 通过newPiece()方法创建一个新的方块 如果不能进入它的初始位置,游戏就结束 """ self.curPiece = Shape() self.curPiece.set_random_shape() self.curX = Board.BoardWidth // 2 + 1 self.curY = Board.BoardHeight - 1 + self.curPiece.min_y() if not self.try_move(self.curPiece, self.curX, self.curY): self.curPiece.set_shape(Tetrominoe.NoShape) self.timer.stop() self.isStarted = False self.msg2Statusbar.emit("Game over") def try_move(self, new_piece, new_x, new_y): """ 使用tryMove()方法尝试移动方块。 如果方块的边缘已经接触到面板边缘或者不能移动,我们返回False。 否则我们当前块下降到一个新的位置。 """ for i in range(4): x = new_x + new_piece.x(i) y = new_y - new_piece.y(i) if x < 0 or x >= Board.BoardWidth or y < 0 or y >= Board.BoardHeight: return False if self.shape_at(x, y) != Tetrominoe.NoShape: return False self.curPiece = new_piece self.curX = new_x self.curY = new_y self.update() return True def draw_square(self, painter, x, y, shape): color_table = [0x000000, 0xCC6666, 0x66CC66, 0x6666CC, 0xCCCC66, 0xCC66CC, 0x66CCCC, 0xDAAA00] color = QColor(color_table[shape]) painter.fillRect(x + 1, y + 1, self.square_width() - 2, self.square_height() - 2, color) painter.setPen(color.lighter()) painter.drawLine(x, y + self.square_height() - 1, x, y) painter.drawLine(x, y, x + self.square_width() - 1, y) painter.setPen(color.darker()) painter.drawLine(x + 1, y + self.square_height() - 1, x + self.square_width() - 1, y + self.square_height() - 1) painter.drawLine(x + self.square_width() - 1, y + self.square_height() - 1, x + self.square_width() - 1, y + 1)
class GameState(QFrame): """Игровая модель""" status_bar_msg = pyqtSignal(str) player_data_msg = pyqtSignal(dict) records_msg = pyqtSignal() def __init__(self, parent): super().__init__(parent) self.timer = QBasicTimer() self.setFocusPolicy(Qt.StrongFocus) def start(self): """Начинаем игру""" self.game_board = Field(20, 10) self.shape = Shape() self.shape.new_shape(self.game_board) self.status_bar_msg.emit(str(self.game_board.score)) self.timer.start(525, self) def send_player(self): name = QInputDialog.getText(None, "Get player name", "Player name:") if name[0]: self.player_data_msg.emit({name[0]: self.game_board.score}) def timerEvent(self, event): if event.timerId() == self.timer.timerId(): self.game_board.score += 1 self.status_bar_msg.emit(str(self.game_board.score)) if self.game_board.is_game_over: self.timer.stop() self.status_bar_msg.emit("Game over!") self.send_player() self.records_msg.emit() elif self.game_board.want_new_shape: self.shape.new_shape(self.game_board) self.update() else: self.shape.move_down(self.game_board) self.update() else: super(GameState, self).timerEvent(event) def paintEvent(self, event): qp = QPainter() qp.begin(self) self.draw(qp) qp.end() def draw_block(self, qp, x, y, color): """Рисуем отдельный блок""" color = QColor(color) col = QColor(self.game_board.grid_color) qp.setPen(col) qp.setBrush(color) qp.drawRect(x, y, 20, 20) def draw(self, qp): """Рисуем карту, рисуем фигуру (по блокам)""" for y in range(self.game_board.rows): for x in range(self.game_board.columns): if self.game_board.grid[y][x]: self.draw_block(qp, x * 20, y * 20, self.shape.shape_color) else: self.draw_block(qp, x * 20, y * 20, self.game_board.grid_color) for y in range(len(self.shape.shape)): for x in range(len(self.shape.shape[y])): if self.shape.shape[y][x]: self.draw_block(qp, (x + self.shape.x) * 20, (y + self.shape.y) * 20, self.shape.shape_color) def keyPressEvent(self, event): if self.game_board.is_game_over: super(GameState, self).keyPressEvent(event) return if event.key() == Qt.Key_Left: self.shape.try_move(self.game_board, self.shape.x - 1, self.shape.y) self.update() elif event.key() == Qt.Key_Right: self.shape.try_move(self.game_board, self.shape.x + 1, self.shape.y) self.update() elif event.key() == Qt.Key_Down: self.shape.move_down(self.game_board) self.update() elif event.key() == Qt.Key_Space: self.shape.drop_down(self.game_board) self.update() elif event.key() == Qt.Key_Up: self.shape.rotate_shape(self.game_board, self.shape.x, self.shape.y) self.shape.try_move(self.game_board, self.shape.x, self.shape.y) self.update() else: super(GameState, self).keyPressEvent(event)
class TetrisGame(QMainWindow): def __init__(self): super().__init__() # 정지ing self.is_paused = False # 시작ing self.is_started = False self.initUI() '''인터페이스 초기화''' def initUI(self): # 테트리스 크기 self.grid_size = 22 # 게임 프레임률 self.fps = 100 self.timer = QBasicTimer() # 초점 self.setFocusPolicy(Qt.StrongFocus) # 수평 배치 layout_horizontal = QHBoxLayout() self.inner_board = InnerBoard() self.external_board = ExternalBoard(self, self.grid_size, self.inner_board) layout_horizontal.addWidget(self.external_board) self.side_panel = SidePanel(self, self.grid_size, self.inner_board) layout_horizontal.addWidget(self.side_panel) self.status_bar = self.statusBar() self.external_board.score_signal[str].connect( self.status_bar.showMessage) self.start() self.center() self.setWindowTitle self.show() self.setFixedSize( self.external_board.width() + self.side_panel.width(), self.side_panel.height() + self.status_bar.height()) # AI 제어 self.tetris_ai = TetrisAI(self.inner_board) self.next_action = None self.pre_tetris = tetrisShape().shape_empty '''게임 인터페이스가 화면 가운데로 이동''' def center(self): screen = QDesktopWidget().screenGeometry() size = self.geometry() self.move((screen.width() - size.width()) // 2, (screen.height() - size.height()) // 2) '''업데이트 인터페이스''' def updateWindow(self): self.external_board.updateData() self.side_panel.updateData() self.update() '''시작''' def start(self): if self.is_started: return self.is_started = True self.inner_board.createNewTetris() self.timer.start(self.fps, self) '''일시정지/무정지''' def pause(self): if not self.is_started: return self.is_paused = not self.is_paused if self.is_paused: self.timer.stop() self.external_board.score_signal.emit('Paused') else: self.timer.start(self.fps, self) self.updateWindow() '''크로노그래프 사건''' def timerEvent(self, event): if event.timerId() == self.timer.timerId(): if not self.next_action: self.next_action = self.tetris_ai.getNextAction() if self.next_action: while self.inner_board.current_direction != self.next_action[0]: self.inner_board.rotateAnticlockwise() count = 0 while self.inner_board.current_coord[0] != self.next_action[ 1] and count < 5: if self.inner_board.current_coord[0] > self.next_action[1]: self.inner_board.moveLeft() else: self.inner_board.moveRight() count += 1 removed_lines = self.inner_board.moveDown() self.external_board.score += removed_lines if self.pre_tetris != self.inner_board.current_tetris: self.next_action = None self.pre_tetris = self.inner_board.current_tetris self.updateWindow() else: super(TetrisGame, self).timerEvent(event) '''버튼 ''' def keyPressEvent(self, event): if not self.is_started or self.inner_board.current_tetris == tetrisShape( ).shape_empty: super(TetrisGame, self).keyPressEvent(event) return key = event.key() # P 키 타임 if key == Qt.Key_P: self.pause() return if self.is_paused: return else: super(TetrisGame, self).keyPressEvent(event) self.updateWindow()
class App(qw.QMainWindow): def __init__(self): super().__init__() self.block_size = 30 # одна из фич self.saved_games = deque(maxlen=3) self.timer = QBasicTimer() self.status_bar = self.statusBar() self.cols = 15 self.rows = 15 self.colors_num = 5 self.name = 'Player' self._default_name = True self.setWindowTitle('Blocks') # статистика self.last_stats = ('You', self.cols, self.rows, 0) self.game = Blocks(self.cols, self.rows, self.colors_num, self.name) self.game.start_new_game() self.editor = Editor() self.editor.butt_ok.clicked.connect(self.edit_settings_close_editor) self.sl_menu = None self.score_table = None self.highest = CountHighest(self.game, 2) new_act = qw.QAction('&New Game', self) new_act.setStatusTip('Start new game') new_act.triggered.connect(self.start_new_game) again_act = qw.QAction('&Play Again', self) again_act.setStatusTip('Start new game with the same field') again_act.triggered.connect(self.start_again) score_act = qw.QAction('&Score Table', self) score_act.setStatusTip('Show score table') score_act.setShortcut('Ctrl+T') score_act.triggered.connect(self.open_score_table) exit_act = qw.QAction('&Exit', self) exit_act.setShortcut('Ctrl+Q') exit_act.setStatusTip('Exit application') exit_act.triggered.connect(sys.exit) edit_act = qw.QAction('&Edit Settings', self) edit_act.setShortcut('Ctrl+E') edit_act.setStatusTip('Change nickname and field size') edit_act.triggered.connect(self.open_editor) save_act = qw.QAction('&Save', self) save_act.setShortcut('Ctrl+S') save_act.triggered.connect(lambda: self.status_bar.showMessage( self.save_game())) load_act = qw.QAction('&Load', self) load_act.setShortcut('Ctrl+L') load_act.triggered.connect(self.open_loader) count_act = qw.QAction('&Count Highest Score', self) count_act.setStatusTip('It is a long process, ' 'some game features will be unavailable') count_act.triggered.connect(self.count_highest) cancel_act = qw.QAction('&Cancel Counting', self) cancel_act.triggered.connect(lambda: self.stop_counting()) menubar = self.menuBar() file_menu = menubar.addMenu('&Game') file_menu.addAction(new_act) file_menu.addAction(again_act) file_menu.addAction(score_act) file_menu.addAction(exit_act) edit_menu = menubar.addMenu('&Edit') edit_menu.addAction(edit_act) save_menu = menubar.addMenu('&Save/Load') save_menu.addAction(save_act) save_menu.addAction(load_act) other_menu = menubar.addMenu('&Other') other_menu.addAction(count_act) other_menu.addAction(cancel_act) self.acts_to_lock = (count_act, ) self.canvas = Canvas(self.game, self.block_size, self) self.score_total = qw.QLCDNumber(self) self.score_total.display(self.game.score()) self.score_total.setSegmentStyle(qw.QLCDNumber.Flat) self.score_total.setStyleSheet("""color: black; background: white;""") self.score_curr = qw.QLCDNumber(self) self.score_curr.display(Blocks.count_score(self.game.highlighted())) self.score_curr.setSegmentStyle(qw.QLCDNumber.Flat) self.score_curr.setStyleSheet("""color: black; background: white;""") scores_layout = qw.QHBoxLayout() scores_layout.addWidget(self.score_total) scores_layout.addWidget(self.score_curr) self.main_layout = qw.QVBoxLayout() self.main_layout.addWidget(self.canvas) self.main_layout.addLayout(scores_layout) self.centr_wid = qw.QWidget(self) self.centr_wid.setLayout(self.main_layout) self.setCentralWidget(self.centr_wid) self.resize_window() self.show() self.timer.start(40, self) def open_loader(self): saves = [save for save in self.saved_games] if saves: self.sl_menu = SaveLoadMenu(saves) [self._set_button_clicked(slot) for slot in self.sl_menu.slots] self.sl_menu.show() def _set_button_clicked(self, slot): slot[0].clicked.connect(lambda: self._load_game(slot[1])) def _load_game(self, game: Blocks): self.timer.stop() self.stop_counting() g = deepcopy(game) self.game = g self.canvas.game = g self.resize_window() self.timer.start(40, self) self.sl_menu.hide() def save_game(self): self.saved_games.append(deepcopy(self.game)) return 'Game saved' def edit_settings_close_editor(self): self.timer.stop() self.stop_counting() settings = self.editor.get_info() self.editor.hide() self.cols, self.rows, self.colors_num = settings self.game.change_settings(*settings) self.start_new_game() self.setWindowTitle('Blocks ({})'.format(self.name)) def open_editor(self): self.editor.pass_info( self.cols, self.rows, self.colors_num) self.editor.show() def open_score_table(self): self.score_table = ScoreTable(self.last_stats) self.score_table.show() def count_highest(self): self.highest = CountHighest(self.game, 2) self.highest.fin.connect(self.show_highest) [act.setDisabled(True) for act in self.acts_to_lock] self.highest.start() def show_highest(self, highest: int): self.stop_counting() self.status_bar.showMessage( 'Possible highest score: {}'.format(highest)) def stop_counting(self): self.highest.shutdown() [act.setDisabled(False) for act in self.acts_to_lock] def timerEvent(self, event): if event.timerId() == self.timer.timerId(): self.update_ui() if self.game.gameover() is True: self.on_gameover() else: super(App.self).timerEvent(self, event) def update_ui(self): self.score_total.display(self.game.score()) self.score_total.update() self.score_curr.display(Blocks.count_score(self.game.highlighted())) self.score_curr.update() self.canvas.update() def on_gameover(self): self.timer.stop() if self._default_name: text, ok = qw.QInputDialog.getText( self, 'Blocks', 'Enter your name:', text='Player') self.name = text or 'Player' if ok else 'Player' self._default_name = False self.game.change_settings( self.game.cols(), self.game.rows(), self.game.colors_num(), self.name) self.last_stats = ( self.game.name(), self.game.cols(), self.game.rows(), self.game.score()) BlocksStatSaver.save_to_stats(self.game) choice = qw.QMessageBox.question( self, 'Game Over! (Score: {})'.format(self.game.score()), "Do you want to start a new game?", qw.QMessageBox.Yes | qw.QMessageBox.Reset | qw.QMessageBox.No) if choice == qw.QMessageBox.Yes: self.start_new_game() elif choice == qw.QMessageBox.Reset: self.start_again() else: sys.exit() def start_new_game(self): self.stop_counting() self.game.start_new_game() self.resize_window() self.timer.start(40, self) def start_again(self): self.stop_counting() self.game.start_again() self.resize_window() self.timer.start(40, self) def resize_window(self): self.cols = self.game.cols() self.rows = self.game.rows() self.name = self.game.name() self.colors_num = self.game.colors_num() self.canvas.setFixedSize( self.cols * self.block_size, self.rows * self.block_size) self.setFixedWidth(self.cols * self.block_size + 20) self.setFixedHeight(self.rows * self.block_size + 100) self.setWindowTitle('Blocks ({})'.format(self.name))
class Board(QFrame): msg2Statusbar = pyqtSignal(str) BoardWidth = 10 BoardHeight = 22 Speed = 300 def __init__(self, parent): super().__init__(parent) self.initBoard() def initBoard(self): self.timer = QBasicTimer() self.isWaitingAfterLine = False self.curX = 0 self.curY = 0 self.numLinesRemoved = 0 self.board = [] self.setFocusPolicy(Qt.StrongFocus) self.isStarted = False self.isPaused = False self.clearBoard() def shapeAt(self, x, y): return self.board[(y * Board.BoardWidth) + x] def setShapeAt(self, x, y, shape): self.board[(y * Board.BoardWidth) + x] = shape def squareWidth(self): return self.contentsRect().width() // Board.BoardWidth def squareHeight(self): return self.contentsRect().height() // Board.BoardHeight def start(self): if self.isPaused: return self.isStarted = True self.isWaitingAfterLine = False self.numLinesRemoved = 0 self.clearBoard() self.msg2Statusbar.emit(str(self.numLinesRemoved)) self.newPiece() self.timer.start(Board.Speed, self) def pause(self): if not self.isStarted: return self.isPaused = not self.isPaused if self.isPaused: self.timer.stop() self.msg2Statusbar.emit("paused") else: self.timer.start(Board.Speed, self) self.msg2Statusbar.emit(str(self.numLinesRemoved)) self.update() def paintEvent(self, event): painter = QPainter(self) rect = self.contentsRect() boardTop = rect.bottom( ) - Board.BoardHeight * self.squareHeight() for i in range(Board.BoardHeight): for j in range(Board.BoardWidth): shape = self.shapeAt(j, Board.BoardHeight - i - 1) if shape != Tetrominoe.NoShape: self.drawSquare( painter, rect.left() + j * self.squareWidth(), boardTop + i * self.squareHeight(), shape) if self.curPiece.shape() != Tetrominoe.NoShape: for i in range(4): x = self.curX + self.curPiece.x(i) y = self.curY - self.curPiece.y(i) self.drawSquare( painter, rect.left() + x * self.squareWidth(), boardTop + (Board.BoardHeight - y - 1) * self.squareHeight(), self.curPiece.shape()) def keyPressEvent(self, event): if not self.isStarted or self.curPiece.shape( ) == Tetrominoe.NoShape: super(Board, self).keyPressEvent(event) return key = event.key() if key == Qt.Key_P: self.pause() return if self.isPaused: return elif key == Qt.Key_Left: self.tryMove(self.curPiece, self.curX - 1, self.curY) elif key == Qt.Key_Right: self.tryMove(self.curPiece, self.curX + 1, self.curY) elif key == Qt.Key_Down: self.tryMove(self.curPiece.rotateRight(), self.curX, self.curY) elif key == Qt.Key_Up: self.tryMove(self.curPiece.rotateLeft(), self.curX, self.curY) elif key == Qt.Key_Space: self.dropDown() elif key == Qt.Key_D: self.oneLineDown() else: super(Board, self).keyPressEvent(event) def timerEvent(self, event): if event.timerId() == self.timer.timerId(): if self.isWaitingAfterLine: self.isWaitingAfterLine = False self.newPiece() else: self.oneLineDown() else: super(Board, self).timerEvent(event) def clearBoard(self): for i in range(Board.BoardHeight * Board.BoardWidth): self.board.append(Tetrominoe.NoShape) def dropDown(self): newY = self.curY while newY > 0: if not self.tryMove(self.curPiece, self.curX, newY - 1): break newY -= 1 self.pieceDropped() def oneLineDown(self): if not self.tryMove(self.curPiece, self.curX, self.curY - 1): self.pieceDropped() def pieceDropped(self): for i in range(4): x = self.curX + self.curPiece.x(i) y = self.curY - self.curPiece.y(i) self.setShapeAt(x, y, self.curPiece.shape()) self.removeFullLines() if not self.isWaitingAfterLine: self.newPiece() def removeFullLines(self): numFullLines = 0 rowsToRemove = [] for i in range(Board.BoardHeight): n = 0 for j in range(Board.BoardWidth): if not self.shapeAt(j, i) == Tetrominoe.NoShape: n = n + 1 if n == 10: rowsToRemove.append(i) rowsToRemove.reverse() for m in rowsToRemove: for k in range(m, Board.BoardHeight): for l in range(Board.BoardWidth): self.setShapeAt(l, k, self.shapeAt(l, k + 1)) numFullLines = numFullLines + len(rowsToRemove) if numFullLines >= 0: self.numLinesRemoved = self.numLinesRemoved + numFullLines self.ourScore = self.numLinesRemoved * 100 self.msg2Statusbar.emit(str(self.ourScore)) self.isWaitingAfterLine = True self.curPiece.setShape(Tetrominoe.NoShape) self.update() def newPiece(self): self.curPiece = Shape() self.curPiece.setRandomShape() self.curX = Board.BoardWidth // 2 + 1 self.curY = Board.BoardHeight - 1 + self.curPiece.minY() if not self.tryMove(self.curPiece, self.curX, self.curY): self.curPiece.setShape(Tetrominoe.NoShape) self.timer.stop() self.isStarted = False self.msg2Statusbar.emit("Игра окончена") root = Tk() root.geometry("400x400") root.title("Игра окончена") v = StringVar() text1 = Label(width=50, height=2, font='Arial 12', text="Игра окончена, вы заработали " + str(self.ourScore) + " очков.") text2 = Label(width=50, height=2, font='Arial 12', text="Пожалуйста укажите свое имя:") mylogin = Entry(textvariable=v, width=30) button1 = Button( width=30, height=5, text="Сохранить результат", font='Arial 12', command=lambda: login(mylogin.get(), self.ourScore)) button2 = Button(width=30, height=5, text="Выйти без сохранения", font='Arial 12', command=lambda: closing()) text1.pack(side=TOP) text2.pack(side=TOP) mylogin.pack(side=TOP) button1.pack(side=TOP) button2.pack(side=TOP) def login(username, userscore): c.execute( "INSERT INTO records (name,score) VALUES ('%s','%s')" % (str(username), userscore)) conn.commit() messagebox.showinfo("Сохранение", "Ваш результат успешно сохранен.") c.close() conn.close() sys.exit() def closing(): if messagebox.askokcancel( "Выход", "Вы действительно хотите выйти?"): root.destroy() sys.exit() root.protocol("WM_DELETE_WINDOW", closing) root.mainloop() def tryMove(self, newPiece, newX, newY): for i in range(4): x = newX + newPiece.x(i) y = newY - newPiece.y(i) if x < 0 or x >= Board.BoardWidth or y < 0 or y >= Board.BoardHeight: return False if self.shapeAt(x, y) != Tetrominoe.NoShape: return False self.curPiece = newPiece self.curX = newX self.curY = newY self.update() return True def drawSquare(self, painter, x, y, shape): colorTable = [ 0x000000, 0xCC6666, 0x66CC66, 0x6666CC, 0xCCCC66, 0xCC66CC, 0x66CCCC, 0xDAAA00 ] color = QColor(colorTable[shape]) painter.fillRect(x + 1, y + 1, self.squareWidth() - 2, self.squareHeight() - 2, color) painter.setPen(color.lighter()) painter.drawLine(x, y + self.squareHeight() - 1, x, y) painter.drawLine(x, y, x + self.squareWidth() - 1, y) painter.setPen(color.darker()) painter.drawLine(x + 1, y + self.squareHeight() - 1, x + self.squareWidth() - 1, y + self.squareHeight() - 1) painter.drawLine(x + self.squareWidth() - 1, y + self.squareHeight() - 1, x + self.squareWidth() - 1, y + 1)
class WidgetCode(QLabel): def __init__(self, *args, **kwargs): super(WidgetCode, self).__init__(*args, **kwargs) self._sensitive = False # 是否大小写敏感 self.setAlignment(Qt.AlignHCenter | Qt.AlignVCenter) self.setBackgroundRole(QPalette.Midlight) self.setAutoFillBackground(True) # 字体 newFont = self.font() newFont.setPointSize(16) newFont.setFamily("Kristen ITC") newFont.setBold(True) self.setFont(newFont) self.reset() # 定时器 self.step = 0 self.timer = QBasicTimer() self.timer.start(60, self) def reset(self): self._code = "".join(sample(WORDS, 4)) # 随机4个字符 self.setText(self._code) def check(self, code): return self._code == str(code) if self._sensitive else self._code.lower() == str(code).lower() def setSensitive(self, sensitive): self._sensitive = sensitive # def setText(self, text): # text = text if (text and len(text) == 4) else "".join(sample(WORDS, 4)) # 随机4个字符 # self._code = str(text) # html = "".join([FONT.format(color=COLORLIST[qrand() % 6], word=t) for t in text]) # super(WidgetCode, self).setText(HTML.format(html=html)) def mouseReleaseEvent(self, event): super(WidgetCode, self).mouseReleaseEvent(event) self.reset() def timerEvent(self, event): if event.timerId() == self.timer.timerId(): self.step += 1 return self.update() return super(WidgetCode, self).timerEvent(event) def paintEvent(self, event): painter = QPainter(self) painter.setRenderHint(QPainter.Antialiasing) # 背景白色 painter.fillRect(event.rect(), QBrush(Qt.white)) # 绘制边缘虚线框 painter.setPen(Qt.DashLine) painter.setBrush(Qt.NoBrush) painter.drawRect(self.rect()) # 随机画条线 for _ in range(3): painter.setPen(QPen(QTCOLORLIST[qrand() % 5], 1, Qt.SolidLine)) painter.setBrush(Qt.NoBrush) painter.drawLine(QPoint(0, qrand() % self.height()), QPoint(self.width(), qrand() % self.height())) painter.drawLine(QPoint(qrand() % self.width(), 0), QPoint(qrand() % self.width(), self.height())) # 绘制噪点 painter.setPen(Qt.DotLine) painter.setBrush(Qt.NoBrush) for _ in range(self.width()): # 绘制噪点 painter.drawPoint(QPointF(qrand() % self.width(), qrand() % self.height())) # super(WidgetCode, self).paintEvent(event) # 绘制文字 # 绘制跳动文字 metrics = QFontMetrics(self.font()) x = (self.width() - metrics.width(self.text())) / 2 y = (self.height() + metrics.ascent() - metrics.descent()) / 2 for i, ch in enumerate(self.text()): index = (self.step + i) % 16 painter.setPen(TCOLORLIST[qrand() % 6]) painter.drawText(x, y - ((SINETABLE[index] * metrics.height()) / 400), ch) x += metrics.width(ch)
class Field(QWidget): def __init__(self, game): super().__init__() self.init_field(game) def init_field(self, game): self.game = game self.ways = Ways() self.timer = QBasicTimer() self.height = self.game.field.get_height() self.width = self.game.field.get_width() self.mat = self.game.field grid = QGridLayout() self.setLayout(grid) grid.setSpacing(1) self.draw() self.timer.start(600, self) def draw(self): """Draws the game field each time a change occurs.""" grid = self.layout() width, height = self.width, self.height mat = self.game.field.mat for i in range(height): for j in range(width): tile = Tile(str(mat[i][j])) tile.setStyle(mat[i][j]) grid.addWidget(tile, i, j) label1 = QLabel('Health: {} Energy: {} Stars: {}'.format( self.game.player.get_health(), self.game.player.get_energy(), self.game.player.get_stars())) grid.addWidget(label1, height, 0, 1, width - 1) label2 = QLabel('>>') label2.setStyleSheet("qproperty-alignment: AlignRight;") grid.addWidget(label2, height, width - 1, 1, width) if (self.game.state is not State.running): lev_num = '' else: lev_num = str(self.game.level) label3 = QLabel('{}{}'.format(self.game.state.value, lev_num)) grid.addWidget(label3, height + 1, 0, 1, width) def clear(self): """Removes all widgets before each drawing.""" grid = self.layout() width, height = self.width, self.height grid.itemAt(height + 1).widget().setParent(None) grid.itemAt(height + width - 1).widget().setParent(None) grid.itemAt(height).widget().setParent(None) for i in reversed(range(height)): for j in reversed(range(width)): grid.itemAt(i * height + j).widget().setParent(None) def move_current_up(self): """Moves the player up and draws the new field.""" self.game.move_current_up() self.clear() self.draw() if self.game.state is State.won: self.message(1) if self.game.state is State.lost: self.message(2) def move_current_down(self): """Moves the player down, draws the new field and checks for end of level.""" self.game.move_current_down() self.clear() self.draw() if self.game.x == self.height - 1 and self.game.y == self.width - 1: if self.game.player.enough_stars(): self.switch_levels() else: self.message(0) if self.game.state is State.won: self.message(1) if self.game.state is State.lost: self.message(2) def move_current_left(self): """Moves the player left and draws the new field.""" self.game.move_current_left() self.clear() self.draw() if self.game.state is State.won: self.message(1) if self.game.state is State.lost: self.message(2) def move_current_right(self): """Moves the player right, draws the new field and checks for end of level.""" self.game.move_current_right() self.clear() self.draw() if self.game.x == self.height - 1 and self.game.y == self.width - 1: if self.game.player.enough_stars(): self.switch_levels() else: self.message(0) if self.game.state is State.won: self.message(1) if self.game.state is State.lost: self.message(2) def move_x(self, place, way): """Specifies the direction of moving of a X.""" letter = way[0] if letter == 'u': self.game.move_x_up(place) if letter == 'd': self.game.move_x_down(place) if letter == 'l': self.game.move_x_left(place) if letter == 'r': self.game.move_x_right(place) way += letter way.pop(0) def keyPressEvent(self, event): if self.game.state is State.paused: key = event.key() if key == Qt.Key_P: self.unpause() else: super(Field, self).keyPressEvent(event) return if self.game.state is not State.running: super(Field, self).keyPressEvent(event) return key = event.key() if key == Qt.Key_Up: self.move_current_up() elif key == Qt.Key_Down: self.move_current_down() elif key == Qt.Key_Left: self.move_current_left() elif key == Qt.Key_Right: self.move_current_right() elif key == Qt.Key_P: self.pause() else: super(Field, self).keyPressEvent(event) def timerEvent(self, event): if self.game.state is not State.running: super(Field, self).timerEvent(event) return lev = self.game.level - 1 if event.timerId() == self.timer.timerId() and self.ways.ways[lev] != []: for moving_x in self.ways.ways[lev]: self.move_x(moving_x['place'], moving_x['way']) self.clear() self.draw() if self.game.state is State.lost: self.message(2) else: super(Field, self).timerEvent(event) def switch_levels(self): self.game.new_level() self.mat = self.game.field self.clear() self.draw() def pause(self): self.game.pause() self.clear() self.draw() def unpause(self): self.game.unpause() self.clear() self.draw() def message(self, text_no): texts = [ "You must collect all {} stars to continue!".format(self.game.player.STARS), "You win! Congratulations!", "Game over! Good luck next time!"] msgBox = QMessageBox() msgBox.setText(texts[text_no]) msgBox.exec_()