python 游戲(記憶拼圖Memory_Puzzle)


1. 游戲功能和流程圖

實現功能:翻開兩個一樣的牌子就顯示,全部翻開游戲結束,設置5種圖形,7種顏色,游戲開始提示隨機8個牌子

游戲流程圖

2. 游戲配置

配置游戲目錄

 

配置游戲(game_conf.py)

FPS=30 #游戲幀數
WINDOW_WIDTH=640 #窗口大小
WINDOW_HEIGHT=480
REVEAL_SPEAD=3 #箱子顯示的速度
BOX_SIZE=40 #箱子的大小寬高相等的正方形
GAP_SIZE=10 #箱子之間的間隔
BOARD_WIDTH=10 #圖標的列數
BOARD_HEIGHT=7 #圖標的行數
assert (BOARD_WIDTH*BOARD_HEIGHT)%2==0,'必須是偶數的棋盤' #檢查語句
X_MARGIN=int((WINDOW_WIDTH-(BOARD_WIDTH*(BOX_SIZE+GAP_SIZE)))/2) #x軸 邊緣空隙
Y_MARGIN=int((WINDOW_HEIGHT-(BOARD_HEIGHT*(BOX_SIZE+GAP_SIZE)))/2) #y軸 邊緣空隙

配置顏色(color.py)

'''游戲顏色'''
GRAY=(100,100,100)
NAVYBLUE=(60,60,100)
WHITE=(255,255,255)
RED=(255,0,0)
GREEN=(0,255,0)
BLUE=(0,0,255)
YELLOW=(255,255,0)
ORANGE=(255,128,0)
PURPLE=(255,0,255)
CYAN=(0,255,255)

配置形狀(shape.py)

DONUT='donut' #圓圈
SQUARE='square' #正方形
DIAMOND='diamond' #鑽石
LINES='lines'#線條
OVAL='oval' #橢圓形

3. 游戲使用工具函數(views.py)

3.1 工具和繪畫類使用模塊和常量

import random
import pygame
from pygame.locals import *
from conf.color import *
from conf.game_conf import *
from conf.shape import *
LIGHTBG_COLOR=GRAY #燈光顏色
BOX_COLOR=WHITE #盒子顏色
HIGHLIGHT_COLOR=BLUE #強調顏色
BG_COLOR=NAVYBLUE #背景顏色
ALL_COLORS=(RED,GREEN,BLUE,YELLOW,ORANGE,PURPLE,CYAN) #顏色元組
ALL_SHAPES=(DONUT,SQUARE,DIAMOND,LINES,OVAL) #形狀元組

3.2 生成游戲數據(游戲坐標,形狀,顏色)

def get_randomized_board():
'''生成所有盒子'''
icons=[]
#生成所有帶顏色的圖標,icons列表
for color in ALL_COLORS:
for shape in ALL_SHAPES:
icons.append((shape,color))
icon_use_number=int(BOARD_HEIGHT*BOARD_WIDTH/2) #所有圖標使用的數量
icons=icons[:icon_use_number]*2
random.shuffle(icons) # 打亂列表圖標
board=[]
#生成坐標
for x in range(BOARD_WIDTH):
column=[] #生成列數
for y in range(BOARD_HEIGHT):
column.append(icons[0]) #給每列添加圖標
del icons[0]
board.append(column)
return board 

3.3 用戶的游戲列表(游戲坐標,初始都是空坐標)

def generate_revealed_boxes_data(val):
'''生成翻開盒子初始列表'''
revealed_boxes = []
for i in range(BOARD_WIDTH):
revealed_boxes.append([val] * BOARD_HEIGHT)
return revealed_boxes

3.4  將盒子列表坐標轉化為實際的像素坐標

def left_top_coords_of_box(box_x, box_y):
'''將盒子位置轉化為像素坐標
:param box_x 盒子x坐標
:param box_y 盒子y坐標
:return 返回屏幕坐標'''
left = box_x * (BOX_SIZE + GAP_SIZE) + X_MARGIN
top = box_y * (BOX_SIZE + GAP_SIZE) + Y_MARGIN
return (left, top)

3.5  根據坐標返回對應的形狀和顏色

def get_shape_and_color(board, box_x, box_y):
'''獲取對應坐標 形狀和顏色
:param board 游戲板塊坐標列表
:param box_x 盒子x坐標
:param box_y 盒子y坐標
:return 返回形狀,顏色'''
#board[box_x][box_y][0] 形狀,board[box_x][box_y][1]顏色
return board[box_x][box_y][0], board[box_x][box_y][1]

3.6  根據鼠標坐標找到矩形列表坐標

def get_box_at_pixel(x,y):
'''根據鼠標坐標找到矩形列表坐標
:param x 鼠標x坐標
:param y 鼠標y坐標
:return 返回列表坐標'''
for box_x in range(BOARD_WIDTH):
for box_y in range(BOARD_HEIGHT):
left,top=left_top_coords_of_box(box_x,box_y)
box_rect=pygame.Rect(left, top, BOX_SIZE, BOX_SIZE) #繪制所有坐標矩形
if box_rect.collidepoint(x,y): #矩形碰撞,判斷該鼠標坐標是否在矩形內
return (box_x,box_y)
return (None,None)

3.7  列表分組

def split_into_group_of(group_size, the_list):
'''分組取值
:param group_size 需要分組的數量 最后一個有多少取多少
:param the_list 需要分組的列表'''
result = []
for i in range(0, len(the_list), group_size):
result.append(the_list[i:i + group_size]) #每組取n個
return result

3.8  檢查牌子是否都開啟了

def has_won(revealed_boxes):
'''檢查所有箱子是否都開啟了
:param revealed_boxes 反轉箱子的坐標'''
for i in revealed_boxes:
if False in i:
return False # return False if any boxes are covered.
return True

4  創建游戲繪畫類(views.py)

4.1  創建類的初始化

class puzzle(object):
def __init__(self,DISPLAY_SURF,FPS_CLOCK):
self.DISPLAY_SURF=DISPLAY_SURF #surf對象
self.FPS_CLOCK=FPS_CLOCK #fps鎖對象
self.main_board=get_randomized_board() #初始化盒子
self.revealed_boxes=generate_revealed_boxes_data(False) #初始化翻開的盒子列表

4.2  繪制游戲盒子(類方法)

def draw_board(self,board,revealed):
'''繪制游戲盒子
:param board 盒子坐標列表
:param revealed 被翻轉盒子坐標列表'''
for box_x in range(BOARD_WIDTH):
for box_y in range(BOARD_HEIGHT):
if not revealed[box_x][box_y]: #判斷該坐標是否被反轉
#繪制沒有翻開的盒子
self.draw_lid(box_x,box_y)
else:
#繪制已翻開的盒子
shape, color = get_shape_and_color(board, box_x, box_y)
self.draw_icon(shape, color, box_x, box_y)

4.3  繪制沒翻開的盒子

def draw_lid(self,box_x,box_y):
'''繪制沒翻開的盒子
:param box_x,box_y 盒子坐標'''
left, top = left_top_coords_of_box(box_x, box_y)
pygame.draw.rect(self.DISPLAY_SURF, BOX_COLOR, (left, top, BOX_SIZE, BOX_SIZE))

4.4  繪制已經翻開的盒子

def draw_icon(self,shape,color,box_x,box_y):
'''繪制翻開盒子的圖案
:param shape 形狀
:param color 形狀的顏色
:param box_x,box_y 盒子坐標'''
quarter=int(BOX_SIZE*0.25) #
half=int(BOX_SIZE*0.5) #
left,top=left_top_coords_of_box(box_x,box_y) #通過盒子坐標找到像素坐標
if shape==DONUT: #繪制甜甜圈形狀
pygame.draw.circle(self.DISPLAY_SURF,color,(left+half,top+half),half-5) #繪制 外圓 半徑離框5個像素
pygame.draw.circle(self.DISPLAY_SURF,BG_COLOR,(left+half,top+half),quarter-5) #繪制內圓 1/4之一個半徑
elif shape==SQUARE: #繪制正方形
pygame.draw.rect(self.DISPLAY_SURF,color,(left+quarter,top+quarter,BOX_SIZE-half,BOX_SIZE-half))
elif shape==DIAMOND: #繪制鑽石形狀
pygame.draw.polygon(self.DISPLAY_SURF,color,((left+half ,top),(left+BOX_SIZE-1,top+half),(left+half,top+BOX_SIZE-1),(left,top+half)))
elif shape==LINES: #繪制線條形
for i in range(0,BOX_SIZE,6): #步長控制密度越小密度越大
pygame.draw.line(self.DISPLAY_SURF,color,(left,top+i),(left+i,top)) #上往左邊的斜角線N條 一半
pygame.draw.line(self.DISPLAY_SURF,color,(left+i,top+BOX_SIZE-1),(left+BOX_SIZE-1,top+i)) #從下往右斜角線條N條 一半
elif shape==OVAL: #繪制橢圓
pygame.draw.ellipse(self.DISPLAY_SURF,color,(left,top+quarter,BOX_SIZE,half))

4.5  鼠標懸停高亮顯示

def draw_hightlight_box(self,box_x, box_y):
'''繪制鼠標懸停加亮顯示
:param box_x 盒子列表x坐標
:param box_y 盒子列表y坐標'''
left, top = left_top_coords_of_box(box_x, box_y)
pygame.draw.rect(self.DISPLAY_SURF,HIGHLIGHT_COLOR,(left-5,top-5,BOX_SIZE+10,BOX_SIZE+10),4) #繪畫外部高亮矩形

4.6  翻箱動畫

def reveal_boxes_animation(self,boxes_to_reveal):
'''翻箱子動畫
:param boxes_to_reveal 需要翻開的箱子坐標列表'''
for coverage in range(BOX_SIZE, (-REVEAL_SPEAD) - 1, -REVEAL_SPEAD): #從大到小繪制蓋板動畫 開蓋子
self.draw_box_covers(boxes_to_reveal, coverage)

4.7  合箱動畫

def cover_boxes_animation(self,boxes_to_cover):
'''蓋上箱子動畫
:param boxes_to_cover 需要蓋上的箱子坐標列表'''
for coverage in range(0, BOX_SIZE + REVEAL_SPEAD, REVEAL_SPEAD): #從小到大繪制蓋板動畫 關蓋子
self.draw_box_covers(boxes_to_cover, coverage)

4.8  動畫遮罩層

def draw_box_covers(self, boxes, coverage):
'''打印一次開/關 蓋子
:param boxes 需要操作的箱子列表
:param coverage 遮罩層的寬度'''
for box in boxes:
left, top = left_top_coords_of_box(box[0], box[1])
pygame.draw.rect(self.DISPLAY_SURF, BG_COLOR, (left, top, BOX_SIZE, BOX_SIZE)) #繪制背景
shape, color = get_shape_and_color(self.main_board, box[0], box[1])
self.draw_icon(shape, color, box[0], box[1]) #繪制形狀
if coverage > 0: # 如果遮罩層的寬度小於0就不繪制遮罩層了
pygame.draw.rect(self.DISPLAY_SURF, BOX_COLOR, (left, top, coverage, BOX_SIZE)) #繪制覆蓋層
pygame.display.update()
self.FPS_CLOCK.tick(FPS)

4.9  玩家勝利動畫

def game_won_animation(self):
'''玩家勝利顯示'''
covered_boxes = generate_revealed_boxes_data(True)
color1 = LIGHTBG_COLOR
color2 = BG_COLOR

for i in range(13):
color1, color2 = color2, color1 # 交替背景色
self.DISPLAY_SURF.fill(color1) #閃爍背景
self.draw_board(self.main_board, covered_boxes) #繪制所有顯示圖案
pygame.display.update()
pygame.time.wait(300) #每次閃爍間隔300毫秒

4.10  游戲開始動畫

def start_game_animation(self):
'''隨機展示8個盒子'''
cover_boxes = generate_revealed_boxes_data(False) #制造隨機翻開的盒子
boxes = []
for x in range(BOARD_WIDTH):
for y in range(BOARD_HEIGHT):
boxes.append((x, y))
random.shuffle(boxes) #隨機盒子坐標
box_groups = split_into_group_of(8, boxes) #隨機抽取8個盒子坐標

self.draw_board(self.main_board,cover_boxes) #繪制沒翻開板子的游戲界面
for box_group in box_groups: #循環翻板
self.reveal_boxes_animation(box_group)
self.cover_boxes_animation(box_group)

 5. 游戲邏輯判斷(游戲核心Memory_Puzzle.py) 

5.1 游戲使用模塊和常量

import sys,pygame
from pygame.locals import *
from conf.color import *
from conf.game_conf import *
from core import views
from conf.shape import *
BG_COLOR=NAVYBLUE #背景色

5.2 游戲邏輯判斷

def main():
pygame.init()
FPS_CLOCK=pygame.time.Clock()
DISPLAY_SURF=pygame.display.set_mode((WINDOW_WIDTH,WINDOW_HEIGHT))
Puzzle = views.puzzle(DISPLAY_SURF, FPS_CLOCK)
pygame.display.set_caption('My Game')
mouse_x=0 #鼠標x坐標
mouse_y=0 #鼠標y坐標
first_selection = None # 存儲第一個翻開的盒子
DISPLAY_SURF.fill(BG_COLOR)#繪制背景色
Puzzle.start_game_animation() #游戲開始提示
while True:
mouse_clicked=False #初始化鼠標點擊
DISPLAY_SURF.fill(BG_COLOR) #循環掩蓋高亮顯示
Puzzle.draw_board(Puzzle.main_board,Puzzle.revealed_boxes)
for event in pygame.event.get():
if event.type==QUIT:
pygame.quit()
sys.exit()
elif event.type==MOUSEMOTION: #獲取鼠標懸停的像素坐標
mouse_x,mouse_y=event.pos
elif event.type==MOUSEBUTTONDOWN: #獲取鼠標點擊的像素坐標
mouse_x,mouse_y=event.pos
mouse_clicked=True
box_x,box_y=views.get_box_at_pixel(mouse_x, mouse_y)
if box_x!=None and box_y!=None: #當鼠標在一個框上的時候
if not Puzzle.revealed_boxes[box_x][box_y]: #沒有翻開的牌子高亮顯示
Puzzle.draw_hightlight_box(box_x,box_y)
if not Puzzle.revealed_boxes[box_x][box_y] and mouse_clicked: #沒有翻開牌子並且點擊的盒子顯示
Puzzle.reveal_boxes_animation([(box_x,box_y)]) #掀開動畫
Puzzle.revealed_boxes[box_x][box_y]=True #設置翻開坐標
if first_selection==None: #檢查是否第一次翻牌子
first_selection=(box_x,box_y)
else:
icon1_shape,icon1_color=views.get_shape_and_color(Puzzle.main_board, first_selection[0], first_selection[1])
icon2_shape,icon2_color=views.get_shape_and_color(Puzzle.main_board, box_x, box_y)
if icon1_shape != icon2_shape or icon1_color!=icon2_color: #判斷兩個方塊不相同
pygame.time.wait(1000)#等待一秒鍾
Puzzle.cover_boxes_animation([(first_selection[0], first_selection[1]), (box_x, box_y)])
Puzzle.revealed_boxes[first_selection[0]][first_selection[1]] = False
Puzzle.revealed_boxes[box_x][box_y]=False
elif views.has_won(Puzzle.revealed_boxes): #判斷游戲是否勝利
Puzzle.game_won_animation() #顯示獲勝界面
pygame.time.wait(200)
#初始化數據
Puzzle.main_board = views.get_randomized_board() #重置箱子
Puzzle.revealed_boxes = views.generate_revealed_boxes_data(False) #重置玩家翻開表
#顯示游戲界面
Puzzle.draw_board(Puzzle.main_board,Puzzle.revealed_boxes)
pygame.display.update()
pygame.time.wait(1000)
#游戲開始前的動畫
PURPLE.start_game_animation()
first_selection=None
pygame.display.update()
FPS_CLOCK.tick(FPS)

5.3  運行游戲

if __name__ == '__main__':
main()
 
        

python學習途徑

本游戲參考書本 <<Python和Pygame游戲開發>>

游戲源碼下載 http://invpy.com/memorypuzzle.py

友情推薦:  猿人學Python【 https://www.yuanrenxue.com/】 由一群工作十余年的老程序員結合實際工作經驗所寫的Python教程。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM