基于Seajs的可控台球碰撞游戏
前言
不记得哪个黑色星期五,贪吃鱼基本完工的时候,产品突然增加需求,要求金币扔出去后不消失,互相可碰撞,其最终结果还要由服务器控制(没错,至今做的所有游戏都有幕后黑手,=W=).
对于碰撞以前只写过一个球到处碰墙壁的,小球之间的碰撞倒是没有接触,想到他们碰撞过程中的角度变化、速度分配,就不敢往下想了,于是马上想到box2d这个牛逼哄哄的引擎.
但是,使用物理引擎虽然高效、逼真,但所有碰撞都是不可控,包括最终的落点。所以引擎不能解决这次遇到的需求。
不能用引擎,咱自己写也不怕,反正当年物理和高数都学得还不错,嘻嘻、
最后,趁游戏上线后的空闲时间,整理下碰撞的思路,记录成本文。
如果你喜欢先睹为快,可以先去玩玩这个游戏: view demo >>
游戏实现
本文的核心代码是通过游戏中的逻辑移动过来,为了方便,所以代码组织也和cocos2d的思想类似。
cocos2d中有Scene、director、layer层级之分,在demo中也有对应的init、game、ball,既然用到模块层级,当然首选seajs。
游戏架构
├ css
├ main.css
├ js
├ jquery
├ jquery.js
├ seajs
├ seajs.js
├ ball
├ game
├ util
└ init
└ CrashBall.html
util模块封装的是一些必要的工具函数
ball模块封装小球move和drawPredict的类
game模块控制游戏进度,管理小球的运动
init模块是游戏入口,调用game.js的初始化和开始接口
游戏难度集中在ball和game模块,所以只分析碰撞过程得碰撞检测和处理。
复杂的碰撞
首先建系很重要。由于我们模拟使用left和top来改变坐标,所以我们以table左上角为坐标原点,垂直向下为x轴正方向,水平向左为y轴正方向。
边缘碰撞处理
边缘碰撞处理较为常规,只需要检测小球坐标和边缘的相对关系即可:
// 左右墙壁
if (ball.x < util.R || ball.x > util.W - util.R) {
ball.angle *= -1;
ball.angle %= Math.PI;
....
if (ball.x < util.R) {
ball.x = util.R;
}
if (ball.x > util.W - util.R) {
ball.x = util.W - util.R;
}
} // 上下墙壁
if (ball.y < util.R || ball.y > util.H - util.R) {
ball.angle = ball.angle > 0 ? Math.PI - ball.angle: -Math.PI - ball.angle;
ball.angle %= Math.PI;
.... }
上述代码作用是,检测小球坐标和墙壁大小关系,修改小球运动的角度。
计算角度的源码:
angle = Math.atan2(toPos[0] - fromPos[0], toPos[1] - fromPos[1]);
计算的是点(left, top)和x正方向的角度,即下图的∠DAC.

左右碰撞处理方案是乘以-1,∠DAC是入角,∠DAB和∠DAC正好差个-1.

上下碰撞是分正负处理。如上图中∠EAC和∠EAB互补,如果反向运动,∠EAB和∠CAB的变化应该是反向再选择180°。
最后注意的是,如果小球坐标超过边界坐标,则要它坐标设为边界坐标,不然就会出现靠着边界来回撞的bug,前人留下来的bug找了好久,= = .
小球碰撞处理
a. 碰撞检测是判断他们的距离和2倍半径的关系:
var dis = Math.sqrt(Math.pow(disX, 2) + Math.pow(disY, 2));
if (dis <= gap) {...}
b. 如果速度太大或者重绘频率太小,怎会看到两个小球互相融入的效果,所以处理第一步是还原碰撞初始状态。
ball.x -= (gap - dis) * sin;
ball.y -= (gap - dis) * cos;
上面代码是修正主动碰的小球的位置,让他退回刚好碰撞的位置,其实就是下图的AB之间的距离,相当于球o1从A退到B.

c. 小球斜碰很难分析,我们把他们的速度旋转到x轴方向。
vx1 = vx * hitcos + vy * hitsin,
vy1 = vy * hitcos - vx * hitsin,
上面的vx是原来速度v在x方向的速度,vy是v在y方向的速度。把原来的速度顺时针旋转两球圆心弦的角度,以后则不考虑y方向的运动。x方向上动量守恒和能量守恒,即
m * vx10 + m * vx20 = m * vx11 + m * vx21;
1/2 * m * vx10² + 1/2 * m * vx20² = 1/2 * m * vx11² + 1/2 * m * v21²
联立求解可得碰撞后的速度大小。
然后将速度旋转回去:
vx = vx1 * hitcos - vy1 * hitsin;
vy = vy1 * hitcos + vx1 * hitsin;
则碰撞后的速度和角度都可以得出:
ball.v = Math.sqrt(vx * vx + vy * vy) * (1 - 0); // (1-0) 变为大小,标量
obj.v = Math.sqrt(objVx * objVx + objVy * objVy) * (1 - 0);
ball.angle = Math.atan2(vx, vy);
obj.angle = Math.atan2(objVx, objVy);
注意atan2(y, x)计算的是(x,y)到(0,0)的角度,我们这里使用(vx, vy),计算的是(vx, vy)到(0,0)角的余角。
考虑外力
ball.v = ball.v * (1 - util.LOSS); // 碰撞边缘后减速
故循环跳出条件是 Math.round(v) <= 0
if( Math.round(ball.v <= 0) {
ball.v = 0;
for(var i = 0; i < movingballs.length; i++) {
if(movingballs[i] == ball) {
movingballs.remove(i);
}
}
window.clearInterval(_this.emmiter);
}
上式moveingballs.remove(i)移除数组指定位置的元素,是手动添加的:
Array.prototype.remove = function() {
...
}
预测线
预测线的运动逻辑和小球一样,唯一不同的是,使用while而不是setInterval, 这样预测路线就会比我们的小球提前运动到指定位置。
由于预测路线和小球运动路径相同,且比小球提前到达,那么就能提前知道小球的停止位置,如果判断到小球到达了不能到达的位置,则可以减小他的速度即可。
预测路线的小黄点,是通过
var elem = document.createElement("div");
....
wrap.append(elem);
追加到DOM父节点上的,所以如果一次碰撞小球太多,则会卡死的现象。
在cocos2d中是使用在Layer上drawDot(),几乎没有内存消耗,所以不存在卡的现象。
如果要应用到是项目中,建议使用canvas 或者 documentFragment处理。
另外在贪吃鱼游戏中,运动的过程是通过加速度和路程来计算每次增加的位置的,运动效果比刚才的每次增加相同dx,dy的方案要好,如果对运动效果要求较高,可以考虑这种方式。
结语
实际需求中,很多情况下我们不能使用现成的引擎或者框架,必须要去自己造轮子。
像刚才的碰撞处理中完全靠数学和物理知识,可见学好基本理论知识的重要性,就像作为程序员必需的数据结构和算法一样,总有你不知道的哪天就会用上,所以不断学习这些基础的东西,才能在用的时候随机应变。
最后,源码放在github上: https://github.com/freestyle21/CrashBall
基于Seajs的可控台球碰撞游戏的更多相关文章
- 课程设计小组报告——基于ARM实验箱的捕鱼游戏的设计与实现
课程设计小组报告--基于ARM实验箱的捕鱼游戏的设计与实现 一.任务简介 1.1 任务内容 捕鱼游戏这个项目是一个娱乐性的游戏开发,该游戏可以给人们带来娱乐的同时还可以给人感官上的享受,所以很受人们的 ...
- 使用unity3d和tensorflow实现基于姿态估计的体感游戏
使用unity3d和tensorflow实现基于姿态估计的体感游戏 前言 之前做姿态识别,梦想着以后可以自己做出一款体感游戏,然而后来才发现too young.但是梦想还是要有的,万一实现了呢.趁着p ...
- 转:高层游戏引擎——基于OGRE所实现的高层游戏引擎框架
高层游戏引擎——基于OGRE所实现的高层游戏引擎框架 这是意念自己的毕业论文,在一个具体的实践之中,意念主要负责的是物件和GUI之外的其他游戏系统.意念才学疏陋,望众位前辈不吝赐教.由于代码质量不高. ...
- 基于FPGA的飞机的小游戏
基于FPGA的飞机的小游戏 实验原理 该实验主要分为4个模块,采用至上而下的设计方法进行设计.由50M的晶振电路提供时钟源,VGA显示控制模块.图形显示控制模块.移动模块的时钟为25M,由时钟分频电路 ...
- 基于HTML5实现的中国象棋游戏
棋类游戏在桌面游戏中已经非常成熟,中国象棋的版本也非常多.今天这款基于HTML5技术的中国象棋游戏非常有特色,我们不仅可以选择中国象棋的游戏难度,而且可以切换棋盘的样式.程序写累了,喝上一杯咖啡,和电 ...
- 基于html5实现的愤怒的小鸟网页游戏
之前给大家分享一款基于html5 canvas和js实现的水果忍者网页版,今天给大家分享一款基于html5实现的愤怒的小鸟网页游戏.这款游戏适用浏览器:360.FireFox.Chrome.Safar ...
- 基于HTML5实现五彩连珠小游戏
今天给大家分享一款基于HTML5实现五彩连珠小游戏.这款游戏的规则:点击彩球移动到期望的位置,每移动一次,画面将随机出现3个新的彩球:当同一颜色的彩球连成5个一行或一列或一斜线时,这5个彩球同时消失, ...
- 课程设计个人报告——基于ARM实验箱的捕鱼游戏的设计与实现
课程设计个人报告--基于ARM实验箱的捕鱼游戏的设计与实现 一.个人贡献 参与课设题目讨论及部分过程 资料收集 负责代码调试 捕鱼游戏相应功能的实现 实验环境 Eclipse软件开发环境: ARM实验 ...
- js实现小球碰撞游戏
效果图: 效果图消失只是截的gif图的问题 源码: <!DOCTYPE html> <html lang="en"> <head> <m ...
随机推荐
- CoreThink主题开发(七)使用H-ui开发博客主题之新闻资讯正文页面
感谢H-ui.感谢CoreThink! 效果图: 后台发文章有上传附件.封面的功能,但是前台代码中有,不能显示,去除了,前台页面还有社会化分享,百度的,页面也不显示. Blog/Cms/Index/d ...
- Linux基础系列:常用命令(3)
作业一: ) 将用户信息数据库文件和组信息数据库文件纵向合并为一个文件/.txt(覆盖) cat /etc/passwd /etc/group > /test/.txt ) 将用户信息数据库文件 ...
- 活用:after 让图片垂直居中
现在莫名虽然更喜欢 background 但大多时候还是选择用 img,这其中的利弊争议不在本文中赘述. 那么在布局中常会遇到定高容器中图片居中的需求,这时就有很多方法了呀: line-height ...
- js常用方法汇总
产生在m.n之间的随机整数 //Math.round()把数四舍五入为最接近的整数. function random(m, n) { return Math.round(Math.random() * ...
- 20165101刘天野 2017-2018-2 《Java程序设计》第4周学习总结
#20165101刘天野 2017-2018-2 <Java程序设计>第4周学习总结 教材学习内容总结 第五章:子类与继承 面向对象程序设计语言有三大特性:封装.继承和多态性.继承是面向对 ...
- INSPIRED启示录 读书笔记 - 第9章 产品副经理
发现帮手 从本质上讲,产品就是创意,产品经理的职责是想出好点并加以实现.我们需要好点子,有些想法是我们自己的创意,但如果仅依靠自己,就会严重限制创意的发挥 做产品要找公司最聪明的人合作,发现公司里潜在 ...
- wampserver安装缺失vcruntime140.dll
wampserver安装缺失vcruntime140.dll,这是安装wamp时候经常遇到的一个问题,对于初学者来说很难解决,以前的百度经验很难解决,所以给大家一个可以用的. 方法/步骤 请先 ...
- MyBatis联合查询association使用
1.需求 两张表 channels(频道表) member(会员表) 频道表里面有会员id,查询频道列表的时候需要关联查询出会员的名称,头像等信息 . 2.channels.xml定义,配置主要在这 ...
- Struts2获取参数的几种方式
Struts2由于是一个贴心的框架,所以获取参数这种体力活,就无需再通过原生的request来getParameter了,有如下几种方式进行获取 1.Action中属性驱动,必须提供与form表单na ...
- Luogu-4774 [NOI2018]屠龙勇士
这题好像只要会用set/平衡树以及裸的\(Excrt\)就能A啊...然而当时我虽然看出是\(Excrt\)却并不会...今天又学了一遍\(Excrt\),趁机把这个坑给填了吧 现预处理一下,找出每条 ...