游戏开发论坛

 找回密码
 立即注册
搜索
查看: 7201|回复: 1

台球游戏的核心算法和AI:box2d模型抽象

[复制链接]

1万

主题

1万

帖子

3万

积分

论坛元老

Rank: 8Rank: 8

积分
36572
发表于 2016-3-15 15:48:28 | 显示全部楼层 |阅读模式
1422431529fOVYBOna.jpg

  GameRes游资网授权发布 文 /mumuxinfei

  这篇文章, 具体讲解台球游戏的box2d模型抽象, 并给出一个初步版本。

  演示:

  台球游戏的雏形如下所示:

1.gif

  该台球游戏, 改编自box2dweb的demo程序, 可用鼠标拖动球来移动。

  分析:

  让我们对台球游戏做个简单的物理抽象, 然后"庖丁解牛", 对每个组件结合box2d进行剖析。

2.png

  如图所示, 其抽象为6个球袋和6个边框构成, 球袋是球落入的目标, 边框则限定了台球的活动范围。

  边框抽象

  台球边框相对简单, 其可视为静态物体。 其物理形状就是一条边。

  1. // 设置为静态物体类型
  2. wallBodyDef.type = b2Body.b2_staticBody;

  3. // 采用多边形形状,然后SetAsEdge设置为边
  4. wallFixDef.shape = new b2PolygonShape;
  5. wallFixDef.shape.SetAsEdge(new b2Vec2(x1, y1), new b2Vec2(x2, y2));
复制代码

  注: 边框转为box2d对象还是简单的。

  球袋抽象

  球袋本身也是静态物体, 但不同于边框, 其的box2d抽象, 多了点复杂和技巧。?

  1)感应设置

  球袋区域应为感应区, 球可以进入该区域, 但并不与之发生碰撞反应。

  可以通过设定定制器(Fixture)的isSensor属性为true来实现, 如下面代码所示:

  1. var holeFixtureDef = new b2FixtureDef;
  2. holeFixtureDef.shape = new b2CircleShape(0.5);
  3. holeFixtureDef.isSensor = true;
复制代码

  注: 其特性为能感知碰撞但不发生碰撞反应

  2)落袋有效区域变换

  球袋和球的区域相交时, 并不代表球就进洞。 如下图所示:

3.png

  注: 红球刚好和球袋区域相交, 但红球重心并没有落入球袋的有效范围内。

  为了完美解决球进洞的逻辑判断, 我们有两种思路去解决。

  一种思路为:从产生的碰撞接触对象b2Contact中, 计算两者的距离, 若两者圆心距离小于球袋半径, 则算进洞, 否则不算。

  另一种思路, 是做一个trick的技巧,?构造一个半径 = 球袋半径 - 球半径, 圆心依旧是球袋中心的圆, 并代替作为球袋的box2d物理模型。 该圆若与球相交, 则可以认为球重心落入球袋区域。 这可以免去前者的计算。

4.png

  注: 绿色的内部圆即是构造的球袋核心圆, 其外部的圆是物理表象的圆。 该场景为球和球袋相交, 但球重心和内部圆没有相交, 即重心没有落入球袋区域。

  环绕球袋本身的3/4圆, 则采用多边形来逼近模拟(样例采用16边形), 这也是防止球出有效区域(实际上这个可以忽略)。

  球体放置

  我们都知道, 台球模拟, 最困难的往往是开球的时候。 一堆球挤在一起, 每个瞬间, 都有好多球彼此互相接触。

  球体的堆放其实是有技巧的, 摆放的球体不需要每个都紧挨着的, 可以适当的留些空隙。 如下所示:

5.png

  整体模拟

  由于采用垂直视角看台球桌面, 重力方向是指向内部。 创建世界对象时, 可简单设置gravity为零向量。

  1. var world = new b2World(new b2Vec2(0, 0), true)
复制代码

  而台球桌面本身的摩擦阻力, 由于台球游戏在box2世界, 没有存在相关物理物体, 因此我们需要设置球的线速度减震来模拟台球桌摩擦阻力。

  1. ballBodyDef.linearDamping = 0.25;
复制代码

  最终台球游戏整体的box2d物理模型, 对转换为如下图:

6.png

  进球处理

  球进球袋后, 需要消失, 可以理解为该球从box2d的物理世界中消除。

  对于碰撞反应, box2d提供了两种方式去处理。

  1)注册ContactListener方式

  2)遍历ContactList列表

  样例代码采用第二种方式, 原因如下:

  1)ContactListener的回调处于step的模拟过程中,?box2d明确规定step模拟过程中, 不允许修改物理属性。

  2)由于台球游戏的物体个数并不多, 因此遍历ContactList列表其性能是可接受的。

  1. /* 清除落入袋中球 */
  2. var contactList = world.GetContactList();
  3. for ( var contact = contactList; contact; contact = contact.GetNext() ) {
  4. if ( !contact.IsTouching() ) { /* 接触只代表AABB重合 但不代表形体碰撞 */
  5. continue;
  6. }
  7. var b1 = contact.GetFixtureA().GetBody();
  8. var b2 = contact.GetFixtureB().GetBody();

  9. if (b1.GetUserData() && b2.GetUserData()) {
  10. if (b1.GetUserData() === BALL_TYPE.BG_HOLE_TYPE && b2.GetUserData() === BALL_TYPE.BG_BALL_TYPE ) {
  11. world.DestroyBody(b2);
  12. }
  13. if ( b2.GetUserData() === BALL_TYPE.BG_HOLE_TYPE && b1.GetUserData() === BALL_TYPE.BG_BALL_TYPE ) {
  14. world.DestroyBody(b1);
  15. }
  16. }
  17. }
复制代码

  注: 该处理代码在world。Step调用之后进行。

  总结:

  这边的demo图形是借助box2d的DrawDebug来渲染的。 下一步计划用漂亮的素材替换, 并完善台球的游戏规则。 虽然水平有限, 但感觉向前迈出了坚实的一步, 这种感觉挺好的。

  相关阅读台球类html5游戏的AI设计与核心算法的实现

0

主题

3

帖子

10

积分

新手上路

Rank: 1

积分
10
发表于 2016-12-14 12:39:30 | 显示全部楼层
版主您好,能帮忙联系mumuxinfei同学吗?谢谢。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

作品发布|文章投稿|广告合作|关于本站|游戏开发论坛 ( 闽ICP备17032699号-3 )

GMT+8, 2025-2-25 04:38

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表