【问题标题】:Making a circle that moves画一个会移动的圆圈
【发布时间】:2012-10-27 14:38:36
【问题描述】:

一直在尝试让一些东西在 HTML 中工作,但我还没有完全确定它。基本上,我想创建一个画布,然后在画布内制作一个从画布边缘移动到画布边缘的圆圈。有什么建议吗?

编辑:

人们想要我目前拥有的东西,所以这里是:

<html> 
<head> 
<script type="text/javascript">   
function draw () {
    var canvas = document.getElementById('circle');
    if (canvas.getContext) {
      var context = canvas.getContext('2d');

      context.fillStyle = "rgb(150,29,28)";
      var startPoint = (Math.PI/180)*0;
      var endPoint = (Math.PI/180)*360;
      context.beginPath(); 
      context.arc(200,200,150,startPoint,endPoint,true);    
      context.fill();
   context.closePath(); 
      }
    }   
} 
</script>
</head>
<body onload="init();"> 
<canvas id="canvas" width="500" height="500"></canvas><br>

</body> 
</html>

我不太确定如何在画布上画一个圆圈(我仍然对它的实现感到不安)以及如何制作它,你知道,移动。我有如何旋转某物的示例,但没有真正如何移动它的示例。对不起,没有经验的家伙,试图自学 HTML,但我得到的书似乎并没有真正描述这方面,即使它应该是教我 HTML。

【问题讨论】:

标签: javascript html css canvas html5-canvas


【解决方案1】:

到目前为止,您已经有了一个代码,您可以在其中在画布表面的某个位置绘制一个圆,很好,现在为了让它看起来像在移动,您必须继续绘制它一次又一次地稍微改变它的位置以赋予它平滑的运动效果,这是每秒绘制 60 次的标准(我认为这是因为每秒 60 帧是人眼可以注意到的最多的帧,或其他)。当然,每次你在另一个位置绘制它时,都需要清除旧的绘图。

让我们稍微修改一下你的代码,让它对动画友好:

<script type="text/javascript">   
function init()
{
   canvas = document.getElementById('canvas');
   if(canvas.getContext)
      context = canvas.getContext('2d');
   else return;

   setInterval(draw, 1000 / 60); // 60 times per second
}

function draw()
{
   context.clearRect(0, 0, canvas.width, canvas.height);
   context.fillStyle = "rgb(150,29,28)";
   // var startPoint = (Math.PI/180)*0; Kinda redundant, it's just 0
   // var endPoint = (Math.PI/180)*360; Again, it's just PI times 2
   context.beginPath(); 
   context.arc(200, 200, 150, 0, Math.PI * 2, true);    
   context.fill();
   context.closePath(); 
} 
</script>
</head>
<body onload="init();"> 
<canvas id="canvas" width="500" height="500"></canvas><br>

现在有很多有趣的方法可以让物体向固定点移动,但最简单的当然是沿直线移动。为此,您需要

  • 包含对象当前位置的向量
  • 包含对象目标位置的向量

让我们更改您的代码,以便我们掌握这些代码

var canvas, context,
    position = {x: 200, y: 200},
    target = {x: 400, y: 400};

function init()
{
    ...
}

function draw()
{
    context.clearRect(0, 0, canvas.width, canvas.height);
    context.fillStyle = "rgb(150,29,28)";
    context.beginPath(); 
    context.arc(position.x, position.y, 150, 0, Math.PI * 2, true);    
    context.fill();
    context.closePath(); 
}

好!这样,每当您更改 position 对象中的某个值时,您的圆圈的位置都会受到影响。

如果你从目标位置减去当前位置,你会得到另一个向量,它直接指向来自当前位置的目标位置,对吧?因此,获取该向量并对其进行标准化,将其长度变为 1,结果实际上将是从目标到对象位置的角度的(余弦,正弦)。这意味着,如果您将该归一化向量添加到对象的当前位置,则对象将一次向目标位置移动 1 个单位。

对向量进行归一化就是简单地将其分量除以它的长度。

function normalize(v)
{
    var length = Math.sqrt(v.x * v.x + v.y * v.y);
    return {x: v.x / length, y: v.y / length};
}

var step = normalize({x: target.x - position.x, y: target.y - position.y});

好的,现在我们需要做的就是不断将step 向量添加到对象的当前位置,直到它到达目标位置。

function normalize(v)
{
    var length = Math.sqrt(v.x * v.x + v.y * v.y);
    return {x: v.x / length, y: v.y / length};
}

var canvas, context,
    position = {x: 200, y: 200},
    target = {x: 400, y: 400},
    step = normalize({x: target.x - position.x, y: target.y - position.y});

function init()
{
   canvas = document.getElementById('canvas');
   if(canvas.getContext)
      context = canvas.getContext('2d');
   else return;

   setInterval(draw, 1000 / 60);
}

function draw()
{
    context.clearRect(0, 0, canvas.width, canvas.height);
    context.fillStyle = "rgb(150,29,28)";
    context.beginPath(); 
    context.arc(position.x, position.y, 150, 0, Math.PI * 2, true);    
    context.fill();
    context.closePath(); 

    position.x += step.x;
    position.y += step.y;
}

你有它。当然这是非常基本的代码,你必须添加一个代码来检查对象是否已经到达目标,否则它会一直越过目标。如果它移动得太慢,只需按任意速度因子缩放step 向量。同样在现实世界的应用程序中,你会有很多对象,而不仅仅是一个圆圈,所以你必须让它完全面向对象,因为每个对象都有它的位置、目标位置、颜色等等等。一个库使用向量会派上用场。这是我前段时间为自己写的一篇:http://pastebin.com/Hdxg8dxn

【讨论】:

    【解决方案2】:

    给你,试试这个 -

    <!DOCTYPE html>
    <html>
    <head>
    <script>
    function byId(e){return document.getElementById(e);}
    function newEl(tag){return document.createElement(tag);}
    function newTxt(txt){return document.createTextNode(txt);}
    function toggleClass(element, newStr)
    {
        index=element.className.indexOf(newStr);
        if ( index == -1)
            element.className += ' '+newStr;
        else
        {
            if (index != 0)
                newStr = ' '+newStr;
            element.className = element.className.replace(newStr, '');
        }
    }
    function forEachNode(nodeList, func)
    {
        var i, n = nodeList.length;
        for (i=0; i<n; i++)
        {
            func(nodeList[i], i, nodeList);
        }
    }
    
    window.addEventListener('load', mInit, false);
    
    var canvas, hdc;
    var posx=50, posy=0, radius=50;
    
    function circle(hdc, x, y, radius)
    {
        hdc.beginPath();
        hdc.arc(x, y, radius, 0, 2*Math.PI);
        hdc.stroke();
    //arc(x,y,r,start,stop)
    }
    
    function mInit()
    {
        canvas = byId('tgtCanvas');
        hdc = canvas.getContext('2d');
    
        //circle(hdc, posx, posy, 50);
        setInterval(animateStep, 50);
    }
    
    var velX = 2;
    function animateStep()
    {
        posx += velX;
        if (posx+radius > canvas.width)
            velX *= -1;
        else if (posx-radius < 0)
            velX *= -1;
    
        hdc.clearRect(0,0,canvas.width,canvas.height);
        circle(hdc, posx, posy, radius);
    }
    
    </script>
    <style>
    </style>
    </head>
    <body>
    
        <canvas id='tgtCanvas' width='256' height='256'></canvas>
    
    </body>
    </html>
    

    【讨论】:

    • 太好了,谢谢,今天下班我一定会试一试的:)
    • 我很好奇前三个函数的作用。
    • 不用担心。很高兴它看起来很有用。 :) 那只是我的blank.html - 如果你愿意的话,一个模板。为使该演示工作而添加的唯一内容是 (a) 画布元素 (b) mInit 的主体 (c) window.addEventListener('load', mInit, false); 后面的所有代码; - 我更喜欢输入 byId 而不是 document.getElementById 等。因此 newEl、newTxt、toggleClass 和 forEachNode 未使用且不必存在。希望我已经回答了你的问题——如果我错过了分数,我当然愿意。 :-)
    猜你喜欢
    • 1970-01-01
    • 2021-06-24
    • 2019-09-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-11-12
    • 2020-09-06
    • 1970-01-01
    相关资源
    最近更新 更多