用pygame实现记忆之迷(Memory Puzzle)小游戏
介绍
记忆之迷(Memory Puzzle) 是一个记忆配对游戏,白色的方块盖住了所有的图标,每种图标都有两个,玩家可以依次在两个方块上点击,如果图标是一致的,则两个方块将打开。当游戏板上所有的方块都打开时,玩家就赢了。可以用Python语言和Pygame框架来开发这个游戏,如下图所示。
文件目录
编写这个小游戏用到的代码文件如下: myDirectory/
- bg_music.mp3 # 背景音乐
- click.wav # 点击音效
- hit.wav # 配对音效
- memory_puzzle.py # 游戏运行程序
- Game.py # 游戏模块,生成游戏板、处理玩家鼠标点击事件等
- Player.py # 玩家模块,记录玩家得分、点击次数等
- RGB.py # 颜色模块,定义了所有RGB颜色常量
前面3个是声音文件,可以在站长素材、freepd等网站免费下载。后面4个是运行游戏用的脚本和3个模块,现在分别介绍一下。
游戏运行程序
运行游戏用的脚本memory_puzzle.py 的全部代码如下:
import pygame, sys, random, RGB, Game, Player
from pygame.locals import *
def main():
game = Game.Game(12, 800, 600, '记忆之谜')
player = Player.Player(0, 0, 0, 0, 0, game)
while True:
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
elif event.type == MOUSEBUTTONDOWN:
player.X, player.Y = event.pos
game.fill(RGB.Black)
game.draw_map(player)
b1, b2, b3 = pygame.mouse.get_pressed()
if b1:
game.check_memory(player)
game.print_text(game.FONT1, 10, 10, "得分:" + str(player.score), color=RGB.White, shadow=True)
game.print_text(game.FONT1, game.window_width-150, 10, "已点击次数:" + str(player.clicked_times), color=RGB.White, shadow=True)
if player.win == 1:
game.print_text(game.FONT1, 100, 10, "恭喜,你赢了!", color=RGB.White, shadow=True)
pygame.display.update()
game.tick()
if __name__ == '__main__':
main()
定义了一个main() 函数,包括了游戏的主要逻辑,包括建立game 对象和player 对象,建立游戏循环,处理鼠标点击事件、绘制游戏板、对玩家点击的响应处理,显示玩家得分和点击次数。 游戏的主要逻辑写的越简单越好,具体的细节可以到各个模块中去实现。
游戏模块
游戏模块Game.py 的全部代码如下:
import pygame, sys, RGB, random, Player
from pygame.locals import *
class Game():
def __init__(self, fps, window_width, window_height, caption):
''' 建立游戏对象,必需参数为帧率,游戏屏幕的宽和高,游戏标题。'''
pygame.init()
self.__f = fps
self.__c = pygame.time.Clock()
self.window_width = window_width
self.window_height = window_height
self.__board_Y = 5
self.__board_X = 7
self.block_width = 50
self.block_height = 50
self.DISPLAYSURF = pygame.display.set_mode((self.window_width, self.window_height))
self.FONT1 = pygame.font.SysFont('stzhongsong', 18)
self.ICONS = ['方形', '矩形', '菱形', '圆形', '方+菱形', '方+圆形', '圆+菱形', '圆+矩形']
self.init_icons()
self.old_track = (0, 0, '')
self.new_track = (-1, -1, 'NA')
pygame.display.set_caption(caption)
self.click_sound = pygame.mixer.Sound('click.ogg')
self.hit_sound = pygame.mixer.Sound('hit.wav')
pygame.mixer.music.load('bg_music.mp3')
pygame.mixer.music.play(-1, 0.0)
def _getf(self): return self.__f
def _setf(self, value): self.__f = value
FPS = property(_getf, _setf)
def _getc(self): return self.__c
def _setc(self, value): self.__c = value
fpsClock = property(_getc, _setc)
def _getx(self): return self.__board_X
def _setx(self, value): self.__board_X = value
board_X = property(_getx, _setx)
def _gety(self): return self.__board_Y
def _sety(self, value): self.__board_Y = value
board_Y = property(_gety, _sety)
def print_text(self, font, x, y, text, color=RGB.White, shadow=True):
''' 打印文字 '''
imgText = font.render(text, True, color)
self.DISPLAYSURF.blit(imgText, (x, y))
def init_icons(self):
''' 配对生成图标。只能是偶数,而方块的总数为5*7=35,所以去除一个索引为(3, 4)的方块(ID:31)。'''
a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 32, 33, 34]
self.ANSWER = [['' for i in range(self.board_Y)] for j in range(self.board_X)]
while len(a) > 0:
r1 = random.choice(a)
r2 = random.choice(a)
if r1 == r2:
continue
r = random.randint(0, self.board_X)
x = r1 % self.board_X
y = r1 // self.board_X
self.ANSWER[x][y] = self.ICONS[r]
x = r2 % self.board_X
y = r2 // self.board_X
self.ANSWER[x][y] = self.ICONS[r]
a.pop(a.index(r1))
a.pop(a.index(r2))
def fill(self, color):
''' 用color填充游戏屏背景 '''
self.DISPLAYSURF.fill(color)
def tick(self):
''' 自动的暂停,控制帧速率 '''
self.fpsClock.tick(self.FPS)
def draw_map(self, player):
''' 绘制游戏板 '''
r = player.get_result()
for i in range(self.board_X):
for j in range(self.board_Y):
if (i, j) == (3, 4):
continue
position = (self.block_width+self.block_width*2*i, self.block_height+self.block_height*2*j, self.block_width, self.block_height)
pygame.draw.rect(self.DISPLAYSURF, RGB.White, position, 0)
if r[i][j] == True:
self.draw_icon(i, j, self.ANSWER[i][j])
def draw_icon(self, x, y, icon_text):
''' 绘制图标 '''
left, top = self.block_width+self.block_width*2*x, self.block_height+self.block_height*2*y
if icon_text == '方形':
position = (left + 10, top + 10, 30, 30)
pygame.draw.rect(self.DISPLAYSURF, RGB.Yellow, position, 0)
elif icon_text == '矩形':
position = (left, top + 15, 50, 20)
pygame.draw.rect(self.DISPLAYSURF, RGB.Green, position, 0)
elif icon_text == '菱形':
pygame.draw.polygon(self.DISPLAYSURF, RGB.Blue, [(left+25, top), (left, top+25), (left+25, top+50), (left+50, top+25)])
elif icon_text == '圆形':
pygame.draw.circle(self.DISPLAYSURF, RGB.Purple, (left+25, top+25), 25, 0)
elif icon_text == '方+菱形':
pygame.draw.polygon(self.DISPLAYSURF, RGB.Blue, [(left+25, top), (left, top+25), (left+25, top+50), (left+50, top+25)])
position = (left + 10, top + 10, 30, 30)
pygame.draw.rect(self.DISPLAYSURF, RGB.Yellow, position, 0)
elif icon_text == '方+圆形':
pygame.draw.circle(self.DISPLAYSURF, RGB.Purple, (left+25, top+25), 25, 0)
position = (left + 10, top + 10, 30, 30)
pygame.draw.rect(self.DISPLAYSURF, RGB.Yellow, position, 0)
elif icon_text == '圆+菱形':
pygame.draw.circle(self.DISPLAYSURF, RGB.Purple, (left+25, top+25), 25, 0)
pygame.draw.polygon(self.DISPLAYSURF, RGB.Blue, [(left+25, top), (left, top+25), (left+25, top+50), (left+50, top+25)])
elif icon_text == '圆+矩形':
pygame.draw.circle(self.DISPLAYSURF, RGB.Purple, (left+25, top+25), 25, 0)
position = (left, top + 15, 50, 20)
pygame.draw.rect(self.DISPLAYSURF, RGB.Green, position, 0)
def get_xy_for_mouse_down_in_block(self, mouse_down_x, mouse_down_y):
''' 如果鼠标的点击点在某方块中,则返回方块的索引如(4, 5),如果不在,则返回(-1, -1) '''
xy = (-1, -1)
for i in range(self.board_X):
for j in range(self.board_Y):
if mouse_down_x > self.block_width+self.block_width*2*i and mouse_down_x < self.block_width*2*(i+1) and mouse_down_y > self.block_height+self.block_height*2*j and mouse_down_y < self.block_height*2*(j+1):
xy = (i, j)
return xy
def check_memory(self, player):
''' 对玩家鼠标点击事件的响应 '''
r = player.get_result()
index = self.get_xy_for_mouse_down_in_block(player.X, player.Y)
if index != (-1, -1) and index != (3, 4) and r[index[0]][index[1]] != True:
player.clicked_times += 1
self.draw_icon(index[0], index[1], self.ANSWER[index[0]][index[1]])
self.new_track = (index[0], index[1], self.ANSWER[index[0]][index[1]])
if self.old_track[2] == self.new_track[2] and (self.old_track[0], self.old_track[1]) != (self.new_track[0], self.new_track[1]):
self.hit_sound.play()
a = self.old_track[0]
b = self.old_track[1]
r[a][b] = True
a = self.new_track[0]
b = self.new_track[1]
r[a][b] = True
self.old_track = (0, 0, '')
self.new_track = (0, 0, '')
player.score = player.count_true_in_results()
if player.score == 34:
player.win = 1
else:
self.click_sound.play()
self.old_track = self.new_track
self.new_track = (0, 0, '')
玩家模块
游戏模块Player.py 的全部代码如下:
class Player():
def __init__(self, mouse_down_x, mouse_down_y, clicked_times, score, win, game):
''' 建立玩家对象,必须参数包括鼠标点击的x和y坐标,玩家得分,玩家是否赢了,game对象。'''
self.__x = mouse_down_x
self.__y = mouse_down_y
self.__t = clicked_times
self.__s = score
self.__w = win
self.board_X = game.board_X
self.board_Y = game.board_Y
self.init_result()
def _getx(self): return self.__x
def _setx(self, value): self.__x = value
X = property(_getx, _setx)
def _gety(self): return self.__y
def _sety(self, value): self.__y = value
Y = property(_gety, _sety)
def _gett(self): return self.__t
def _sett(self, value): self.__t = value
clicked_times = property(_gett, _sett)
def _gets(self): return self.__s
def _sets(self, value): self.__s = value
score = property(_gets, _sets)
def _getw(self): return self.__w
def _setw(self, value): self.__w = value
win = property(_getw, _setw)
def init_result(self):
''' 初始化玩家的游戏进度数组 '''
self.result = [[False for i in range(self.board_Y)] for j in range(self.board_X)]
def get_result(self):
''' 返回玩家进度数组 '''
return self.result
def count_true_in_results(self):
''' 计算玩家进度数组中已翻开方块的数量 '''
x = 0
for i in range(self.board_X):
for j in range(self.board_Y):
if self.result[i][j] == True:
x += 1
return x
颜色模块
游戏模块RGB.py 的部分代码如下:
Black = (0, 0, 0)
White = (255, 255, 255)
Yellow = (255, 255, 0)
Green = (0, 255, 0)
Blue = (0, 0, 255)
Purple = (160, 32, 240)
以上是本游戏用到的颜色,全部RGB的颜色代码可以查RGB颜色表,一个现成的RGB颜色表点 这里 。
源代码已经上传到GitCode: 下唐人 / memory_puzzle · GitCode
|