用pygame实现记忆之迷(Memory Puzzle)小游戏

用pygame实现记忆之迷(Memory Puzzle)小游戏,第1张

pygame实现记忆之迷(Memory Puzzle)小游戏
  • 介绍
    • 文件目录
    • 游戏运行程序
    • 游戏模块
    • 玩家模块
    • 颜色模块

介绍

记忆之迷(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


  1. [美] Al Sweigart 著,李强 译. Python和Pygame游戏开发指南. 人民邮电出版社. 2015.12 ↩︎

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/869815.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-13
下一篇 2022-05-13

发表评论

登录后才能评论

评论列表(0条)

保存