《每周一点canvas动画》——坐标旋转

每周一点canvas动画代码文件

在上一节中我们介绍了一些碰撞检测的方法。这一节本来打算讲解一个基于距离碰撞检测的小游戏。但是,因为最近比较忙,一直没来的及把游戏的整个过程完整的写出来。所以,这一节我们继续介绍下一项新技术——坐标旋转,它可能相对枯燥一些,而且有一些大家十分讨厌的数学公式。但是,它是我们后面高级动画的基石。所以,看的时候还请耐心一点,关于碰撞检测的游戏示例,我会在本周发出。

本章主要内容:

  1. 简单的坐标旋转

  2. 高级的坐标旋转

坐标旋转是一个非常有用的技术,它主要是让坐标围绕某个点旋转。通过它我们能实现很对有意思的效果,比如,一个物体与一个非水平的表面发生碰撞后,物体的反弹方向,反弹速度等。现在有没有注意到,我们的整个系列文章其实是一个循序渐进的过程,上一章我们介绍如何判断两个物体发生碰撞,而这一节我们介绍的就是两个物体发生碰撞后的事情。

1.简单的坐标旋转

在《每周一点canvas动画》——三角函数(1)这一节中我们介绍了关于三角函数的使用。不知道你是否还能回忆起让一个物体做圆周运动的条件是什么?

首先我们得有一个中心点(center point),一个物体(object),然后是半径(radius),角度(angle)。通过增加或减少angle的值,使用基本的三角函数我们就可以让物体围绕某个点做圆周运动。这里我们回忆一下:

objectvr = 0.1angle = 0radius = 100centerX = 0centerY = 0object.x = centerX + Math.sin(angle)*radiusobject.y = centerY + Math.cos(angle)*radiusangle += vr

上述代码只是展示了我们以前让物体做圆周运动的方法,并没有把它放在动画循环中。so, 看看我们让一个物体做圆周运动需要多少条件吧!如果你知道半径(radius)和角度(angle),上面的方法应该说是相当不错。

但是,如果你只知道中心点(center point)和物体的位置,还想要物体做圆周运动?该怎么做呢?

当然,如果你还是想要使用上面的方法,那也不难,你还是可以通过这两个已知量来计算我们需要的条件:角度(angle)和半径(radius)都是没问题的。

var dx = objext.x - center.x,
dy = object.y - center.y,
angle = Math.atan2(dy, dx),
radius = Math.sqrt(dxdx + dydy);

对于单个物体的旋转,使用这种方法非常不错,尤其是半径(radius)和角度(angle)这两变量,只需要设定一次的情况下。但是,在大多数的情况下,你可能有很多物体需要做旋转,而且他们距离中心点的相对位置也可能发生变化。so,你需要去计算距离,角度,半径,然后让角度在每一帧都加上vr,最终才能在每一帧得到物体的新坐标。

这个方法怎么说呢?既不高效,也不优雅。所以,我们需要一个新方法。

2.高级的坐标旋转

一提到高级,肯定离不开数学这货。

好吧,我只是给你打个预防针。要想让方法既优雅,又高效,我们必须调整思路。怎样用最少的条件得到我们想要的结果,这时候数学就要上场了。

这里我们不会用到多么高深的大学数学知识,只是简单的中学三角函数变换。你会发现原来老师整天唠叨的公式尽然会如此有用。

这个公式只需要物体的x,y坐标,和每一帧物体旋转的角度(角速度)。

newX = x cos(rotation) - y sin(rotation);
newY = y cos(rotation) + x sin(rotation);
如果你设置了一个中心点,上述公式可以变为

newX = (x - centerX) cos(rotation) - (y - centerY) sin(rotation);
newY = (y - centerY) cos(rotation) + (x - centerX) sin(rotation);

明白其中的原理了吗?学霸就直接跳过,没明白的听我细细讲来。

上图展示了该公式基于的原理图。物体旋转了一个很小的角度rotation, 那么它的位置该如何计算呢?

//物体的原始位置,距离中心点的距离radius
x = radius cos(angle);
y = radius
sin(angle);

newX = radius cos(angle + rotation);
newY = raidus
sin(angle + rotation);
我们知道

cos(a + b) = cos(a) cos(b) - sin(a) sin(b);
sin(a + b) = sin(a) cos(b) + cos(a) sin(b);
所以面的公式可以化简成如下形式

newX = radius cos(angle) cos(rotation) - raidus sin(angle) sin(rotation);
newY = raidus sin(angle) cos(rotation) + raidus cos(angle) sin(rotation);

又因为 x = radius cos(angle); y = radius sin(angle); 将其带入得

newX = x cos(rotation) - y sin(rotation);
newY = y cos(rotation) + x sin(rotation);
也就是说我们只需要知道物体的位置,设置它每秒钟要旋转的角度(角速度vr),就可以完成以前圆周运动的效果,至于中心点就看你自己的设置了。是不是很优雅,感谢一下你的数学老师吧!下面,我们就运用这个公式来完成一个简单的效果。

2.1 单物体旋转

也就是我们用它来代替以前的圆周运动

辅助线条是我加上去的,你不用太在意,具体看源代码文件:高级坐标旋转.html我们只关心核心代码

   window.onload = function(){       var canvas = document.getElementById('canvas'),           context = canvas.getContext('2d'),           ball = new Ball(20, "red"),           vr = 0.05, //每一帧转动的弧度值           cos = Math.cos(vr), // 得到cos值           sin = Math.sin(vr), // 得到sin值           centerX = canvas.width/2,           centerY = canvas.height/2,           canvasWidth = canvas.width,           canvasHeight = canvas.height;          ball.x = Math.random()*canvasWidth;          ball.y = Math.random()*canvasHeight;          (function drawFrame(){           window.requestAnimationFrame(drawFrame, canvas);           context.clearRect(0, 0, canvas.width, canvas.height);           var x1 = ball.x - centerX; //相对中心点的位置           var y1 = ball.y - centerY;           var newX = x1*cos - y1*sin; //旋转一定角度后的位置           var newY = y1*cos + x1*sin;           ball.x = centerX + newX; //更新球的位置           ball.y = centerY + newY;           ball.draw(context);       }());   }

2.2 多物体旋转

那么怎样将该公式运用到多个物体上呢?这个其实在以前的例子中我们已经讲过很多遍了

...
var cos = Math.cos(vr),
sin = math.sin(vr);

balls.forEash(function(ball){
var x1 = ball.x - center.x,
y1 = ball.y - center.y;

var newX = x1 * cos - y1 * sin,    newY = y1 * cos + x1 * sin;ball.x = centerX + newX;ball.y = centerY + newY;

})
...

下一节,我们讲与之紧密相关的角度反弹,敬请期待!

关键字:JavaScript, html5, canvas, rotation

版权声明

本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处。如若内容有涉嫌抄袭侵权/违法违规/事实不符,请点击 举报 进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部