前言:
  前几天目睹了大学同学开了个微店, 算是间接体验微信公众平台的使用. 觉得非常便捷和方便, 于是自己也想捣鼓一个. 公众号取名: "木目的H5游戏世界", 定位做成一个, 个人H5游戏的小站点, 同时分享游戏技术博文. 你的体验, 是对我最大的肯定.
  本文将讲述一下定点投篮游戏的编写, 主要阐述其物理模型的抽象, 后续慢慢的完善和迭代.

构思和体验:
  当初设想, 是做一个简单的H5游戏, 可在移动端运行. 而且入手简单, 一看即会. 但不知道做啥好? 后来看到微信朋友中有人以背身投篮照作为头像, 觉得很向上又美好. 于是想到, 是不是做个简单的定点投篮游戏呢?
  说干就干, 因为有类似的投篮游戏App可供参考, 游戏创意不需要自己来构思, 因此算是一个模仿实现之作.
  
  在线体验的游戏链接: 定点投篮游戏. (点我呀, 点我呀, ^_^!)

模型抽象:
  游戏的主场景, 由篮板, 篮框, 篮球和地面组成. 篮球需投进篮框才能得分. 辅助线用于瞄准和定位, 简单触发即可投篮.
  由于是2维场景, 同时涉及到简单物理碰撞和处理. 但还是决定杀鸡用牛刀------使用box2d来构建物理模型. box2d是对真实物理世界的模拟, 其谐调单位为米-千克-秒(MKS), 因此使用真实的数据去设定大小即可, 只要设定好与像素的对应缩放系数即可.
  为了体现"专业性", 特地参考了真实篮球场的尺寸参数.
  
  我们设定如下参数: 篮板高1.05米, 篮球半径为0.123米, 篮框中心半径为0.19米(比真实要小一些). 用尽量真实的数据, 在物理世界中模拟.
  篮板是个静态刚体, 忽略其宽长, 简单设定为一条竖直的边.

// *) 创建篮板
var bodyDef = new b2BodyDef;
bodyDef.type = b2Body.b2_staticBody; var fixDef = new b2FixtureDef;
fixDef.shape = new b2PolygonShape;
fixDef.shape.SetAsEdge(
  new b2Vec2(1, 3),
  new b2Vec2(1, 4.05)
);
fixDef.restitution = 1;
world.CreateBody(bodyDef).CreateFixture(fixDef);

  篮框的设定, 所见非所得, 其用了个很trick的方法. 它的圆框在物理世界中, 并不存在, 其所拥有的就两个点: 左框点和右框点.
  

var bodyDef = new b2BodyDef;
var fixDef = new b2FixtureDef;
bodyDef.type = b2Body.b2_staticBody; // 左框点
bodyDef.position.x = 1.09;
bodyDef.position.y = 3.05;
fixDef.shape = new b2CircleShape(0.01);
world.CreateBody(bodyDef).CreateFixture(fixDef); // 右框点
bodyDef.position.x = 1.5;
bodyDef.position.y = 3.05;
fixDef.shape = new b2CircleShape(0.01);
world.CreateBody(bodyDef).CreateFixture(fixDef);

  篮球是个球体, 其实动态刚体.

var bodyDef = new b2BodyDef();
bodyDef.type = b2Body.b2_dynamicBody; var fixDef = new b2FixtureDef;
fixDef.density = 1.5;
fixDef.shape = new b2CircleShape(0.123);
world.CreateBody(bodyDef).CreateFixture(fixDef);

核心算法:
  除了物理引擎本身的以外, 还有两个重要的核心要点. 一个是辅助抛物线, 另一个是篮球判进算法.
  • 辅助抛物线
  有人曾评论到, 为何"愤怒的小鸟"火极一时, 是因为人们对"抛物线"的痴迷. 因此辅助抛物线也成了这个游戏本身的核心要点. 辅助抛物线, 隐藏了投篮的角度和力量设定, 使得游戏非常容易入手. 其采用模拟描点法来进行绘制. 而不是反过来算的抛物线方程, 再来计算轨道点.

var dt = 0.62;
for (var i = 0; i < dlevel; i++) {
  var tx = spx * dt * i + this.posx * scaleFactor;
  var ty = spy * dt * i - 0.5 * gavity * dt * dt * i * i + this.posy * scaleFactor;
  this.tracklines[i].drawCircle(cc.p(tx, ty), 2, cc.degreesToRadians(180), 100, false, cc.color(0, 0, 0, 255));
}

  注: 由物理公式得: Sx = Vx * t, Sy = Vy * t + 1/2 * a * t^2; Vx, Vy由投掷点决定.
  • 篮球判进判定算法
  问题的本质就是如何判定篮球球心通过球框的直径线段? 这个问题, 可以稍作变换. 记录运动篮球的前后两个时间点的圆心位置, 若该两个点构成的线段, 与 蓝框直径构成的线段相交. 则认为篮球球心过了直径线段. 即进球了.
  所以问题最终演化为, 求解两个线段相交的判断问题了?
  
  具体算法, 可参见如下博文: 判断两线段是否相交. 引入了快速测试跨立试验这两个阶段.
  这边的大致算法代码描述如下:

collideWith:function(ball) {
  // *)
  var px1 = ball.prevposx;
  var py1 = ball.prevposy;
  var px2 = ball.posx;
  var py2 = ball.posy;   var qx1 = 1.1, qx2 = 1.5;
  var qy1 = 3.05, qy2 = 3.05;   // *) 快速测试,
  if (!(Math.min(px1, px2) <= Math.max(qx1, qx2)
      && Math.min(qx1, qx2) <= Math.max(px1, px2)
      && Math.min(py1, py2) <= Math.max(qy1, qy2)
      && Math.min(qy1, qy2) <= Math.max(py1, py2))) {
    return false;
  }   // *) 交叉判定
  var d1 = (px1 - qx1) * (qy2 - qy1) - (qx2 - qx1) * (py1 - qy1);
  var d2 = (px2 - qx1) * (qy2 - qy1) - (qx2 - qx1) * (py2 - qy1);
  
  var d3 = (qx1 - px1) * (py2 - py1) - (px2 - px1) * (qy1 - py1);
  var d4 = (qx2 - px1) * (py2 - py1) - (px2 - px1) * (qy2 - py1);   if (d1 * d2 < 0 && d3 * d4 < 0) {
    return true;
  } else if ( d1 == 0 && this.isOnSegline(qx1, qy1, qx2, qy2, px1, py1) ) {
    return true;
  } else if ( d2 == 0 && this.isOnSegline(qx1, qy1, qx2, qy2, px2, py2) ) {
    return true;
  } else if ( d3 == 0 && this.isOnSegline(px1, py1, px2, py2, qx1, qy1) ) {
    return true;
  } else if ( d4 == 0 && this.isOnSegline(px1, py1, px2, py2, qx2, qy2) ) {
    return true;
  }
  return false;
},
isOnSegline: function(px1, py1, px2, py2, px3,py3) {
  var minx = Math.min(px1, px2);
  var maxx = Math.max(px1, px2);
  var miny = Math.min(py1, py2);
  var maxy = Math.max(py1, py2);
  return px3 >= minx && px3 <= maxx && py3 >= miny && py3 <= maxy;
}

总结:
  朋友玩了一把, 吐槽不少, 不过还是很开心, 能体验就是种肯定. 后期一定好好再改善一把, 使得其用户体验上, 更加友好.

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

  

公众号&游戏站点:
  个人微信公众号: 木目的H5游戏世界
  

H5版定点投篮游戏(1)--物理模型抽象的更多相关文章

  1. H5版俄罗斯方块(2)---游戏的基本框架和实现

    前言: 上文中谈到了H5版俄罗斯方块的需求和目标, 这次要实现一个可玩的版本. 但饭要一口一口吃, 很多东西并非一蹴而就. 本文将简单实现一个可玩的俄罗斯方块版本. 下一步会引入AI, 最终采用coc ...

  2. Swift版iOS游戏框架Sprite Kit基础教程下册

    Swift版iOS游戏框架Sprite Kit基础教程下册 试读下载地址:http://pan.baidu.com/s/1qWBdV0C 介绍:本教程是国内唯一的Swift版的Spritekit教程. ...

  3. android版猜拳游戏源码分享

    android版猜拳游戏源码分享安卓版猜拳游戏源码,该文件中带有安装测试包的,这个游戏源码比较简单的,现在有两个代码,一个自定义VIEW的,一个就是普通的imageView图片,游戏非常适合一些新手的 ...

  4. 《Genesis-3D开源游戏引擎--横版格斗游戏制作教程:简介及目录》(附上完整工程文件)

    介绍:讲述如何使用Genesis-3D来制作一个横版格斗游戏,涉及如何制作连招系统,如何使用包围盒实现碰撞检测,软键盘的制作,场景切换,技能读表,简单怪物AI等等,并为您提供这个框架的全套资源,源码以 ...

  5. 一个用 C 语言写的迷你版 2048 游戏,仅仅有 500个字符

    Jay Chan 用 C 语言写的一个迷你版 2048 游戏,仅仅有 487 个字符. 来围观吧 M[16],X=16,W,k;main(){T(system("stty cbreak&qu ...

  6. 亲历H5移动端游戏微信支付接入及那些坑(二)——获取Openid和授权

    第一篇中将一些坑说明,那么这篇开始正式进入接入步骤.具体的参数说明,我不会列出,毕竟微信官方文档都有,我想大家都看的懂,而且这接口也有可能微信会变动,所以不列出来,也是不想引起大家的误解,接入步骤只起 ...

  7. 简易2D横版RPG游戏制作

    Unity学习笔记1 简易2D横版RPG游戏制作 http://m.blog.csdn.net/article/details?id=24601905

  8. Cocos2d-x 3.x版2048游戏开发

    Cocos2d-x 3.x版2048游戏开发 本篇博客给大家介绍怎样高速开发2048这样一款休闲游戏,理解整个2048游戏的开发流程.从本篇博客你将能够学习到下面内容: 这里注明一下,本教程来自极客学 ...

  9. 相当牛X的java版星际游戏

    分享一款牛人用java写的经典游戏,目录结构如下: 虽然只能算一个Demo,但是用到了很多Java基础技术和算法: Java2D,双缓冲,A星寻路,粒子系统,动画效果,处理图片,Swing ui ,U ...

随机推荐

  1. linux下启动AP热点时出错

    1.启动hostapd,在终端下输入sudo ./hostapd hostapd.conf (注意:使用到的hostapd和hostapd.conf都处在当前工作目录下) 1.2.在执行1之后会出现以 ...

  2. XDocument 获取包括第一行的声明(版本、编码)的所有节点

    XDocument保存为xml文件的方法如下: XDocument doc = new XDocument( new XDeclaration("1.0","UTF-8& ...

  3. iOS开发 Masonry的简单使用

    首先,在正式使用Masonry之前,我们先来看看在xib中我们是如何使用AutoLayout     从图中我们可以看出,只要设置相应得局限,控制好父视图与子视图之间的关系就应该很ok的拖出你需要的需 ...

  4. zabbix3.0.4 部署之二 (Centos6.5系统准备)

    1.安装Centos6.5  2.6.32-642.4.2.el6.x86_64 升级所有软件至最新: yum update 2.同步时间.安装ntpd yum  install ntpddate n ...

  5. h.SSL协议栈整体分解

    1.SSL整体框图 SSL协议是应用层次(http协议)和TCP层级的一个可选的位置,可以从下面的图中非常清楚看到该层次: 绿色的框图就是这个SSL./TLS的位置,最右面的SSL/TLS图可以进一步 ...

  6. Objective-C( Category 分类,非正式协议,分类延展)

    分类: 主要是给原来类增加一些方法;不可以增加成员变量 Person (Person+eat) 非正式协议: 非正式协议就是类别,即凡是NSObject或其子类Foundation框架中的类增加的类别 ...

  7. 第十二章 非对称加密算法-RSA

    注意:本节内容主要参考自<Java加密与解密的艺术(第2版)>第8章“高等加密算法--非对称加密算法” 12.1.RSA(最经典的非对称加密算法) 特点: 使用一套密钥即可完成加解密(与D ...

  8. JAVA 十六进制与字符串的转换

    public static String toHexString(int i)以十六进制的无符号整数形式返回一个整数参数的字符串表示形式.如果参数为负,那么无符号整数值为参数加上 232:否则等于该参 ...

  9. $('div','li'),$('div , li'),$('div li')的区别

    要搞清楚$('div','li') 和 $('div , li') 和 $('div li') 区别: $('div','li'):是$(子,父),是从父节点里找子,而不是找li外面的div $('d ...

  10. [双连通分量] POJ 3177 Redundant Paths

    Redundant Paths Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 13712   Accepted: 5821 ...