首页 > 代码库 > 『HTML5挑战经典』是英雄就下100层-开源讲座(二)危险!英雄
『HTML5挑战经典』是英雄就下100层-开源讲座(二)危险!英雄
本篇为《『HTML5挑战经典』是英雄就下100层-开源讲座》第二篇,需要用到开源引擎lufylegend,可以到这里下载:
下载地址:http://lufylegend.googlecode.com/files/lufylegend-1.7.1.rar
API文档:http://lufylegend.com/lufylegend/api
却说我们的英雄能顺利地从天而降了,不过丝毫没有悬念,他一定会被摔死的,因为还没有跳板出现。我每次路过时都看到我们的英雄是边下降边大叫:help! help!然后就摔死了。怪可怜的,于是我今天便完善了一下游戏,也好让我们的英雄活动活动筋骨。
这一次我们来实现不断上升的跳板。如果你想了解了解上一讲的内容,可以点击以下地址:
『HTML5挑战经典』是英雄就下100层-开源讲座(一)从天而降的英雄
http://blog.csdn.net/yorhomwang/article/details/8764748
一,加入跳板
首先,我们要几张图片:
跳板(一):
跳板(二):
由于在下素材不足,就只好先搞了两个主要的跳板。说到素材,我们的英雄便有话说了:“我本是Yorhom帐下一小卒,不想人长帅了点,被强征去当英雄,还不给我跳板踩,害得我摔死几回!本想摔死了投胎成一个程序员,这样就可以把Yorhom拉去当英雄,然后让他尝尝摔死的滋味。不想万恶的浏览器加了缓存,害得在下摔死了又投胎成英雄,然后又接着摔死!!苦哉苦哉。。。”
我听了他的话心中只有一句话想说:”投胎和缓存有多大关系?小卒果真就是没文化,只有干替死这一行了。。。“
我们的英雄悲伤地哭了。。。算了不管他,我们继续学习游戏开发,哈!
回入正题,我们有了图片接着上代码,首先是一些变量:
var hitStage = false; var stageSpeed = 5; //是否已经扣血变量 var isCutHp = false;
hitStage是用来检测是否碰撞,如果是就改为true。stageSpeed是跳板下降速度。isCutHp是判断是否已经扣血,每当英雄落到有钉子的跳板上时,我们就给英雄扣血,但因为我们的页面是不断刷新的,所以每当一扣血就会一次性地扣完,所以给它一个变量,控制页面刷新时是否让英雄扣血。这里只提一下,减血等留到后面讲。
接着是跳板Stage类构造器代码:
/** *Stage障碍物类 */ function Stage(speed,data){ base(this,LSprite,[]); var self = this; //取出一个整数,使0<=index<=10成立 var index = Math.floor(Math.random()*10); var bitmapIndex; if(index == 0){ bitmapIndex = 1; }else{ bitmapIndex = 0; } //将index的值取出对应的图片 var bitmap = new LBitmap(new LBitmapData(imglist["stage"+bitmapIndex])); //定义障碍物的模式 self.mode = ""; //判断障碍物是否可以触碰 self.value = http://www.mamicode.com/0 == index ? -1:1; self.addChild(bitmap); }
可以结合注释看一下,如果你对lufylegend是十分了解,那么看起来就很简单了。
只简单说明一个地方。就是index这个变量,首先给它随机弄一个1~10的整数,接着判断,如果index值为0,则为有钉子的跳板,否则为可以站立的跳板。这样的话,出现有钉子的跳板的概率则为十分之一。
其中mode属性和上一讲中Character类的mode属性是一样的。它用于判断跳板当前状况。
value属性判断是否可以触碰。
当然光有构造器还不行,我们为了让跳板能上升,添加run方法:
/** *Stage类中run函数 */ Stage.prototype.run = function(){ var self = this; //让障碍物不断上升 self.y -= stageSpeed; //使用Stage中checkHit函数,判断是否碰撞 var hit = self.checkHit(); //判断是否到达边缘 if(self.y < 0){ self.mode = "die"; } //判断碰撞 if(!hit){ //当没有碰撞时…… //将模式设为up self.mode = "up"; }else{ //当产生碰撞时…… //将模式设为hit self.mode = "hit"; } }
因为Stage继承自LSprite类,所以当你改变y属性时,跳板就会上升。代码的逻辑是这样的:
判断跳板是否移出屏幕,如果是,则将mode改为die ---> 判断是否碰到人物,如果没有则将mode改为up,让它自己不断上升;如果是则将mode改为hit
这样设计的话,我们可以在页面每刷新一次就调用checkHit。在checkHit里判断这个mode,根据它的值判断它要做的处理。
当然,大家可能已经想看看checkHit里的代码了,那我也不好再隐瞒代码了,贴出来给大家看看:
/** *Stage类中检测碰撞的checkHit函数 */ Stage.prototype.checkHit = function(){ var self = this; //检测碰撞 if(LStage.hitTest(self,hero)){ //将碰撞变量设定为true hitStage = true; //判断碰到的是可触碰的还是不可碰的以及有没有扣血 if(isCutHp == false){ //当为没有扣血时…… //将层数加一 layer++; //显示层数 showLayer(); if(self.value =http://www.mamicode.com/= -1){ //当为不可触碰时…… //hp减一 hp--; //显示hp showHp(); } } if(self.mode == "hit"){ //将isCutHp设为ture isCutHp = true; if(self.value =http://www.mamicode.com/= 1){ //当是可触碰物时…… //将人物坐标移到障碍物上一个人的身高减8 hero.y = (self.y - hero.height) + 5; }else if(self.value =http://www.mamicode.com/= -1){ //当是不可触碰物时…… //将人物坐标移到障碍物上一个人的身高减30 hero.y = (self.y - hero.height) + 27; } }else{ //将isCutHp设为false isCutHp = false; } }else{ //将hitStage设为false hitStage = false; } }
首先我们用lufylegend中提供的检测碰撞方法LStage.hitText,第一个参数是检测碰撞的区域A,第一个参数是检测碰撞的区域B,它的用法可以去API上看看。
我们的if里有一大段代码。接下来由我为大家逐一解释。
首先,如果我们的英雄碰到了跳板就将碰撞变量hitStage设为true,否则设为false,这样的话就可以在别处检测是否碰撞了。接着我们将英雄的层数加1并显示,然后判断是否碰到带钉子的跳板。如果碰到就让英雄的hp减1并显示。接着我们判断mode,如果值是hit,说明还处于碰撞之中,然后就将isCurHp改为true,说明已经减血,不需要再减了。其实无论是碰到带钉子的跳板还是没有都要把这个变量改了,目的在于判断人物是否在跳板上。
接着我们将人物的坐标y移到当前跳板上,为了让人物停止下降,我们改一下Charactor中的run方法,更改后的代码:
/** *Charactor类中run函数 */ Charactor.prototype.run = function (){ var self = this; if(hitStage == false){ //当没有碰到障碍物时…… //将人物不断下落 self.y += fallSpeed; } //减少动画切换的频率 if(self.stepindex++ > self.step){ self.stepindex = 0; self.anime.onframe(); } //判断人物模式,以便用来移动人物 if(self.mode == "left"){ //向左移动时的处理 //判断人物是否到了最左画布边缘 if(self.x > 10){ self.x -= heroSpeed; } }else if(self.mode == "right"){ //向右移动时的处理 //判断人物是否到了最右画布边缘 if(self.x < LStage.width - self.getWidth()-20){ self.x += heroSpeed; } }else if(self.mode == "stand"){ return; } }
其实就也只改了人物下降方式了:
if(hitStage == false){ //当没有碰到障碍物时…… //将人物不断下落 self.y += fallSpeed; }
在上面已经说了,如果碰到跳板就将hitStage设为true,这时判断不通过,人物就不动了。当然如果没有碰撞,那么判断就通过,英雄还是得往下落。
这些都好理解,好好看几分钟,理解了就自然简单了。
我们的Stage类已经搞定了,接着我们要把它实例化出来,因此添加addStage函数:
function addStage(){ //创建一个障碍物 var stage = new Stage(); stage.x = Math.floor(Math.random()*300); stage.y = LStage.height; stageLayer.addChild(stage); stageLayer.scaleX = 1.2; stageLayer.scaleY = 1.2; }
很简单,就是把当前这个stage对象放入stageLayer中,这样才能让它显现。至于scaleX,scaleY什么的,是我因为感觉跳板太小,所以把它们拉大了。scaleX,scaleY是lufylgend中专门用来拉图的。大家可以看看API,了解了解。
我以前说过,我们的游戏画面是不断刷新的,在刷新的时候是可以响应时间的,因此我们修改刷新事件触发的函数onframe:
function onframe(){ //使用Charactor中run函数,让人物动起来 hero.run(); //循环遍历stageLayer成员,以便用来判断是否移除该成员 for(var key in stageLayer.childList){ //使用Stage中run函数,让障碍物动起来 stageLayer.childList[key].run(); if(stageLayer.childList[key].mode == "die"){ //当障碍物移出屏幕时…… //移除该成员 stageLayer.removeChild(stageLayer.childList[key]); } //让人物不断下落或者随障碍物上升 if(hero.y < LStage.height && hero.y > 0 && hp != 0){ //正常时…… if(hitStage == true){ //当碰到障碍物时…… //将该成员的模式设为hit stageLayer.childList[key].mode = "hit"; } }else{ //当人物降到屏幕外或没有hp时…… gameover(); return; } } //减少障碍物出现的频率 if(stageStepIndex++ > stageStep){ stageStepIndex = 0; //加入障碍物 addStage(); } }
由于我们的跳板是加到一个名叫stageLayer的LSprite中的,所以我们就遍历一下stageLayer的成员列表,每遍历到一个,就对那一个进行run操作。然后判断那一个的mode是否为die,如果是,就把它移除掉。
接着我们进行对人物的操作。首先我们如果人物坐标不为0也就是说没有接触了最上层的钉子并且没有掉到屏幕下以及hp不为0时,就进行正常的操作。如果我们的人物发生了碰撞就将与其碰撞的那个跳板mode设为hit,表示已经碰撞。
如果我们的英雄接触了最上层的钉子并且掉到屏幕下甚至hp为0时,就将游戏结束,我们通过gameover函数实现它。
然后我们加入几个全局变量:
//障碍物频率变量 var stageStepIndex = 0,stageStep = 30;
它们是控制跳板出现频率的。由于onframe里的东西是页面每刷新一次就调用的,所以在onframe中我们将stageStepIndex加1,并判断是否大于stageStep,如果是的话就加一个障碍物。这个做法在上一讲中也提到过,可以去看看。
经过这样一设计,我们就可以让跳板不断出现并且不断上升。
接下来看几个显示hp和层数的函数:
function addPoint(){ //定义layerText为一个文本 layerText = new LTextField(); //显示人物hp图片 hpBitmapdata = http://www.mamicode.com/new LBitmapData(imglist["hp"]); //显示hp showHp(); //显示层数 showLayer(); } function showHp(){ //设定显示图片的长度,以便用来显示扣hp hpBitmapdata.setProperties(0,0,20*hp,18); var hpBitmap = new LBitmap(hpBitmapdata); //设定hp显示位置 hpBitmap.x = 20; hpBitmap.y = LStage.height - 55; overLayer.addChild(hpBitmap); } function showLayer(){ //设定字体 layerText.font = "HG行書体"; //设定颜色 layerText.color = "white"; //设定文本 layerText.text = "Layer:"+layer; //设定x坐标 layerText.x = 23; //设定y坐标 layerText.y = LStage.height - 35; //设定字的大小 layerText.size = 15; overLayer.addChild(layerText); }
代码很简单,看看注释就能懂。
另外加如一个暂停功能,原理很简单,就是将刷新事件移除:
function addSetButton(){ //显示一个暂停按钮 btnPause = new LButton(new LBitmap(new LBitmapData(imglist["pause"])), new LBitmap(new LBitmapData(imglist["pause"]))); btnPause.x = LStage.width - 60; btnPause.y = LStage.height - 40; btnPause.scaleX = 0.5; btnPause.scaleY = 0.5; overLayer.addChild(btnPause); //添加按钮事件 btnPause.addEventListener(LMouseEvent.MOUSE_DOWN,function(){ if(isPlay == 1){ //当没有暂停时…… //将isPlay设为0 isPlay = 0; //移除鼠标事件 backLayer.removeEventListener(LMouseEvent.MOUSE_DOWN,onDown); backLayer.removeEventListener(LMouseEvent.MOUSE_UP,onUp); //移除onframe调用 backLayer.removeEventListener(LEvent.ENTER_FRAME,onframe); }else if(isPlay == 0){ //当暂停时…… //将isPlay设为1 isPlay = 1; //加入鼠标事件 backLayer.addEventListener(LMouseEvent.MOUSE_DOWN,onDown); backLayer.addEventListener(LMouseEvent.MOUSE_UP,onUp); //加入onframe调用 backLayer.addEventListener(LEvent.ENTER_FRAME,onframe); } }); }
运行代码看看:
二,英雄威名
我们上面提到了gameover函数,我们在这里看看它的代码:
function gameover(){ //将人物模式设为die hero.mode = "die"; //移除人物 charaLayer.removeAllChild(); //移除所有事件 removeEvent(); //获得玩家称号 getName(); //添加游戏结束文字 overLayer.graphics.drawRect(5,"gray",[40,80,330,200],true,"lightgray"); overLayer.alpha = 0.8; for(var i=0;i<gameoverContentArr.length;i++){ //字的公共属性 gameoverText = new LTextField(); gameoverText.font = "HG行書体"; gameoverText.text = gameoverContentArr[i]; //字的私有属性 if(i == 0){ //当字是GAME OVER时…… gameoverText.x = 50; gameoverText.color = "dimgray"; gameoverText.size = 40; gameoverText.y = 100; }else if(i == 1){ //当字是Tap to Restart时…… gameoverText.x = 120; gameoverText.color = "dimgray"; gameoverText.size = 20; gameoverText.y = 170; } overLayer.addChild(gameoverText); } //定义nameText为一个文本 nameText = new LTextField(); //设定字体 nameText.font = "HG行書体"; //设定颜色 nameText.color = "white"; //设定字体粗细 nameText.weight = "bold"; //设定字体大小 nameText.size = 15; //设定x坐标 nameText.x = 100; //设定y坐标 nameText.y = 220; nameText.text = "你的称号是:"+getName(); overLayer.addChild(nameText); //添加重新开始游戏的事件 backLayer.addEventListener(LMouseEvent.MOUSE_DOWN, function (event){ //移除场上所有东西 backLayer.removeAllChild(); backLayer.die(); //变量设为初始值 hp = 3; layer = 0; isPlay = 1; //游戏重开 initLayer(); startGame(); }); }
注释写得很清楚,不用我多说了。其中调用了一个getName(),其中的代码很后意思:
function getName(){ if(layer < 10){ return "小试身手者"; }else if(layer >= 10 &&layer < 20){ //当分数在10~20时…… return "英勇无畏者"; }else if(layer >= 20 &&layer < 30){ //当分数在20~30时…… return "行如风行者"; }else if(layer >= 30 &&layer < 40){ //当分数在30~40时…… return "影身如风者"; }else if(layer >= 40 &&layer < 50){ //当分数在40~50时…… return "深渊掌控者"; }else if(layer >= 50 &&layer < 60){ //当分数在50~60时…… return "极限飞登者"; }else if(layer >= 60 &&layer < 70){ //当分数在60~70时…… return "可谓英雄者"; }else if(layer >= 70 &&layer < 80){ //当分数在70~80时…… return "冲锋陷阵者"; }else if(layer >= 80 &&layer < 90){ //当分数在80~90时…… return "身如疾风者"; }else{ //当分数在90以上…… return "再现武魂者"; } }
代码当然很简单,但是值得一提的是,其中“再现武魂者”和“身如疾风者”都是出自真三国无双5,我想不出称号了,借用了一下。
运行代码:
演示地址:http://www.cnblogs.com/yorhom/archive/2013/04/14/3020566.html
话说我们的小卒已经死了九亿九千九百九十九万次了,趁我写文章这段时间,他叫了不下九千九百九十九万次help,我写完文章按下F5运行下代码,小卒愤怒地大叫道:“我X,我都死了九亿九千九百九十九万次了,就算去见阎王也要当个无常什么的。恩。。。人生自古谁无死,留取丹心照汗青!!!”没等他说下一句鬼话,他忽然眼前一亮,看见一个跳板向他飞来。小卒高兴地大叫:“老夫有救了!!!”他飞快地冲到跳板上,又接着往下一块上跳,不想下一块是一个钉板,小卒刚一碰到就被戳了一下。“Yorhom,你到底要怎样???你已经困俺500年了!!家中老小早不知死活了,如今还要拿钉板来陷害本人,是何意思???”小卒大骂。
Yorhom:“只有你跨越一道道难关才能修成正果,最终成为再现武魂者,加油!”
小卒:“。。。”
路过高僧:“阿弥陀佛,善哉善哉”
本次讲座就到这里,谢谢大家的捧场。
源代码下载:http://files.cnblogs.com/yorhom/jump(2).rar
『HTML5挑战经典』是英雄就下100层-开源讲座(二)危险!英雄