前言

不记得哪个黑色星期五,贪吃鱼基本完工的时候,产品突然增加需求,要求金币扔出去后不消失,互相可碰撞,其最终结果还要由服务器控制(没错,至今做的所有游戏都有幕后黑手,=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的初始化和开始接口

游戏难度集中在ballgame模块,所以只分析碰撞过程得碰撞检测和处理。

复杂的碰撞

首先建系很重要。由于我们模拟使用lefttop来改变坐标,所以我们以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

转载于:https://www.cnblogs.com/freestyle21/p/4457520.html

基于Seajs的可控台球碰撞游戏相关推荐

  1. 课程设计小组报告——基于ARM实验箱的捕鱼游戏的设计与实现

    课程设计小组报告--基于ARM实验箱的捕鱼游戏的设计与实现 一.任务简介 1.1 任务内容 捕鱼游戏是一个娱乐性的游戏开发,可以给人们带来娱乐的同时还可以给人感官上的享受,所以很受人们的欢迎.本次游戏 ...

  2. 基于cocos2dx的横版动作游戏制作(二)

    基于cocos2dx的横版动作游戏制作(二) 如果你看过第一部分介绍,你应该大体知道一个横版游戏该怎么样去做,需要什么东西了....本部分介绍一些细节设计... 第一个:单例对象我们应该怎么设计才比较 ...

  3. 转:高层游戏引擎——基于OGRE所实现的高层游戏引擎框架

    高层游戏引擎--基于OGRE所实现的高层游戏引擎框架 这是意念自己的毕业论文,在一个具体的实践之中,意念主要负责的是物件和GUI之外的其他游戏系统.意念才学疏陋,望众位前辈不吝赐教.由于代码质量不高. ...

  4. 高层游戏引擎——基于OGRE所实现的高层游戏引擎框架

    技术文档(Document) 来自:noslopforever的专栏 高层游戏引擎--基于OGRE所实现的高层游戏引擎框架 这是意念自己的毕业论文,在一个具体的实践之中,意念主要负责的是物件和GUI之 ...

  5. 基于Unity3D的体素沙盒游戏设计与实现(上)

    基于Unity3D的体素沙盒游戏设计与实现 摘    要 随着计算机硬件和软件技术的逐步发展,世界游戏开发行业也在日益壮大,涌现出不少优秀的作品,逐渐成为各国文化创意领域一张闪亮的名片.本文以全球知名 ...

  6. 基于Java+Swing实现捕鱼达人游戏(含课程报告)

    基于Java+Swing实现捕鱼达人游戏(含课程报告) 一.系统介绍 1.开发背景 2.基本内容.实现方法及主要技术实现目标 3实现目标 二.功能展示 三.其他系统 四.获取源码 一.系统介绍 1.开 ...

  7. 台球html游戏算法介绍

    台球html游戏算法介绍 获取本游戏代码 游戏运行示例 基础物理知识 构建物理模型 桌台及小球 摩擦力 小球间的碰撞检测 小球间的碰撞反应 小球与边界的碰撞 检测落袋 电脑玩家的基本思路 电脑判断击目 ...

  8. 【java毕业设计】基于java+swing+GUI的雷电游戏GUI设计与实现(毕业论文+程序源码)——雷电游戏

    基于java+swing+GUI的雷电游戏GUI设计与实现(毕业论文+程序源码) 大家好,今天给大家介绍基于java+swing+GUI的雷电游戏GUI设计与实现,文章末尾附有本毕业设计的论文和源码下 ...

  9. android教育游戏设计方案,基于Android平台的儿童教育游戏的设计与开发

    摘要: 在通讯技术和信息技术的不断发展时代,智能手机(平板电脑)等移动终端的普及和功能的不断强大,基于移动终端的移动学习的理念渐渐深入人心且被广大的学习者所青睐,逐渐成为一种新的学习方式.学习者在面对 ...

最新文章

  1. SPOJ 375. Query on a tree (树链剖分)
  2. 关于Could not parse configuration: /hibernate.cfg.xml的问题
  3. Python学习之面向对象编程
  4. 手机安全卫士——进程管理
  5. idea怎么给项目改名_微软改名部惹祸了
  6. 让你的原创设计作品展示给世界
  7. redis常用命令getex_Redis常用命令
  8. 查看和设置tomcat内存
  9. 解决ECLIPSE 卡死的方法
  10. 每天只睡 4 小时!大佬们都这么拼吗?
  11. IDEA失去焦点,取消自动编译【已解决】
  12. Python新闻网站项目-9.Django前端HTML功能
  13. 使用python实现可视化ftp客户端(本地文件展示和搜索功能、ftp文件展示和搜索功能以及上传和下载功能)
  14. 生物信息学常用软件—2(PCR引物设计及相关软件使用)
  15. 因算法裁定“效率低下”,近150名员工遭解雇
  16. 世界顶级音响品牌排名
  17. 计算机提示无法识别优盘,插入U盘显示无法识别怎么办
  18. 人生成绩单97php,2020年国际国内正赛男乒成绩单,樊振东冠军最多。
  19. Python TypeError: cat() takes no arguments
  20. Minio Utils

热门文章

  1. Iframe的高级操作
  2. C++之---友元函数
  3. Python----进程之间共享数据(全局变量)
  4. PyTorch 入坑八:卷积与转置卷积
  5. 达梦系统录音服务器是哪个,达梦服务器安装及使用教程
  6. linux建立数列文本,Linux实验内容.doc
  7. linux阵列建立分区,在Linux上创建磁盘阵列———RAID-5
  8. python自动化脚本编写教程_开发工具pycharm写第一个Python自动化程序案例|python基础教程|python入门|python教程...
  9. 迅捷cad_迅捷属性
  10. 如何使用DevStack在Ubuntu 18.04上安装OpenStack