Pygame(七) 碰撞检测

Pygame(七) 碰撞检测

前情提要

第六课内容提要

作业分析:

作业内容:

  • 设计一个碰到墙壁就反弹的pygame实现

完整代码

# /usr/bin/python3

# Author: 爱编程的章老师
# @Time: 2021/1/5 0005
# E-mail: [email protected]

import pygame
import sys
import time

def homeworkd():
    pygame.init()
    s = pygame.display.set_mode((800, 600))
    rect = pygame.Rect(400,300, 100,100)
    GREEN = 0, 255, 0
    BLACK = 0,0,0
    pygame.draw.rect(s, GREEN, rect)
    pygame.display.update()

    dx = 5
    while 1:
        for e in pygame.event.get():
            if e.type == pygame.QUIT:
                sys.exit()
        if dx == 5 and rect.right > 795:
            dx = -5
        elif rect.left <=0:
            dx = 5
        rect.move_ip(dx, 0)
        s.fill(BLACK)
        pygame.draw.rect(s, GREEN, rect)
        pygame.display.update()
        time.sleep(0.01)

if __name__ == '__main__':
    homeworkd()

代码分析

移动后要检测有没有撞到屏幕边缘,如果碰到了,就改变运动方向.
核心代码:

if dx == 5 and rect.right > 795:
    dx = -5
elif rect.left <=0:
    dx = 5

效果图:

碰撞反弹效果图

本节提要

本节提要

内容详解

游戏中,两个角色的碰撞是经常会发生的事情.比如飞机大战的子弹与敌机,子弹与主机,敌机与主机之间都需要进行碰撞检测
再比如动作游戏的主角与敌人之间的对战的碰撞检测也是必须的.
当然,这一节,我们不涉及不规则形状的碰撞.我们只探讨考虑两个(多个)矩形之间的碰撞逻辑与检测

自主实现

  • 两个矩形的碰撞检测不实现
    逻辑分析:
    两个矩形的碰撞,无外乎以下几种情况
  • 正面碰撞
    效果图如下:
    7_2_1.gif
  • 斜向碰撞
    7_2_2.gif

在我们事先已经知道是哪种情况下的碰撞,那代码写起来会简单很多.
先看第一种情况,我们只需要检测左边矩形的右边与右边矩形的左边的值的大小即可
代码如下:

def pong1():
    pygame.init()
    s = pygame.display.set_mode((800, 600))
    rect1 = pygame.Rect(100,300, 100,100)
    rect2 = pygame.Rect(400,300,100,100)
    GREEN = 0, 255, 0 # 绿色
    BLUE = 0, 0, 255  # 蓝色
    BLACK = 0,0,0  # 黑色
    pygame.draw.rect(s, GREEN, rect1)
    pygame.draw.rect(s, BLUE, rect2)

    pygame.display.update()

    while 1:
        for e in pygame.event.get():
            if e.type == pygame.QUIT:
                sys.exit()
        if rect2.left > rect1.right:
            print("未碰撞")
            rect2.move_ip(-5, 0)
        else:
            print("碰撞成功")
        s.fill(BLACK)
        pygame.draw.rect(s, BLUE, rect2)
        pygame.draw.rect(s, GREEN, rect1)
        pygame.display.update()
        time.sleep(0.1)

效果图如下
7_3.gif

可以看到,没有碰撞的时候,输出的是未碰撞.
碰撞成功的时候,输出的是碰撞成功
可以成功检测到碰撞情形

  • 第二种情况斜撞
    我们只需要考虑左边矩形的上边< 右侧矩形的下边 且 左边矩形的右边< 右边矩形的左边的时候就是未碰撞.否则就是碰撞成功.这里代码就不再写了

但是实际场景中,我们很难确定两个矩形是哪一种碰撞逻辑.因此,我们要把两种碰撞的八种情况都写一遍.显然这样的代码会很复杂.
因此,实际工作中,我们通常采用反法(即证未碰撞)
image.png
未碰撞的四种情形
R2.bottom> R1.top
R3.right < R1.left
R4.top > R1.bottom
R5.left > R1.right
当然 在实际的时候,周边四个矩形是同一个矩形的四种位置.
因此,代码可以写成如下形式:

c1 = rect2.bottom > rect1.top
c2 = rect2.right < rect1.left
c3 = rect2.top > rect1.bottom
c4 = rect2.left > rect1.right
if c1 or c2 or c3 or c4:
    print("矩形2与矩形1没有碰撞")
else:
    print("两个矩形碰撞成功")

具体的代码这边就不再展开了.
因为pygame为我们做这项工作,可以让我们直接使用

pygame实现

rect1.colliderect(rect2)

用来判断rect1 与 rect2是否碰撞的.返回值为True 或 False

改进的代码:

def pong2():
    pygame.init()
    s = pygame.display.set_mode((800, 600))
    rect1 = pygame.Rect(100,300, 100,100)
    rect2 = pygame.Rect(400,300,100,100)
    GREEN = 0, 255, 0 # 绿色
    BLUE = 0, 0, 255  # 蓝色
    BLACK = 0,0,0  # 黑色
    pygame.draw.rect(s, GREEN, rect1)
    pygame.draw.rect(s, BLUE, rect2)

    pygame.display.update()

    while 1:
        for e in pygame.event.get():
            if e.type == pygame.QUIT:
                sys.exit()
        # 以下是改进的代码
        if rect1.colliderect(rect2):
            print("碰撞成功")
        else:
            print("未碰撞")
            rect2.move_ip(-5, 0)
        # 改动到这里结束
        s.fill(BLACK)
        pygame.draw.rect(s, BLUE, rect2)
        pygame.draw.rect(s, GREEN, rect1)
        pygame.display.update()
        time.sleep(0.1)

改动过的地方已经作出了标志.
效果同上,不再上图了.

碰撞是检测由外而内的相遇过程
有时候,我们也有可能会遇到,一个角色在另一个角色内活动.出去就会触发特殊效果的情况.
比如,我们开了一个无敌的护罩.大小是200的正方形.当主角在护罩内时无敌才有效果.出了这个护罩就无效了.
这个时候如果采用自主实现的方法,就是判断主角的矩形四个方向的边是否在大矩形的四个边之内即可.

pygame同样帮我们实现了这样的判断方法

rect1.contains(rect2)

如果rect2在rect1内,就返回True, 否则就返回False

看一下示例代码

def pygame_contains():
    pygame.init()
    s = pygame.display.set_mode((800, 600))
    rect1 = pygame.Rect(100, 100, 600, 400)
    rect2 = pygame.Rect(400, 300, 100, 100)
    GREEN = 0, 255, 0  # 绿色
    BLUE = 0, 0, 255  # 蓝色
    BLACK = 0, 0, 0  # 黑色
    pygame.draw.rect(s, BLUE, rect2)
    pygame.draw.rect(s, GREEN, rect1)

    pygame.display.update()

    while 1:
        for e in pygame.event.get():
            if e.type == pygame.QUIT:
                sys.exit()
        if rect1.contains(rect2):
            print("我是无敌的")
        else:
            print("我感觉我活不久了")
        rect2.move_ip(4, 0)
        s.fill(BLACK)
        pygame.draw.rect(s, GREEN, rect1)
        pygame.draw.rect(s, BLUE, rect2)
        pygame.display.update()
        time.sleep(0.1)

效果图:
包含检测
注意观察左下角的输出内容
当蓝色矩形在绿色矩形内时,输出是无敌的.当蓝色矩形不完全在绿色矩形内时,输出是我感觉我活不久了.

关于矩形的操作,还有很多.比如,我们捡到一把枪,把枪装备到角色上,相当于把两个矩形合成了一个.pygame也帮我们实现了.
这些复杂的操作.我们在后续的内容中慢慢给到大家.

作业

自由落体

  1. 画一个棕色的扁长方形当地板
  2. 画一个蓝色小正方形(有能力的可以画球)当小球
  3. 小球自上而下.起始高度差200
  4. 每次落地后反弹高度为掉落高度的一半.直到反弹高度<5时停止
  5. 不考虑加速度.即速度在下落与反弹过程中假高是恒定的

猜你喜欢

转载自blog.csdn.net/weixin_41810846/article/details/112253540