2048小遊戲-pygame來實現.(借鑑網友代碼,僅供學習)
文件結構如下:
main.py代碼
# main.py
"""
功能:2048小遊戲
作者:指尖魔法師
QQ:14555110
"""
import pygame
from sys import exit
from modules.game2048 import *
from modules.utils import *
import cfg
from modules.endInterface import *
def main(cfg):
# 初始化pygame
pygame.init()
pygame.mixer.music.load(cfg.BGMPATH)
pygame.mixer.music.play(-1)
# 創建一個窗口
screen = pygame.display.set_mode(cfg.SCREENSIZE, 0, 32)
# 設置窗口標題
pygame.display.set_caption("2048小遊戲--作者:指尖魔法師 QQ:14555110")
# 實例化Game2048
game_2048 = Game2048(matrix_size=cfg.GAME_MATRIX_SIZE, max_score_filepath=cfg.MAX_SCORE_FILEPATH)
# 遊戲主循環
is_running = True
while is_running:
# 填充背景顏色
screen.fill(pygame.Color(cfg.BG_COLOR))
# 按鍵檢測
for event in pygame.event.get():
if event.type == pygame.QUIT:
# 接受到退出事件後退出
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])
# 更新遊戲狀態
game_2048.update()
if game_2048.isGameOver:
print('遊戲結束')
is_running = False
game_2048.saveMaxScore()
# 將元素畫到屏幕上
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)
# 刷新畫面
pygame.display.update()
# 遊戲結束界面
return endInterface(screen, cfg)
if __name__ =='__main__':
while True:
if not main(cfg):
break
cfg.py代碼
# cfg.py
"""
功能:配置文件
作者:指尖魔法師
QQ:14555110
"""
import os
# 屏幕大小
SCREENSIZE = (650, 370)
# 背景顏色
BG_COLOR = '#92877d'
# 背景音樂路徑
BGMPATH = 'resources/shaonian.mp3'
# 字體路徑
FONTPATH = os.path.join(os.getcwd(), 'resources/gabriola.ttf')
# 4 * 4 大小
GAME_MATRIX_SIZE = (4, 4)
# 方塊大小
MATRIX_SIZE = 80
# 方塊間間距
MARGIN_SIZE = 10
# 保存最高分文件路徑
MAX_SCORE_FILEPATH = 'score'
game2048.py代碼
# game2048.py
"""
功能:Game2048類
作者:指尖魔法師
QQ:14555110
"""
import pygame
import random
import copy
class Game2048(object):
def __init__(self, matrix_size=(4, 4), max_score_filepath=None):
self.matrix_size = matrix_size
# 遊戲最高分保存路徑
self.max_score_filepath = max_score_filepath
self.initialize()
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()
# 初始化時隨機2位數值
self.randomGenerateNumber()
self.randomGenerateNumber()
# 當前所有位置的數值
print(self.game_matrix)
self.move_direction = None
def update(self):
"""更新遊戲狀態"""
self.game_matrix_before = copy.deepcopy(self.game_matrix)
self.move()
if self.game_matrix != self.game_matrix_before:
# 方塊變化後,隨機一個新的數字
self.randomGenerateNumber()
# 遊戲分數大於最高分,更新最高分
if self.score > self.max_score:
self.max_score = self.score
def randomGenerateNumber(self):
"""在空白位置產生隨機數 2 或者 4"""
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])
# 空白位置列表
# print(empty_pos)
# 隨機位置生成
i, j = random.choice(empty_pos)
# 隨機數生成
self.game_matrix[i][j] = 2 if random.random() > 0.1 else 4
print('隨機數位置爲[{0}][{1}] = 數值{2}'.format(i, j, self.game_matrix[i][j]))
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
def setDirection(self, direction):
assert direction in ['UP', 'DOWN', 'LEFT', 'RIGHT']
self.move_direction = direction
print(self.move_direction)
def move(self):
# 提取非空數值
def extract(array):
new_array = []
for arr in array:
if arr != 'null':
new_array.append(arr)
return new_array
# 合併非空數字
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] += array[i+1]
score += array[i]
array.pop(i+1)
array.append('null')
return extract(array), score
# 不需要移動的話直接返回
if self.move_direction is None:
return
if self.move_direction == 'UP':
# print("向上移動一次")
for j in range(self.matrix_size[1]):
# 獲取該列數據
col = []
for i in range(self.matrix_size[0]):
col.append(self.game_matrix[i][j])
# 提取非空數值
new_col = extract(col)
# 合併非空數字
new_col, score = merge(new_col)
self.score += score
# 補全列表null
new_col.extend('null' for _ in range(self.matrix_size[0] - len(new_col)))
# 從上往下更新該列數據
for i in range(self.matrix_size[0]):
self.game_matrix[i][j] = new_col[i]
# print(self.game_matrix)
elif self.move_direction == 'DOWN':
# print("向下移動一次")
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.reverse()
# 提取非空數值
new_col = extract(col)
# 合併非空數字
new_col, score = merge(new_col)
self.score += score
# 補全列表null
new_col.extend('null' for _ in range(self.matrix_size[0] - len(new_col)))
# 翻轉列
new_col.reverse()
# 從上往下更新該列數據
for i in range(self.matrix_size[0]):
self.game_matrix[i][j] = new_col[i]
# print(self.game_matrix)
elif self.move_direction == 'LEFT':
# print("向左移動一次")
for i in range(self.matrix_size[0]):
# 獲取該和行數據
row = []
for j in range(self.matrix_size[1]):
row.append(self.game_matrix[i][j])
# 提取非空數值
new_row = extract(row)
# 合併非空數字
new_row, score = merge(new_row)
self.score += score
# 補全列表null
new_row.extend('null' for _ in range(self.matrix_size[1] - len(new_row)))
# 從左往右更新該該行數據
for j in range(self.matrix_size[1]):
self.game_matrix[i][j] = new_row[j]
# print(self.game_matrix)
elif self.move_direction == 'RIGHT':
# print("向右移動一次")
for i in range(self.matrix_size[0]):
# 獲取該和行數據
row = []
for j in range(self.matrix_size[1]):
row.append(self.game_matrix[i][j])
# 翻轉行列表
row.reverse()
# 提取非空數值
new_row = extract(row)
# 合併非空數字
new_row, score = merge(new_row)
self.score += score
# 補全列表null
new_row.extend('null' for _ in range(self.matrix_size[1] - len(new_row)))
# 翻轉行列表
new_row.reverse()
# 從左往右更新該該行數據
for j in range(self.matrix_size[1]):
self.game_matrix[i][j] = new_row[j]
# print(self.game_matrix)
# 狀態置空
self.move_direction = None
def saveMaxScore(self):
"""保存最高分"""
f = open(self.max_score_filepath, 'w', encoding='utf-8')
f.write(str(self.max_score))
f.close()
@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
elif (j + 1 <= self.matrix_size[1] - 1) and (self.game_matrix[i][j] == self.game_matrix[i][j+1]):
return False
elif (i + 1 <= self.matrix_size[0] - 1) and (self.game_matrix[i][j] == self.game_matrix[i+1][j]):
return False
return True
if __name__ == "__main__":
game_2048 = Game2048(matrix_size=(4, 4), max_score_filepath='../score')
utils.py代碼
"""
功能:部分函數
作者:指尖魔法師
QQ:14555110
"""
import pygame
# 方塊背景顏色和字體顏色
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]
# 繪製遊戲方塊
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 = (j+1)*cfg.MARGIN_SIZE + j*cfg.MATRIX_SIZE
y = (i+1)*cfg.MARGIN_SIZE + i*cfg.MATRIX_SIZE
pygame.draw.rect(screen, pygame.Color(getColorByNumber(number)[0]), (x, y, cfg.MATRIX_SIZE, cfg.MATRIX_SIZE))
# print('game_matrix[{0}][{1}]={2}'.format(i, j, number))
if number != 'null':
font_color = pygame.Color(getColorByNumber(number)[1])
font_size = cfg.MATRIX_SIZE - cfg.MARGIN_SIZE*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.MATRIX_SIZE / 2, y + cfg.MATRIX_SIZE / 2
screen.blit(text, text_rect)
# 繪製分數
def drawScore(screen, score, max_score, cfg):
font_color = (255, 255, 255)
font_size = 30
font = pygame.font.Font(cfg.FONTPATH, font_size)
text_score = font.render('Score: '+str(score), True, font_color)
text_max_score = font.render('Best Score: ' + str(max_score), True, font_color)
start_x = cfg.GAME_MATRIX_SIZE[1] * cfg.MATRIX_SIZE + (cfg.GAME_MATRIX_SIZE[1] + 1) * cfg.MARGIN_SIZE
screen.blit(text_max_score, (start_x+10, 10))
screen.blit(text_score, (start_x + 10, 20 + text_score.get_height()))
start_y = 30 + text_score.get_height() * 2
return (start_x, start_y)
# 繪製遊戲介紹
def drawGameIntro(screen, start_x, start_y, cfg):
start_y += 40
font_color = (255, 255, 255)
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 = ['TIPS:', 'Use arrow keys to move the number blocks.', 'Adjacent blocks with the same number will',
'be merged. Just try to merge the blocks as', 'many as you can!']
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 += font.get_height() + 10
endInterface.py
"""
功能:遊戲結束頁面
作者:指尖魔法師
QQ:14555110
"""
import pygame
import sys
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((188, 188, 188, 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, (156, 139, 125), (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, (156, 139, 125), (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()