java台球游戏设计原理_台球游戏的核心算法和AI(1)

前言:

08年的时候, 写过一个台球游戏, 用的是java, 不过代码真的是用传说中的神器notepad写的(你信吗? 其实是用GVIM写的, ^_^), 很多类都在同一java文件中编写. 可见当时的JAVA水平真的不咋地, 时过进迁, 还是一样的不咋地.

这边是当时的CSDN下载链接: java(台球游戏), 实现比较简单. 后来写过一个版本, 比这个要强大许多, 可惜源码丢失了.

效果展示入下图所示:

本文想讲述下台球游戏中核心算法的实现, 以及游戏AI的设计技巧. 当然自己也有个小愿望, 希望能实现一个html5版的台球游戏.

基础物理知识:

• 摩擦阻力

其满足牛顿第二定律:

f = m * a

速度与加速度关系公式:

vt = v0 + a * t

地面摩擦力与运动物体的方向相反, 阻碍物体的向前运动.

• 动量守恒

假设物体A质量为m1, 速度为v1, 物体B质量为m2, 速度为v2, 碰撞后速度分别为v1', v2'.

则满足动量守恒定律:

m1 * v1 + m2 * v2 = m1 * v1' + m2 * v2'

• 碰撞类型和能量守恒定律

1). 完全弹性碰撞

动能没有损失, 则满足如下公式:

1/2 * m1 * v1^2 + 1/2 * m2 * v2^2 = 1/2 * m1 * v1'^2 + 1/2 * m2 * v2'^2

注: 前后物体的动能保持均衡, 没有其他能量的转化.

结合之前的动量守恒定律, 我们可以进一步得到:

v1' = [(m1-m2) * v1 + 2 * m2 * v2] / (m1 + m2)

v2' = [(m2-m1) * v2 + 2 * m1 * v1] / (m1 + m2)

2). 完全非弹性碰撞

则存在其他能量的转化, 动能不守恒.

且此时两物体粘连, 速度一致, 即v1'=v2', 此时动能损失最大.

3). 弹性碰撞

介于完全弹性碰撞和完全非弹性碰撞两者之间. 动能有损失的.

物理模型:

台球游戏中, 最核心的就是其物理模型的抽象及其碰撞算法的执行过程了.

鉴于是2D版的台球游戏, 因此我们对物理模型做下简化, 球运动的方向必然穿越球的中心.

把每个台球抽象为圆(x, y, radius), 而台球桌边框抽象为线段((x1, y1), (x2, y2)).

• 碰撞检测

1). 检测球与球碰撞

我们假定球A(x1, y1, r), 球B(x2, y2, r). 则满足条件:

(x1 - x2) ^ 2 + (y1 - y2) ^ 2 <= (2*r) ^ 2

则发生碰撞, 否则没有发生碰撞

2). 检测球与球台边框碰撞

相对比较简单. 求球心到边框的垂直距离即可, 若小于等于则发生碰撞, 若大于则没有.

• 碰撞反应

1). 球与球的碰撞反应

动量是向量, 其在正交的两个方向上, 互相守恒. 我们选取两球圆心的直线为x轴, 垂直于圆心直线的为y轴. 如上图所述.

x轴上满足动量守恒:

m1 * Vx + m2 * Ux = m1 * Vx' + m2 * Ux';

并假定两球碰撞是完全弹性碰撞, 两球质量相等m1=m2, 依据基础物理知识篇的结论.

Vx' = [(m1-m2) * Vx + 2 * m2 * Ux] / (m1 + m2) = Ux;

Ux' = [(m2-m1) * Ux + 2 * m1 * Vx] / (m1 + m2) = Vx;

在X轴方向, 两球交换速度, 而在Y轴方向, 两球分速度不变.

Vy' = Vy;

Uy' = Uy;

最终碰撞后的速度公式为:

V' = Vx' + Vy' = Ux + Vy;

U' = Ux' + Uy' = Vx + Uy;

2). 球与边框的碰撞反应

把台球边框视为质量无穷大, 则简单把运动的球, 其在垂直边框的分方向反向即可.

假定碰撞碰撞平面为x轴

Vx' = Vx;

Vy' = -Vy;

最终速度公式为:

V' = Vx' + Vy' = Vx - Vy;

碰撞执行算法:

游戏的主循环往往遵循如下代码结构:

while ( true ) {

game.update(time_interval);

game.render();

}

这个时间间隔(time_interval), 由游戏的FPS来确定. 以24帧为例, 每40毫秒刷新一次.

对于台球本身而言, 若以该time_interval为更新周期, 使得运动的球体满足:

Vt = V0 + a * t

运行距离为:

S = V0 * t + 1/2 * a * t^2.

然后来检测球体是否发生了碰撞, 然后进行碰撞反应处理. 看似没有问题.

但是当球体初速度很快时, 在time_interval中有可能, 发生穿越现象.

如下图所展示的现象:

紫色球在t2时刻, 和蓝球检测到碰撞, 但实际上, 在紫球在t1~t2之间的某时刻和蓝球发生了碰撞.

为了解决该问题, 在具体的算法中, 需要引入更细的时间分片slice, 该过程在具体的update中进行模拟.

整个台球场景的更新函数:

void update(time_interval) {

while time_interval > 0:

// 碰撞检测

if detectionCollide(time_interval, least_time, ball_pairs):

// 游戏更新least_time

billiards.update(least_time)

// 对碰撞的两球进行碰撞反应

collideReaction(ball_pairs=>(ball, other))

// time_interval 减少 least_time

time_interval -= least_time

else:

// 游戏更新least_time

billiards.update(time_interval)

time_interval = 0

}

注: 碰撞反应, 按物理模型篇讲述的来.

而具体的碰撞检测算法为:

/*

@brief

在time_interval 时间内, 返回最先碰撞的球或台球边, 以及时间点

*/

bool detectionCollide(time_interval, least_time, ball_pairs) {

res = false;

least_time = time_interval;

foreach ball in billiards:

foreach otherBall in billiards:

// 求出两球的距离

S = distance(ball, otherBall)

// 以某一球作为参考坐标系, 则令一球速度向量变为 U’=U-V

// 在圆心的直线作为x轴

Ux(relative) = Ux(other ball) - Vx(ball)

// 若该方向使得两球远离, 则直接忽略

if Ux(relative) < 0:

continue

// 某该方向使得两球接近, 则可求其碰撞的预期时间点

A' = 2 * A;// 加速度为原来的两倍

// 取两者最小的时间点

delta_time = min(time_interval, Ux(relative) / Ax’)

// 预期距离 小于 两球距离,则在time_interval中不会发生碰撞

if 1/2 * Ax’ * delta_time ^ 2 + Ux(relative) * delta_time < S - 2*r:

continue

// 解一元二次方程, 使用二分搜索逼近求解

res_time <= slove(1/2 * Ax’ * x ^ 2 + Ux(relative) * x = S - 2 * r)

if res_time < least_time:

ball_pairs <= (ball, otherBall)

least_time = res_time

res = true

foreach wall in billiards:

S = distance(ball, wall)

// 设垂直于平面的方向为x轴

if Vx < 0:

continue

// 取两者最小的时间点

delta_time = min(time_interval, Vx / Ax)

// 预期距离 小于 两球距离,则在time_interval中不会发生碰撞

if 1/2 * Ax * delta_time ^ 2 + Vx * delta_time < S - r:

continue

// 解一元二次方程, 使用二分搜索逼近求解

res_time <= slove(1/2 * A * x ^ 2 + Vx * x = S - r)

if res_time < least_time:

ball_pairs <= (ball, walll)

least_time = res_time

res = true

return res

}

注:对于一元二次方程, 也可以借助分1000个细粒度时间片, 然后计算逼近求解.

台球模拟碰撞算法过程, 大致就是如上所述.

计算最复杂的时刻, 其实就是开球, 打散一堆球的时候.

总结:

本文参考了"NEHE的OPENGL中文教程 第30课 碰撞检测与模型运动". 当然实现台球游戏, 未必真的需要该算法, 很多开发者直接使用box2d就能完美并轻松的实现. 参考"使用 cocos2d-x Box2d 的实现". 后续的文章, 想讲述下台球游戏的AI如何设计和实现. 望一同努力.

写在最后:如果你觉得这篇文章对你有帮助, 请小小打赏下. 其实我想试试, 看看写博客能否给自己带来一点小小的收益. 无论多少, 都是对楼主一种由衷的肯定.

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/431283.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

murmurhash

http://www.oschina.net/translate/state-of-hash-functions http://calvin1978.blogcn.com/articles/murmur.html https://zh.wikipedia.org/wiki/Murmur%E5%93%88%E5%B8%8C http://www.trueeyu.com/?p1325转载于:https://www.cnblogs.com/LyonLys/p/murmurhash.html

cat命令详解_好程序员Python培训之详解eval好与坏

好程序员Python培训之详解eval好与坏&#xff0c;文中通过示例代码介绍的非常详细&#xff0c;对大家的学习或者工作具有一定的参考学习价值&#xff0c;下面我们一起来看一下吧。eval是Python的一个内置函数&#xff0c;这个函数的作用是&#xff0c;返回传入字符串的表达式的…

对代理商的评价怎么写_简历中的自我评价怎么写才能更吸引人?

有统计报告显示&#xff1a;HR每天看到的职位简历至少1000&#xff0c;每封简历的停留时间不过10秒。在这么短的时间内&#xff0c;让hr印象深刻&#xff0c;自我评价的价值就出现啦&#xff01;不少人认为自我评价要幽默风趣&#xff0c;例如&#xff1a;“您都看到这儿了&…

thinkphp小技巧

thinkphp小技巧 if(IS_POST) _404("页面不存在",U("index")) //如果不是POST提交&#xff0c;则跳转到index。debug模式中不跳转&#xff0c;显示string。 if(IS_POST) halt("页面不存在") //更详…

android ui状态栏高度,Android--状态栏高度,导航栏高度,Window高度,DecorView高度,heightPixels...

1:DecorView的高度DecorView的高度代表的是: 整个装饰窗口的高度, 这个高度包括:状态烂的高度和导航栏的高度.(状态栏和导航栏通常叫做装饰窗口, 而ActionBar不属于装饰窗口)这个高度, 可以代表着整个玻璃屏幕的高度.2.Window的RootView的高度RootView的获取方式:getWindow().f…

sdk是什么_人脸识别在美颜SDK中存在什么意义?

在得益于短视频、直播平台的飞速发展下&#xff0c;美颜SDK也得到了很大的发展&#xff0c;变得越来越受欢迎。美颜SDK现在已经融入到我们的生活&#xff0c;是社交中必不可少的工具。现在人们对于美颜的要求越来越高&#xff0c;这就意味着美颜SDK的质量也要越来越好。而人脸识…

检查mysql的replication_MySQL Replication需要注意的问题

MySQL Replication 大家都非常熟悉了&#xff0c;我也不会写怎么搭建以及复制的原理&#xff0c;网上相关文章非常多&#xff0c;大家可以自己去搜寻。我在这里就是想总结一下mysql主从复制需要注意的地方。有人说主从复制很简单嘛&#xff0c;就是master&#xff0c;slave的se…

socket工具android,Android通过socket长连接实现推送

工具&#xff1a;Android studio软件方法及协议&#xff1a;socket、protobuf实现原理&#xff1a;通过本地建立一个socket&#xff0c;绑定服务器IP和port&#xff0c;然后connect&#xff0c;再开启另外线程定时心跳(注意这里的心跳不是自定义发送数据&#xff0c;而是采用so…

一行代码为UITextField添加收键盘功能

iOS开发中收键盘是十分常用的功能&#xff0c;只需一行代码即可为ViewController添加工具条收键盘功能 更重要的是使用catogory&#xff0c;无代码污染。 代码 // UITextFieldkeyboard.h // TextFieldKeyBord // // Created by luo.h on 15/10/8. // Copyright © 2015…

excel一列求和_【excel每日提升】Excel周日不排班!

【新朋友】点击标题下面蓝色字“王俊东“关注。 【老朋友】点击右上角&#xff0c;转发或分享本页面内容。excel系列课程excel特效系列课程&#xff01;第1节&#xff1a;Excel有公式的单元格标记颜色&#xff0c;很简单&#xff01;第2节&#xff1a;Excel删除空行&#xff0…

ubuntu没有指纹登录_ubuntu安装指纹识别驱动

无聊时在用lsusb突然发现笔记本的指纹识别被列了出来&#xff0c;就想着怎么装上一个指纹识别的软件&#xff0c;找一了一下&#xff0c;找到了解决的办法&#xff0c;添加下面的源&#xff0c;安装fingerprint-gui就可以了。sudo add-apt-repository ppa:fingerprint/fingerpr…

android 减速动画,Android View Animation

概述可译为视图动画&#xff0c;分为缩放动画平移动画渐变动画旋转动画Android系统中定义了一个抽象类Animation来定义这种视图动画&#xff0c;它的具体子类如下表&#xff1a;动画名称对应的子类xml中标签描述缩放动画ScaleAnimation< scale />S平移动画TranslateAnima…

主键生成

早上时候想到ID生成这一回事&#xff0c;随便记下。 我们很多时候会用到数据库。而数据表中的记录基本上都是有主键的。读书的时候&#xff0c;最常见的主键生成方式&#xff0c;就是主键自增。例如&#xff1a; record_id int(11) NOT NULL AUTO_INCREMENT COMMENT 记录ID&…

excel排名_Excel案例:比赛中,如何实时显示排名

其实今天的重点&#xff0c;是要借这个常规比赛记分与公布的案例&#xff0c;介绍一下数组函数&#xff01;今天的案例&#xff0c;最关键的地方只用了一次数组函数就搞定了&#xff01;------分-----割-----线-----下面进入案例&#xff1a;常见的比赛&#xff0c;有很评委一起…

node 存储过程_用Node.js操作跨平台数据库Firebird

FireBirdFirebird是一个跨平台的关系数据库系统&#xff0c;目前能够运行在Windows、linux和各种Unix操作系统上&#xff0c;提供了大部分SQL-99标准的功能。它既能作为多用户环境下的数据库服务器运行&#xff0c;也提供嵌入式数据库的实现。Firebird脱胎于Borland公司的开源版…

鸿蒙是内核名字,华为徐直军:鸿蒙只是内核的名字,是媒体给误解成操作系统...

集微网消息(文/Jimmy)&#xff0c;华为轮值董事徐直军表示鸿蒙操作系统名字是媒体取得&#xff0c;华为并没打算取这个名字。他解释称&#xff0c;本来鸿蒙这个是用于华为内部一个内核的名字&#xff0c;只是挂在市场监管总局那里注册了。然后不知道哪个媒体好朋友看到了这个&a…

自动编译失效的Oracle数据库对象

昨天看有个帖子说到的失效对象重新编译的问题&#xff0c;然后发现自己公司里也出现莫名其妙的失效对象。 --创建自动编译失效过程事务记录表 declaretabcnt integer : 0; beginselect count(*) into tabcnt from dba_tables where table_nameRECOMPILE_LOG;if tabcnt 0 thene…

手机进程设置多少个最好_安卓手机难逃卡顿宿命?打开4个系统设置,秒变新机般流畅...

近两年安卓手机的进步无疑的巨大的&#xff0c;不论是界面美观性、系统流畅度&#xff0c;还是功能的丰富性都有很大的进步&#xff0c;但是针对安卓的旧设备&#xff0c;用了两三年依旧开始变得卡顿&#xff0c;难道安卓手机真的难逃卡顿的宿命吗&#xff1f;虽然不能解决&…

dropzonejs vue 使用_如何在Dropzone上手动触发上传文件事件

我将Dropzonejs很好地集成到了我的前端(VueJS)中。如何在Dropzone上手动触发上传文件事件我有验收测试Dropzone使用Webdriver/Codeception的问题。底线是Webdriver需要一个文件输入&#xff0c;因此它也可以附加文件。任何方式手动触发例如悬浮窗内上传&#xff1f;我可以在页面…

html5新增的js,HTML5新增属性data-*和js/jquery之间的交互及注意事项

html的data-*属性是HTML5的新属性&#xff0c;用的时候在IE8html的data-*属性是HTML5的新属性&#xff0c;用来自定义属性&#xff0c;以在JS 中控制&#xff0c;用不会出问题&#xff0c;就是用js去获得的时候会有问题&#xff0c; 不过用Jquery的$(element).attr("data-…