pygame综合

到目前为止,你已经学习了制作一款简单游戏的所有必要基础。您应该了解如何创建Pygame对象,Pygame如何显示对象,如何处理事件,以及如何使用物理在游戏中引入一些运动。现在我将展示如何将这些代码块整合到一个可运行的游戏中。我们首先需要的是让球击中屏幕的两侧,让球棒能够击中球,否则就不会有太多的游戏参与。我们使用Pygame的碰撞方法来实现这一点。

让球打到两边
让它弹跳的基本原理很容易掌握。
您获取球的四个角的坐标,并检查它们是否与屏幕边缘的x或y坐标相对应。
如果左上角和右上角的y坐标都为0,你就知道当前球在屏幕的上边缘。
在我们计算出球的新位置之后,我们在update函数中做了所有这些。

if not self.area.contains(newpos):
      tl = not self.area.collidepoint(newpos.topleft)
      tr = not self.area.collidepoint(newpos.topright)
      bl = not self.area.collidepoint(newpos.bottomleft)
      br = not self.area.collidepoint(newpos.bottomright)
      if tr and tl or (br and bl):
              angle = -angle
      if tl and bl:
              self.offcourt(player=2)
      if tr and br:
              self.offcourt(player=1)

self.vector = (angle,z)

这里我们检查该区域是否包含球的新位置(它总是应该的,所以我们不需要有一个else子句,尽管在其他情况下你可能想要考虑它。
然后我们检查四个角的坐标是否与区域的边缘发生碰撞,并为每个结果创建对象。
如果是,则对象的值为1或True。
如果没有,则该值为None或False。
然后我们看看它是碰到了顶部还是底部,如果碰到了,我们就改变球的方向。
使用弧度,我们可以通过简单地反转它的正负值来方便地做到这一点。
我们也检查球是否已经越过了边线,如果有,我们调用场外功能。
在我的游戏中,这将重置球,在调用函数时为指定的玩家的分数增加1分,并显示新的分数。

最后,我们根据新的角度重新编译向量。
就是这样。
现在,球将愉快地弹回墙,并以良好的姿态离开球场。

让球击中球棒
让球击中球棒与让它击中屏幕的两侧非常相似。
我们仍然使用碰撞方法,但这一次我们检查是否长方形的球和任何一个球棒碰撞。
在这段代码中,我还添加了一些额外的代码,以避免各种故障。
你会发现你不得不添加各种各样的额外代码来避免小故障和bug,所以习惯看到它是很好的。

else:
    # 缩小矩形,这样你就不能接住球棒后面的球了
    player1.rect.inflate(-3, -3)
    player2.rect.inflate(-3, -3)

    # 球和球棒会碰撞吗?
    # 注意,我放入了一个奇数规则,设置self。当它们碰撞时,点击1,并在下一个中取消它
    # 迭代。这是停止古怪的球行为,它发现一个碰撞*inside*
    # 球在球棒内翻转,所以仍在球棒内弹跳。
    # 这样,球总是可以逃脱和反弹干净
    if self.rect.colliderect(player1.rect) == 1 and not self.hit:
        angle = math.pi - angle
        self.hit = not self.hit
    elif self.rect.colliderect(player2.rect) == 1 and not self.hit:
        angle = math.pi - angle
        self.hit = not self.hit
    elif self.hit:
        self.hit = not self.hit
self.vector = (angle,z)

我们以一个else语句开始这一节,因为它从前面的代码块开始检查球是否击中了边沿。
这就说得通了,如果它不打边,它可能会打球棒,所以我们继续条件语句。
第一个故障修复是缩小球员矩形3像素在这两个维度,停止背后的蝙蝠抓球(如果你想象你只是把蝙蝠这球旅行,矩形重叠,所以通常球将被“打击”,这可以防止)。

接下来,我们检查是否矩形碰撞,与另一个故障修复。
请注意,我已经对这些奇怪的代码进行了注释——解释一些不正常的代码总是好的,对于查看您的代码的其他人来说都是如此,这样当您回到代码时就可以理解它。
如果没有修正,球可能会打到球棒的一个角落,改变方向,一帧后仍然发现自己在球棒内。
然后它会再次认为自己被击中了,并改变方向。
这可能会发生多次,使球的运动完全不现实。
我们有一个变量self。
hit,当它被击中时我们设为True,一帧后设为False。
当我们检查两个矩形是否相撞时,我们还要检查self。
hit为True/False,表示停止内部弹跳。

这里的重要代码非常容易理解。
所有的矩形都有一个colliderect函数,你可以在这个函数中输入另一个对象的矩形,如果矩形有重叠则返回True,如果没有重叠则返回False。
如果他们这样做了,我们可以通过从pi减去当前的角度来改变方向(同样,这是你可以用弧度做的一个方便的技巧,它会将角度调整90度,并将其发送到正确的方向;
在这一点上,您可能会发现对弧度的透彻理解是合理的!)
为了完成故障检查,我们切换自我。
如果是被击中后的帧,则返回False。

然后,我们还重新编译vector。
您当然希望删除前面代码块中的同一行,以便只在if-else条件语句之后执行一次。
这是它!
合并后的规则将允许球击中两侧和拍子。

成品
最终的产品,将所有的代码放在一起,以及一些其他的代码将它们粘在一起,就像这样:

#
# 汤姆的乒乓球
# 一个简单的乒乓球游戏与现实的物理和AI
# http://www.tomchance.uklinux.net/projects/pong.shtml
#
# 根据GNU通用公共许可证发布

VERSION = "0.4"

try:
    import sys
    import random
    import math
    import os
    import getopt
    import pygame
    from socket import *
    from pygame.locals import *
except ImportError, err:
    print "无法加载模块. %s" % (err)
    sys.exit(2)

def load_png(name):
    """ 加载图像并返回图像对象"""
    fullname = os.path.join('data', name)
    try:
        image = pygame.image.load(fullname)
        if image.get_alpha is None:
            image = image.convert()
        else:
            image = image.convert_alpha()
    except pygame.error, message:
        print 'Cannot load image:', fullname
        raise SystemExit, message
    return image, image.get_rect()

class Ball(pygame.sprite.Sprite):
    """在屏幕上移动的球
返回:球对象
功能:更新calcnewpos
属性:面积、向量"""

    def __init__(self, (xy), vector):
        pygame.sprite.Sprite.__init__(self)
        self.image, self.rect = load_png('ball.png')
        screen = pygame.display.get_surface()
        self.area = screen.get_rect()
        self.vector = vector
        self.hit = 0

    def update(self):
        newpos = self.calcnewpos(self.rect,self.vector)
        self.rect = newpos
        (angle,z) = self.vector

        if not self.area.contains(newpos):
            tl = not self.area.collidepoint(newpos.topleft)
            tr = not self.area.collidepoint(newpos.topright)
            bl = not self.area.collidepoint(newpos.bottomleft)
            br = not self.area.collidepoint(newpos.bottomright)
            if tr and tl or (br and bl):
                angle = -angle
            if tl and bl:
                #self.offcourt()
                angle = math.pi - angle
            if tr and br:
                angle = math.pi - angle
                #self.offcourt()
        else:
            # 缩小矩形,这样你就不能接住球棒后面的球了
            player1.rect.inflate(-3, -3)
            player2.rect.inflate(-3, -3)

            # 球和球棒会碰撞吗?
            # 注意,我放入了一个奇数规则,设置self。当它们碰撞时,点击1,并在下一个中取消它
            # 迭代。这是停止古怪的球行为,它发现一个碰撞*内部*
            # 球在球棒内翻转,所以仍在球棒内弹跳。
            # 这样,球总是可以逃脱和反弹干净
            if self.rect.colliderect(player1.rect) == 1 and not self.hit:
                angle = math.pi - angle
                self.hit = not self.hit
            elif self.rect.colliderect(player2.rect) == 1 and not self.hit:
                angle = math.pi - angle
                self.hit = not self.hit
            elif self.hit:
                self.hit = not self.hit
        self.vector = (angle,z)

    def calcnewpos(self,rect,vector):
        (angle,z) = vector
        (dx,dy) = (z*math.cos(angle),z*math.sin(angle))
        return rect.move(dx,dy)

class Bat(pygame.sprite.Sprite):
    """可移动的网球“球拍”,用来击球
返回:蝙蝠对象
功能:reinit, update, moveup, movedown
属性:速度"""

    def __init__(self, side):
        pygame.sprite.Sprite.__init__(self)
        self.image, self.rect = load_png('bat.png')
        screen = pygame.display.get_surface()
        self.area = screen.get_rect()
        self.side = side
        self.speed = 10
        self.state = "still"
        self.reinit()

    def reinit(self):
        self.state = "still"
        self.movepos = [0,0]
        if self.side == "left":
            self.rect.midleft = self.area.midleft
        elif self.side == "right":
            self.rect.midright = self.area.midright

    def update(self):
        newpos = self.rect.move(self.movepos)
        if self.area.contains(newpos):
            self.rect = newpos
        pygame.event.pump()

    def moveup(self):
        self.movepos[1] = self.movepos[1] - (self.speed)
        self.state = "moveup"

    def movedown(self):
        self.movepos[1] = self.movepos[1] + (self.speed)
        self.state = "movedown"


def main():
    # 初始化屏幕
    pygame.init()
    screen = pygame.display.set_mode((640, 480))
    pygame.display.set_caption('Basic Pong')

    # 填充背景
    background = pygame.Surface(screen.get_size())
    background = background.convert()
    background.fill((0, 0, 0))

    # 初始化玩家
    global player1
    global player2
    player1 = Bat("left")
    player2 = Bat("right")

    # 初始化球
    speed = 13
    rand = ((0.1 * (random.randint(5,8))))
    ball = Ball((0,0),(0.47,speed))

    # 初始化精灵
    playersprites = pygame.sprite.RenderPlain((player1, player2))
    ballsprite = pygame.sprite.RenderPlain(ball)

    # 把所有东西都放在屏幕上
    screen.blit(background, (0, 0))
    pygame.display.flip()

    # 初始化时钟
    clock = pygame.time.Clock()

    # 事件循环
    while 1:
        # 确保游戏的运行速度不要超过每秒60帧
        clock.tick(60)

        for event in pygame.event.get():
            if event.type == QUIT:
                return
            elif event.type == KEYDOWN:
                if event.key == K_a:
                    player1.moveup()
                if event.key == K_z:
                    player1.movedown()
                if event.key == K_UP:
                    player2.moveup()
                if event.key == K_DOWN:
                    player2.movedown()
            elif event.type == KEYUP:
                if event.key == K_a or event.key == K_z:
                    player1.movepos = [0,0]
                    player1.state = "still"
                if event.key == K_UP or event.key == K_DOWN:
                    player2.movepos = [0,0]
                    player2.state = "still"

        screen.blit(background, ball.rect, ball.rect)
        screen.blit(background, player1.rect, player1.rect)
        screen.blit(background, player2.rect, player2.rect)
        ballsprite.update()
        playersprites.update()
        ballsprite.draw(screen)
        playersprites.draw(screen)
        pygame.display.flip()


if __name__ == '__main__': main()
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值