Introduction
"Hey! Don't sleep, wake up! It's time to work ~"
by - Gu Muzi!
"Just woke up, boss, what can I do for you?"
by - all members!
Have you had a thorough understanding of the super detailed - simple version of 2048 shared with you in the last issue? Cough... It doesn't matter if you haven't eaten it thoroughly!
Take your time, mumuzi has been waiting for you to rise ~ ha ha, ha ha, Na ~ now this article is an upgraded version of 2048 game promised last time.
What about the previous one? Any difference?
Of course, it's very different. Today, I teach you to write this small program with interface. This point with interface alone can surpass the previous one. It's more interesting. Let's have a look!
text
Environmental installation:
Python 3, pycharm, Pygame modules, etc.
pip install -i https://pypi.douban.com/simple/ pygame
Profile:
Music, background, font, etc.
import os '''FPS''' FPS = 60 '''background color ''' BG_COLOR = '#D3D3D3' '''Screen size''' SCREENSIZE = (650, 370) '''Save the current highest score file''' MAX_SCORE_FILEPATH = 'score' '''Font path''' FONTPATH = os.path.join(os.getcwd(), 'resources/font/Gabriola.ttf') '''Background music path''' BGMPATH = os.path.join(os.getcwd(), 'resources/audio/bgm.mp3') '''Other necessary constants''' MARGIN_SIZE = 10 BLOCK_SIZE = 80 GAME_MATRIX_SIZE = (4, 4)
Define 2048 Games:
class Game2048(object): def __init__(self, matrix_size=(4, 4), max_score_filepath=None, **kwargs): # matrix_size: (num_rows, num_cols) self.matrix_size = matrix_size # Save path of the highest score of the game self.max_score_filepath = max_score_filepath # initialization self.initialize() '''Update game status''' def update(self): game_matrix_before = copy.deepcopy(self.game_matrix) self.move() if game_matrix_before != self.game_matrix: self.randomGenerateNumber() if self.score > self.max_score: self.max_score = self.score '''According to the specified direction, Move all blocks''' def move(self): # Extract non empty number def extract(array): array_new = [] for item in array: if item != 'null': array_new.append(item) return array_new # Merge non empty numbers def merge(array): score = 0 if len(array) < 2: return array, score for i in range(len(array)-1): if array[i] == 'null': break if array[i] == array[i+1]: array[i] *= 2 array.pop(i+1) array.append('null') score += array[i] return extract(array), score # return if you don't need to move if self.move_direction is None: return # Up if self.move_direction == 'up': for j in range(self.matrix_size[1]): col = [] for i in range(self.matrix_size[0]): col.append(self.game_matrix[i][j]) col = extract(col) col.reverse() col, score = merge(col) self.score += score col.reverse() col = col + ['null',] * (self.matrix_size[0] - len(col)) for i in range(self.matrix_size[0]): self.game_matrix[i][j] = col[i] # down elif self.move_direction == 'down': for j in range(self.matrix_size[1]): col = [] for i in range(self.matrix_size[0]): col.append(self.game_matrix[i][j]) col = extract(col) col, score = merge(col) self.score += score col = ['null',] * (self.matrix_size[0] - len(col)) + col for i in range(self.matrix_size[0]): self.game_matrix[i][j] = col[i] # towards the left elif self.move_direction == 'left': for idx, row in enumerate(copy.deepcopy(self.game_matrix)): row = extract(row) row.reverse() row, score = merge(row) self.score += score row.reverse() row = row + ['null',] * (self.matrix_size[1] - len(row)) self.game_matrix[idx] = row # towards the right elif self.move_direction == 'right': for idx, row in enumerate(copy.deepcopy(self.game_matrix)): row = extract(row) row, score = merge(row) self.score += score row = ['null',] * (self.matrix_size[1] - len(row)) + row self.game_matrix[idx] = row self.move_direction = None '''Randomly generate numbers in new locations''' def randomGenerateNumber(self): empty_pos = [] for i in range(self.matrix_size[0]): for j in range(self.matrix_size[1]): if self.game_matrix[i][j] == 'null': empty_pos.append([i, j]) i, j = random.choice(empty_pos) self.game_matrix[i][j] = 2 if random.random() > 0.1 else 4 '''initialization''' def initialize(self): self.game_matrix = [['null' for _ in range(self.matrix_size[1])] for _ in range(self.matrix_size[0])] self.score = 0 self.max_score = self.readMaxScore() self.move_direction = None self.randomGenerateNumber() self.randomGenerateNumber() '''Set direction of movement''' def setDirection(self, direction): assert direction in ['up', 'down', 'left', 'right'] self.move_direction = direction '''Save highest score''' def saveMaxScore(self): f = open(self.max_score_filepath, 'w', encoding='utf-8') f.write(str(self.max_score)) f.close() '''Read the highest score of the game''' def readMaxScore(self): try: f = open(self.max_score_filepath, 'r', encoding='utf-8') score = int(f.read().strip()) f.close() return score except: return 0 '''Is the game over''' @property def isgameover(self): for i in range(self.matrix_size[0]): for j in range(self.matrix_size[1]): if self.game_matrix[i][j] == 'null': return False if (i == self.matrix_size[0] - 1) and (j == self.matrix_size[1] - 1): continue elif (i == self.matrix_size[0] - 1): if (self.game_matrix[i][j] == self.game_matrix[i][j+1]): return False elif (j == self.matrix_size[1] - 1): if (self.game_matrix[i][j] == self.game_matrix[i+1][j]): return False else: if (self.game_matrix[i][j] == self.game_matrix[i+1][j]) or (self.game_matrix[i][j] == self.game_matrix[i][j+1]): return False return True
Then set different colors.
Different numbers 2-4-8 and so on are combined into different numbers, and the color changes accordingly.
Color display:
'''obtain [grid background color, font color in the grid]' 'according to the current score of the grid'
def getColorByNumber(number): number2color_dict = { 2: ['#eee4da', '#776e65'], 4: ['#ede0c8', '#776e65'], 8: ['#f2b179', '#f9f6f2'], 16: ['#f59563', '#f9f6f2'], 32: ['#f67c5f', '#f9f6f2'], 64: ['#f65e3b', '#f9f6f2'], 128: ['#edcf72', '#f9f6f2'], 256: ['#edcc61', '#f9f6f2'], 512: ['#edc850', '#f9f6f2'], 1024: ['#edc53f', '#f9f6f2'], 2048: ['#edc22e', '#f9f6f2'], 4096: ['#eee4da', '#776e65'], 8192: ['#edc22e', '#f9f6f2'], 16384: ['#f2b179', '#776e65'], 32768: ['#f59563', '#776e65'], 65536: ['#f67c5f', '#f9f6f2'], 'null': ['#9e948a', None] } return number2color_dict[number] '''Draw the current number arrangement of 2048 games to the screen''' def drawGameMatrix(screen, game_matrix, cfg): for i in range(len(game_matrix)): for j in range(len(game_matrix[i])): number = game_matrix[i][j] x = cfg.MARGIN_SIZE * (j + 1) + cfg.BLOCK_SIZE * j y = cfg.MARGIN_SIZE * (i + 1) + cfg.BLOCK_SIZE * i pygame.draw.rect(screen, pygame.Color(getColorByNumber(number)[0]), (x, y, cfg.BLOCK_SIZE, cfg.BLOCK_SIZE)) if number != 'null': font_color = pygame.Color(getColorByNumber(number)[1]) font_size = cfg.BLOCK_SIZE - 10 * len(str(number)) font = pygame.font.Font(cfg.FONTPATH, font_size) text = font.render(str(number), True, font_color) text_rect = text.get_rect() text_rect.centerx, text_rect.centery = x + cfg.BLOCK_SIZE / 2, y + cfg.BLOCK_SIZE / 2 screen.blit(text, text_rect)
Add additional elements to the game interface.
The following figure: introduction to playing methods and score display.
'''Draw the highest score and current score of the game to the screen''' def drawScore(screen, score, max_score, cfg): font_color = (255, 255, 255) font_size = 30 font = pygame.font.Font(cfg.FONTPATH, font_size) text_max_score = font.render('Best: %s' % max_score, True, font_color) text_score = font.render('Score: %s' % score, True, font_color) start_x = cfg.BLOCK_SIZE * cfg.GAME_MATRIX_SIZE[1] + cfg.MARGIN_SIZE * (cfg.GAME_MATRIX_SIZE[1] + 1) screen.blit(text_max_score, (start_x+10, 10)) screen.blit(text_score, (start_x+10, 20+text_score.get_rect().height)) start_y = 30 + text_score.get_rect().height + text_max_score.get_rect().height return (start_x, start_y) '''Game introduction''' def drawGameIntro(screen, start_x, start_y, cfg): start_y += 40 font_color = (0, 0, 0) font_size_big = 30 font_size_small = 20 font_big = pygame.font.Font(cfg.FONTPATH, font_size_big) font_small = pygame.font.Font(cfg.FONTPATH, font_size_small) intros = ['Game play:', ' Slide the keyboard up, down, left and right.', 'Combine two identical numbers', 'For example: 2 + 2 = 4, 4 + 4 = 8... Until 1024 + 1024 = 2048!', 'You win!'] for idx, intro in enumerate(intros): font = font_big if idx == 0 else font_small text = font.render(intro, True, font_color) screen.blit(text, (start_x+10, start_y)) start_y += text.get_rect().height + 10
Game end interface:
Attached source code:
def endInterface(screen, cfg): font_size_big = 60 font_size_small = 30 font_color = (255, 255, 255) font_big = pygame.font.Font(cfg.FONTPATH, font_size_big) font_small = pygame.font.Font(cfg.FONTPATH, font_size_small) surface = screen.convert_alpha() surface.fill((127, 255, 212, 2)) text = font_big.render('Game Over!', True, font_color) text_rect = text.get_rect() text_rect.centerx, text_rect.centery = cfg.SCREENSIZE[0]/2, cfg.SCREENSIZE[1]/2-50 surface.blit(text, text_rect) button_width, button_height = 100, 40 button_start_x_left = cfg.SCREENSIZE[0] / 2 - button_width - 20 button_start_x_right = cfg.SCREENSIZE[0] / 2 + 20 button_start_y = cfg.SCREENSIZE[1] / 2 - button_height / 2 + 20 pygame.draw.rect(surface, (0, 255, 255), (button_start_x_left, button_start_y, button_width, button_height)) text_restart = font_small.render('Restart', True, font_color) text_restart_rect = text_restart.get_rect() text_restart_rect.centerx, text_restart_rect.centery = button_start_x_left + button_width / 2, button_start_y + button_height / 2 surface.blit(text_restart, text_restart_rect) pygame.draw.rect(surface, (0, 255, 255), (button_start_x_right, button_start_y, button_width, button_height)) text_quit = font_small.render('Quit', True, font_color) text_quit_rect = text_quit.get_rect() text_quit_rect.centerx, text_quit_rect.centery = button_start_x_right + button_width / 2, button_start_y + button_height / 2 surface.blit(text_quit, text_quit_rect) while True: screen.blit(surface, (0, 0)) for event in pygame.event.get(): if event.type == pygame.QUIT: pygame.quit() sys.exit() elif event.type == pygame.MOUSEBUTTONDOWN and event.button: if text_quit_rect.collidepoint(pygame.mouse.get_pos()): return False if text_restart_rect.collidepoint(pygame.mouse.get_pos()): return True pygame.display.update()
Main program:
def main(cfg): # Game initialization pygame.init() screen = pygame.display.set_mode(cfg.SCREENSIZE) pygame.display.set_caption('2048 Small game upgrade') # Play background music pygame.mixer.music.load(cfg.BGMPATH) pygame.mixer.music.play(-1) # Instantiate 2048 games game_2048 = Game2048(matrix_size=cfg.GAME_MATRIX_SIZE, max_score_filepath=cfg.MAX_SCORE_FILEPATH) # Game main loop clock = pygame.time.Clock() is_running = True while is_running: screen.fill(pygame.Color(cfg.BG_COLOR)) # --Key detection for event in pygame.event.get(): if event.type == pygame.QUIT: pygame.quit() sys.exit() elif event.type == pygame.KEYDOWN: if event.key in [pygame.K_UP, pygame.K_DOWN, pygame.K_LEFT, pygame.K_RIGHT]: game_2048.setDirection({pygame.K_UP: 'up', pygame.K_DOWN: 'down', pygame.K_LEFT: 'left', pygame.K_RIGHT: 'right'}[event.key]) # --Update game status game_2048.update() if game_2048.isgameover: game_2048.saveMaxScore() is_running = False # --Draw the necessary game elements to the screen drawGameMatrix(screen, game_2048.game_matrix, cfg) start_x, start_y = drawScore(screen, game_2048.score, game_2048.max_score, cfg) drawGameIntro(screen, start_x, start_y, cfg) # --Screen update pygame.display.update() clock.tick(cfg.FPS) return endInterface(screen, cfg) '''run''' if __name__ == '__main__': while True: if not main(cfg): break
2048 game effect is shown in the figure below:
I wanted to cut a picture of 2048 for you, but it got stuck after playing for several times. You'll make do with it. BAM ~ I tried my best!
summary
All right! This upgraded 2048 game is over here. Come and try. Can you pass the customs?
Free source code collection office:
Your support is my biggest motivation!! Remember the third company ~mua Welcome to read previous articles~