diff --git a/.DS_Store b/.DS_Store index 33ddf2c..cfb63d6 100644 Binary files a/.DS_Store and b/.DS_Store differ diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..caefa6c --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2021 RahulShagri + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md index cdf1fac..b40cc24 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,3 @@ -# Sudoku Game In Python +# Tetris Game In Python - -### run: - -* python gui.py - -### Mac - -* python3 gui.py \ No newline at end of file + \ No newline at end of file diff --git a/block_speeds_data.csv b/block_speeds_data.csv new file mode 100644 index 0000000..24ca3c9 --- /dev/null +++ b/block_speeds_data.csv @@ -0,0 +1,31 @@ +level,speed +0,15.974 +1,14.31 +2,12.646 +3,10.982 +4,9.318 +5,7.654 +6,5.99 +7,4.326 +8,2.662 +9,1.997 +10,1.664 +11,1.664 +12,1.664 +13,1.331 +14,1.331 +15,1.331 +16,0.998 +17,0.998 +18,0.998 +19,0.666 +20,0.666 +21,0.666 +22,0.666 +23,0.666 +24,0.666 +25,0.666 +26,0.666 +27,0.666 +28,0.666 +29,0.333 diff --git a/config.py b/config.py new file mode 100644 index 0000000..c5344b6 --- /dev/null +++ b/config.py @@ -0,0 +1,77 @@ +# Sets up all important config variables +import dearpygui.dearpygui as dpg + +# Set up all IDs required by items in Dear PyGui +item_id = { + "windows": { + "main_window": dpg.generate_uuid(), + "score_window": dpg.generate_uuid(), + "tetris_board": dpg.generate_uuid(), + "next_block_board": dpg.generate_uuid(), + "statistics_window": dpg.generate_uuid(), + }, + "displays": { + "enter_level": dpg.generate_uuid(), + "level_text": dpg.generate_uuid(), + "full_line_text": dpg.generate_uuid(), + "score_text": dpg.generate_uuid(), + "I_block_stat": dpg.generate_uuid(), + "J_block_stat": dpg.generate_uuid(), + "L_block_stat": dpg.generate_uuid(), + "O_block_stat": dpg.generate_uuid(), + "S_block_stat": dpg.generate_uuid(), + "T_block_stat": dpg.generate_uuid(), + "Z_block_stat": dpg.generate_uuid(), + "Total_block_stat": dpg.generate_uuid(), + }, + "registries": { + "texture_registry": dpg.generate_uuid(), + "key_release_handler": dpg.generate_uuid(), + "mouse_release_handler": dpg.generate_uuid(), + }, + "buttons": { + "play_button": dpg.generate_uuid(), + }, + "block_texture": { + "I_block": dpg.generate_uuid(), + "J_block": dpg.generate_uuid(), + "L_block": dpg.generate_uuid(), + "O_block": dpg.generate_uuid(), + "S_block": dpg.generate_uuid(), + "T_block": dpg.generate_uuid(), + "Z_block": dpg.generate_uuid(), + }, + "blocks": { + }, +} + +# Names of all blocks +block_names = ["I", "J", "L", "O", "S", "T", "Z"] + +# Set up lists to track walls and cells occupied +cell_boundary1 = [[n, -1] for n in range(10)] # Bottom Wall +cell_boundary2 = [[10, n] for n in range(20)] # Right Wall +cell_boundary3 = [[n, 20] for n in range(10)] # Top Wall +cell_boundary4 = [[-1, n] for n in range(20)] # Left Wall + +cell_boundary = cell_boundary1 + cell_boundary2 + cell_boundary3 + cell_boundary4 # All points in all walls combined +cells_occupied = [] # List of all cells occupied by tetris blocks + +# List of all block numbers active on the tetris board +block_numbers = [] + +# Count of blocks created +block_count = 0 + +# Flag to check if the last block is moving or not. 0=Stationary, 1-7=Corresponding type of block in motion +block_moving_flag = 0 + +# Keep track of level and corresponding speed +level = 0 +speed = 0 + +# Keep track of full lines completed +full_lines = 0 + +# Keep track of score +score = 0 diff --git a/data/.DS_Store b/data/.DS_Store deleted file mode 100644 index 4f5efd7..0000000 Binary files a/data/.DS_Store and /dev/null differ diff --git a/data/Highscore.txt b/data/Highscore.txt deleted file mode 100644 index e69de29..0000000 diff --git a/data/audios/.DS_Store b/data/audios/.DS_Store deleted file mode 100644 index e06e2bb..0000000 Binary files a/data/audios/.DS_Store and /dev/null differ diff --git a/data/audios/Crash.mp3 b/data/audios/Crash.mp3 deleted file mode 100644 index b94cf51..0000000 Binary files a/data/audios/Crash.mp3 and /dev/null differ diff --git a/data/audios/game.mp3 b/data/audios/game.mp3 deleted file mode 100644 index 2b04fbc..0000000 Binary files a/data/audios/game.mp3 and /dev/null differ diff --git a/data/audios/rtn.mp3 b/data/audios/rtn.mp3 deleted file mode 100644 index 94dcb7f..0000000 Binary files a/data/audios/rtn.mp3 and /dev/null differ diff --git a/data/images/.DS_Store b/data/images/.DS_Store deleted file mode 100644 index a0fd77d..0000000 Binary files a/data/images/.DS_Store and /dev/null differ diff --git a/data/images/Background.png b/data/images/Background.png deleted file mode 100644 index 3ed5060..0000000 Binary files a/data/images/Background.png and /dev/null differ diff --git a/data/images/Car.png b/data/images/Car.png deleted file mode 100644 index e747827..0000000 Binary files a/data/images/Car.png and /dev/null differ diff --git a/data/images/Coming Cars/CC1.png b/data/images/Coming Cars/CC1.png deleted file mode 100644 index d4bcb4b..0000000 Binary files a/data/images/Coming Cars/CC1.png and /dev/null differ diff --git a/data/images/Coming Cars/CC2.png b/data/images/Coming Cars/CC2.png deleted file mode 100644 index 552dcf4..0000000 Binary files a/data/images/Coming Cars/CC2.png and /dev/null differ diff --git a/data/images/Coming Cars/CC3.png b/data/images/Coming Cars/CC3.png deleted file mode 100644 index c556452..0000000 Binary files a/data/images/Coming Cars/CC3.png and /dev/null differ diff --git a/data/images/Coming Cars/CC4.png b/data/images/Coming Cars/CC4.png deleted file mode 100644 index 4761af9..0000000 Binary files a/data/images/Coming Cars/CC4.png and /dev/null differ diff --git a/data/images/Coming Cars/CC5.png b/data/images/Coming Cars/CC5.png deleted file mode 100644 index 2f7334f..0000000 Binary files a/data/images/Coming Cars/CC5.png and /dev/null differ diff --git a/data/images/Coming Cars/CC6.png b/data/images/Coming Cars/CC6.png deleted file mode 100644 index 6d5dcbe..0000000 Binary files a/data/images/Coming Cars/CC6.png and /dev/null differ diff --git a/data/images/Coming Cars/CC7.png b/data/images/Coming Cars/CC7.png deleted file mode 100644 index 3fefdbf..0000000 Binary files a/data/images/Coming Cars/CC7.png and /dev/null differ diff --git a/data/images/Coming Cars/CC8.png b/data/images/Coming Cars/CC8.png deleted file mode 100644 index 6c690ad..0000000 Binary files a/data/images/Coming Cars/CC8.png and /dev/null differ diff --git a/data/images/Coming Cars/CC9.png b/data/images/Coming Cars/CC9.png deleted file mode 100644 index d9a0e9b..0000000 Binary files a/data/images/Coming Cars/CC9.png and /dev/null differ diff --git a/data/images/Explosion.png b/data/images/Explosion.png deleted file mode 100644 index 05ff1d4..0000000 Binary files a/data/images/Explosion.png and /dev/null differ diff --git a/data/images/Fuel.png b/data/images/Fuel.png deleted file mode 100644 index b285bec..0000000 Binary files a/data/images/Fuel.png and /dev/null differ diff --git a/data/images/GameOver.png b/data/images/GameOver.png deleted file mode 100644 index 0dbbcb0..0000000 Binary files a/data/images/GameOver.png and /dev/null differ diff --git a/data/images/Going Cars/GC1.png b/data/images/Going Cars/GC1.png deleted file mode 100644 index e4e9af1..0000000 Binary files a/data/images/Going Cars/GC1.png and /dev/null differ diff --git a/data/images/Going Cars/GC2.png b/data/images/Going Cars/GC2.png deleted file mode 100644 index 5da0299..0000000 Binary files a/data/images/Going Cars/GC2.png and /dev/null differ diff --git a/data/images/Going Cars/GC3.png b/data/images/Going Cars/GC3.png deleted file mode 100644 index 9ea6b61..0000000 Binary files a/data/images/Going Cars/GC3.png and /dev/null differ diff --git a/data/images/Going Cars/GC4.png b/data/images/Going Cars/GC4.png deleted file mode 100644 index a437d5e..0000000 Binary files a/data/images/Going Cars/GC4.png and /dev/null differ diff --git a/data/images/Going Cars/GC5.png b/data/images/Going Cars/GC5.png deleted file mode 100644 index 090dacb..0000000 Binary files a/data/images/Going Cars/GC5.png and /dev/null differ diff --git a/data/images/Going Cars/GC6.png b/data/images/Going Cars/GC6.png deleted file mode 100644 index f8cf0fb..0000000 Binary files a/data/images/Going Cars/GC6.png and /dev/null differ diff --git a/data/images/Going Cars/GC7.png b/data/images/Going Cars/GC7.png deleted file mode 100644 index 6279978..0000000 Binary files a/data/images/Going Cars/GC7.png and /dev/null differ diff --git a/data/images/Going Cars/GC8.png b/data/images/Going Cars/GC8.png deleted file mode 100644 index 401de16..0000000 Binary files a/data/images/Going Cars/GC8.png and /dev/null differ diff --git a/data/images/Going Cars/GC9.png b/data/images/Going Cars/GC9.png deleted file mode 100644 index 3a4a03f..0000000 Binary files a/data/images/Going Cars/GC9.png and /dev/null differ diff --git a/data/images/LeftDisplay.png b/data/images/LeftDisplay.png deleted file mode 100644 index ff30950..0000000 Binary files a/data/images/LeftDisplay.png and /dev/null differ diff --git a/data/images/RightDisplay.png b/data/images/RightDisplay.png deleted file mode 100644 index 48f0828..0000000 Binary files a/data/images/RightDisplay.png and /dev/null differ diff --git a/data/images/Road.png b/data/images/Road.png deleted file mode 100644 index 1820217..0000000 Binary files a/data/images/Road.png and /dev/null differ diff --git a/data/images/Sand.jpg b/data/images/Sand.jpg deleted file mode 100644 index b6f640e..0000000 Binary files a/data/images/Sand.jpg and /dev/null differ diff --git a/data/images/Strip.png b/data/images/Strip.png deleted file mode 100644 index fad42aa..0000000 Binary files a/data/images/Strip.png and /dev/null differ diff --git a/data/images/Tree.png b/data/images/Tree.png deleted file mode 100644 index 4aa382c..0000000 Binary files a/data/images/Tree.png and /dev/null differ diff --git a/fonts/PressStart2P-vaV7.ttf b/fonts/PressStart2P-vaV7.ttf new file mode 100644 index 0000000..98044e9 Binary files /dev/null and b/fonts/PressStart2P-vaV7.ttf differ diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..5c8bab6 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,3 @@ +dearpygui==1.0.2 +pandas==1.3.4 +playsound2==0.1 \ No newline at end of file diff --git a/resources/tetris.png b/resources/tetris.png new file mode 100644 index 0000000..d50d786 Binary files /dev/null and b/resources/tetris.png differ diff --git a/sounds/clear.wav b/sounds/clear.wav new file mode 100644 index 0000000..f825b25 Binary files /dev/null and b/sounds/clear.wav differ diff --git a/sounds/fall.wav b/sounds/fall.wav new file mode 100644 index 0000000..0ca458e Binary files /dev/null and b/sounds/fall.wav differ diff --git a/sounds/gameover.wav b/sounds/gameover.wav new file mode 100644 index 0000000..4a1728d Binary files /dev/null and b/sounds/gameover.wav differ diff --git a/sounds/line.wav b/sounds/line.wav new file mode 100644 index 0000000..dd85cb4 Binary files /dev/null and b/sounds/line.wav differ diff --git a/sounds/selection.wav b/sounds/selection.wav new file mode 100644 index 0000000..bc4467e Binary files /dev/null and b/sounds/selection.wav differ diff --git a/sounds/success.wav b/sounds/success.wav new file mode 100644 index 0000000..5058f93 Binary files /dev/null and b/sounds/success.wav differ diff --git a/sounds/theme.mp3 b/sounds/theme.mp3 new file mode 100644 index 0000000..50033e8 Binary files /dev/null and b/sounds/theme.mp3 differ diff --git a/speed.py b/speed.py deleted file mode 100644 index b797d61..0000000 --- a/speed.py +++ /dev/null @@ -1,395 +0,0 @@ -import pygame -import time -import random -import os - -pygame.init() -pygame.mixer.init() - -gameWindow = pygame.display.set_mode((1200,700)) -pygame.display.set_caption("Speed Racer") - -clock = pygame.time.Clock() -fps = 60 - -font1 = pygame.font.SysFont("Franklin Gothic Demi Cond",50) - -car = pygame.image.load("data/images/Car.png") -car = pygame.transform.scale(car,(150,150)).convert_alpha() - -road = pygame.image.load("data/images/Road.png") -road = pygame.transform.scale(road,(400,700)).convert_alpha() - -sand = pygame.image.load("data/images/Sand.jpg") -sand = pygame.transform.scale(sand,(150,700)).convert_alpha() - -leftDisp = pygame.image.load("data/images/LeftDisplay.png") -leftDisp = pygame.transform.scale(leftDisp,(250,700)).convert_alpha() - -rightDisp = pygame.image.load("data/images/RightDisplay.png") -rightDisp = pygame.transform.scale(rightDisp,(250,700)).convert_alpha() - -tree = pygame.image.load("data/images/Tree.png") -tree = pygame.transform.scale(tree,(185,168)).convert_alpha() -treeLXY = [[290,0],[290,152.5],[290,305],[290,457.5],[290,610]] -treeRXY = [[760,0],[760,152.5],[760,305],[760,457.5],[760,610]] - -strip = pygame.image.load("data/images/Strip.png") -strip = pygame.transform.scale(strip,(25,90)).convert_alpha() -stripXY = [[593,0],[593,152.5],[593,305],[593,457.5],[593,610]] - -explosion = pygame.image.load("data/images/Explosion.png") -explosion = pygame.transform.scale(explosion,(290,164)).convert_alpha() - -fuel = pygame.image.load("data/images/Fuel.png") -fuel = pygame.transform.scale(fuel,(98,104)).convert_alpha() - -comingCars,goingCars = [],[] -speedCC = [13,14,15,14,14,15,13,14,15] -speedGC = [8,6,7,5,8,7,8,6,8] - -for i in range(1,10): - CCi = pygame.image.load("data/images/Coming Cars/"+"CC"+str(i)+".png") - CCi = pygame.transform.scale(CCi, (75, 158)).convert_alpha() - comingCars.append([CCi,speedCC[i-1]]) - GCi = pygame.image.load("data/images/Going Cars/"+"GC"+str(i)+".png").convert_alpha() - GCi = pygame.transform.scale(GCi,(75,158)).convert_alpha() - goingCars.append([GCi,speedGC[i-1]]) - -def distance(carX,obstX,carY,obstY,isFuel = False): - - if not isFuel: - carX += 75 # 75,75,37,79,55,130 - carY += 75 - obstX += 37 - obstY += 79 - - return abs(carX - obstX) < 55 and abs(carY - obstY) < 130 - else: - carX += 75 - carY += 75 - obstX += 98 - obstY += 104 - - return abs(carX - obstX) < 70 and abs(carY - obstY) < 80 - -def textOnScreen(text,color,x,y,font): - screenText = font.render(text,True,color) - gameWindow.blit(screenText,[x,y]) - -def slowDown(carX,carY,dist,highscore): - - stripXY_ = [[593, 0], [593, 152.5], [593, 305], [593, 457.5], [593, 610]] - exitScreen = False - - stripSpeed = 2 - - start = time.time() - while not exitScreen: - if time.time() - start > 3: - stripSpeed = 1 - if time.time() - start > 6: - exitScreen = True - for event in pygame.event.get(): - if event.type == pygame.QUIT: - exitScreen = True - - gameWindow.fill((0,0,0)) - gameWindow.blit(leftDisp, (0, 0)) - textOnScreen("DISTANCE", (255, 255, 0), 27, 388, font1) - textOnScreen(str(dist) + " Kms", (255, 0, 0), 56, 480, font1) - textOnScreen("FUEL", (255, 255, 0), 73, 90, font1) - textOnScreen(str(0.00) + ' %', (255, 0, 0), 75, 184, font1) - gameWindow.blit(rightDisp, (950, 0)) - textOnScreen("HIGHSCORE", (255, 255, 0), 958, 236, font1) - if(highscore < 10): - disp = str(0) + str(highscore) - else: - disp = str(highscore) - textOnScreen(disp + " Kms", (255, 0, 0), 1005, 342, font1) - gameWindow.blit(road, (400, 0)) - gameWindow.blit(sand,(250,0)) - gameWindow.blit(sand,(800,0)) - - for i in range(len(stripXY_)): - stripXY_[i][1] += stripSpeed - if stripXY_[i][1] > 700: - stripXY_[i] = [593, -60] - for i in range(len(treeLXY)): - treeLXY[i][1] += stripSpeed - if treeLXY[i][1] > 700: - treeLXY[i] = [290,-60] - for i in range(len(treeRXY)): - treeRXY[i][1] += stripSpeed - if treeRXY[i][1] > 700: - treeRXY[i] = [760,-60] - - for X,Y in stripXY_: - gameWindow.blit(strip,(X,Y)) - for treeX,treeY in treeLXY: - gameWindow.blit(tree,(treeX,treeY)) - for treeX,treeY in treeRXY: - gameWindow.blit(tree,(treeX,treeY)) - - gameWindow.blit(car,(carX,carY)) - pygame.display.update() - -def gameLoop(): - - pygame.mixer.music.load("data/audios/game.mp3") - pygame.mixer.music.play() - - time.sleep(1) - - carX,carY = 625,540 - drift = 4 - carSpeedX = 0 - - obstacleXY = [[460,-10],[710,-300]] - c1,c2 = random.randint(0,8),random.randint(0,8) - if(c1 == c2): - c1 = random.randint(0,8) - - obstacleSpeed = [comingCars[c1][1],goingCars[c2][1]] - obstacles = [comingCars[c1][0],goingCars[c2][0]] - - stripSpeed = 9 - - exitGame = False - gameOver = False - explode = False - - fuelCount = 50 - fuelX,fuelY = random.randint(420,620),-1000 - fuelSpeed = 8 - dist = 0 - - with open("data/Highscore.txt","r") as f: - highscore = int(f.read()) - - slow = False - plotFuel = True - - start1 = time.time() - start = [start1,start1] - start2 = start1 - start3 = start1 - start4 = start1 - arrival = [2,3.5] - - while not exitGame: - if gameOver: - - if slow: - slowDown(carX,carY,dist,highscore) - time.sleep(2) - - pygame.mixer.music.stop() - pygame.mixer.music.load("data/audios/rtn.mp3") - pygame.mixer.music.play() - - exitScreen = False - go = pygame.image.load("data/images/GameOver.png") - go = pygame.transform.scale(go,(1239,752)).convert_alpha() - - with open("data/Highscore.txt","w") as f: - f.write(str(highscore)) - - while not exitScreen: - for event in pygame.event.get(): - if event.type == pygame.QUIT: - exitScreen = True - elif event.type == pygame.KEYDOWN: - if event.key == pygame.K_RETURN: - pygame.mixer.music.stop() - homeScreen() - gameWindow.fill((0,0,0)) - gameWindow.blit(go,(0,0)) - if(dist < 10): - disp = str(0) + str(dist) - else: - disp = str(dist) - textOnScreen(disp,(255,0,0),540,429,font1) - pygame.display.update() - clock.tick(fps) - - pygame.quit() - quit() - else: - for event in pygame.event.get(): - if event.type == pygame.QUIT: - exitGame = True - elif event.type == pygame.KEYDOWN: - if event.key == pygame.K_RIGHT: - carSpeedX = drift - elif event.key == pygame.K_LEFT: - carSpeedX = -drift - elif event.key == pygame.K_a: - obstacleXY[0][0] -= 20 - elif event.key == pygame.K_d: - obstacleXY[1][0] += 20 - - carX += carSpeedX - fuelY += fuelSpeed - - if time.time() - start4 >= 2: - dist += 1 - if dist > highscore: - highscore = dist - start4 = time.time() - - if time.time() - start2 >= 3: - fuelCount -= 5 - start2 = time.time() - - if distance(carX,fuelX,carY,fuelY,True) and plotFuel: - plotFuel = False - fuelCount += 20 - - for i in range(len(obstacleXY)): - obstacleXY[i][1] += obstacleSpeed[i] - - fuelper = fuelCount/50 - if fuelper >= 1: - fuelper = 1 - - gameWindow.fill((0,0,0)) - gameWindow.blit(leftDisp,(0,0)) - textOnScreen("DISTANCE", (255, 255, 0),27,388,font1) - if(dist < 10): - disp = str(0) + str(dist) - else: - disp = str(dist) - textOnScreen(disp + " Kms",(255,0,0),56,480,font1) - textOnScreen("FUEL",(255,255,0),73,90,font1) - textOnScreen(str(fuelper*100) + ' %',(255,0,0),60,184,font1) - gameWindow.blit(rightDisp, (950, 0)) - textOnScreen("HIGHSCORE",(255,255,0),958,236,font1) - if(highscore < 10): - disp = str(0) + str(highscore) - else: - disp = str(highscore) - textOnScreen(disp + " Kms",(255,0,0),1005,342,font1) - gameWindow.blit(road,(400,0)) - gameWindow.blit(sand, (250, 0)) - gameWindow.blit(sand, (800, 0)) - - if fuelCount == 0: - gameOver = True - slow = True - - if carX > 720 or carX < 330: - pygame.mixer.music.load("data/audios/Crash.mp3") - pygame.mixer.music.play() - gameOver = True - explode = True - - for i in range(len(obstacleXY)): - if distance(carX,obstacleXY[i][0],carY,obstacleXY[i][1]): - pygame.mixer.music.load("data/audios/Crash.mp3") - pygame.mixer.music.play() - gameOver = True - explode = True - break - for i in range(len(stripXY)): - stripXY[i][1] += stripSpeed - if stripXY[i][1] > 700: - stripXY[i] = [593,-60] - for i in range(len(treeLXY)): - treeLXY[i][1] += stripSpeed - if treeLXY[i][1] > 700: - treeLXY[i] = [290, -60] - for i in range(len(treeRXY)): - treeRXY[i][1] += stripSpeed - if treeRXY[i][1] > 700: - treeRXY[i] = [760, -60] - - for stripX,stripY in stripXY: - gameWindow.blit(strip,(stripX,stripY)) - - if fuelY < 750: - if plotFuel: - gameWindow.blit(fuel,(fuelX,fuelY)) - - gameWindow.blit(car,(carX,carY)) - - for i in range(len(obstacleXY)): - if obstacleXY[i][1] < 750: - gameWindow.blit(obstacles[i],(obstacleXY[i][0], obstacleXY[i][1])) - - for treeX, treeY in treeLXY: - gameWindow.blit(tree, (treeX, treeY)) - for treeX, treeY in treeRXY: - gameWindow.blit(tree, (treeX, treeY)) - - if time.time() - start[0] >= arrival[0]: - x = random.randint(430,530) - x+=3 - obstacleXY[0] = [x,-10] - c1 = random.randint(0,8) - obstacles[0] = comingCars[c1][0] - obstacleSpeed[0] = comingCars[c1][1] - start[0] = time.time() - if time.time() - start[1] >= arrival[1]: - x = random.randint(620,710) - x-=3 - obstacleXY[1] = [x,-10] - c2 = random.randint(0,8) - obstacles[1] = goingCars[c2][0] - obstacleSpeed[1] = goingCars[c2][1] - start[1] = time.time() - if time.time() - start3 >= 15: - fuelX,fuelY = random.randint(420,710),-500 - plotFuel = True - start3 = time.time() - if explode: - gameWindow.blit(explosion,(carX - 63,carY)) - - pygame.display.update() - clock.tick(fps) - - - pygame.quit() - quit() - -def homeScreen(): - - pygame.mixer.music.load("data/audios/rtn.mp3") - pygame.mixer.music.play() - - if not os.path.exists("data/Highscore.txt"): - with open("data/Highscore.txt","w") as f: - f.write("0") - highscore = 0 - else: - with open("data/Highscore.txt","r") as f: - highscore = int(f.read()) - - - background = pygame.image.load("data/images/Background.png") - background = pygame.transform.scale(background,(1213,760)).convert_alpha() - - exitScreen = False - while not exitScreen: - for event in pygame.event.get(): - if event.type == pygame.QUIT: - exitScreen = True - elif event.type == pygame.KEYDOWN: - if event.key == pygame.K_RETURN: - pygame.mixer.music.stop() - gameLoop() - - gameWindow.blit(background,(-6,-32)) - if(highscore < 10): - disp = str(0) + str(highscore) - else: - disp = str(highscore) - textOnScreen(disp,(255,0,0),980,9,font1) - pygame.display.update() - clock.tick(fps) - - pygame.quit() - quit() - - -homeScreen() diff --git a/tetris.py b/tetris.py new file mode 100644 index 0000000..42de2b8 --- /dev/null +++ b/tetris.py @@ -0,0 +1,208 @@ +import dearpygui.dearpygui as dpg + +dpg.create_context() +# Configure viewport +dpg.create_viewport(title="Tetris Game") +dpg.configure_viewport(0, x_pos=0, y_pos=0, width=1000, height=790) +dpg.set_viewport_max_height(790) +dpg.set_viewport_max_width(1000) +dpg.set_viewport_min_height(790) +dpg.set_viewport_min_width(100) + +import time +from theme_settings import * +from config import * +import config +import tetrominos_handler +import threading + + +def set_main_window(): + # Function sets up the displays of the main game window + + # Play audio for selection made + tetrominos_handler.audio_effectsDispatcher("selection.wav") + + # Get level entered by the user + config.level = dpg.get_value(item=item_id["displays"]["enter_level"]) + + # Main window config + with dpg.window(pos=[0, 0], autosize=True, no_collapse=True, no_resize=True, no_close=True, no_move=True, + no_title_bar=True, tag=item_id["windows"]["main_window"]): + with dpg.group(horizontal=True): + # Score board and help window config + with dpg.child_window(width=320, tag=item_id["windows"]["score_window"]): + dpg.add_spacer(height=10) + + with dpg.group(horizontal=True): + dpg.add_text(default_value=" Your level : ") + dpg.add_text(default_value=config.level, tag=item_id["displays"]["level_text"]) + + dpg.add_spacer() + + with dpg.group(horizontal=True): + dpg.add_text(default_value=" Full lines : ") + dpg.add_text(default_value="0", tag=item_id["displays"]["full_line_text"]) + + dpg.add_spacer(height=10) + + with dpg.group(horizontal=True): + dpg.add_text(default_value=" SCORE : ") + dpg.add_text(default_value="0", color=(161, 94, 33), tag=item_id["displays"]["score_text"]) + + dpg.add_spacer(height=50) + + help_text = dpg.add_button(label="H E L P", width=-1) + dpg.bind_item_theme(item=help_text, theme=dummy_button_theme) + + dpg.add_spacer(height=20) + dpg.add_text(default_value=" LEFT KEY : Left") + dpg.add_text(default_value=" RIGHT KEY : Right") + dpg.add_text(default_value=" UP KEY : Rotate") + dpg.add_text(default_value=" DOWN KEY : Speed up") + dpg.add_text(default_value=" SPACE : Drop") + + dpg.add_spacer(height=50) + next_text = dpg.add_button(label="Next :", width=-1) + dpg.bind_item_theme(item=next_text, theme=dummy_button_theme) + + with dpg.plot(no_menus=False, no_title=True, no_box_select=True, no_mouse_pos=True, width=315, + height=160, equal_aspects=True, tag=item_id["windows"]["next_block_board"]): + dpg.bind_item_theme(item=item_id["windows"]["next_block_board"], theme=no_border_board_theme) + + x = dpg.add_plot_axis(axis=0, no_gridlines=True, no_tick_marks=True, no_tick_labels=True, + lock_min=True) + y = dpg.add_plot_axis(axis=1, no_gridlines=True, no_tick_marks=True, no_tick_labels=True, + lock_min=True) + + dpg.set_axis_limits(axis=x, ymin=0, ymax=8) + dpg.set_axis_limits(axis=y, ymin=0, ymax=4) + + # Tetris board window config + with dpg.group(): + with dpg.plot(no_menus=False, no_title=True, no_box_select=True, no_mouse_pos=True, width=325, + height=650, equal_aspects=True, tag=item_id["windows"]["tetris_board"]): + default_x = dpg.add_plot_axis(axis=0, no_gridlines=False, no_tick_marks=True, no_tick_labels=True, + lock_min=True) + default_y = dpg.add_plot_axis(axis=1, no_gridlines=False, no_tick_marks=True, no_tick_labels=True, + lock_min=True) + + dpg.set_axis_limits(axis=default_x, ymin=0, ymax=10) + dpg.set_axis_limits(axis=default_y, ymin=0, ymax=20) + + dpg.add_vline_series(x=[n for n in range(10)], parent=default_x) + dpg.add_hline_series(x=[n for n in range(120)], parent=default_y) + + dpg.add_button(label="Play TETRIS !", width=325, callback=tetrominos_handler.create_blocksDispatcher, + tag=item_id["buttons"]["play_button"]) + dpg.bind_item_font(item=item_id["buttons"]["play_button"], font=play_font) + dpg.bind_item_theme(item=item_id["buttons"]["play_button"], theme=play_button_theme) + + # Statistics window config + with dpg.child_window(autosize_x=True): + dpg.add_spacer(height=10) + + statistics_text = dpg.add_button(label="STATISTICS", width=-1) + dpg.bind_item_theme(item=statistics_text, theme=dummy_button_theme) + + with dpg.plot(no_menus=False, no_title=True, no_box_select=True, no_mouse_pos=True, width=315, + height=560, equal_aspects=True, tag=item_id["windows"]["statistics_window"]): + dpg.bind_item_theme(item=item_id["windows"]["statistics_window"], theme=no_border_board_theme) + + x = dpg.add_plot_axis(axis=0, no_gridlines=True, no_tick_marks=True, no_tick_labels=True, + lock_min=True) + y = dpg.add_plot_axis(axis=1, no_gridlines=True, no_tick_marks=True, no_tick_labels=True, + lock_min=True) + + dpg.set_axis_limits(axis=x, ymin=0, ymax=10) + dpg.set_axis_limits(axis=y, ymin=0, ymax=19) + + tetrominos_handler.draw_statistics_LBlock() + tetrominos_handler.draw_statistics_IBlock() + tetrominos_handler.draw_statistics_TBlock() + tetrominos_handler.draw_statistics_ZBlock() + tetrominos_handler.draw_statistics_SBlock() + tetrominos_handler.draw_statistics_OBlock() + tetrominos_handler.draw_statistics_JBlock() + + dashed_line_text = dpg.add_button(label="-------------------", width=-1) + + with dpg.group(horizontal=True): + dpg.add_text(default_value=" Total") + dpg.add_spacer(width=160) + dpg.add_text(default_value="0", tag=item_id["displays"]["Total_block_stat"]) + + dpg.bind_item_theme(item=dashed_line_text, theme=dummy_button_theme) + + dpg.delete_item(item=enter_level_screen) + dpg.set_primary_window(window=item_id["windows"]["main_window"], value=True) + + +def press_any_key_to_start(): + # Function continues to show enter level screen when any key is pressed + # Play audio effect to indicate selection + tetrominos_handler.audio_effectsDispatcher("selection.wav") + + # Continue with setting up enter level screen + dpg.delete_item(item=item_id["registries"]["key_release_handler"]) + dpg.delete_item(item=item_id["registries"]["mouse_release_handler"]) + dpg.delete_item(item=welcome_screen) + dpg.configure_item(item=enter_level_screen, show=True) + dpg.set_primary_window(window=enter_level_screen, value=True) + + +# Welcome screen config +with dpg.window(modal=True, autosize=True, no_collapse=True, no_resize=True, no_close=True, no_move=True, + no_title_bar=True) as welcome_screen: + width, height, channels, data = dpg.load_image("textures/welcome_screen.jpg") + + welcome_screen_image = dpg.add_static_texture(width, height, data, tag="welcome_screen_image", + parent=item_id["registries"]["texture_registry"]) + dpg.add_image("welcome_screen_image") + + dpg.add_handler_registry(tag=item_id["registries"]["key_release_handler"]) + dpg.add_handler_registry(tag=item_id["registries"]["mouse_release_handler"]) + + dpg.add_key_release_handler(callback=press_any_key_to_start, + parent=item_id["registries"]["key_release_handler"]) + dpg.add_mouse_release_handler(callback=press_any_key_to_start, + parent=item_id["registries"]["mouse_release_handler"]) + +# Enter level screen config +with dpg.window(autosize=True, no_collapse=True, no_resize=True, no_close=True, no_move=True, + no_title_bar=True, show=False) as enter_level_screen: + dpg.add_spacer(height=350) + + with dpg.group(horizontal=True): + dpg.add_child_window(width=280) + + with dpg.group(horizontal=True): + dpg.add_text(default_value="Enter your level (0-9) > ") + dpg.add_input_int(label="", step=0, min_value=0, max_value=9, width=30, on_enter=True, + default_value=0, callback=set_main_window, tag=item_id["displays"]["enter_level"]) + + +def background_theme(): + # Function starts a new thread to play the background theme + play_theme_thread = threading.Thread(name="play theme", target=theme_audio, args=(), daemon=True) + play_theme_thread.start() + + +def theme_audio(): + # Function loops the background theme + while True: + tetrominos_handler.audio_effectsDispatcher("theme.mp3") + time.sleep(84) + + +dpg.bind_theme(global_theme) +dpg.bind_font(regular_font) + +# Initiates the theme playback +background_theme() + +dpg.set_primary_window(window=welcome_screen, value=True) +dpg.setup_dearpygui() +dpg.show_viewport() +dpg.start_dearpygui() +dpg.destroy_context() diff --git a/tetrominos_handler/IBlock.py b/tetrominos_handler/IBlock.py new file mode 100644 index 0000000..04d3368 --- /dev/null +++ b/tetrominos_handler/IBlock.py @@ -0,0 +1,87 @@ +import time +import threading +import config +from config import * + + +class IBlock: + def __init__(self): + self.cells = 4 # Number of cells occupied by the block + config.block_count += 1 + config.item_id["blocks"][f"{config.block_count}"] = {} # Add a new key to dictionary to add block IDs + + for n in range(self.cells): + # Loop draws the complete block on the top of the board + + # Generate an ID for each cell occupied by the block + config.item_id["blocks"][f"{config.block_count}"][f"{n}"] = dpg.generate_uuid() + + # Make a list of the initial cells occupied by the blocks + config.cells_occupied.append([3 + n, 19]) + + # Draw the cell + dpg.draw_image(texture_tag=item_id["block_texture"]["I_block"], pmin=[3 + n, 20], pmax=[4 + n, 19], + parent=item_id["windows"]["tetris_board"], + id=config.item_id["blocks"][f"{config.block_count}"][f"{n}"]) + + # Update statistics + # Take the value shown, add 1 and set value + dpg.configure_item(item=item_id["displays"]["I_block_stat"], + text=int( + dpg.get_item_configuration(item=item_id["displays"]["I_block_stat"])["text"]) + 1) + + dpg.set_value(item=item_id["displays"]["Total_block_stat"], + value=int(dpg.get_value(item=item_id["displays"]["Total_block_stat"])) + 1) + + def move_blockDispatcher(self): + # Function creates a new thread that controls the continuous movement of the new blocks + move_block_thread = threading.Thread(name="move block", target=self.move_block, args=(), daemon=True) + move_block_thread.start() + + def move_block(self): + # Function controls the continuous downward movement of the blocks + config.block_moving_flag = 1 # Set to 1=IBlock. Block is moving + + while True: + for n in range(self.cells): + config.cells_occupied[-1 - n][1] -= 1 # Shift the Y Coordinate down by 1 unit + + if any(item in config.cells_occupied[-self.cells:] for item in config.cell_boundary) or \ + any(item in config.cells_occupied[-self.cells:] for item in config.cells_occupied[:-self.cells]): + # Check if any cells have touched the wall or other blocks. If so, stop the movement + for n in range(self.cells): + config.cells_occupied[-1 - n][1] += 1 # Reset the Y coordinate + config.block_moving_flag = 0 # Block has stopped moving + return + + for n in range(self.cells): + # Draw after all cells are updated + dpg.configure_item(item=config.item_id["blocks"][f"{config.block_count}"][f"{n}"], + pmin=[config.cells_occupied[-1 - n][0], config.cells_occupied[-1 - n][1] + 1], + pmax=[config.cells_occupied[-1 - n][0] + 1, config.cells_occupied[-1 - n][1]]) + + time.sleep(config.speed) # Wait at each cell + + +def draw_next_IBlock(): + for n in range(4): + # Loop draws the complete block on the "next" board + + # Draw the cell + dpg.draw_image(texture_tag=item_id["block_texture"]["I_block"], pmin=[2 + n, 4], pmax=[3 + n, 3], + parent=item_id["windows"]["next_block_board"]) + + +def draw_statistics_IBlock(): + for n in range(4): + # Loop draws the complete block on the "next" board + + # Draw the cell + dpg.draw_image(texture_tag=item_id["block_texture"]["I_block"], pmin=[2 + n, 16], pmax=[3 + n, 15], + parent=item_id["windows"]["statistics_window"]) + + dpg.draw_line(p1=[6.5, 15.5], p2=[7.5, 15.5], thickness=0.1, color=[168, 168, 168], + parent=item_id["windows"]["statistics_window"]) + + dpg.draw_text(pos=[8.5, 15.8], text="0", size=0.5, color=[168, 168, 168], + id=item_id["displays"]["I_block_stat"]) \ No newline at end of file diff --git a/tetrominos_handler/JBlock.py b/tetrominos_handler/JBlock.py new file mode 100644 index 0000000..e338831 --- /dev/null +++ b/tetrominos_handler/JBlock.py @@ -0,0 +1,103 @@ +import time +import threading +import config +from config import * + + +class JBlock: + def __init__(self): + self.cells = 4 # Number of cells occupied by the block + config.block_count += 1 + config.item_id["blocks"][f"{config.block_count}"] = {} # Add a new key to dictionary to add block IDs + + for n in range(self.cells - 1): + # Loop draws the bottom cells of the block on the top of the board + + # Generate an ID for each cell occupied by the block + config.item_id["blocks"][f"{config.block_count}"][f"{n}"] = dpg.generate_uuid() + + # Make a list of the initial cells occupied by the blocks + config.cells_occupied.append([3 + n, 18]) + + # Draw the cell + dpg.draw_image(texture_tag=item_id["block_texture"]["J_block"], pmin=[3 + n, 19], pmax=[4 + n, 18], + parent=item_id["windows"]["tetris_board"], + id=config.item_id["blocks"][f"{config.block_count}"][f"{n}"]) + + # Draw the final cell on the top + # Generate an ID for the top cell occupied by the block + config.item_id["blocks"][f"{config.block_count}"]["3"] = dpg.generate_uuid() + # Add point to cells_occupied list + config.cells_occupied.append([3, 19]) + # Draw the cell + dpg.draw_image(texture_tag=item_id["block_texture"]["J_block"], pmin=[3, 20], pmax=[4, 19], + parent=item_id["windows"]["tetris_board"], + id=config.item_id["blocks"][f"{config.block_count}"]["3"]) + + # Update statistics + # Take the value shown, add 1 and set value + dpg.configure_item(item=item_id["displays"]["J_block_stat"], + text=int(dpg.get_item_configuration(item=item_id["displays"]["J_block_stat"])["text"]) + 1) + + dpg.set_value(item=item_id["displays"]["Total_block_stat"], + value=int(dpg.get_value(item=item_id["displays"]["Total_block_stat"])) + 1) + + + def move_blockDispatcher(self): + # Function creates a new thread that controls the continuous movement of the new blocks + move_block_thread = threading.Thread(name="move block", target=self.move_block, args=(), daemon=True) + move_block_thread.start() + + def move_block(self): + # Function controls the continuous downward movement of the blocks + config.block_moving_flag = 2 # Set to 2=JBlock. Block is moving + + while True: + for n in range(self.cells): + config.cells_occupied[-1 - n][1] -= 1 # Shift the Y Coordinate down by 1 unit + + if any(item in config.cells_occupied[-self.cells:] for item in config.cell_boundary) or \ + any(item in config.cells_occupied[-self.cells:] for item in config.cells_occupied[:-self.cells]): + # Check if any cells have touched the wall or other blocks. If so, stop the movement + for n in range(self.cells): + config.cells_occupied[-1 - n][1] += 1 # Reset the Y coordinate + config.block_moving_flag = 0 # Block has stopped moving + return + + for n in range(self.cells): + # Draw after all cells are updated + dpg.configure_item(item=config.item_id["blocks"][f"{config.block_count}"][f"{n}"], + pmin=[config.cells_occupied[-1 - n][0], config.cells_occupied[-1 - n][1] + 1], + pmax=[config.cells_occupied[-1 - n][0] + 1, config.cells_occupied[-1 - n][1]]) + + time.sleep(config.speed) # Wait at each cell + + +def draw_next_JBlock(): + for n in range(3): + # Loop draws the complete block on the "next" board + dpg.draw_image(texture_tag=item_id["block_texture"]["J_block"], pmin=[3 + n, 3], pmax=[4 + n, 2], + parent=item_id["windows"]["next_block_board"]) + + # Draw the final cell on the top + # Draw the cell + dpg.draw_image(texture_tag=item_id["block_texture"]["J_block"], pmin=[3, 4], pmax=[4, 3], + parent=item_id["windows"]["next_block_board"]) + + +def draw_statistics_JBlock(): + for n in range(3): + # Loop draws the complete block on the "next" board + dpg.draw_image(texture_tag=item_id["block_texture"]["J_block"], pmin=[1 + n, 1], pmax=[2 + n, 0], + parent=item_id["windows"]["statistics_window"]) + + # Draw the final cell on the top + # Draw the cell + dpg.draw_image(texture_tag=item_id["block_texture"]["J_block"], pmin=[1, 2], pmax=[2, 1], + parent=item_id["windows"]["statistics_window"]) + + dpg.draw_line(p1=[6.5, 1], p2=[7.5, 1], thickness=0.1, color=[168, 168, 168], + parent=item_id["windows"]["statistics_window"]) + + dpg.draw_text(pos=[8.5, 1.3], text="0", size=0.5, color=[168, 168, 168], + id=item_id["displays"]["J_block_stat"]) diff --git a/tetrominos_handler/LBlock.py b/tetrominos_handler/LBlock.py new file mode 100644 index 0000000..077a5ae --- /dev/null +++ b/tetrominos_handler/LBlock.py @@ -0,0 +1,101 @@ +import time +import threading +import config +from config import * + + +class LBlock: + def __init__(self): + self.cells = 4 # Number of cells occupied by the block + config.block_count += 1 + config.item_id["blocks"][f"{config.block_count}"] = {} # Add a new key to dictionary to add block IDs + + for n in range(self.cells - 1): + # Loop draws the bottom cells of the block on the top of the board + + # Generate an ID for each cell occupied by the block + config.item_id["blocks"][f"{config.block_count}"][f"{n}"] = dpg.generate_uuid() + + # Make a list of the initial cells occupied by the blocks + config.cells_occupied.append([3 + n, 18]) + + # Draw the cell + dpg.draw_image(texture_tag=item_id["block_texture"]["L_block"], pmin=[3 + n, 19], pmax=[4 + n, 18], + parent=item_id["windows"]["tetris_board"], + id=config.item_id["blocks"][f"{config.block_count}"][f"{n}"]) + + # Draw the final cell on the top + # Generate an ID for the top cell occupied by the block + config.item_id["blocks"][f"{config.block_count}"]["3"] = dpg.generate_uuid() + # Add point to cells_occupied list + config.cells_occupied.append([5, 19]) + # Draw the cell + dpg.draw_image(texture_tag=item_id["block_texture"]["L_block"], pmin=[5, 20], pmax=[6, 19], + parent=item_id["windows"]["tetris_board"], + id=config.item_id["blocks"][f"{config.block_count}"]["3"]) + + # Update statistics + # Take the value shown, add 1 and set value + dpg.configure_item(item=item_id["displays"]["L_block_stat"], + text=int(dpg.get_item_configuration(item=item_id["displays"]["L_block_stat"])["text"]) + 1) + + dpg.set_value(item=item_id["displays"]["Total_block_stat"], + value=int(dpg.get_value(item=item_id["displays"]["Total_block_stat"])) + 1) + + def move_blockDispatcher(self): + # Function creates a new thread that controls the continuous movement of the new blocks + move_block_thread = threading.Thread(name="move block", target=self.move_block, args=(), daemon=True) + move_block_thread.start() + + def move_block(self): + # Function controls the continuous downward movement of the blocks + config.block_moving_flag = 3 # Set to 3=LBlock. Block is moving + + while True: + for n in range(self.cells): + config.cells_occupied[-1 - n][1] -= 1 # Shift the Y Coordinate down by 1 unit + + if any(item in config.cells_occupied[-self.cells:] for item in config.cell_boundary) or \ + any(item in config.cells_occupied[-self.cells:] for item in config.cells_occupied[:-self.cells]): + # Check if any cells have touched the wall or other blocks. If so, stop the movement + for n in range(self.cells): + config.cells_occupied[-1 - n][1] += 1 # Reset the Y coordinate + config.block_moving_flag = 0 # Block has stopped moving + return + + for n in range(self.cells): + # Draw after all cells are updated + dpg.configure_item(item=config.item_id["blocks"][f"{config.block_count}"][f"{n}"], + pmin=[config.cells_occupied[-1 - n][0], config.cells_occupied[-1 - n][1] + 1], + pmax=[config.cells_occupied[-1 - n][0] + 1, config.cells_occupied[-1 - n][1]]) + + time.sleep(config.speed) # Wait at each cell + + +def draw_next_LBlock(): + for n in range(3): + # Loop draws the complete block on the "next" board + dpg.draw_image(texture_tag=item_id["block_texture"]["L_block"], pmin=[3 + n, 3], pmax=[4 + n, 2], + parent=item_id["windows"]["next_block_board"]) + + # Draw the final cell on the top + # Draw the cell + dpg.draw_image(texture_tag=item_id["block_texture"]["L_block"], pmin=[5, 4], pmax=[6, 3], + parent=item_id["windows"]["next_block_board"]) + + +def draw_statistics_LBlock(): + for n in range(3): + # Loop draws the complete block on the "next" board + dpg.draw_image(texture_tag=item_id["block_texture"]["L_block"], pmin=[1 + n, 18], pmax=[2 + n, 17], + parent=item_id["windows"]["statistics_window"]) + + # Draw the final cell on the top + # Draw the cell + dpg.draw_image(texture_tag=item_id["block_texture"]["L_block"], pmin=[3, 19], pmax=[4, 18], + parent=item_id["windows"]["statistics_window"]) + + dpg.draw_line(p1=[6.5, 18], p2=[7.5, 18], thickness=0.1, color=[168, 168, 168], + parent=item_id["windows"]["statistics_window"]) + + dpg.draw_text(pos=[8.5, 18.3], text="0", size=0.5, color=[168, 168, 168], id=item_id["displays"]["L_block_stat"]) diff --git a/tetrominos_handler/OBlock.py b/tetrominos_handler/OBlock.py new file mode 100644 index 0000000..74cbbe5 --- /dev/null +++ b/tetrominos_handler/OBlock.py @@ -0,0 +1,96 @@ +import time +import threading +import config +from config import * + + +class OBlock: + def __init__(self): + self.cells = 4 # Number of cells occupied by the block + config.block_count += 1 + config.item_id["blocks"][f"{config.block_count}"] = {} # Add a new key to dictionary to add block IDs + + cell_count = 0 + for n in range(self.cells - 2): + for m in range(self.cells - 2): + # Loop draws the bottom cells of the block on the top of the board + + # Generate an ID for each cell occupied by the block + config.item_id["blocks"][f"{config.block_count}"][f"{cell_count}"] = dpg.generate_uuid() + + # Make a list of the initial cells occupied by the blocks + config.cells_occupied.append([4 + m, 19 - n]) + + # Draw the cell + dpg.draw_image(texture_tag=item_id["block_texture"]["O_block"], pmin=[4 + m, 20 - n], pmax=[5 + m, 19 - n], + parent=item_id["windows"]["tetris_board"], + id=config.item_id["blocks"][f"{config.block_count}"][f"{cell_count}"]) + cell_count += 1 + + # Update statistics + # Take the value shown, add 1 and set value + dpg.configure_item(item=item_id["displays"]["O_block_stat"], + text=int(dpg.get_item_configuration(item=item_id["displays"]["O_block_stat"])[ + "text"]) + 1) + + dpg.set_value(item=item_id["displays"]["Total_block_stat"], + value=int(dpg.get_value(item=item_id["displays"]["Total_block_stat"])) + 1) + + def move_blockDispatcher(self): + # Function creates a new thread that controls the continuous movement of the new blocks + move_block_thread = threading.Thread(name="move block", target=self.move_block, args=(), daemon=True) + move_block_thread.start() + + def move_block(self): + # Function controls the continuous downward movement of the blocks + config.block_moving_flag = 4 # Set to 4=OBlock. Block is moving + + while True: + for n in range(self.cells): + config.cells_occupied[-1 - n][1] -= 1 # Shift the Y Coordinate down by 1 unit + + if any(item in config.cells_occupied[-self.cells:] for item in config.cell_boundary) or \ + any(item in config.cells_occupied[-self.cells:] for item in config.cells_occupied[:-self.cells]): + # Check if any cells have touched the wall or other blocks. If so, stop the movement + for n in range(self.cells): + config.cells_occupied[-1 - n][1] += 1 # Reset the Y coordinate + config.block_moving_flag = 0 # Block has stopped moving + return + + for n in range(self.cells): + # Draw after all cells are updated + dpg.configure_item(item=config.item_id["blocks"][f"{config.block_count}"][f"{n}"], + pmin=[config.cells_occupied[-1 - n][0], config.cells_occupied[-1 - n][1] + 1], + pmax=[config.cells_occupied[-1 - n][0] + 1, config.cells_occupied[-1 - n][1]]) + + time.sleep(config.speed) # Wait at each cell + + +def draw_next_OBlock(): + for n in range(2): + # Loop draws the bottom layer of the complete block on the "next" board + dpg.draw_image(texture_tag=item_id["block_texture"]["O_block"], pmin=[3 + n, 3], pmax=[4 + n, 2], + parent=item_id["windows"]["next_block_board"]) + + for n in range(2): + # Loop draws the top layer of the complete block on the "next" board + dpg.draw_image(texture_tag=item_id["block_texture"]["O_block"], pmin=[3 + n, 4], pmax=[4 + n, 3], + parent=item_id["windows"]["next_block_board"]) + + +def draw_statistics_OBlock(): + for n in range(2): + # Loop draws the bottom layer of the complete block on the "next" board + dpg.draw_image(texture_tag=item_id["block_texture"]["O_block"], pmin=[4 + n, 4], pmax=[5 + n, 3], + parent=item_id["windows"]["statistics_window"]) + + for n in range(2): + # Loop draws the top layer of the complete block on the "next" board + dpg.draw_image(texture_tag=item_id["block_texture"]["O_block"], pmin=[4 + n, 5], pmax=[5 + n, 4], + parent=item_id["windows"]["statistics_window"]) + + dpg.draw_line(p1=[6.5, 4], p2=[7.5, 4], thickness=0.1, color=[168, 168, 168], + parent=item_id["windows"]["statistics_window"]) + + dpg.draw_text(pos=[8.5, 4.3], text="0", size=0.5, color=[168, 168, 168], + id=item_id["displays"]["O_block_stat"]) diff --git a/tetrominos_handler/SBlock.py b/tetrominos_handler/SBlock.py new file mode 100644 index 0000000..482fd0e --- /dev/null +++ b/tetrominos_handler/SBlock.py @@ -0,0 +1,105 @@ +import time +import threading +import config +from config import * + + +class SBlock: + def __init__(self): + self.cells = 4 # Number of cells occupied by the block + config.block_count += 1 + config.item_id["blocks"][f"{config.block_count}"] = {} # Add a new key to dictionary to add block IDs + + for n in range(self.cells - 2): + # Loop draws the bottom cells of the block on the top of the board + + # Generate an ID for each cell occupied by the block + config.item_id["blocks"][f"{config.block_count}"][f"{n}"] = dpg.generate_uuid() + + # Make a list of the initial cells occupied by the blocks + config.cells_occupied.append([3 + n, 18]) + + # Draw the cell + dpg.draw_image(texture_tag=item_id["block_texture"]["S_block"], pmin=[3 + n, 19], pmax=[4 + n, 18], + parent=item_id["windows"]["tetris_board"], + id=config.item_id["blocks"][f"{config.block_count}"][f"{n}"]) + + for n in range(self.cells - 2): + # Draw the final cells on the top + # Generate an ID for the top cell occupied by the block + config.item_id["blocks"][f"{config.block_count}"][f"{n + 2}"] = dpg.generate_uuid() + # Add point to cells_occupied list + config.cells_occupied.append([4 + n, 19]) + # Draw the cell + dpg.draw_image(texture_tag=item_id["block_texture"]["S_block"], pmin=[4 + n, 20], pmax=[5 + n, 19], + parent=item_id["windows"]["tetris_board"], + id=config.item_id["blocks"][f"{config.block_count}"][f"{n + 2}"]) + + # Update statistics + # Take the value shown, add 1 and set value + dpg.configure_item(item=item_id["displays"]["S_block_stat"], + text=int( + dpg.get_item_configuration(item=item_id["displays"]["S_block_stat"])["text"]) + 1) + + dpg.set_value(item=item_id["displays"]["Total_block_stat"], + value=int(dpg.get_value(item=item_id["displays"]["Total_block_stat"])) + 1) + + + def move_blockDispatcher(self): + # Function creates a new thread that controls the continuous movement of the new blocks + move_block_thread = threading.Thread(name="move block", target=self.move_block, args=(), daemon=True) + move_block_thread.start() + + def move_block(self): + # Function controls the continuous downward movement of the blocks + config.block_moving_flag = 5 # Set to 5=SBlock. Block is moving + + while True: + for n in range(self.cells): + config.cells_occupied[-1 - n][1] -= 1 # Shift the Y Coordinate down by 1 unit + + if any(item in config.cells_occupied[-self.cells:] for item in config.cell_boundary) or \ + any(item in config.cells_occupied[-self.cells:] for item in config.cells_occupied[:-self.cells]): + # Check if any cells have touched the wall or other blocks. If so, stop the movement + for n in range(self.cells): + config.cells_occupied[-1 - n][1] += 1 # Reset the Y coordinate + config.block_moving_flag = 0 # Block has stopped moving + return + + for n in range(self.cells): + # Draw after all cells are updated + dpg.configure_item(item=config.item_id["blocks"][f"{config.block_count}"][f"{n}"], + pmin=[config.cells_occupied[-1 - n][0], config.cells_occupied[-1 - n][1] + 1], + pmax=[config.cells_occupied[-1 - n][0] + 1, config.cells_occupied[-1 - n][1]]) + + time.sleep(config.speed) # Wait at each cell + + +def draw_next_SBlock(): + for n in range(2): + # Loop draws the bottom layer of the complete block on the "next" board + dpg.draw_image(texture_tag=item_id["block_texture"]["S_block"], pmin=[3 + n, 3], pmax=[4 + n, 2], + parent=item_id["windows"]["next_block_board"]) + + for n in range(2): + # Loop draws the top layer of the complete block on the "next" board + dpg.draw_image(texture_tag=item_id["block_texture"]["S_block"], pmin=[4 + n, 4], pmax=[5 + n, 3], + parent=item_id["windows"]["next_block_board"]) + + +def draw_statistics_SBlock(): + for n in range(2): + # Loop draws the bottom layer of the complete block on the "next" board + dpg.draw_image(texture_tag=item_id["block_texture"]["S_block"], pmin=[3 + n, 10], pmax=[4 + n, 9], + parent=item_id["windows"]["statistics_window"]) + + for n in range(2): + # Loop draws the top layer of the complete block on the "next" board + dpg.draw_image(texture_tag=item_id["block_texture"]["S_block"], pmin=[4 + n, 11], pmax=[5 + n, 10], + parent=item_id["windows"]["statistics_window"]) + + dpg.draw_line(p1=[6.5, 10], p2=[7.5, 10], thickness=0.1, color=[168, 168, 168], + parent=item_id["windows"]["statistics_window"]) + + dpg.draw_text(pos=[8.5, 10.3], text="0", size=0.5, color=[168, 168, 168], + id=item_id["displays"]["S_block_stat"]) diff --git a/tetrominos_handler/TBlock.py b/tetrominos_handler/TBlock.py new file mode 100644 index 0000000..b47085a --- /dev/null +++ b/tetrominos_handler/TBlock.py @@ -0,0 +1,103 @@ +import time +import threading +import config +from config import * + + +class TBlock: + def __init__(self): + self.cells = 4 # Number of cells occupied by the block + config.block_count += 1 + config.item_id["blocks"][f"{config.block_count}"] = {} # Add a new key to dictionary to add block IDs + + for n in range(self.cells - 1): + # Loop draws the bottom cells of the block on the top of the board + + # Generate an ID for each cell occupied by the block + config.item_id["blocks"][f"{config.block_count}"][f"{n}"] = dpg.generate_uuid() + + # Make a list of the initial cells occupied by the blocks + config.cells_occupied.append([3 + n, 18]) + + # Draw the cell + dpg.draw_image(texture_tag=item_id["block_texture"]["T_block"], pmin=[3 + n, 19], pmax=[4 + n, 18], + parent=item_id["windows"]["tetris_board"], + id=config.item_id["blocks"][f"{config.block_count}"][f"{n}"]) + + # Draw the final cell on the top + # Generate an ID for the top cell occupied by the block + config.item_id["blocks"][f"{config.block_count}"]["3"] = dpg.generate_uuid() + # Add point to cells_occupied list + config.cells_occupied.append([4, 19]) + # Draw the cell + dpg.draw_image(texture_tag=item_id["block_texture"]["T_block"], pmin=[4, 20], pmax=[5, 19], + parent=item_id["windows"]["tetris_board"], + id=config.item_id["blocks"][f"{config.block_count}"]["3"]) + + # Update statistics + # Take the value shown, add 1 and set value + dpg.configure_item(item=item_id["displays"]["T_block_stat"], + text=int(dpg.get_item_configuration(item=item_id["displays"]["T_block_stat"])["text"]) + 1) + + dpg.set_value(item=item_id["displays"]["Total_block_stat"], + value=int(dpg.get_value(item=item_id["displays"]["Total_block_stat"])) + 1) + + + def move_blockDispatcher(self): + # Function creates a new thread that controls the continuous movement of the new blocks + move_block_thread = threading.Thread(name="move block", target=self.move_block, args=(), daemon=True) + move_block_thread.start() + + def move_block(self): + # Function controls the continuous downward movement of the blocks + config.block_moving_flag = 6 # Set to 6=TBlock. Block is moving + + while True: + for n in range(self.cells): + config.cells_occupied[-1 - n][1] -= 1 # Shift the Y Coordinate down by 1 unit + + if any(item in config.cells_occupied[-self.cells:] for item in config.cell_boundary) or \ + any(item in config.cells_occupied[-self.cells:] for item in config.cells_occupied[:-self.cells]): + # Check if any cells have touched the wall or other blocks. If so, stop the movement + for n in range(self.cells): + config.cells_occupied[-1 - n][1] += 1 # Reset the Y coordinate + config.block_moving_flag = 0 # Block has stopped moving + return + + for n in range(self.cells): + # Draw after all cells are updated + dpg.configure_item(item=config.item_id["blocks"][f"{config.block_count}"][f"{n}"], + pmin=[config.cells_occupied[-1 - n][0], config.cells_occupied[-1 - n][1] + 1], + pmax=[config.cells_occupied[-1 - n][0] + 1, config.cells_occupied[-1 - n][1]]) + + time.sleep(config.speed) # Wait at each cell + + +def draw_next_TBlock(): + for n in range(3): + # Loop draws the complete block on the "next" board + dpg.draw_image(texture_tag=item_id["block_texture"]["T_block"], pmin=[3 + n, 3], pmax=[4 + n, 2], + parent=item_id["windows"]["next_block_board"]) + + # Draw the final cell on the top + # Draw the cell + dpg.draw_image(texture_tag=item_id["block_texture"]["T_block"], pmin=[4, 4], pmax=[5, 3], + parent=item_id["windows"]["next_block_board"]) + + +def draw_statistics_TBlock(): + for n in range(3): + # Loop draws the bottom of the complete block on the board + dpg.draw_image(texture_tag=item_id["block_texture"]["T_block"], pmin=[1 + n, 13], pmax=[2 + n, 12], + parent=item_id["windows"]["statistics_window"]) + + # Draw the final cell on the top + # Draw the cell + dpg.draw_image(texture_tag=item_id["block_texture"]["T_block"], pmin=[2, 14], pmax=[3, 13], + parent=item_id["windows"]["statistics_window"]) + + dpg.draw_line(p1=[6.5, 13], p2=[7.5, 13], thickness=0.1, color=[168, 168, 168], + parent=item_id["windows"]["statistics_window"]) + + dpg.draw_text(pos=[8.5, 13.3], text="0", size=0.5, color=[168, 168, 168], + id=item_id["displays"]["T_block_stat"]) diff --git a/tetrominos_handler/ZBlock.py b/tetrominos_handler/ZBlock.py new file mode 100644 index 0000000..95c7fea --- /dev/null +++ b/tetrominos_handler/ZBlock.py @@ -0,0 +1,103 @@ +import time +import threading +import config +from config import * + + +class ZBlock: + def __init__(self): + self.cells = 4 # Number of cells occupied by the block + config.block_count += 1 + config.item_id["blocks"][f"{config.block_count}"] = {} # Add a new key to dictionary to add block IDs + + for n in range(self.cells - 2): + # Loop draws the bottom cells of the block on the top of the board + + # Generate an ID for each cell occupied by the block + config.item_id["blocks"][f"{config.block_count}"][f"{n}"] = dpg.generate_uuid() + + # Make a list of the initial cells occupied by the blocks + config.cells_occupied.append([3 + n, 19]) + + # Draw the cell + dpg.draw_image(texture_tag=item_id["block_texture"]["Z_block"], pmin=[3 + n, 20], pmax=[4 + n, 19], + parent=item_id["windows"]["tetris_board"], + id=config.item_id["blocks"][f"{config.block_count}"][f"{n}"]) + + for n in range(self.cells - 2): + # Draw the final cells on the top + # Generate an ID for the top cell occupied by the block + config.item_id["blocks"][f"{config.block_count}"][f"{n + 2}"] = dpg.generate_uuid() + # Add point to cells_occupied list + config.cells_occupied.append([4 + n, 18]) + # Draw the cell + dpg.draw_image(texture_tag=item_id["block_texture"]["Z_block"], pmin=[4 + n, 19], pmax=[5 + n, 18], + parent=item_id["windows"]["tetris_board"], + id=config.item_id["blocks"][f"{config.block_count}"][f"{n + 2}"]) + + # Update statistics + # Take the value shown, add 1 and set value + dpg.configure_item(item=item_id["displays"]["Z_block_stat"], + text=int(dpg.get_item_configuration(item=item_id["displays"]["Z_block_stat"])["text"]) + 1) + + dpg.set_value(item=item_id["displays"]["Total_block_stat"], + value=int(dpg.get_value(item=item_id["displays"]["Total_block_stat"])) + 1) + + def move_blockDispatcher(self): + # Function creates a new thread that controls the continuous movement of the new blocks + move_block_thread = threading.Thread(name="move block", target=self.move_block, args=(), daemon=True) + move_block_thread.start() + + def move_block(self): + # Function controls the continuous downward movement of the blocks + config.block_moving_flag = 7 # Set to 5=SBlock. Block is moving + + while True: + for n in range(self.cells): + config.cells_occupied[-1 - n][1] -= 1 # Shift the Y Coordinate down by 1 unit + + if any(item in config.cells_occupied[-self.cells:] for item in config.cell_boundary) or \ + any(item in config.cells_occupied[-self.cells:] for item in config.cells_occupied[:-self.cells]): + # Check if any cells have touched the wall or other blocks. If so, stop the movement + for n in range(self.cells): + config.cells_occupied[-1 - n][1] += 1 # Reset the Y coordinate + config.block_moving_flag = 0 # Block has stopped moving + return + + for n in range(self.cells): + # Draw after all cells are updated + dpg.configure_item(item=config.item_id["blocks"][f"{config.block_count}"][f"{n}"], + pmin=[config.cells_occupied[-1 - n][0], config.cells_occupied[-1 - n][1] + 1], + pmax=[config.cells_occupied[-1 - n][0] + 1, config.cells_occupied[-1 - n][1]]) + + time.sleep(config.speed) # Wait at each cell + + +def draw_next_ZBlock(): + for n in range(2): + # Loop draws the bottom layer of the complete block on the "next" board + dpg.draw_image(texture_tag=item_id["block_texture"]["Z_block"], pmin=[4 + n, 3], pmax=[5 + n, 2], + parent=item_id["windows"]["next_block_board"]) + + for n in range(2): + # Loop draws the top layer of the complete block on the "next" board + dpg.draw_image(texture_tag=item_id["block_texture"]["Z_block"], pmin=[3 + n, 4], pmax=[4 + n, 3], + parent=item_id["windows"]["next_block_board"]) + + +def draw_statistics_ZBlock(): + for n in range(2): + # Loop draws the bottom layer of the complete block on the "next" board + dpg.draw_image(texture_tag=item_id["block_texture"]["Z_block"], pmin=[1 + n, 8], pmax=[2 + n, 7], + parent=item_id["windows"]["statistics_window"]) + + for n in range(2): + # Loop draws the top layer of the complete block on the "next" board + dpg.draw_image(texture_tag=item_id["block_texture"]["Z_block"], pmin=[2 + n, 7], pmax=[3 + n, 6], + parent=item_id["windows"]["statistics_window"]) + + dpg.draw_line(p1=[6.5, 7], p2=[7.5, 7], thickness=0.1, color=[168, 168, 168], + parent=item_id["windows"]["statistics_window"]) + + dpg.draw_text(pos=[8.5, 7.3], text="0", size=0.5, color=[168, 168, 168], + id=item_id["displays"]["Z_block_stat"]) diff --git a/tetrominos_handler/__init__.py b/tetrominos_handler/__init__.py new file mode 100644 index 0000000..5e03b3d --- /dev/null +++ b/tetrominos_handler/__init__.py @@ -0,0 +1,8 @@ +from tetrominos_handler.tetrominosAPI import * +from tetrominos_handler.IBlock import * +from tetrominos_handler.JBlock import * +from tetrominos_handler.LBlock import * +from tetrominos_handler.OBlock import * +from tetrominos_handler.SBlock import * +from tetrominos_handler.TBlock import * +from tetrominos_handler.ZBlock import * diff --git a/tetrominos_handler/__pycache__/IBlock.cpython-310.pyc b/tetrominos_handler/__pycache__/IBlock.cpython-310.pyc new file mode 100644 index 0000000..177a034 Binary files /dev/null and b/tetrominos_handler/__pycache__/IBlock.cpython-310.pyc differ diff --git a/tetrominos_handler/__pycache__/JBlock.cpython-310.pyc b/tetrominos_handler/__pycache__/JBlock.cpython-310.pyc new file mode 100644 index 0000000..7fc292b Binary files /dev/null and b/tetrominos_handler/__pycache__/JBlock.cpython-310.pyc differ diff --git a/tetrominos_handler/__pycache__/LBlock.cpython-310.pyc b/tetrominos_handler/__pycache__/LBlock.cpython-310.pyc new file mode 100644 index 0000000..d939d5d Binary files /dev/null and b/tetrominos_handler/__pycache__/LBlock.cpython-310.pyc differ diff --git a/tetrominos_handler/__pycache__/OBlock.cpython-310.pyc b/tetrominos_handler/__pycache__/OBlock.cpython-310.pyc new file mode 100644 index 0000000..e440929 Binary files /dev/null and b/tetrominos_handler/__pycache__/OBlock.cpython-310.pyc differ diff --git a/tetrominos_handler/__pycache__/SBlock.cpython-310.pyc b/tetrominos_handler/__pycache__/SBlock.cpython-310.pyc new file mode 100644 index 0000000..5ab6c8f Binary files /dev/null and b/tetrominos_handler/__pycache__/SBlock.cpython-310.pyc differ diff --git a/tetrominos_handler/__pycache__/TBlock.cpython-310.pyc b/tetrominos_handler/__pycache__/TBlock.cpython-310.pyc new file mode 100644 index 0000000..66219c5 Binary files /dev/null and b/tetrominos_handler/__pycache__/TBlock.cpython-310.pyc differ diff --git a/tetrominos_handler/__pycache__/ZBlock.cpython-310.pyc b/tetrominos_handler/__pycache__/ZBlock.cpython-310.pyc new file mode 100644 index 0000000..2effbbe Binary files /dev/null and b/tetrominos_handler/__pycache__/ZBlock.cpython-310.pyc differ diff --git a/tetrominos_handler/__pycache__/__init__.cpython-310.pyc b/tetrominos_handler/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000..08ce687 Binary files /dev/null and b/tetrominos_handler/__pycache__/__init__.cpython-310.pyc differ diff --git a/tetrominos_handler/__pycache__/tetrominosAPI.cpython-310.pyc b/tetrominos_handler/__pycache__/tetrominosAPI.cpython-310.pyc new file mode 100644 index 0000000..813aed6 Binary files /dev/null and b/tetrominos_handler/__pycache__/tetrominosAPI.cpython-310.pyc differ diff --git a/tetrominos_handler/tetrominosAPI.py b/tetrominos_handler/tetrominosAPI.py new file mode 100644 index 0000000..d0bcdf7 --- /dev/null +++ b/tetrominos_handler/tetrominosAPI.py @@ -0,0 +1,336 @@ +# All settings required for tetris blocks (aka tetrominos) +import time +import threading +import math +import random +from playsound import playsound +import pandas as pd +import os +import config +from theme_settings import * +from config import * +import tetrominos_handler + + +# Load and add all block textures +with dpg.texture_registry(tag=item_id["registries"]["texture_registry"]): + # Start a texture registry. Textures will be added later + pass + +for block in block_names: + # Extract data from images and add static textures for each cell of a block + width, height, channels, data = dpg.load_image(f"textures/{block}-block.jpg") + + dpg.add_static_texture(width, height, data, tag=item_id["block_texture"][f"{block}_block"], + parent=item_id["registries"]["texture_registry"]) + + +def get_distance_between_points(point1: list, point2: list): + # Calculates the distance between two points + return math.sqrt(math.pow((point2[0] - point1[0]), 2) + math.pow((point2[1] - point1[1]), 2)) + + +# Set up the class for each tetris blocks +def rotate_block(cells: int, rotation_point: int): + # Function rotates the block 90 degrees clockwise when called + rotation_point = config.cells_occupied[-rotation_point] + temp_point = [] + new_point = [] + + for n in range(cells): + radius = get_distance_between_points(config.cells_occupied[-1 - n], rotation_point) + + # Shift the origin to the rotation point and calculate the angle of points + if config.cells_occupied[-1 - n][1] - rotation_point[1] >= 0: # If point is above the rotation point + x = rotation_point[0] - config.cells_occupied[-1 - n][0] + y = config.cells_occupied[-1 - n][1] - rotation_point[1] + temp_point.append([x, y]) + angle_of_rotation = math.degrees(math.atan2(temp_point[-1][1], temp_point[-1][0])) + temp_point[-1][0] = -1*temp_point[-1][0] + + else: # If the point is below the rotation point + x = config.cells_occupied[-1 - n][0] - rotation_point[0] + y = config.cells_occupied[-1 - n][1] - rotation_point[1] + temp_point.append([x, y]) + angle_of_rotation = - math.degrees(math.atan2(temp_point[-1][1], temp_point[-1][0])) + 180 + + x = round(radius*math.sin(math.radians(angle_of_rotation))) + y = round(radius*math.cos(math.radians(angle_of_rotation))) + new_point.append([x, y]) + config.cells_occupied[-1 - n][0] += (new_point[-1][0] - temp_point[-1][0]) + config.cells_occupied[-1 - n][1] += (new_point[-1][1] - temp_point[-1][1]) + + if any(item in config.cells_occupied[-cells:] for item in config.cell_boundary) or \ + any(item in config.cells_occupied[-cells:] for item in config.cells_occupied[:-cells]): + # If any of the cells updated above, are found to be clashing with the walls or other blocks, reset the + # cells occupied list and return. Do NOT move the block further + for n in range(cells): + config.cells_occupied[-1 - n][0] -= (new_point[n][0] - temp_point[n][0]) + config.cells_occupied[-1 - n][1] -= (new_point[n][1] - temp_point[n][1]) + return + + for n in range(cells): + dpg.configure_item(item=config.item_id["blocks"][f"{config.block_count}"][f"{n}"], + pmin=[config.cells_occupied[-1 - n][0], config.cells_occupied[-1 - n][1] + 1], + pmax=[config.cells_occupied[-1 - n][0] + 1, config.cells_occupied[-1 - n][1]]) + + +def audio_effectsDispatcher(file_name): + # Function creates a new thread that runs the audio file so that the main code does not lag or interfere + play_audio_thread = threading.Thread(name="play audio", target=play_audio_effect, args=(file_name,), daemon=True) + play_audio_thread.start() + + +def play_audio_effect(file_name): + playsound(os.path.abspath(os.path.abspath("tetris_game.py")[:-14]) + "\\sounds\\" + file_name) + + +def create_blocksDispatcher(): + # Function creates a new thread that controls the continuous movement of the new blocks + dpg.add_handler_registry(tag=item_id["registries"]["mouse_release_handler"]) + dpg.add_key_press_handler(callback=tetrominos_handler.key_release_handler, + parent=item_id["registries"]["mouse_release_handler"]) + dpg.configure_item(item=item_id["buttons"]["play_button"], enabled=False) + dpg.bind_item_theme(item=item_id["buttons"]["play_button"], theme=play_button_theme) + + create_blocks_thread = threading.Thread(name="create blocks", target=create_blocks, args=(), daemon=True) + create_blocks_thread.start() + + +def create_blocks(): + # Play audio effect to indicate selection + tetrominos_handler.audio_effectsDispatcher("selection.wav") + + # Set up the speed for level chosen by the user + # CSV file contains speed to reach the bottom of the board, i.e. to cross 20 cells. Divide the speed by 20 to get + # time per each cell + block_speeds_data = pd.read_csv("block_speeds_data.csv") + config.speed = (block_speeds_data.values[config.level][1]) / 20 + + random_blocks = [random.randint(0, 6), random.randint(0, 6)] + temp_block = eval(f"tetrominos_handler.{block_names[random_blocks[0]]}Block()") + + dpg.delete_item(item=item_id["windows"]["next_block_board"], children_only=True) + eval(f"tetrominos_handler.draw_next_{block_names[random_blocks[1]]}Block()") + + time.sleep(config.speed) + temp_block.move_blockDispatcher() + + # If any of the blocks occupy these cells, then the game ends + top_cells = [[3, 19], [4, 19], [5, 19], [6, 19], [3, 18], [4, 18], [5, 18], [6, 18]] + + while True: # Check if top cells are occupied + if config.block_moving_flag == 0: + + if any(item in config.cells_occupied for item in top_cells): + break + + random_blocks.pop(0) + random_blocks.append(random.randint(0, 6)) + check_complete_line() + temp_block = eval(f"tetrominos_handler.{block_names[random_blocks[0]]}Block()") + + dpg.delete_item(item=item_id["windows"]["next_block_board"], children_only=True) + eval(f"tetrominos_handler.draw_next_{block_names[random_blocks[1]]}Block()") + + time.sleep(config.speed) + temp_block.move_blockDispatcher() + + # Fade the board by placing a semi-transparent rectangle + dpg.draw_rectangle(pmin=[0,0], pmax=[10, 20], color=[0, 0, 0, 150], thickness=0, + fill=[0, 0, 0, 150], parent=item_id["windows"]["tetris_board"]) + + # Show GAME OVER text on the board + dpg.draw_text(pos=[0.5, 11], text="GAME OVER", size=1, parent=item_id["windows"]["tetris_board"]) + + # Play the game over tune + audio_effectsDispatcher("gameover.wav") + + +def check_complete_line(): + # Function checks every horizontal line to see if a complete row has been filled. If so, the line disappears + + row = 0 + lines_completed = 0 # Total lines completed together (max 4 using I block) + + while row < 20: + cell_count = 0 # Count the number of cells occupied in the given row. If equals 10, then line is complete + for point in config.cells_occupied: + if point[1] == row: + cell_count += 1 + + if cell_count == 10: + # Increase complete lines in one-go + lines_completed += 1 + # Increase full lines text display + config.full_lines += 1 + dpg.set_value(item=item_id["displays"]["full_line_text"], value=config.full_lines) + + # Check if level up is needed using the number of full lines completed + if min((config.level*10 + 10), (max(100, (config.level*10 - 50)))) == config.full_lines: + config.level += 1 + dpg.set_value(item=item_id["displays"]["level_text"], value=config.level) + + # Speed up to match the speed for the corresponding level + block_speeds_data = pd.read_csv("block_speeds_data.csv") + config.speed = (block_speeds_data.values[config.level][1]) / 20 + + # Play audio effect + audio_effectsDispatcher("success.wav") + + block_cells = [] + + for block in config.item_id["blocks"].keys(): + for cell in config.item_id["blocks"][block].keys(): + cell_id = config.item_id["blocks"][block][cell] + cell_number = dpg.get_item_configuration(item=cell_id)["pmax"] + + if cell_number[1] == row: + dpg.delete_item(item=cell_id) + block_cells.append([block, cell]) + config.cells_occupied.remove([cell_number[0] - 1, cell_number[1]]) + + audio_effectsDispatcher("line.wav") + + for pair in block_cells: + del config.item_id["blocks"][pair[0]][pair[1]] + + time.sleep(0.1) + + for block in config.item_id["blocks"].keys(): + for cell in config.item_id["blocks"][block].keys(): + cell_id = config.item_id["blocks"][block][cell] + cell_number = dpg.get_item_configuration(item=cell_id)["pmax"] + cell_number[0] -= 1 + + if cell_number[1] > row: + cells_occupied_index = config.cells_occupied.index([cell_number[0], cell_number[1]]) + config.cells_occupied[cells_occupied_index][1] -= 1 + cell_number[1] -= 1 + + dpg.configure_item(item=cell_id, + pmin=[cell_number[0], cell_number[1] + 1], + pmax=[cell_number[0] + 1, cell_number[1]]) + time.sleep(0.1) + + else: + row += 1 + + if lines_completed == 1: + config.score += 40*(config.level + 1) + + elif lines_completed == 2: + config.score += 100*(config.level + 1) + + elif lines_completed == 3: + config.score += 300*(config.level + 1) + + elif lines_completed == 4: + config.score += 1200*(config.level + 1) + + dpg.set_value(item=item_id["displays"]["score_text"], value=config.score) + + +def key_release_handler(sender, app_data): + if config.block_moving_flag != 0: + cells = 0 # Number of cells occupied by the moving block + rotation_cell = 0 # Cell about which the block will rotate + + if config.block_moving_flag == 1: + cells = 4 # I Block occupies 4 cells + rotation_cell = 2 # Second from the right in the list of points + + if config.block_moving_flag == 2: + cells = 4 # J Block occupies 4 cells + rotation_cell = 3 # Third from the right in the list of points + + if config.block_moving_flag == 3: + cells = 4 # J Block occupies 4 cells + rotation_cell = 3 # Third from the right in the list of points + + if config.block_moving_flag == 4: + cells = 4 # O Block occupies 4 cells + rotation_cell = 0 # Set to 0 because no rotation + + if config.block_moving_flag == 5: + cells = 4 # S Block occupies 4 cells + rotation_cell = 3 + + if config.block_moving_flag == 6: + cells = 4 # T Block occupies 4 cells + rotation_cell = 3 + + if config.block_moving_flag == 7: + cells = 4 # Z Block occupies 4 cells + rotation_cell = 2 + + if app_data == 38: + if config.block_moving_flag == 4: # Do NOT rotate O-Block + return + rotate_block(cells, rotation_cell) + return + + if app_data == 32: + # Hard drop block + cells_dropped = 0 # Count of number of cells the block dropped. Used to calculate the score + + while True: + # Loop and move Y coordinate down until we hit another block or the bottom wall + for n in range(cells): + config.cells_occupied[-1 - n][1] -= 1 # Shift the Y Coordinate down by 1 unit + + if any(item in config.cells_occupied[-cells:] for item in config.cell_boundary) or \ + any(item in config.cells_occupied[-cells:] for item in config.cells_occupied[:-cells]): + # If any of the cells updated above, are found to be clashing with the walls or other blocks, + # reset the cells occupied list and return. Do NOT move the block further + for n in range(cells): + config.cells_occupied[-1 - n][1] += 1 + break + + cells_dropped += 1 + + for n in range(cells): + # Finally when the block hits another block or bottom, draw and show the block + dpg.configure_item(item=config.item_id["blocks"][f"{config.block_count}"][f"{n}"], + pmin=[config.cells_occupied[-1 - n][0], config.cells_occupied[-1 - n][1] + 1], + pmax=[config.cells_occupied[-1 - n][0] + 1, config.cells_occupied[-1 - n][1]]) + + # Update the score accordingly + config.score += cells_dropped*2 + dpg.set_value(item=item_id["displays"]["score_text"], value=config.score) + + audio_effectsDispatcher("fall.wav") + + for n in range(cells): + if app_data == 37: # Move left + config.cells_occupied[-1 - n][0] -= 1 # Shift the X Coordinate left by 1 unit + + elif app_data == 39: # Move right + config.cells_occupied[-1 - n][0] += 1 # Shift the X Coordinate right by 1 unit + + elif app_data == 40: # Soft drop (Accelerate down) + config.cells_occupied[-1 - n][1] -= 1 # Shift the Y Coordinate down by 1 unit + + if any(item in config.cells_occupied[-cells:] for item in config.cell_boundary) or \ + any(item in config.cells_occupied[-cells:] for item in config.cells_occupied[:-cells]): + # If any of the cells updated above, are found to be clashing with the walls or other blocks, reset the + # cells occupied list and return. Do NOT move the block further + for n in range(cells): + if app_data == 37: + config.cells_occupied[-1 - n][0] += 1 + elif app_data == 39: + config.cells_occupied[-1 - n][0] -= 1 + elif app_data == 40: + config.cells_occupied[-1 - n][1] += 1 + return + + for n in range(cells): + dpg.configure_item(item=config.item_id["blocks"][f"{config.block_count}"][f"{n}"], + pmin=[config.cells_occupied[-1 - n][0], config.cells_occupied[-1 - n][1] + 1], + pmax=[config.cells_occupied[-1 - n][0] + 1, config.cells_occupied[-1 - n][1]]) + + # Check if soft drop was successfully completed and add to scoring points and play audio effect + if app_data == 40: + config.score += 1 + dpg.set_value(item=item_id["displays"]["score_text"], value=config.score) + audio_effectsDispatcher("fall.wav") diff --git a/textures/I-block.jpg b/textures/I-block.jpg new file mode 100644 index 0000000..e2def1f Binary files /dev/null and b/textures/I-block.jpg differ diff --git a/textures/J-block.jpg b/textures/J-block.jpg new file mode 100644 index 0000000..e2ce0e1 Binary files /dev/null and b/textures/J-block.jpg differ diff --git a/textures/L-block.jpg b/textures/L-block.jpg new file mode 100644 index 0000000..90b18d0 Binary files /dev/null and b/textures/L-block.jpg differ diff --git a/textures/O-block.jpg b/textures/O-block.jpg new file mode 100644 index 0000000..16922ca Binary files /dev/null and b/textures/O-block.jpg differ diff --git a/textures/S-block.jpg b/textures/S-block.jpg new file mode 100644 index 0000000..228ab7d Binary files /dev/null and b/textures/S-block.jpg differ diff --git a/textures/T-block.jpg b/textures/T-block.jpg new file mode 100644 index 0000000..9723a4a Binary files /dev/null and b/textures/T-block.jpg differ diff --git a/textures/Z-block.jpg b/textures/Z-block.jpg new file mode 100644 index 0000000..e43b612 Binary files /dev/null and b/textures/Z-block.jpg differ diff --git a/textures/welcome_screen.jpg b/textures/welcome_screen.jpg new file mode 100644 index 0000000..f7bbafd Binary files /dev/null and b/textures/welcome_screen.jpg differ diff --git a/theme_settings/__init__.py b/theme_settings/__init__.py new file mode 100644 index 0000000..09b8ff4 --- /dev/null +++ b/theme_settings/__init__.py @@ -0,0 +1,2 @@ +from theme_settings.font_registry import * +from theme_settings.theme_registry import * diff --git a/theme_settings/__pycache__/__init__.cpython-310.pyc b/theme_settings/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000..bb4a0f3 Binary files /dev/null and b/theme_settings/__pycache__/__init__.cpython-310.pyc differ diff --git a/theme_settings/__pycache__/font_registry.cpython-310.pyc b/theme_settings/__pycache__/font_registry.cpython-310.pyc new file mode 100644 index 0000000..8f00a6e Binary files /dev/null and b/theme_settings/__pycache__/font_registry.cpython-310.pyc differ diff --git a/theme_settings/__pycache__/theme_registry.cpython-310.pyc b/theme_settings/__pycache__/theme_registry.cpython-310.pyc new file mode 100644 index 0000000..bfaa827 Binary files /dev/null and b/theme_settings/__pycache__/theme_registry.cpython-310.pyc differ diff --git a/theme_settings/font_registry.py b/theme_settings/font_registry.py new file mode 100644 index 0000000..d8e9a17 --- /dev/null +++ b/theme_settings/font_registry.py @@ -0,0 +1,6 @@ +# Add all fonts +import dearpygui.dearpygui as dpg + +with dpg.font_registry() as main_font_registry: + regular_font = dpg.add_font('fonts/PressStart2P-vaV7.ttf', 15) + play_font = dpg.add_font('fonts/PressStart2P-vaV7.ttf', 18) diff --git a/theme_settings/theme_registry.py b/theme_settings/theme_registry.py new file mode 100644 index 0000000..44cd0da --- /dev/null +++ b/theme_settings/theme_registry.py @@ -0,0 +1,49 @@ +# Set up themes +import dearpygui.dearpygui as dpg + +with dpg.theme() as global_theme: # Sets up the default theme + with dpg.theme_component(dpg.mvAll): + # Styles + dpg.add_theme_style(dpg.mvStyleVar_WindowPadding, 4, 4, category=dpg.mvThemeCat_Core) + dpg.add_theme_style(dpg.mvStyleVar_FramePadding, 8, 8, category=dpg.mvThemeCat_Core) + dpg.add_theme_style(dpg.mvStyleVar_ItemSpacing, 4, 4, category=dpg.mvThemeCat_Core) + dpg.add_theme_style(dpg.mvStyleVar_ChildRounding, 4, 4, category=dpg.mvThemeCat_Core) + dpg.add_theme_style(dpg.mvStyleVar_FrameRounding, 4, 4, category=dpg.mvThemeCat_Core) + dpg.add_theme_style(dpg.mvStyleVar_ChildBorderSize, 0, category=dpg.mvThemeCat_Core) + + # Colors + dpg.add_theme_color(dpg.mvThemeCol_WindowBg, (0, 0, 0), category=dpg.mvThemeCat_Core) + dpg.add_theme_color(dpg.mvThemeCol_FrameBg, (0, 0, 0), category=dpg.mvThemeCat_Core) + dpg.add_theme_color(dpg.mvThemeCol_PopupBg, (0, 0, 0), category=dpg.mvThemeCat_Core) + dpg.add_theme_color(dpg.mvThemeCol_ChildBg, (0, 0, 0), category=dpg.mvThemeCat_Core) + dpg.add_theme_color(dpg.mvThemeCol_MenuBarBg, (48, 48, 48), category=dpg.mvThemeCat_Core) + dpg.add_theme_color(dpg.mvThemeCol_Text, (168, 168, 168), category=dpg.mvThemeCat_Core) + dpg.add_theme_color(dpg.mvThemeCol_Button, (0, 0, 0), category=dpg.mvThemeCat_Core) + dpg.add_theme_color(dpg.mvThemeCol_ButtonHovered, (33, 33, 33), category=dpg.mvThemeCat_Core) + dpg.add_theme_color(dpg.mvThemeCol_ButtonActive, (33, 33, 33), category=dpg.mvThemeCat_Core) + dpg.add_theme_color(dpg.mvPlotCol_PlotBg, (0, 0, 0), category=dpg.mvThemeCat_Plots) + dpg.add_theme_color(dpg.mvPlotCol_XAxisGrid, (30, 30, 255), category=dpg.mvThemeCat_Plots) + dpg.add_theme_color(dpg.mvPlotCol_YAxisGrid, (30, 30, 255), category=dpg.mvThemeCat_Plots) + dpg.add_theme_color(dpg.mvPlotCol_Line, (0, 0, 255), category=dpg.mvThemeCat_Plots) + dpg.add_theme_color(dpg.mvPlotCol_FrameBg, (0, 0, 0), category=dpg.mvThemeCat_Plots) + dpg.add_theme_color(dpg.mvPlotCol_PlotBorder, (30, 30, 255), category=dpg.mvThemeCat_Plots) + +with dpg.theme() as dummy_button_theme: + with dpg.theme_component(dpg.mvAll): + # Styles + # Colors + dpg.add_theme_color(dpg.mvThemeCol_Button, (0, 0, 0), category=dpg.mvThemeCat_Core) + dpg.add_theme_color(dpg.mvThemeCol_ButtonHovered, (0, 0, 0), category=dpg.mvThemeCat_Core) + dpg.add_theme_color(dpg.mvThemeCol_ButtonActive, (0, 0, 0), category=dpg.mvThemeCat_Core) + +with dpg.theme() as play_button_theme: + with dpg.theme_component(dpg.mvAll): + # Styles + # Colors + dpg.add_theme_color(dpg.mvThemeCol_Text, (161, 94, 33), category=dpg.mvThemeCat_Core) + +with dpg.theme() as no_border_board_theme: + with dpg.theme_component(dpg.mvAll): + # Styles + # Colors + dpg.add_theme_color(dpg.mvPlotCol_PlotBorder, (0, 0, 0), category=dpg.mvThemeCat_Plots)