首页 > 其他 > 详细

04.碰撞反应

时间:2019-11-01 15:01:57      阅读:82      评论:0      收藏:0      [点我收藏+]

碰撞检查   两精灵之间的距离<=精灵显示图像宽度一半的和,就说明碰撞了

实施碰撞功能:

我们将两点间的距离等常用函数抽取成一个util模块

import math


def distance(point_1=(0, 0), point_2=(0, 0)):
    """计算两点间的距离"""
    return math.sqrt((point_1[0] - point_2[0]) ** 2 + (point_1[1] - point_2[1]) ** 2)


def center_image(image):
    """锚点居中"""
    image.anchor_x = image.width / 2
    image.anchor_y = image.height / 2

在Physicalobject类构造方法中增加属性dead表示是否死亡

 # 是否死亡
 self.dead = False

接着添加两个方法:

 def collides_with(self, other_object):
     """是否与other_object碰撞"""
      collision_distance = self.image.width / 2 + other_object.image.width / 2
      actual_distance = util.distance(self.position, other_object.position)
      return (actual_distance <= collision_distance)

def handle_collision_with(self, other_object):
    """碰撞处理
       每个对象在碰到另一个对象时就死掉
    """
    self.dead = True

接下来就是对游戏对象列表遍历移除死亡对象game_objects,在修改启动模块的update()

def update(dt):
    for obj in game_objects:
        obj.update(dt)  # 调用Physicalobject的更新
    # 检查所有对象对
    for i in range(len(game_objects)):
        for j in range(i + 1, len(game_objects)):
            obj_1 = game_objects[i]
            obj_2 = game_objects[j]
            if not obj_1.dead and not obj_2.dead:
                if obj_1.collides_with(obj_2):
                    obj_1.handle_collision_with(obj_2)
                    obj_2.handle_collision_with(obj_1)

    for to_remove in [obj for obj in game_objects if obj.dead]:
        to_remove.delete()
        game_objects.remove(to_remove)

 

现在可以运行查看,两精灵碰撞会都消失

碰撞响应:

现在需要我们在游戏过程中开始将内容添加到game_objects列表中,并让对象检查彼此的类型以决定是否应该死亡

 在循环下方声明一个to_add列表,然后向其中添加新对象。在update()最底部,在删除对象代码之后,将to_add中的对象添加到game_objects中:

def update(dt):
    # 检查所有对象对
    for i in range(len(game_objects)):
        for j in range(i + 1, len(game_objects)):
            obj_1 = game_objects[i]
            obj_2 = game_objects[j]
            if not obj_1.dead and not obj_2.dead:
                if obj_1.collides_with(obj_2):
                    obj_1.handle_collision_with(obj_2)
                    obj_2.handle_collision_with(obj_1)

    to_add = []
    for obj in game_objects:
        obj.update(dt)  # 调用Physicalobject的更新
        to_add.extend(obj.new_objects)
        obj.new_objects = [] # 添加完置空

    for to_remove in [obj for obj in game_objects if obj.dead]:
        # 如果垂死的对象产生了任何新对象,请稍后将它们添加到game_objects列表中
        to_add.extend(obj.new_objects)
        to_remove.delete()
        game_objects.remove(to_remove)
    game_objects.extend(to_add)

Physicalobject类构造中添加new_objects属性:

self.new_objects = []

下面来完成子弹模块:

"""子弹bullet.py"""
import pyglet
from let import physicalobject3, resources


class Bullet(physicalobject3.Physicalobject):
    def __init__(self, *args, **kwargs):
        super().__init__(resources.bullet_image, *args, **kwargs)
        # 执行一次
        pyglet.clock.schedule_once(self.die, 0.5)
        self.is_bullet = True  # 是子弹

    def die(self, dt):
        self.dead = True

发射子弹:

Player类,构造中定义子弹的速度:
 # 子弹速度
 self.bullet_speed = 700.0

发射子弹的按键控制:

    def on_key_press(self, symbol, modifiers):
        if symbol == key.SPACE:
            self.fire()

我们需要在船头而不是在船头放出子弹。我们还需要将飞船的现有速度添加到子弹的新速度中,否则,如果玩家走得足够快,子弹的运行速度最终会比飞船慢

 def fire(self):
        """将飞船的现有速度添加到子弹的新速度中"""
        # 子弹的大小
        angle_radians = -math.radians(self.rotation)  # 转换为弧度并反转方向
        ship_radius = self.image.width / 2
        bullet_x = self.x + math.cos(angle_radians) * ship_radius
        bullet_y = self.y + math.sin(angle_radians) * ship_radius
        # 子弹
        new_bullet = bullet.Bullet(bullet_x, bullet_y, batch=self.batch)
        # 飞船的现有速度+子弹的速度=子弹的新速度
        bullet_vx = self.velocity_x + math.cos(angle_radians) * self.bullet_speed
        bullet_vy = self.velocity_y + math.sin(angle_radians) * self.bullet_speed
        new_bullet.velocity_x, new_bullet.velocity_y = bullet_vx, bullet_vy
        self.new_objects.append(new_bullet)

player构造中新增event_handlers属性如下,这样就包含了放子弹事件与KeyStateHandler

self.event_handlers = [self, self.key_handler]

主模块中修改原来的推送事件

# 将其推送到事件堆栈中
for handler in play_ship.event_handlers:
    game_window.push_handlers(handler)

碰撞时不应破坏相同类型的对象,修改Physicalobject类中的handle_collision_with:

    def handle_collision_with(self, other_object):
        """碰撞处理
        碰撞时不应破坏相同类型的对象
        """
        if other_object.__class__ == self.__class__:
            self.dead = False
        else:
            self.dead = True

现在还有一个问题是,子弹与玩家碰撞,我们在Physicalobject构造中定义reacts_to_bullets,表示是否对子弹有反应碰撞,并默认为不是子弹:

self.is_bullet = False  # 不是子弹
self.reacts_to_bullets = True # 对子弹有反应

显然,玩家构造中设置为False

 self.reacts_to_bullets = False  # 对子弹无反应

然后我们修改collides_with碰撞检测:

    def collides_with(self, other_object):
        """是否与other_object碰撞"""
        if not self.reacts_to_bullets and other_object.is_bullet:
            return False
        if self.is_bullet and not other_object.reacts_to_bullets:
            return False
        collision_distance = self.image.width / 2 + other_object.image.width / 2
        actual_distance = util.distance(self.position, other_object.position)
        return (actual_distance <= collision_distance)

ok,现在让我们让子弹击中小行星吧

技术分享图片

 

04.碰撞反应

原文:https://www.cnblogs.com/fly-book/p/11775990.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!