- 介绍
- 文件目录
- 游戏运行程序
- 游戏模块
- 玩家模块
- 颜色模块
记忆之迷(Memory Puzzle) 是一个记忆配对游戏1,白色的方块盖住了所有的图标,每种图标都有两个,玩家可以依次在两个方块上点击,如果图标是一致的,则两个方块将打开。当游戏板上所有的方块都打开时,玩家就赢了。可以用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 # 游戏板上方块在Y轴上的数量
self.__board_X = 7 # 游戏板上方块在X轴上的数量
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)
# 共8种图标
self.ICONS = ['方形', '矩形', '菱形', '圆形', '方+菱形', '方+圆形', '圆+菱形', '圆+矩形']
self.init_icons()
# 追踪玩家点击信息,(x, y, '图标')表示玩家鼠标点击的坐标(x, y),如果点到了图标,是哪个图标。
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)] # 建立二维数组,全为空:'';ANSWER是5*7的二维数组,记录每个方块中是哪个图标
# 配对生成,随机选两个位置,赋值为某随机图标。
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() # r为5*7的二维数组,记录玩家打开方块的进度,内容为True或False,表示游戏板上某个方块是否已翻开
for i in range(self.board_X):
for j in range(self.board_Y):
if (i, j) == (3, 4): # 跳过索引为(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) # 方块的边长为50像素,方块间的间距是50像素,方块与屏幕边界的距离也是50像素。
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 # 图标的左上角XY坐标
if icon_text == '方形':
position = (left + 10, top + 10, 30, 30) # 方块是50*50像素,方形是30*30像素,边界是10像素。
pygame.draw.rect(self.DISPLAYSURF, RGB.Yellow, position, 0)
elif icon_text == '矩形':
position = (left, top + 15, 50, 20) # 矩形宽50像素,高20像素,距上下边界各15像素。
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) # 方块的内接圆,半径25像素。
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() # r为5*7的二维数组,记录玩家打开方块的进度,内容为True或False,表示游戏板上某个方块是否已翻开
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]]) # ANSWER是5*7的二维数组,记录每个方块中是哪个图标
self.new_track = (index[0], index[1], self.ANSWER[index[0]][index[1]]) # 记下玩家点击的位置x和y,以及点到的方块里的图标是什么
# 判断上次点击的图标和这次点击的图标是否同一类
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 # 将game对象的方块数量传递进来
self.board_Y = game.board_Y # 将game对象的方块数量传递进来
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)] # result为5*7的二维数组,记录玩家打开方块的进度,内容为True或False,表示游戏板上某个方块是否已翻开
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
[美] Al Sweigart 著,李强 译. Python和Pygame游戏开发指南. 人民邮电出版社. 2015.12 ↩︎
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)