台球游戏的核心算法和AI(2)
前言:
最近研究了box2dweb, 觉得自己编写Html5版台球游戏的时机已然成熟. 这也算是圆自己的一个愿望, 一个梦想.
承接该序列的相关博文:
• 台球游戏核心算法和AI(1)
同时结合html5的学习笔记:
• box2dweb 学习笔记--sample讲解
这篇文章, 具体讲解台球游戏的box2d模型抽象, 并给出一个初步版本.
演示:
台球游戏的雏形如下所示:

该台球游戏, 改编自box2dweb的demo程序, 可用鼠标拖动球来移动.
代码的下载链接: http://pan.baidu.com/s/1sjzCwqD
分析:
让我们对台球游戏做个简单的物理抽象, 然后"庖丁解牛", 对每个组件结合box2d进行剖析.

如图所示, 其抽象为6个球袋和6个边框构成, 球袋是球落入的目标, 边框则限定了台球的活动范围.
• 边框抽象
台球边框相对简单, 其可视为静态物体. 其物理形状就是一条边.
// 设置为静态物体类型
wallBodyDef.type = b2Body.b2_staticBody; // 采用多边形形状,然后SetAsEdge设置为边
wallFixDef.shape = new b2PolygonShape;
wallFixDef.shape.SetAsEdge(new b2Vec2(x1, y1), new b2Vec2(x2, y2));
注: 边框转为box2d对象还是简单的.
• 球袋抽象
球袋本身也是静态物体, 但不同于边框, 其的box2d抽象, 多了点复杂和技巧.
1). 感应设置
球袋区域应为感应区, 球可以进入该区域, 但并不与之发生碰撞反应.
可以通过设定定制器(Fixture)的isSensor属性为true来实现, 如下面代码所示:
var holeFixtureDef = new b2FixtureDef;
holeFixtureDef.shape = new b2CircleShape(0.5);
holeFixtureDef.isSensor = true;
注: 其特性为能感知碰撞但不发生碰撞反应
2). 落袋有效区域变换
球袋和球的区域相交时, 并不代表球就进洞. 如下图所示:

注: 红球刚好和球袋区域相交, 但红球重心并没有落入球袋的有效范围内.
为了完美解决球进洞的逻辑判断, 我们有两种思路去解决.
一种思路为: 从产生的碰撞接触对象b2Contact中, 计算两者的距离, 若两者圆心距离小于球袋半径, 则算进洞, 否则不算.
另一种思路, 是做一个trick的技巧, 构造一个半径 = 球袋半径 - 球半径, 圆心依旧是球袋中心的圆, 并代替作为球袋的box2d物理模型. 该圆若与球相交, 则可以认为球重心落入球袋区域. 这可以免去前者的计算.

注: 绿色的内部圆即是构造的球袋核心圆, 其外部的圆是物理表象的圆. 该场景为球和球袋相交, 但球重心和内部圆没有相交, 即重心没有落入球袋区域.
环绕球袋本身的3/4圆, 则采用多边形来逼近模拟(样例采用16边形), 这也是防止球出有效区域(实际上这个可以忽略).
• 球体放置
我们都知道, 台球模拟, 最困难的往往是开球的时候. 一堆球挤在一起, 每个瞬间, 都有好多球彼此互相接触.
球体的堆放其实是有技巧的, 摆放的球体不需要每个都紧挨着的, 可以适当的留些空隙. 如下所示:

• 整体模拟
由于采用垂直视角看台球桌面, 重力方向是指向内部. 创建世界对象时, 可简单设置gravity为零向量.
var world = new b2World(new b2Vec2(0, 0), true)
而台球桌面本身的摩擦阻力, 由于台球游戏在box2世界, 没有存在相关物理物体, 因此我们需要设置球的线速度减震来模拟台球桌摩擦阻力.
ballBodyDef.linearDamping = 0.25;
最终台球游戏整体的box2d物理模型, 对转换为如下图:

• 进球处理
球进球袋后, 需要消失, 可以理解为该球从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.Step调用之后进行.
总结:
这边的demo图形是借助box2d的DrawDebug来渲染的. 下一步计划用漂亮的素材替换, 并完善台球的游戏规则. 虽然水平有限, 但感觉向前迈出了坚实的一步, 这种感觉挺好的.
写在最后:
如果你觉得这篇文章对你有帮助, 请小小打赏下. 其实我想试试, 看看写博客能否给自己带来一点小小的收益. 无论多少, 都是对楼主一种由衷的肯定.

台球游戏的核心算法和AI(2)的更多相关文章
- 台球游戏的核心算法和AI(1)
前言: 08年的时候, 写过一个台球游戏, 用的是java, 不过代码真的是用传说中的神器notepad写的(你信吗? 其实是用GVIM写的, ^_^), 很多类都在同一java文件中编写. 可见当时 ...
- Prim算法和Kruskal算法
Prim算法和Kruskal算法都能从连通图找出最小生成树.区别在于Prim算法是以某个顶点出发挨个找,而Kruskal是先排序边,每次选出最短距离的边再找. 一.Prim(普里姆算法)算法: ...
- 转:极小极大搜索方法、负值最大算法和Alpha-Beta搜索方法
转自:极小极大搜索方法.负值最大算法和Alpha-Beta搜索方法 1. 极小极大搜索方法 一般应用在博弈搜索中,比如:围棋,五子棋,象棋等.结果有三种可能:胜利.失败和平局.暴力搜索,如果想通 ...
- 字符串匹配-BF算法和KMP算法
声明:图片及内容基于https://www.bilibili.com/video/av95949609 BF算法 原理分析 Brute Force 暴力算法 用来在主串中查找模式串是否存以及出现位置 ...
- BF算法和KMP算法
这两天复习数据结构(严蔚敏版),记录第四章串中的两个重要算法,BF算法和KMP算法,博主主要学习Java,所以分析采用Java语言,后面会补上C语言的实现过程. 1.Brute-Force算法(暴力法 ...
- 最小生成树---Prim算法和Kruskal算法
Prim算法 1.概览 普里姆算法(Prim算法),图论中的一种算法,可在加权连通图里搜索最小生成树.意即由此算法搜索到的边子集所构成的树中,不但包括了连通图里的所有顶点(英语:Vertex (gra ...
- js实现web网页版台球游戏
js桌球小游戏在线试玩地址:http://keleyi.com/game/13/ 游戏截图: 完整代码,保存到html文件可以试玩: <!DOCTYPE html PUBLIC "-/ ...
- 经典算法和OJ网站(开发者必备-转)
一. Online Judge简介: Online Judge系统(简称OJ)是一个在线的判题系统.用户可以在线提交程序多种程序(如C.C++.Pascal)源代码,系统对源代码进行编译和执行,并通过 ...
- BM算法和Sunday快速字符串匹配算法
BM算法研究了很久了,说实话BM算法的资料还是比较少的,之前找了个资料看了,还是觉得有点生涩难懂,找了篇更好的和算法更好的,总算是把BM算法搞懂了. 1977年,Robert S.Boyer和J St ...
随机推荐
- excel如何设置输入数字后单元格自动填充颜色
在使用excel的过程中,有时需要在输入数字时,突出显示这些单元格,突出显示可以用有填充颜色的单元格来表示.为了实现这样的效果,需要借助excel的条件格式. 工具/原料 电脑 Excel 2010 ...
- BZOJ 2286: [Sdoi2011]消耗战
2286: [Sdoi2011消耗战 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 2082 Solved: 736[Submit][Status] ...
- iOS - CocoaPods 第三方开源框架管理
1.CocoaPods CocoaPods 是一个负责管理 iOS 项目中第三方开源库的工具.CocoaPods 的项目源码在 Github 上管理.该项目开始于 2011 年 8 月 12 日,在这 ...
- sqlalchemy 优化count()……
一.sqlalchemy 中的count() count()统计数据特别慢: session.query(cls).count() 8W 数据花费了近50s 但是在数据库中直接查询: select ...
- 使用WordPress模板搭建博客系统
综述: 前端展示:外观--->主题. 功能模块:插件. 遇到的问题: 1:无法加载编辑器文件: 切换下不同的wordPress模板,可能缓存文件有问题. 2:注册功能:密码重设链接无效bug-- ...
- Openfire开发配置,Openfire源代码配置,OpenFire二次开发配置
原文:http://www.cnblogs.com/lixiaolun/archive/2013/12/07/3462780.html 1.下载源代码:http://www.igniterealtim ...
- 数据库 基础篇2(mysql)
2.1MySQL入门 1)到mysql官网下载. 2)安装mysql软件 3)使用 验证是否成功 打开cmd -> 输入 mysql -u root -p 回车 -> 输入密码 ...
- MySQL默认数据库
欢迎和大家交流技术相关问题: 邮箱: jiangxinnju@163.com 博客园地址: http://www.cnblogs.com/jiangxinnju GitHub地址: https://g ...
- <select>的下拉样式
今天做一个专题,其中,select标签的样式要做成下图的模样,但是默认情况是下下图的模样: 如何实现呢,实现的办法竟然比我想象中的简单好多: select{ border: solid 1px #00 ...
- python的函数及参数
函数式编程最重要的是增强代码的重用性和可读性 def 函数名(参数): ... 函数体 ... 函数的定义主要有如下要点: def:表示函数的关键字 函数名:函数的名称,日后根据函数名调用函数 函数体 ...