你曾经好奇过视频游戏是如何开发的吗?其实没有你想的那么难!现在就让我们动手开发一款游戏。
这篇文章的作者是一位时年仅13岁的python开发者,这是他的Google+与Twitter账号。这篇文章原文在这儿。原来的代码基于python v2.7,翻译时略有改动,以适应python v3.2。
在这篇教程中,你将创建一个叫做兔子与獾的游戏。游戏中的英雄——兔子妈妈,将抵抗成群结队的獾的进攻,保卫堡垒中的兔子宝宝。
这个游戏使用Python,当然,这儿我不是指蛇(python英文原意为蟒蛇)! :]
Python是一种计算机语言。这个教程中我们选择Python,因为这种语言对于编程初学者来说很简单,而且学起来容易而有趣。
如果你对Python很陌生,那么编写这个游戏前,你应该具备一些Python基础知识。
开始:安装Python
如果你使用的是Linux系统(如Ubuntu),那么你的电脑中已经内置有python了。如果你用的是windows系统,那么你要安装Python。你可以访问Python官网下载最新版(译注:目前最新版本是v3.6.1,但目前pygame在windows下只支持v3.2,如果你的操作系统是windows我建议你点击这儿下载并安装v3.2版本)。安装完成后,在开始
菜单所有程序
中你应该可以找到IDLE,单击它,如果安装正确,你将会看到以下画面:
进入IDLE之后,你可以测试Python能不能正确工作,输入print(1+1)
然后回车试一试。Python会返回2
。恭喜你,你刚刚写完了你的第一个Python程序!
现在你已经成功安装了Python并运行了第一个程序,为了用Python写游戏,你还需要安装PyGame(译注:单击这儿直接下载安装包运行安装,注意安装时要选择你的Python安装目录)。
为了验证你的PyGame安装正确,打开IDLE输入import pygame
并回车。如果没有返回任何结果,那么恭喜你,你的PyGame安装正确。
运行存储在文件中的Python代码
现在,你可以在IDLE中运行Python程序了。但是,如果你想运行代码比较多的程序(例如游戏),你需要把你的程序代码存储到磁盘上的文件中,这样,再次运行的时候,你就不需要在IDLE中一遍又一遍的输入啦。
运行文件中的Python代码有好几种方法。我们使用这种方法:在IDEL编辑器中运行代码。在这个教程中,我们将用这种方式。运行IDLE,你只需要在开始菜单中输入idle并回车。然后在IDEL菜单中选择File\New,会有一个文本编辑器窗口打开,你可以在这儿输入代码啦。如果要保存的话,选择File
菜单中的Save
;如果要运行,点击Run
菜单下的Run Module
(快捷键为F5)。也许你注意到了,Run
菜单只有在你打开代码文件时才有效。
添加游戏资源
现在你几乎马上就可以开始编写游戏啦。但是,如果游戏没有画面和音效是不是太逊了?我已经把设计游戏中需要用到的图片和声音文件打包成一个zip压缩包,你可以点击这儿下载。下载之后,在你的硬盘上为你的游戏创建一个文件夹,将刚下载的压缩文件解压到这个文件夹里,你这样你游戏文件夹中有个子文件夹resources
,文件夹的结构如下图:
现在,你可以开始编写你的兔子与獾游戏啦!
第一步:哈罗,兔子!
运行IDLE并且打开一个文本编辑窗口,输入以下代码:
1 | # 1 - 导入pygame库 |
在你的游戏文件夹中保存这个文件,文件名为game.py。
让我们分析这段代码:
- 导入PyGame库,导入后我们才可以在后面的程序用使用这个库的功能。
- 初始化游戏,设置游戏窗口的尺寸。
- 加载兔子图像。
- 在缩进代码中保持循环。
注意:其他编程语言像java、C或PHP,使用括号来标识一段循环或条件判断中的代码块,Python使用缩进来标明代码块。所以正确的缩进非常重要,一定要记住。
- 在绘制图像之前用黑色填充屏幕。
- 在x=100,y=100位置显示兔子。
- 更新屏幕。
- 检查事件, 如果事件是退出命令,退出程序。
如果你现在运行程序,你会看到下面的屏幕:
兔子准备好了,随时准备攻击!但是黑色屏幕上一只孤零零的兔子,看起来很可怜。让我们在增加一点东西。
第二步:添加舞台布景
我们先为游戏增加背景。通过调用screen.blit()
可以做到。
在#3末尾,加载图像之后,增加下面的代码:
1 | grass = pygame.image.load("resources/images/grass.png") |
这段代码加载草地和兔子堡垒的图像,然后存储到变量中。现在应该把它们绘制到屏幕上。但现在如果你检查草地图像,会发现它没有覆盖整个屏幕(屏幕尺寸设置为640x480)。这意味着你不得不把草地图片铺满整个屏幕。
在#6下面增加以下代码(在绘制玩家之前):
1 | for x in range(int(width/grass.get_width())+1): |
像你看到的那样,for
首先循环x
次,然后在这个循环里,它又循环y
次,绘制草地图像。下面的几段代码在屏幕上绘制四个兔子堡垒。
如果你现在运行程序,看上去应该像这样:
看起来好多了吧?
第三步:让兔子动起来
接下来,您需要添加一些实际的游戏元素,例如让兔子响应按键。
要做到这一点,首先你会实现一个很好的方法,用来跟踪在给定的时刻哪些键按下了。 你可以简单地做一个关键状态的数组,来保存每个要用于游戏的键的状态。
在第#2节末尾添加以下代码到game.py(设置屏幕高度和宽度后):
1 | keys = [False, False, False, False] |
这段代码非常简单。 按键数组按照以下顺序跟踪被按下的键:WASD。数组中的每个项目对应一个键 - 第一个为W,第二个为A,等等。
playerpos变量是程序绘制游戏玩家的位置。由于游戏会将玩家移动到不同的位置,所以设置一个包含玩家位置的变量,然后简单地在不同位置绘制这个变量。
现在您需要修改现有的代码来绘制玩家以使用新的playerpos变量。 更改第6节中的以下行:
1 | screen.blit(player, (100,100)) |
更改为:
1 | screen.blit(player, playerpos) |
接下来,根据按下哪个键更新键数组。PyGame通过添加event.key功能使检测按键更容易。
在#8的末尾,在检查event.type == pygame.QUIT
之后,增加以下代码(与pygame.QUIT相同的缩进级别):
1 | if event.type == pygame.KEYDOWN: |
哇!很多代码行!其实如果你把它分解成if语句,并不是那么复杂。
首先,您检查一下按键是否被按下或释放。 然后您检查按下或释放了哪个键,如果按下或释放的键是您正在使用的键之一,则相应地更新键变量。
最后,您需要根据按键更新playerpos变量。 这其实很简单。
将以下代码添加到game.py的末尾(一个缩进,将其放在与for循环相同的级别):
1 | # 9 - Move player |
该代码简单地检查按下哪个键,并从兔子的x或y位置添加或减去(取决于按下的键)5来移动玩家。
运行游戏,你应该像以前一样得到一个兔子。尝试按WASD。 好极了! 对吧?
第四步:旋转玩家
是的,当你按键你的兔子现在会移动,如果你可以使用鼠标旋转兔子面对你选择的方向,那就更酷了,所以它不就不会一直朝向同一个方向了?使用三角函数可以很容易地实现。
看下图:
在上述图像中,如果(5,3)是兔子的位置,(2,4)是鼠标的当前位置,则可以通过将atan2三角函数应用于差两点之间的距离来找到旋转角度(z)。当然,一旦你知道旋转角度,你可以简单地旋转兔子。 :]
如果你对这部分有些困惑,别担心 —— 你可以继续下去。但这就是为什么你应该在数学课上注意! :]你会一直在游戏编程中使用这些东西。
现在你需要把这个概念应用到你的游戏中。 为此,您可以使用PyGame Surface.rotate
(度)函数。 顺便说一句,请记住,Z值是弧度。 :[
atan2
函数来自Python数学库。 所以首先添加到第1节的末尾:
1 | import math |
然后,用以下代码替换#6中的最后一行(player.blit):
1 | # 6.1 - Set player position and rotation |
我们来看一下上述代码的基本结构。首先你会得到鼠标和兔子的位置。然后你把这些输入atan2功能。之后,您将从atan2功能接收到的角度从弧度转换为度数(乘以弧度大约为57.29或360/2π)。
由于兔子会旋转,它的位置会改变。所以现在你计算出新的兔子的位置,并在屏幕上显示兔子。
再次运行游戏。如果您只使用WASD键,那么游戏应该像以前一样。但如果你移动鼠标,兔子也会旋转。酷!
第五步:射击,兔子,射击!
现在你的兔子移动了,现在是添加一点点动作的时候了。 :] 如何让兔子用箭射杀入侵的敌人?这不是一只温和的兔子!
这个步骤有点复杂,因为你必须跟踪所有的箭,更新它们,旋转它们,并在屏幕外删除它们。
首先,将必要的变量添加到#2初始化部分的末尾:
1 | acc=[0,0] |
第一个变量跟踪播放器的准确度,第二个数组跟踪所有的箭。精确度变量(acc)本质上是发射射击次数和击中獾数量的数组。之后,我们将使用这些信息来计算准确率。
接下来,在第#3节末尾的加载箭头图像:
1 | arrow = pygame.image.load("resources/images/bullet.png") |
现在当用户点击鼠标时,需要发射箭头。将以下内容添加到第#8节末尾作为新的事件处理程序:
1 | if event.type==pygame.MOUSEBUTTONDOWN: |
该代码检查鼠标是否被点击,如果是,它会获取鼠标位置,并根据旋转的兔子位置和鼠标位置计算箭头旋转。 该旋转值存储在箭头数组中。
接下来,你必须在画面上画箭头。在第6.1节之后添加以下代码:
1 | # 6.2 - Draw arrows |
使用基本三角法计算vely和velx值。10是箭头的速度。if语句只是检查箭头是否超出范围,如果是,它会删除箭头。第二个语句循环所有的箭头,并以正确的旋转绘制它们。
尝试并运行该程序。你应该有一个兔子,当你点击鼠标时它会射出箭! :D
第六步:拿起武器!獾!
好的,你有一座城堡,你有一个可以移动和射击的英雄。那么少了什么?攻击英雄防护的城堡的敌人!
在此步骤中,您将创建随机生成的向城堡进攻的。游戏进行中,会有越来越多的獾。所以,让我们列出你需要做什么。
- 将坏人添加到列表中。
- 更新每个帧中的坏家伙数组,并检查他们是否走到屏幕以外。
- 显示坏人。
轻松吧? :]
首先,将以下代码添加到第#2节的末尾:
1 | badtimer=100 |
以上设置了一个计时器(以及一些其他值),以便游戏在运行一段时间后添加新的獾。你在每一帧不断减少badtimer数值,直到它为零,然后产生一个新的獾。
现在将以下内容添加到第#3节的末尾:
1 | badguyimg1 = pygame.image.load("resources/images/badguy.png") |
上面的第一行类似于所有以前的图像加载代码。第二行设置图像的副本,以便您可以更轻松地为坏人制作动画。
接下来,你必须更新并显示坏人。在第#6.2节之后添加此代码:
1 | # 6.3 - Draw badgers |
许多代码。:] 第一行检查badtimer是否为零,如果是,创建一个獾,并根据到目前为止运行badtimer多少次,再次设置badtimer。第一个for循环更新獾的x位置,检查獾是否离开屏幕,并且如果在屏幕外,则会删除獾。第二个循环绘制所有的獾。
为了在上面的代码中使用随机函数,你还需要导入随机库。因此,将以下内容添加到第#1节的末尾:
1 | import random |
最后,在while语句(第#4节)之后添加这一行,以减少每一帧的badtimer的值:
1 | badtimer-=1 |
通过运行游戏来尝试所有这些代码。现在你应该开始看到真正的游戏 —— 你可以射击,移动,转身和獾们试图跑到你身边。
可是等等! 为什么獾们扑向城堡?让我们快点添加一下…
在第#6.3节第一个for循环的index+=1
之前添加此代码:
1 | # 6.3.1 - Attack castle |
这段代码很简单。如果獾的x值小于64,则删除该坏人,并将游戏健康值降低5到20之间的随机值(稍后将显示当前的健康值)。
如果你建立和运行程序,你应该得到一堆攻击的獾,当他们击中城堡时消失。 虽然你看不到,但是獾们实际上z在降低你的健康值。
第七步:獾与箭的碰撞
獾们攻击你的城堡,但你的箭对他们没有影响!兔子应该如何保卫自己的家?
是时候设置箭头杀死獾了,然后你可以保护城堡,赢得比赛!基本上,你必须在每一个循环里循环遍历所有的坏家伙,循环遍历所有的箭头,并检查它们是否碰撞。如果他们碰撞了,那么删除獾,删除箭头,并将你的准确率加一。
在第#6.3.1节之后,添加:
1 | #6.3.2 - Check for collisions |
在这段代码中只需要注意一点。if语句中是一个内置的PyGame函数,用于检查两个矩形是否相交。其他几行代码我上面已经解释过。
现在如果你运行这个程序,你应该能够射击和杀死獾。
第八步:添加健康计时器和时钟
游戏进度相当不错。你有你的攻击者,你有你的防守者。现在你需要的只是一种累计分数并显示兔子做得很好的方法。
最简单的方法是添加一个显示城堡当前运行状况的HUD(头像显示)。您还可以添加时钟来显示城堡已经存活多久。
先添加时钟。 在#7开头之前添加以下代码:
1 | # 6.4 - Draw clock |
上述代码使用默认的PyGame字体设置创建一个新的字体,字体大小为24。然后使用该字体将时间的文本渲染到屏幕上。之后,文本在屏幕上定位和绘制。
接下来添加健康栏。但在绘制健康条之前,您需要加载条形图像。将以下代码添加到第#3节的末尾:
1 | healthbar = pygame.image.load("resources/images/healthbar.png") |
第一个是用于完整健康值的红色图像。第二个是用于显示当前健康水平的绿色图像。
现在在第#6.4节(您刚添加的)之后添加以下代码,以在屏幕上绘制健康条:
1 | # 6.5 - Draw health bar |
代码首先绘制全红的健康栏。然后,根据城堡剩余的生命,它在健康栏上画一定数量的绿色。
如果你建立并运行程序,你应该有一个计时器和一个健康条了。
第九步:胜利或失败
但是怎么回事?如果你玩得时间足够长,即使你的健康状况下降到零,游戏还会继续下去!不仅如此,你也可以继续在獾们身上射击。那不行,现在呢?你需要一些胜利/失败的场景,使游戏值得玩。
所以让我们添加胜利与失败的条件以及显示赢或输结果的屏幕。 :] 你通过退出主循环进入一个赢/输循环实现。 在赢/输循环中,您必须弄清楚用户是赢还是输,并相应地显示屏幕。
这是一个基本的失败场景:
如果时间到了(90000毫秒或90秒),那么:
- 停止运行游戏
- 将比赛的结果设为1或赢
如果城堡被毁了,那么:
- 停止运行游戏
- 将比赛的结果设为1或赢
以任一方式计算准确度。
注意:
acc[0]*1.0
只是将acc[0]
转换成float。如果不这样做,则除法操作数将返回像1或2这样的整数,而不是1.5。
在game.py末尾添加以下代码:
1 | #10 - 输赢检查 |
这是最长的代码了!但并不复杂。
第一个if语句检查时间是否满足。第二个检查城堡是否被毁坏。第三个计算您的准确率。之后,if语句检查您是否赢了或失败并显示对应的图像。
当然,如果要显示失败或胜利的图像,则必须首先加载这些图像。 因此,将以下代码添加到第#3节的末尾:
1 | gameover = pygame.image.load("resources/images/gameover.png") |
还有一件简单的工作,把#4从:
1 |
|
修改为:
1 | # 4 - 保持循环 |
运行变量跟踪游戏是否结束,退出代码变量跟踪玩家是赢或输。
再次运行游戏,现在你可以胜利或死亡! :]
第十步:音乐和声音效果!
游戏看起来很不错,但是怎么回事?有点安静,不是吗?添加一些音效可以改变游戏的感觉。
PyGame使加载和播放声音超级简单。首先,您必须在第#2节末尾加入调音台:
1 | pygame.mixer.init() |
然后在#3末尾加载声音,设置音量:
1 | # 3.1 - 加载音频 |
以上代码大部分仅仅是加载音频文件并配置音频音量级别。但是请注意pygame.mixer.music.load
行 —— 该行加载游戏的背景音乐,下一行将背景音乐设置为重复。
还需要处理音频配置。 :] 现在你需要做的就是根据需要播放各种音效。按照以下代码的注释中的说明进行操作:
1 | # 6.3.1 if badrect.left<64 之后: |
再次运行游戏,你会注意到,你现在有了背景音乐和射击的音效。 游戏感觉更棒! :]
接下来呢?
你应该为自己感到自豪:你刚刚完成了一个有趣的游戏,包括音乐,声音,杀手级的兔子,凶恶的獾等等。 我告诉过你,你可以做到! :]
您可以在这里下载游戏的最终源代码。
在这个基础上,您可以任意将这个游戏扩展到你自己的创作中! 也许尝试用自己的照片替换背景,或者添加不同的武器或类型的怪物!