【问题标题】:How to make animation out of canvas images in Kinetic.js?如何在 Kinetic.js 中使用画布图像制作动画?
【发布时间】:2013-09-14 15:26:23
【问题描述】:

我有以下代码应该是动画的三帧,我怎样才能将它们变成 Kinetic.js 中的动画?这是一个像吃豆人一样的六角形,可以打开和关闭它的嘴。 我有三个画布图像,作为三个框架,Kinetic.js 中是否有任何内置函数可以做到这一点?还是我应该从头开始创建一个?在我制作了精灵之后,我怎样才能在不破坏动画的情况下进行其他动画,例如移动它或旋转它(吃豆人应该仍然张开和关闭它的嘴)?

        pacMan1 = new Kinetic.Shape({
            x: 15,
            y: 13,
            //fill: 'rgb(62, 53, 67)',
            // a Kinetic.Canvas renderer is passed into the drawFunc function
            drawFunc: function (canvas) {
                var context = canvas.getContext();
                // layer1/Compound Path
                context.save();
                context.beginPath();

                // layer1/Compound Path/Path
                context.moveTo(54.0, 12.8);
                context.lineTo(34.2, 1.4);
                context.bezierCurveTo(31.2, -0.3, 27.6, -0.3, 24.7, 1.4);
                context.lineTo(4.9, 12.8);
                context.bezierCurveTo(1.9, 14.5, 0.1, 17.7, 0.1, 21.0);
                context.lineTo(0.1, 43.9);
                context.bezierCurveTo(0.1, 47.3, 1.9, 50.5, 4.9, 52.1);
                context.lineTo(24.7, 63.6);
                context.bezierCurveTo(27.6, 65.3, 31.2, 65.3, 34.2, 63.6);
                context.lineTo(54.0, 52.1);
                context.bezierCurveTo(56.9, 50.5, 58.7, 47.3, 58.7, 43.9);
                context.lineTo(58.7, 21.0);
                context.bezierCurveTo(58.7, 17.7, 56.9, 14.5, 54.0, 12.8);
                context.closePath();

                // layer1/Compound Path/Path
                context.moveTo(32.3, 10.8);
                context.bezierCurveTo(30.7, 10.8, 29.5, 9.5, 29.5, 8.0);
                context.bezierCurveTo(29.5, 6.4, 30.7, 5.1, 32.3, 5.1);
                context.bezierCurveTo(33.9, 5.1, 35.1, 6.4, 35.1, 8.0);
                context.bezierCurveTo(35.1, 9.5, 33.9, 10.8, 32.3, 10.8);
                context.closePath();
                context.fillStyle = "rgb(62, 53, 67)";
                context.fill();
                context.lineWidth = 0.3;
                context.stroke();
                canvas.fillStroke(this);
                context.restore();
            }
        });
        pacMan2 = new Kinetic.Shape({
            x: 15,
            y: 13,
            //fill: 'rgb(62, 53, 67)',
            // a Kinetic.Canvas renderer is passed into the drawFunc function
            drawFunc: function (canvas) {
                var context = canvas.getContext();
                // layer1/Compound Path
                context.save();
                context.beginPath();

                // layer1/Compound Path/Path
                context.moveTo(29.1, 36.9);
                context.bezierCurveTo(27.6, 36.0, 26.7, 34.5, 26.7, 32.8);
                context.bezierCurveTo(26.7, 31.2, 27.6, 29.6, 29.1, 28.8);
                context.lineTo(55.2, 13.7);
                context.bezierCurveTo(54.8, 13.4, 54.4, 13.1, 54.0, 12.8);
                context.lineTo(34.2, 1.4);
                context.bezierCurveTo(31.2, -0.3, 27.6, -0.3, 24.7, 1.4);
                context.lineTo(4.9, 12.8);
                context.bezierCurveTo(1.9, 14.5, 0.1, 17.7, 0.1, 21.0);
                context.lineTo(0.1, 43.9);
                context.bezierCurveTo(0.1, 47.3, 1.9, 50.5, 4.9, 52.1);
                context.lineTo(24.7, 63.6);
                context.bezierCurveTo(27.6, 65.3, 31.2, 65.3, 34.2, 63.6);
                context.lineTo(54.0, 52.1);
                context.bezierCurveTo(54.2, 52.0, 54.5, 51.8, 54.7, 51.7);
                context.lineTo(29.1, 36.9);
                context.closePath();

                // layer1/Compound Path/Path
                context.moveTo(32.3, 5.1);
                context.bezierCurveTo(33.9, 5.1, 35.1, 6.4, 35.1, 8.0);
                context.bezierCurveTo(35.1, 9.5, 33.9, 10.8, 32.3, 10.8);
                context.bezierCurveTo(30.7, 10.8, 29.5, 9.5, 29.5, 8.0);
                context.bezierCurveTo(29.5, 6.4, 30.7, 5.1, 32.3, 5.1);
                context.closePath();
                context.fillStyle = "rgb(62, 53, 67)";
                context.fill();
                context.lineWidth = 0.3;
                context.stroke();
                canvas.fillStroke(this);
                context.restore();
            }
        });
        pacMan3 = new Kinetic.Shape({
            x: 15,
            y: 13,
            //fill: 'rgb(62, 53, 67)',
            // a Kinetic.Canvas renderer is passed into the drawFunc function
            drawFunc: function (canvas) {
                var context = canvas.getContext();
                    // layer1/Compound Path
                    context.save();
                    context.beginPath();

                    // layer1/Compound Path/Path
                    context.moveTo(32.0, 36.9);
                    context.bezierCurveTo(28.7, 36.0, 26.7, 34.5, 26.7, 32.8);
                    context.bezierCurveTo(26.7, 31.2, 28.7, 29.6, 32.0, 28.8);
                    context.lineTo(58.7, 22.0);
                    context.lineTo(58.7, 21.0);
                    context.bezierCurveTo(58.7, 17.7, 56.9, 14.5, 54.0, 12.8);
                    context.lineTo(34.2, 1.4);
                    context.bezierCurveTo(31.2, -0.3, 27.6, -0.3, 24.7, 1.4);
                    context.lineTo(4.9, 12.8);
                    context.bezierCurveTo(1.9, 14.5, 0.1, 17.7, 0.1, 21.0);
                    context.lineTo(0.1, 43.9);
                    context.bezierCurveTo(0.1, 47.3, 1.9, 50.5, 4.9, 52.1);
                    context.lineTo(24.7, 63.6);
                    context.bezierCurveTo(27.6, 65.3, 31.2, 65.3, 34.2, 63.6);
                    context.lineTo(54.0, 52.1);
                    context.bezierCurveTo(56.9, 50.5, 58.7, 47.3, 58.7, 43.9);
                    context.lineTo(58.7, 43.7);
                    context.lineTo(32.0, 36.9);
                    context.closePath();

                    // layer1/Compound Path/Path
                    context.moveTo(32.3, 5.1);
                    context.bezierCurveTo(33.9, 5.1, 35.1, 6.4, 35.1, 8.0);
                    context.bezierCurveTo(35.1, 9.5, 33.9, 10.8, 32.3, 10.8);
                    context.bezierCurveTo(30.7, 10.8, 29.5, 9.5, 29.5, 8.0);
                    context.bezierCurveTo(29.5, 6.4, 30.7, 5.1, 32.3, 5.1);
                    context.closePath();
                    context.fillStyle = "rgb(62, 53, 67)";
                    context.fill();
                    context.lineWidth = 0.3;
                    context.stroke();
                    canvas.fillStroke(this);
                    context.restore();
                }
        });

【问题讨论】:

    标签: javascript animation canvas frame kineticjs


    【解决方案1】:

    以下是如何从“chomping hexes”创建 Kinetic.Sprite 动画

    由于您已经有了十六进制 + 嘴的坐标,您甚至不需要预先创建的 spritesheet。

    您可以使用 html 画布元素动态创建“chomping”精灵表。

    方法:

    • 从一个临时的 html 画布元素开始
    • 在画布上画出所有的格子
    • 使用 canvas.toDataURL 将该画布转换为 spritesheet 图像
    • 正常使用该 spritesheet 运行 Kinetic.Sprite 动画

    这是从 html 画布创建的动态创建的 spritesheet

    以下代码出于说明目的在屏幕上显示画布,但您将在屏幕外创建临时画布。

    这是代码和小提琴:http://jsfiddle.net/m1erickson/sEjvx/

    <!DOCTYPE html>
    <html>
      <head>
        <meta charset="utf-8">
        <title>Prototype</title>
        <script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
        <script src="http://d3lp1msu2r81bx.cloudfront.net/kjs/js/lib/kinetic-v4.5.5.min.js"></script>
    
    <style>
    #container{
      border:solid 1px #ccc;
      margin-top: 10px;
      width:400px;
      height:400px;
    }
    </style>        
    <script>
    $(function(){
    
        var stage = new Kinetic.Stage({
            container: 'container',
            width: 400,
            height: 400
        });
        var layer = new Kinetic.Layer();
        stage.add(layer);
    
    
        // get a reference to the temp canvas
        // it will be used to dynamically create a spritesheet
        var tempCanvas=document.getElementById("canvas");
        var context=tempCanvas.getContext("2d");
    
        // define the sprites
        var pac;
        var translateX=0;
        var y1=18;
        var y2=46;
        var ychange=2.5;
        var width=70;
        var height=70;
        var chomping=[];
        var animations={
            stopped:[{x:0,y:0,width:width,height:height}],
            chomp:chomping
        };
    
    
        // draw the sprites on the canvas
        // also add the sprite definitions (x,y,width,height) 
        // to the chomping animation
        for(var i=0;i<8;i++){
            drawSprite(translateX,y1,y2);
            translateX+=70;
            y1+=2;
            y2-=2;
            if(i<7){
                chomping.push({x:translateX,y:0,width:width,height:height});
            }
        }
    
    
        // convert the sprites on the canvas to a spritesheet image
        // and create a Kinetic.Sprite
        var spritesheet=new Image();
        spritesheet.onload=function(){
            pac=new Kinetic.Sprite({
                x:100,
                y:75,
                image:spritesheet,
                animations:animations,
                framerate:15,
                index:0
            });
            layer.add(pac);
    
            pac.setAnimation("stopped");
            pac.start();
    
            layer.draw();
        }
        spritesheet.src=tempCanvas.toDataURL();
    
    
        // wire up the buttons to start the chomp and stopped animations
        $("#chomp").click(function(){ pac.setAnimation("chomp"); });
        $("#stopped").click(function(){ pac.setAnimation("stopped"); });
    
    
        // draw 1 sprite on the canvas
        function drawSprite(translateX,y1,y2){
    
            // draw hexagon
            context.save();
            context.translate(translateX,0);
            context.beginPath();
            context.moveTo(54.0, 12.8);
            context.lineTo(34.2, 1.4);
            context.bezierCurveTo(31.2, -0.3, 27.6, -0.3, 24.7, 1.4);
            context.lineTo(4.9, 12.8);
            context.bezierCurveTo(1.9, 14.5, 0.1, 17.7, 0.1, 21.0);
            context.lineTo(0.1, 43.9);
            context.bezierCurveTo(0.1, 47.3, 1.9, 50.5, 4.9, 52.1);
            context.lineTo(24.7, 63.6);
            context.bezierCurveTo(27.6, 65.3, 31.2, 65.3, 34.2, 63.6);
            context.lineTo(54.0, 52.1);
            context.bezierCurveTo(56.9, 50.5, 58.7, 47.3, 58.7, 43.9);
            context.lineTo(58.7, 21.0);
            context.bezierCurveTo(58.7, 17.7, 56.9, 14.5, 54.0, 12.8);
            context.closePath();
            context.fillStyle="blue";
            context.fill();
    
            // draw eye
            context.beginPath();
            context.arc(34,10,3,0,Math.PI*2,false);
            context.closePath();
            context.fillStyle="white";
            context.fill();
            context.strokeStyle="orange";
            context.lineWidth=1.5;
            context.stroke();
    
            // draw mouth in various stages of chomping
            context.beginPath();                
            context.moveTo(59,y1);
            context.lineTo(25,32);
            context.lineTo(59,y2);
            context.closePath();   
            context.fillStyle="white";             
            context.fill();
            context.restore();
    
        }
    
    
    }); // end $(function(){});
    
    </script>       
    </head>
    
    <body>
        <button id="chomp">Chomp</button>
        <button id="stopped">Stop</button>
        <div id="container"></div><br>
        <canvas id="canvas" width=600 height=100></canvas>
    </body>
    </html>
    

    【讨论】:

    • 如何开始动画?我在代码末尾使用pac.setAnimation("chomp"); 来启动动画,但我得到TypeError: 'undefined' is not an object (evaluating 'pac.setAnimation')
    • @igaar。您是否解决了“未定义”错误?由于 pac 对象是在函数内部构建的,因此请确保在函数外部定义它以进行全局访问(var pac; 在函数外部)。
    【解决方案2】:

    您可以使用带有 switch 语句的Kinetic.Animation 来确定要显示的帧,如下所示:

        var group = new Kinetic.Group({
            x:10,
            y:10
        });
    
        group.add(pacMan1);
        group.add(pacMan2);
        group.add(pacMan3);
        layer.add(group);
        layer.draw();
    
        pacMan2.hide();
        pacMan3.hide();
    
        var frameCount = 0;
        var anim = new Kinetic.Animation(function (frame) {
            frameCount++;
            var mod = frameCount % 30;
            switch (mod) {
                case 0:
                    pacMan1.show();
                    pacMan2.hide();
                    pacMan3.hide();
                    break;
                case 10:
                    pacMan1.hide();
                    pacMan2.show();
                    pacMan3.hide();
                    break;
                case 20:
                    pacMan1.hide();
                    pacMan2.hide();
                    pacMan3.show();
                    break;
            }
            group.setX(group.getX()+1);
        }, layer);
    
        anim.start();
    

    您可以通过更改模数公式和案例编号使帧通过得更快。

    //Faster
    var mod = frameCount % 3;
    switch (mod) {
        case 0:
            break;
        case 1:
            break;
        case 2:
            break;
    }
    
    //Slower
    var mod = frameCount % 300;
    switch (mod) {
        case 0:
            break;
        case 100:
            break;
        case 200:
            break;
    }
    

    如果你想让他移动得比改变x增加的间隔更快:

    //Move 5 pixels every frame.
    group.setX(group.getX()+5);
    

    JSFIDDLE

    这不是一个很好的答案,但它是一个开始。


    另一种方式

    我想过使用toImage() 方法将您的hex 形状转换为图像,然后在Kinetic.Sprite 中使用它

    http://kineticjs.com/docs/Kinetic.Shape.html#toImage

    http://kineticjs.com/docs/Kinetic.Sprite.html

    还有一个教程:http://www.html5canvastutorials.com/kineticjs/html5-canvas-kineticjs-sprite-tutorial/

    但是,我认为问题在于您需要为精灵设置图像(例如:http://www.html5canvastutorials.com/demos/assets/blob-sprite.png

    理想情况下,尽管出于您的目的,我认为使用 Kinetic.Sprite 是您正在寻找的,所以如果您可以使用 pac man 形状设置基于 sprite 的图像,那么您将需要做很多事情sprite 的东西。

    【讨论】:

      猜你喜欢
      • 2012-08-11
      • 2012-03-13
      • 2013-05-13
      • 1970-01-01
      • 2023-03-20
      • 2013-10-23
      • 2016-03-20
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多