游戏开发论坛

 找回密码
 立即注册
搜索
查看: 9239|回复: 1

H5版定点投篮游戏编程设计--物理模型抽象

[复制链接]

1万

主题

1万

帖子

3万

积分

论坛元老

Rank: 8Rank: 8

积分
36572
发表于 2016-4-25 17:54:08 | 显示全部楼层 |阅读模式
QQ截图20160425175159.jpg

  GameRes游资网授权发布 文/mumuxinfei

  本文将讲述一下定点投篮游戏的编写, 主要阐述其物理模型的抽象, 后续慢慢的完善和迭代。

  构思和体验:

  当初设想, 是做一个简单的H5游戏, 可在移动端运行。 而且入手简单, 一看即会。 但不知道做啥好? 后来看到微信朋友中有人以背身投篮照作为头像, 觉得很向上又美好。 于是想到, 是不是做个简单的定点投篮游戏呢?

  说干就干, 因为有类似的投篮游戏App可供参考, 游戏创意不需要自己来构思, 因此算是一个模仿实现之作。

1.png

  在线体验的游戏链接: 定点投篮游戏。 (点我呀, 点我呀, ^_^!)模型抽象:

  游戏的主场景, 由篮板, 篮框, 篮球和地面组成。 篮球需投进篮框才能得分。 辅助线用于瞄准和定位, 简单触发即可投篮。

  由于是2维场景, 同时涉及到简单物理碰撞和处理。 但还是决定杀鸡用牛刀------使用box2d来构建物理模型。 box2d是对真实物理世界的模拟, 其谐调单位为米-千克-秒(MKS), 因此使用真实的数据去设定大小即可, 只要设定好与像素的对应缩放系数即可。

  为了体现"专业性", 特地参考了真实篮球场的尺寸参数。

2.png

  我们设定如下参数: 篮板高1。05米, 篮球半径为0。123米, 篮框中心半径为0。19米(比真实要小一些)。 用尽量真实的数据, 在物理世界中模拟。

  篮板是个静态刚体, 忽略其宽长, 简单设定为一条竖直的边。

  1. // *) 创建篮板
  2. var bodyDef = new b2BodyDef;
  3. bodyDef.type = b2Body.b2_staticBody;

  4. var fixDef = new b2FixtureDef;
  5. fixDef.shape = new b2PolygonShape;
  6. fixDef.shape.SetAsEdge(
  7.   new b2Vec2(1, 3),
  8.   new b2Vec2(1, 4.05)
  9. );
  10. fixDef.restitution = 1;
  11. world.CreateBody(bodyDef).CreateFixture(fixDef);
复制代码

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

3.png

  1. var bodyDef = new b2BodyDef;
  2. var fixDef = new b2FixtureDef;
  3. bodyDef.type = b2Body.b2_staticBody;

  4. // 左框点
  5. bodyDef.position.x = 1.09;
  6. bodyDef.position.y = 3.05;
  7. fixDef.shape = new b2CircleShape(0.01);
  8. world.CreateBody(bodyDef).CreateFixture(fixDef);

  9. // 右框点
  10. bodyDef.position.x = 1.5;
  11. bodyDef.position.y = 3.05;
  12. fixDef.shape = new b2CircleShape(0.01);
  13. world.CreateBody(bodyDef).CreateFixture(fixDef);
复制代码

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

  1. var bodyDef = new b2BodyDef();
  2. bodyDef.type = b2Body.b2_dynamicBody;

  3. var fixDef = new b2FixtureDef;
  4. fixDef.density = 1.5;
  5. fixDef.shape = new b2CircleShape(0.123);
  6. world.CreateBody(bodyDef).CreateFixture(fixDef);
复制代码

  核心算法:

  除了物理引擎本身的以外, 还有两个重要的核心要点。 一个是辅助抛物线, 另一个是篮球判进算法。

  辅助抛物线

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

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

  注: 由物理公式得: Sx = Vx * t, Sy = Vy * t + 1/2 * a * t^2; Vx, Vy由投掷点决定。

  篮球判进判定算法

  问题的本质就是如何判定篮球球心通过球框的直径线段? 这个问题, 可以稍作变换。 记录运动篮球的前后两个时间点的圆心位置, 若该两个点构成的线段, 与 蓝框直径构成的线段相交。 则认为篮球球心过了直径线段。 即进球了。

  所以问题最终演化为, 求解两个线段相交的判断问题了?

4.png

  具体算法, 可参见如下博文: 判断两线段是否相交。 引入了快速测试和跨立试验这两个阶段。

  这边的大致算法代码描述如下:

  1. collideWith:function(ball) {
  2.   // *)
  3.   var px1 = ball.prevposx;
  4.   var py1 = ball.prevposy;
  5.   var px2 = ball.posx;
  6.   var py2 = ball.posy;

  7.   var qx1 = 1.1, qx2 = 1.5;
  8.   var qy1 = 3.05, qy2 = 3.05;

  9.   // *) 快速测试,
  10.   if (!(Math.min(px1, px2) <= Math.max(qx1, qx2)
  11.       && Math.min(qx1, qx2) <= Math.max(px1, px2)
  12.       && Math.min(py1, py2) <= Math.max(qy1, qy2)
  13.       && Math.min(qy1, qy2) <= Math.max(py1, py2))) {
  14.     return false;
  15.   }

  16.   // *) 交叉判定
  17.   var d1 = (px1 - qx1) * (qy2 - qy1) - (qx2 - qx1) * (py1 - qy1);
  18.   var d2 = (px2 - qx1) * (qy2 - qy1) - (qx2 - qx1) * (py2 - qy1);
  19.   
  20.   var d3 = (qx1 - px1) * (py2 - py1) - (px2 - px1) * (qy1 - py1);
  21.   var d4 = (qx2 - px1) * (py2 - py1) - (px2 - px1) * (qy2 - py1);

  22.   if (d1 * d2 < 0 && d3 * d4 < 0) {
  23.     return true;
  24.   } else if ( d1 == 0 && this.isOnSegline(qx1, qy1, qx2, qy2, px1, py1) ) {
  25.     return true;
  26.   } else if ( d2 == 0 && this.isOnSegline(qx1, qy1, qx2, qy2, px2, py2) ) {
  27.     return true;
  28.   } else if ( d3 == 0 && this.isOnSegline(px1, py1, px2, py2, qx1, qy1) ) {
  29.     return true;
  30.   } else if ( d4 == 0 && this.isOnSegline(px1, py1, px2, py2, qx2, qy2) ) {
  31.     return true;
  32.   }
  33.   return false;
  34. },
  35. isOnSegline: function(px1, py1, px2, py2, px3,py3) {
  36.   var minx = Math.min(px1, px2);
  37.   var maxx = Math.max(px1, px2);
  38.   var miny = Math.min(py1, py2);
  39.   var maxy = Math.max(py1, py2);
  40.   return px3 >= minx && px3 <= maxx && py3 >= miny && py3 <= maxy;
  41. }
复制代码

  总结:

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

  相关阅读:H5版俄罗斯方块游戏开发:需求分析和框架实现

2

主题

46

帖子

1270

积分

金牌会员

Rank: 6Rank: 6

积分
1270
发表于 2018-4-11 18:08:25 | 显示全部楼层
你这投篮不考虑角度因素的吗?
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

作品发布|文章投稿|广告合作|关于本站|游戏开发论坛 ( 闽ICP备17032699号-3 )

GMT+8, 2024-4-19 07:35

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表