为了账号安全,请及时绑定邮箱和手机立即绑定

做一个游戏引擎的Demo-弹幕大战

做一个游戏引擎的Demo-弹幕大战

还记得上次我们开发的那个游戏引擎吗?又经过几次更新维护,终于可以编写这游戏引擎的Demo啦!

注意:该游戏引擎已经过大换血,所以最好去查看一下我在GitHub上的README再看接下来的内容。

这次是要开发什么游戏呢?这次的游戏是结合弹幕与飞机大战于一身的游戏——弹幕大战。

这首先是什么玩法呢?先看看下面的演示:
图片描述

游戏功能

功能操作 功能
鼠标移动 控制飞机左右移动
按下空格 发射子弹
按下回车 创建子弹墙

根据以上内容,我们可以制定文件结构了:
图片描述

首先咱需要准备几张图片与影片(都在GitHub上),然后编写基本html代码。

<!DOCTYPE html>
<html lang="cn">
<head>
    <meta charset="UTF-8">
    <title>弹幕大战</title>
    <link rel="icon" href="img/logo.ico"/>
    <link type="text/css" rel="stylesheet" href="css/index.css"/>
    <script type="text/javascript" class="lazyload" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB/AAffA0nNPuCLAAAAAElFTkSuQmCC" data-original="webfire/js/jQuery-v3.3.1.js"></script>
    <script type="text/javascript" class="lazyload" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB/AAffA0nNPuCLAAAAAElFTkSuQmCC" data-original="webfire/js/obj.js"></script>
    <script type="text/javascript" class="lazyload" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB/AAffA0nNPuCLAAAAAElFTkSuQmCC" data-original="webfire/js/physics.js"></script>
</head>
<body>
<header>
    <img class="lazyload" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB/AAffA0nNPuCLAAAAAElFTkSuQmCC" data-original="img/logo.png" width="50">
    <h1>弹幕大战</h1>
    <h4>文字中的战斗机<br/>文字版飞机大战</h4>
    <h1>        </h1>
    <h4><span>歼灭数:</span><span id="killNum">0</span><br/><span>剩余血量:</span><span id="bloodNum">20</span></h4>
</header>
<main id="main">
    <video class="lazyload" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB/AAffA0nNPuCLAAAAAElFTkSuQmCC" data-original="movies/test.mp4" id="movie" loop="loop" autoplay="autoplay"></video>
</main>
<script type="text/javascript" class="lazyload" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB/AAffA0nNPuCLAAAAAElFTkSuQmCC" data-original="js/index.js"></script>
</body>
</html>

这样就完成了html结构。

都说如果html是名词,那么css就是形容词,一个漂亮的游戏总是需要css的帮助的,所以,可以编写index.css,让我们的网页更漂亮。

header{
    background-color: crimson;
    height: 50px;
    width: 100%;
    position: absolute;
    top: 0;
    left: 0;
    color: #fff;
}
header *{
    margin-right: 10px;
    margin-top: 0;
    float: left;
}
main{
    overflow: hidden;
}
#movie{
    position: absolute;
    top: 50px;
    left: 0;
    z-index: -2;
}

这下子,再去浏览器查看一遍,是不是好多了?

接着,开始编写游戏主逻辑。

首先不管后面的视频,将用户飞机移动的逻辑做好。

// 创建对象
var posY = screen.height - 200;
var me = new role({
    image: "img/me.png",
    width: 100,
    height: 50,
    type: "img",
    name: "me",
    x: screen.width / 2 - 50,
    y: posY,
    pos: "main"
});
var blood = $("#bloodNum");
var kill = $("#killNum");
var bloodNum = 20;
var killNum = 0;
me.speed = 3;
// 添加事件监听
$(document).mousemove(function (e) {
    me.move(e.pageX - 50,posY);
    bullet.move(e.pageX - 50,posY - 5);
});

接着发射子弹的逻辑,可以首先定义一个子弹的游戏对象,然后不断克隆它:

var bullet = new role({
    image: "webfire/img/outText.png",
    width: 100,
    height: 100,
    type: "img",
    name: "bullet",
    x: me.x,
    y: me.y - 5,
    pos: "main"
});
bullet.setText({
    text: "^",
    size: 30,
    color: "#f00"
});
bullet.webEntity.fadeOut(0);
$(document).keydown(function (e) {
    switch (e.keyCode){
        case 32:// space
            var newBullet = bullet.copy();
            newBullet.setText({
                text: "^",
                color: "#f00",
                size: 30
            });
            var Interval = setInterval(function () {
                if (newBullet.die){
                    clearInterval(Interval);
                } else {
                    newBullet.run(270);
                    if (newBullet.y <= 60){
                        newBullet.del("none",0);
                        clearInterval(Interval);
                    }
                }
            },10);
            window.moveTo(0,0);
            break;
    }
});

然后可以再实现创建子弹墙了:

var can = false;
$(document).keydown(function (e) {
    switch (e.keyCode){
        case 13:
            can = false;
            for (var i = 0 ; i < 15 ; i++){
                for (var j = 0 ; j < 5 ; j++){
                    var newBullet = bullet.copy();
                    newBullet.setText({
                        text: "^",
                        color: "#f00",
                        size: 30
                    });
                    newBullet.move(i * 30 + me.x,j * 30 + 300);
                }
            }
            setTimeout(function () {
                can = true;
            },10000);
            break;
    }
});
setTimeout(function () {
    can = true;
},10000);

再将这两个语句合并,变为:

var can = false;
$(document).keydown(function (e) {
    switch (e.keyCode){
        case 32:// space
            var newBullet = bullet.copy();
            newBullet.setText({
                text: "^",
                color: "#f00",
                size: 30
            });
            var Interval = setInterval(function () {
                if (newBullet.die){
                    clearInterval(Interval);
                } else {
                    newBullet.run(270);
                    if (newBullet.y <= 60){
                        newBullet.del("none",0);
                        clearInterval(Interval);
                    }
                }
            },10);
            window.moveTo(0,0);
            break;
        case 13:
            can = false;
            for (var i = 0 ; i < 15 ; i++){
                for (var j = 0 ; j < 5 ; j++){
                    var newBullet = bullet.copy();
                    newBullet.setText({
                        text: "^",
                        color: "#f00",
                        size: 30
                    });
                    newBullet.move(i * 30 + me.x,j * 30 + 300);
                }
            }
            setTimeout(function () {
                can = true;
            },10000);
            break;
    }
});
setTimeout(function () {
    can = true;
},10000);

阅读上面的源码后,细心的朋友可能发现了,剩下的敌人对象的名字是不是叫"em"呢?是的,正是如此,而且实现方法与子弹的创建实现方法也如出一辙,只不过需要一个数组来存储敌人弹幕的文字罢了与随机颜色罢了。

var em = new role({
    image: "webfire/img/outText.png",
    width: 50,
    height: 50,
    type: "img",
    name: "em",
    x: 0,
    y: 50,
    pos: "main"
});
var texts = ["emmm","哈哈","_","打call","尬聊","你的良心不会痛吗?","惊不惊喜,意不意外","皮皮虾,我们走","扎心了,老铁","还有这种操作?","怼","你有freestyle吗?","油腻"];
em.webEntity.fadeOut(0);
var gameLoop = setInterval(function () {
    var newEm = em.copy();
    newEm.move(Math.floor(Math.random() * screen.width - 100),newEm.y);
    newEm.setText({
        text: texts[Math.floor(Math.random() * texts.length)],
        size: 10,
        color: color.hex({
            r: Math.floor(Math.random() * 255),
            g: Math.floor(Math.random() * 255),
            b: Math.floor(Math.random() * 255)
        })
    });
    var interval = setInterval(function () {
        newEm.run(90);
        var collisionObjs = collisionObj(newEm);
        if (collisionObjs.length){
            for (var i = 0 ; i < collisionObjs.length ; i++){
                if (collisionObjs[i].name == "bullet"){
                    newEm.del("none",0);
                    killNum++;
                    kill.html(killNum);
                    collisionObjs[i].del("none",0);
                    gameObjs.splice(collisionObjs[i].id,1);
                    clearInterval(interval);
                    break;
                } else if (collisionObjs[i].name == "me"){
                    newEm.del("none",0);
                    clearInterval(interval);
                    bloodNum--;
                    blood.html(bloodNum);
                    if (bloodNum <= 0){
                        clearInterval(gameLoop);
                        for (var j in gameObjs){
                            gameObjs[j].del("none",0);
                        }
                        alert("游戏结束");
                    }
                }
            }
        }
        if (newEm.y >= (screen.height - 200)){
            newEm.del("none",0);
            clearInterval(interval);
        }
    },100);
},100);

现在实现完成后,大部分功能是实现了,只是还有一个小问题,就是子弹可能会在飞机上面,所以这还有一个小优化:

me.setCss({
    "z-index": "1"
});
bullet.setCss({
    "z-index": "0"
});
em.setCss({
    "z-index": "-1"
});

最后,就到令人轻松的话题了,终于可以实现影片播放啦!html的dom结构已经组织好,只差js的点睛之笔了。

var movie = $("#movie");
movie.attr("width",screen.width + "px");
movie.attr("height",screen.height - 125 + "px");

现在代码编写完成,全部代码如下:

index.html

<!DOCTYPE html>
<html lang="cn">
<head>
    <meta charset="UTF-8">
    <title>弹幕大战</title>
    <link rel="icon" href="img/logo.ico"/>
    <link type="text/css" rel="stylesheet" href="css/index.css"/>
    <script type="text/javascript" class="lazyload" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB/AAffA0nNPuCLAAAAAElFTkSuQmCC" data-original="webfire/js/jQuery-v3.3.1.js"></script>
    <script type="text/javascript" class="lazyload" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB/AAffA0nNPuCLAAAAAElFTkSuQmCC" data-original="webfire/js/obj.js"></script>
    <script type="text/javascript" class="lazyload" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB/AAffA0nNPuCLAAAAAElFTkSuQmCC" data-original="webfire/js/physics.js"></script>
</head>
<body>
<header>
    <img class="lazyload" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB/AAffA0nNPuCLAAAAAElFTkSuQmCC" data-original="img/logo.png" width="50">
    <h1>弹幕大战</h1>
    <h4>文字中的战斗机<br/>文字版飞机大战</h4>
    <h1>        </h1>
    <h4><span>歼灭数:</span><span id="killNum">0</span><br/><span>剩余血量:</span><span id="bloodNum">20</span></h4>
</header>
<main id="main">
    <video class="lazyload" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB/AAffA0nNPuCLAAAAAElFTkSuQmCC" data-original="movies/test.mp4" id="movie" loop="loop" autoplay="autoplay"></video>
</main>
<script type="text/javascript" class="lazyload" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB/AAffA0nNPuCLAAAAAElFTkSuQmCC" data-original="js/index.js"></script>
</body>
</html>

index.js

var posY = screen.height - 200;
var me = new role({
    image: "img/me.png",
    width: 100,
    height: 50,
    type: "img",
    name: "me",
    x: screen.width / 2 - 50,
    y: posY,
    pos: "main"
});
var bullet = new role({
    image: "webfire/img/outText.png",
    width: 100,
    height: 100,
    type: "img",
    name: "bullet",
    x: me.x,
    y: me.y - 5,
    pos: "main"
});
var em = new role({
    image: "webfire/img/outText.png",
    width: 50,
    height: 50,
    type: "img",
    name: "em",
    x: 0,
    y: 50,
    pos: "main"
});
var blood = $("#bloodNum");
var kill = $("#killNum");
var bloodNum = 20;
var killNum = 0;
var can = false;
var texts = ["emmm","哈哈","_","打call","尬聊","你的良心不会痛吗?","惊不惊喜,意不意外","皮皮虾,我们走","扎心了,老铁","还有这种操作?","怼","你有freestyle吗?","油腻"];
bullet.setText({
    text: "^",
    size: 30,
    color: "#f00"
});
me.setCss({
    "z-index": "1"
});
bullet.setCss({
    "z-index": "0"
});
em.setCss({
    "z-index": "-1"
});
bullet.webEntity.fadeOut(0);
em.webEntity.fadeOut(0);
me.speed = 3;
$(document).keydown(function (e) {
    switch (e.keyCode){
        case 32:// space
            var newBullet = bullet.copy();
            newBullet.setText({
                text: "^",
                color: "#f00",
                size: 30
            });
            var Interval = setInterval(function () {
                if (newBullet.die){
                    clearInterval(Interval);
                } else {
                    newBullet.run(270);
                    if (newBullet.y <= 60){
                        newBullet.del("none",0);
                        clearInterval(Interval);
                    }
                }
            },10);
            window.moveTo(0,0);
            break;
        case 13:
            can = false;
            for (var i = 0 ; i < 15 ; i++){
                for (var j = 0 ; j < 5 ; j++){
                    var newBullet = bullet.copy();
                    newBullet.setText({
                        text: "^",
                        color: "#f00",
                        size: 30
                    });
                    newBullet.move(i * 30 + me.x,j * 30 + 300);
                }
            }
            setTimeout(function () {
                can = true;
            },10000);
            break;
    }
});
var gameLoop = setInterval(function () {
    var newEm = em.copy();
    newEm.move(Math.floor(Math.random() * screen.width - 100),newEm.y);
    newEm.setText({
        text: texts[Math.floor(Math.random() * texts.length)],
        size: 10,
        color: color.hex({
            r: Math.floor(Math.random() * 255),
            g: Math.floor(Math.random() * 255),
            b: Math.floor(Math.random() * 255)
        })
    });
    var interval = setInterval(function () {
        newEm.run(90);
        var collisionObjs = collisionObj(newEm);
        if (collisionObjs.length){
            for (var i = 0 ; i < collisionObjs.length ; i++){
                if (collisionObjs[i].name == "bullet"){
                    newEm.del("none",0);
                    killNum++;
                    kill.html(killNum);
                    collisionObjs[i].del("none",0);
                    gameObjs.splice(collisionObjs[i].id,1);
                    clearInterval(interval);
                    break;
                } else if (collisionObjs[i].name == "me"){
                    newEm.del("none",0);
                    clearInterval(interval);
                    bloodNum--;
                    blood.html(bloodNum);
                    if (bloodNum <= 0){
                        clearInterval(gameLoop);
                        for (var j in gameObjs){
                            gameObjs[j].del("none",0);
                        }
                        alert("游戏结束");
                    }
                }
            }
        }
        if (newEm.y >= (screen.height - 200)){
            newEm.del("none",0);
            clearInterval(interval);
        }
    },100);
},100);
$(document).mousemove(function (e) {
    me.move(e.pageX - 50,posY);
    bullet.move(e.pageX - 50,posY - 5);
});
setTimeout(function () {
    can = true;
},10000);
var movie = $("#movie");
movie.attr("width",screen.width + "px");
movie.attr("height",screen.height - 125 + "px");

index.css

header{
    background-color: crimson;
    height: 50px;
    width: 100%;
    position: absolute;
    top: 0;
    left: 0;
    color: #fff;
}
header *{
    margin-right: 10px;
    margin-top: 0;
    float: left;
}
main{
    overflow: hidden;
}
#movie{
    position: absolute;
    top: 50px;
    left: 0;
    z-index: -2;
}

[完]

点击查看更多内容
7人点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
全栈工程师
手记
粉丝
54
获赞与收藏
183

关注作者,订阅最新文章

阅读免费教程

感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消