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()