前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【Flutter&Flame游戏 - 拾肆】碰撞检测 | 之前代码优化

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

作者头像
张风捷特烈
发布2022-06-19 16:26:54
4210
发布2022-06-19 16:26:54
举报

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


前言

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


0. 前情回顾

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

代码语言:javascript
复制
lass TolyGame extends FlameGame with HasCollisionDetection,
复制代码

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


1.子弹的处理逻辑

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

代码语言:javascript
复制
class AnimBullet extends SpriteAnimationComponent with CollisionCallbacks {
复制代码

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

代码语言:javascript
复制
void addHitbox(){
  ShapeHitbox hitbox = RectangleHitbox();
  hitbox.debugMode = true;
  add(hitbox);
}
复制代码

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

代码语言:javascript
复制
@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 ,支持监听碰撞回调:

代码语言:javascript
复制
class HeroComponent extends PositionComponent with HasGameRef, CollisionCallbacks 
复制代码

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

代码语言:javascript
复制
void addHitbox(){
  ShapeHitbox hitbox = RectangleHitbox();
  hitbox.debugMode = true;
  add(hitbox);
}
复制代码

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

代码语言:javascript
复制
@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 ,支持监听碰撞回调:

代码语言:javascript
复制
class Monster extends SpriteAnimationComponent with CollisionCallbacks,
复制代码

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

代码语言:javascript
复制
void addHitbox(){
  ShapeHitbox hitbox = RectangleHitbox();
  hitbox.debugMode = true;
  add(hitbox);
}
复制代码

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

代码语言:javascript
复制
@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 倍。可以看出默认情况下,矩形区域的左上角和构件的左上角对齐:

https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/2e57f9d9d09245429a8e3c910f6f3c9a~tplv-k3u1fbpfcp-zoom-in-crop-mark:1304:0:0:0.awebp?

代码语言:javascript
复制
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 时,可以看出此时矩形的中心和构件的左上角对齐。

代码语言:javascript
复制
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 即可和构件的中心点对齐,可以看出此时矩形区域还需要向下微调。

代码语言:javascript
复制
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);
}
复制代码

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

https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/fe691155ce5f4674ac3ad3482cd5e060~tplv-k3u1fbpfcp-zoom-in-crop-mark:1304:0:0:0.awebp?

代码语言:javascript
复制
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 来优化之前代码中的碰撞检测逻辑。一般的休闲游戏的重头戏就是对碰撞的检测和逻辑处理,可以说这点还是非常实用的。那本文就到这里,明天见 ~

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2022-06-08,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • 0. 前情回顾
  • 1.子弹的处理逻辑
  • 2. HeroComponent 的处理逻辑
  • 3. Monster 的处理逻辑
  • 4. 区域调整
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档