IP Address: 54.147.142.16



前面教程第一部分已经成了小兔子的正确移动和转向,现在需要给它添加更多的动作以进行游戏的进一步开发。

让小兔子可以射箭

你的小兔子可以正确移动后,现在就可为它增加一些新动作了。给它增加一个射箭的动作如何呢?这个步骤实现起来有一点点复杂,因为你要跟踪每一枝射出去的箭,随时更新、旋转箭的状,并在箭离开游戏屏幕后删除它。

在程序的#2部分初始化参数程序中增加如下必要的变量。

acc=[0,0]
arrows=[]

第一个变更跟踪玩家的精准度,第二个变量跟踪所有的箭。精准度变量本质上是射击次数和命中次数的列表,稍后,我们根据这些信息来计算命中率。

在#3程序段加入如下代码以加载箭的图像:

arrow = pygame.image.load (“resources/images/bullet.png”)

当用户单击鼠标时,会触发pygame的MOUSEBUTTONDOWN事件。在#8中增加如下代码以进行事件处理。

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

这段代码检测是否有鼠标点击事件,如果点击了,会首先取得鼠标所在的位置,并在命中列表中的射出箭的数值增加1。最后根据鼠标位置来计算箭图片需要的旋转角度值,并将此值增加到前面定义的箭列表中。

将如下代码添加到#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”循环是正确的绘制出这些箭并进行正确的旋转。

现在运行程序,点击鼠标,你就可以得到一个会射箭的兔子了,正如图4所示:

图4

拿起武器,对付鼹鼠

当你有城堡和可以移动和射击的英雄,那么,少了什么呢?当然是兔子英雄可以射击的进攻城堡的敌人们。

在这个步骤中,你将随机生成冲向城堡的鼹鼠。随着游戏的进行,将会有更多的鼹鼠产生。现在让我们来看看需要做些什么,首先是将这些敌人加入到一个列表中,更新敌人信息,并将敌人都显示在屏幕上。在#2程序段加入如下内容:

badtimer=100
badtimer1=0
badguys=[[640,100]]
healthvalue=194

这里将设置一个计时器(当然你也可以设置为其它值),以保证在鼹鼠消逝一段时间后可以产生新的鼹鼠来充当敌人。当每个badtimer值减到0时会释放一个新的鼹鼠。
在#3程序段最后增加如下代码:

badguyimg1 = pygame.image.load("resources/images/badguy.png")
badguyimg=badguyimg1

程序第一行和之前加载图片的代码类似,而第二行是建立一个图片对象的复本,以便给这些鼹鼠敌人添加动画时更加容易。

现在更新代码,以便可以显示敌人。在#6.2程序段后添加如下代码:

# 6.3 – Draw moles
    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″,如果为”0″,则创建一个新的鼹鼠,并根据badtimer运行的次数重新设置badtimer值。第一个”for”循环会更新鼹鼠的x轴位置,并检测鼹鼠否离开屏幕,如果是话就删除它们。

第二个”for”循环将绘制所有的鼹鼠。为了在上面的代码中使用random函数,需要在#1程序段使用如下代码将其引入:

import random

在#4程序段的while语句后添加以下代码来让badtime值在每帧后发生变化:

badtimer-=1

运行程序,现在你会看到自己的程序比较像一个真正的游戏了,你可以让兔子移动、转动和射击,而鼹鼠则试图向它跑去。效果如图5所示:

图5

但是等一下,为什么鼹鼠不能攻击城堡呢。在#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)

如果鼹鼠图片的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)

运行一下程序,你的兔子就可以射箭杀敌了。

给游戏添加血条和计时器

现在你要做的就是给游戏添加一个计分方法,并展示小兔子做的怎么样。实现这个功能最简单的办法就是给游戏添加一下警示显示(Heads-Up Display-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)

下面的代码是用来显示血条的,但在绘制之前,需要在#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))

第一行代码用于绘制一个全红的生命条,然后,现根据生命值绘制也相应的血量条。如果你现在运行程序,会发现游戏有了计时器和血量条。注意这里的血量图片只有1像素宽,正好配合生命值来显示。

胜利或失败

接下来要做的就是设定一个胜利或失败的场景,让你的游戏更具可玩性。通过相应判断条件来退出主循环,进入显示胜利或失败的循环中,最终显示玩家胜利或失败,并在屏幕加以显示。

在程序代码末尾加入如下代码:

    #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”语句判断是否到时,第二个判断检测城堡是否被毁坏,第三个判断语句用于计算命中率。#11程序段是根据相应结果显示正确的画面。

注意

此处使用acc[0]*1.0是为了将acc[0]的值转换为浮点型数据,如是不这样写的话,那么除法的结果会返回一个整形数据。

如果你想显示胜利或失败的图片,那就需要在#3程序段将图片加载进来:

gameover = pygame.image.load("resources/images/gameover.png")
youwin = pygame.image.load("resources/images/youwin.png")

将程序段#4修改为如下代码,以保证循环正常:

# 4 – keep looping through
running = 1
exitcode = 0
while running:

其中running变量用于检测游戏是否结束、exitcode变量用于记录玩家是胜利还是失败。

加入音效

pygame让添加音效变得十分简单,首先,需要在#2程序段初始化音效模块mixer:

pygame.mixer.init()

然后在#3程序段将声音文件加到不同对象上:

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

要知道,给游戏添加背景音乐和给攻击添加音效后,会让游戏变得更加生动。

还可以做的内容

现在,你刚刚完成了一个简单好玩的游戏,这个游戏有背景音乐、有攻击音效、一只杀敌的小兔子以及不断产生的鼹鼠敢死队。当然,你还可以做的更多,你可以随意修改这款游戏,例如将图片换成自己的作品、增加新的武器以及加入更多的怪物等。

测试游戏
游戏运行前,请确认pygame已经正确安装,双击game.py文件,游戏就会启动,看看各项功能是否正常吧。

教程第一部分

源代码下载

One thought on “手把手Python和pygame游戏开发教程(二)”

发表评论

电子邮件地址不会被公开。 必填项已用*标注