# /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
游戏中,两个角色的碰撞是经常会发生的事情.比如飞机大战的子弹与敌机,子弹与主机,敌机与主机之间都需要进行碰撞检测
再比如动作游戏的主角与敌人之间的对战的碰撞检测也是必须的.
当然,这一节,我们不涉及不规则形状的碰撞.我们只探讨考虑两个(多个)矩形之间的碰撞逻辑与检测
在我们事先已经知道是哪种情况下的碰撞,那代码写起来会简单很多.
先看第一种情况,我们只需要检测左边矩形的右边与右边矩形的左边的值的大小即可
代码如下:
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)
可以看到,没有碰撞的时候,输出的是未碰撞.
碰撞成功的时候,输出的是碰撞成功
可以成功检测到碰撞情形
但是实际场景中,我们很难确定两个矩形是哪一种碰撞逻辑.因此,我们要把两种碰撞的八种情况都写一遍.显然这样的代码会很复杂.
因此,实际工作中,我们通常采用反法(即证未碰撞)
未碰撞的四种情形
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为我们做这项工作,可以让我们直接使用
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也帮我们实现了.
这些复杂的操作.我们在后续的内容中慢慢给到大家.
自由落体