python游戏脚本检测_【python游戏编程之旅】第七篇---
pygame中的冲突检测技术
本系列博客介绍以python+pygame库进⾏⼩游戏的开发。有写的不对之处还望各位海涵。
这次我们来⼀起学习pygame中的冲突检测技术。
pygame⽀持⾮常多的冲突检测技术,我们来⼀⼀的看⼀下他们是如何使⽤的:
⼀、精灵与精灵之间的冲突检测
1.两个精灵之间的矩形检测
在只有两个精灵的时候我们可以使⽤llide_rect()函数来进⾏⼀对⼀的冲突检测。这个函数需要传递2个参数,并且每个参数都是需要继承⾃pygame.sprite.Sprite。
举个例⼦:
spirte_1 = MySprite("sprite_1.png",200,200,1)
sprite_2= MySprite("sprite_2.png",50,50,1)
result=llide_rect(sprite_1,sprite_2)ifresult:print "Collision occurred"
MySprite使我们上个博客中创建的类,他继承⾃sprite。
Hint:这个函数还有⼀个⾮常有⽤的变体:llide_rect_ratio()。这个函数需要⼀个额外的浮点类型的参数。这个参数⽤来指定检测矩形的百分⽐。
邱泽资料有的时候我们希望冲突检测更精准⼀些的话,就可以收缩检测的区域,让矩形更⼩⼀些,就是通过这个参数控制的。使⽤⽅法如下:
result = llide_rect_ratio( 0.5 )(sprite_1,sprite_2)
2.两个精灵之间的圆检测
矩形冲突检测并不适⽤于所有形状的精灵,因此pygame中还有个圆形冲突检测。llide_circle(),这个函数是基于每个精灵的半径值来进⾏检测的。
你可以⾃⼰指定半径,或者让函数⾃⼰计算半径。
result =llide_circle(sprite_1,sprite_2)ifresult:print "Collision occurred"
这个函数也有⼀个变体:llide_circle_ratio()。函数的功能和⽤法和上⾯的llide_rect_ratio()是类似的。
3.两个精灵之间的像素遮罩检测
如果矩形检测和圆形检测都不能满⾜我们的需求怎么办?别担⼼,pygame还为我们提供了⼀个更加精确的检测:
llide_mask()。
这个函数接收两个精灵作为参数,返回值是⼀个bool变量。
llide_mask(sprite_1,sprite_2):print ("Collision occurred")
4.精灵和组之间的矩形冲突检测
pygame.sprite.spritecollide(sprite,sprite_group,bool)。调⽤这个函数的时候,⼀个组中的所有精灵都会逐个地对另外⼀个单个精灵进⾏冲突检测,发⽣冲突的精灵会作为⼀个列表返回。
这个函数的第⼀个参数就是单个精灵,第⼆个参数是精灵组,第三个参数是⼀个bool值,最后这个参数起了很⼤的作⽤。当为True的时候,会删除组中所有冲突的精灵,False的时候不会删除冲突的精灵
list_collide = pygame.sprite.spritecollide(sprite,sprite_group,False);
另外这个函数也有⼀个变体:pygame.sprite.spritecollideany()。这个函数在判断精灵组和单个精灵冲突的时候,会返回⼀个bool值。
5.精灵组之间的矩形冲突检测
upcollide()。利⽤这个函数可以检测两个组之间的冲突,他返回⼀个字典。(键-值对)
好了⼤概常⽤的⼏种冲突检测函数我们已经了解完了,下⾯我们做⼀个⼩⼩的实例实际运⽤⼀下上⾯学到的知识。
⼆、冲突检测实例---吃苹果⼩游戏
先看⼀下效果图:
游戏开始会在屏幕上随机⽣成⼀些苹果,玩家通过上下左右⽅向键来控制⼈物去吃苹果。
吃到⼀个苹果,能量条就会增长⼀些,直到吃完所有的苹果,游戏结束。
【源代码+素材下载地址】
1.模块化编程
这个游戏会使⽤到我们上个博客创建的MySprite类,为了让这个类变的更具有可重⽤性,我们将它做成⼀个模块。
华为手机怎么开美颜只要将类的实现代码放进⼀个单独的py,然后在使⽤的时候引⼊他就可以了。⽐如我们将这个单独的py取名为:MyLibrary.py
import MyLibrary
这样在使⽤这个模块⾥⾯的函数和类的时候我们只需要这样做:MyLibrary.fun()。但是这样看起来也不是很⽅便的说,因此我们使⽤import的变体:
from MyLibrary import *
#将⽂件中的所有内容引⼊
2.⾼级⾏⾛动画
通过效果图,我们可以看到程序⾥⾯⽤到了⾼级的⾏⾛动画,⼈物⼀共有上下左右四个⽅向的⾏⾛动画。
实际上这个精灵序列图⾥⾯⼀共有8个⽅向的⾏⾛动画,为了简便,我们只是使⽤了其中的四⽅向,如图:
通过⾏的数⽬就可以来⽅便的区分,动画是向左⾛还是向右⾛的。现在说起来可能有点⽐较难以理解,看完下⾯的代码就⽐较好理解了。我们还为Mysprite这个类增加了⼀个velocity属性,以便精灵可以根据其⽅向来移动。
classMySprite(pygame.sprite.Sprite):def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.master_image=None
self.frame=0
self.old_frame= -1self.frame_width= 1self.frame_height= 1self.first_frame=0
self.last_frame=0
self.direction=0#新增了velocity属性,他是⼀个point
self.velocity = Point(0.0,0.0)
当按UP键的时候,将⽅向设置为0(向上),按DOWN键的时候,将⽅向设置为4(向下),按LEFT键,将⽅向设置为6(向左),按RIGHT键,将⽅向设置为2(向右)
ifkeys[K_ESCAPE]: it()elif keys[K_UP] orkeys[K_w]:
player.direction=0
player_moving=Trueelif keys[K_RIGHT] orkeys[K_d]:
player.direction= 2player_moving=Trueelif keys[K_DOWN] orkeys[K_s]:
player.direction= 4player_moving=Trueelif keys[K_LEFT] orkeys[K_a]:
player.direction= 6player_moving= True
这个⽅向就是我们之前说的⽤来决定使⽤动画帧的范围⽅法。并且还有⼀个player_moving变量,在按键按下的时候将它置为True,也就是按键按下的时候才会有⾏⾛动画,否则⼈物将会是静⽌的。
3.判断⼈物与苹果的冲突
为了获得更精准的冲突,我们组合使⽤了不同的冲突函数。
⾸先⽤pygame.sprite.spritecollideany来判断玩家是否与任意的苹果产⽣了碰撞,如果产⽣碰撞,则再使⽤
llide_circle_ratio缩⼩检测范围做⼀次检测,
看看到底是哪个苹果和⼈物产⽣了冲突,然后将产⽣碰撞的果实从精灵组中移除(remove)。
#检测玩家是否与⾷物冲突,是否吃到果实
attacker =None
attacker=pygame.sprite.spritecollideany(player, food_group)if attacker !=None:if llide_circle_ratio(0.65) (player,attacker):
player_health+=2;
ve(attacker);
吃了果实以后,能量值会增加,然后我们通过绘制⼀个矩形的能量条来反映给⽤户。
好了最后上⼀下全部的源代码(不包含MyLibrary模块):
importitertools, sys, time, random, math, pygamefrom pygame.locals import *
费霞
from MyLibrary import *
def calc_velocity(direction, vel=1.0):
velocity=Point(0,0)if direction == 0: #上
velocity.y = -velelif direction == 2: #右
velocity.x =velelif direction == 4: #下
velocity.y =velelif direction == 6: #左
velocity.x = -velreturnvelocity
pygame.init()
screen= pygame.display.set_mode((800,600))
pygame.display.set_caption("吃苹果")
font= pygame.font.Font(None, 36)
timer=pygame.time.Clock()#创建精灵组
player_group =pygame.sprite.Group()
food_group=pygame.sprite.Group()#初始化玩家精灵组
player =MySprite()
player.load("farmer walk.png", 96, 96, 8)
player.position= 80, 80player.direction= 4player_group.add(player)#初始化food精灵组
for n in range(1,50):
food=MySprite();
food.load("food_low.png", 35, 35, 1)
food.position= random.randint(0,780),random.randint(0,580)
food_group.add(food)
game_over=False
李莹念微博player_moving=False
player_health=0whileTrue:
timer.tick(30)
ticks=_ticks()for event ():pe ==QUIT:
pygame.quit()
keys=_pressed()ifkeys[K_ESCAPE]: it()elif keys[K_UP] orkeys[K_w]:
player.direction=0
player_moving=Trueelif keys[K_RIGHT] orkeys[K_d]:
player.direction= 2player_moving=Trueelif keys[K_DOWN] orkeys[K_s]:
player.direction= 4player_moving=Trueelif keys[K_LEFT] orkeys[K_a]:
player.direction= 6player_moving=Trueelse:
player_moving=Falseif notgame_over:#根据⾓⾊的不同⽅向,使⽤不同的动画帧
失恋了很痛苦怎么办
player.first_frame = player.direction *lumns
player.last_frame= player.first_frame + lumns-1
if player.frame
player.frame=player.first_frameif notplayer_moving:#当停⽌按键(即⼈物停⽌移动的时候),停⽌更新动画帧player.frame = player.first_frame =player.last_frameelse:
player.velocity= calc_velocity(player.direction, 1.5)
player.velocity.x*= 1.5player.velocity.y*= 1.5
#更新玩家精灵组
player_group.update(ticks, 50)#移动玩家
ifplayer_moving:
player.X+=player.velocity.x
player.Y+=player.velocity.yif player.X < 0: player.X =0elif player.X > 700: player.X = 700
if player.Y < 0: player.Y =0elif player.Y > 500: player.Y = 500
#检测玩家是否与⾷物冲突,是否吃到果实
attacker =None
attacker=pygame.sprite.spritecollideany(player, food_group)if attacker !=None:if llide_circle_ratio(0.65) (player,attacker):
player_health+=2;
ve(attacker);if player_health > 100: player_health = 100
#更新⾷物精灵组
food_group.update(ticks, 50)if len(food_group) ==0:
game_over=True#清屏
screen.fill((50,50,100))#绘制精灵
food_group.draw(screen)
刘雨欣三围player_group.draw(screen)#绘制玩家⾎量条
(screen, (50,150,50,180), Rect(300,570,player_health*2,25))
(screen, (100,200,100,180), Rect(300,570,200,25), 2)ifgame_over:
print_text(font,300, 100, "G A M E O V E R")
pygame.display.update()
在下个博客⾥⾯我们将⼀起学习在游戏⾥⾯常⽤的⼀些数据结构: 数据,列表,元组,队列,栈。