vpython 贞测碰撞_7、Pygame碰撞检测
本文目標(biāo)
1,本章我們繼續(xù)學(xué)習(xí)使用sprite木塊,來實現(xiàn)我們游戲當(dāng)中的碰撞檢測
2,完成游戲?qū)嵗?#xff1a;吃蘋果小游戲
Pygame模塊的Sprite碰撞檢測
下面是幾種常見的碰撞檢測以及實現(xiàn)代碼。
1.兩個精靈之間的矩形檢測
在只有兩個精靈的時候我們可以使用pygame.sprite.collide_rect()函數(shù)來進行一對一的沖突檢測。這個函數(shù)需要傳遞2個參數(shù),并且每個參數(shù)都是需要繼承自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使我們上個博客中創(chuàng)建的類,他繼承自sprite。
Hint:這個函數(shù)還有一個非常有用的變體:pygame.sprite.collide_rect_ratio()。這個函數(shù)需要一個額外的浮點類型的參數(shù)。這個參數(shù)用來指定檢測矩形的百分比。
有的時候我們希望沖突檢測更精準一些的話,就可以收縮檢測的區(qū)域,讓矩形更小一些,就是通過這個參數(shù)控制的。使用方法如下:
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(),這個函數(shù)是基于每個精靈的半徑值來進行檢測的。
你可以自己指定半徑,或者讓函數(shù)自己計算半徑。
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"
這個函數(shù)也有一個變體:pygame.sprite.collide_circle_ratio()。函數(shù)的功能和用法和上面的pygame.sprite.collide_rect_ratio()是類似的。
3.兩個精靈之間的像素遮罩檢測
如果矩形檢測和圓形檢測都不能滿足我們的需求怎么辦?別擔(dān)心,pygame還為我們提供了一個更加精確的檢測:pygame.sprite.collide_mask()。
這個函數(shù)接收兩個精靈作為參數(shù),返回值是一個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)。
調(diào)用這個函數(shù)的時候,一個組中的所有精靈都會逐個地對另外一個單個精靈進行沖突檢測,發(fā)生沖突的精靈會作為一個列表返回。
這個函數(shù)的第一個參數(shù)就是單個精靈,第二個參數(shù)是精靈組,第三個參數(shù)是一個bool值,最后這個參數(shù)起了很大的作用。當(dāng)為True的時候,會刪除組中所有沖突的精靈,False的時候不會刪除沖突的精靈
Python
list_collide = pygame.sprite.spritecollide(sprite,sprite_group,False);
1
list_collide=pygame.sprite.spritecollide(sprite,sprite_group,False);
另外這個函數(shù)也有一個變體:pygame.sprite.spritecollideany()。這個函數(shù)在判斷精靈組和單個精靈沖突的時候,會返回一個bool值。
5.精靈組之間的矩形沖突檢測
Python
pygame.sprite.groupcollide()。
1
pygame.sprite.groupcollide()。
利用這個函數(shù)可以檢測兩個組之間的沖突,他返回一個字典。(鍵-值對)
游戲?qū)嵗蕴O果小游戲
先看一下效果圖:
游戲開始會在屏幕上隨機生成一些蘋果,玩家通過上下左右方向鍵來控制人物去吃蘋果。
吃到一個蘋果,能量條就會增長一些,直到吃完所有的蘋果,游戲結(jié)束。
【源代碼+素材下載地址】
1.模塊化編程
這個游戲會使用到我們上個博客創(chuàng)建的MySprite類,為了讓這個類變的更具有可重用性,我們將它做成一個模塊。
只要將類的實現(xiàn)代碼放進一個單獨的py,然后在使用的時候引入他就可以了。比如我們將這個單獨的py取名為:MyLibrary.py
Python
import MyLibrary
1
importMyLibrary
這樣在使用這個模塊里面的函數(shù)和類的時候我們只需要這樣做:MyLibrary.fun()。但是這樣看起來也不是很方便的說,因此我們使用import的變體:
Python
from MyLibrary import *
#將文件中的所有內(nèi)容引入
1
2
fromMyLibraryimport*
#將文件中的所有內(nèi)容引入
2.高級行走動畫
通過效果圖,我們可以看到程序里面用到了高級的行走動畫,人物一共有上下左右四個方向的行走動畫。
實際上這個精靈序列圖里面一共有8個方向的行走動畫,為了簡便,我們只是使用了其中的四方向,如圖:
通過行的數(shù)目就可以來方便的區(qū)分,動畫是向左走還是向右走的。現(xiàn)在說起來可能有點比較難以理解,看完下面的代碼就比較好理解了。我們還為Mysprite這個類增加了一個velocity屬性,以便精靈可以根據(jù)其方向來移動。
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)
當(dāng)按UP鍵的時候,將方向設(shè)置為0(向上),按DOWN鍵的時候,將方向設(shè)置為4(向下),按LEFT鍵,將方向設(shè)置為6(向左),按RIGHT鍵,將方向設(shè)置為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變量,在按鍵按下的時候?qū)⑺脼門rue,也就是按鍵按下的時候才會有行走動畫,否則人物將會是靜止的。
3.判斷人物與蘋果的沖突
為了獲得更精準的沖突,我們組合使用了不同的沖突函數(shù)。
首先用pygame.sprite.spritecollideany來判斷玩家是否與任意的蘋果產(chǎn)生了碰撞,如果產(chǎn)生碰撞,則再使用pygame.sprite.collide_circle_ratio縮小檢測范圍做一次檢測,
看看到底是哪個蘋果和人物產(chǎn)生了沖突,然后將產(chǎn)生碰撞的果實從精靈組中移除(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()
#創(chuàng)建精靈組
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:
#根據(jù)角色的不同方向,使用不同的動畫幀
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:
#當(dāng)停止按鍵(即人物停止移動的時候),停止更新動畫幀
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()
#創(chuàng)建精靈組
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:
#根據(jù)角色的不同方向,使用不同的動畫幀
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:
#當(dāng)停止按鍵(即人物停止移動的時候),停止更新動畫幀
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()
在下個博客里面我們將一起學(xué)習(xí)在游戲里面常用的一些數(shù)據(jù)結(jié)構(gòu): 數(shù)據(jù),列表,元組,隊列,棧。
總結(jié)
以上是生活随笔為你收集整理的vpython 贞测碰撞_7、Pygame碰撞检测的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 越野滑雪板在我国的发展趋势?
- 下一篇: 成者会议星会不会太贵啊?