HTML5游戏系列(2):装B达人

本文详细介绍了HTML5游戏‘装B达人’的开发过程,包括游戏流程、技术框架(使用Canvas和CreateJS)、实现流程。游戏通过Canvas进行实时绘图,借助CreateJS的EaselJS、TweenJS等组件进行交互和动画处理。玩家通过移动篮子接住下落的B,碰撞检测和动画更新都在JavaScript中实现。
摘要由CSDN通过智能技术生成

HTML5游戏系列(2):装B达人 由David发表在天码营 

小编的第一款HTML游戏:“你能戳几下?”引起了微信圈不错的反响,这更加激发了“天码营”团队以及小编本人的斗志。此次小编带来了可玩性更强的HTML5游戏:“装B达人”!还没有玩过的可以关注天码营公众号“TMY-EDE”并获取最新文章即可得到游戏链接。也可以直接打开链接: http://tianmaying.com/app/collect-b/

下面便开始详述“装B达人”是怎样炼就的!先上图,一睹为快:

简介

游戏流程

B会不断地从天而降,玩家可以移动篮子来装B,我们会给出装B计数。一旦B已经接触地面在本次装B失败,游戏结束(Game Over~)。

技术框架

本游戏的实现借助于HTML5提供的Canvas标签,Canvas是一个基于位图的矩形绘图区域,该标签最初由Safari提供支持,在2014年10月终于被纳入HTML标准。进入HTML标准意味着主流浏览器都将对此提供支持,Google在Android4.0中便对Canvas提供了硬件加速。这意味着在HTML中复杂的游戏也可以做到很好的性能。

Canvas: a resolution-dependent bitmap canvas which can be used for rendering graphs, game graphics, or other visual images on the fly. -- HTML5, W3C

“装B达人”引入了CreateJS来进行更方便的Canvas操作,以及Sprite素材的载入。

CreateJS: A suite of modular libraries and tools which work together or independently to enable rich interactive content on open web technologies via HTML5.

CreateJS是一个组件库,它提供了四部分的工具:

  1. EaselJS:提供了更加方便的Canvas操作,这是我们主要使用的一个组件。
  2. TweenJS:更方便地进行HTML5中元素属性的渐变和动画。
  3. SoundJS:提供了丰富的音频处理API。
  4. PreloadJS:用来管理Web资源的载入,我们用它来载入图片素材,并形成一个Sprite对象以供使用。

实现流程

理论上HTML文件只需提供一个canvas标签,其它的交给JS来处理。最终的实现也是这样的,HTML框架非常简单,只需引入需要的样式的脚本即可。在脚本中完成游戏的初始化过程与交互动画。

首先利用PreloadJS载入需要的图片素材;然后用这些素材来初始化整个场景。此后游戏就可以开始啦!游戏开始后,我们需要在Tick(时钟)事件到达时重新绘图,完成如下几个操作:

  1. 让B下落。只需增加该元素的y属性。
  2. 检测B与地面的碰撞。如果发生碰撞则游戏结束。
  3. 检测B与篮子的碰撞。如果发生碰撞则分数+1,从天上再掉下一个B。

为了让玩家能够移动篮子,需要监听mousedownpressmove事件:

  1. mousedown时,记录按下的位置。
  2. pressmove时,计算与mousedown时的位置差,并相应地移动篮子。

HTML框架

“装B达人”使用HTML5 Canvas实现,因此HTML框架非常简单。只需定义一个<canvas>并在HTML头部引入相应的样式和JS即可!

<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="initial-scale=1.0, user-scalable=no"/>
  <link rel="stylesheet" href="assets/css/main.css">

  <script src="assets/lib/easeljs-NEXT.combined.js"></script>
  <script src="assets/lib/preloadjs-NEXT.min.js"></script>
  <script src="assets/lib/tweenjs-NEXT.min.js"></script>
  <script src="assets/js/main.js"></script>
</head>

<body>
  <canvas id="testCanvas"></canvas>
</body>
</html>

其中的easeljs-NEXTpreloads-NEXTtweenjs-NEXTCreateJS提供的Canvas工具,这三个文件可以在参考代码中下载;我们的所有编程工作都在main.cssmain.js中,请手动新建这两个文件!

全局样式

样式很简单啦,只需要样canvas全屏即可:

/* css/main.css */
html, body{
    padding: 0;
    margin: 0;
}

因为有些浏览器的UA默认样式表会为htmlbody提供边距,所以我们需要设置它们的内外边距为0.

初始化场景

说道游戏,你首先想到的概念可能是:场景、模型、灯光、动画。游戏引擎们尽可能地封装了这些数据和操作,尤其在JavaScript中这些概念只会更简单!我们看看CreateJS中,如何创建一个初始的场景!

首先你需要从参考代码中把图片素材都解压出来。然后建立一个素材清单:

// file: js/main.js
manifest = [
    {src: "sky.png", id: "sky"},
    {src: "ground.png", id: "ground"},
    {src: "hill1.png", id: "hill"},
    {src: "hill2.png", id: "hill2"},
    {src: "b.png", id: "b"},
    {src: 'basket.png', id: 'basket'}
];

接着,我们需要载入这些素材,并初始化场景。

// file: js/main.js
var score = 0, w, h, bs = [];    // 全局变量:得分、画布宽高、B的数组
document.addEventListener('DOMContentLoaded', function(){
    $canvas = document.getElementById('testCanvas');
    $canvas.setAttribute('width', window.innerWidth);
    $canvas.setAttribute('height', window.innerHeight);

    stage = new createjs.Stage($canvas);
    w = stage.canvas.width;
    h = stage.canvas.height;

    loader = new createjs.LoadQueue(false);
    loader.addEventListener("complete", handleComplete);
    loader.loadManifest(manifest, true, "assets/art/");
});

在CreateJS中,出于性能考虑,图片清单是异步加载的。当我们给出的图片清单加载完毕时,handleComplete()会被调用。在handleComplete中素材都已下载完毕,我们需要设置这些图片的位置,变换,以及平铺属性:

function handleComplete() {
    // 分数文本:放在右上角,红色
    scoreText = new createjs.Text("", "bold 28px Impact", "red");
    scoreText.x = w - 20;
    scoreText.y = 10;

    // 天空:横向平铺。地面和山丘也是类似的,请见参考代码
    var skyImg = loader.getResult("sky");
    sky.graphics.beginBitmapFill(skyImg, 'repeat-x').drawRect(0, 0, w, h);

    // 篮筐:为了方便动画,将中心点设为参考点
    basketImg = loader.getResult('basket');
    basket = new createjs.Bitmap(basketImg);
    basket.regX = basketImg.width / 2;
    basket.regY = basketImg.height / 2;
    basketRange = {
        x: basket.regX,
        y: basket.regY,
        width: w - basketImg.width,
        height: h - groundImg.height - basketImg.height
    };

    // 把上述对象添加到场景中
    stage.addChild(skybg, sky, hill, ground, trolley, scoreText);

    // 获取B的图片
    bImg = loader.getResult("b");
    brange = {
        width: w - bImg.width,
        height: h - groundImg.height
    };

    // 把它们都添加到场景中
    for (var i = 0; i < 5; i++) {    // 为什么是5?见下一节
        var b = new createjs.Bitmap(bImg);
        initB(b);                    // 初始化B,见下一节
        bs.push(b); stage.addChild(b);
    }

    // 更新这个场景,触发canvas刷新
    stage.update();
}

初始化B

游戏中会有大量的B从天而降,为了保证性能我们手动地管理B的缓存。基于我们的观察,在任何一刻的画面中B的数量都是有限的。不妨就此规定B的数量,比如5个。当一个B被收集或者落地时,我们回收它,让它重新从天而降。回收和初始化B都是用initB()函数:

function initB(b){  
    b.regX = bImg.width / 2;
    b.regY = bImg.height / 2;  
    // 随机生成一个在当前场景上方的位置。
    b.x = Math.random() * (brange.width - bImg.width) + b.regX;
    b.y = Math.random() * brange.height - brange.height - bImg.height / 2;
}

掉落动画

随着时间的推移,B应当从天而降。为了逐帧地更新动画,在handleComplete()函数最后监听时钟:

createjs.Ticker.addEventListener("tick", tick);

其中的tick函数中,我们需要让B往下落,同时要检测B是否被收集了,以及B是否碰到地面了。

function tick(){
    // event.delta是距离上次`tick`的时间,以毫秒计
    // 将时间变换为距离,0.15是可调参数,其物理意义是下落速度 v = s/t
    var deltaS = event.delta * 0.15;

    // 遍历所有的B
    bs.forEach(function (b) {
        if (b.inCollision) return;    // 如果它已经触地,则返回
        b.y += deltaS;                // 让它下落!

        if (collisionX(b, basket)) {  // b和basket的碰撞检测,见下一节
            b.inCollision = true;
            score ++;                 // 更新分数
            scoreText.text = score + 'B';
            initB(b);                 // 初始化B,让它重新从天而降
        }
        else if (b.y + b.regY >= brange.height) {
            b.inCollision = true;     // b碰到地面啦,游戏结束
            gameOver();
        }
    });

    // 刷新canvas
    stage.update(event);
}

function gameOver(){
    // 游戏结束!
    // 以任何形式告知用户
}

碰撞检测

上述的掉落动画中,我们调用了B和basket的碰撞检测,CreateJS并未提供这样的高阶功能,但矩形的碰撞检测并不困难!

function collisionX(a, b) {
    return a.x + a.regX > b.x - b.regX    // a的右边超出了b的左边
        && a.x - a.regX < b.x + b.regX    // b的右边超出了a的左边
        && a.y + a.regY > b.y - b.regY    // a的下边超出了b的上边
        && a.y - a.regY < b.y + b.regY;   // b的下边超出了a的上边
}

可执行的、完整的代码见此处参考代码


更多文章请访问 天码营网站




  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值