本文目标

1,本章我们继续学习使用sprite木块,来实现我们游戏当中的碰撞检测

2,完成游戏实例:吃苹果小游戏

Pygame模块的Sprite碰撞检测

下面是几种常见的碰撞检测以及实现代码。

1.两个精灵之间的矩形检测

在只有两个精灵的时候我们可以使用pygame.sprite.collide_rect()函数来进行一对一的冲突检测。这个函数需要传递2个参数,并且每个参数都是需要继承自pygame.sprite.Sprite。

举个例子:

Python

spirte_1 = MySprite("sprite_1.png",200,200,1)

sprite_2 = MySprite("sprite_2.png",50,50,1)

result = pygame.sprite.collide_rect(sprite_1,sprite_2)

if result:

print("Collision occurred")

1

2

3

4

5

spirte_1=MySprite("sprite_1.png",200,200,1)

sprite_2=MySprite("sprite_2.png",50,50,1)

result=pygame.sprite.collide_rect(sprite_1,sprite_2)

ifresult:

print("Collision occurred")

MySprite使我们上个博客中创建的类,他继承自sprite。

Hint:这个函数还有一个非常有用的变体:pygame.sprite.collide_rect_ratio()。这个函数需要一个额外的浮点类型的参数。这个参数用来指定检测矩形的百分比。

有的时候我们希望冲突检测更精准一些的话,就可以收缩检测的区域,让矩形更小一些,就是通过这个参数控制的。使用方法如下:

Python

result = pygame.sprite.collide_rect_ratio( 0.5 )(sprite_1,sprite_2)

1

result=pygame.sprite.collide_rect_ratio(0.5)(sprite_1,sprite_2)

2.两个精灵之间的圆检测

矩形冲突检测并不适用于所有形状的精灵,因此pygame中还有个圆形冲突检测。pygame.sprite.collide_circle(),这个函数是基于每个精灵的半径值来进行检测的。

你可以自己指定半径,或者让函数自己计算半径。

Python

result = pygame.sprite.collide_circle(sprite_1,sprite_2)

if result:

print "Collision occurred"

1

2

3

result=pygame.sprite.collide_circle(sprite_1,sprite_2)

ifresult:

print"Collision occurred"

这个函数也有一个变体:pygame.sprite.collide_circle_ratio()。函数的功能和用法和上面的pygame.sprite.collide_rect_ratio()是类似的。

3.两个精灵之间的像素遮罩检测

如果矩形检测和圆形检测都不能满足我们的需求怎么办?别担心,pygame还为我们提供了一个更加精确的检测:pygame.sprite.collide_mask()。

这个函数接收两个精灵作为参数,返回值是一个bool变量。

Python

if pygame.sprite.collide_mask(sprite_1,sprite_2):

print ("Collision occurred")

1

2

ifpygame.sprite.collide_mask(sprite_1,sprite_2):

print("Collision occurred")

4.精灵和组之间的矩形冲突检测

Python

pygame.sprite.spritecollide(sprite,sprite_group,bool)。

1

pygame.sprite.spritecollide(sprite,sprite_group,bool)。

调用这个函数的时候,一个组中的所有精灵都会逐个地对另外一个单个精灵进行冲突检测,发生冲突的精灵会作为一个列表返回。

这个函数的第一个参数就是单个精灵,第二个参数是精灵组,第三个参数是一个bool值,最后这个参数起了很大的作用。当为True的时候,会删除组中所有冲突的精灵,False的时候不会删除冲突的精灵

Python

list_collide = pygame.sprite.spritecollide(sprite,sprite_group,False);

1

list_collide=pygame.sprite.spritecollide(sprite,sprite_group,False);

另外这个函数也有一个变体:pygame.sprite.spritecollideany()。这个函数在判断精灵组和单个精灵冲突的时候,会返回一个bool值。

5.精灵组之间的矩形冲突检测

Python

pygame.sprite.groupcollide()。

1

pygame.sprite.groupcollide()。

利用这个函数可以检测两个组之间的冲突,他返回一个字典。(键-值对)

游戏实例—吃苹果小游戏

先看一下效果图:

游戏开始会在屏幕上随机生成一些苹果,玩家通过上下左右方向键来控制人物去吃苹果。

吃到一个苹果,能量条就会增长一些,直到吃完所有的苹果,游戏结束。

【源代码+素材下载地址】

1.模块化编程

这个游戏会使用到我们上个博客创建的MySprite类,为了让这个类变的更具有可重用性,我们将它做成一个模块。

只要将类的实现代码放进一个单独的py,然后在使用的时候引入他就可以了。比如我们将这个单独的py取名为:MyLibrary.py

Python

import MyLibrary

1

importMyLibrary

这样在使用这个模块里面的函数和类的时候我们只需要这样做:MyLibrary.fun()。但是这样看起来也不是很方便的说,因此我们使用import的变体:

Python

from MyLibrary import *

#将文件中的所有内容引入

1

2

fromMyLibraryimport*

#将文件中的所有内容引入

2.高级行走动画

通过效果图,我们可以看到程序里面用到了高级的行走动画,人物一共有上下左右四个方向的行走动画。

实际上这个精灵序列图里面一共有8个方向的行走动画,为了简便,我们只是使用了其中的四方向,如图:

通过行的数目就可以来方便的区分,动画是向左走还是向右走的。现在说起来可能有点比较难以理解,看完下面的代码就比较好理解了。我们还为Mysprite这个类增加了一个velocity属性,以便精灵可以根据其方向来移动。

Python

class MySprite(pygame.sprite.Sprite):

def __init__(self):

pygame.sprite.Sprite.__init__(self)

self.master_image = None

self.frame = 0

self.old_frame = -1

self.frame_width = 1

self.frame_height = 1

self.first_frame = 0

self.last_frame = 0

self.columns = 1

self.last_time = 0

self.direction = 0

#新增了velocity属性,他是一个point

self.velocity = Point(0.0,0.0)

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

classMySprite(pygame.sprite.Sprite):

def__init__(self):

pygame.sprite.Sprite.__init__(self)

self.master_image=None

self.frame=0

self.old_frame=-1

self.frame_width=1

self.frame_height=1

self.first_frame=0

self.last_frame=0

self.columns=1

self.last_time=0

self.direction=0

#新增了velocity属性,他是一个point

self.velocity=Point(0.0,0.0)

当按UP键的时候,将方向设置为0(向上),按DOWN键的时候,将方向设置为4(向下),按LEFT键,将方向设置为6(向左),按RIGHT键,将方向设置为2(向右)

Python

if keys[K_ESCAPE]: sys.exit()

elif keys[K_UP] or keys[K_w]:

player.direction = 0

player_moving = True

elif keys[K_RIGHT] or keys[K_d]:

player.direction = 2

player_moving = True

elif keys[K_DOWN] or keys[K_s]:

player.direction = 4

player_moving = True

elif keys[K_LEFT] or keys[K_a]:

player.direction = 6

player_moving = True

1

2

3

4

5

6

7

8

9

10

11

12

13

ifkeys[K_ESCAPE]:sys.exit()

elifkeys[K_UP]orkeys[K_w]:

player.direction=0

player_moving=True

elifkeys[K_RIGHT]orkeys[K_d]:

player.direction=2

player_moving=True

elifkeys[K_DOWN]orkeys[K_s]:

player.direction=4

player_moving=True

elifkeys[K_LEFT]orkeys[K_a]:

player.direction=6

player_moving=True

这个方向就是我们之前说的用来决定使用动画帧的范围方法。并且还有一个player_moving变量,在按键按下的时候将它置为True,也就是按键按下的时候才会有行走动画,否则人物将会是静止的。

3.判断人物与苹果的冲突

为了获得更精准的冲突,我们组合使用了不同的冲突函数。

首先用pygame.sprite.spritecollideany来判断玩家是否与任意的苹果产生了碰撞,如果产生碰撞,则再使用pygame.sprite.collide_circle_ratio缩小检测范围做一次检测,

看看到底是哪个苹果和人物产生了冲突,然后将产生碰撞的果实从精灵组中移除(remove)。

Python

#检测玩家是否与食物冲突,是否吃到果实

attacker = None

attacker = pygame.sprite.spritecollideany(player, food_group)

if attacker != None:

if pygame.sprite.collide_circle_ratio(0.65)(player,attacker):

player_health +=2;

food_group.remove(attacker);

1

2

3

4

5

6

7

#检测玩家是否与食物冲突,是否吃到果实

attacker=None

attacker=pygame.sprite.spritecollideany(player,food_group)

ifattacker!=None:

ifpygame.sprite.collide_circle_ratio(0.65)(player,attacker):

player_health+=2;

food_group.remove(attacker);

吃了果实以后,能量值会增加,然后我们通过绘制一个矩形的能量条来反映给用户。

好了最后上一下全部的源代码(不包含MyLibrary模块):

Python

import itertools, sys, time, random, math, pygame

from pygame.locals import *

from MyLibrary import *

def calc_velocity(direction, vel=1.0):

velocity = Point(0,0)

if direction == 0: #上

velocity.y = -vel

elif direction == 2: #右

velocity.x = vel

elif direction == 4: #下

velocity.y = vel

elif direction == 6: #左

velocity.x = -vel

return velocity

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, 80

player.direction = 4

player_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 = 0

while True:

timer.tick(30)

ticks = pygame.time.get_ticks()

for event in pygame.event.get():

if event.type == QUIT:

pygame.quit()

sys.exit()

keys = pygame.key.get_pressed()

if keys[K_ESCAPE]: sys.exit()

elif keys[K_UP] or keys[K_w]:

player.direction = 0

player_moving = True

elif keys[K_RIGHT] or keys[K_d]:

player.direction = 2

player_moving = True

elif keys[K_DOWN] or keys[K_s]:

player.direction = 4

player_moving = True

elif keys[K_LEFT] or keys[K_a]:

player.direction = 6

player_moving = True

else:

player_moving = False

if not game_over:

#根据角色的不同方向,使用不同的动画帧

player.first_frame = player.direction * player.columns

player.last_frame = player.first_frame + player.columns-1

if player.frame < player.first_frame:

player.frame = player.first_frame

if not player_moving:

#当停止按键(即人物停止移动的时候),停止更新动画帧

player.frame = player.first_frame = player.last_frame

else:

player.velocity = calc_velocity(player.direction, 1.5)

player.velocity.x *= 1.5

player.velocity.y *= 1.5

#更新玩家精灵组

player_group.update(ticks, 50)

#移动玩家

if player_moving:

player.X += player.velocity.x

player.Y += player.velocity.y

if player.X < 0: player.X = 0

elif player.X > 700: player.X = 700

if player.Y < 0: player.Y = 0

elif player.Y > 500: player.Y = 500

#检测玩家是否与食物冲突,是否吃到果实

attacker = None

attacker = pygame.sprite.spritecollideany(player, food_group)

if attacker != None:

if pygame.sprite.collide_circle_ratio(0.65)(player,attacker):

player_health +=2;

food_group.remove(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)

#绘制玩家血量条

pygame.draw.rect(screen, (50,150,50,180), Rect(300,570,player_health*2,25))

pygame.draw.rect(screen, (100,200,100,180), Rect(300,570,200,25), 2)

if game_over:

print_text(font, 300, 100, "G A M E O V E R")

pygame.display.update()

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

importitertools,sys,time,random,math,pygame

frompygame.localsimport*

fromMyLibraryimport*

defcalc_velocity(direction,vel=1.0):

velocity=Point(0,0)

ifdirection==0:#上

velocity.y=-vel

elifdirection==2:#右

velocity.x=vel

elifdirection==4:#下

velocity.y=vel

elifdirection==6:#左

velocity.x=-vel

returnvelocity

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,80

player.direction=4

player_group.add(player)

#初始化food精灵组

forninrange(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=0

whileTrue:

timer.tick(30)

ticks=pygame.time.get_ticks()

foreventinpygame.event.get():

ifevent.type==QUIT:

pygame.quit()

sys.exit()

keys=pygame.key.get_pressed()

ifkeys[K_ESCAPE]:sys.exit()

elifkeys[K_UP]orkeys[K_w]:

player.direction=0

player_moving=True

elifkeys[K_RIGHT]orkeys[K_d]:

player.direction=2

player_moving=True

elifkeys[K_DOWN]orkeys[K_s]:

player.direction=4

player_moving=True

elifkeys[K_LEFT]orkeys[K_a]:

player.direction=6

player_moving=True

else:

player_moving=False

ifnotgame_over:

#根据角色的不同方向,使用不同的动画帧

player.first_frame=player.direction*player.columns

player.last_frame=player.first_frame+player.columns-1

ifplayer.frame

player.frame=player.first_frame

ifnotplayer_moving:

#当停止按键(即人物停止移动的时候),停止更新动画帧

player.frame=player.first_frame=player.last_frame

else:

player.velocity=calc_velocity(player.direction,1.5)

player.velocity.x*=1.5

player.velocity.y*=1.5

#更新玩家精灵组

player_group.update(ticks,50)

#移动玩家

ifplayer_moving:

player.X+=player.velocity.x

player.Y+=player.velocity.y

ifplayer.X<0:player.X=0

elifplayer.X>700:player.X=700

ifplayer.Y<0:player.Y=0

elifplayer.Y>500:player.Y=500

#检测玩家是否与食物冲突,是否吃到果实

attacker=None

attacker=pygame.sprite.spritecollideany(player,food_group)

ifattacker!=None:

ifpygame.sprite.collide_circle_ratio(0.65)(player,attacker):

player_health+=2;

food_group.remove(attacker);

ifplayer_health>100:player_health=100

#更新食物精灵组

food_group.update(ticks,50)

iflen(food_group)==0:

game_over=True

#清屏

screen.fill((50,50,100))

#绘制精灵

food_group.draw(screen)

player_group.draw(screen)

#绘制玩家血量条

pygame.draw.rect(screen,(50,150,50,180),Rect(300,570,player_health*2,25))

pygame.draw.rect(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()

在下个博客里面我们将一起学习在游戏里面常用的一些数据结构: 数据,列表,元组,队列,栈。

vpython 贞测碰撞_7、Pygame碰撞检测相关推荐

  1. vpython 贞测碰撞_python碰撞检测?

    所以我一直在为一个项目开发一个python游戏,现在我遇到了一个问题,如果我在游戏中设置了一个障碍,我就不能让它对我的图片做出响应,就像我的图片与它发生碰撞一样,游戏就结束了.我已经做了很长一段时间了 ...

  2. vpython 贞测碰撞_球碰撞vPython问题

    所以我在编写一个斯诺克游戏,我决定找出如何使球相互碰撞的最好方法是在一个单独的程序中这样做,然后复制进去.我是一个很有能力的数学家,所以我坐下来,画了一个事件,然后用数学的方法研究了实际发生的事情.在 ...

  3. vpython 贞测碰撞_VPython - example - 模拟球在两板之间的碰撞

    作者:liuyuan_jq 2011-04-10 ######################################### # Import the library(s) ######### ...

  4. pygame碰撞检测

    最近在学Pygame,花一段时间做了一个异常简陋版的"打砖块". 这次重点说一下困扰我比较长时间的碰撞检测(个人太菜..). 按照网上教程比较普遍的方法(也可能是我没看见别的),碰 ...

  5. java两个小球相撞_JAVA小游戏之两个物体碰撞产生的碰撞检测

    首先必须了解两个物体,在移动时,会有怎样的效果,比如沪我们小时候耍过的坦克大战.看起来很简单,但是写起代码来,复杂的要多: 下面举个例子: // 构造一个新的 Rectangle,其左上角的坐标为 ( ...

  6. pygame.mask原理及使用pygame.mask实现精准碰撞检测

    通常一个游戏中会有很多角色出现,而这些角色之间的"碰撞"在所难免,例如炮弹是否击中了飞机等.碰撞检测在绝大多数游戏中都是一个必须处理的至关重要的问题.pygame提供了多种碰撞的检 ...

  7. Pygame精灵和碰撞检测

    在开始学习相关知识点之前,我们有必要先学习精灵和碰撞检测的含义. 精灵(英文译为 Sprite),其实在一个游戏程序中,精灵本质指的是一张张小尺寸的图片,比如游戏中的各种道具.人物.场景装饰等,它们都 ...

  8. 如何用Python实现超级玛丽的人物行走和碰撞检测?

    作者 | marble_xu 编辑 | 郭芮 出品 | CSDN博客 在<如何用 Python 实现超级玛丽的界面和状态机?>这篇文章中我们讲解如何用代码实现界面和状态机,本文详解人物行走 ...

  9. 基于pygame实现的飞机大战游戏

    目录 1.引言 1.1 背景 1.2 意义 1.3 功能 2.系统结构 2.1 整体框架 2.2 精灵与精灵组 2.3 功能介绍 2.3.1 玩家飞机 2.3.2 敌机类型和关卡设定 2.3.3 敌机 ...

最新文章

  1. 《连线》杂志:2015年六大安全威胁预测
  2. c++socket多个客户端通过不同端口与一个服务端通信_手写RPC,深入底层理解整个RPC通信...
  3. VA01销售订单增强MV45AFZZ注意点
  4. 千万千万不要运行的 Linux 命令
  5. Windows CE(C#)嵌入式应用开发pdf
  6. python测试用例管理模块_python-selenium并发执行测试用例(方法一 各模块每一条并发执行)...
  7. Lottie-iOS的应用及部分源码分析
  8. 自动量程万用表的实现原理_自动量程万用表设计方案
  9. 一种基于linux系统的精准流量统计方法
  10. amd的服务器cpu型号大全,amdcpu型号大全
  11. 关于周期性学习率(Cyclical Learning Rate, CLR)
  12. python图片转手绘_python图片转素描软件
  13. 联想T430i笔记本电脑无声音
  14. 串口通信协议(基于面试),与及树莓派与电脑之间串口通信
  15. 20180710-B · Craft Beer USA · ggplot2 geom_density_ridges_gradient 核密度估计峰峦图 字体设置 · R 语言数据可视化 案例 源码
  16. EXCEL 启动参数设置
  17. 释疑:SI-RNTI,C-RNTI,P-RNTI,RA-RNTI,SPS-RNTI
  18. 谈谈MySQL查询优化
  19. 016 | JavaWeb芝麻开门博客网项目源码 | 大学生毕业设计 | 极致技术工厂
  20. 做了6年php,30岁程序员要去做外包,这个选择靠谱么?网友:别!

热门文章

  1. 2018南京网络赛L题 Magical Girl Haze(分层图+优先队列优化的dijkstra)
  2. 3.5 《数据库系统概论》之基本表更新(INSERT、UPDATE、ALTER、DELETE)与视图VIEW(定义、查询、更新)
  3. php代码升级更新机制,php如何实现更新功能
  4. python正则表达式操作指南_Python重新正则表达式操作指南
  5. linux / pkg-config 原理及用法
  6. Cpp 对象模型探索 / 含有虚基类的类的内存布局
  7. node 没有界面的浏览器_node.js爬虫入门(二)爬取动态页面(puppeteer)
  8. Openwrt系统初始时间
  9. python批量查询数据库_Python + MySQL 批量查询百度收录
  10. 浏览器解析JavaScript原理