自上一章公布到如今已时隔四月,实在对不住大家。让大家久等了~话说不是我不关注我的博客,而是事情一多起来写博客的时间就少了。

待到今日有空了,回头看了看自己曾经写的文章,猛得发现已经四个月不曾写文章了。便仅仅得叫声:“苦也~”,我害怕本系列文章会拖得更久,于是立马提笔,也好为本系列文章留个凤尾。

首先,大家来温习一下前面两篇里的内容吧:

HTML5物理游戏开发 - 越野山地自行车(二)创建一辆可操控的自行车

http://blog.csdn.net/yorhomwang/article/details/21300253

HTML5物理游戏开发 - 越野山地自行车(一)建立各式各样的地形

http://blog.csdn.net/yorhomwang/article/details/19710537

今天我们要实现的内容就是——当我们自行车的关键部分碰壁后。立马使其粉碎,通俗点讲就是“自行车碎一地”。Ok。闲话何苦多说呢,我们就開始咯~

先放上两张截图吧:

※再次声明,本次开发用到了lufylegend.js开源html5游戏引擎和box2dweb物理引擎,请到官方站点下载使用。官方站点地址已在第一章中说过了。

一,粉碎原理

用过锤子的人都知道(假设你没用过,并且也不知道怎么用,建议你去问问雷神索尔)。要砸碎一个自行车该怎么砸呢?假设你不会,我教你三招吧:

法一:使劲砸;这样的方法适用于你想换把锤子

法二:到阿斯嘉找雷神大哥去。这个速率最快,预计不到抽完一根烟的工夫,你的自行车就仅仅剩原子了

法三:去某个地方把锤子换成螺丝刀等工具。然后把你那自行车零件一块一块地给卸下来

显然。这三种方法各有所长。只是既然我们的自行车是一块一块地拼起来的,那么还是一块一块地给拆了好,于是,我选择了3(实际上是由于Box2dWeb没有锤子这玩意。也认不得雷神)。我们在上一章中提到过怎样把零件拼起来,原理是运用了Box2dWeb里的关节,这些关节把零件们连在了一起,那么假设这些关节一销毁,那么这些零件就会散落。但是怎样销毁关节呢?Box2dWeb的b2World里有一个DestroyJoint函数,參数就是你要销毁的b2Joint对象。我们来看看在lufylegend里怎样销毁关节吧。

首先,在lufylegend里通过LBox2d关键关节的函数都会返回创建出的b2Joint对象,也就是说:

var j = LStage.box2d.setRevoluteJoint(a.box2dBody, b.box2dBody);
LStage.box2d.world.DestroyJoint(j);

我们能够把调用setRevoluteJoint创建出的旋转关节保存在变量j里,然后销毁时就直接调用LStage.box2d.world.DestroyJoint函数,參数则是j。

假设我们有多个关节怎么办呢?放数组里呗,想必聪明的你在我说这话之前就已经想到了这点吧。
原理搞定。那么我们開始看代码吧。

二。更新自行车类和Main类

上一章中我们着重讲了怎样实现自行车类,这次由于要粉碎它,所以要先在它身上动手术。安放几个炸弹再说。装炸弹前要做好准备,以免把自己给炸over了,所以得先搞个盒子把要炸毁的地方装起来。恰巧Main类路过(关于Main请看第一章),我把它一手提了过来。唱声喏。道:“阁下暂且替我装两个东西,怎样?”,Main类寻思道:“这厮能够掌管全部程序。万一这厮火了。一把delete把我等删个干净却不是个好事。

”,于是他无可奈何地替我担负了这个重任。却说看官欲知是哪两个东西呢?原来是一个名叫jointList的数组和一个唤作gameOverController的bool型变量;这两厮一个管装全部生成的关节,一个管游戏是否结束。

于是Main的构造器改造后例如以下:

function Main(){var s = this;base(s,LSprite,[]);/**设置场景大小*/s.sceneWidth = 8500;s.sceneHeight = LStage.height+1000;/**关节列表*/s.jointList = new Array();/**游戏结束控制器*/s.gameOverController = false;
}

却说上面那段明显有些水浒的风格。不好意思。最近《水浒传》看多了,望各位包括包括。

我们知道。炸弹都是要有点火线的。或者更高级一点的开关啊,反正就是一个引爆装置,这个工作还是交给Main吧。改动Main的init方法:

Main.prototype.init = function(){var s = this;/**增加边框*/s.addBorder();/**增加路面*/s.addRoad();/**增加自行车*/s.addBicycle();/**增加刚体碰撞事件*/LStage.box2d.setEvent(LEvent.POST_SOLVE,s.postSolve);/**增加循环事件*/s.addEventListener(LEvent.ENTER_FRAME,s.loop);
};

主要是加了个调用LStage.box2d.setEvent函数。这个函数是LBox2d类的一个方法(LStage.box2d是LBox2d的实例化对象),详细的用法是这样子滴:

■setEvent(type, func)

參数介绍:

type box2d世界里的碰撞事件类型

func 触发事件时调度的函数

碰撞事件的类型能够为:

LEvent.BEGIN_CONTACT:刚刚碰撞開始的时候会触发这个函数
LEvent.END_CONTACT:碰撞结束的时候会触发这个函数
LEvent.POST_SOLVE:碰撞后会处理这个函数
LEvent.PRE_SOLVE:碰撞前即将碰撞的时候

这里我们选的是POST_SOLVE,也就是碰撞后会处理这个函数,事实上选择其它的事件类型,效果也应该是一样的。

事件触发时调度的函数是postSolve,这个函数也交给Main吧~ [Main类:说好的装两个呢(T_T)]

Main.prototype.postSolve = function(contact){if(world.gameOverController)return;var l = world.jointList;if(l.length == 0)return;//获取碰撞的LSprite对象var cA = contact.GetFixtureA().GetBody().GetUserData();var cB = contact.GetFixtureB().GetBody().GetUserData();//推断是否摧毁自行车if(//--------------------------------------------//条件一:当自行车和墙碰撞时//--------------------------------------------((cA.name=="wall" && cB.name=="bicycle")||(cA.name=="bicycle" && cB.name=="wall"))||//--------------------------------------------//条件二:当自行车的车把、车把到轮子的支架或者车座碰到其它物体时//--------------------------------------------((cA.trigger=="destroy_bicycle" && cB.name!="bicycle")||(cA.name!="bicycle" && cB.trigger=="destroy_bicycle"))){//去掉自行车上的全部关节以达到催毁自行车for(var i in l){var jo = l[i];//去掉关节LStage.box2d.world.DestroyJoint(jo);//将游戏结束控制器设置为游戏结束world.gameOverController = true;}//从自行车关节列表中移除全部关节l.length = 0;//增加游戏结束提示var gameOverText = new LTextField();gameOverText.text = "Game Over";gameOverText.size = 50;gameOverText.alpha = 0;gameOverText.x = (LStage.width-gameOverText.getWidth())*0.5;gameOverText.y = (LStage.height-gameOverText.getHeight())*0.5;addChild(gameOverText);LTweenLite.to(gameOverText,5,{delay:1.5,alpha:1});}
};

该函数会接受一个參数。參数是个啥对象呢?事实上我也不清楚,反正里面有GetFixtureA和GetFixtureB这两个函数。这两个函数能取到正在碰撞的刚体的刚形,通过刚形的GetBody取到b2Body对象,然后用b2Body的GetUserData取到终于的LSprite对象。

參数介绍完了,我还是来介绍一下这个函数的执行逻辑吧。首先,假设游戏已经结束或者jointList为空的数组,则不再执行后面的代码。假设继续执行代码,则首先把碰撞的两个刚体所在的LSprite取出来。然后进行游戏结束推断。假设通过则执行游戏结束的代码。

有人或许纳闷那个world是个啥?假设你从第一章看起,就应该会明确了。主要是postSolve是个回调函数。里面的this不是指向Main的。

在那个长达19行的推断条件里。我设定了两个条件,满足这两个条件之中的一个,便进行销毁关节:条件一:当自行车和墙碰撞时;条件二:当自行车的车把、车把到轮子的支架或者车座碰到其它物体时。

销毁部分的代码主要是注意,在box2d里,销毁关节用DestroyJoint这个函数,这一点在“粉碎原理”中就已经提到过了,这个函数是在b2World类中的,LBox2d的world属性就是b2World的实例化对象。

能不能结束游戏关键要看碰撞的b2Body所在的LSprite对象的name和trigger(英文翻译过来是“触发器”的意思),这些属性在哪里设置的呢?当然是在构造自行车的类Bicycle类里呢。接下来就来看看Bicycle类里增加&改进的代码。

首先来看Bicycle的init函数的变化:

Bicycle.prototype.init = function(){var s = this;var sx = s.sx;var sy = s.sy; /**轮子半径*/var wheelR = 20;/**轮子之间的距离*/var gapBetweenWheelAndWheel = 100;/**车手柄到轮子的距离*/var gapBetweenWheelAndHandlebar = 50;/**车把尺寸*/var handlebarWidth=20,handlebarHeight=5;/**座椅到轮子支架的距离*/var gapBetweenWheelFrameAndSeat = 30;/**座椅尺寸*/var seatWidth=30,seatHeight=5;/**支架尺寸*/var frameSize = 10;/**增加支架*///轮子上的支架var frameAObj = new LSprite();frameAObj.x = sx+gapBetweenWheelAndWheel/2;frameAObj.y = sy+frameSize/2;frameAObj.addBodyPolygon(gapBetweenWheelAndWheel,frameSize,1,5);world.addChild(frameAObj);s.bodyList.push(frameAObj);//车把到轮子的支架var frameBObj = new LSprite();frameBObj.trigger = "destroy_bicycle";frameBObj.x = sx+gapBetweenWheelAndWheel-frameSize/2;frameBObj.y = sy-gapBetweenWheelAndHandlebar/2;frameBObj.addBodyPolygon(frameSize,gapBetweenWheelAndHandlebar,1,2);world.addChild(frameBObj);s.bodyList.push(frameBObj);/**增加车把*/var handlebarObj = new LSprite();handlebarObj.trigger = "destroy_bicycle";handlebarObj.x = sx+gapBetweenWheelAndWheel-handlebarWidth/2-frameSize;handlebarObj.y = sy-gapBetweenWheelAndHandlebar+handlebarHeight/2;handlebarObj.addBodyPolygon(handlebarWidth,handlebarHeight,1,.5);world.addChild(handlebarObj);s.bodyList.push(handlebarObj);/**增加座椅*///座椅到轮子支架的支架var seatFrameObj = new LSprite();seatFrameObj.x = sx+30;seatFrameObj.y = sy-gapBetweenWheelFrameAndSeat/2;seatFrameObj.addBodyPolygon(frameSize,gapBetweenWheelFrameAndSeat,1,1);world.addChild(seatFrameObj);s.bodyList.push(seatFrameObj);//座椅var seatObj = new LSprite();seatObj.trigger = "destroy_bicycle";seatObj.x = sx+30;seatObj.y = sy-gapBetweenWheelFrameAndSeat-seatHeight/2;seatObj.addBodyPolygon(seatWidth,seatHeight,1,.5);world.addChild(seatObj);s.bodyList.push(seatObj);/**增加轮子*///左边轮子Avar wheelAObj = new LSprite();wheelAObj.x = sx-wheelR;wheelAObj.y = sy;wheelAObj.addBodyCircle(wheelR,wheelR,wheelR,1,2.5,.2,.4);world.addChild(wheelAObj);s.bodyList.push(wheelAObj);//右边轮子Bvar wheelBObj = new LSprite();wheelBObj.x = sx+gapBetweenWheelAndWheel-wheelR;wheelBObj.y = sy;wheelBObj.addBodyCircle(wheelR,wheelR,wheelR,1,2.5,.2,.4);world.addChild(wheelBObj);s.bodyList.push(wheelBObj);/**增加关节*///轮子A和轮子支架的旋转关节world.jointList.push(LStage.box2d.setRevoluteJoint(frameAObj.box2dBody, wheelAObj.box2dBody));//轮子B和轮子支架的旋转关节world.jointList.push(LStage.box2d.setRevoluteJoint(frameAObj.box2dBody, wheelBObj.box2dBody));//车把到轮子的支架和轮子支架的焊接关节world.jointList.push(LStage.box2d.setWeldJoint(frameAObj.box2dBody, frameBObj.box2dBody));//车把到轮子的支架和车把的焊接关节world.jointList.push(LStage.box2d.setWeldJoint(handlebarObj.box2dBody, frameBObj.box2dBody));//轮子的支架和座椅的焊接关节world.jointList.push(LStage.box2d.setWeldJoint(seatFrameObj.box2dBody, frameAObj.box2dBody));//座椅的支架和座椅的焊接关节world.jointList.push(LStage.box2d.setWeldJoint(seatFrameObj.box2dBody, seatObj.box2dBody));/**遍历全部自行车零件刚体*/for(var key in s.bodyList){var obj = s.bodyList[key];//增加鼠标拖动if(obj.box2dBody)obj.setBodyMouseJoint(true);//设置对象名称obj.name = "bicycle";}/**设置主刚体*/s.mainBody = frameAObj.box2dBody;/**设置拉压操作刚体*/s.tcBody = wheelBObj.box2dBody;
};

主要改的是这里:

/**增加关节*/
//轮子A和轮子支架的旋转关节
world.jointList.push(LStage.box2d.setRevoluteJoint(frameAObj.box2dBody, wheelAObj.box2dBody));
//轮子B和轮子支架的旋转关节
world.jointList.push(LStage.box2d.setRevoluteJoint(frameAObj.box2dBody, wheelBObj.box2dBody));
//车把到轮子的支架和轮子支架的焊接关节
world.jointList.push(LStage.box2d.setWeldJoint(frameAObj.box2dBody, frameBObj.box2dBody));
//车把到轮子的支架和车把的焊接关节
world.jointList.push(LStage.box2d.setWeldJoint(handlebarObj.box2dBody, frameBObj.box2dBody));
//轮子的支架和座椅的焊接关节
world.jointList.push(LStage.box2d.setWeldJoint(seatFrameObj.box2dBody, frameAObj.box2dBody));
//座椅的支架和座椅的焊接关节
world.jointList.push(LStage.box2d.setWeldJoint(seatFrameObj.box2dBody, seatObj.box2dBody));

我把全部的关节都增加到wolrd的jointList里了,这样一来我们就能够通过遍历取出关节来,然后进行销毁,这一点在Main的postSolve里就已经实现了。

还有改动的就是:1。给全部的属于自行车的刚体都加了一个name属性,设定为:“bicycle”。2。给关键部位的刚体(车把、车把到轮子的支架和车座)加了trigger属性,设置为“destroy_bicycle”。表示假设这些部位碰到了其它不属于自行车的刚体,就结束游戏。

至于name为"wall"的刚体事实上就仅仅有一个(bottomBorder底部边框。促使自行车跌究竟部时结束游戏):

Main.prototype.addBorder = function(){var s = this;/**创建边框*///设置边框尺寸var borderSize = 10;//顶部边框var topBorder = new LSprite();topBorder.x = s.sceneWidth/2;topBorder.y = 5;topBorder.addBodyPolygon(s.sceneWidth,borderSize,0);s.addChild(topBorder);//右部边框var rightBorder = new LSprite();rightBorder.x = s.sceneWidth-5;rightBorder.y = s.sceneHeight/2;rightBorder.addBodyPolygon(borderSize,s.sceneHeight,0);s.addChild(rightBorder);//底部边框var bottomBorder = new LSprite();bottomBorder.name = "wall";bottomBorder.x = s.sceneWidth/2;bottomBorder.y = s.sceneHeight-5;bottomBorder.addBodyPolygon(s.sceneWidth,borderSize,0);s.addChild(bottomBorder);//左部边框var leftBorder = new LSprite();leftBorder.x = 5;leftBorder.y = s.sceneHeight/2;leftBorder.addBodyPolygon(borderSize,s.sceneHeight,0);s.addChild(leftBorder);
};

Ok,执行代码,得到的就是本文最上方图片所看到的的效果了。

奉上源码下载地址:http://files.cnblogs.com/yorhom/box2dBicycle%283%29.rar

測试地址:http://yuehaowang.github.io/demo/ridebike_box2d/

本系列教程就到此为止了,事实上假设要做一个真正的“越野山地自行车”这样的游戏,还须要对刚体进行贴图,胜利推断等。这些都非常easy,大家能够自己动手做一做吧~(眼下我做的demo应该能够当作一种发泄工具吧,压力大了,就来把这辆虚拟的自行车拿来狠狠地摔吧~ 哈哈)

还有同学(这会儿但是真正意义上的同学了...)问我怎样操作,好吧。算我失误。没有在本章告诉大家(事实上你看了第两章就会知道的),在这里补充一下。

操作说明:上下左右键操作,至于这些按键相应的效果就自己摸索吧,实在总结不出来就去第二章慢慢找吧,我也就偷个懒吧~

本章就先到这里了。假设文章有不论什么疏漏之处,欢迎指正。当然,有不懂之处也欢迎各位在本文下方留言。我会尽力回复大家的。

----------------------------------------------------------------

欢迎大家转载我的文章。

转载请注明:转自Yorhom's Game Box

http://blog.csdn.net/yorhomwang

欢迎继续关注我的博客

HTML5物理游戏开发 - 越野山地自行车(三)粉碎自行车相关推荐

  1. HTML5物理游戏开发 - 越野山地自行车(二)创建一辆可操控的自行车

    第二章又拖到现在才发布,话说本次更新离上次已经很久了.不知道大家还记得上一章讲的内容否? 在上一章中,我们创建了各式各样的地形,今天我们就在这个地形之上,创建一辆自行车,并让它受到我们的控制.首先放上 ...

  2. Html5 Egret游戏开发 成语大挑战(三)开始界面

    Html5 Egret游戏开发 成语大挑战(三)开始界面 本篇需要在前面的素材准备完毕,才可以开始,使用egret的eui结合代码编辑,快速完成基本的界面搭建,这里写的可能比较细,目的是减少大家对于其 ...

  3. HTML5 Canvas游戏开发实战 PDF扫描版

    HTML5 Canvas游戏开发实战主要讲解使用HTML5 Canvas来开发和设计各类常见游戏的思路和技巧,在介绍HTML5 Canvas相关特性的同时,还通过游戏开发实例深入剖析了其内在原理,让读 ...

  4. Html5 Egret游戏开发 成语大挑战(一)开篇

    最近接触了Egret白鹭引擎,感觉非常好用,提供了各种各样的开发工具让开发者和设计者更加便捷,并且基于typescript语言开发省去了很多学习成本,对于我们这种掉微软坑许久的童鞋来说,确实很有吸引力 ...

  5. Html5 Egret游戏开发 成语大挑战(二)干净的eui项目和资源准备

    Html5 Egret游戏开发 成语大挑战(二)干净的eui项目和资源准备 现在我们使用egret来起步开发一个名叫<成语大挑战>的小游戏,关于egret的开发环境就不在这里啰嗦了,直接去 ...

  6. 《HTML5完美游戏开发》——1.2 为什么要关注Open Web Game

    本节书摘来自异步社区<HTML5完美游戏开发>一书中的第1章,第1.2节,作者: [白]Egor Kuryanovich , 等 更多章节内容可以访问云栖社区"异步社区" ...

  7. 《HTML5 Canvas游戏开发实战》——2.1 绘制基本图形

    本节书摘来自华章计算机<HTML5 Canvas游戏开发实战>一书中的第2章,第2.1节,作者:张路斌著, 更多章节内容可以访问云栖社区"华章计算机"公众号查看. 2. ...

  8. Html5 Egret游戏开发 成语大挑战(五)界面切换和数据处理

    Html5 Egret游戏开发 成语大挑战(五)界面切换和数据处理 经过前面的制作,使用Egret的Wing很快完成了开始界面和选关卡界面,下面通常来说就是游戏界面,但此时界面切换和关卡数据还没有准备 ...

  9. 《MFC游戏开发》笔记三 游戏贴图与透明特效的实现

    本系列文章由七十一雾央编写,转载请注明出处. http://blog.csdn.net/u011371356/article/details/9313239 作者:七十一雾央 新浪微博:http:// ...

最新文章

  1. 对象的创建、内存布局和访问定位
  2. 分布式文件系统Hadoop
  3. linux内核网络协议栈--kernel bridge转发逻辑(十一)
  4. js在客户端创建文件——ActiveXObject
  5. 潜水员(信息学奥赛一本通-T1271)
  6. LNMP--Nginx代理详解
  7. 大数据分析常见的几种方法
  8. DsoFramer2
  9. 三大框架 —— 持久层框架MyBatis
  10. ECharts 简明教程,用js输出图表
  11. 流媒体视频网络 Tout 获 2600 万美元 C 轮融资
  12. php redis统计在线人数,每天活跃度
  13. python 用cx_Freeze打包程序详细解读setup.py
  14. 【无标题】上班族做什么副业赚钱?4种副业让你超过主业!
  15. 基于微信校园跑腿小程序系统设计与实现 开题报告
  16. 思岚科技定位导航技术凸显 成为服务机器人企业首选品牌
  17. 非煤矿山生产安全事故应急预案
  18. 调试SQL SERVER存储过程
  19. js制作12进制的时钟特效
  20. 教你怎样煮鸡蛋 煮软蛋 煮溏心蛋

热门文章

  1. WPF Demo20 模板
  2. 如何获取客户端MAC地址(三个方法)
  3. HDU 4115 Eliminate the Conflict【2011 ACM Asia Chengdu Regional Problem E】
  4. oem718d 基准站设置_诺瓦泰NovAtel OEM718D全系统多频单机测向板卡
  5. c语言三种循环语句,C语言三种循环语句的功能等价性
  6. 与计算机专业相关的英语科普短文,英语科普文选-中英文对照(计算机.doc
  7. linux安装软件imagemagick,Linux系统中怎么安装和使用ImageMagick软件?
  8. 程序员操作系统推荐_程序员的这些问题,竟然在工作后才发现!
  9. python 多线程 异步_python 多线程异步
  10. 缺失数据em算法python_EM算法