zoukankan      html  css  js  c++  java
  • pygame 笔记-6 碰撞检测

    这一节学习碰撞检测,先看原理图:

     2个矩形如果发生碰撞(即:图形有重叠区域),按上图的判断条件就能检测出来,如果是圆形,则稍微变通一下,用半径检测。如果是其它不规则图形,大多数游戏中,并不要求精确检测,可以在外层套一个矩形,大致用上图的原理检测。

    可以封装一个函数:

    def collision_check(a, b):
        temp1 = (b.x <= a.x + a.width <= b.x + b.width)
        temp2 = (b.y <= a.y + a.height <= b.y + b.height)
        return temp1 and temp2
    

    要注意的是:矩形A,B碰撞时,有可能是A撞B,也有可能是B撞A,所以使用上面的函数时,最好写好 if collision_check(a,b) or collision_check(b,a):

    为了方便观察,我们在上节的3个类文件(即:Player、Enemy、Bullet)里,略做修改,手动在外层套一个矩形(hit_box)

    import pygame
    
    
    # 主角
    class Player(object):
    
        def __init__(self, x, y, width, height, img_base_path):
            self.x = x
            self.y = y
            self.width = width
            self.height = height
            self.speed = 5
            self.left = False
            self.right = True
            self.isJump = False
            self.walkCount = 0
            self.t = 10
            self.speed = 5
            self.char = pygame.image.load(img_base_path + 'standing.png')
            self.walkRight = [pygame.image.load(img_base_path + 'actor/R1.png'),
                              pygame.image.load(img_base_path + 'actor/R2.png'),
                              pygame.image.load(img_base_path + 'actor/R3.png'),
                              pygame.image.load(img_base_path + 'actor/R4.png'),
                              pygame.image.load(img_base_path + 'actor/R5.png'),
                              pygame.image.load(img_base_path + 'actor/R6.png'),
                              pygame.image.load(img_base_path + 'actor/R7.png'),
                              pygame.image.load(img_base_path + 'actor/R8.png'),
                              pygame.image.load(img_base_path + 'actor/R9.png')]
    
            self.walkLeft = [pygame.image.load(img_base_path + 'actor/L1.png'),
                             pygame.image.load(img_base_path + 'actor/L2.png'),
                             pygame.image.load(img_base_path + 'actor/L3.png'),
                             pygame.image.load(img_base_path + 'actor/L4.png'),
                             pygame.image.load(img_base_path + 'actor/L5.png'),
                             pygame.image.load(img_base_path + 'actor/L6.png'),
                             pygame.image.load(img_base_path + 'actor/L7.png'),
                             pygame.image.load(img_base_path + 'actor/L8.png'),
                             pygame.image.load(img_base_path + 'actor/L9.png')]
            self.hit_box = (self.x + 17, self.y + 11, 29, 52)
    
        def draw(self, win):
            if self.walkCount >= 9:
                self.walkCount = 0
    
            if self.left:
                win.blit(self.walkLeft[self.walkCount % 9], (self.x, self.y))
                self.walkCount += 1
            elif self.right:
                win.blit(self.walkRight[self.walkCount % 9], (self.x, self.y))
                self.walkCount += 1
            else:
                win.blit(self.char, (self.x, self.y))
            # 碰撞检测框
            self.hit_box = (self.x + 17, self.y + 11, 29, 52)
            pygame.draw.rect(win, (255, 0, 0), self.hit_box, 2)
    

    Enemy类:

    import pygame
    
    
    class Enemy(object):
    
        def __init__(self, x, y, width, height, end, img_base_path):
            self.x = x
            self.y = y
            self.width = width
            self.height = height
            self.path = [x, end]
            self.walkCount = 0
            self.vel = 3
            self.walkRight = [pygame.image.load(img_base_path + 'enemy/R1E.png'),
                              pygame.image.load(img_base_path + 'enemy/R2E.png'),
                              pygame.image.load(img_base_path + 'enemy/R3E.png'),
                              pygame.image.load(img_base_path + 'enemy/R4E.png'),
                              pygame.image.load(img_base_path + 'enemy/R5E.png'),
                              pygame.image.load(img_base_path + 'enemy/R6E.png'),
                              pygame.image.load(img_base_path + 'enemy/R7E.png'),
                              pygame.image.load(img_base_path + 'enemy/R8E.png'),
                              pygame.image.load(img_base_path + 'enemy/R9E.png'),
                              pygame.image.load(img_base_path + 'enemy/R10E.png'),
                              pygame.image.load(img_base_path + 'enemy/R11E.png')]
    
            self.walkLeft = [pygame.image.load(img_base_path + 'enemy/L1E.png'),
                             pygame.image.load(img_base_path + 'enemy/L2E.png'),
                             pygame.image.load(img_base_path + 'enemy/L3E.png'),
                             pygame.image.load(img_base_path + 'enemy/L4E.png'),
                             pygame.image.load(img_base_path + 'enemy/L5E.png'),
                             pygame.image.load(img_base_path + 'enemy/L6E.png'),
                             pygame.image.load(img_base_path + 'enemy/L7E.png'),
                             pygame.image.load(img_base_path + 'enemy/L8E.png'),
                             pygame.image.load(img_base_path + 'enemy/L9E.png'),
                             pygame.image.load(img_base_path + 'enemy/L10E.png'),
                             pygame.image.load(img_base_path + 'enemy/L11E.png')]
            self.hit_box = (self.x + 17, self.y + 2, 31, 57)
    
        def draw(self, win):
            self.move()
            if self.walkCount >= 11:
                self.walkCount = 0
    
            if self.vel > 0:
                win.blit(self.walkRight[self.walkCount % 11], (self.x, self.y))
                self.walkCount += 1
            else:
                win.blit(self.walkLeft[self.walkCount % 11], (self.x, self.y))
                self.walkCount += 1
            # 碰撞检测框
            self.hit_box = (self.x + 17, self.y + 2, 31, 57)
            pygame.draw.rect(win, (255, 0, 0), self.hit_box, 2)
    
        def move(self):
            if self.vel > 0:
                if self.x < self.path[1] + self.vel:
                    self.x += self.vel
                else:
                    self.vel = self.vel * -1
                    self.x += self.vel
                    self.walkCount = 0
            else:
                if self.x > self.path[0] - self.vel:
                    self.x += self.vel
                else:
                    self.vel = self.vel * -1
                    self.x += self.vel
                    self.walkCount = 0
    

    以及子弹类:

    import pygame
    
    
    # 子弹类
    class Bullet(object):
    
        def __init__(self, x, y, direction, img_base_path):
            self.x = x
            self.y = y
            self.direction = direction
            self.vel = 8 * direction
            self.width = 24
            self.height = 6
            self.bullet_right = pygame.image.load(img_base_path + 'r_bullet.png')
            self.bullet_left = pygame.image.load(img_base_path + 'l_bullet.png')
            self.hit_box = (self.x + 17, self.y + 11, 24, 6)
    
        def draw(self, win):
            # 根据人物行进的方向,切换不同的子弹图片
            if self.direction == -1:
                win.blit(self.bullet_left, (self.x - 35, self.y))
                # 碰撞检测框
                self.hit_box = (self.x - 38, self.y + 1, 24, 6)
            else:
                win.blit(self.bullet_right, (self.x + 10, self.y))
                # 碰撞检测框
                self.hit_box = (self.x + 10, self.y + 1, 24, 6)
            pygame.draw.rect(win, (255, 0, 0), self.hit_box, 2)
    

    这样处理后,运动起来的样子如下:

    最后主文件中,加入碰撞检测代码:

    import os
    from bullet import *
    from player import *
    from enemy import *
    
    WIN_WIDTH, WIN_HEIGHT = 500, 500
    pygame.init()
    win = pygame.display.set_mode((WIN_WIDTH, WIN_HEIGHT))
    pygame.display.set_caption("first game")
    img_base_path = os.getcwd() + '/img/'
    bg = pygame.image.load(img_base_path + 'bg.jpg')
    
    clock = pygame.time.Clock()
    
    
    def redraw_game_window():
        win.blit(bg, (0, 0))
        # 显示击中后的得分
        text = font.render('Score: ' + str(score), 1, (0, 0, 0))
        win.blit(text, (370, 10))
        man.draw(win)
        enemy.draw(win)
        for bullet in bullets:
            bullet.draw(win)
        pygame.display.update()
    
    def collision_check(a, b):
        temp1 = (b.x <= a.x + a.width <= b.x + b.width)
        temp2 = (b.y <= a.y + a.height <= b.y + b.height)
        return temp1 and temp2
    
    # main
    font = pygame.font.SysFont('comicsans', 30, True)
    man = Player(200, 410, 64, 64, img_base_path)
    enemy = Enemy(100, 414, 64, 64, 400, img_base_path)
    run = True
    score = 0
    bullets = []
    while run:
        clock.tick(27)
    
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                run = False
    
        for b in bullets:
            # 碰撞检测
            if collision_check(b, enemy) or collision_check(enemy, b):
                score += 1
                bullets.pop(bullets.index(b))
    
            if WIN_WIDTH > b.x > 0:
                b.x += b.vel
            else:
                bullets.pop(bullets.index(b))
    
        keys = pygame.key.get_pressed()
    
        if keys[pygame.K_SPACE]:
            if man.left:
                direction = -1
            else:
                direction = 1
    
            if len(bullets) < 5:
                bullets.append(Bullet(man.x + man.width // 2, man.y + man.height // 2, direction, img_base_path))
    
        if keys[pygame.K_LEFT] and man.x > 0:
            man.x -= man.speed
            man.left = True
            man.right = False
        elif keys[pygame.K_RIGHT] and man.x < win.get_size()[0] - man.
            man.x += man.speed
            man.left = False
            man.right = True
        else:
            man.walkCount = 0
    
        if not man.isJump:
            if keys[pygame.K_UP]:
                man.isJump = True
                man.walkCount = 0
        else:
            if man.t >= -10:
                a = 1
                if man.t < 0:
                    a = -1
                man.y -= 0.5 * a * (man.t ** 2)
    
                man.t -= 1
            else:
                man.isJump = False
                man.t = 10
    
        redraw_game_window()
    
    pygame.quit()
    

    源码下载: https://github.com/yjmyzz/pygame_tutorial

  • 相关阅读:
    搭建vue项目脚手架
    vue项目中的iconfont图标下载及配置
    vue-awesome-swiper 轮播图的使用
    IDEA自动生成Mapper和实体文件
    云服务器通过IP如何访问项目
    社保,步入社会的第一步
    Memcached安装与启动
    IDEA提示非法字符,你不懂的UTF-8
    MyEclipse导入eclipse的web项目,将WebRoot切换为WebContent
    Myeclipse2017删除tomcat后,项目全部报错的解决办法
  • 原文地址:https://www.cnblogs.com/yjmyzz/p/pygame-tutorial-6-collision-detection.html
Copyright © 2011-2022 走看看