如图所示, 其抽象为6个球袋和6个边框构成, 球袋是球落入的目标, 边框则限定了台球的活动范围。
边框抽象
台球边框相对简单, 其可视为静态物体。 其物理形状就是一条边。
- // 设置为静态物体类型
- wallBodyDef.type = b2Body.b2_staticBody;
-
- // 采用多边形形状,然后SetAsEdge设置为边
- wallFixDef.shape = new b2PolygonShape;
- wallFixDef.shape.SetAsEdge(new b2Vec2(x1, y1), new b2Vec2(x2, y2));
注: 红球刚好和球袋区域相交, 但红球重心并没有落入球袋的有效范围内。
为了完美解决球进洞的逻辑判断, 我们有两种思路去解决。
一种思路为:从产生的碰撞接触对象b2Contact中, 计算两者的距离, 若两者圆心距离小于球袋半径, 则算进洞, 否则不算。
另一种思路, 是做一个trick的技巧,?构造一个半径 = 球袋半径 - 球半径, 圆心依旧是球袋中心的圆, 并代替作为球袋的box2d物理模型。 该圆若与球相交, 则可以认为球重心落入球袋区域。 这可以免去前者的计算。
![154407qv1ne3aeq7yjayno.png](https://di.gameres.com/attachment/forum/201603/15/154407qv1ne3aeq7yjayno.png)
注: 绿色的内部圆即是构造的球袋核心圆, 其外部的圆是物理表象的圆。 该场景为球和球袋相交, 但球重心和内部圆没有相交, 即重心没有落入球袋区域。
环绕球袋本身的3/4圆, 则采用多边形来逼近模拟(样例采用16边形), 这也是防止球出有效区域(实际上这个可以忽略)。
球体放置
我们都知道, 台球模拟, 最困难的往往是开球的时候。 一堆球挤在一起, 每个瞬间, 都有好多球彼此互相接触。
球体的堆放其实是有技巧的, 摆放的球体不需要每个都紧挨着的, 可以适当的留些空隙。 如下所示:
![154408lhjjtitshcq10cql.png](https://di.gameres.com/attachment/forum/201603/15/154408lhjjtitshcq10cql.png)
整体模拟
由于采用垂直视角看台球桌面, 重力方向是指向内部。 创建世界对象时, 可简单设置gravity为零向量。
- var world = new b2World(new b2Vec2(0, 0), true)
进球处理
球进球袋后, 需要消失, 可以理解为该球从box2d的物理世界中消除。
对于碰撞反应, box2d提供了两种方式去处理。
1)注册ContactListener方式
2)遍历ContactList列表
样例代码采用第二种方式, 原因如下:
1)ContactListener的回调处于step的模拟过程中,?box2d明确规定step模拟过程中, 不允许修改物理属性。
2)由于台球游戏的物体个数并不多, 因此遍历ContactList列表其性能是可接受的。
- /* 清除落入袋中球 */
- var contactList = world.GetContactList();
- for ( var contact = contactList; contact; contact = contact.GetNext() ) {
- if ( !contact.IsTouching() ) { /* 接触只代表AABB重合 但不代表形体碰撞 */
- continue;
- }
- var b1 = contact.GetFixtureA().GetBody();
- var b2 = contact.GetFixtureB().GetBody();
-
- if (b1.GetUserData() b2.GetUserData()) {
- if (b1.GetUserData() === BALL_TYPE.BG_HOLE_TYPE b2.GetUserData() === BALL_TYPE.BG_BALL_TYPE ) {
- world.DestroyBody(b2);
- }
- if ( b2.GetUserData() === BALL_TYPE.BG_HOLE_TYPE b1.GetUserData() === BALL_TYPE.BG_BALL_TYPE ) {
- world.DestroyBody(b1);
- }
- }
- }
- }
- }
- world.DestroyBody(b1);
- if ( b2.GetUserData() === BALL_TYPE.BG_HOLE_TYPE b1.GetUserData() === BALL_TYPE.BG_BALL_TYPE ) {
- }
- world.DestroyBody(b2);
- if (b1.GetUserData() === BALL_TYPE.BG_HOLE_TYPE b2.GetUserData() === BALL_TYPE.BG_BALL_TYPE ) {
-
- var b2 = contact.GetFixtureB().GetBody();
- var b1 = contact.GetFixtureA().GetBody();
- }
- continue;
- if ( !contact.IsTouching() ) { /* 接触只代表AABB重合 但不代表形体碰撞 */
- for ( var contact = contactList; contact; contact = contact.GetNext() ) {
- var contactList = world.GetContactList();
注: 该处理代码在world。Step调用之后进行。
总结:
这边的demo图形是借助box2d的DrawDebug来渲染的。 下一步计划用漂亮的素材替换, 并完善台球的游戏规则。 虽然水平有限, 但感觉向前迈出了坚实的一步, 这种感觉挺好的。
相关阅读:台球类html5游戏的AI设计与核心算法的实现
![锐亚教育](http://www.insideria.cn/files/default/2017/03-19/164933d4e4bd117214.jpg)
锐亚教育,游戏开发论坛|游戏制作人|游戏策划|游戏开发|独立游戏|游戏产业|游戏研发|游戏运营| unity|unity3d|unity3d官网|unity3d 教程|金融帝国3|8k8k8k|mcafee8.5i|游戏蛮牛|蛮牛 unity|蛮牛
- 还没有人评论,欢迎说说您的想法!