這是一篇由教程團隊成員Julian Meyer發表的文章,一個12歲的python開發人員。你可以在Google+和Twitter上找到他。
你可曾想過如何創建電玩遊戲嗎?它不像你想像的那麼複雜!
在本教程中,您將創建一個簡單的遊戲叫做兔子和獾,在這裡作為英雄的兔子要保衛城堡反擊進攻的獾群。 :O
# 寫這個遊戲,你將使用Python。不,我指的不是一條大蛇! :]
# Python是一種電腦程式語言。我們就本教學選擇Python,Python是一種易於上手、有趣且容易學習的語言。
如果你剛接觸Python,開始之前先檢出這本書 - 深入Python:怎樣像計算機科學家一樣思考,這將使你提升速度。
然後回到這裡,準備開始— 有一場小兔子和獾之間的戰爭即將發生。繼續閱讀將加入戰爭吧!
如果你想在Windows電腦上嘗試本教學,你需要安裝Python,記得要安裝2.7.3版本而不是3.3.0!運行完安裝程式後,在開始功能表程式資料夾中會有IDLE,執行IDL。
如果你使用Mac,Python已經安裝了!只要打開一個終端機(/Applications/Utilities/Terminal.app),輸入python然後按回車。
注意:如果你從python.org安裝Python(如果你想獲得PyGame需要這樣做),那麼你也需要在Mac上進入IDLE。它應該在“Applications/Python 2.7”資料夾內。
如果操作正確的話,你將會看到類似輸出:
Python 2.7.3 (v2.7.3:70274d53c1dd, Apr 9 2012, 20:52:43) [GCC 4.2.1 (Apple Inc. build 5666) (dot 3)] on darwin Type "help", "copyright", "credits" or "license" for more information. >>>
注意:如果你想退出Python提示窗(三個尖括號提示:>>>),你可以透過在提示視窗輸入exit()或按Ctrl+D。
一旦你在Python提示窗了,測試Python是否正常工作的話輸入print 1+1,然後按回車或換行,它將輸出2。你已經寫了你的第一個Python程式。
# 現在你知道Python運作正常,為使用Python寫遊戲你需要安裝PyGame。
PyGame是一個讓寫遊戲變得簡單的Python庫,它提供如圖像處理、聲音回放等你可以輕鬆添加都遊戲中的功能。
到這來下載你係統適合的PyGame,確認你下載的是一個Python2.7版本。
注意:從上面鏈接下載的PyGame安裝檔案不能與Apple的Mac上預設安裝的Python一起工作,為使用PyGame你需要從python.org上下載安裝Python,或者你可以透過MacPorts安裝Python和PyGame。
要檢驗PyGame安裝是否正確的話,打開IDLE或通過終端運行Python,在Python提示符處輸入import pygames,如果回車後沒有輸出的話你安裝成功了。
如果,另一方面,輸出了下附類似錯誤,PyGame沒有正確安裝。
Python 2.7.2 (default, Jun 20 2012, 16:23:33) [GCC 4.2.1 Compatible Apple Clang 4.0 (tags/Apple/clang-418.0.60)] on darwin Type "help", "copyright", "credits" or "license" for more information. >>> import pygame Traceback (most recent call last): File "<stdin>", line 1, in <module> ImportError: No module named pygame >>>
如果你遇到類似的錯誤,在論壇上發出來我將幫助你讓它正常。
雖然你可以在Python提示字元下運行短的Python程式碼,但如果你工作在一個大的程式(例如游戲)裡,你可能想要將你的程式碼保存到一個文件,這樣你就不必一遍又一遍地鍵入它了。
有幾種方法可以運行Python程式檔案。一種方法是使用純文字編輯器,不如記事本(Windows)或TextEdit(Mac)。開啟一個新的文字文件,輸入你的Python程式碼(像print 1 + 1)。然後將它保存為asXXX.py(XXX可以是任何描述性的檔案名稱)。
使用Windows的話,透過雙擊這個檔案來運行它。在Mac上,打開終端,輸入python,然後拖曳你儲存的檔案到終端視窗並按下Enter。
另一種方法是鍵入程式碼類別到IDLE,也就是你在這個教學中需要做的方式。運行IDLE - 只需在終端機輸入IDLE。 然後選擇文,然後選擇File\New Window,會出現一個你可以輸入程式碼的文字編輯器視窗。你可以透過File\Save儲存你更改的程式碼,透過執行Run\Run Module(F5)運行程式碼。
請注意運行選單只在你已有一個檔案在編輯器視窗開啟時有效。
# 你幾乎已經可以開始創建你的遊戲了。但沒有一些震撼的影像和聲音效果的遊戲又算什麼呢?我已經收集了遊戲所需的所的圖形和聲音效果並把它們壓縮成了一個ZIP存檔,你可以在這裡下載。
下載檔案後,在你的硬碟上建立一個遊戲使用的資料夾,將resources資料夾解壓縮到這個資料夾中,這樣你的遊戲資料夾有了名為resources的子資料夾,各種資源在resources文件夾裡面分組顯示如下:
兔子和獾的游戏你已经准备就绪。:]
运行IDLE开发环境,向上一节提到的那样,打开一个新的文本编辑窗。在编辑窗键入以下代码:
# 1 - Import library import pygame from pygame.locals import * # 2 - Initialize the game pygame.init() width, height = 640, 480 screen=pygame.display.set_mode((width, height)) # 3 - Load images player = pygame.image.load("resources/images/dude.png") # 4 - keep looping through while 1: # 5 - clear the screen before drawing it again screen.fill(0) # 6 - draw the screen elements screen.blit(player, (100,100)) # 7 - update the screen pygame.display.flip() # 8 - loop through the events for event in pygame.event.get(): # check if the event is the X button if event.type==pygame.QUIT: # if it is quit the game pygame.quit() exit(0)
把它保存到你的游戏目录下(即资源子目录)并命名为itgame.py。
让我们逐段分析以上代码:
1. 导入PyGame库。这一步让你在你的程序中使用来自库中的函数。
2. 初始化PyGame并设置显示窗口。
3. 加载你想要给bunny使用的图片。
4. 循环执行以下缩进的代码。
5. 在绘图前,将屏幕填充成黑色。
6. 将之前加载进来的bunny图片以100*100的大小显示在屏幕上。
7. 更新屏幕。
8. 检查任何新事件如果有的话,否则转到退出命令,退出程序。
注意:根据PyGame的文档,你不需要调用pygame.quit()因为解析器关闭时会自动调用它。然而,至少在Mac OS上,这个游戏会在退出时挂起除非pygame.quite被调用。
如果现在运行这段代码(在Idle菜单栏点击 “Run\Run Module"),你应该可以看到一个如下所示的屏幕:
耶,兔子就显示在屏幕上了,并准备做动作!
但是只有一只兔子显示在一个黑漆漆的屏幕上,这个游戏看起来很吓人且很孤单。接下来要做的就是稍微美化一下咯。
我们首先给游戏场景添加背景图片,可以通过调用一组screen.blit()来完成背景添加。
在代码的#3 小节,载入角色图像之后添加下面的代码:
grass = pygame.image.load("resources/images/grass.png") castle = pygame.image.load("resources/images/castle.png")
这些代码载入图片然后赋给指定的变量,然后把它们画到屏幕上。但如果你检查草地的图片,你会发现它没有覆盖整个640 x 480的屏幕,所以你必须平铺使草地的图片完全覆盖屏幕。
在#6小节的开始(把兔子画在屏幕上之前),添加以下代码到game.py:
for x in range(width/grass.get_width()+1): for y in range(height/grass.get_height()+1): screen.blit(grass,(x*100,y*100)) screen.blit(castle,(0,30)) screen.blit(castle,(0,135)) screen.blit(castle,(0,240)) screen.blit(castle,(0,345 ))
正如你所见,首先把x坐标通过for循环递增,在这个循环中再把y坐标循环递增,并且将草地画在使用循环生成的x、y坐标上。紧接着的一组代码只是将城堡画在屏幕上。
你现在运行这个程序,你会看到像如下的结果:
从现在开始,变得好看点了! :]
下面你需要添加一些真正的游戏元素,比如让兔子响应键盘的按键。
要做到这一点,你需要实现好一个方法记录哪一个键在某一时刻被按下。你可以简单的使用一个数组保存在游戏需要使用的键的按下状态。
添加如下代码到game.py的#2小节结束(在你设了屏幕高和宽度之后):
keys = [False, False, False, False] playerpos=[100,100]
这段代码是非常明了。数组keys按WASD的顺序记录它们的状态。数组的每个元素对应一个键,第一个是W,第二个是A等等。
playerpos变量定义程序开始绘制游戏角色的起始位置。因为这个游戏将移动游戏角色到不同的位置,设置一个储存角色位置的变量,然后便可以简单地将角色绘制到这个位置。
现在你需要修改现有的代码来绘制角色,使用新的playerpos变量,将# 6的程序:
screen.blit(player, (100,100))
改为:
screen.blit(player, playerpos)
接下来,基于哪些按键被按下更新键数组,PyGame通过添加event.key事件使检测按键很容易实现。
在# 8检测event.type==pygame.QUIT之后,添加这些代码(如果有块缩进的话使用与pygame.QUIT相同的缩进级):
if event.type == pygame.KEYDOWN: if event.key==K_w: keys[0]=True elif event.key==K_a: keys[1]=True elif event.key==K_s: keys[2]=True elif event.key==K_d: keys[3]=True if event.type == pygame.KEYUP: if event.key==pygame.K_w: keys[0]=False elif event.key==pygame.K_a: keys[1]=False elif event.key==pygame.K_s: keys[2]=False elif event.key==pygame.K_d: keys[3]=False
哇!这里有很多行代码,如果你把它按If语句拆分也不是很复杂的。
首先你要检测一是否有键被按下或释放,然后你需要检测哪个键被按下或者释放,如果被按下或者释放的键是你要使用的键,根据键值更新相应的键变量。
最后,你需要更新playerpos变量作为键按下的响应,这太简单了。
将下附代码添加到game.py的末尾(使用相同的缩进级,使用和for循环相同的缩进级)
# 9 - Move player if keys[0]: playerpos[1]-=5 elif keys[2]: playerpos[1]+=5 if keys[1]: playerpos[0]-=5 elif keys[3]: playerpos[0]+=5
这段代码只是检查哪个键被按下,然后添加或减去游戏角色的x或y位置(取决于按下的键)来移动游戏角色。
运行这个游戏,你会得到根以前一样的角色。试一下按WASD键,哈哈,起效了!
是的,你的兔子现在可以随着你的按键移动,但用鼠标来旋转兔子朝向到你选择的方向岂不更酷,所以它不是所有时间都朝向一个方向。使用三角函数来实现,这很简单。
看一下下面的图解:
上图中,如果(5,3)是兔子的位置,(2,4)是当前鼠标的位置,你可以通过对两点间距离的不同应用atan2三角函数获得旋转角度(z)。当然,一旦你知道旋转角,你可以轻松相应地旋转兔子。:]
如果你对这部分有点困惑,不要担心,你依然可以继续。但这就是你应该在数学课上用功的原因!:]在游戏编程时你会一直使用这个东西。
现在你需要将这个原理应用到你的游戏上,为做到这一点,你可以使用PyGameSurface.rotate(度数)函数, 顺便说一下,记住,Z值是弧度。:[
atan2函数在Python的math库总,所有先在#1结尾处增加:
import math
然后,将#6最后一行(player.blit这行)替换成下面的代码:
# 6.1 - Set player position and rotation position = pygame.mouse.get_pos() angle = math.atan2(position[1]-(playerpos[1]+32),position[0]-(playerpos[0]+26)) playerrot = pygame.transform.rotate(player, 360-angle*57.29) playerpos1 = (playerpos[0]-playerrot.get_rect().width/2, playerpos[1]-playerrot.get_rect().height/2) screen.blit(playerrot, playerpos1)
让我们梳理一下上面代码的基本流程。首先获取鼠标和游戏角色的位置,然后你对两个位置应用atan2函数,之后,你将atan2返回的弧度转化成度数(将弧度乘以近似57.29或360/2π)。
因为兔子会旋转,它的位置也将会改变。所以现在计算兔子的新位置并把它显示在屏幕。
再次运行这个游戏。如果你只按了“WASD”键,那么这个游戏应该和之前完全一样,但如果你移动你的鼠标兔子也会随之旋转,酷!
现在你的兔子已经可以自由活动了,是时候给它添加更多的动作了。让兔子可以用剑射击敌人怎么样?它可不是只温顺的兔斯基!
这一步稍微有点复杂,因为你必须记录所有射出的剑,更新它们的位置、旋转并且在它们飞出屏幕后删除它们。
首先,在初始化小节(#2小节)的结束添加必要的变量:
acc=[0,0] arrows=[]
第一个变量记录玩家的射击精度,第二个变量记录所有的剑。精度变量acc实际上是一个包含射击数量和命中獾 次数的列表。最后我们可以使用这些信息来计算精度的百分比。
接下来,在section #3的末尾加载弓箭图像:
arrow = pygame.image.load("resources/images/bullet.png")
现在当玩家点击鼠标,弓箭就要射出。在section #8的末尾加入以下代码作为新的事件句柄(event handler):
if event.type==pygame.MOUSEBUTTONDOWN: position=pygame.mouse.get_pos() acc[1]+=1 arrows.append([math.atan2(position[1]-(playerpos1[1]+32),position[0]-(playerpos1[0]+26)),playerpos1[0]+32,playerpos1[1]+32])
这些代码检查是否有鼠标点击,如果有它会读取鼠标位置,并根据玩家的旋转和指针的位置计算出弓箭的旋转。这个旋转储存在arrows数组里。
接下来你需要真正在屏幕上画出弓箭了。在section #6.1之后插入以下代码:
# 6.2 - Draw arrows for bullet in arrows: index=0 velx=math.cos(bullet[0])*10 vely=math.sin(bullet[0])*10 bullet[1]+=velx bullet[2]+=vely if bullet[1]<-64 or bullet[1]>640 or bullet[2]<-64 or bullet[2]>480: arrows.pop(index) index+=1 for projectile in arrows: arrow1 = pygame.transform.rotate(arrow, 360-projectile[0]*57.29) screen.blit(arrow1, (projectile[1], projectile[2]))
运用基本的三角函数可以计算出vely和velx。10是弓箭的速度。if语句检查弓箭是否飞出边界,如果是则删除该弓箭。第二个for语句循环过arrows数组并画出相应旋转的弓箭。
试试运行程序。你应该有一只兔兔在你点击鼠标时发射弓箭了。(。☉౪ ⊙。)
好的,你有了一个城堡和可以移动和射击的英雄。但少了什么东西呢?攻击城堡的敌人!
(炸掉你的城堡!)
在这个步骤中,你将创建几只随机生成并跑向城堡的獾。随着游戏的进展会有越来越多的獾。所以,让我们做一个列表看看需要做那些工作。
1、把坏家伙们添加到一个数组列表;
2、每帧每帧的更新这个数组并检查他们是否都出现在屏幕上;
3、显示这些坏家伙。
很容易,是吧?:]
首先,把下面这段代码添加到section #2后面:
badtimer=100 badtimer1=0 badguys=[[640,100]] healthvalue=194
上面这段代码设置了一个计时器(以及其他一些值)以便每过一段时间在游戏中增加一只新的獾。你每帧每帧的减少 badtimer直到0, 然后就生成一个新的獾。
现在把下面这段代码添加到section #3后面:
badguyimg1 = pygame.image.load("resources/images/badguy.png") badguyimg=badguyimg1
上面代码的第一行类似于前面所有的图片加载代码。第二行代码设置了一个图片副本以便于这个坏家伙能更容易动起来。
下一步,你必须更新并且显示这个坏家伙。把下面代码添加到section #6.2之后:
# 6.3 - Draw badgers if badtimer==0: badguys.append([640, random.randint(50,430)]) badtimer=100-(badtimer1*2) if badtimer1>=35: badtimer1=35 else: badtimer1+=5 index=0 for badguy in badguys: if badguy[0]<-64: badguys.pop(index) badguy[0]-=7 index+=1 for badguy in badguys: screen.blit(badguyimg, badguy)
仔细的看下这段代码,:] 第一行检查badtimer是否为0,以badtimer至今为止已经运行的次数为基础,创建一个新的獾并再次设置badtimer。第一个for循环更新獾的X坐标,并检查是否在屏幕上。如果不再屏幕上就删除掉。第二个佛如循环绘制所有獾。
为了在上述代码中使用随机函数,我们必须引入 random 库:
import random
最后,在 while 语句后面添加下面一行代码用来让 badtimer 值减1:
badtimer-=1
再次运行游戏来测试上述代码,现在你将看到真正的游戏,你可以发射、移动、转向,而且獾也尝试跑向你。
但等等,为什么不是獾炸毁这座城堡吗?马上搞定!
在#6.3小节中每一个循环前的 index += 1 之前添加如下代码:
# 6.3.1 - Attack castle badrect=pygame.Rect(badguyimg.get_rect()) badrect.top=badguy[1] badrect.left=badguy[0] if badrect.left<64: healthvalue -= random.randint(5,20) badguys.pop(index) # 6.3.3 - Next bad guy
这段代码非常简单,如果獾的x坐标值小于64,则删除这家伙然后随机递减5到20点的城堡的生命值。(在后面你可以显示生命值到屏幕上)
现在你构建并运行程序,你将看到一堆獾攻击城堡后消失。虽然你不能看到但獾确实降低了城堡的生命值。
现在獾可以攻击你的城堡但你的箭却对它们没有任何效果!兔子该如何保护自己的家园?
是时候让箭可以杀死獾,你才可以保护你的城堡赢得游戏!首先,你必须循环检查每个坏蛋,在检查时以需要循环检查所有的箭是不是和獾碰撞了。如果箭碰到了獾则删除箭和獾,并且递增命中值。
在#6.3.1小节后添加如下代码:
#6.3.2 - Check for collisions index1=0 for bullet in arrows: bullrect=pygame.Rect(arrow.get_rect()) bullrect.left=bullet[1] bullrect.top=bullet[2] if badrect.colliderect(bullrect): acc[0]+=1 badguys.pop(index) arrows.pop(index1) index1+=1
这段代码里有一个值得注意的地方,if语句后是PyGame内建的检查两个矩形是否相交的函数。其他语句只是按上面解释运行。
如果你现在运行程序,你会发现已经可以射击并杀死獾了。
游戏现在进展良好,有攻击者和守卫者。现在你还需要一种方式显示分数,看看这些兔子干得怎么样。
最简单的方式是添加一个HUD(平视显示器)显示当前城堡的健康状况。也可以添加一个时钟显示城堡被保护了多久。
首先添加时钟,在#7小节前添加如下代码:
# 6.4 - Draw clock font = pygame.font.Font(None, 24) survivedtext = font.render(str((90000-pygame.time.get_ticks())/60000)+":"+str((90000-pygame.time.get_ticks())/1000%60).zfill(2), True, (0,0,0)) textRect = survivedtext.get_rect() textRect.topright=[635,5] screen.blit(survivedtext, textRect)
上面代码简单的使用PyGame默认字体创建字体并设置尺寸为24。然后使用字体渲染时间到表面上。之后广西被定位并绘制到屏幕上。
下一步添加生命条。在绘制生命条之前你需要载入它的背景图。添加如下代码到#3小节结束:
healthbar = pygame.image.load("resources/images/healthbar.png") health = pygame.image.load("resources/images/health.png")
第一个是红色图用来铺满生命条。第二个绿色图显示当前生命值。
现在添加如下代码到#6.4节(你上一步添加的)之后来将生命条画到屏幕上:
# 6.5 - Draw health bar screen.blit(healthbar, (5,5)) for health1 in range(healthvalue): screen.blit(health, (health1+8,8))
上面的代码首先画出全红色的生命条,然后根据城堡的剩余的生命绘制绿色生命条。
现在你构建并运行程序,你可以看到时钟和生命条。
这是什么?如果你玩得足够久,即使你的命令值降到了0,游戏还是继续!不仅仅如此,你也还可以继续射击獾。这应该行不通的,但现在就是这样。你需要添加某种赢/输形式的场景让这个游戏值得玩。
所以我们现在添加输赢条件和各自的画面。你可以退出主游戏循环并进入输赢界面的循环。在输赢循环中,你可以检查用户是输了还是赢了,并显示相应的界面。
下面是一个判断输赢的基本方法:
如果超过了时间(90000毫秒或90秒):
停止运行游戏
设置游戏的结果为赢了
如果城堡被摧毁了:
停止运行游戏
设置游戏结果为输了
计算准确度的方法。
注:使用acc[0]*1.0 只是将acc[0]转换成float浮点类型,如果你不这么转换,则除法操作将返回一个整数值比如1或2而不是1.5。
将下面的代码加到game.py末尾:
#10 - Win/Lose check if pygame.time.get_ticks()>=90000: running=0 exitcode=1 if healthvalue<=0: running=0 exitcode=0 if acc[1]!=0: accuracy=acc[0]*1.0/acc[1]*100 else: accuracy=0 # 11 - Win/lose display if exitcode==0: pygame.font.init() font = pygame.font.Font(None, 24) text = font.render("Accuracy: "+str(accuracy)+"%", True, (255,0,0)) textRect = text.get_rect() textRect.centerx = screen.get_rect().centerx textRect.centery = screen.get_rect().centery+24 screen.blit(gameover, (0,0)) screen.blit(text, textRect) else: pygame.font.init() font = pygame.font.Font(None, 24) text = font.render("Accuracy: "+str(accuracy)+"%", True, (0,255,0)) textRect = text.get_rect() textRect.centerx = screen.get_rect().centerx textRect.centery = screen.get_rect().centery+24 screen.blit(youwin, (0,0)) screen.blit(text, textRect) while 1: for event in pygame.event.get(): if event.type == pygame.QUIT: pygame.quit() exit(0) pygame.display.flip()
这是截至目前最长的代码块,但不是最复杂的。
第一个if语句检查是否到时间,第二个检查城堡是否被摧毁,第三个计算你的准确率。之后,一个快速的if语句检查你是胜利还是失败了,并显示正确的图像。
当然,如果你想显示胜利与失败的屏幕图像,那么这些图像必须先被加载。将下面的代码添加到# 3结束的地方:
gameover = pygame.image.load("resources/images/gameover.png") youwin = pygame.image.load("resources/images/youwin.png")
另一点,更改#4处:
# 4 - keep looping through while 1: badtimer-=1
更改为:
# 4 - keep looping through running = 1 exitcode = 0 while running: badtimer-=1
running变量跟踪游戏是否结束,exitcode变量跟踪玩家是赢了还是输了。
再次运行游戏,现在你可以尝试胜利或死亡!酷!:]
这个游戏看起来相当棒,可是有声音吗?是不是太安静了点呢?增加一点点音效会让整个游戏的感觉变得更棒。
PyGame 加载并播放声音的方法非常简单。首先你需要初始化混音器,代码如下:
pygame.mixer.init()
然后加载要播放的声音,并设置音量大小:
# 3.1 - Load audio hit = pygame.mixer.Sound("resources/audio/explode.wav") enemy = pygame.mixer.Sound("resources/audio/enemy.wav") shoot = pygame.mixer.Sound("resources/audio/shoot.wav") hit.set_volume(0.05) enemy.set_volume(0.05) shoot.set_volume(0.05) pygame.mixer.music.load('resources/audio/moonlight.wav') pygame.mixer.music.play(-1, 0.0) pygame.mixer.music.set_volume(0.25)
最上代码中大多数是简单加载音频文件和配置的音频音量,但要注意pygame.mixer.music.load这一行——这一行加载游戏的背景音乐,下一行设置背景音乐一直重复。
注意音频配置。:] 现在,你所需要做的就是按需要播放各种声音效果。像下面每段注释代码那样做:
# section 6.3.1 after if badrect.left<64: hit.play() # section 6.3.2 after if badrect.colliderect(bullrect): enemy.play() # section 8, after if event.type==pygame.MOUSEBUTTONDOWN: shoot.play()
多次运行游戏,你会发现你现在有碰撞的背景音乐和射击的声音效果,游戏让人感觉更逼真了!:]
你应该为自己感到自豪:你刚刚创建完成一个有趣的游戏,里面充满了音乐,音效,一个杀手兔子,神风特攻队獾和更多东西。我告诉你你可以做到!:]
你可以在这里下载最终的游戏源代码。
这时,在游戏中随意拓展你的创造力!也许可以试着换成与你自己的绘画风格,或添加不同的武器或不同类型的怪物到游戏中!
在完成这个教程中你有问题或评论吗? 如果有,请加入我们论坛的讨论中! 我很期待你的来信。
原文位址:beginning-game-programming-for-teens-with-python
以上是如何用Python開發遊戲的詳細內容。更多資訊請關注PHP中文網其他相關文章!