制作一款HTML5 RPG游戏引擎教程(五).docx
该引擎是基于lufylegend开发的,学习时请先了解lufylegend。一,人物类LCharacter首先来看LCharacter构造器:javascript view plaincopy1. /* 2. *LCharacter.js 3. */ 4. function LCharacter(data,row,col,speed,isFighter) 5. var s = this; 6. base(s,LSprite,); 7. s.type = "LCharacter" 8. if(!speed)speed = 0; 9. if(isFighter = undefined)isFighter = false; 10. s.speed = speed; 11. s.speedIndex = 0; 12. s.x = 0; 13. s.y = 0; 14. s.mode = "" 15. s.index = 0; 16. if(isFighter = true) 17. s.hp = 0; 18. s.attack = 0; 19. s.defense = 0; 20. 21. s.effect = null; 22. s.avatarNum = 0; 23. s.flickerNum = 0; 24. s.img = data; 25. s.row = row; 26. s.col = col; 27. s.effectSprite = new LSprite(); 28. s.addChild(s.effectSprite); 29. s.nameSprite = new LSprite(); 30. s.addChild(s.nameSprite); 31. var imgData = new LBitmapData(data); 32. imgData.setProperties(0,0,imgData.image.width/col,imgData.image.height/row); 33. var list = LGlobal.divideCoordinate(imgData.image.width,imgData.image.height,row,col); 34. s.imgWidth = imgData.image.width/col; 35. s.imgHeight = imgData.image.height/row; 36. s.anime = new LAnimation(s,imgData,list); 37. s.addEventListener(LEvent.ENTER_FRAME,function() 38. if(s.effect != null) 39. s.showEffect(s,s.effect); 40. 41. ); 42. 这个类有5个参数,功能如下:javascript view plaincopy1. data:人物图片 2. row:将图片切成多少行,以方便执行动画 3. col:将图片切成多少列,以方便执行动画 4. speed:人物动画播放频率相对屏幕刷新频率的倍数 5. isFighter:是否处于战斗状态 上面的介绍有些含糊,我接着解释一下。首先,data所代表的图片是一个装有每帧动画的图片,比如下面这种图片:然后我们的参数row和参数col就是用来表示这个图片可以分成几行,几列。比如上图,row就赋值成4,col也赋值成4,这样恰好能将每帧都分割出来。speed是用来表示播放动画频率的,假设我们在用init初始化游戏时,传入游戏频率为30毫秒,那如果不给这个参数赋值,播放动画的频率就是30毫秒,但是如果你觉得30毫秒播放一帧太快了,想慢一点,便可以用到这个参数。比如说你想让播放频率达到每120毫秒播放一帧,而游戏频率设的是30毫秒,那就可以把这个参数设置为4。假设达到每150毫秒播放一帧,那就可以把这个参数设置为5。但要注意,这个参数赋值必须是正整数。isFighter这个参数是用来判断是否这个角色是处于战斗状态的。如果是就设为true,不是就设为false,当然你不设定就默认为false。当这个参数为true时,人物类就可以加几个属性,它们用来控制人物的hp,战斗力,防御力等,判断代码如下:javascript view plaincopy1. if(isFighter = true) 2. s.hp = 0; 3. s.attack = 0; 4. s.defense = 0; 5. 为了给这个类更方便地添加特效,我给它自身创建了一个叫effectLayer的LSprite。用于特效的几个属性还如下几个:s.effect = null;s.avatarNum = 0;s.flickerNum = 0;接着我创建了一个LAnimation对象,用它来显示人物动画,代码如下:javascript view plaincopy1. var imgData = new LBitmapData(data); 2. imgData.setProperties(0,0,imgData.image.width/col,imgData.image.height/row); 3. var list = LGlobal.divideCoordinate(imgData.image.width,imgData.image.height,row,col); 4. s.imgWidth = imgData.image.width/col; 5. s.imgHeight = imgData.image.height/row; 6. s.anime = new LAnimation(s,imgData,list); 具体LAnimation使用方法可以去lufylegend官方API中查看。这里就先不多讲了为了使特效使用方便,我设计为直接通过调整effect属性来完成。但是effect在实例化前值是null,所以如果不做处理就调整了属性依然是不会显示的。所以我加入了一个时间轴事件,让它不断地判断effect属性,以至于达到一改effect属性就能立刻显示效果。代码如下:javascript view plaincopy1. s.addEventListener(LEvent.ENTER_FRAME,function() 2. if(s.effect != null) 3. s.showEffect(s,s.effect); 4. 5. ); 关于时间轴,说白了就是一个死循环,只不过是停顿一段时间调用一次,javascript中通常用setInerval来实现,具体方法Google一下或百度一下就OK,我不多解释了。当然,具体如何显示效果留到下面讲,我们先看其他方法。由于我们在开发的过程中要用到修改数据的方法,因此我们还得加一个setData方法:javascript view plaincopy1. LCharacter.prototype.setData = function(data,row,col,speed,isFighter) 2. var s = this; 3. if(!speed)speed = 0; 4. if(isFighter = undefined)isFighter = false; 5. s.speed = speed; 6. s.img = data; 7. s.row = row; 8. s.col = col; 9. if(isFighter = true) 10. s.hp = 0; 11. s.attack = 0; 12. s.defense = 0; 13. 14. var imgData = new LBitmapData(data); 15. imgData.setProperties(0,0,imgData.image.width/col,imgData.image.height/row); 16. var list = LGlobal.divideCoordinate(imgData.image.width,imgData.image.height,row,col); 17. s.imgWidth = imgData.image.width/col; 18. s.imgHeight = imgData.image.height/row; 19. s.removeChild(s.anime); 20. s.anime = new LAnimation(s,imgData,list); 21. 参数和构造器的参数是一样的,方法也差不多,大家可以自己看一下。二,动画操作上面我们做好了构造器和重设数据方法,并解释了大半天,接下来就要讲讲动画操作了。动画操作一般有这几种:1,设置动画 2,获取动画信息 3,加入动画监听事件 4,播放动画还好,这三种方法在lufylegend中都封装得有,我们用起来就很方便了。添加addActionEventListener方法,以达到给动画加入监听事件:javascript view plaincopy1. LCharacter.prototype.addActionEventListener = function(type,listener) 2. var s = this; 3. s.anime.addEventListener(type,listener); 4. 添加setAction方法,以达到设置动画:javascript view plaincopy1. LCharacter.prototype.setAction = function(rowIndex,colIndex,mode,isMirror) 2. var s = this; 3. s.anime.setAction(rowIndex,colIndex,mode,isMirror); 4. 添加getAction方法,以达到获取动画信息:javascript view plaincopy1. LCharacter.prototype.getAction = function() 2. var s = this; 3. var returnAction = s.anime.getAction(); 4. return returnAction; 5. 添加onframe方法,以达到播放动画:javascript view plaincopy1. LCharacter.prototype.onframe = function() 2. var s = this; 3. if(s.speedIndex+ < s.speed)return; 4. s.speedIndex = 0; 5. s.anime.onframe(); 6. 有了这些使用时就方便多了。开发到这里,其实是已经可以显示人物动画了。只用这样写即可:javascript view plaincopy1. var backLayer = new LSprite(); 2. addChild(backLayer); 3. var chara = new LCharacter(imglist"player",4,4,3); 4. backLayer.addChild(chara); 5. backLayer.addEventListener(LEvent.ENTER_FRAME,onframe); 6. function onframe() 7. chara.onframe(); 8. 三,moveTo方法为了简化操作,我加入moveTo方法来控制人物移动。moveTo方法的代码:javascript view plaincopy1. LCharacter.prototype.moveTo = function(x,y,timer,type,style,completefunc) 2. var s = this; 3. if(!timer)timer = 1; 4. if(!type)type = Quad.easeIn; 5. if(!style)style = LMoveStyle.direct; 6. 7. switch(style) 8. case LMoveStyle.direct: 9. var vars = 10. x:x, 11. y:y, 12. ease:type, 13. onComplete:completefunc 14. 15. LTweenLite.to(s,timer,vars); 16. break; 17. case LMoveStyle.horizontal: 18. LTweenLite.to(s,timer, 19. x:x, 20. ease:type, 21. onComplete:function() 22. LTweenLite.to(s,timer, 23. y:y, 24. ease:type, 25. onComplete:completefunc 26. ); 27. 28. ); 29. break; 30. case LMoveStyle.vertical: 31. LTweenLite.to(s,timer, 32. y:y, 33. ease:type, 34. onComplete:function() 35. LTweenLite.to(s,timer, 36. x:x, 37. ease:type, 38. onComplete:completefunc 39. ); 40. 41. ); 42. break; 43. default: 44. trace("Error: Value of last param is wrong!"); 45. 46. 参数分别为:目标x坐标,目标y坐标,移动时间,缓动类型,移动样式,移动完成后调用的函数目标x坐标,目标y坐标不用解释。关键是后面几个比较重要。首先,由于这个效果我使用lufylegend的缓动类LTweenLite做的,所以timer就代表LTweenLite参数$duration,type就代表LTweenLite中的ease(缓动函数),LTweenLite的用法很广,可以上官网看看。我们创建一个JSON对象,叫LMoveStyle,如下:javascript view plaincopy1. var LMoveStyle = 2. horizontal:"horizontal", 3. vertical:"vertical", 4. direct:"direct" 5. ; style这个参数传得值为LMoveStyle中的成员,就是LMoveStyle.horizontal,LMoveStyle.vertical,LMoveStyle.direct。LMoveStyle.horizontal是先横向移动,再竖向移动;LMoveStyle.vertical则是先竖向移动,再横向移动;LMoveStyle.direct则是直接移到该地点。以后或许还会加更多效果,这里就先做3个。使用时这么写就行了:javascript view plaincopy1. charaObj.moveTo(200,100,10,Quad.easeIn,LMoveStyle.direct,function(); 四,加入角色名称以前在lufy博客上看到有人问如何给人物加一个名称,当时看到了就想到了要加这个方法。其实实现起来很简单,代码如下:javascript view plaincopy1. LCharacter.prototype.addName = function(name,style) 2. var s = this; 3. s.nameSprite.removeAllChild(); 4. if(!name)name = 0; 5. if(!style)style = 6. if(!style0)style0 = 0; 7. if(!style1)style1 = 0; 8. if(!style2)style2 = "black" 9. if(!style3)style3 = "11" 10. if(!style4)style4 = "utf-8" 11. var nameText = new LTextField(); 12. nameText.text = name; 13. nameText.x = style0; 14. nameText.y = style1; 15. nameText.color = style2; 16. nameText.size = style3; 17. nameText.font = style4; 18. s.nameSprite.addChild(nameText); 19. 代码很简单,要用的时候直接这么写:javascript view plaincopy1. charaObj.addName("yorhom",0,0,"black",10,"黑体"); 五,人物特效1,分身术分身效果通常是出现在游戏的战斗过程中放大招什么的,实现起来也不是很难,主要也是用到LTweenLite缓动类。首先我们来看看showEffect方法:javascript view plaincopy1. LCharacter.prototype.showEffect = function(s,type) 2. switch(type) 3. 4. 5. 这个方法是用时间轴驱动的,因此里面的内容是不断调用的。这个参数很特别,首先是将自身指针传入,然后将效果类型传入。接着在内部判断类型为何,然后根据类型来作出相应的效果。我们创建一个LSkill对象,它是一个JSON对象,如下:javascript view plaincopy1. var LSkill = 2. avatar:"LSkillAvatar" 3. ; avatar音译为阿凡达,分身的意思(据我初步地了解应该是这样)。在这里就代表分身效果。写的时候就只用写:javascript view plaincopy1. charaObj.effect = LSkill.avatar; 但具体怎么实现呢,可以看看下面代码:javascript view plaincopy1. LCharacter.prototype.showEffect = function(s,type) 2. switch(type) 3. case LSkill.avatar: 4. if(s.avatarNum+ < 3) 5. var nowImg = s.anime.getAction(); 6. var nowY = nowImg0; 7. var nowX = nowImg1; 8. 9. var bitmapData = new LBitmapData(s.img,nowX*s.imgWidth,nowY*s.imgHeight,s.imgWidth,s.imgHeight); 10. var bitmap = new LBitmap(bitmapData); 11. bitmap.x = 0; 12. bitmap.y = 0; 13. LTweenLite.to(bitmap,0.5, 14. x:(s.imgWidth)*s.avatarNum, 15. alpha:0.2, 16. ease:Quad.easeIn, 17. onComplete:function() 18. LTweenLite.to(bitmap,0.5, 19. x:(s.imgWidth)*s.avatarNum, 20. ease:Quad.easeIn, 21. ); 22. 23. ); 24. s.effectSprite.addChild(bitmap); 25. 26. var bitmapData2 = new LBitmapData(s.img,nowX*s.imgWidth,nowY*s.imgHeight,s.imgWidth,s.imgHeight); 27. var bitmap2 = new LBitmap(bitmapData2); 28. bitmap2.x = 0; 29. bitmap2.y = 0; 30. LTweenLite.to(bitmap2,0.5, 31. x:(s.imgWidth)*s.avatarNum * -1, 32. alpha:0.2, 33. ease:Quad.easeIn, 34. onComplete:function() 35. LTweenLite.to(bitmap2,0.5, 36. x:(s.imgWidth)*s.avatarNum * -1, 37. ease:Quad.easeIn, 38. onComplete:function() 39. s.avatarNum = 0; 40. s.effect = null; 41. s.effectSprite.removeAllChild(); 42. 43. ); 44. 45. ); 46. s.effectSprite.addChild(bitmap2); 47. 48. break; 49. 50. 代码很长,不过逻辑很简单,我们慢慢解释:首先我们的分身有六个也就是3对,然后我们判断是否达到3对,如果是就不再显示分身。接着我们取出动画的前几帧,作为分身的图片,如下:javascript view plaincopy1. var nowImg = s.anime.getAction(); 2. var nowY = nowImg0; 3. var nowX = nowImg1; 然后创建左边分身的LBitmap对象,如下:javascript view plaincopy1. var bitmapData = new LBitmapData(s.img,nowX*s.imgWidth,nowY*s.imgHeight,s.imgWidth,s.imgHeight); 2. var bitmap = new LBitmap(bitmapData); 3. bitmap.x = 0; 4. bitmap.y = 0; bitmap对象的显示区域大小就是人物动画的显示区域大小,图片就是人物本身那张图片。有了这些,就可以将人物的分身和人物本身做得一模一样了,只不过分身是静态的,人物本身是动态的。接着我们开始将右边的分身缓动操作:javascript view plaincopy1. LTweenLite.to(bitmap,0.5, 2. x:(s.imgWidth)*s.avatarNum, 3. alpha:0.2, 4. ease:Quad.easeIn, 5. onComplete:function() 6. LTweenLite.to(bitmap,0.5, 7. x:(s.imgWidth)*s.avatarNum, 8. ease:Quad.easeIn, 9. ); 10. 11. ); 12. s.effectSprite.addChild(bitmap); 这个缓动是一个特别的缓动,因为它是缓动套缓动,这样做就可以让分身移动的速度达到 慢->快->慢->快 的效果。并切在移动的过程中改变透明度。右边的分身效果很左边得差不多,就是改一改方向而已。如下:javascript view plaincopy1. var bitmapData2 = new LBitmapData(s.img,nowX*s.imgWidth,nowY*s.imgHeight,s.imgWidth,s.imgHeight); 2. var bitmap2 = new LBitmap(bitmapData2); 3. bitmap2.x = 0; 4. bitmap2.y = 0; 5. LTweenLite.to(bitmap2,0.5, 6. x:(s.imgWidth)*s.avatarNum * -1, 7. alpha:0.2, 8. ease:Quad.easeIn, 9. onComplete:function() 10. LTweenLite.to(bitmap2,0.5, 11. x:(s.imgWidth)*s.avatarNum * -1, 12. ease:Quad.easeIn, 13. onComplete:function() 14. s.avatarNum = 0; 15. s.effect = null; 16. s.effectSprite.removeAllChild(); 17. 18. ); 19. 20. ); 21. s.effectSprite.addChild(bitmap2); 当右边缓动结束后,就会将effect属性设为null,然后移除所有分身。为了让大家见证一下分身效果,发两张截图:2,闪烁闪烁很简单,直接用缓动调整透明度就行了。如下:javascript view plaincopy1. if(s.flickerNum+ < 3) 2. LTweenLite.to(s,0.3, 3. alpha:0.5, 4. ease:Quad.easeIn, 5. onComplete:function() 6. LTweenLite.to(s,0.5, 7. alpha:1, 8. ease:Quad.easeIn, 9. onComplete:function() 10. s.effect = null; 11. s.flickerNum = 0; 12. 13. ); 14. 15. ); 16. 同时为LSkill添加一项,完整LSkill代码如下:javascript view plaincopy1. var LSkill = 2. avatar:"LSkillAvatar", 3. flicker:"LSkillFlicker" 4. ; 效果如下:完整showEffect代码如下:javascript view plaincopy1. LCharacter.prototype.showEffect = function(s,type) 2. switch(type) 3. case LSkill.avatar: 4. if(s.avatarNum+ < 3) 5. var nowImg = s.anime.getAction(); 6. var nowY = nowImg0; 7. var nowX = nowImg1; 8.