PHP群:95885625 Hbuilder+MUI群:81989597 站长QQ:634381967
    您现在的位置: 首页 > 开发编程 > HTML5+CSS3教程 > 正文

    《html5 canvas动画》——移动物体(1)

    作者:admin来源:segmentfault浏览:时间:2020-09-30 00:07:50我要评论
    导读:我们介绍了用户交互事件,包括:鼠标事件,触摸事件和键盘事件。但是,到目前为止,我们除了键盘事件,对于另外两个事件几乎没有做过任何相...
    我们介绍了用户交互事件,包括:鼠标事件触摸事件键盘事件。但是,到目前为止,我们除了键盘事件,对于另外两个事件几乎没有做过任何相应的应用。那么,在这一章,我们将要学习如何让canvas中的物体对用户的动作做出反应,并且学习如何拖拽和抛扔一个物体。不用担心,用到的都是我们学过的知识。本节主要内容:
    1. 物体捕获

    2. 捕获验证

    3. 物体的拖拽

    1.物体捕获

    鼠标是个简单,却效率极高的装置。它简单来说只做两件事:移动监测和按钮点击。然后,电脑会根据鼠标得到的信息来做很多事情,比如:位置追踪,点击事件发生时光标的位置,决定鼠标移动的速度,识别双击事件等等。仔细想想,所有的这些是不是都可以归结于鼠标的点击和移动。
    现在,好好回忆一下,我们平时玩游戏的时候是怎样移动一个物体的。当然,如果没玩过的话,就别想了。它的基本流程如下:

    click -> move -> release

    整个流程对应的事件如下:

    • mousedown:当按下鼠标按钮时发生

    • mouseup:当鼠标按钮抬起时发生

    • mousemove:当你移动鼠标时发生

    OK!现在我们知道了,移动一个物体分为哪几步(是不是和想起了把大象装进冰箱分为那几步)。接下来还有一个重要的事情:怎样捕获一个物体呢。我们已经知道了如何移动一个物体,可是如果你都没有要移动的对象,那不是白搭嘛!简单来说就是怎样判定我们的鼠标真的点击到了物体上,你知道了不行,必须得让我们的电脑知道才行。

    1.1 外接矩形判别法

    《html5 canvas动画》——移动物体(1)
    这里为了便于理解,我做了一个倍详细的图。灰色区域代表canvas, 蓝色的代表rect, 我们已知的是rect的坐标(这里以左上角作为坐标基准)和宽高。当鼠标点击在蓝色区域,即rect上就代表我们捕获这个物体。那么怎样算是鼠标落在这块区域上呢?看下面的几个条件:
    1.mouse.x > rect.x
    2.mouse.x < rect.x + rect.width
    3.mouse.y > rect.y
    4.mouse.y < rect.y + rect.height

    我们列出了四个条件,仔细对比图片看看。是不是只要所有条件同时满足就可以判定我们的鼠标落在了rect上。所以,如果你要检测的物体是矩形,或者趋近于矩形都可以使用这种方法。

    1.2 外接圆判别法

    《html5 canvas动画》——移动物体(1)

    我们可以看到,如果当物体变成圆形,再使用上面的方法去判定鼠标是否落在ball上,就不会那么精确了。当然,不是不行,就是不够精确,当球体很小的时候还是可以接受的。

    对于球体,还有另一种方法,那就是判定鼠标距离球心的距离。如果距离小于球体半径就可以判断鼠标落在了球体上,反之则没有。所以,如果你要检测的物体趋近于圆,就可以使用这种方法。

    鼠标距球心的距离
    dx = mouse.x - ball.x;
    dy = mouse.y - ball.y;
    dist = Math.sqrt(dx*dx + dy*dy)
    if(dist < ball.radius){
       //碰上了
    }

    1.3 多边形和不规则图形

    要是我们要捕获的对象是不规则的,那就比较难了,我们需要用到分离轴定理(SAT)和最小平移向量(MTV),听起来就很高深啊。自己去了解一下吧!其实挺容易的,这里就不介绍了。

    在本章中为了简单,我们的球体也是使用外接矩形法。我们需要在ball.js文件中增加如下代码:

    Ball.prototype.getBounds = function(){
        return {
            x: this.x - this.radius,
            y: this.y - this.radius,
            width: this.radius*2,
            height: this.radius*2
        };
    }

    这里定义了一个方法getBounds(),该方法返回一个对象,包含物体的坐标(以左上角为基准)和宽高,就跟上图中表示的一样。同时我们也需要在工具函数文件utils.js中增加一个新方法:

    utils.containsPoint = function(rect, x, y){
        return !(x<rect.x || x>rect.x + rect.width ||
                 y<rect.y || y>rect.y + rect.height);
    }

    注意,该方法返回的是个布尔值,如果落在区域内,那么返回的是!(0 || 0 || 0 || 0)也就是true,如果有任意一个条件不满足,那么久返回false,表示不在区域内。该方法传入三个参数,
    rect: 表示要检测的物体
    x,y: 鼠标坐标

    2.捕获验证

    为了防止步子迈的太大扯着蛋!我们先做个简单的效果:

    《html5 canvas动画》——移动物体(1)

    当在鼠标没有点击在ball上时,打印出canvas和当前的活动状态,当鼠标点击在球体上时打印出ball和鼠标的运动状态。具体代码如下:

    1. <canvas id="canvas" width="400" height="400" style="background:#000;"
    2.        your browser not support canvas 
    3.    </canvas> 
    4.    <textarea name="textarea" id="txt" cols="30" rows="10"></textarea> 
    5.    <script src="../js/utils.js"></script> 
    6.    <script src="../js/ball.js"></script> 
    7.    <script> 
    8.        window.onload = function(){ 
    9.            var canvas = document.getElementById('canvas'), 
    10.                context = canvas.getContext('2d'), 
    11.                log = document.getElementById('txt'); 
    12.             
    13.            //传入canvas,获取鼠标坐标 
    14.            var mouse = utils.captureMouse(canvas); 
    15.             
    16.            var ball = new Ball(20,"red"); 
    17.                ball.x = canvas.width/2; 
    18.                ball.y = canvas.height/2; 
    19.                ball.draw(context); 
    20.              
    21.            //定义状态函数 
    22.            function state(wrd){ 
    23.                /*注意这里用到了我们前面新加的代码 
    24.                  ball.getBounds(): 返回一个对象包含球的坐标,宽高.并作为参数传入 
    25.                  utils.containsPoint(): 判断点击区域,返回布尔值 
    26.                */ 
    27.                if(utils.containsPoint(ball.getBounds(), mouse.x, mouse.y)){ 
    28.                    log.value = "in ball : "+ wrd; 
    29.                }else
    30.                    log.value = "canvas : " + wrd; 
    31.                } 
    32.            } 
    33.            // 为canvas添加mousedown事件 
    34.            canvas.addEventListener('mousedown'function(event){ 
    35.                state("mousedown"); 
    36.                //mouseup 
    37.                canvas.addEventListener('mouseup'function(event){ 
    38.                     state("mouseup"); 
    39.                },false); 
    40.                //mousemove 
    41.                canvas.addEventListener('mousemove'function(event){ 
    42.                     state("mousemove"); 
    43.                }, false); 
    44.            }, false); 
    45.        } 
    46.     </script> 
    注意这里,我们将mouseupmousemove定义在了mousedown事件内部。也就是说如果mousedown事件不触发,就无法触发另外两个事件。想想我们移动一个物体的基本流程,也的确合乎情理。

    touch事件与鼠标点击事件很相似,这里我就不给代码了,具体的文件可以在文章开头看到。

    3.物体的拖拽

    有了前面的基础,要移动一个物体算什么难事,我们先上效果图:

    《html5 canvas动画》——移动物体(1)

    具体代码如下:

     

    1. <canvas id="canvas" width="400" height="400" style="background:#000;"
    2.        your browser not support canvas 
    3.    </canvas> 
    4.    <script src="../js/utils.js"></script> 
    5.    <script src="../js/ball.js"></script> 
    6.    <script> 
    7.        window.onload = function(){ 
    8.            var canvas = document.getElementById('canvas'), 
    9.                context = canvas.getContext('2d'), 
    10.                mouse = utils.captureMouse(canvas), 
    11.                ball = new Ball(20, "red"); 
    12.             
    13.            ball.x = canvas.width/2; 
    14.            ball.y = canvas.height/2; 
    15.             
    16.            var w = 0, h = 0; 
    17.             
    18.            //为canvas设置监听事件 
    19.            canvas.addEventListener('mousedown'function(event){ 
    20.                //判断是否点击在球体上 
    21.                if(utils.containsPoint(ball.getBounds(), mouse.x, mouse.y)){ 
    22.                    w = mouse.x - ball.x; 
    23.                    h = mouse.y - ball.y; 
    24.                    canvas.addEventListener('mouseup', onMouseUp, false); 
    25.                    canvas.addEventListener('mousemove', onMouseMove, false); 
    26.                } 
    27.            }, false); 
    28.             
    29.            //mouseup事件执行函数 
    30.            function onMouseUp(event){ 
    31.                canvas.removeEventListener('mouseup', onMouseUp, false); 
    32.                canvas.removeEventListener('mousemove', onMouseMove, false); 
    33.            } 
    34.            //mousemove事件执行函数 
    35.            function onMouseMove(event){ 
    36.                   ball.x = mouse.x - w; 
    37.                   ball.y = mouse.y - h; 
    38.            } 
    39.            //动画循环 
    40.            (function dramFrame(){ 
    41.                window.requestAnimationFrame(dramFrame, canvas); 
    42.                context.clearRect(0, 0, canvas.width, canvas.height); 
    43.                 
    44.                ball.draw(context); 
    45.            }()) 
    46.        } 
    47.     </script> 

    这部分代码,其实只是在对上部分代码的改进。我们在canvas上设置了mousedown事件,当鼠标点击在canvas上时,就会触发。此时注意我们的判定条件,如果为true,就会执行if中的语句。

    if中,我们为canvas添加了mousemovemouseup事件,mousemove事件的触发是在鼠标点击在了ball之后,移动鼠标才触发的,他执行的函数是onMouseMovemouseup是当鼠标抬起是触发的,执行函数是onMouseUp

    onMouseMove函数中我们重新设置了ball的位置。onMouseUp函数中移除监听事件。

    注意,这里有两个变量wh,这两个变量的作用是修正ball的位置的。为什么这样说呢?因为当我们点击球体的时候,不一定点击的就是球体的球心。这时移动物体,如果没有这个修正值,小球就会出现一个快速的偏移,让鼠标位于小球的球心,感觉很别扭。所以,在点击时,我们就把鼠标与球心之间的坐标差值计算出来,在移动的时候给个修正就不会出现快速偏移的现象了。

    转载请注明(B5教程网)原文链接:https://b5.mxunkeji.com/content-142-5106-1.html
    相关热词搜索: