├── highscore.txt ├── tetris └── .idea │ └── workspace.xml ├── Sounds ├── bip.ogg ├── line clear.ogg └── Child's Nightmare.ogg ├── fonts ├── icon.png ├── ka1.ttf ├── ARCADE.TTF ├── retro.ttf ├── ARCADE_I.TTF ├── PIXEL CRAFT.ttf ├── Pixelmania.ttf └── ARCADECLASSIC.TTF ├── __pycache__ ├── Block.cpython-311.pyc ├── Blocks.cpython-311.pyc ├── Color.cpython-311.pyc ├── Game.cpython-311.pyc ├── Grid.cpython-311.pyc └── Position.cpython-311.pyc ├── Position.py ├── .idea ├── vcs.xml ├── .gitignore ├── misc.xml ├── inspectionProfiles │ ├── profiles_settings.xml │ └── Project_Default.xml ├── modules.xml └── Summer1.iml ├── Color.py ├── LICENSE ├── Block.py ├── Grid.py ├── README.md ├── Blocks.py ├── Game.py └── main.py /highscore.txt: -------------------------------------------------------------------------------- 1 | 0 -------------------------------------------------------------------------------- /tetris/.idea/workspace.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Sounds/bip.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Farid-Karimi/Tetris/HEAD/Sounds/bip.ogg -------------------------------------------------------------------------------- /fonts/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Farid-Karimi/Tetris/HEAD/fonts/icon.png -------------------------------------------------------------------------------- /fonts/ka1.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Farid-Karimi/Tetris/HEAD/fonts/ka1.ttf -------------------------------------------------------------------------------- /fonts/ARCADE.TTF: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Farid-Karimi/Tetris/HEAD/fonts/ARCADE.TTF -------------------------------------------------------------------------------- /fonts/retro.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Farid-Karimi/Tetris/HEAD/fonts/retro.ttf -------------------------------------------------------------------------------- /fonts/ARCADE_I.TTF: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Farid-Karimi/Tetris/HEAD/fonts/ARCADE_I.TTF -------------------------------------------------------------------------------- /Sounds/line clear.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Farid-Karimi/Tetris/HEAD/Sounds/line clear.ogg -------------------------------------------------------------------------------- /fonts/PIXEL CRAFT.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Farid-Karimi/Tetris/HEAD/fonts/PIXEL CRAFT.ttf -------------------------------------------------------------------------------- /fonts/Pixelmania.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Farid-Karimi/Tetris/HEAD/fonts/Pixelmania.ttf -------------------------------------------------------------------------------- /fonts/ARCADECLASSIC.TTF: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Farid-Karimi/Tetris/HEAD/fonts/ARCADECLASSIC.TTF -------------------------------------------------------------------------------- /Sounds/Child's Nightmare.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Farid-Karimi/Tetris/HEAD/Sounds/Child's Nightmare.ogg -------------------------------------------------------------------------------- /__pycache__/Block.cpython-311.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Farid-Karimi/Tetris/HEAD/__pycache__/Block.cpython-311.pyc -------------------------------------------------------------------------------- /__pycache__/Blocks.cpython-311.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Farid-Karimi/Tetris/HEAD/__pycache__/Blocks.cpython-311.pyc -------------------------------------------------------------------------------- /__pycache__/Color.cpython-311.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Farid-Karimi/Tetris/HEAD/__pycache__/Color.cpython-311.pyc -------------------------------------------------------------------------------- /__pycache__/Game.cpython-311.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Farid-Karimi/Tetris/HEAD/__pycache__/Game.cpython-311.pyc -------------------------------------------------------------------------------- /__pycache__/Grid.cpython-311.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Farid-Karimi/Tetris/HEAD/__pycache__/Grid.cpython-311.pyc -------------------------------------------------------------------------------- /Position.py: -------------------------------------------------------------------------------- 1 | class Position: 2 | def __init__(self, row, column): 3 | self.row = row 4 | self.column = column -------------------------------------------------------------------------------- /__pycache__/Position.cpython-311.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Farid-Karimi/Tetris/HEAD/__pycache__/Position.cpython-311.pyc -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | # Editor-based HTTP Client requests 5 | /httpRequests/ 6 | # Datasource local storage ignored files 7 | /dataSources/ 8 | /dataSources.local.xml 9 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /.idea/inspectionProfiles/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.idea/Summer1.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /.idea/inspectionProfiles/Project_Default.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 13 | -------------------------------------------------------------------------------- /Color.py: -------------------------------------------------------------------------------- 1 | class Colors: 2 | Cells = (0, 91, 150) 3 | green = (89, 209, 2) 4 | red = (249,65,68) 5 | orange = (255, 140, 0) 6 | yellow = (175, 252, 175) 7 | purple = (188, 0, 221) 8 | lime = (255, 237, 0) 9 | blue = (0, 255, 208) 10 | white = (255, 255, 255) 11 | black = (0, 0, 0) 12 | backGround = (1, 31, 75) 13 | boxes = (3, 57, 108) 14 | 15 | @classmethod 16 | def getCellColors(cls): 17 | return [cls.Cells, cls.green, cls.red, cls.orange, cls.yellow, cls.purple, cls.lime, cls.blue] -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Farid Karimi 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Block.py: -------------------------------------------------------------------------------- 1 | import pygame 2 | 3 | from Color import Colors 4 | from Position import Position 5 | 6 | 7 | class Block: 8 | def __init__(self, id): 9 | self.id = id 10 | self.cells = {} 11 | self.cellSize = 30 12 | self.rotationState = 0 13 | self.rowOffset = 0 14 | self.columnOffset = 0 15 | self.colors = Colors.getCellColors() 16 | 17 | def move(self, rows, columns): 18 | self.rowOffset += rows 19 | self.columnOffset += columns 20 | 21 | def getCellPositions(self): 22 | tiles = self.cells[self.rotationState] 23 | moved_tiles = [] 24 | for position in tiles: 25 | position = Position(position.row + self.rowOffset, position.column + self.columnOffset) 26 | moved_tiles.append(position) 27 | return moved_tiles 28 | 29 | def rotate(self): 30 | self.rotationState += 1 31 | if self.rotationState == len(self.cells): 32 | self.rotationState = 0 33 | 34 | def undoRotation(self): 35 | self.rotationState -= 1 36 | if self.rotationState == -1: 37 | self.rotationState = len(self.cells) - 1 38 | 39 | def draw(self, screen, offset_x, offset_y): 40 | tiles = self.getCellPositions() 41 | for tile in tiles: 42 | tile_rect = pygame.Rect(offset_x + tile.column * self.cellSize,offset_y + tile.row * self.cellSize, self.cellSize - 1, self.cellSize - 1) 43 | pygame.draw.rect(screen, self.colors[self.id], tile_rect) -------------------------------------------------------------------------------- /Grid.py: -------------------------------------------------------------------------------- 1 | import pygame 2 | 3 | from Color import Colors 4 | 5 | 6 | class Grid: 7 | def __init__(self): 8 | self.numberOfRows = 20 9 | self.numberOfColumns = 10 10 | self.cellSize = 30 11 | self.grid = [[0 for j in range(self.numberOfColumns)] for i in range(self.numberOfRows)] 12 | self.colors = Colors.getCellColors() 13 | 14 | def printGrid(self): 15 | for row in range(self.numberOfRows): 16 | for column in range(self.numberOfColumns): 17 | print(self.grid[row][column], end=" ") 18 | print() 19 | 20 | def draw(self, screen): 21 | for row in range(self.numberOfRows): 22 | for column in range(self.numberOfColumns): 23 | cellValue = self.grid[row][column] 24 | cellRect = pygame.Rect(column * self.cellSize + 11, row * self.cellSize + 11, self.cellSize - 1, 25 | self.cellSize - 1) 26 | pygame.draw.rect(screen, self.colors[cellValue], cellRect) 27 | 28 | def isInside(self, row, column): 29 | if row >= 0 and row < self.numberOfRows and column >= 0 and column < self.numberOfColumns: 30 | return True 31 | return False 32 | 33 | def isEmpty(self, row, column): 34 | if self.grid[row][column] == 0: 35 | return True 36 | return False 37 | 38 | def isRowFull(self, row): 39 | for column in range(self.numberOfColumns): 40 | if self.grid[row][column] == 0: 41 | return False 42 | return True 43 | 44 | def clearRow(self, row): 45 | for column in range(self.numberOfColumns): 46 | self.grid[row][column] = 0 47 | 48 | def moveRowDown(self, row, numberOfRows): 49 | for column in range(self.numberOfColumns): 50 | self.grid[row + numberOfRows][column] = self.grid[row][column] 51 | self.grid[row][column] = 0 52 | 53 | def clearFullRows(self): 54 | completed = 0 55 | for row in range(self.numberOfRows - 1, 0, -1): 56 | if self.isRowFull(row): 57 | self.clearRow(row) 58 | completed += 1 59 | elif completed > 0: 60 | self.moveRowDown(row, completed) 61 | return completed 62 | 63 | def reset(self): 64 | for row in range(self.numberOfRows): 65 | for column in range(self.numberOfColumns): 66 | self.grid[row][column] = 0 67 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 🕹️ Python Tetris 2 | 3 | ## Introduction 4 | This project is my first endeavor in game development using the Pygame library. 5 | The primary goal of this project was to gain hands-on experience with Pygame, strengthen my understanding of Python syntax, and improve my overall programming skills. 6 | The project involved implementing the popular game "Tetris" in Python. 7 | 8 | ## Technologies Used 9 | - Python programming language 10 | - Pygame library 11 | 12 | ## Project Scope 13 | The project focused on building a functional Tetris game using object-oriented programming (OOP) principles, specifically leveraging the concept of inheritance. 14 | The inheritance structure allowed for the creation of modular and reusable code components, enhancing the game's maintainability and scalability. 15 | 16 | ## Design and Visuals 17 | To enhance the visual appeal of the game, I made deliberate design choices and utilized a color palette to create an engaging and aesthetically pleasing user interface. The color palette selection aimed to ensure good contrast, readability, and an enjoyable gaming experience for players. 18 | 19 | ## Learning Outcomes 20 | Through the development of this project, I achieved several learning outcomes, including: 21 | - Gained proficiency in using the Pygame library to create interactive games. 22 | - Deepened my understanding of object-oriented programming (OOP) concepts and their application in game development. 23 | - Strengthened my grasp of Python syntax, including control flow, event handling, and graphics rendering. 24 | - Developed skills in designing and implementing game mechanics, such as block movement, rotation, and collision detection. 25 | - Gained experience in managing game states, such as pausing and game over conditions. 26 | - Improved problem-solving skills by tackling challenges specific to game development. 27 | 28 | ## Conclusion 29 | In conclusion, the Python Tetris project served as an excellent opportunity for me to explore game development, refine my programming skills, and gain practical experience in utilizing the Pygame library. 30 | This project has provided a solid foundation for future game development endeavors and has been instrumental in enhancing my understanding of Python syntax, OOP principles, and design choices. 31 | I look forward to further expanding my knowledge and skills in game development through future projects. 32 | 33 | ## Screenshots 34 | ![Screenshot 2023-07-05 195503](https://github.com/Farid-Karimi/Tetris/assets/118434072/5b4a4717-2de5-4192-ae8b-a703ce3914f5) 35 | 36 | -------------------------------------------------------------------------------- /Blocks.py: -------------------------------------------------------------------------------- 1 | from Block import Block 2 | from Position import Position 3 | 4 | 5 | class LBlock(Block): 6 | def __init__(self): 7 | super().__init__(id=1) 8 | self.cells = { 9 | 0: [Position(0, 2), Position(1, 0), Position(1, 1), Position(1, 2)], 10 | 1: [Position(0, 1), Position(1, 1), Position(2, 1), Position(2, 2)], 11 | 2: [Position(1, 0), Position(1, 1), Position(1, 2), Position(2, 0)], 12 | 3: [Position(0, 0), Position(0, 1), Position(1, 1), Position(2, 1)] 13 | } 14 | self.move(0, 3) 15 | 16 | 17 | class JBlock(Block): 18 | def __init__(self): 19 | super().__init__(id=2) 20 | self.cells = { 21 | 0: [Position(0, 0), Position(1, 0), Position(1, 1), Position(1, 2)], 22 | 1: [Position(0, 1), Position(0, 2), Position(1, 1), Position(2, 1)], 23 | 2: [Position(1, 0), Position(1, 1), Position(1, 2), Position(2, 2)], 24 | 3: [Position(0, 1), Position(1, 1), Position(2, 0), Position(2, 1)] 25 | } 26 | self.move(0, 3) 27 | 28 | 29 | class IBlock(Block): 30 | def __init__(self): 31 | super().__init__(id=3) 32 | self.cells = { 33 | 0: [Position(1, 0), Position(1, 1), Position(1, 2), Position(1, 3)], 34 | 1: [Position(0, 2), Position(1, 2), Position(2, 2), Position(3, 2)], 35 | 2: [Position(2, 0), Position(2, 1), Position(2, 2), Position(2, 3)], 36 | 3: [Position(0, 1), Position(1, 1), Position(2, 1), Position(3, 1)] 37 | } 38 | self.move(-1, 3) 39 | 40 | 41 | class OBlock(Block): 42 | def __init__(self): 43 | super().__init__(id=4) 44 | self.cells = { 45 | 0: [Position(0, 0), Position(0, 1), Position(1, 0), Position(1, 1)] 46 | } 47 | self.move(0, 4) 48 | 49 | 50 | class SBlock(Block): 51 | def __init__(self): 52 | super().__init__(id=5) 53 | self.cells = { 54 | 0: [Position(0, 1), Position(0, 2), Position(1, 0), Position(1, 1)], 55 | 1: [Position(0, 1), Position(1, 1), Position(1, 2), Position(2, 2)], 56 | 2: [Position(1, 1), Position(1, 2), Position(2, 0), Position(2, 1)], 57 | 3: [Position(0, 0), Position(1, 0), Position(1, 1), Position(2, 1)] 58 | } 59 | self.move(0, 3) 60 | 61 | 62 | class TBlock(Block): 63 | def __init__(self): 64 | super().__init__(id=6) 65 | self.cells = { 66 | 0: [Position(0, 1), Position(1, 0), Position(1, 1), Position(1, 2)], 67 | 1: [Position(0, 1), Position(1, 1), Position(1, 2), Position(2, 1)], 68 | 2: [Position(1, 0), Position(1, 1), Position(1, 2), Position(2, 1)], 69 | 3: [Position(0, 1), Position(1, 0), Position(1, 1), Position(2, 1)] 70 | } 71 | self.move(0, 3) 72 | 73 | 74 | class ZBlock(Block): 75 | def __init__(self): 76 | super().__init__(id=7) 77 | self.cells = { 78 | 0: [Position(0, 0), Position(0, 1), Position(1, 1), Position(1, 2)], 79 | 1: [Position(0, 2), Position(1, 1), Position(1, 2), Position(2, 1)], 80 | 2: [Position(1, 0), Position(1, 1), Position(2, 1), Position(2, 2)], 81 | 3: [Position(0, 1), Position(1, 0), Position(1, 1), Position(2, 0)] 82 | } 83 | self.move(0, 3) 84 | -------------------------------------------------------------------------------- /Game.py: -------------------------------------------------------------------------------- 1 | import random 2 | import pygame 3 | from Blocks import * 4 | from Grid import Grid 5 | 6 | 7 | class Game: 8 | def __init__(self): 9 | self.grid = Grid() 10 | self.blocks = [IBlock(), JBlock(), LBlock(), OBlock(), SBlock(), TBlock(), ZBlock()] 11 | self.currentBlock = self.getRandomBlock() 12 | self.nextBlock = self.getRandomBlock() 13 | self.gameOver = False 14 | self.score = 0 15 | self.rotate_sound = pygame.mixer.Sound("Sounds/bip.ogg") 16 | self.clear_sound = pygame.mixer.Sound("Sounds/line clear.ogg") 17 | pygame.mixer.music.load("Sounds/Child's Nightmare.ogg") 18 | pygame.mixer.music.play(-1) 19 | 20 | def updateScore(self, linesCleared, moveDownPoints): 21 | if linesCleared == 1: 22 | self.score += 100 23 | elif linesCleared == 2: 24 | self.score += 300 25 | elif linesCleared == 3: 26 | self.score += 500 27 | self.score += moveDownPoints 28 | 29 | def getRandomBlock(self): 30 | if len(self.blocks) == 0: 31 | self.blocks = [IBlock(), JBlock(), LBlock(), OBlock(), SBlock(), TBlock(), ZBlock()] 32 | block = random.choice(self.blocks) 33 | self.blocks.remove(block) 34 | return block 35 | 36 | def moveLeft(self): 37 | self.currentBlock.move(0, -1) 38 | if self.blockInside() == False or self.blockFits() == False: 39 | self.currentBlock.move(0, 1) 40 | 41 | def moveRight(self): 42 | self.currentBlock.move(0, 1) 43 | if self.blockInside() == False or self.blockFits() == False: 44 | self.currentBlock.move(0, -1) 45 | 46 | def moveDown(self): 47 | self.currentBlock.move(1, 0) 48 | if self.blockInside() == False or self.blockFits() == False: 49 | self.currentBlock.move(-1, 0) 50 | self.lockBlock() 51 | 52 | def lockBlock(self): 53 | tiles = self.currentBlock.getCellPositions() 54 | for position in tiles: 55 | self.grid.grid[position.row][position.column] = self.currentBlock.id 56 | self.currentBlock = self.nextBlock 57 | self.nextBlock = self.getRandomBlock() 58 | rowsCleared = self.grid.clearFullRows() 59 | if rowsCleared > 0: 60 | self.clear_sound.play() 61 | self.updateScore(rowsCleared, 0) 62 | if not self.blockFits(): 63 | self.gameOver = True 64 | 65 | def reset(self): 66 | self.grid.reset() 67 | self.blocks = [IBlock(), JBlock(), LBlock(), OBlock(), SBlock(), TBlock(), ZBlock()] 68 | self.currentBlock = self.getRandomBlock() 69 | self.nextBlock = self.getRandomBlock() 70 | self.score = 0 71 | 72 | def blockFits(self): 73 | tiles = self.currentBlock.getCellPositions() 74 | for tile in tiles: 75 | if not self.grid.isEmpty(tile.row, tile.column): 76 | return False 77 | return True 78 | 79 | def rotate(self): 80 | self.currentBlock.rotate() 81 | if self.blockInside() == False or self.blockFits() == False: 82 | self.currentBlock.undoRotation() 83 | else: 84 | self.rotate_sound.play() 85 | 86 | def blockInside(self): 87 | tiles = self.currentBlock.getCellPositions() 88 | for tile in tiles: 89 | if not self.grid.isInside(tile.row, tile.column): 90 | return False 91 | return True 92 | 93 | def draw(self, screen): 94 | self.grid.draw(screen) 95 | self.currentBlock.draw(screen, 11, 11) 96 | 97 | if self.nextBlock.id == 3: 98 | self.nextBlock.draw(screen, 255, 290) 99 | elif self.nextBlock.id == 4: 100 | self.nextBlock.draw(screen, 255, 280) 101 | else: 102 | self.nextBlock.draw(screen, 270, 270) 103 | -------------------------------------------------------------------------------- /main.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import pygame 3 | 4 | from Color import Colors 5 | from Game import Game 6 | 7 | pygame.init() 8 | titleFont = pygame.font.Font("fonts/ARCADECLASSIC.TTF", 40) 9 | titleFontForHS = pygame.font.Font("fonts/ARCADECLASSIC.TTF", 30) 10 | titleFontForPause = pygame.font.Font("fonts/ARCADECLASSIC.TTF", 60) 11 | scoreSurface = titleFont.render("Score", True, Colors.white) 12 | nextSurface = titleFont.render("Next", True, Colors.white) 13 | gameOverSurface = titleFontForPause.render("GAME OVER", True, Colors.white) 14 | pauseSurface = titleFontForPause.render("PAUSED", True, Colors.white) 15 | highScoreSurface = titleFontForHS.render("High Score", True, Colors.white) 16 | 17 | scoreRect = pygame.Rect(320, 55, 170, 60) 18 | nextRect = pygame.Rect(320, 215, 170, 180) 19 | highScoreRect = pygame.Rect(320, 500, 170, 60) 20 | 21 | screen = pygame.display.set_mode((500, 620)) 22 | pygame.display.set_caption("Python Tetris") 23 | img = pygame.image.load('fonts/icon.png') 24 | pygame.display.set_icon(img) 25 | 26 | clock = pygame.time.Clock() 27 | 28 | game = Game() 29 | 30 | gameUpdate = pygame.USEREVENT 31 | pygame.time.set_timer(gameUpdate, 250) 32 | 33 | paused = False 34 | 35 | dim_surface = pygame.Surface(screen.get_size()) 36 | dim_surface.set_alpha(100) 37 | dim_surface.fill(Colors.black) 38 | 39 | # Load highscore from a text file 40 | def load_highscore(): 41 | try: 42 | with open("highscore.txt", "r") as file: 43 | highscore = int(file.read()) 44 | except FileNotFoundError: 45 | highscore = 0 46 | return highscore 47 | 48 | # Save highscore to a text file 49 | def save_highscore(highscore): 50 | with open("highscore.txt", "w") as file: 51 | file.write(str(highscore)) 52 | 53 | highscore = load_highscore() 54 | 55 | while True: 56 | for event in pygame.event.get(): 57 | if event.type == pygame.QUIT: 58 | # Save highscore before exiting the game 59 | save_highscore(highscore) 60 | pygame.quit() 61 | sys.exit() 62 | if event.type == pygame.KEYDOWN: 63 | if event.key == pygame.K_p: 64 | paused = not paused 65 | if game.gameOver: 66 | game.gameOver = False 67 | game.reset() 68 | if not paused: 69 | if event.key == pygame.K_LEFT and game.gameOver == False: 70 | game.moveLeft() 71 | if event.key == pygame.K_RIGHT and game.gameOver == False: 72 | game.moveRight() 73 | if event.key == pygame.K_DOWN and game.gameOver == False: 74 | game.moveDown() 75 | game.updateScore(0, 1) 76 | if event.key == pygame.K_UP and game.gameOver == False: 77 | game.rotate() 78 | if event.type == gameUpdate and game.gameOver == False and not paused: 79 | game.moveDown() 80 | 81 | scoreValueSurface = titleFont.render(str(game.score), True, Colors.white) 82 | highscoreNum = titleFont.render(str(highscore), True, Colors.white) 83 | 84 | screen.fill(Colors.backGround) 85 | 86 | pygame.draw.rect(screen, Colors.boxes, scoreRect, 0, 15) 87 | screen.blit(scoreValueSurface, scoreValueSurface.get_rect(centerx=scoreRect.centerx, centery=scoreRect.centery)) 88 | pygame.draw.rect(screen, Colors.boxes, nextRect, 0, 15) 89 | pygame.draw.rect(screen, Colors.boxes, highScoreRect, 0, 15) 90 | game.draw(screen) 91 | 92 | if game.gameOver: 93 | screen.blit(dim_surface, (0, 0)) 94 | screen.blit(gameOverSurface, ((screen.get_width() - gameOverSurface.get_width()) // 2 , 95 | (screen.get_height() - gameOverSurface.get_height()) // 2)) 96 | # Update highscore if the current score is higher 97 | if game.score > highscore: 98 | highscore = game.score 99 | if paused: 100 | screen.blit(dim_surface, (0, 0)) 101 | screen.blit(pauseSurface, ((screen.get_width() - pauseSurface.get_width()) // 2, 102 | (screen.get_height() - pauseSurface.get_height()) // 2)) 103 | 104 | screen.blit(scoreSurface, (352, 15, 50, 50)) 105 | screen.blit(nextSurface, (367, 175, 50, 50)) 106 | screen.blit(highScoreSurface, (325, 460, 50, 50)) 107 | screen.blit(highscoreNum, highscoreNum.get_rect(centerx=highScoreRect.centerx, centery=highScoreRect.centery)) 108 | 109 | pygame.display.update() 110 | clock.tick(60) 111 | --------------------------------------------------------------------------------