小游戏我机牺牲及爆炸效果

作为游戏核心教程的最后一章节,我想在这一章节结束所有游戏性方面的内容,就不把我机碰到敌机和爆炸效果分开来了,因为它们都是蛋炒饭,对之前内容的封装而已

首先是敌机碰到我方机器,检测,这个我们写在 enemy_hit() 方法里

还记得上一章节我们为什么要先循环敌机吗?

  1. 我们先创建一个类型为 Sprite 的全局变量 myplane ,也就是我们要开始对我方飞机进行封装了

    var myplane = new Sprite();
    myplane.status = 1; // 状态 1 表示正常  0 表示被命中
    
  2. 然后修改 enemy_hit() 方法添加敌机碰到我机的算法

    enemy_hit: function () {
        var enemys = this._bucket['enemy'];
        var bullets = this._bucket['bullet'];
    
        for (var i in enemys) {
            var enemy = enemys[i];
    
            if ( myplane.status != 0 )
            {
                var px = (lasted.x - enemy.x);
                var py = (lasted.y - enemy.y);
    
                if (px * px + py * py <= 64*64) {
    
                    // 我方飞机被命中了
                    myplane.status = 0;
    
                    // 创建爆炸效果
                    create_boom(lasted.x, lasted.y);
                    // 移除飞机
                    this._bucket['enemy'].splice(i, 1);
    
                    continue;
                }
            }
    
            // 子弹命中敌机效果 start
            // ...
            // 子弹命中敌机效果 end
    
        }
    }
    
  3. 修改 timeit() 函数取消发射子弹

    function timeit() {
    
        if (t % 30 == 0) {
            var enemy = Resource.item('images/enemy.png');
            create_enemy(enemy);
        }
    
        if (myplane.status != 0 && in_plane && t % 20 == 0) {
            var bullet = Resource.item('images/bullet.png');
            create_bullet(bullet);
        }
    
        t++;
    
    }
    
  4. 修改动画 animate_it() 修改下面代码,当我机状态为 0,取消绘制飞机

    if ( myplane.status != 0 ){
        ctx.drawImage(plane, 0, 0, 128, 128, lasted.x - 64, lasted.y - 64, 128, 128);
    }
    

有关重构

为什么我不把飞机直接重构完成?

  1. 重构这事,不是说重构就重构的,要一点一点的来,我们这个教程从无到有,发展到这章节,其实每章节都有做一点重构的

  2. 重构都是在逻辑非常清晰的情况下实现的,而真正的灵感, 是不清晰的,可以事后重构,但绝不能事先重构

把上面的代码整合到我们的游戏中

直接就是搬运代码了,没啥好说的了

game.js

var inherits = function (superCtor) {
    var f = function () { superCtor.call(this); }
    f.super_ = superCtor;
    f.prototype = Object.create(superCtor.prototype, {
        constructor: {
            value: f,
            enumerable: false,
            writable: true,
            configurable: true
        }
    });
    return f;
};


var Resource = {
    _res: [], // [][] 资源对象数组, 0 表示资源 1  url  2 类型 3 是否加载完成
    _load: function (idx, ops) {
        var res = this._res[idx];
        if (!res[3]) {
            if (res[2] == "audio")
                this._load_audio(res[1], idx, ops)
            if (res[2] == "image")
                this._load_image(res[1], idx, ops);
        }
    },

    _load_image: function (src, i, ops) {
        var img = wx.createImage();
        var that = this;
        that._res[i][0] = img;
        img.onload = function () {
            that._res[i][3] = true;
        }
        img.src = src;
    },

    _load_audio: function (src, i, ops) {
        var audio = wx.createInnerAudioContext();

        if (ops != null) {
            for (var k in ops) {
                audio[k] = ops[k];
            }
        }

        var that = this;
        that._res[i][0] = audio;

        audio.onCanplay(function () {
            that._res[i][3] = true;
        });
        audio.src = src;
    },

    loaded: function (callback) {
        for (var i = 0; i < this._res.length; i++) {
            if (!this._res[i][3]) {
                var that = this;
                setTimeout(function () { that.loaded(callback); }, 200);
                return;
            }

        }
        callback();
    },

    add: function (src, type, id, ops) {
        this._res.push([null, src, type, false, id]);
        this._load(this._res.length - 1, ops);
    },

    item: function (src) {
        for (var i = 0; i < this._res.length; i++) {
            if (this._res[i][1] == src) {
                return this._res[i][0];
            }
        }
        return null;
    }
}


function Sprite() {
    // 位置
    this.x = 0;
    this.y = 0;

    //宽高
    this.w = 0;
    this.h = 0;

    // 飞行速度
    this.speed = 0;

    // 图片
    this.img = null;

    // 类型
    this.kind = 0;

    // 原图位置
    this.rx = 0;
    this.ry = 0;
    this.rw = 0;
    this.rh = 0;
    this.ctx = null;

    this.change_kind = function (k) {
        this.rx = (k - 1) * this.rw;
        this.ry = 0;
    }

    this.move = function () {
        this.y += this.speed;
    };

    this.draw = function () {
        this.ctx.drawImage(this.img, this.rx, this.ry,
            this.rw, this.rh,
            this.x - this.w / 2, this.y - this.h / 2,
            this.w, this.h);
    }
}

var Bucket = {
    _bucket: {},
    move: function () {
        for (var i in this._bucket) {
            for (var j in this._bucket[i]) {
                this._bucket[i][j].move();

                if (this._bucket[i][j].hit()) {
                    this._bucket[i].splice(j, 1);
                }
            }
        }
    },

    add: function (obj, bucket) {
        if (!(bucket in this._bucket)) {
            this._bucket[bucket] = [];
        }
        this._bucket[bucket].push(obj);
    },

    draw: function (ctx) {
        for (var i in this._bucket) {

            for (var j in this._bucket[i]) {
                this._bucket[i][j].draw();
            }
        }
    },

    enemy_hit: function () {
        var enemys = this._bucket['enemy'];
        var bullets = this._bucket['bullet'];

        for (var i in enemys) {
            var enemy = enemys[i];

            if ( myplane.status != 0 )
            {
                var px = (lasted.x - enemy.x);
                var py = (lasted.y - enemy.y);

                if (px * px + py * py <= 64*64) {

                    // 我方飞机被命中了
                    myplane.status = 0;

                    // 创建爆炸效果
                    create_boom(lasted.x, lasted.y);
                    // 移除飞机
                    this._bucket['enemy'].splice(i, 1);

                    continue;
                }
            }

            for (var j in bullets) {
                var bullet = bullets[j];

                var r = enemy.w / 2;
                var x = (bullet.x - enemy.x);
                var y = (bullet.y - enemy.y);

                // 因为子弹比敌机要小,所以直接判断子弹是否和敌机相交即可
                if (x * x + y * y <= r * r) {

                    // 创建爆炸效果
                    create_boom(enemy.x, enemy.y);

                    // 移除子弹
                    this._bucket['bullet'].splice(j, 1);
                    // 移除飞机
                    this._bucket['enemy'].splice(i, 1);
                }
            }
        }
    }
}

function Sprite() {
    // 位置
    this.x = 0;
    this.y = 0;

    //宽高
    this.w = 0;
    this.h = 0;

    // 飞行速度
    this.speed = 0;

    // 图片
    this.img = null;

    // 类型
    this.kind = 0;

    // 原图位置
    this.rx = 0;
    this.ry = 0;
    this.rw = 0;
    this.rh = 0;
    this.ctx = null;

    this.draw = function () {
        this.ctx.drawImage(this.img, this.rx, this.ry,
            this.rw, this.rh,
            this.x - this.w / 2, this.y - this.h / 2,
            this.w, this.h);
    }
}

var Bullet = inherits(Sprite);
Bullet.prototype.hit = function () {
    return this.y <= 0;
}
Bullet.prototype.move = function () {
    this.y += this.speed;
};

var Enemy = inherits(Sprite);
Enemy.prototype.hit = function () {
    return this.y >= screenHeight;
}

Enemy.prototype.move = function () {
    this.y += this.speed;
};


var Boom = inherits(Sprite);
Boom.prototype.img_size = 3;

Boom.prototype.change_kind = function () {
    this.kind++;
    this.rx = (this.kind - 1) * this.rw;
    this.ry = 0;
}

Boom.prototype.move = function () {
    this.speed++;
    if (this.speed % 20 == 0)
        this.change_kind();
};

Boom.prototype.hit = function () {
    return this.kind == this.img_size;
}


var c = wx.createCanvas();
var ctx = c.getContext('2d');

var myplane = new Sprite();
myplane.status = 1; // 状态 1 表示正常  0 表示被命中

var img = wx.createImage();
var plane = wx.createImage();

var bgCanvas = null;
var offset = 0;
var w = 0;
var h = 0;
var screenWidth = c.width;
var screenHeight = c.height;

// 上一次飞机的位置
var lasted = { x: 0, y: 0 };
// 触摸区域是否在飞机内部
var in_plane = false;

// 创建计时器
var t = 0;



function init_bg() {
    bgCanvas = wx.createCanvas();
    bgCanvas.width = screenWidth;
    bgCanvas.height = screenHeight + h;

    var bgctx = bgCanvas.getContext('2d');

    var y = 0;
    var x = 0;

    // 底部多绘制一张图片
    while (y < screenHeight + h) {
        x = 0;
        while (x < screenWidth) {
            bgctx.drawImage(img, x, y, w, h);
            x += w;
        }
        y += h;
    }
}

function reset() {

    ctx.save();
    ctx.fillStyle = "#fff";
    ctx.fillRect(0, 0, c.width, c.height);
    ctx.restore();
}

function draw_copy() {
    ctx.save();
    ctx.textAlign = "center" // 居中对齐
    ctx.textBaseline = "middle" //垂直居中绘制
    ctx.fillStyle = "#aaa";
    ctx.font = "16px Arial" // 字体大小 16 像素
    ctx.fillText("简单教程,简单编程", c.width / 2, (c.height - 36))
    ctx.fillText(" © 2015-2018 www.twle.cn", c.width / 2, (c.height - 18));
    ctx.restore();
}

function animate_it() {

    reset(ctx);

    ctx.drawImage(bgCanvas, 0, offset, screenWidth, screenHeight, 0, 0, screenWidth, screenHeight);

    Bucket.move();
    Bucket.enemy_hit();
    Bucket.draw(ctx);

    if (myplane.status != 0) {
        ctx.drawImage(plane, 0, 0, 128, 128, lasted.x - 64, lasted.y - 64, 128, 128);
    }


    draw_copy();

    timeit();

    offset;
    if (offset % h == 0) {
        offset = 0;
    }

    requestAnimationFrame(animate_it);
}

wx.onShow(function () {
    Resource.item('audio/bgm.mp3').play();
})

wx.onAudioInterruptionBegin(function () {
    // 暂停音乐
    Resource.item('audio/bgm.mp3').stop();
    // 中断动画
    //cancelAnimationFrame(animate_it);
})

wx.onAudioInterruptionEnd(function () {

    Resource.item('audio/bgm.mp3').play()
    // 恢复动画
    cancelAnimationFrame(animate_it);
})



wx.onTouchStart(function (e) {

    var x = e.touches[0].clientX;
    var y = e.touches[0].clientY;
    if (plane_hit(x, y)) {
        in_plane = true;
    }
});


wx.onTouchEnd(function (e) {

    if (in_plane) {
        lasted.x = e.touches[0].clientX;
        lasted.y = e.touches[0].clientY;
        in_plane = false;
    }
});

// 触摸移动事件
wx.onTouchMove(function (e) {

    if (in_plane) {
        lasted.x = e.touches[0].clientX;
        lasted.y = e.touches[0].clientY;
    }
})

function plane_hit(x, y) {
    return x > (lasted.x - 64) &&
        x < (lasted.x + 64) &&
        y > (lasted.y - 64) &&
        y < (lasted.y + 64);
}

function start() {

    w = screenWidth > img.width ? img.width : screenWidth;
    h = img.height * (w / img.width);

    lasted.x = (screenWidth - 128) / 2;
    lasted.y = screenHeight - 128;

    Resource.item('audio/bgm.mp3').play();

    init_bg();
    ctx.drawImage(plane, 0, 0, 128, 128, lasted.x, lasted.y, 128, 128);
    draw_copy();
    requestAnimationFrame(animate_it);
}

function create_bullet(img) {
    var bullet = new Bullet();

    bullet.x = lasted.x;
    bullet.y = lasted.y;
    bullet.img = img;
    bullet.w = 30;
    bullet.h = 30;
    bullet.speed = - 2;
    bullet.kind = 1;
    bullet.rw = 60;
    bullet.rh = 60;
    bullet.ctx = ctx;

    Bucket.add(bullet, 'bullet');
}

function create_enemy(img) {
    var enemy = new Enemy();

    enemy.w = 50;
    enemy.h = 50;
    enemy.x = (enemy.w / 2) + Math.random() * (screenWidth - enemy.w / 2);
    enemy.y = -50;
    enemy.img = img;
    enemy.speed = 2;
    enemy.kind = 1;
    enemy.rw = 100;
    enemy.rh = 100;
    enemy.ctx = ctx;

    Bucket.add(enemy, 'enemy');
}


function create_boom(x, y) {
    var boom = new Boom();

    boom.w = 50;
    boom.h = 50;
    boom.x = x;
    boom.y = y;
    boom.img = Resource.item('images/boom.png');
    boom.speed = 0;
    boom.kind = 1;
    boom.rw = 100;
    boom.rh = 100;
    boom.ctx = ctx;

    Bucket.add(boom, 'boom');
}


function timeit() {

    if (t % 30 == 0) {
        var enemy = Resource.item('images/enemy.png');
        create_enemy(enemy);
    }


    if (myplane.status != 0 && in_plane && t % 20 == 0) {
        var bullet = Resource.item('images/bullet.png');
        create_bullet(bullet);
    }

    t++;

}


reset();


Resource.add('images/bg.jpg', 'image');
Resource.add('audio/bgm.mp3', 'audio', null, { loop: true });
Resource.add('images/plane.png', 'image');
Resource.add('images/bullet.png', 'image');
Resource.add('images/enemy.png', 'image');
Resource.add('images/boom.png', 'image');

Resource.loaded(function () {
    img = Resource.item('images/bg.jpg');
    plane = Resource.item('images/plane.png');
    start();
});

运行演示如下

关于   |   FAQ   |   我们的愿景   |   广告投放   |  博客

  简单教程,简单编程 - IT 入门首选站

Copyright © 2013-2022 简单教程 twle.cn All Rights Reserved.