【Flutter&Flame游戏 - 拾肆】碰撞检测 | 之前代码优化


theme: cyanosis

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第 15 天,点击查看活动详情


前言

这是一套 张风捷特烈 出品的 Flutter&Flame 系列教程,发布于掘金社区。如果你在其他平台看到本文,可以根据对于链接移步到掘金中查看。因为文章可能会更新、修正,一切以掘金文章版本为准。本系列源码于 【toly_game】 ,如果本系列对你有所帮助,希望点赞支持,本系列文章一览:

第一季完结,谢谢支持 ~


0. 前情回顾

之前的 矩形域中心点 的包含关系,这样校验有很大的误差。上一篇介绍了 CollisionCallbacks 的使用,本篇就来基于 CollisionCallbacks 对之前的代码进行优化。首先让 TolyGame 混入 HasCollisionDetection 支持配置检测:

dart lass TolyGame extends FlameGame with HasCollisionDetection,


接下来让三类主要角色: HeroComponentMonsterBullet 混入 HasCollisionDetection 。确定碰撞区域,并处理碰撞逻辑。代码详见 【14/01】


1.子弹的处理逻辑

之前把子弹分为了静止 Bullet 的和运动 AnimBullet 的 ,这里把 Bullet 去掉了。一张图片也可以看做是一帧动画,只要不循环播放,先在 AnimBullet 中混入 CollisionCallbacks ,支持监听碰撞回调:

dart class AnimBullet extends SpriteAnimationComponent with CollisionCallbacks {


然后在 onLoad 中添加 Hitbox 碰撞区域,这里用矩形区域:

dart void addHitbox(){ ShapeHitbox hitbox = RectangleHitbox(); hitbox.debugMode = true; add(hitbox); }


然后覆写 onCollision 监听碰撞,这里的处理逻辑是:当子弹类型是 hero 射的,碰撞物体是 Monster ,则说名主角的子弹命中的怪兽,消失即可,反正亦然。

dart @override void onCollision(Set<Vector2> intersectionPoints, PositionComponent other) { super.onCollision(intersectionPoints, other); if (type == BulletType.hero && other is Monster) { removeFromParent(); } if (type == BulletType.monster && other is HeroComponent) { removeFromParent(); } }


2. HeroComponent 的处理逻辑

先看 HeroComponent 中的处理,先混入 CollisionCallbacks ,支持监听碰撞回调:

dart class HeroComponent extends PositionComponent with HasGameRef, CollisionCallbacks

然后在 onLoad 中添加 Hitbox 碰撞区域,这里用矩形区域:

dart void addHitbox(){ ShapeHitbox hitbox = RectangleHitbox(); hitbox.debugMode = true; add(hitbox); }


然后覆写 onCollision 监听碰撞,这里的处理逻辑是当碰撞物体类型是 AnimBullet ,且类型为 BulletType.monster 时,就表示 HeroComponent 已经中弹了,通过 loss 方法添加伤害。

dart @override void onCollision(Set<Vector2> intersectionPoints, PositionComponent other) { super.onCollision(intersectionPoints, other); if (other is AnimBullet&&other.type==BulletType.monster) { loss(other.attr); } }


3. Monster 的处理逻辑

同样,先混入 CollisionCallbacks ,支持监听碰撞回调:

dart class Monster extends SpriteAnimationComponent with CollisionCallbacks,


然后在 onLoad 中添加 Hitbox 碰撞区域,这里用矩形区域:

dart void addHitbox(){ ShapeHitbox hitbox = RectangleHitbox(); hitbox.debugMode = true; add(hitbox); }


然后覆写 onCollision 监听碰撞,这里的处理逻辑是当碰撞物体类型是 AnimBullet ,且类型为 BulletType.hero 时,就表示 Monster 已经中弹了,通过 loss 方法添加伤害。

dart @override void onCollision(Set<Vector2> intersectionPoints, PositionComponent other) { super.onCollision(intersectionPoints, other); if (other is AnimBullet&&other.type==BulletType.hero) { loss(other.attr); } }

其实 MonsterHeroComponent 整体结构是类似的。都具有发射子弹、减少生命值、基础属性等特点。但也有很多不同点,比如主角是用户的主动操作,怪物是系统的固定行为。以后可以考虑进一步进行抽象,求同存异来,优化逻辑。

最后把之前在 TolyGame#update 中校验的一堆逻辑删掉即可。从这里可以看出,CollisionCallbacks 的优势是: 可以给让构件监听到自身的碰撞事件,从而主动处理碰撞逻辑;而之前那样,就像是一个 监工 ,在不断看着有没有人碰撞,构件本身是被动的。


4. 区域调整

由于图片的关系,可能碰撞区域会比较大,如果我们只想取区域中的某一块,而非整体区域,该怎么做呢?


默认情况下,RectangleHitbox 会占据整个构件区域,但其构造方法中可以指定一些尺寸和位置属性。


下面我们来结合上一篇中的碰撞试针,来看一下如何对碰撞区域进行调整,代码详见 【14/02】。下图中将矩形区域的宽变成角色尺寸的 0.5 倍,高变为 0.8 倍。可以看出默认情况下,矩形区域的左上角和构件的左上角对齐:

dart void addHitbox(){ Vector2 boxSize = Vector2(size.x*0.5, size.y*0.8); ShapeHitbox hitbox = RectangleHitbox( size: boxSize, ); hitbox.debugMode = true; add(hitbox); }


当将RectangleHitboxanchor 指定为 Anchor.center 时,可以看出此时矩形的中心和构件的左上角对齐。

dart void addHitbox(){ Vector2 boxSize = Vector2(size.x*0.5, size.y*0.8); ShapeHitbox hitbox = RectangleHitbox( size: boxSize, anchor: Anchor.center, ); hitbox.debugMode = true; add(hitbox); }


然后只有通过 position 进行偏移 size/2 即可和构件的中心点对齐,可以看出此时矩形区域还需要向下微调。

dart void addHitbox(){ Vector2 boxSize = Vector2(size.x*0.5, size.y*0.8); ShapeHitbox hitbox = RectangleHitbox( size: boxSize, anchor: Anchor.center, position: size/2 ); hitbox.debugMode = true; add(hitbox); }


主要,偏移的微调最好用构件的尺寸分率计算得到,不要直接写死多少数值,不然在构建进行放大时,肯定会出问题。如下的操作,就可以得到一个比较满意的碰撞区域:

dart void addHitbox(){ Vector2 boxSize = Vector2(size.x*0.5, size.y*0.8); double offsetFixY = -size.y*0.11; ShapeHitbox hitbox = RectangleHitbox( size: boxSize, anchor: Anchor.center, position: size/2-Vector2(0,offsetFixY) ); hitbox.debugMode = true; add(hitbox); }


其他的构建,也可以用类似的方式来优化碰撞区域。本文介绍了一下如通过 CollisionCallbacks 来优化之前代码中的碰撞检测逻辑。一般的休闲游戏的重头戏就是对碰撞的检测和逻辑处理,可以说这点还是非常实用的。那本文就到这里,明天见 ~

\

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值