自从上次发布一个小恐龙游戏以后,到现在10天了,前后又写了3个游戏,挑了一个感觉比较有挑战的游戏和大家分享一下。
这是我模拟一个苹果游戏《stick hero》游戏写的一个小游戏,在这里记录一下,希望大家会喜欢。
一直按下鼠标,会出一根棍子,棍子会变长,小人会根据棍子长度来移动。判断小人是否停留在柱子上,因为放在网上以后,鼠标判断有点卡,请大家见谅。
那我们还是从头开始介绍一下这游戏的开发过程吧。
图片加载
这次的图片加载器是用的《H5手把手教你玛丽游戏》的图片加载器,个人感觉非常好用,可能是我没接触更好的图片加载器,大神都是用自己框架写的,感觉研究起来我很吃力,基础跟不上,最近一个大哥叫我去研究OOP思想来编写框架开发游戏,这也是我以后的方向,很感谢这位大哥给我的指导。
function loadImg(imgCount,callback){ var img = {}, total = imgCount.length, loaded = 0; for(var i = 0;i < total;i++){ var imgs = img[imgCount[i].id] = new Image(); imgs.src = imgCount[i].src; imgs.onload = function(){ loaded++; }; } if(typeof callback == "function"){ function check(){ if(loaded >= total) callback(); else setTimeout(check,300); } check(); } return img; }
调用的方式和我上次那个差不多,也是传id和src,和回调函数,确保图片加载完以后执行。
var imgs = null, game = null; function init(){ imgs = loadImg([ {id:"bg",src:"img/bg2.png"}, {id:"player",src:"img/player.png"} ],start); } init(); function start(){ game = new Game({ width:500, height:600, FPS:30, }); game.init(); game.move(); }
精灵类
这次比较复杂的是存在着精灵,精灵存在动画,所以加了2个类,Sprite和Animation,在这个游戏中,我把柱子也当做精灵处理,因为每次的柱子他的宽度和初始位置是随机的,而且在检测人物是否站在柱子上的时候比较好检测。
function Sprite(option){ for(var attr in option){ this[attr] = option[attr]; } } Sprite.prototype = { constructor:Sprite, x:0, y:340, w:0, h:0, maxX:999, maxY:999, animation:null, accX:0, accY:0, init:function(){ if(this.animation){ this.animation.init(); this.animation.setNow(0); } }, //每次更变人物的移动动画,让人物动起来。 update:function(sleep,long){ this.x += this.accX; this.animation.update(sleep); if(this.x >= long+40){ this.x = long+40; this.animation.setNow(0); this.checkCollide(); } }, //人物的绘制 draw:function(ct){ this.animation.draw(ct,this.x,this.y); }, //矩形的绘制 drawRect:function(ct){ ct.fillRect(this.x,this.y,this.w,this.h); }, //检测人物是否在柱子上 checkCollide:function(){ var Px1 = this.x; var Px2 = this.x + 40; var Rx1 = game.colRect.x; var Rx2 = game.colRect.x + game.colRect.w ; if(Px1 > Rx2 || Px2 < Rx1){ this.y += this.accY; if(this.y >= this.maxY){ clearInterval(game.mainLoop); alert("挑战失败! "); } }else{ game.initStart(); } } };
下面是生成人物和柱子的代码,通过参数可以区分他们。
function createPlayer(){ var config = { //人物走路速度 accX:4, //人物掉落速度 accY:7, //人物初始位置 x:0, y:340, maxY:600, //人物移动过程 animation:new Animation({ frame:[ {x:20,y:0,w:80,h:80,action:100}, {x:120,y:0,w:80,h:80,action:100}, {x:220,y:0,w:80,h:80,action:100}, {x:320,y:0,w:80,h:80,action:100}, ] }) }; return new Sprite(config); }
function createRect(){ var config = { //每次随机获取宽度和x位置,这样让游戏更有挑战 w:(Math.random()*40 + 20)|0, x:(Math.random()*300+150)|0, y:400, h:200, }; return new Sprite(config); }
下面介绍的是人物的移动,通过组图的不断更换,让人物动起来。
function Animation(option){ for(var attr in option){ this[attr] = option[attr]; } } Animation.prototype = { constructor:Animation, img:null, //移动过程 frame:null, //动作的索引值 index:null, //一个动作的进行时间 time:null, //当前为多少帧 frameNow:null, len:-1, init:function(){ this.img = imgs["player"]||null; this.frame = this.frame||[]; this.len = this.frame.length - 1; this.index = 0; this.setNow(this.index); }, setNow:function(index){ this.index = index; this.frameNow = this.frame[this.index]; }, //action为每个动作进行多长时间(前面传过来) update:function(sleep){ if(this.time >= this.frameNow.action){ this.time = 0; if(this.index >= this.len){ this.index = 0; }else{ this.index++; } this.setNow(this.index); }else{ this.time += sleep; } }, //人物的绘制 draw:function(ct,x,y){ var f = this.frameNow; ct.drawImage(this.img,f.x,f.y,f.w,f.h,x,y,60,60); } };
游戏类
这个类里面一个主循环控制着我们所有移动的进行,这里我分步来说一下我遇到的问题。
1.如何实现一个柱子倒下的过程,开始我的想法是画一个矩形,然后通过rotate来实现倾斜,因为以前没有用过rotate方法,进入尝试了一次,才知道他的倾斜是将整个画布倾斜,这样连背景一起倾斜,根本无法达到效果,然后通过在纸上画了一下,用数学知识解决了这个问题,我把矩形换成换线,改变他的lineWidth让他看起来像一个矩形。
stick:function(){ //当鼠标按下以后执行,并且在棍子移动时不会再次触发。 if(this.moused && !this.clicked){ this.time += this.sleep; //让棍子垂直向上伸展,通过循环让他的长度累加 this.drawStick(this.time); }else if(!this.moused && this.long > 0){ //当鼠标松开(mouseup)以后,让棍子倒下去 this.clicked = true; this.length = this.stickY - this.long; this.fallRect(this.length); } }, //棍子向上伸展 drawStick:function(time){ this.time = time; this.long += (time/200)|0; this.ct.beginPath(); this.ct.lineWidth = 5; this.ct.moveTo(this.stickX,this.stickY); this.ct.lineTo(this.stickX,this.stickY - this.long); this.ct.stroke(); }, //棍子向下掉落,记录下棍子的长度,就是人物行走的距离 fallRect:function(length){ this.length = length; if(this.angle < 30){ this.angle += this.sleep/50; this.ct.beginPath(); this.lineWidth = 5; this.ct.moveTo(this.stickX,this.stickY); var hudu = (2*Math.PI / 360) * 3 * this.angle; this.fallX = this.stickX + this.long*Math.sin(hudu); this.fallY = this.stickY - this.long*Math.cos(hudu); if(this.fallY >= this.stickY){ this.fallY = this.stickY; } this.ct.lineTo(this.fallX,this.fallY); this.ct.stroke(); }else{ this.ct.beginPath(); this.lineWidth = 5; this.ct.moveTo(this.stickX,this.stickY); this.ct.lineTo(this.fallX,this.fallY); this.ct.stroke(); this.success = true; } },
2.当我以为这个游戏已经结束的时候出现了一个bug,就是每次棍子的绘制路径都被保留下来了,这是我canvas控制能力不足,每次绘制之前加一个beginPath就好了。
结束语
在这里,感谢帮助我的每一个人,以后我也会成为大牛,写更多更好的博文,尽自己的力量去帮助更多人。
最近在实验室学习,突然很想回家了,毕竟好久没看见家人了,还有10天就能回家了,心里还是很高兴。
只有半年的时间就要去找工作了,有时间都去研究JS,感觉JS真是非常强大,我现在的水平想开发框架还是太难了,不过慢慢来吧,欲速则不达,一步一步积累终有一天我能自己开发框架。
谢谢大家,如有什么疑问或者建议请留言。