《每周一点canvas动画》——坐标旋转
每周一点canvas动画代码文件
在上一节中我们介绍了一些碰撞检测的方法。这一节本来打算讲解一个基于距离碰撞检测的小游戏。但是,因为最近比较忙,一直没来的及把游戏的整个过程完整的写出来。所以,这一节我们继续介绍下一项新技术——坐标旋转,它可能相对枯燥一些,而且有一些大家十分讨厌的数学公式。但是,它是我们后面高级动画的基石。所以,看的时候还请耐心一点,关于碰撞检测的游戏示例,我会在本周发出。
本章主要内容:
简单的坐标旋转
高级的坐标旋转
坐标旋转是一个非常有用的技术,它主要是让坐标围绕某个点旋转。通过它我们能实现很对有意思的效果,比如,一个物体与一个非水平的表面发生碰撞后,物体的反弹方向,反弹速度等。现在有没有注意到,我们的整个系列文章其实是一个循序渐进的过程,上一章我们介绍如何判断两个物体发生碰撞,而这一节我们介绍的就是两个物体发生碰撞后的事情。
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
版权声明
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处。如若内容有涉嫌抄袭侵权/违法违规/事实不符,请点击 举报 进行投诉反馈!