这个捕鱼游戏挺有意思的,通过发射子弹,打鱼。打鱼的子弹会消耗金币,但是打鱼如果打到了鱼,就会奖励金币的数量。
我如果写这个的话,应该会画一个 背景海底,然后生成很多鱼的图片,还要有一个大炮,金币。大炮会发射子弹,角度不同发摄子弹的方向不同。 发射子弹就消耗金币,如果打中鱼了就奖励金币,大炮两边的加号和减号就是控制让子弹连续发射的。不过此时发送炸弹的角度不好控制。 接下来我们看效果先放下作者大大的项目地址:
接下来我们分析代码 页面初始化绘制图片Document
//bullet//绘制子弹形状class Bullet extends Sprite{ constructor(type,x=0,y=0,rotation=0){ const SIZE=[ null, new DrawRect(_imgs.bullet,86,0,24,26), new DrawRect(_imgs.bullet,61,0,25,29), new DrawRect(_imgs.bullet,32,36,29,30), new DrawRect(_imgs.bullet,30,82,29,33), new DrawRect(_imgs.bullet,0,82,30,34), new DrawRect(_imgs.bullet,30,0,31,26), new DrawRect(_imgs.bullet,0,44,32,38) ]; super(SIZE[type],x,y,rotation); this.type=type; this.speed=5; this.radius=14; }}
绘制按钮
//buttonclass Button extends Sprite{ constructor(drawRectNormal, drawRectActive, x=0, y=0, rotation=0){ super(drawRectNormal, x, y, rotation); this.drawRectNormal=drawRectNormal; this.drawRectActive=drawRectActive; this.downAtMe=false; } down(x, y){ if(this.inRect(x, y)){ this.setDrawRect(this.drawRectActive); this.downAtMe=true; }else{ this.downAtMe=false; } } up(x, y){ this.setDrawRect(this.drawRectNormal); if(this.inRect(x, y) && this.downAtMe){ //触发onclick this.onclick && this.onclick(); } }}
绘制大炮
//cannon.jsclass Cannon extends Sprite { constructor(type, x = 0, y = 0, rotation = 0) { if (type > 7 || type < 1) { throw new Error('unkonw cannon type'); } const SIZE = [ null, { w: 74, h: 74 }, { w: 74, h: 76 }, { w: 74, h: 76 }, { w: 74, h: 83 }, { w: 74, h: 85 }, { w: 74, h: 90 }, { w: 74, h: 94 } ]; //父级 super( new DrawRect(_imgs[`cannon${type}`], 0, 0, SIZE[type].w, SIZE[type].h), x, y, rotation ); this.SIZE=SIZE; this.setType(type); this.MAX_FRAME=5; } setType(type){ this.type = type; this.setDrawRect( new DrawRect(_imgs[`cannon${type}`], 0, 0, this.SIZE[type].w, this.SIZE[type].h) ); }}
金币
//js\coin.jsclass Coin extends Sprite{ constructor(type,x=0,y=0,rotation=0){ const SIZE=[ null, new DrawRect(_imgs.coin1,0,0,60,60), new DrawRect(_imgs.coin2,0,0,60,60) ]; super(SIZE[type],x,y,rotation); this.MAX_FRAME=10; this.speed=10; }}
初始化加载图片
//common.jslet _imgs=null;const _resources={ fish1: 'img/fish1.png', fish2: 'img/fish2.png', fish3: 'img/fish3.png', fish4: 'img/fish4.png', fish5: 'img/fish5.png', cannon1: 'img/cannon1.png', cannon2: 'img/cannon2.png', cannon3: 'img/cannon3.png', cannon4: 'img/cannon4.png', cannon5: 'img/cannon5.png', cannon6: 'img/cannon6.png', cannon7: 'img/cannon7.png', bottom: 'img/bottom.png', bullet: 'img/bullet.png', coin1: 'img/coinAni1.png', coin2: 'img/coinAni2.png', number: 'img/number_black.png',};function loadImages(json, fn){ let res={}; let complete=0; let total=0; for(let name in json){ total++; let oImg=new Image(); res[name]=oImg; oImg.onload=function (){ complete++; if(complete==total){ _imgs=res; fn(); } }; oImg.onerror=function (){ alert('图片加载失败'+oImg.src); }; oImg.src=json[name]; }}function d2a(n){ return n*Math.PI/180;}function a2d(n){ return n*180/Math.PI;}function rnd(n, m){ return Math.floor(Math.random()*(m-n)+n);}
画方形的类
//js\drawRect.jsclass DrawRect{ constructor(img,sx,sy,sw,sh){ if(!img || !sw || !sh) { throw new Error('img and sw and sh is required'); } this.img=img; this.sx=sx; this.sy=sy; this.sw=sw; this.sh=sh; }}
定义的鱼的类型
//js\fish.jsclass Fish extends Sprite { constructor(type, x = 0, y = 0, rotation = 0) { if (type > 5 || type < 1) { throw new Error('unkonw fish type'); } const SIZE = [ null, { w: 55, h: 37, r: 12 }, { w: 78, h: 64, r: 18 }, { w: 72, h: 56, r: 15 }, { w: 77, h: 59, r: 15 }, { w: 107, h: 122, r: 23 } ]; super(new DrawRect(_imgs[`fish${type}`], 0, 0, SIZE[type].w, SIZE[type].h), x, y, rotation); this.type = type; this.curFrame = 0; this.MAX_FRAME = 4; this.speed = rnd(1, 4); this.frameRate = 5; this.radius=SIZE[type].r; //死鱼 this.isdead=false; } draw(gd) { if(this.isdead) { this.curFrame+=4; } if (this.rotation == -90) { this.scaleY = -1; } this.rotation -= 90; super.draw(gd); this.rotation += 90; if (this.rotation == -90) { this.scaleY = 1; } if(this.isdead) { this.curFrame-=4; } }}
绘制鱼的类型
//js\sprite.jsclass Sprite { //w,h,x,y,rotate //draw(),碰撞检测() constructor(drawRect, x = 0, y = 0, rotation = 0) { if (!(drawRect instanceof DrawRect)) { throw new Error('img must be DrawRect'); } this.setDrawRect(drawRect); this.x = x; this.y = y; this.rotation = rotation; this.speed = 0; //动画 this.MAX_FRAME=0; this.curFrame=0; this.scaleX=1; this.scaleY=1; this.frameRate=1; this.frameRateNow=0; // 碰撞检测 this.radius=0; } setDrawRect(drawRect) { this.drawRect = drawRect; this.width = drawRect.sw; this.height = drawRect.sh; } nextFrame(){ this.frameRateNow++; // console.log(this.frameRateNow); if(this.frameRateNow==this.frameRate) { this.frameRateNow=0; this.curFrame++; if(this.curFrame>=this.MAX_FRAME) { this.curFrame=0; return true; } return false; } } draw(gd) { gd.save(); gd.translate(this.x, this.y); gd.rotate(d2a(this.rotation)); gd.scale(this.scaleX,this.scaleY); gd.drawImage( this.drawRect.img, this.drawRect.sx, this.drawRect.sy+this.height*this.curFrame, this.width, this.height, -this.width / 2, -this.height / 2, this.width, this.height, ); gd.restore(); } inRect(x, y) { if ( this.x - this.width / 2 <= x && x <= this.x + this.width / 2 && this.y - this.height / 2 <= y && y <= this.y + this.height / 2 ) { return true; } else { return false; } } outRect(x,y,w,h){ if(this.xx+w || this.y>y+h) { return true; }else { return false; } } move(x,y) { if(arguments.length == 0) { let x_speed = this.speed * Math.sin(d2a(this.rotation)); let y_speed = this.speed * Math.cos(d2a(this.rotation)); this.x += x_speed; this.y -= y_speed; }else { this.x+=(x-this.x)/20; this.y+=(y-this.y)/20; } } collTest(other){ return Math.sqrt(Math.pow(this.x-other.x,2)+Math.pow(this.y-other.y,2))
后记:代码我并没有完全看懂