python编写一个游戏_学习python编写一个小游戏(2020-07-08)

摘要

本次使用python语言编写了一个记忆游戏,主要利用pygame库的一些类方法实现图形界面的编辑,事件的发生,实现一个简单的翻牌的记忆游戏。

1.引言

在进行完python课程的学习后,为了更好的掌握这个语言,以及学习一些相关库的用法,故在此编写了一个简单的游戏—记忆游戏。此游戏开始时先通过快速的翻牌显示,来展示每个牌上的图案。然后玩家通过鼠标选择点击进行翻牌,连续两次翻出一样图案的牌视为成功,不一样的图案则会重新覆盖牌子,玩家需要重新选择,直到所有牌子图案都显示出来了,则玩家获胜。

2. 介绍系统的结构

实现的功能:鼠标点击翻开牌子,两个相同的图案就显示,不相同就重新覆盖,定义五种图形,七种颜色,游戏开始时候提示随机8个牌子。

2.1 系统的界面结构

2.1.1主窗口

界面显示的整体窗口是所有牌子的容器,默认大小为1000px(宽)*480px(长),默认颜色为红色

2.1.2 牌(盒子)

是图案的容器,默认大小为40px*40px,每张牌有五种图案与七种颜色搭配使用。

2.1.3 图案

为牌子上显示的图案,默认为五种图案,分别为:甜甜圈,方块,钻石,线,椭圆

2.1.4 颜色

是界面窗口,牌等展示的颜色,默认有十种颜色,分别为:GRAY,

NAYYYELLOW, WHITE, RED, GREEN, BLUE, YELLOW, ORANGE, PURPLE, CYAN.

2.1.5边框

是当鼠标移动到牌的时候,显示的边框,包裹着牌子。默认颜色为红色

2.1.6 获胜提示

当取得胜利时,会显示“You Are Win!”的话语。

2.2 系统的功能逻辑

598428833b21

图1 功能逻辑

2.3 使用的相关模块及方法

2.3.1  pygame模块

Pygame.Init() 初始化

Pygame.Time.clock()创建一个对象来帮助跟踪时间。

Pygame.display.set_mode()初始化图形显示,建立一个画布

Pygame.display.set_caption()设计标题名

Pygame.rect(left,

top, width, height) rect对象是用来存储矩形对象的,rect对象有一些虚拟属性,

Pygam.event()

Event.pos()

2.3.2 random模块

2.3.3 sys 模块

3. 实现代码。

3.1相关定义初始化。

3.1.1 引入的模块

模块有:random, pygame, sys

代码实现:

import random, pygame, sys

from pygame.locals import *

3.2.2 默认值的声明定义(变量名,[变量值])

帧数:(FPS, 60)

窗口的宽:(WINDOWWIDTH,1000)

窗口的长:(WINDOWHEIGHT,480)

翻牌的显示速度:(REVEALSPEED,

8)

图案盒子的大小(正方形牌):(BOSXIZE,40)

盒子(牌)之间的间距:(GAPSIZE,10)

窗口盒子(牌)排列的横排数:(BOARDWIDTH, 5)

窗口盒子(牌)排列的横排数:(BOARDHEIGHT, 2)

盒子(牌)区域的横向外边距:(XMARGIN)

盒子(牌)区域纵向外边距:(YMARGIN)

颜色定义:

(GRAY,(100,100,100)))

(NAVYYELLOW,(255,165, 0)))

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

图案:

DONUT = 'donut' # 甜甜圈

SQUARE = 'square' # 方块

DIAMOND = 'diamond' # 钻石

LINES = 'lines' # 线

OVAL = 'oval' # 椭圆

储存颜色的元组(

ALLCOLORS)

储存图案的元组( ALLSHAPES)

窗口背景色:(BGOLOR)

闪烁的时候变换的背景颜色:(LIGHTBGCOLOR)

盒子(牌)的颜色:(BOXCOLOR)

鼠标选中的时候外边框的颜色:(HIGHLIGHTCOLOR,RED)

代码实现:

FPS = 60 # 每秒的帧数,开局提示

WINDOWWIDTH = 1000 # 窗口的宽度

WINDOWHEIGHT = 480 # 窗口的长

REVEALSPEED = 8 # 翻盖的速度

BOXSIZE = 40 # 图案盒子的大小

GAPSIZE = 10 # 图之间的间距

BOARDWIDTH =  5 # 横排个数

BOARDHEIGHT = 2 # 纵排个数

assert (BOARDWIDTH * BOARDHEIGHT) % 2 == 0, 'Board needs to have an even number of boxes for pairs of matches.'

XMARGIN = int((WINDOWWIDTH - (BOARDWIDTH * (BOXSIZE + GAPSIZE))) / 2)

YMARGIN = int((WINDOWHEIGHT - (BOARDHEIGHT * (BOXSIZE + GAPSIZE))) / 2)

#                R    G    B

GRAY         = (100, 100, 100)

NAVYYELLOW   = (255, 165,   0)

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)

BGCOLOR = NAVYYELLOW # 背景色

LIGHTBGCOLOR = GRAY # 闪烁时候的背景颜色

BOXCOLOR = WHITE # 盒子的颜色

HIGHLIGHTCOLOR = RED # 鼠标选中时候外边框的颜色

DONUT = 'donut' # 甜甜圈

SQUARE = 'square' # 方块

DIAMOND = 'diamond' # 钻石

LINES = 'lines' # 线

OVAL = 'oval' # 椭圆

# 定义两个元组ALLCOLRS 和 ALLSHAPES 分别存储 颜色 和 图案。

ALLCOLORS = (RED, GREEN, BLUE, YELLOW, ORANGE, PURPLE, CYAN)

ALLSHAPES = (DONUT, SQUARE, DIAMOND, LINES, OVAL)

assert len(ALLCOLORS) * len(ALLSHAPES) * 2 >= BOARDWIDTH * BOARDHEIGHT, "Board is too big for the number of shapes/colors defined."

3.2.3 函数的定义实现

根据系统的逻辑实现,得出以下一些实现相关功能逻辑的函数:

(1)主函数main()

变量的定义:

全局变量 FPSCLOCK和 DISPLAYSURE:

前者用来存储一个对象来跟踪时间,后者用来存储显示的对象

mousex和 mousex:

分别用来存储鼠标事件的x和y坐标

Fontobj和testsurfaceobj:

分别用来存储pygame的字体对象和输出胜利提示的文本

函数的实现逻辑:

首先初始化跟踪事件和显示的事件,然后调用函数实现牌的窗口的初始化、牌的初始化、监控鼠标的动态位置数据,以及相关的点击事件,来实现整个游戏流程。代码实现如下:

def main():

global FPSCLOCK, DISPLAYSURF

pygame.init()   #初始化

FPSCLOCK = pygame.time.Clock() # 创建一个对象来帮助跟踪时间

DISPLAYSURF = pygame.display.set_mode((WINDOWWIDTH, WINDOWHEIGHT)) # 初始化显示

mousex = 0 # 存储鼠标时间的x坐标

mousey = 0 # 储存鼠标时间的y坐标

pygame.display.set_caption('游戏') # 设计标题

# 设置胜利时候输出语句

fontObj = pygame.font.Font('freesansbold.ttf',32)

textSurfaceObj = fontObj.render('You Are Win!',True,GREEN,BLUE)

textRectObj = textSurfaceObj.get_rect()

textRectObj.center=(200,150)

#初始化界面随机的图案排列

mainBoard = getRandomizedBoard()

#初始化每个图案的默认值为False

revealedBoxes = generateRevealedBoxesData(False)

firstSelection = None # 储存点击的第一个图的(x,y)

DISPLAYSURF.fill(BGCOLOR) # 设置背景颜色

# 游戏开始的动画

startGameAnimation(mainBoard)

while True: # 主游戏循环

mouseClicked = False

DISPLAYSURF.fill(BGCOLOR) # 绘制窗口

drawBoard(mainBoard, revealedBoxes)

for event in pygame.event.get(): # event 处理循环

if event.type == QUIT or (event.type == KEYUP and event.key == K_ESCAPE):

pygame.quit()

sys.exit()

elif event.type == MOUSEMOTION:

mousex, mousey = event.pos

elif event.type == MOUSEBUTTONUP:

mousex, mousey = event.pos

mouseClicked = True

boxx, boxy = getBoxAtPixel(mousex, mousey)

if boxx != None and boxy != None:

# 鼠标位于一个盒子里的事件(显示红色边框框)

if not revealedBoxes[boxx][boxy]:

drawHighlightBox(boxx, boxy)

if not revealedBoxes[boxx][boxy] and mouseClicked:

revealBoxesAnimation(mainBoard, [(boxx, boxy)])

revealedBoxes[boxx][boxy] = True # 将盒子设置为显示

if firstSelection == None: # 判断当前框是否第一个单击的框

firstSelection = (boxx, boxy)

else: # 第二个点击的框

# 检查两个图是否匹配

icon1shape, icon1color = getShapeAndColor(mainBoard, firstSelection[0], firstSelection[1])

icon2shape, icon2color = getShapeAndColor(mainBoard, boxx, boxy)

if icon1shape != icon2shape or icon1color != icon2color:

# 不匹配,隐藏显示

pygame.time.wait(250) # 250毫秒的等待时间

coverBoxesAnimation(mainBoard, [(firstSelection[0], firstSelection[1]), (boxx, boxy)])

revealedBoxes[firstSelection[0]][firstSelection[1]] = False

revealedBoxes[boxx][boxy] = False

elif hasWon(revealedBoxes): # 判断是否找出所有的对

gameWonAnimation(mainBoard)

DISPLAYSURF.fill(YELLOW)

DISPLAYSURF.blit(textSurfaceObj,textRectObj)

pygame.time.wait(000)

# 重置面板

mainBoard = getRandomizedBoard()

revealedBoxes = generateRevealedBoxesData(False)

drawBoard(mainBoard, revealedBoxes)

pygame.display.update()

pygame.time.wait(1000)

# 重新开始游戏动画

startGameAnimation(mainBoard)

firstSelection = None # 重置 firstSelection变量

pygame.display.update()

FPSCLOCK.tick(FPS)

(2)getRandomizedBoard(val)

将传进来的值(布尔值)赋予每个牌,可用来界面牌的初始化(也就是实现将所有牌盖起来了),存储进序列revealedBoxes[],并返回此值。

代码实现:

def generateRevealedBoxesData(val):

revealedBoxes = []

for i in range(BOARDWIDTH):

revealedBoxes.append([val] * BOARDHEIGHT)

return revealedBoxes

(3)getRandomizedBoard()

根据初始化声明BOARDWIDTH和BORDHEIGHT的值确定牌的种类数,以及图案的个数。将颜色与图案的组合利用随机函数随机排序,存进序列中。

代码实现如下:

def getRandomizedBoard():

# 用每种颜色列出每种可能的形状

icons = []

for color in ALLCOLORS:

for shape in ALLSHAPES:

icons.append( (shape, color) )

random.shuffle(icons) # 随机排序图标列表的顺序

numIconsUsed = int(BOARDWIDTH * BOARDHEIGHT / 2) # 计算要多少个图标

icons = icons[:numIconsUsed] * 2 # 图标双倍

random.shuffle(icons) # 将序列的所有元素随机排序

# 用随机放置的图片创建一个列表

board = []

for x in range(BOARDWIDTH):

column = []

for y in range(BOARDHEIGHT):

column.append(icons[0])

del icons[0] # 移除指定的图标

board.append(column)

return board

(4) splitIntoGrounpsOs(groupsize,

thelist)

接受传进来的值(开局每次提示的个数),序列,拆分列表,根据定义的个数把序列随机拆分,每组就是定义的个数(此处根据默认定义,传进来的值应该为8)

代码实现:

def splitIntoGroupsOf(groupSize, theList):

# 拆分列表的逻辑实现,为了开局的每次展示图案(8个)

result = []

for i in range(0, len(theList), groupSize):

result.append(theList[i:i + groupSize])

return result

(5)leftTopCoordsOfBox(boxx, boxy)

将传进来的鼠标的横纵坐标转为以盒子边距为参考的像素,外边距已声明。

代码实现:

def leftTopCoordsOfBox(boxx, boxy):

# 将面板转换为像素坐标

left = boxx * (BOXSIZE + GAPSIZE) + XMARGIN

top = boxy * (BOXSIZE + GAPSIZE) + YMARGIN

return (left, top)

(6)getBoxAtPixel(x, y)

确定盒子(牌)的像素位置区域,根据盒子(牌)的大小,以及盒子在横排纵排的个数确定。

此区域分别用boxx,和boxy来表示横向,纵向。

代码实现:

def getBoxAtPixel(x, y):

for boxx in range(BOARDWIDTH):

for boxy in range(BOARDHEIGHT):

left, top = leftTopCoordsOfBox(boxx, boxy)

boxRect = pygame.Rect(left, top, BOXSIZE, BOXSIZE)

if boxRect.collidepoint(x, y):

return (boxx, boxy)

return (None, None)

(7)drawIcon(shape, color, boxx, boxy)

绘制牌子图案,根据图型,颜色,以及盒子的区域,画出每一张牌上的图案。

代码实现如下:

def drawIcon(shape, color, boxx, boxy):

quarter = int(BOXSIZE * 0.25) # 语法糖

half =    int(BOXSIZE * 0.5)  # 语法糖

left, top = leftTopCoordsOfBox(boxx, boxy) # 从面板坐标获取像素坐标

# 画形状

if shape == DONUT:

pygame.draw.circle(DISPLAYSURF, color, (left + half, top + half), half - 5)

pygame.draw.circle(DISPLAYSURF, BGCOLOR, (left + half, top + half), quarter - 5)

elif shape == SQUARE:

pygame.draw.rect(DISPLAYSURF, color, (left + quarter, top + quarter, BOXSIZE - half, BOXSIZE - half))

elif shape == DIAMOND:

pygame.draw.polygon(DISPLAYSURF, color, ((left + half, top), (left + BOXSIZE - 1, top + half), (left + half, top + BOXSIZE - 1), (left, top + half)))

elif shape == LINES:

for i in range(0, BOXSIZE, 4):

pygame.draw.line(DISPLAYSURF, color, (left, top + i), (left + i, top))

pygame.draw.line(DISPLAYSURF, color, (left + i, top + BOXSIZE - 1), (left + BOXSIZE - 1, top + i))

elif shape == OVAL:

pygame.draw.ellipse(DISPLAYSURF, color, (left, top + quarter, BOXSIZE, half))

(7)getShapeAndColor(board, boxx, boxy)

用来存储每张盒子(牌)的图形以及颜色。

代码实现如下:

def getShapeAndColor(board, boxx, boxy):

# 存储x,y的形状值    board[x][y][0]

# 存储x,y的颜色值    board[x][y][1]

return board[boxx][boxy][0], board[boxx][boxy][1]

(8)drawBoxCovers(board, boxes, coverage)

用来实现盒子(牌)的副盖(翻)

代码实现如下:

def drawBoxCovers(board, boxes, coverage):

# 绘制覆盖/显示的盒子,是一个列表

# 两个列表分别存储x&y的位置

for box in boxes:

left, top = leftTopCoordsOfBox(box[0], box[1])

pygame.draw.rect(DISPLAYSURF, BGCOLOR, (left, top, BOXSIZE, BOXSIZE))

shape, color = getShapeAndColor(board, box[0], box[1])

drawIcon(shape, color, box[0], box[1])

if coverage > 0: # 判断是否覆盖

pygame.draw.rect(DISPLAYSURF, BOXCOLOR, (left, top, coverage, BOXSIZE))

pygame.display.update()

FPSCLOCK.tick(FPS) # 覆盖(翻牌)的速度

(9)revealBoxesAnimation(board, boxesToReveal)

用来实现展示盒子(牌)图案的动画

代码实现:

def revealBoxesAnimation(board, boxesToReveal):

# 盒子展示的动画

for coverage in range(BOXSIZE, (-REVEALSPEED) - 1, -REVEALSPEED):

drawBoxCovers(board, boxesToReveal, coverage)

(10)coverBoxesAnimation(board, boxesToCover)

用来实现隐藏盒子(牌)的动画

代码实现如下:

def coverBoxesAnimation(board, boxesToCover):

# 盒子覆盖的动画

for coverage in range(0, BOXSIZE + REVEALSPEED, REVEALSPEED):

drawBoxCovers(board, boxesToCover, coverage)

(11)drawBoard(board, revealed)

用来实现盒子(牌)的覆盖或者展示,用if判断传进来的值若是展示则进行覆盖操作,若传进来的值是覆盖,则画上(展示)此位置的图案。

代码实现如下:def drawBoard(board, revealed):

# 绘制框

for boxx in range(BOARDWIDTH):

for boxy in range(BOARDHEIGHT):

left, top = leftTopCoordsOfBox(boxx, boxy)

if not revealed[boxx][boxy]:

# 画一个有盖的盒子.

pygame.draw.rect(DISPLAYSURF, BOXCOLOR, (left, top, BOXSIZE, BOXSIZE))

else:

# 绘制(显示)图标

shape, color = getShapeAndColor(board, boxx, boxy)

drawIcon(shape, color, boxx, boxy)

(12)drawHighlightBox(boxx, boxy)

绘制当鼠标挪动到盒子(牌)时周边的红色边框。

代码实现:

def drawHighlightBox(boxx, boxy):

left, top = leftTopCoordsOfBox(boxx, boxy)

pygame.draw.rect(DISPLAYSURF, HIGHLIGHTCOLOR, (left - 5, top - 5, BOXSIZE + 10, BOXSIZE + 10), 4)

(13)startGameAnimation(board)

实现开始游戏时的提示,默认设置为每次随机展示八个盒子(牌)

代码实现如下:def startGameAnimation(board):

# 一次随机展示八个盒子

coveredBoxes = generateRevealedBoxesData(False) # 覆盖每个盒子

boxes = []

for x in range(BOARDWIDTH):

for y in range(BOARDHEIGHT):

boxes.append( (x, y) )

random.shuffle(boxes)

boxGroups = splitIntoGroupsOf(8, boxes) # 每次展示八个图案

drawBoard(board, coveredBoxes)

for boxGroup in boxGroups:

revealBoxesAnimation(board, boxGroup)

coverBoxesAnimation(board, boxGroup)

(14)gameWonAnimation(board)

玩家获胜时,背景会两种颜色交替闪烁。

代码实现如下:

def gameWonAnimation(board):

# 当玩家获胜时闪烁背景色

coveredBoxes = generateRevealedBoxesData(True)

color1 = LIGHTBGCOLOR

color2 = BGCOLOR

for i in range(6):

color1, color2 = color2, color1 # 墙的颜色

DISPLAYSURF.fill(color1)

drawBoard(board, coveredBoxes)

pygame.display.update()

pygame.time.wait(180)

(15)hasWon(revealedBoxes)

判断是否游戏胜利,当所有牌都是展示的时候就是游戏胜利,此时返回布尔值 True。

代码实现如下:

def hasWon(revealedBoxes):

# 判断是否胜利,胜利返回True 失败返回Falee

for i in revealedBoxes:

if False in i:

return False # 如果有覆盖的盒子,则返回False

return True

4. 实验。

4.1游戏界面展示

598428833b21

图2 游戏主界面

4.2 盒子图案展示

598428833b21

图3 游戏图案展示

4.3 翻牌成功展示

598428833b21

图4 游戏翻牌展示

598428833b21

图5 游戏翻牌

4.4 游戏胜利展示

598428833b21

图6 游戏胜利

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值