createjs高级教程:createjs与dom的协作

  • 内容
  • 评论
  • 相关

今天这篇文章看名字是createjs与dom的协作,其实是createjs的游戏UI制作,非常重要,所以大家好好看。

一直以来大家用createjs都会有这样那样的问题,其中最难解决的就是什么?如果你有一定的基础,就大概率会说是性能和ui的问题。性能问题之前我博客里很多文章已经可以优化了,那么ui问题呢?确实相比同类的H5引擎,createjs在这方面确实是弱势,但是dom的ui已经非常完善了为什么还需要用canvas来实现呢?因为很多人不会协作,那么我今天就来讲createjs与dom和协作。

/=============2024/7/12更新==============/

由于多个dom可能互相影响,请把所有需要对接domElement的对象,css设置为:position: absolute;left: 0;top:0;

我下面的demo没影响是因为我canvas在最后面,并且之操作了一个dom。

其实createjs的官方已经给出了相关的协作类,那就是DOMElement,但是官方没有给出例子,下面我就来写个例子。

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>domElement的使用</title>
    <style>
        *{
            margin: 0;
            padding: 0;
        }
    </style>
</head>
<body>
<p id="testTxt" style="width: 200px;color: #ff0000">CreateJS是基于HTML5开发的一套模块化的库和工具。
    基于这些库,<span style="color: #00ff00;font-size: 20px">可以非常快捷地开发出基于HTML5的游戏</span>、动画和交互应用。</p>
<canvas id="canvas" width="1000" height="700"></canvas>
<script src="js/createjs-2015.11.26.min.js"></script>
<!--<script src="createjs-1.0.0.min.js"></script>-->
<script>
    var canvas = document.getElementById("canvas");
    var stage = new createjs.Stage(canvas);
    // var stage = new createjs.StageGL(canvas);//stagegl也支持
    var testTxt = document.getElementById("testTxt")
    var domElement = new createjs.DOMElement(testTxt);
    domElement.x = 200
    domElement.y = 200;
    domElement.regX = 100;
    domElement.regY = 100;
    domElement.htmlElement.onclick = function() {
        //它只支持原生的点击,并且不支持层级,遮罩等功能
        console.log("clicked");
    }
    stage.addChild(domElement)
    createjs.Ticker.setFPS(60);
    createjs.Ticker.addEventListener("tick",function (){
        domElement.rotation +=1;
        stage.update();
    })
</script>
</body>
</html>

演示地址:http://www.ajexoop.com/demo/DOMElementTest/demo1.html

大家点击链接就可以看到,里面是一个相当于富文本richText,里面有多种颜色大小并且在旋转,而且是可以选中的。

然后我们看代码,我new了一个DOMElement并把div传进去,我就可以像操作createjs中的显示对象一样操作dom,是不是很简单?

刚才我们是直接放在舞台上操作的,那DOMElement对象可不可以放入容器中么?我们试试。

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>容器中的domElement</title>
    <style>
        *{
            margin: 0;
            padding: 0;
        }
    </style>
</head>
<body>
<p id="testTxt" style="width: 200px;color: #ff0000">CreateJS是基于HTML5开发的一套模块化的库和工具。
    基于这些库,<span style="color: #00ff00;font-size: 20px">可以非常快捷地开发出基于HTML5的游戏</span>、动画和交互应用。</p>
<canvas id="canvas" width="1000" height="700"></canvas>
<script src="js/createjs-2015.11.26.min.js"></script>
<script>
    var canvas = document.getElementById("canvas");
    var stage = new createjs.Stage(canvas);
    var testTxt = document.getElementById("testTxt")
    var domElement = new createjs.DOMElement(testTxt);
    var container = new createjs.Container();
    stage.addChild(container);
    container.addChild(domElement);
    container.x = 200;
    container.y = 200;
    container.regX = 100;
    container.regY = 100;
    container.addEventListener("click",function (){
        console.log("clicked")//就算加了容器点击也是无效的
    })
    createjs.Ticker.setFPS(60);
    createjs.Ticker.addEventListener("tick",function (){
        container.rotation +=1;//使用容器操作一样可以
        stage.update();
    })
</script>
</body>
</html>

演示地址:http://www.ajexoop.com/demo/DOMElementTest/demo2.html

大家可以看到,在容器里也是可以实现的。

那么既然在容器里也可以,那么我们就举一反三,我们在animateCC中实现。animateCC2017以上的版本是可以直接放组件的,但是animateCC中组件的功能并不好,我们如果自己用dom写,就可以完全拥有dom的功能,想要什么样的组件都可以。下面看代码↓

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>animateCC与domElement和协作</title>
    <style>
        *{
            margin: 0;
            padding: 0;
        }
        .input_txt{
            color:#BAB1EE;width: 182px;height: 41px;background-color: #270C51;border:3px solid #4E2383;line-height: 41px;font-size: 14px;padding: 0 10px;
        }
        .open_btn{
            color:#000000;font-size: 50px;text-decoration: none;cursor: pointer;
        }
    </style>
</head>
<body onload="init()">
<a id="openBtn" class="open_btn">打开弹窗</a>
<input type="text" placeholder="请输入姓名" class="input_txt" id="nameInput">
<canvas id="canvas" width="1000" height="700"></canvas>
<script src="js/createjs-2015.11.26.min.js"></script>
<script src="js/assets.js"></script>
<script>
    var canvas, stage,pop
    function init()
    {
        canvas = document.getElementById("canvas");

        var loader = new createjs.LoadQueue(false);
        loader.addEventListener("fileload", handleFileLoad);
        loader.addEventListener("complete", handleComplete);
        loader.loadManifest(lib.properties.manifest);
    }

    function handleFileLoad(evt) {
        if (evt.item.type == "image") { images[evt.item.id] = evt.result; }
    }

    function handleComplete(evt) {

        stage = new createjs.Stage(canvas);

        var openBtn =  document.getElementById("openBtn");
        var openBtnElement = new createjs.DOMElement(openBtn);
        stage.addChild(openBtnElement);
        openBtnElement.htmlElement.onclick = function() {
            showHandler();
        }

        var nameInput = document.getElementById("nameInput");
        var domElement = new createjs.DOMElement(nameInput);
        domElement.x = 140;
        domElement.y = 80;
        pop = new lib.pop();//animate里的弹窗动画
        stage.addChild(pop);
        pop.win.con.addChild(domElement)//层级目录看fla文件
        pop.win.btn.addEventListener("click",function (){
            hideHandler();
        })

        createjs.Ticker.setFPS(60);
        createjs.Ticker.addEventListener("tick", stage);
    }
    function showHandler()
    {
        pop.gotoAndPlay(1);
    }
    function hideHandler()
    {
        pop.gotoAndStop(0);
    }
</script>
</body>
</html>

演示地址:http://www.ajexoop.com/demo/DOMElementTest/demo3.html

从演示地址中我们看到,我在弹窗中加了一个input,并且可以正常操作。然后我们看代码,代码也很简单,原来获取来的输入框DOMElement对象,我直接放进了animateCC的一个虚拟容器中(下载fla源文件可以看到我在弹窗中放了一个隐藏的容器),输入框可以正常的动画,正常的操作。这时候很多人问的“怎么在createjs放输入文本”的问题也解决了

但是这也是有问题的!!! 懂dom的前端看下demo在浏览器中的html结构就会明白,createjs的DOMElement只是在canvas的上面新建了dom来操作,并不是直接操作canvas中的对象,这就会很多问题,比如:层级,遮罩等等。

大家来看这个demo:

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>domElement的问题</title>
    <style>
        *{
            margin: 0;
            padding: 0;
        }
    </style>
</head>
<body>
<p id="testTxt" style="width: 200px;color: #ff0000">CreateJS是基于HTML5开发的一套模块化的库和工具。
    基于这些库,<span style="color: #00ff00;font-size: 20px">可以非常快捷地开发出基于HTML5的游戏</span>、动画和交互应用。</p>
<canvas id="canvas" width="1000" height="700"></canvas>
<script src="js/createjs-2015.11.26.min.js"></script>
<script>
    var canvas = document.getElementById("canvas");
    var stage = new createjs.Stage(canvas);
    var testTxt = document.getElementById("testTxt")
    var domElement = new createjs.DOMElement(testTxt);
    domElement.x = 200
    domElement.y = 200;
    domElement.regX = 100;
    domElement.regY = 100;
    stage.addChild(domElement)
    var bitmap = new createjs.Bitmap("images/100.jpg");
    bitmap.x = 200;
    bitmap.y = 200;
    stage.addChild(bitmap);//背景图也不能置于上面
    var shape = new createjs.Shape();
    shape.graphics.beginFill("#FF0000");
    shape.graphics.drawRect(0,0,50,50);
    shape.graphics.endFill();
    shape.x = 200;
    shape.y = 200;
    domElement.mask = shape;//遮罩无效
    createjs.Ticker.setFPS(60);
    createjs.Ticker.addEventListener("tick",function (){
        domElement.rotation +=1;
        stage.update();
    })
</script>
</body>
</html>

演示地址:http://www.ajexoop.com/demo/DOMElementTest/demo4.html

这个demo中的层级和遮罩都失效了,这是一个非常严重的问题,是一个必须要解决的问题,那怎么解决呢?

这时候真正的高级教程就来了,那就是利用像素拷贝来解决问题,不多说上代码:

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>createjs的像素拷贝</title>
    <style>
        *{
            margin: 0;
            padding: 0;
        }
    </style>
</head>
<body>
<p id="testTxt" style="width: 200px;color: #ff0000;position: absolute;left: -9999px">CreateJS是基于HTML5开发的一套模块化的库和工具。
    基于这些库,<span style="color: #00ff00;font-size: 20px">可以非常快捷地开发出基于HTML5的游戏</span>、动画和交互应用。</p>
<canvas id="canvas" width="1000" height="700"></canvas>
<script src="js/createjs-2015.11.26.min.js"></script>
<script src="js/html2canvas.min.js"></script>
<script>
    var canvas = document.getElementById("canvas");
    var stage = new createjs.Stage(canvas);
    var testTxt = document.getElementById("testTxt")
    var bitmap;

    html2canvas(testTxt).then(function(cc) {
        bitmap = new createjs.Bitmap(cc);
        stage.addChild(bitmap);
        bitmap.regX = 100;
        bitmap.regY = 100;
        bitmap.x = 200;
        bitmap.y = 200;
        var shape = new createjs.Shape();
        shape.graphics.beginFill("#ff0000");
        shape.graphics.drawCircle(0,0,30);
        shape.graphics.endFill();
        shape.x = 200;
        shape.y = 200;
        bitmap.mask = shape;
        testTxt.style.display='none';//用完后隐藏或者销毁
        var bg = new createjs.Bitmap("images/100.jpg");
        bg.x = 100;
        bg.y = 100;
        stage.addChild(bg);//这时候层级也生效了
    });
    createjs.Ticker.setFPS(60);
    createjs.Ticker.addEventListener("tick",function (){
        bitmap.rotation +=1;
        stage.update();
    })
</script>
</body>
</html>

演示地址:http://www.ajexoop.com/demo/DOMElementTest/demo5.html

这里额外先讲一下html2canvas,这个js的功能就是截图,就是像素拷贝,很好理解,网上自己去下就可以了。

看demo,原理很简单,就是用canvas拷贝dom中的像素,然后再转化为createjs的对象,这时候遮罩和层级就完全恢复了,通过像素拷贝过的Bitmap跟操作平时的Bitmap没什么两样。但是这时候他已经变成了图片是不能交互的,但是我们可以通过别的交互,比如点击,再把原来的dom通过DOMElement调出来,dom就又可以顺利的交互了(如果交互的时候需要调用层级,遮罩,滤镜,叠加模式,就必须要把这些用dom实现,然后用DOMElement转进来,不过一般很少交互的时候会有层级,遮罩,滤镜,叠加模式)。

大家以后用createjs做游戏ui的时候就可以用上面的方法制作,附上下载地址。

下载地址:https://pan.baidu.com/s/1FZhWCa1OB1xtj6QT9pebyw

好了文章讲完了,通过这篇文章大家除了理解做法还知道了dom的重要性,所以flash出身的程序员还是要学dom和css的,就像前端要学animateCC要学游戏逻辑一样,这种时候前端的优势就很明显了。

最后,如果大家还有问题可以在博客下面留言,也可以在createjs群里找我。

1542183776360437.jpg

评论

2条评论
  1. Gravatar 头像

    yang 回复

    楼主用createJs做过那种问答形式的H5推广页面吗?

发表评论

电子邮件地址不会被公开。