HTML5游戏实战(2):90行代码实现捕鱼达人

捕鱼达人是一款非常流行的游戏,几年里赚取了数以千万的收入,这里借用它来介绍一下用Gamebuilder+CanTK开发游戏的方法。其实赚钱的游戏未必技术就很难,今天我们就仅用90来行代码来实现这个游戏。 

CanTK(Canvas ToolKit)是一个开源的游戏引擎和APP框架,是开发HTML5游戏和APP的利器,如果你喜欢它,请在github上给它加星,您的支持是我们努力的动力:https://github.com/drawapp8/cantk

0.先Show一下最终成果:

在线运行:http://www.tangide.com/apprun.html?appid=previewupyunosgames1-841431856568571

在线编辑:http://www.tangide.com/gamebuilder.php?appid=previewupyunosgames1-841431856568571

1,新建一个项目,删除场景里的球和地面,把手机设置成横屏,然后设置场景的物理引擎参数,把X/Y方向的重力设置为0。

HTML5游戏实战(2):90行代码实现捕鱼达人_第1张图片

设置场景的背景图片:

HTML5游戏实战(2):90行代码实现捕鱼达人_第2张图片

效果如下:
HTML5游戏实战(2):90行代码实现捕鱼达人_第3张图片

2,在场景中放一个图片,如下图设置它的属性。

HTML5游戏实战(2):90行代码实现捕鱼达人_第4张图片

HTML5游戏实战(2):90行代码实现捕鱼达人_第5张图片

HTML5游戏实战(2):90行代码实现捕鱼达人_第6张图片

3,在图片中再放一个帧动画,用来表示大炮,如下图设置它的属性。

HTML5游戏实战(2):90行代码实现捕鱼达人_第7张图片

HTML5游戏实战(2):90行代码实现捕鱼达人_第8张图片

HTML5游戏实战(2):90行代码实现捕鱼达人_第9张图片

4,在场景中再放一个帧动画,用来表示鱼,如下图设置它的属性。

HTML5游戏实战(2):90行代码实现捕鱼达人_第10张图片

HTML5游戏实战(2):90行代码实现捕鱼达人_第11张图片

通过拷贝&粘贴,创建10条鱼,名称分别命名为ui-fish1到ui-fish10。得到下面的效果:
HTML5游戏实战(2):90行代码实现捕鱼达人_第12张图片

5,在场景中再放一个帧动画,用来表示金币,如下图设置它的属性。

HTML5游戏实战(2):90行代码实现捕鱼达人_第13张图片

HTML5游戏实战(2):90行代码实现捕鱼达人_第14张图片

6,在场景中再放一个帧动画,用来表示炮弹,如下图设置它的属性。

HTML5游戏实战(2):90行代码实现捕鱼达人_第15张图片

HTML5游戏实战(2):90行代码实现捕鱼达人_第16张图片

HTML5游戏实战(2):90行代码实现捕鱼达人_第17张图片

7,在底部的图片中放一个图片字体,用来表示总金币数量,如下图设置它的属性。

HTML5游戏实战(2):90行代码实现捕鱼达人_第18张图片

HTML5游戏实战(2):90行代码实现捕鱼达人_第19张图片

8,在场景中中放一个图片字体,用来表示单次金币数,如下图设置它的属性。

HTML5游戏实战(2):90行代码实现捕鱼达人_第20张图片

HTML5游戏实战(2):90行代码实现捕鱼达人_第21张图片

9,在底部的图片中放两个按钮,用来改变大炮的威力,如下图设置它的属性。

HTML5游戏实战(2):90行代码实现捕鱼达人_第22张图片

HTML5游戏实战(2):90行代码实现捕鱼达人_第23张图片

到此界面基本完成了(后面可能需要做些调整),效果如下:

HTML5游戏实战(2):90行代码实现捕鱼达人_第24张图片

10,现在我们开始写代码。

在场景的onOpen里定义几个函数:

var win = this;
function isObjInvisible(obj) {return !obj.visible;}
//当炮弹和鱼移动到场景之外时,把它们设置为不可见不可用,后面重用这些对象,以减小内存开销。
function handleOnMoved() {
    var x = this.x, y = this.y, r = x + this.w, b = y + this.h, w = win.w, h = win.h;
    if(x > w || y > h || r < 0 || b < 0) {
        this.setVisible(false).setEnable(false);
    }
}
//定时产生鱼
function makeFish() {
    if(!win.info) return;
    var info = win.info,cannon = info.cannon;
    var fish = info.fishs.find(isObjInvisible);
    if(!fish && info.fishs.length < 20) {
        var index = Math.floor(10 * Math.random())+1;
        fish = win.dupChild("ui-fish"+index);
        
    }
    if(fish) {
        info.fishs.push(fish);
        var y = Math.max(0, Math.floor((win.h - info.bottom.h) * Math.random() - fish.h));
        var x =  y%2 ? -fish.w : win.w;
        var vx = x > 0 ? -1 : 1;
        var rotation = x > 0 ? Math.PI : 0;
        fish.setPosition(x, y).setVisible(true).setEnable(true).setV(vx, 0).setRotation(rotation).play("live");
    }
    setTimeout(makeFish, 500);
}
//初始化游戏
win.initGame = function() {
    var info = {bullets:[], fishs:[], cannonType:1, scoreValue:0};
    var cannon = this.find("ui-cannon", true);
    var p = cannon.getPositionInWindow(); 
    cannon.center ={x: p.x + (cannon.w >> 1), y: p.y + (cannon.h >> 1)};    
    info.cannon = cannon;

    info.bottom = this.find("ui-image");
    var totalScore = this.find("ui-total-score", true);
    p = totalScore.getPositionInWindow(); 
    totalScore.center ={x: p.x + (totalScore.w >> 1), y: p.y + (totalScore.h >> 1)};    
    info.totalScore = totalScore;
    
    var bullet = this.find("ui-bullet").setVisible(false).setEnable(false);
    bullet.handleOnMoved = handleOnMoved;
    info.bullets.push(bullet);
    
    info.coin = this.find("ui-coin").setVisible(false);
    info.score = this.find("ui-score").setVisible(false);
    for(var i = 0; i < this.children.length; i++) {
        var iter = this.children[i];
        if(iter.name.indexOf("ui-fish") >= 0) {
            iter.handleOnMoved = handleOnMoved;
            iter.setEnable(false).setVisible(false);
            info.fishs.push(iter);
        }
    }
    info.timerID = setTimeout(makeFish, 1000);
    this.info = info;
}
//改变大炮类型
win.changeCannon = function(delta) {
    var info = this.info,cannon = info.cannon;
    info.cannonType = Math.max(1, Math.min(7, info.cannonType + delta));
    cannon.play("default"+info.cannonType, 100000);
}
//炮弹打中鱼时,炮弹变成网,鱼播放die动画,金币从炮弹处移动到总金币处。
win.onContacted = function(bullet, fish) {
    var info = this.info,cannon = info.cannon;
    bullet.setEnable(false).play("web"+info.cannonType, 1, function() {bullet.setVisible(false);});
    fish.setEnable(false).play("die", 1, function() {fish.setVisible(false)});
    info.scoreValue += 100;
    info.totalScore.setValue(info.scoreValue);
    info.coin.setVisible(true).animate({xStart:bullet.x, yStart:bullet.y, xEnd:info.totalScore.x, yEnd:info.totalScore.y-20});
}
//点击场景时,调整大炮位置,发射炮弹,大炮播放射击动画。
win.handleClick = function(point) {
    var info = this.info,cannon = info.cannon;
    if(this.targetShape != this.info.bottom) {
        var angle = Math.lineAngle(cannon.center, point) - 1.5 * Math.PI;
        cannon.setRotation(angle);
        var bullet = info.bullets.find(isObjInvisible);
        if(!bullet)  {
            bullet = win.dupChild("ui-bullet",0);
            info.bullets.push(bullet);
        }
        var x = cannon.center.x - (bullet.w >> 1), y = cannon.center.y - (bullet.h >> 1);
        bullet.setPosition(x, y).setRotation(angle).setVisible(true).setEnable(true).setV(5*Math.sin(angle),-5*Math.cos(angle));
        bullet.play("bullet"+info.cannonType);
        cannon.play("fire"+info.cannonType, 1);
        console.log(angle);
    }
}

this.initGame();

在场景的点击事件中:

this.handleClick(point);

在两个按钮中:

this.getWindow().changeCannon(-1);

好了,我们的捕鱼达人基本完成了。还有几个地方需要完善:1.射中多条鱼时分数加倍。2.鱼有不同的生命值,炮弹有不同的杀伤力。

呵河,这些问题留给读者动手去做吧,或许您就是下一个千万级游戏的开发者呢:)

参考资料:

https://github.com/drawapp8/gamebuilder/wiki/%E4%B8%AD%E6%96%87%E6%96%87%E6%A1%A3

你可能感兴趣的:(游戏,html5,canvas,游戏引擎,捕鱼达人)