python 游戏脚本 检测_【python游戏编程之旅】第七篇---pygame中的冲突检测技术

本系列博客介绍以python+pygame库进行小游戏的开发。有写的不对之处还望各位海涵。

这次我们来一起学习pygame中的冲突检测技术。

pygame支持非常多的冲突检测技术,我们来一一的看一下他们是如何使用的:

一、精灵与精灵之间的冲突检测

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

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

举个例子:

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()。这个函数需要一个额外的浮点类型的参数。这个参数用来指定检测矩形的百分比。

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

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

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

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

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

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变量。

ifpygame.sprite.collide_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.精灵组之间的矩形冲突检测

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

好了大概常用的几种冲突检测函数我们已经了解完了,下面我们做一个小小的实例实际运用一下上面学到的知识。

二、冲突检测实例---吃苹果小游戏

先看一下效果图:

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

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

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

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.columns= 1self.last_time=0

self.direction=0#新增了velocity属性,他是一个point

self.velocity = Point(0.0,0.0)

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

ifkeys[K_ESCAPE]: sys.exit()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来判断玩家是否与任意的苹果产生了碰撞,如果产生碰撞,则再使用pygame.sprite.collide_circle_ratio缩小检测范围做一次检测,

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

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

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

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

好了最后上一下全部的源代码(不包含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=pygame.time.get_ticks()for event inpygame.event.get():if event.type ==QUIT:

pygame.quit()

sys.exit()

keys=pygame.key.get_pressed()ifkeys[K_ESCAPE]: sys.exit()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 *player.columns

player.last_frame= player.first_frame + player.columns-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 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)ifgame_over:

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

pygame.display.update()

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

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,我们来继续编写2D跑酷游戏脚本。 首先,我们需要导入一些库: ```python import pygame import random import time ``` 然后,我们需要定义一些常量: ```python # 游戏窗口大小 WINDOW_WIDTH = 800 WINDOW_HEIGHT = 600 # 背景颜色 BG_COLOR = (255, 255, 255) # 玩家初始位置 PLAYER_X = 100 PLAYER_Y = 400 # 玩家速度 PLAYER_SPEED_X = 5 PLAYER_SPEED_Y = 0 # 障碍物速度 OBSTACLE_SPEED = 5 # 障碍物间距 OBSTACLE_DISTANCE = 200 # 障碍物宽度 OBSTACLE_WIDTH = 30 # 障碍物高度范围 OBSTACLE_HEIGHT_MIN = 50 OBSTACLE_HEIGHT_MAX = 300 ``` 接着,我们需要定义一些类: ```python class Player(pygame.sprite.Sprite): def __init__(self): super().__init__() self.image = pygame.Surface((30, 50)) self.image.fill((0, 0, 255)) self.rect = self.image.get_rect() self.rect.x = PLAYER_X self.rect.y = PLAYER_Y self.speed_x = PLAYER_SPEED_X self.speed_y = PLAYER_SPEED_Y def update(self): self.rect.x += self.speed_x self.rect.y += self.speed_y class Obstacle(pygame.sprite.Sprite): def __init__(self, x, y, height): super().__init__() self.image = pygame.Surface((OBSTACLE_WIDTH, height)) self.image.fill((255, 0, 0)) self.rect = self.image.get_rect() self.rect.x = x self.rect.y = y def update(self): self.rect.x -= OBSTACLE_SPEED ``` Player 类表示玩家,包括玩家的图像、位置和速度等信息。Obstacle 类表示障碍物,包括障碍物的图像、位置和速度等信息。 接着,我们需要初始化游戏: ```python pygame.init() window = pygame.display.set_mode((WINDOW_WIDTH, WINDOW_HEIGHT)) pygame.display.set_caption('跑酷游戏') clock = pygame.time.Clock() all_sprites = pygame.sprite.Group() player = Player() all_sprites.add(player) obstacle_list = [] last_obstacle_x = WINDOW_WIDTH score = 0 font = pygame.font.SysFont(None, 50) ``` 我们创建了一个窗口,设置了窗口标题,创建了一个时钟对象,创建了一个精灵组,创建了一个玩家对象并添加到精灵组,创建了一个障碍物列表和最后一个障碍物的 x 坐标,创建了一个得分变量和一个字体对象。 然后,我们需要定义一些函数: ```python def add_obstacle(): global last_obstacle_x, score height = random.randint(OBSTACLE_HEIGHT_MIN, OBSTACLE_HEIGHT_MAX) obstacle = Obstacle(last_obstacle_x + OBSTACLE_DISTANCE, WINDOW_HEIGHT - height, height) obstacle_list.append(obstacle) all_sprites.add(obstacle) last_obstacle_x = obstacle.rect.x score += 1 def draw_text(text, x, y): image = font.render(text, True, (0, 0, 0)) window.blit(image, (x, y)) def game_over(): while True: for event in pygame.event.get(): if event.type == pygame.QUIT: pygame.quit() quit() window.fill(BG_COLOR) draw_text('游戏结束', 350, 250) draw_text('得分:{}'.format(score), 350, 300) pygame.display.update() ``` add_obstacle() 函数用于添加障碍物。障碍物的高度是随机生成的,障碍物的 x 坐标是上一个障碍物的 x 坐标加上障碍物间距。得分变量也会相应增加。 draw_text() 函数用于绘制文字。 game_over() 函数用于在游戏结束时显示得分和游戏结束的提示,并等待玩家关闭游戏窗口。 最后,我们需要实现游戏循环: ```python running = True while running: for event in pygame.event.get(): if event.type == pygame.QUIT: running = False if len(obstacle_list) == 0 or obstacle_list[-1].rect.x < WINDOW_WIDTH - OBSTACLE_DISTANCE: add_obstacle() for obstacle in obstacle_list: if pygame.sprite.collide_rect(player, obstacle): game_over() all_sprites.update() if player.rect.y >= WINDOW_HEIGHT - player.rect.height: game_over() window.fill(BG_COLOR) all_sprites.draw(window) draw_text('得分:{}'.format(score), 10, 10) pygame.display.update() clock.tick(60) pygame.quit() quit() ``` 我们首先处理游戏窗口关闭事件。然后,判断是否需要添加障碍物。如果障碍物已经全部通过了屏幕,或者最后一个障碍物的 x 坐标小于窗口宽度减去障碍物间距,就需要添加新的障碍物。 接着,我们检查玩家是否与障碍物碰撞。如果发生碰撞,就调用 game_over() 函数结束游戏。 然后,我们更新所有精灵的位置和状态。接着,我们检查玩家是否掉落到了屏幕底部。如果是,就调用 game_over() 函数结束游戏。 最后,我们绘制游戏界面,包括背景、精灵和得分信息,并刷新窗口。我们还设置了帧率为60。 现在,我们已经完成了2D跑酷游戏的脚本编写。完整代码如下:

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值