如果你没有任何编程经验,而且想尝试一下学习编程开发,这个系列教程一定适合你,它将带你学习最基本的Python语法,并让你掌握小游戏的开发技巧。你所需要的,就是付出一些时间和耐心来尝试这些代码和操作。

@[top]

一、准备工作

1 下载安装 python

2 下载安装 VS code编辑器

安装时,要注意勾选 添加到path



3 安装pygame模块

  • 在VisualStudioCode的顶部菜单【Terminal-New Teminal】打开命令行终端,然后输入命令python -m pip install --upgrade pip,回车,等待完成。

  • 然后同样输入命令pip install pygame,等待完成安装,可能需要几分钟

二、创建项目

  1. 在桌面上创建一个文件夹mygame,然后在VSCode中使用菜单【File-Open Folder】,选择mygame文件夹,VSCode左侧将会出现EXPLORER导航栏。

  2. 在左侧导航栏中,【右键-New File】创建文件main.py

- 将下面的代码粘贴到右侧`main.py`文件中。

import pygame
import sys
pygame.display.set_mode([600,400])
while 1:
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()

在这里我还是要说一下,文中素材以及可执行代码可以加群:456926667,获取,这个是我创建的一个针对0基础的伙伴一个交流群,下个文章我会更新关于pycharm版本的打地鼠。

  1. 运行代码。
*   仍然【Terminal-New terminal】终端中输入命令`python main.py`,这将运行我们上面的代码,看到弹出一个黑色窗口。

三、可选操作

  1. 执行上面的操作的时候,VSCode的右下角会经常弹出一些提示,如果有【Install】字样,可以放心的点击它进行安装更多内容。

  2. 也可以从左侧栏点击图标打开【EXTENSIONS】,然后搜索@id:ms-python.python,点击找到的结果,右侧再点击【Install】按钮进行安装。安装之后main.py文件的右上角就会出现三角形运行按钮,点击它同样可以运行代码,相当于终端中输入python main.py

  1. pip install ...安装命令太慢。Windows用户,可以从上面的网盘中下载pip.ini文件,然后在【C盘-用户-用户名】文件夹下面创建pip文件夹,再把下载的pip.ini文件拷贝进去,此后再运行pip install ...安装速度就会快很多。

  2. 对于苹果用户就麻烦很多。先在终端执行cd ~切换到用户文件夹,然后执行mkdir .pip创建.pip文件夹,它是隐身的,我们打开访达,从菜单执行【前往-前往文件夹...】,前往~/.test目录,把下载的pip.conf文件粘贴进去,搞定。

pip.ini或者pip.conf文件是把原来pip默认从国外下载安装改成了从国内下载,所以速度会变快很多。

  • 其中import是导入我们要使用的外部代码模块,pygame当然是必须的,syssystem系统的简写,因为我们的游戏要运行在系统(windows或者苹果macOS)上面,所以我们会用到系统的一些命令,比如下面的sys.exit()这个命令。

  • pyagme.display.set_mode([600,400]),这里的[600,400]是一对数字组合在一起的,叫二元数组,这里它表示宽600,高400的一个矩形。整句话就是设置要弹出的窗口的大小,display显示,set设置,mode模式

  • while 1:...当是1的时候,就...,1在代码里面表示正确的、真的、存在的,相反,0表示错误、假的、不存在的。while 1:do something那么something就会做,如果while 0: do something那么就不会做了。

  • for ... sys.exit()这一段暂时可以不深究,只是固定格式。只要知道它表示游戏程序运行结束的时候系统把窗口也关掉,清理好计算机不要留痕迹,exit退出

游戏开发的思路

游戏开发都有固定的套路,无论是打地鼠、愤怒的小鸟,还是西瓜忍者,甚至是王者荣耀这样的大型游戏,他们大致都遵循下面几个思路:

  1. 创建一个地图场景,上面可能有些道具。

    比如几个地鼠洞,一些可以放小猪的木盒子,甚至非常复杂的山谷地形,上面还有很多野怪。

    这些地图上的元素一般都是被动的,就是你不去靠近或招惹野怪的话,它们不会互相打起来自相残杀,同样,小鸟还没发射的时候,木盒子也不会自己倒塌。

  2. 创建至少一个玩家可以控制的元素,它可以和地图场景发生交互。

    这个可以被控制的元素我们称为玩家角色。在打地鼠游戏中这个角色就是一个锤子,愤怒的小鸟中这个角色其实是弹弓,弹出的小鸟其实是个道具,在王者荣耀游戏中玩家的角色就是自己的英雄。

  3. 必须要有评判标准,用来衡量输赢胜败。

    玩家控制的角色和地图场景进行交互,发生反应,对应的也必须要有一个评判标准,比如计算3分钟内击中地鼠的次数,或者计算砸死的绿猪的数量,或者是打野怪获得的经验,这些规则一定要清晰而且不能互相矛盾。

    大多数游戏都有输赢胜败,而胜败往往本质上只是谁的积分首先达到某个临界点。可以是某个关键道具的变化,比如对战游戏中塔被摧毁,也可以是玩家角色的属性变化,比如格斗游戏中被击杀;也可以只是纯粹的某项积分评比,用排行榜代替输赢。

游戏开发的技术点

  1. 要能够在窗口内绘制图形。

    可以是直接用代码绘制几何图形,也可以是载入图片显示内容。

  2. 要能用代码控制每个元素(道具和角色)的动画。

    动画就是一组图片不停地轮番变化。要能用代码控制播放和停止每个元素的动画,还能在不同动画之间快速切换。

  3. 能够接收用户的控制,并借此影响游戏中的元素。

    知道用户什么时候按了键盘,什么时候点了鼠标,按了哪个按键,鼠标左键还是右键?我们经常把这些操作称之为交互事件。

  4. 能够对游戏中各种元素产生的有效数据进行计算和管理。

    玩家角色一刀砍下去,怪物的血量减少了100点,这个就是数据,而且是很有用的数据,没有这个数据的话怪物可能永远砍不死了。

    有时候这些数据要保存好,让用户下一次打开游戏的时候仍然看到自己的等级和装备都还存在。有些时候这些数据要及时清理,比如新的一局又开始了,地图上的道具和角色都要恢复原样。

打地鼠游戏

我们可以把经典的打地鼠游戏简化概括为:

  • 地图和道具:随机位置出现地鼠图形
  • 交互角色:控制锤子图形,点击地鼠图形使其消失
  • 积分输赢:限定时间内击中地鼠图形的次数

核心玩法简化成一句话就是:点击随机出现图形。

绘制地鼠

我们用一个蓝色的圆形代表地鼠。那怎么在窗口中绘制一个圆形呢?

可以百度【pygame 画圆圈】类似的关键字,可以查到要使用pygame.draw.circle语句,它的具体语法可以从官方说明文档中找到,英文版详细说明点这里。

我们查到它的语法是:

pygame.draw.circle()
circle(surface, color, center, radius) -> Rect

这表示draw.circle()需要四个参数,分别是surface表面,color颜色,center中心点,radius半径

我们继续看surface参数的说明:

surface (Surface) -- surface to draw on

听上去像是画布,——先要有个画布才能在上面画圆。

点击Surface链接,找到更进一步说明:

Surface((width, height), flags=0, depth=0, masks=None) -> Surface

结尾的->Surface表示Surface((width....)这句话可以生成一个Surface表面,我们可以用下面的语句捕捉到这个生成的表面:

sur=pygame.Surface((600, 400)

这样,sur就是我们生成的表面了。

颜色和位置

再返回来看color参数:

color (Color or int or tuple(int, int, int, [int]))
-- color to draw with,
the alpha value is optional if using a tuple (RGB[A])

很明显它是表示画什么颜色的圆。tuple(int, int, int, [int])表示这里需要三个整数int一起表示颜色,RGB是指red红,green绿,blue蓝,alpha透明度

clr=(0,0,255) #蓝色

对于center中心位置我们也可以用同样的方法得到,这里的Vector2表示二元向量,及横向x和竖向y的位置:

pos=pygame.vector2(300,200) #窗口中央

绘制圆形

参数都具备了,那么就可以开始画圆了。运行下面的代码:

import pygame
import sys pygame.init() # 初始化
window = pygame.display.set_mode([600, 400]) # 设定窗口 sur = pygame.Surface([600, 400]) # 绘制背景容器
clr = (0, 0, 255)
pos = (300,200)
rad = 100 while 1:
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit() # 每帧循环执行的代码
pygame.draw.circle(sur, clr, pos, 100# 绘制圆 # 刷新画面
window.blit(sur, (0, 0))
pygame.display.flip()

注意这里最底部刷新画面的两行,其中window.blit(sur, (0, 0))表示把我们绘制好的表面sur刷新到window窗口中;pygame.display.flip()表示进行窗口刷新。

随机出现

随机出现就是随机位置,我们必须确保每一次花圆的pos位置都不同,而且应该是固定的几个地鼠洞位置。——别忘了我们要做打地鼠游戏。

假设有6个地鼠位置pos分别是[200,200],[300,200],[400,200],[200,300],[300,300],[400,300],那么如何随机取到6个中一个呢?也就是如何随机取到1~6其中的一个数字即可。

我们可以百度【python 随机数】查到需要使用random模块,这是python自带的模块,不需要再重新pip install

如果搜索【python random document】可以查找到官方的语法说明,如下:

random.randint(a, b)
Return a random integer N such that a <= N <= b.
Alias for randrange(a, b+1).

这是说可以随机生成ab之间的一个数字。也可以从中文的菜鸟教程网

学习到这个知识。

新建一个test.py文件,我们进行测试:

import random
a = random.randint(0, 5)
print(a)

每次运行都能生成不同的数字。

继续测试:

import random
a = random.randint(0, 6)
pos6=[[200,200],[300,200],[400,200],[200,300],[300,300],[400,300]]
print(pos6[a])

这里的pos6[a]表示pos6的六个位置中的第a个。运行这个代码就会每次生成不同的位置。

测试成功之后我们把它拷贝到刚才的画圆代码中,得到:

import pygame
import sys
import random pygame.init() # 初始化
window = pygame.display.set_mode([600, 400]) # 设定窗口 sur = pygame.Surface([600, 400]) # 绘制背景容器
clr = (0, 0, 255)
pos6 = [[200, 200], [300, 200], [400, 200], [
200, 300], [300, 300], [400, 300]] # !!六个位置
rad = 100 while 1:
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit() # 每帧循环执行的代码
sur.fill((0, 0, 0)) # !!用黑色覆盖前一帧的画面,实现刷新
a = random.randint(0, 5) # !!随机0到5
pygame.draw.circle(sur, clr, pos6[a], 100) # !!使用随机位置 # 刷新画面
window.blit(sur, (0, 0))
pygame.display.flip()

注意新增了sur.fill...一行,这是用黑色(0,0,0)来清理掉上一帧的内容,避免出现多个圆。

隔n帧刷新

上面的代码运行之后会看到蓝色的圆四处乱跳,太快了,我们希望改变位置之后能停一下,等我们锤它。

我们需要画面的圆每隔n帧再随机变换一次,而不是现在的每帧都随机变。思路是这样的:我们设定一个计数器,开始是0,每帧都给它增加1,就是0,1,2,3,4...直到它增到到超过50,这时候我们就改变圆的位置并同时把计数器重置为0。

代码如下:

import pygame
import sys
import random pygame.init() # 初始化
window = pygame.display.set_mode([600, 400]) # 设定窗口 sur = pygame.Surface([600, 400]) # 绘制背景容器
clr = (0, 0, 255)
pos6 = [[200, 200], [300, 200], [400, 200], [
200, 300], [300, 300], [400, 300]] # 六个位置
rad = 100
tick=0 #!!计数器 while 1:
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit() # 每帧循环执行的代码
if tick>50: #每50次刷新变换一次
sur.fill((0, 0, 0)) # 用黑色覆盖前一帧的画面,实现刷新
a = random.randint(0, 5) # 随机0到5
pygame.draw.circle(sur, clr, pos6[a], 100) # 使用随机位置
tick=0
else: #!!不刷新变换的时候
tick=tick+1 #!!增加计数器 # 刷新画面
window.blit(sur, (0, 0))
pygame.display.flip()

增加交互点击

当用户点击画面的时候,我们要知道它点击了哪里,是否点击到了我们画的圆上面。

百度搜索【pygame 点击】可以找到相关资源,也可以直接在官方说明文档中找到

思路是我们添加对event.type事件类型的实时监测,一旦发现点击事件就获取位置坐标。代码如下:

import pygame
import sys
import random
from pygame.locals import * # 引入鼠标事件类型 pygame.init() # 初始化
window = pygame.display.set_mode([600, 400]) # 设定窗口 sur = pygame.Surface([600, 400]) # 绘制背景容器
clr = (0, 0, 255)
pos6 = [[200, 200], [300, 200], [400, 200], [
200, 300], [300, 300], [400, 300]] # 六个位置
rad = 100
tick = 0 # !!计数器
pos = pos6[0] # !!在外面记录圆的位置 while 1:
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
elif event.type == MOUSEBUTTONDOWN: # !!如果是鼠标按下事件
mpos = pygame.mouse.get_pos() # !!获取鼠标位置
print(mpos) # 每帧循环执行的代码
if tick > 50: # 每50次刷新变换一次
sur.fill((0, 0, 0)) # 用黑色覆盖前一帧的画面,实现刷新
a = random.randint(0, 5) # 随机0到5
pos = pos6[a] # !!更新外部记录的圆的位置
pygame.draw.circle(sur, clr, pos, 100) # !!使用随机位置
tick = 0 # 重置计数器
else: # !!不刷新变换的时候
tick = tick+1 # !!增加计数器 # 刷新画面
window.blit(sur, (0, 0))
pygame.display.flip()

运行这个代码,任意点击屏幕上的时候就会打印出档期鼠标点击的位置。

距离测量

知道当前圆的位置pos,也知道当前点击的位置mpos,这样我们就可以计算出两点之间的距离,距离大于圆半径的就是没有点到地鼠,距离小于半径的就是点到地鼠了。

百度搜索【pygame 两点距离】可以搜到一些计算距离的方法,我们这里使用pygame官方提供的方法,测试下面代码:

import pygame
a=pygame.math.Vector2.length(pygame.math.Vector2(3,4))
print(a)

它会输出5(勾三股四玄五)。这里的(3,4)posmpos相减得到的差。

把这个思路带入原来的代码,得到:

import pygame
import sys
import random
from pygame.locals import * # 引入鼠标事件类型 pygame.init() # 初始化
window = pygame.display.set_mode([600, 400]) # 设定窗口 sur = pygame.Surface([600, 400]) # 绘制背景容器
clr = (0, 0, 255)
pos6 = [[200, 200], [300, 200], [400, 200], [
200, 300], [300, 300], [400, 300]] # 六个位置
rad = 50
tick = 0 # 计数器
pos = pos6[0] # 外面记录圆的位置 while 1:
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
elif event.type == MOUSEBUTTONDOWN: # 如果是鼠标按下事件
mpos = pygame.mouse.get_pos() # 获取鼠标位置
dis = pygame.math.Vector2(
mpos[0]-pos[0], mpos[1]-pos[1]) # !!计算坐标差
len = pygame.math.Vector2.length(dis) # !!计算距离
if len < rad:
tick = 51 # !!立即变换位置 # 每帧循环执行的代码
if tick > 50: # 每50次刷新变换一次
sur.fill((0, 0, 0)) # 用黑色覆盖前一帧的画面,实现刷新
a = random.randint(0, 5) # 随机0到5
pos = pos6[a] # 更新外部记录的圆的位置
pygame.draw.circle(sur, clr, pos, 100) # 使用随机位置
tick = 0 # 重置计数器
else: # 不刷新变换的时候
tick = tick+1 # 增加计数器 # 刷新画面
window.blit(sur, (0, 0))
pygame.display.flip()

在这里我们设定如果距离长度len小于圆半径rad,那么就立即设置tick=51使它大于50,立即进行随机位置变换。

截止到这里运行上面的代码,可以实现随机出现地鼠(圆)并能够点击使它消失,这也实现了游戏的最基本逻辑功能。后续我们将进一步编写更多内容,让它更完善一些。

记录分数

计算数字增加很容易,设定一个score=0,然后击中地鼠的时候增加1就可以了。但是,如何把它显示到屏幕上呢?

可以百度搜索【pygame 显示文字】然后就可以找到大致方法,我们先进行一些测试:

import pygame

pygame.init()  # 初始化
window = pygame.display.set_mode([600, 400]) # 设定窗口 # 显示文字
pygame.font.init() # !!初始化文字
font = pygame.font.SysFont('微软雅黑', 30) # !!设定字体和字号
sur = font.render("Hello World!!{}".format(999), False, (255, 0, 0)) # !!生成w文字表面 while 1:
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit() window.blit(sur, (200, 10)) # !!增加分数表面
pygame.display.flip()

这段代码中可以看到pygame绘制文字分三步:

  • pygame.font.init()先要初始化
  • pygame.font.SysFont('微软雅黑', 30)设定字体和字号大小
  • font.render("Hello World!!{}".format(999), False, (255, 0, 0))生成一个Surface表面

    当然,最后别忘了把表面放到窗口里window.blit(sur, (200, 10))

运行上面的代码得到一个窗口如下:

我们根据这个经验改进的代码:

import pygame
import sys
import random
from pygame.locals import * # 引入鼠标事件类型 pygame.init() # 初始化
window = pygame.display.set_mode([600, 400]) # 设定窗口 sur = pygame.Surface([600, 400]) # 绘制背景容器
clr = (0, 0, 255)
pos6 = [[200, 200], [300, 200], [400, 200], [
200, 300], [300, 300], [400, 300]] # 六个位置
rad = 50
tick = 0 # 计数器
pos = pos6[0] # 外面记录圆的位置 # 分数
score = 0 # !!分数计数
pygame.font.init() # !!初始化文字
score_font = pygame.font.SysFont('微软雅黑', 30) # !!设定字体和字号
score_sur = score_font.render(str(score), False, (255, 0, 0)) # !!生成计数表面 while 1:
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
elif event.type == MOUSEBUTTONDOWN: # 如果是鼠标按下事件
mpos = pygame.mouse.get_pos() # 获取鼠标位置
dis = pygame.math.Vector2(
mpos[0]-pos[0], mpos[1]-pos[1]) # 计算坐标差
len = pygame.math.Vector2.length(dis) # 计算距离
if len < rad:
tick = 1000 # 立即变换位置
score = score+1 # 计分增加 # 每帧循环执行的代码
if tick > 50: # 每50次刷新变换一次
score_sur = score_font.render(
str(score), False, (255, 0, 0)) # !!重新生成分数文字表面
sur.fill((0, 0, 0)) # 用黑色覆盖前一帧的画面,实现刷新
a = random.randint(0, 5) # 随机0到5
pos = pos6[a] # 更新外部记录的圆的位置
pygame.draw.circle(sur, clr, pos, 50) # 使用随机位置
tick = 0 # 重置计数器
else: # 不刷新变换的时候
tick = tick+1 # 增加计数器 # 刷新画面
window.blit(sur, (0, 0))
window.blit(score_sur, (200, 10)) # !!增加分数表面
pygame.display.flip()

运行上面的代码,可以用鼠标点击跳动的蓝色圆,每次击中就能获得1分,实时显示在顶部。

关于文字的更多内容可以参考官方文档说明

鼠标指针变锤子

现在窗口中显示的仍然是鼠标,而不是锤子,下面我们来看如何把鼠标变为一个特定的图形。

pygame关于鼠标控制的模块是pygame.mouse官方说明文档看这里。

我们可以用pygame.mouse.set_visible(False)来隐藏鼠标,但这样一来我们就看不到鼠标无法操作了。

不过不要紧,我们之前还记得当鼠标点击的时候有一个mpos = pygame.mouse.get_pos()可以获取当前鼠标的位置,同样我们可以在鼠标移动的时候获取鼠标的位置,然后在这个位置上画一个红色圆圈代表鼠标。

测试下面的代码:

import pygame
from pygame.locals import * pygame.init()
window = pygame.display.set_mode([600, 400]) pygame.mouse.set_visible(False) # 隐藏鼠标
sur = pygame.Surface([600, 400])
mpos = [300, 200] # 记录鼠标位置 while 1:
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
elif event.type == MOUSEMOTION: # 当鼠标移动的时候
mpos = pygame.mouse.get_pos() # 更新鼠标位置 sur.fill((0, 0, 0)) # 填充黑色
pygame.draw.circle(sur, (255, 0, 0), mpos, 10) # 在鼠标位置画红色圆
window.blit(sur, (0, 0))
pygame.display.flip()

运行这个代码将,当鼠标划到窗口上面的时候就会有一个红点跟着鼠标移动,红点代替了原来的指针。

我们把这个红点鼠标代码放入到游戏中,得到下面的代码:

import pygame
import sys
import random
from pygame.locals import * # 引入鼠标事件类型 pygame.init() # 初始化
window = pygame.display.set_mode([600, 400]) # 设定窗口 sur = pygame.Surface([600, 400]) # 绘制背景容器
clr = (0, 0, 255)
pos6 = [[200, 200], [300, 200], [400, 200], [
200, 300], [300, 300], [400, 300]] # 六个位置
rad = 50
tick = 0 # 计数器
pos = pos6[0] # 外面记录圆的位置 # 分数
score = 0 # 分数计数
pygame.font.init() # 初始化文字
score_font = pygame.font.SysFont('微软雅黑', 30) # !!设定字体和字号
score_sur = score_font.render(str(score), False, (255, 0, 0)) # !!生成计数表面 # 鼠标
pygame.mouse.set_visible(False) # !!隐藏鼠标
mpos = [300, 200] # !!记录鼠标位置 while 1:
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
elif event.type == MOUSEBUTTONDOWN: # 如果是鼠标按下事件
mpos = pygame.mouse.get_pos() # 获取鼠标位置
dis = pygame.math.Vector2(
mpos[0]-pos[0], mpos[1]-pos[1]) # 计算坐标差
len = pygame.math.Vector2.length(dis) # 计算距离
if len < rad:
tick = 1000 # 立即变换位置
score = score+1 # 计分增加
elif event.type == MOUSEMOTION: # !!当鼠标移动的时候
mpos = pygame.mouse.get_pos() # !!更新鼠标位置 # 每帧循环执行的代码
if tick > 50: # 每50次刷新变换一次
score_sur = score_font.render(
str(score), False, (255, 0, 0)) # 重新生成分数文字表面
a = random.randint(0, 5) # 随机0到5
pos = pos6[a] # 更新外部记录的圆的位置
tick = 0 # 重置计数器
else: # 不刷新变换的时候
tick = tick+1 # 增加计数器 # 绘制鼠标
sur.fill((0, 0, 0)) # !用黑色覆盖前一帧的画面,实现刷新
pygame.draw.circle(sur, clr, pos, 50) # !使用随机位置画地鼠
pygame.draw.circle(sur, (255, 0, 0), mpos, 10) # !!在鼠标位置画红色圆 # 刷新画面
window.blit(sur, (0, 0))
window.blit(score_sur, (200, 10)) # 增加分数表面
pygame.display.flip()

主义者了把sur.fill和原来画地鼠蓝圆的代码移到了下面,和画鼠标红点的代码放在了一起,这样把绘图内容放在一起更加合理。

限定每局时间

我们有很多办法限定每局的长度,比如计时限定1分钟,或者限定地鼠跳出总计100次。我们这里使用第二种限制,跳出100次就结束并统计分数。

添加一个计数器times=0,然后每次随机位置都给它增加1,当times>100的时候,我们就结束游戏并显示结束画面统计战果。

具体的代码没有新的内容,不多解释,直接上结果:

import pygame
import sys
import random
from pygame.locals import * # 引入鼠标事件类型 pygame.init() # 初始化
window = pygame.display.set_mode([600, 400]) # 设定窗口 sur = pygame.Surface([600, 400]) # 绘制背景容器
clr = (0, 0, 255)
pos6 = [[200, 200], [300, 200], [400, 200], [
200, 300], [300, 300], [400, 300]] # 六个位置
rad = 50
tick = 0 # 计数器
pos = pos6[0] # 外面记录圆的位置 # 分数
score = 0 # 分数计数
pygame.font.init() # 初始化文字
score_font = pygame.font.SysFont('微软雅黑', 30) # !!设定字体和字号
score_sur = score_font.render(str(score), False, (255, 0, 0)) # !!生成计数表面 # 鼠标
pygame.mouse.set_visible(False) # !!隐藏鼠标
mpos = [300, 200] # !!记录鼠标位置 times = 0 # 地鼠跳出的次数
times_max=10 #最多次数
tick_max=15 #地鼠每次跳多少帧 while 1:
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
elif event.type == MOUSEBUTTONDOWN: # 如果是鼠标按下事件
mpos = pygame.mouse.get_pos() # 获取鼠标位置
dis = pygame.math.Vector2(
mpos[0]-pos[0], mpos[1]-pos[1]) # 计算坐标差
len = pygame.math.Vector2.length(dis) # 计算距离
if len < rad:
tick = 1000 # 立即变换位置
score = score+1 # 计分增加
elif event.type == MOUSEMOTION: # !!当鼠标移动的时候
mpos = pygame.mouse.get_pos() # !!更新鼠标位置 if times > times_max:
# 显示结束画面
sur.fill((0, 0, 0))
pygame.mouse.set_visible(True)
sur.fill((0, 0, 0))
end_font = pygame.font.SysFont('微软雅黑', 80) # !!设定字体和字号
end_sur = score_font.render("Your Score is:{}/{}!".format(score,times_max), False, (255, 0, 0)) # !!生成计数表面
window.blit(sur, (0, 0))
window.blit(end_sur, (100, 100)) # 增加分数表面
pygame.display.flip()
else:
# 每帧循环执行的代码
if tick > tick_max: # 每50次刷新变换一次
times=times+1 #增加计次
score_sur = score_font.render(
str(score), False, (255, 0, 0)) # 重新生成分数文字表面
a = random.randint(0, 5) # 随机0到5
pos = pos6[a] # 更新外部记录的圆的位置
tick = 0 # 重置计数器
else: # 不刷新变换的时候
tick = tick+1 # 增加计数器 # 绘制鼠标
sur.fill((0, 0, 0)) # !用黑色覆盖前一帧的画面,实现刷新
pygame.draw.circle(sur, clr, pos, 50) # !使用随机位置画地鼠
pygame.draw.circle(sur, (255, 0, 0), mpos, 10) # !!在鼠标位置画红色圆 # 刷新画面
window.blit(sur, (0, 0))
window.blit(score_sur, (200, 10)) # 增加分数表面
pygame.display.flip()

运行这个代码,用鼠标点击蓝圆,蓝圆跳动10次之后结束,然后显示击中的次数。你可以通过调整tick_max的数字让圆跳动的更快或更慢,调整times_max=100来让地鼠跳动100次后再结束。

现在我们的地鼠游戏已经有些模样了,但还都是蓝色红色的圆圈和圆点,下一篇我们来改变成为图片。

中文字体

在上一节中我们只使用了英文字体,怎么显示中文字体呢?

直接下载网盘里面的文件,放在你的main.py一起,将原来的

score_font = pygame.font.SysFont('微软雅黑', 30)

修改为:

score_font = pygame.font.Font('MicrosoftYaqiHeiLight-2.ttf', 30) 

然后在render里面使用中文就可以正常显示了:

end_sur = score_font.render("你的得分:{}/{}!".format(score,times_max), False, (255, 0, 0))

另外,也可以使用系统的中文字体,但是我们不清楚系统里面到底装了哪些字体,可以用print(pygame.font.get_fonts())将所有系统字体都打印出来,然后只能从名字猜出哪些是中文字体了,注意系统字体还是要用font.SysFont而不只是font.Font

显示背景图片

这是我们的背景图片dds-map.jpg

我们可以用map=pygame.image.load('dds-map.jpg')把图片读取到代码里面。

更多官方关于图片的操作说明看这里

注意pygame.image.load()得到的是一个表面surface,我们可以直接把它blit到窗口wind,也可以把它blit到。

这里是完整代码:

import pygame
import sys
import random
from pygame.locals import * # 引入鼠标事件类型 pygame.init() # 初始化
window = pygame.display.set_mode([600, 400]) # 设定窗口 sur = pygame.Surface([600, 400]) # 绘制背景容器
clr = (0, 0, 255)
posAll = [[100, 150], [300, 150], [500, 150], [
200, 300], [400, 300]] # 六个位置
rad = 50
tick = 0 # 计数器
pos = posAll[0] # 外面记录圆的位置 # 分数
score = 0 # 分数计数
pygame.font.init() # 初始化文字
score_font = pygame.font.Font('MicrosoftYaqiHeiLight-2.ttf', 30) # !!设定字体和字号
score_sur = score_font.render(str(score), False, (255, 0, 0)) # !!生成计数表面 # 鼠标
pygame.mouse.set_visible(False) # !!隐藏鼠标
mpos = [300, 200] # !!记录鼠标位置 times = 0 # 地鼠跳出的次数
times_max=10 #最多次数
tick_max=30 #地鼠每次跳多少帧
map=pygame.image.load('dds-map.jpg')#!!读取图片 while 1:
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
elif event.type == MOUSEBUTTONDOWN: # 如果是鼠标按下事件
dis = pygame.math.Vector2(
mpos[0]-pos[0], mpos[1]-pos[1]) # 计算坐标差
len = pygame.math.Vector2.length(dis) # 计算距离
if len < rad:
tick = 1000 # 立即变换位置
score = score+1 # 计分增加
elif event.type == MOUSEMOTION: # 当鼠标移动的时候
mpos = pygame.mouse.get_pos() # 更新鼠标位置 if times >= times_max:
# 显示结束画面
sur.fill((0, 0, 0)) #!!结束时候仍然用黑色清空画面
pygame.mouse.set_visible(True)
end_font = pygame.font.Font('MicrosoftYaqiHeiLight-2.ttf',48) # !!设定字体和字号
end_sur = score_font.render("你的分数是:{}/{}!".format(score,times_max), True, (255, 0, 0)) # !!生成计数表面
window.blit(sur, (0, 0))
window.blit(end_sur, (100, 100)) # 增加分数表面
else:
sur.blit(map, (0, 0)) #!!添加背景图片
# 每帧循环执行的代码
if tick > tick_max: # 每50次刷新变换一次
times=times+1 #增加计次
score_sur = score_font.render(
"分数:{}/{}!".format(score,times), False, (255, 0, 0)) # 重新生成分数文字表面
a = random.randint(0, 4) # 随机0到4
pos = posAll[a] # 更新外部记录的圆的位置
tick = 0 # 重置计数器
else: # 不刷新变换的时候
tick = tick+1 # 增加计数器 # 绘制鼠标
pygame.draw.circle(sur, clr, pos, 50) # 使用随机位置画地鼠
pygame.draw.circle(sur, (255, 0, 0), mpos, 10) # !在鼠标位置画红色圆 # 刷新画面
window.blit(sur, (0, 0))
window.blit(score_sur, (200, 10)) # 增加分数表面
pygame.display.flip() #刷新画面

注意我们先把图片读取,然后在每帧里面决定是否使用。运行后如下图:

使用动态图片

地鼠和锤子各有两个状态,正常的地鼠和被击打的地鼠,正常的锤子和砸下的锤子,如下图所示(下图无法直接使用,请从网盘下载):

我们可以先把四个图片都load读取进来成为rat1,rat2,ham1,ham2,然后我们使用ratsurhamsur表示真正要使用的表面,当鼠标按下的时候我们设定hamsur=ham2是砸下图片,当鼠标点击位置距离地鼠小于地鼠半径的时候我们使用ratsur=rat2被砸中的图片。最后我们再分别把地鼠和锤头blitsur上面。

改造后的代码如下:

import pygame
import sys
import random
from pygame.locals import * # 引入鼠标事件类型
import time pygame.init() # 初始化
window = pygame.display.set_mode([600, 400]) # 设定窗口 sur = pygame.Surface([600, 400]) # 绘制背景容器
clr = (0, 0, 255)
posAll = [[100, 150], [300, 150], [500, 150], [
200, 300], [400, 300]] # 六个位置
rad = 50
tick = 0 # 计数器
pos = posAll[0] # 外面记录圆的位置 # 分数
score = 0 # 分数计数
pygame.font.init() # 初始化文字
score_font = pygame.font.Font('MicrosoftYaqiHeiLight-2.ttf', 30) # !!设定字体和字号
score_sur = score_font.render(str(score), False, (255, 0, 0)) # !!生成计数表面 # 鼠标
pygame.mouse.set_visible(False) # !!隐藏鼠标
mpos = [300, 200] # !!记录鼠标位置 times = 0 # 地鼠跳出的次数
times_max=10 #最多次数
tick_max=30 #地鼠每次跳多少帧
map=pygame.image.load('dds-map.jpg')#!!读取图片
rat1=pygame.image.load('rat1.png')#!!读取地鼠图片
rat2=pygame.image.load('rat2.png')#!!读取被砸地鼠图片
ham1=pygame.image.load('hammer1.png')#!!读取锤子图片
ham2=pygame.image.load('hammer2.png')#!!读取砸下锤子图片 while 1:
hamsur=ham1
ratsur=rat1
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
elif event.type == MOUSEBUTTONDOWN: # 如果是鼠标按下事件
hamsur=ham2 #!!使用下落锤子
mpos = pygame.mouse.get_pos() # 获取鼠标位置
dis = pygame.math.Vector2(
mpos[0]-pos[0], mpos[1]-pos[1]) # 计算坐标差
len = pygame.math.Vector2.length(dis) # 计算距离
if len < rad:
tick = 1000 # 立即变换位置
score = score+1 # 计分增加
ratsur=rat2 #!!使用被砸地鼠
elif event.type == MOUSEMOTION: # 当鼠标移动的时候
mpos = pygame.mouse.get_pos() # 更新鼠标位置 if times >= times_max:
# 显示结束画面
sur.fill((0, 0, 0)) #结束时候仍然用黑色清空画面
pygame.mouse.set_visible(True)
end_font = pygame.font.Font('MicrosoftYaqiHeiLight-2.ttf',48) # !!设定字体和字号
end_sur = score_font.render("你的分数是:{}/{}!".format(score,times_max), True, (255, 0, 0)) # !!生成计数表面
window.blit(sur, (0, 0))
window.blit(end_sur, (100, 100)) # 增加分数表面
else:
sur.blit(map, (0, 0)) #添加背景图片
# 每帧循环执行的代码
if tick > tick_max: # 每50次刷新变换一次
times=times+1 #增加计次
score_sur = score_font.render(
"分数:{}/{}!".format(score,times), False, (255, 0, 0)) # 重新生成分数文字表面
a = random.randint(0, 4) # 随机0到4
pos = posAll[a] # 更新外部记录的圆的位置
tick = 0 # 重置计数器
else: # 不刷新变换的时候
tick = tick+1 # 增加计数器 sur.blit(ratsur,(pos[0]-50,pos[1]-70)) #绘制地鼠
sur.blit(hamsur,(mpos[0]-50,mpos[1]-100)) #绘制锤头 # 刷新画面
window.blit(sur, (0, 0))
window.blit(score_sur, (200, 10)) # 增加分数表面
pygame.display.flip() #刷新画面
time.sleep(0.04) #!!保持画面一点时间

注意这里的import timetime.sleep(0.04)这是让每一帧停留一点点时间,0.04秒,每秒25帧(假设每帧画图不需要时间的话)。

另外我们再blit的时候使用了(pos[0]-50,pos[1]-50)这样的偏移,因为图片总是用左上角作为位置的起点,这样偏移之后就变到了图片中心,实际上我们又故意让地鼠和锤子更高一些,就使用了(pos[0]-50,pos[1]-70)

运行之后的样子如下图:

让游戏重新开始

每次显示最终成绩之后,能不能让游戏3秒后重新开始呢?

我们设定一个gameover=0,游戏结束后每帧都增加这个数字,如果gameover>100,就是过了100帧,那么我们就重新开始。

重新开始必须意味着各种数据(分数,计时什么的)和画面都要重置到原来的状态。

修改后的整体代码如下:

import pygame
import sys
import random
from pygame.locals import * # 引入鼠标事件类型
import time pygame.init() # 初始化
window = pygame.display.set_mode([600, 400]) # 设定窗口 sur = pygame.Surface([600, 400]) # 绘制背景容器
clr = (0, 0, 255)
posAll = [[100, 150], [300, 150], [500, 150], [200, 300], [400, 300]] # 六个位置
rad = 50
tick = 0 # 计数器
pos = posAll[0] # 外面记录圆的位置 # 分数
score = 0 # 分数计数
pygame.font.init() # 初始化文字
score_font = pygame.font.Font("MicrosoftYaqiHeiLight-2.ttf", 30) # !!设定字体和字号
score_sur = score_font.render(str(score), False, (255, 0, 0)) # !!生成计数表面 # 鼠标
pygame.mouse.set_visible(False) # !!隐藏鼠标
mpos = [300, 200] # !!记录鼠标位置 times = 0 # 地鼠跳出的次数
times_max = 10 # 最多次数
tick_max = 30 # 地鼠每次跳多少帧
map = pygame.image.load("dds-map.jpg") # !!读取图片
rat1 = pygame.image.load("rat1.png") # !!读取地鼠图片
rat2 = pygame.image.load("rat2.png") # !!读取被砸地鼠图片
ham1 = pygame.image.load("hammer1.png") # !!读取锤子图片
ham2 = pygame.image.load("hammer2.png") # !!读取砸下锤子图片 gameover = 0 #!!结束计时
gameover_max = 100 #!!结束计时最大值,超过这个值就重新开始 while 1:
hamsur = ham1
ratsur = rat1
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
elif event.type == MOUSEBUTTONDOWN: # 如果是鼠标按下事件
hamsur = ham2 # !!使用下落锤子
mpos = pygame.mouse.get_pos() # 获取鼠标位置
dis = pygame.math.Vector2(mpos[0] - pos[0], mpos[1] - pos[1]) # 计算坐标差
len = pygame.math.Vector2.length(dis) # 计算距离
if len < rad:
tick = 1000 # 立即变换位置
score = score + 1 # 计分增加
ratsur = rat2 # !!使用被砸地鼠
elif event.type == MOUSEMOTION: # 当鼠标移动的时候
mpos = pygame.mouse.get_pos() # 更新鼠标位置 if times >= times_max:
# 显示结束画面
sur.fill((0, 0, 0)) # 结束时候仍然用黑色清空画面
pygame.mouse.set_visible(True)
end_font = pygame.font.Font("MicrosoftYaqiHeiLight-2.ttf", 48) # !!设定字体和字号
end_sur = score_font.render(
"你的分数是:{}/{}!".format(score, times_max), True, (255, 0, 0)
) # !!生成计数表面
sur.blit(end_sur, (100, 150))
cd = int((gameover_max - gameover) / 10)
cd_sur = score_font.render(
"重新开始倒计时{}".format(cd), True, (255, 0, 0)
) # !!生成计数表面
sur.blit(cd_sur, (100, 200)) # 增加分数表面
gameover = gameover + 1 #!!增加结束计时
else:
sur.blit(map, (0, 0)) # 添加背景图片
score_sur = score_font.render(
"分数:{}/{}!".format(score, times + 1), False, (255, 0, 0)
) # 重新生成分数文字表面
sur.blit(score_sur, (200, 10)) # 增加分数表面
if tick > tick_max: # 每50次刷新变换一次
times = times + 1 # 增加计次
a = random.randint(0, 4) # 随机0到4
pos = posAll[a] # 更新外部记录的圆的位置
tick = 0 # 重置计数器
else: # 不刷新变换的时候
tick = tick + 1 # 增加计数器
if tick > 5: # 开始几帧不显示地鼠
sur.blit(ratsur, (pos[0] - 50, pos[1] - 70)) # 绘制地鼠
sur.blit(hamsur, (mpos[0] - 50, mpos[1] - 100)) # 绘制锤头 # 刷新画面
window.blit(sur, (0, 0))
pygame.display.flip() # 刷新画面
time.sleep(0.04) # !!保持画面一点时间 # !!重置游戏
if gameover > gameover_max:
pygame.mouse.set_visible(False)
times = 0
score = 0
gameover = 0

运行这个代码就能反复玩游戏了。

到这里游戏看上去好了很多,但是还没有背景音乐,打地鼠的时候也没有音效,下一节我们继续添加声音。

添加音效

游戏里面的声音分为两种,一种叫音乐music,另一种叫音效sound。背景音乐是music,游戏里面的击打声点击声都是音效。同一时间播放的音乐一般只有一个,但音效可以有很多个同时播放。

pygame可以使用pygame.mixer.music.load('bg.mp3')来载入foo.mp3音乐,然后pygame.mixer.music.play(0)就可以播放,这里0表示播放1次,如果要无限次的播放则要改为-1.

但是如果要播放音效sound,那么pygame里面只能使用wav格式(并且不支持32位深,只支持16位深)。载入音效的方法是sd=pygame.mixer.Sound("hit.wav"),播放是sd.play(0),这里0也是1次,一般音效不需要连续播放。

我们在游戏一开始就可以播放背景音乐了,但只有在点击鼠标event.type == MOUSEBUTTONDOWN的时候才播放锤子的声音,只有在击中地鼠的时候才播放地鼠的叫声。

修改之后的代码如下:

import pygame
import sys
import random
from pygame.locals import * # 引入鼠标事件类型
import time pygame.init() # 初始化
window = pygame.display.set_mode([600, 400]) # 设定窗口 sur = pygame.Surface([600, 400]) # 绘制背景容器
clr = (0, 0, 255)
posAll = [[100, 150], [300, 150], [500, 150], [200, 300], [400, 300]] # 六个位置
rad = 50
tick = 0 # 计数器
pos = posAll[0] # 外面记录圆的位置 # 分数
score = 0 # 分数计数
pygame.font.init() # 初始化文字
score_font = pygame.font.Font("MicrosoftYaqiHeiLight-2.ttf", 30) # !!设定字体和字号
score_sur = score_font.render(str(score), False, (255, 0, 0)) # !!生成计数表面 # 鼠标
pygame.mouse.set_visible(False) # !!隐藏鼠标
mpos = [300, 200] # !!记录鼠标位置 times = 0 # 地鼠跳出的次数
times_max = 10 # 最多次数
tick_max = 30 # 地鼠每次跳多少帧
map = pygame.image.load("dds-map.jpg") # !!读取图片
rat1 = pygame.image.load("rat1.png") # !!读取地鼠图片
rat2 = pygame.image.load("rat2.png") # !!读取被砸地鼠图片
ham1 = pygame.image.load("hammer1.png") # !!读取锤子图片
ham2 = pygame.image.load("hammer2.png") # !!读取砸下锤子图片 gameover = 0 # !!结束计时
gameover_max = 100 # !!结束计时最大值,超过这个值就重新开始 # 音乐和音效
pygame.mixer.music.load("bg.mp3") # !!载入背景音乐
pygame.mixer.music.play(-1) # !!无限播放背景音乐
hitsound = pygame.mixer.Sound("hit.wav") # !!载入击打声音
hurtsound = pygame.mixer.Sound("aiyo2.wav") # !!载入地鼠叫声 while 1:
hamsur = ham1
ratsur = rat1
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
elif event.type == MOUSEBUTTONDOWN: # 如果是鼠标按下事件
hamsur = ham2 # 使用下落锤子
hitsound.play() # !!播放击打声音
mpos = pygame.mouse.get_pos() # 获取鼠标位置
dis = pygame.math.Vector2(mpos[0] - pos[0], mpos[1] - pos[1]) # 计算坐标差
len = pygame.math.Vector2.length(dis) # 计算距离
if len < rad:
tick = 1000 # 立即变换位置
score = score + 1 # 计分增加
ratsur = rat2 # 使用被砸地鼠
hurtsound.play() # !!播放地鼠声音
elif event.type == MOUSEMOTION: # 当鼠标移动的时候
mpos = pygame.mouse.get_pos() # 更新鼠标位置 if times >= times_max:
# 显示结束画面
sur.fill((0, 0, 0)) # 结束时候仍然用黑色清空画面
pygame.mouse.set_visible(True)
end_font = pygame.font.Font("MicrosoftYaqiHeiLight-2.ttf", 48) # 设定字体和字号
end_sur = score_font.render(
"你的分数是:{}/{}!".format(score, times_max), True, (255, 0, 0)
) # 生成计数表面
sur.blit(end_sur, (100, 150))
cd = int((gameover_max - gameover) / 10)
cd_sur = score_font.render(
"重新开始倒计时{}".format(cd), True, (255, 0, 0)
) # 生成计数表面
sur.blit(cd_sur, (100, 200)) # 增加分数表面
gameover = gameover + 1 # !!增加结束计时
else:
sur.blit(map, (0, 0)) # 添加背景图片
score_sur = score_font.render(
"分数:{}/{}!".format(score, times + 1), False, (255, 0, 0)
) # 重新生成分数文字表面
sur.blit(score_sur, (200, 10)) # 增加分数表面
if tick > tick_max: # 每50次刷新变换一次
times = times + 1 # 增加计次
a = random.randint(0, 4) # 随机0到4
pos = posAll[a] # 更新外部记录的圆的位置
tick = 0 # 重置计数器
else: # 不刷新变换的时候
tick = tick + 1 # 增加计数器
if tick > 5: # 开始几帧不显示地鼠
sur.blit(ratsur, (pos[0] - 50, pos[1] - 70)) # 绘制地鼠
sur.blit(hamsur, (mpos[0] - 50, mpos[1] - 100)) # 绘制锤头 # 刷新画面
window.blit(sur, (0, 0))
pygame.display.flip() # 刷新画面
time.sleep(0.04) # 保持画面一点时间 # 重置游戏
if gameover > gameover_max:
pygame.mouse.set_visible(False)
times = 0
score = 0
gameover = 0

运行上面的代码,可以听到欢快的背景音乐,点击鼠标时候会有捶地声音,打中地鼠会有哎呦的叫声。

发布软件

我们写的代码目前只能在自己的电脑上运行,因为我们先要安装python,然后还要安装pygame才行,这和我们平常下载的软件不同,下载的软件可以直接运行(或者安装自身后运行)。

Python给我们提供了自动把代码打包成软件的工具,Windows下推荐使用auto-py-to-exe工具。同样先安装pip install auto-py-to-exe,然后只要执行auto-py-to-exe就会打开一个窗口。

基本设置如下:

注意几个地方:

  • Script Location要指向你的主要.py文件,这里是main.py
  • Onefile选One Directory,这会把生产的所有文件放在一个文件夹中
  • Console Window选Console Based,因为我们的pygame是基于控制台的
  • Icon图标,你可以在网上下载.ico文件,比如easyicon有很多,网盘里面有一个地鼠图标icon.ico
  • Additional Files附加文件,点击Add Files按钮要把全部用到的字体、图片、声音都选择
  • CONVERT .PY TO .EXE点击这个按钮进行生成,生成后会变为两个蓝色按钮

点击OPEN OUTPUT FOLDER打开生产的软件目录(默认在你的代码文件夹下面的output文件夹内),找到那个和你的Script Location同名的文件,点击它就可以运行游戏了。

也可以把这个MAIN.exe复制然后在桌面上粘贴快捷方式,以后只要点这个快捷方式就可以了。

在网盘文件中包含一个main.rar文件,下载它然后解压就可以得到我打包生成的软件了。

关于Mac苹果电脑下面生成软件的方法暂时遇到一点麻烦,搞定之后再更新,敬请关注。

第一个小游戏似乎开发完成了,但是还有很多内容,我们的代码也有很多不合理的地方,下一篇我们一起来回顾和整理,并且继续介绍更多小游戏的开发方法。

添加音效

游戏里面的声音分为两种,一种叫音乐music,另一种叫音效sound。背景音乐是music,游戏里面的击打声点击声都是音效。同一时间播放的音乐一般只有一个,但音效可以有很多个同时播放。

pygame可以使用pygame.mixer.music.load('bg.mp3')来载入foo.mp3音乐,然后pygame.mixer.music.play(0)就可以播放,这里0表示播放1次,如果要无限次的播放则要改为-1.

但是如果要播放音效sound,那么pygame里面只能使用wav格式(并且不支持32位深,只支持16位深)。载入音效的方法是sd=pygame.mixer.Sound("hit.wav"),播放是sd.play(0),这里0也是1次,一般音效不需要连续播放。

我们在游戏一开始就可以播放背景音乐了,但只有在点击鼠标event.type == MOUSEBUTTONDOWN的时候才播放锤子的声音,只有在击中地鼠的时候才播放地鼠的叫声。

修改之后的代码如下:

import pygame
import sys
import random
from pygame.locals import * # 引入鼠标事件类型
import time pygame.init() # 初始化
window = pygame.display.set_mode([600, 400]) # 设定窗口 sur = pygame.Surface([600, 400]) # 绘制背景容器
clr = (0, 0, 255)
posAll = [[100, 150], [300, 150], [500, 150], [200, 300], [400, 300]] # 六个位置
rad = 50
tick = 0 # 计数器
pos = posAll[0] # 外面记录圆的位置 # 分数
score = 0 # 分数计数
pygame.font.init() # 初始化文字
score_font = pygame.font.Font("MicrosoftYaqiHeiLight-2.ttf", 30) # !!设定字体和字号
score_sur = score_font.render(str(score), False, (255, 0, 0)) # !!生成计数表面 # 鼠标
pygame.mouse.set_visible(False) # !!隐藏鼠标
mpos = [300, 200] # !!记录鼠标位置 times = 0 # 地鼠跳出的次数
times_max = 10 # 最多次数
tick_max = 30 # 地鼠每次跳多少帧
map = pygame.image.load("dds-map.jpg") # !!读取图片
rat1 = pygame.image.load("rat1.png") # !!读取地鼠图片
rat2 = pygame.image.load("rat2.png") # !!读取被砸地鼠图片
ham1 = pygame.image.load("hammer1.png") # !!读取锤子图片
ham2 = pygame.image.load("hammer2.png") # !!读取砸下锤子图片 gameover = 0 # !!结束计时
gameover_max = 100 # !!结束计时最大值,超过这个值就重新开始 # 音乐和音效
pygame.mixer.music.load("bg.mp3") # !!载入背景音乐
pygame.mixer.music.play(-1) # !!无限播放背景音乐
hitsound = pygame.mixer.Sound("hit.wav") # !!载入击打声音
hurtsound = pygame.mixer.Sound("aiyo2.wav") # !!载入地鼠叫声 while 1:
hamsur = ham1
ratsur = rat1
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
elif event.type == MOUSEBUTTONDOWN: # 如果是鼠标按下事件
hamsur = ham2 # 使用下落锤子
hitsound.play() # !!播放击打声音
mpos = pygame.mouse.get_pos() # 获取鼠标位置
dis = pygame.math.Vector2(mpos[0] - pos[0], mpos[1] - pos[1]) # 计算坐标差
len = pygame.math.Vector2.length(dis) # 计算距离
if len < rad:
tick = 1000 # 立即变换位置
score = score + 1 # 计分增加
ratsur = rat2 # 使用被砸地鼠
hurtsound.play() # !!播放地鼠声音
elif event.type == MOUSEMOTION: # 当鼠标移动的时候
mpos = pygame.mouse.get_pos() # 更新鼠标位置 if times >= times_max:
# 显示结束画面
sur.fill((0, 0, 0)) # 结束时候仍然用黑色清空画面
pygame.mouse.set_visible(True)
end_font = pygame.font.Font("MicrosoftYaqiHeiLight-2.ttf", 48) # 设定字体和字号
end_sur = score_font.render(
"你的分数是:{}/{}!".format(score, times_max), True, (255, 0, 0)
) # 生成计数表面
sur.blit(end_sur, (100, 150))
cd = int((gameover_max - gameover) / 10)
cd_sur = score_font.render(
"重新开始倒计时{}".format(cd), True, (255, 0, 0)
) # 生成计数表面
sur.blit(cd_sur, (100, 200)) # 增加分数表面
gameover = gameover + 1 # !!增加结束计时
else:
sur.blit(map, (0, 0)) # 添加背景图片
score_sur = score_font.render(
"分数:{}/{}!".format(score, times + 1), False, (255, 0, 0)
) # 重新生成分数文字表面
sur.blit(score_sur, (200, 10)) # 增加分数表面
if tick > tick_max: # 每50次刷新变换一次
times = times + 1 # 增加计次
a = random.randint(0, 4) # 随机0到4
pos = posAll[a] # 更新外部记录的圆的位置
tick = 0 # 重置计数器
else: # 不刷新变换的时候
tick = tick + 1 # 增加计数器
if tick > 5: # 开始几帧不显示地鼠
sur.blit(ratsur, (pos[0] - 50, pos[1] - 70)) # 绘制地鼠
sur.blit(hamsur, (mpos[0] - 50, mpos[1] - 100)) # 绘制锤头 # 刷新画面
window.blit(sur, (0, 0))
pygame.display.flip() # 刷新画面
time.sleep(0.04) # 保持画面一点时间 # 重置游戏
if gameover > gameover_max:
pygame.mouse.set_visible(False)
times = 0
score = 0
gameover = 0

运行上面的代码,可以听到欢快的背景音乐,点击鼠标时候会有捶地声音,打中地鼠会有哎呦的叫声。

Python 0基础开发游戏:打地鼠(详细教程)VS code版本的更多相关文章

  1. PyCharm Django Python 开发环境配置 详细教程

    PyCharm Django Python 开发环境配置 详细教程 1. Python 下载及安装 (1)根据需要的版本去 Python 官网(https://www.python.org/downl ...

  2. VSCode Java 开发环境配置 详细教程

    VSCode Java 开发环境配置 详细教程 配置java 下载 用于现在大多数使用者用的是java 8,小白的我先安装java 8好了,^ w ^. 下载地址:Java 8 | Java SE 打 ...

  3. Python、 Pycharm、Django安装详细教程(图文)

    前言 这篇文章主要介绍了Python. Pycharm.Django安装详细教程,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧. ...

  4. VSCode PHP 开发环境配置 详细教程

    VSCode PHP 开发环境配置 详细教程 这篇文章主要介绍了VScode+PHPstudy配置PHP开发环境的步骤,整理了官方以及优秀第三方的内容,对于学习和工作有一定借鉴意义. 配置过程 第一步 ...

  5. 【python】10分钟教你用Python做个打飞机小游戏超详细教程

    更多精彩尽在微信公众号[程序猿声] 我知道你们一定想先看效果如何 00 目录 整体框架 开始之前-精灵类Sprite 子弹类class Bullet 玩家飞机类class Player 敌机类clas ...

  6. Qt5 C++ GUI界面 开发环境配置 详细教程

    本博客已暂停更新,需要请转新博客http://www.whbwiki.com/333.html Qt 下载 Qt 体积很大,有 1GB~3GB,官方下载通道非常慢,相信很多读者会崩溃,所以建议大家使用 ...

  7. Python之简单的SMTP发送邮件详细教程附代码

      简介 Python发送邮件的教程本人在网站搜索的时候搜索出来了一大堆,但是都是说了一大堆原理然后就推出了实现代码,我测试用给出的代码进行发送邮件时都不成功,后面找了很久才找到原因,这都是没有一个详 ...

  8. JDK11.0.7下载及安装详细教程(win10)

    0.背景知识 JRE: Java Runtime Environment JDK:Java Development Kit JRE顾名思义是java运行时环境,包含了java虚拟机,java基础类库. ...

  9. VSCode C/C++ 开发环境配置 详细教程

    本博客已暂停更新,需要请转新博客http://www.whbwiki.com/335.html VsCode是一个轻量级的编辑器,但是配置有点复杂,这里我做了C/C++开发环境配置总结,适用于wind ...

随机推荐

  1. 开发架构+osi七层协议+socket(day26)

    目录 软件开发架构 C/S架构 B/S架构 网络编程 互联网协议/OSI七层协议 传输层 网络层 数据链路层 物理连接层 socket 什么是socket 为什么用socket 如何使用 软件开发架构 ...

  2. 有些需要禁用的PHP危险函数(disable_functions)

    phpinfo() 功能描述:输出 PHP 环境信息以及相关的模块.WEB 环境等信息. 危险等级:中 passthru() 功能描述:允许执行一个外部程序并回显输出,类似于 exec(). 危险等级 ...

  3. go map数据结构和源码详解

    目录 1. 前言 2. go map的数据结构 2.1 核心结体体 2.2 数据结构图 3. go map的常用操作 3.1 创建 3.2 插入或更新 3.3 删除 3.4 查找 3.5 range迭 ...

  4. js图片随机切换

    使用js做到随机切换图片 <!DOCTYPE html> <html lang="en"> <head> <meta charset=&q ...

  5. expect实现自动输入密码功能

    系统: Ubuntu:16.04 安装expect: sudo apt-get update sudo apt-get install expect 脚本实例: //这一行告诉操作系统脚本里的代码使用 ...

  6. SpringBoot 整合 Elasticsearch深度分页查询

    es 查询共有4种查询类型 QUERY_AND_FETCH: 主节点将查询请求分发到所有的分片中,各个分片按照自己的查询规则即词频文档频率进行打分排序,然后将结果返回给主节点,主节点对所有数据进行汇总 ...

  7. 一张图牢记vim常用命令

    1.示例(前提要切到命令状态) ^  光标移动到行首 $  光标移动到行尾 set nu 显示行号 :%s/foo/bar/g 会在全局范围(%)查找foo并替换为bar,所有出现都会被替换(g) 参 ...

  8. 接口自动化、移动端、web端自动化如何做?

    1.<Python+Appium移动端自动化项目实战>-带您进入APP自动化测试的世界https://yuedu.baidu.com/ebook/765b38a5690203d8ce2f0 ...

  9. CSS3解决字母不换行的方法

    CSS3解决字母不换行的方法 <pre>word-wrap: break-word;</pre>

  10. 护网杯web

    首先进入网页后,观察到有sign up 点击sign up 进行注册 再点击sign in 进行登录 进入一个买辣条的界面,可以知道,5元可以买一包大辣条,多包大辣条可以换一包辣条之王,多包辣条之王可 ...