基于pygame的自定义游戏《the box》
Posted 西兹克利斯托夫
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了基于pygame的自定义游戏《the box》相关的知识,希望对你有一定的参考价值。
目录
引言
最近在学习java之余,利用空余时间写了一款基于pygame的游戏,主要是想测试pygame各方面的性能,其次是因为python语言的简洁性,写起来是真的舒服,最后是拿来自娱自乐一下还挺有趣的(划重点)。声明:该游戏所有代码均为原创,纯手工制作而成。我会在文末放上游戏运行需要的完整文件包,需要的朋友请自取。
创建一款什么样的游戏
由于pygame本身是一款轻量级的游戏开发工具,可以实现的功能也是比较的有限,因此为了简单化,便于操作等目的,本文通过创建一个基本矩形方块来实现各种目的,因为是以矩形方块作为主要操作对象,所以游戏命名为《The Box》。
需要实现什么样的功能
作为一款测试开发游戏,需要实现的功能比较的基本,由于是一款二维平面游戏,因此需要实现一些较为传统的功能:
- 游戏主要操作对象的创建与交互
- 游戏中基本的键鼠交互
- 游戏中场景的构建与其他对象的交互
- 游戏中其他非环境对象的创建与交互
- 游戏中基本循环逻辑的实现
除了以上几个需要实现的基本功能,还需要考虑游戏的基本逻辑构建,所谓的逻辑构建就是为了实现游戏需要达到的目的,比如游戏能否足够有趣,是否具有可玩性,是否有足够的交互性等,当然这些都在不在本文的考虑范围之内(悲)。
如何去实现基本的功能
目前只是初步的实现了一下一些基本功能,因为最近比较忙就暂停开发了,所以先发布一下看看自己有没有可能哪天能捡起来(笑)。废话不多说,先看目前的实现效果:
《 The Box》
看起来还行,就是太呆了(大笑)。好了关于如何实现的问题,其实我们只需要从模块化设计入手就行。这款游戏主要是通过几个基本模块来实现的:背景模块、主角色模块、场景模块、逻辑模块。上面几个模块主要实现的功能及代码如下:
背景模块
# 背景墙
class BackgroundWall(py.sprite.Sprite):
def __init__(self, screen):
py.sprite.Sprite.__init__(self)
wallPath = '../素材库/背景墙素材/'
self.index = 0
self.imageFiles = [os.path.join(wallPath, i) for i in os.listdir(wallPath)]
self.images = [py.transform.smoothscale(py.image.load(name), (screen.get_width(), screen.get_height())) for name
in self.imageFiles]
self.image = self.images[self.index]
self.rect = self.image.get_rect()
self.rect.topleft = (0, 0)
def update(self, game_time):
timeH, timeM = divmod(game_time, 60)
self.index = int(timeH)
if self.index>17:
self.index =17- self.index%17
self.image = self.images[self.index]
self.rect = self.image.get_rect()
self.rect.topleft = (0, 0)
背景模块顾名思义是用来创建游戏的背景,本文在此实现的功能也是极其简单,主要通过调用游戏时间来实现游戏背景的自动切换。如果你想实现各种功能,比如说随着BGM切换背景,或者通过某种事件切换背景都是可以的,只需要在update函数中添加各种需要的功能即可。
主角色模块
class CubeHuman(object):
def __init__(self, screen):
self.x = screen.get_width()
self.y = screen.get_height()
self.CubeBodyGroup = py.sprite.Group()
self.CubeEyeballGroup = py.sprite.Group()
self.CubeMouthGroup = py.sprite.Group()
self.CubeEyesGroup = py.sprite.Group()
self.cube_body = self.CubeBody()
self.cube_eyes = self.CubeEyes()
self.cube_eyeball = self.CubeEyeball()
self.cube_mouth = self.CubeMouth()
self.CubeBodyGroup.add(self.cube_body)
self.CubeEyeballGroup.add(self.cube_eyeball)
self.CubeMouthGroup.add(self.cube_mouth)
self.CubeEyesGroup.add(self.cube_eyes)
# 伤害,血量等自身参数
self.basicDamage = 10 # 基础伤害
self.basic = 10 # 基础防御
self.basicHp = 100 # 基础血量
self.basicMp = 100 # 基础蓝量
self.HP = 100
self.MP = 100
self.rate = 4
hpImage = py.image.load('../素材库/血条和蓝条/血条.png')
hpRect = hpImage.get_rect()
self.hpImage = py.transform.smoothscale(hpImage,
(int(hpRect.width / self.rate), int(hpRect.height / self.rate)))
self.hpRect = self.hpImage.get_rect()
mpImage = py.image.load('../素材库/血条和蓝条/蓝条.png')
self.mpImage = py.transform.smoothscale(mpImage, (self.hpRect.width, self.hpRect.height))
self.mpRect = self.mpImage.get_rect()
hpWordImage = py.image.load('../素材库/血条和蓝条/HP.png')
hpWordRect = hpWordImage.get_rect()
self.hpWordImage = py.transform.smoothscale(hpWordImage,
(int(hpWordRect.width / self.rate),
int(hpWordRect.height / self.rate)))
self.hpWordRect = self.hpWordImage.get_rect()
mpWordImage = py.image.load('../素材库/血条和蓝条/MP.png')
self.mpWordImage = py.transform.smoothscale(mpWordImage, (self.hpWordRect.width, self.hpWordRect.height))
self.mpWordRect = self.mpWordImage.get_rect()
self.lossImage = py.image.load('../素材库/血条和蓝条/空白条.png')
self.hpWordRect.topleft = (5, 5)
self.mpWordRect.topleft = (5, self.hpWordRect.height + 10)
self.hpRect.topleft = (self.hpWordRect.right, self.hpWordRect.top)
self.mpRect.topleft = (self.mpWordRect.right, self.mpWordRect.top)
def DrawAttributes(self, screen):
rateHp = 1 - (self.HP / self.basicHp)
rateMp = 1 - (self.MP / self.basicMp)
lossHPImage = py.transform.smoothscale(self.lossImage, (int(self.hpRect.width * rateHp), self.hpRect.height))
lossHPRect = lossHPImage.get_rect()
lossHPRect.topright = self.hpRect.topright
lossMPImage = py.transform.smoothscale(self.lossImage, (int(self.mpRect.width * rateMp), self.mpRect.height))
lossMPRect = lossMPImage.get_rect()
lossMPRect.topright = self.mpRect.topright
screen.blit(self.hpWordImage, self.hpWordRect)
screen.blit(self.mpWordImage, self.mpWordRect)
screen.blit(self.hpImage, self.hpRect)
screen.blit(self.mpImage, self.mpRect)
screen.blit(lossHPImage, lossHPRect)
screen.blit(lossMPImage, lossMPRect)
class CubeBody(py.sprite.Sprite):
def __init__(self):
rate = 3 # 缩放比例,下同
py.sprite.Sprite.__init__(self)
self.speed = 1
self.image = py.image.load('../素材库/人物素材/方块人/body/body_basic.png').convert_alpha()
self.rect = self.image.get_rect()
self.image = py.transform.smoothscale(self.image,
(int(self.rect.width / rate), int(self.rect.height / rate)))
self.rect = self.image.get_rect()
self.rect.topleft = (0, 0) # 初始生成位置
self.gravity = 2 # 重力系数为2,表示相邻每帧图像下降2个像素
self.startJumpPos = 0
self.on_ground = False
self.jump = False
self.jumpMaxDis = 100 # 最大跳跃高度(像素)
self.lastPos = None
self.nowPos = None
def KeyControl(self, key):
if key[py.K_d]:
if key[py.K_LSHIFT]:
self.rect.x += self.speed + 1
else:
self.rect.x += self.speed
if key[py.K_a]:
if key[py.K_LSHIFT]:
self.rect.x -= self.speed + 1
else:
self.rect.x -= self.speed
if key[py.K_SPACE] and self.on_ground:
self.gravity = -4 # 跳越速度
self.on_ground = False
self.jump = True
self.startJumpPos = self.rect.y
self.lastPos = self.nowPos
def update(self, floor, screen):
if len(self.rect.collidelistall(floor.floorBody)) > 1: # 与墙体碰撞检测
self.rect.x = self.lastPos
if self.rect.collidelist(floor.floorTop) == -1: # 与地面碰撞检测
self.on_ground = False
if self.rect.right > screen.get_width() or self.rect.left < 0: # 防止移动超越屏幕边缘
self.rect.x = self.lastPos
if not self.on_ground and not self.jump:
self.rect.y += self.gravity
if self.rect.collidelist(floor.floorTop) != -1:
self.on_ground = True
if not self.on_ground and self.jump and (self.startJumpPos - self.rect.y) <= self.jumpMaxDis:
self.rect.y += self.gravity
else:
self.jump = False
self.gravity = 2
self.startJumpPos = 0
self.nowPos = self.rect.x
class CubeEyes(py.sprite.Sprite):
def __init__(self):
rate = 2
py.sprite.Sprite.__init__(self)
self.image = py.image.load('../素材库/人物素材/方块人/eyes/eyes_black.png').convert_alpha()
self.rect = self.image.get_rect()
self.image = py.transform.smoothscale(self.image,
(int(self.rect.width / rate), int(self.rect.width / rate)))
self.rect = self.image.get_rect()
def EyesMove(self, pos, mouse_pos, eyeball):
x0, y0 = pos[0], pos[1]
x1, y1 = mouse_pos[0], mouse_pos[1]
R = eyeball.rect.width / 2
r = self.rect.width / 2
sita_Angel = np.sign(y1 - y0) * np.pi / 2
if x1 != x0:
sita_Angel = np.arctan((y1 - y0) / (x1 - x0))
x2, y2 = x0 + np.sign(x1 - x0) * R * np.cos(sita_Angel), y0 + np.sign(x1 - x0) * R * np.sin(sita_Angel)
x3, y3 = x2 - np.sign(x1 - x0) * r * np.cos(sita_Angel), y2 - np.sign(x1 - x0) * r * np.sin(sita_Angel)
return x3, y3
def update(self, eyeball, body, screen):
pos = eyeball.rect.center
self.rect.center = pos
rect = self.rect.copy()
rect.center = (rect.center[0] + int(body.rect.width / 2), rect.center[1])
'''鼠标控制眼睛方向'''
mousePos = py.mouse.get_pos()
x1, y1 = self.EyesMove(self.rect.center, mousePos, eyeball)
x2, y2 = self.EyesMove(rect.center, mousePos, eyeball)
self.rect.center = (int(x1), int(y1))
rect.center = (int(x2), int(y2))
screen.blit(self.image, rect)
class CubeEyeball(py.sprite.Sprite):
def __init__(self):
rate = 2
py.sprite.Sprite.__init__(self)
self.image = py.image.load('../素材库/人物素材/方块人/eyeball/eyeball_basic.png').convert_alpha()
self.rect = self.image.get_rect()
self.image = py.transform.smoothscale(self.image,
(int(self.rect.width / rate), int(self.rect.width / rate)))
self.rect = self.image.get_rect()
def update(self, body, screen):
pos = body.rect.center
self.rect.center = (pos[0] - int(body.rect.width / 4), pos[1] - int(body.rect.height / 4))
rect_right = self.rect.copy()
rect_right.center = (rect_right.center[0] + int(body.rect.width / 2), rect_right.center[1])
screen.blit(self.image, rect_right)
class CubeMouth(py.sprite.Sprite):
def __init__(self):
rate = 3
py.sprite.Sprite.__init__(self)
self.image = py.image.load('../素材库/人物素材/方块人/mouth/mouth_basic.png').convert_alpha()
self.rect = self.image.get_rect()
self.image = py.transform.smoothscale(self.image,
(int(self.rect.width / rate), int(self.rect.height / rate)))
self.rect = self.image.get_rect()
def update(self, body):
pos = body.rect.center
self.rect.center = (pos[0], pos[1] + int(body.rect.height / 4))
def update(self, floor, screen):
self.DrawAttributes(screen)
self.CubeBodyGroup.update(floor, screen)
self.CubeBodyGroup.draw(screen)
self.CubeEyeballGroup.update(self.cube_body, screen)
self.CubeEyeballGroup.draw(screen)
self.CubeMouthGroup.update(self.cube_body)
self.CubeMouthGroup.draw(screen)
self.CubeEyesGroup.update(self.cube_eyeball, self.cube_body, screen)
self.CubeEyesGroup.draw(screen)
这段代码看起来十分冗长,主要是因为创建了几个内部类来实现主角色关于眼睛,身体,嘴巴等部位的控制,通过修改每个部件,可以实现极为复杂的功能,这里只是简单的实现了一下眼睛的鼠标控制功能,即眼睛跟随鼠标移动,如果你想的话甚至嘴巴也能跟随鼠标移动(笑)。其次是通过键盘控制物体的前后移动,比如按住shift可以加快物体移动,按下空格可以实现物体的跳跃等。最后关于物体与场景之间的交互,比如判断物体是否处于地面上,是否达到了游戏边界等。还有就是角色的一些属性的生成,比如血条什么的。
场景模块
场景模块又分为以下几个小模块:
地板模块:
class FloorGen(object):
def __init__(self, screen, cube):
self.x = screen.get_width()
self.y = screen.get_height()
self.floorPos = []
self.floorImage = []
self.floorRect = []
self.floorTop = []
self.floorBody = []
self.jumpMaxDis = cube.cube_body.jumpMaxDis
self.roadLength = random.randint(20, 25) # 游戏界面总长度
'''地板自身参数设置
分别表示单位地板宽度,高度'''
self.width = int(self.x / 4)
self.heightA = int(self.y / 25)
self.heightB = int(self.heightA / 4)
'''地板生成按照一定规律,相邻地板之间的最大距离差不超过方块的最大跳跃极限'''
def floor_pos_gen(self):
self.floorPos = [[(0, random.randint(int(self.y * (1 - 1 / 3)), self.y - self.heightB))]]
for group in range(1, self.roadLength):
body = [(group * self.width,
random.randint(max(self.floorPos[group - 1][0][1] - self.jumpMaxDis, self.y / 2),
min(self.floorPos[group - 1][0][1] + self.jumpMaxDis, self.y - 5)))]
self.floorPos.append(body)
for floor in self.floorPos:
num = int(np.ceil(self.y - floor[0][1] - self.heightB) / self.heightA) + 1
head = floor[0][1] + self.heightB
floor.append((floor[0][0], head))
for member in range(1, num):
nextHead = head + self.heightA * member
floor.append((floor[0][0], nextHead))
def floor_Image(self):
floorImage = []
for i in range(5):
locals()['image'.format(i)] = py.image.load('../素材库/地板素材/floor_lv.png'.format(i)).convert_alpha()
floorImage.append(eval('image'.format(i)))
floorImage[i] = py.transform.smoothscale(floorImage[i], (self.width, self.heightA))
floorImage[0] = py.transform.smoothscale(floorImage[0], (self.width, self.heightB))
self.floorImage = floorImage
def generator(self, screen):
self.floor_pos_gen()
self.floor_Image()
for floor in self.floorPos:
rectLs = []
for i in range(len(floor)):
floorPos = floor[i]
image = [self.floorImage[-1] if i > len(self.floorImage) - 1 else self.floorImage[i]][0].copy()
rect = image.get_rect()
rect.topleft = floorPos
screen.blit(image, rect)
rectLs.append(rect)
self.floorBody.append(rect)
self.floorRect.append(rectLs)
self.floorTop.append(rectLs[0])
# 更新所有地板图像
def update(self, screen):
for floorL in self.floorRect:
for i in range(len(floorL)):
floorRect = floorL[i]
floorImage = [self.floorImage[-1] if i > len(self.floorImage) - 1 else self.floorImage[i]][0].copy()
screen.blit(floorImage, floorRect)
def updatePre(self, cube, point):
for floorL in self.floorRect:
for floorRect in floorL:
floorRect.x -= cube.cube_body.nowPos - cube.cube_body.lastPos
cube.cube_body.rect.x = cube.cube_body.lastPos
地板模块用来创建地面。本文通过随机生成一定长度的地面用来实现游戏场景的移动,同时相邻地板之间的高度不能超过主角色的极限跳跃高度,这是为了避免方块无法穿越游戏场景。
云模块:
class Cloud(py.sprite.Sprite):
def __init__(self, screen, game_time):
py.sprite.Sprite.__init__(self)
cloudPath = '../素材库/云/'
rate = 3
self.speed = 1 # 移动速度
self.genTime = game_time
self.imageFiles = [os.path.join(cloudPath, i) for i in os.listdir(cloudPath)]
self.images = [py.image.load(name) for name in self.imageFiles]
self.rects = [image.get_rect() for image in self.images]
self.images = [
py.transform.smoothscale(self.images[i],
(int(self.rects[i].width / rate), int(self.rects[i].height / rate)))
for i in range(len(self.images))]
self.index = random.randint(0, len(self.images) - 1)
self.image = self.images[self.index]
self.rect = self.image.get_rect()
self.width = screen.get_width()
self.height = screen.get_height()
self.x = random.randint(int(self.width + self.rect.width / 2), int(self.width + self.rect.width / 2 + 100))
self.y = random.randint(int(self.rect.height / 2), int(self.height / 4))
self.rect.center = (self.x, self.y)
def update(self):
self.rect.x -= self.speed
if self.rect.right < 0:
self.kill()
# 控制云朵生成速率
def cloudGen(cloud_group, screen, game_time, ls):
if len(cloud_group) == 0:
cloud = Cloud(screen, game_time)
cloud_group.add(cloud)
elif 0 < len(cloud_group) < 3:
spriteTime = list(cloud_group.spritedict.keys())[-1].genTime
if len(ls) == 0:
timeSlot = random.randint(3, 50)
ls.append(timeSlot)
else:
timeSlot = ls[-1]
timeWait = (game_time - spriteTime)
if timeWait >= timeSlot:
ls.pop(-1)
cloud = Cloud(screen, game_time)
cloud_group.add(cloud)
这个模块用来生成一些云朵,同时按照一定的速度进入和离开游戏界面,这样使得场景看起来更加具有动感。(别说贴图太丑了,这都是用wps一个个设计出来的)
太阳和月亮:
class SunAndMoon(py.sprite.Sprite):
def __init__(self):
py.sprite.Sprite.__init__(self)
self.rate = 3
self.MoonFilePath = '../素材库/月亮/'
self.imageRaw = py.image.load('../素材库/太阳/sun.png').convert_alpha()
self.MoonFiles = [os.path.join(self.MoonFilePath, i) for i in os.listdir(self.MoonFilePath)]
self.imageMoonRaw = [py.image.load(name).convert_alpha() for name in self.MoonFiles]
self.MoonRect = [image.get_rect() for image in self.imageMoonRaw]
self.imageMoon = [py.transform.smoothscale(self.imageMoonRaw[i], (int(self.MoonRect[i].width / self.rate),
int(self.MoonRect[i].width / self.rate))) for
i in range(len(self.imageMoonRaw))]
self.MoonRect = [image.get_rect() for image in self.imageMoonRaw]
self.rect = self.imageRaw.get_rect()
self.imageRaw = py.transform.smoothscale(self.imageRaw,
(int(self.rect.width / self.rate), int(self.rect.width / self.rate)))
self.rect = self.imageRaw.get_rect()
self.y = self.rect.height
self.image = self.imageRaw.copy()
self.time = 0
def update(self, game_time, screen):
hour, minute = divmod(game_time, 60)
if hour <= 9:
self.time += 1
self.image = py.transform.rotate(self.imageRaw, self.time).convert_alpha()
self.rect = self.image.get_rect()
self.rect.center = (int(screen.get_width() / 2), int(self.y / 2))
elif 17 >= hour > 9:
self.image = self.imageMoon[int(hour) - 10]
self.rect = self.MoonRect[int(hour) - 10]
self.rect.center = (int(screen.get_width() / 2), int(self.y / 2))
这个模块实现了太阳的旋转,月亮的生成。
逻辑模块
# 移动游戏镜头
def moveCamera(cube, floor, screen):
rate = 0.70 # 镜头移动触发区域为屏幕右端(1-rate)/2范围,和屏幕左端(1-rate)/2范围
triggerPointRight = screen.get_width() * (0.5 + rate / 2)
triggerPointLeft = screen.get_width() * (1 - rate) / 2
if cube.cube_body.rect.right > triggerPointRight:
if floor.floorTop[0].left > -floor.roadLength * floor.width + screen.get_width():
floor.updatePre(cube, triggerPointRight)
elif cube.cube_body.rect.left < triggerPointLeft:
if floor.floorTop[-1].right < floor.roadLength * floor.width:
floor.updatePre(cube, triggerPointLeft)
floor.update(screen)
这个模块用来控制屏幕的镜头的移动,所谓的移动实际上是相对的,因为屏幕本身不会移动因此只能通过移动地板来实现,通过创建两条边界线来检测触发移动,这里我同时设置无法移动镜头的情况,以免超过了游戏地板的生成界限。
启动程序:
def Main():
py.init()
FPS = 200 # 游戏帧率
width, height = 800, 600 # 设置窗口大小
py.display.set_caption('THE BOX') # 设置游戏名称
screen = py.display.set_mode((width, height))
clock = py.time.Clock()
backGround = BackgroundWall(screen)
bgGroup = py.sprite.Group()
bgGroup.add(backGround)
cube = CubeHuman(screen)
sunAndMoon = SunAndMoon()
sunGroup = py.sprite.Group()
sunGroup.add(sunAndMoon)
floor = FloorGen(screen, cube)
floor.generator(screen)
cloudGroup = py.sprite.Group()
cloudUpdateTimeLs = []
while True:
GameTime = ControlTime()
bgGroup.update(GameTime)
bgGroup.draw(screen)
sunGroup.update(GameTime, screen)
sunGroup.draw(screen)
cloudGen(cloudGroup, screen, GameTime, cloudUpdateTimeLs)
cloudGroup.update()
cloudGroup.draw(screen)
key = py.key.get_pressed() # 获取键盘输入
cube.cube_body.KeyControl(key)
cube.cube_body.update(floor, screen)
moveCamera(cube, floor, screen) # 包含了地面刷新程序
if key[py.K_ESCAPE]: exit() # 退出设置
for event in py.event.get():
if event.type == py.QUIT:
py.quit()
sys.exit()
''''''
cube.update(floor, screen)
py.display.update() # 刷新
clock.tick(FPS)
if __name__ == '__main__':
Main()
启动程序中各位模块创建和刷新的先后顺序一定不要搞错。以上就是本文的全部的内容了,根据以往经验,我知道这篇文章大概率没什么人看,主要是为了以防万一哪天我想捡起来看看,故作此文。最后按照惯例给个懒人包:The Box 提取码:s2gj
PS:有时间我再去修改修改,比如写个启动界面什么的(恼),加个音乐包什么的,自动创建一个爬虫什么的(笑),也可能会写一个人工智能代替我玩(悲)。
pygame游戏检测矩形是否碰撞指定颜色的自定义函数(仅5行代码)
游戏中经常要检测角色之间的碰撞。pygame提供了各种图形之间碰撞检测,似乎并没有一个检测矩形与某颜色碰撞的函数。本文用pygame自定义一个函数,完成矩形与某颜色碰撞的检测。
pygame语句screen=pygame.display.set_mode((400,300))创建1个Surface实例作为显示窗体,这个screen水平方向400点,垂直方向300点的一个矩形,可用一个2维数组描述。在screen上可以画各种图形(如线和矩形)或Surface实例,先画的图形将被后画图形覆盖。完成1帧图像后,将screen拷贝到屏幕。如编写这样一个程序,在窗体两侧各画了1条黑色竖线,两线之间画一个小矩形,令其沿x轴方向不停移动,每当碰到黑线,反向运动。那么如何判断小矩形是否碰到黑色(线)呢?可在把小矩形画到screen前,检测在screen上小矩形所在新位置内是否有黑色点。具体方法是将screen每点颜色值保存到一个2维数组,从这个2维数组中创建一个矩形切片,矩形切片的位置和大小是小矩形在screen上新位置,然后判断该切片中是否有黑色的点。实际实现代码如下。
import pygame
def collide_color(aSurface,aRect,aColor):
pixel=pygame.PixelArray(aSurface)#锁定aSurface,将各点颜色保存在2维数组
aPixel=pixel[aRect.x:aRect.x+aRect.width,aRect.y:aRect.y+aRect.height]
pygame.PixelArray.close(pixel) #解锁aSurface并删除数组,上句得到数组切片
return aColor in aPixel#指定颜色在切片中返回真,两者颜色应同为rgb或rgba
函数的参数1是一个Surface实例,这里是上文创建的screen;参数2是矩形移动后新位置;参数3是要检测的颜色。第1条语句锁定aSurface,即不允许在aSurface画图形,并将aSurface上各点颜色值保存在一个2维数组中,注意数组是PixelArray实例,不是python的列表。第2条语句是做数组切片,切片范围是矩形在aSurface上新位置。第3条语句解锁aSurface对象,并删除第1条语句创建的2维数组。最后函数返回一个布尔值,即判断aColor颜色是否在切片数组中,两者颜色格式应相同,同是rgb或rgba。注意,很多网上文章介绍第3条语句使用del Pixel解锁,pygame1.9.4版本前是可以的,pygame1.9.4版本后,用del Pixel,不能解锁aSurface对象,但不报错。特别注意必须在画小矩形前检测,因画了小矩形后将会覆盖黑线,就无法检测了。另外要检测的黑色线必须在检查前画到screen上,因此在游戏窗体画图形的顺序十分重要。
本例并非必须采用检测矩形碰撞颜色方法,例如把两条黑线换成很窄Surface实例并填充黑色,就可以采用检测矩形碰撞矩形方法。但是如所画是任意黑色曲线,似乎只能采用检测矩形碰撞颜色方法了。
小矩形在两条黑色竖线间往返的程序运行效果图如下。
小矩形在两条黑色竖线间往返的完整程序如下。
import pygame
def collide_color(aSurface,aRect,aColor):
pixel=pygame.PixelArray(aSurface) #锁定aSurface,将各点颜色保存在2维数组
aPixel=pixel[aRect.x:aRect.x+aRect.width,aRect.y:aRect.y+aRect.height] #得到数组切片
pygame.PixelArray.close(pixel) #解锁aSurface并删除数组
return aColor in aPixel #指定颜色在切片中返回真,否则返回假。两者颜色应同为rgb或rgba
bgcolor = pygame.Color('white')
red=pygame.Color('red')
black=pygame.Color('black')
pygame.init()
size = width, height = 200,100
screen = pygame.display.set_mode(size)
pygame.display.set_caption("检测矩形和颜色的碰撞")
rect = pygame.Rect( 100 ,35, 20, 20 ) #所画小矩形
dx=10 #小矩形移动速度
fclock = pygame.time.Clock()
fps = 4
angle=0
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
screen.fill(bgcolor) #背景色
pygame.draw.line(screen,black,(10,10),(10,90),5) #画窗体两侧的两条黑线
pygame.draw.line(screen,black,(190,10),(190,90),5) #必须在检测前完成画黑线
rect.x+=dx #小矩形移到新位置
if collide_color(screen,rect,black): #开始检测,必须在画矩形前检测
dx=-(dx) #碰到黑色线,速度反向
pygame.draw.rect(screen, red, rect) #画小矩形
pygame.display.update()
fclock.tick(fps)
pygame.quit()
以上是关于基于pygame的自定义游戏《the box》的主要内容,如果未能解决你的问题,请参考以下文章
pygame游戏检测矩形是否碰撞指定颜色的自定义函数(仅5行代码)
python编写游戏怎么打包——详解python+pygame游戏开发之使用Py2exe打包游戏为exe文件
python编写游戏怎么打包——详解python+pygame游戏开发之使用Py2exe打包游戏为exe文件