坐标旋转模拟场景:已知一个中心点(centerX,centerY),旋转前的物体球(x1,y1),旋转弧(rotation);seek旋转的对象(x2,y2)。(如下图所示)坐标旋转就是将坐标围绕某一点进行旋转。我们需要根据旋转的角度(弧度)计算出物体旋转前后的坐标。一般有两种方法:简单的坐标旋转,灵活运用前几章的三角函数知识可以轻松解决,基本思路:计算物体相对于中心点的初始位置;使用atan2计算弧度角;使用勾股定理计算半径radius;angle+旋转后,用cos计算旋转后的x轴位置,用sin计算旋转后的y轴位置。下面是使用这种方法的圆周运动的例子,其中vr是小球相对于中心点的圆弧变化速度。由于旋转半径是固定的,所以不会在动画循环中每次都获取。完整示例:简单坐标旋转演示/***简单坐标旋转演示**/window.onload=function(){constcanvas=document.getElementById('canvas');constcontext=canvas.getContext('2d');常量球=新球();球.x=300;球.y=200;//电弧变化速度constvr=0.05;//中心点位置设置在画布的中心constcenterX=canvas.width/2;constcenterY=canvas.height/2;//球与中心的距离constdx=ball.x-centerX;constdy=ball.y-centerY;//球和中心之间的弧线letangle=Math.atan2(dy,dx);//旋转半径constradius=Math.sqrt(dx**2+dy**2);(functiondrawFrame(){window.requestAnimationFrame(drawFrame,canvas);context.clearRect(0,0,canvas.width,canvas.height);ball.x=centerX+Math.cos(angle)*radius;ball.y=centerY+Math.sin(angle)*radius;angle+=vr;ball.draw(context);}());};坐标旋转公式上面的方法非常适用于单个物体,尤其是角度和半径只需要计算一次的时候。但在动态性更强的场景中,可能需要旋转多个物体,而且它们相对于中心点的位置都不同。所以每一帧都要计算出每个物体的距离、角度和半径,然后在角度上加上vr,最后计算出物体的新坐标。这显然不是一个优雅的方法。理想的方法是每次都用数学方法推导出旋转角度和位置的关系,直接代入计算。推导过程如下图所示:其实推导过程并不重要,我们只需要记住下面两组公式即可,其中dx2和dy2是球的终点到圆心的距离点,所以要得到物体的终点,要分别加上中心点的坐标。//正向旋转dx2=(x1-centerX)*cos(rotation)-(y1-centerY)*sin(rotation)dy2=(y1-centerY)*cos(rotation)+(x1-centerX)*sin(rotation)//反向旋转dx2=(x1-centerX)*cos(rotation)+(y1-centerY)*sin(rotation)dy2=(y1-centerY)*cos(rotation)-(x1-centerX)*sin(rotation)下面是使用这种方法的圆周运动的例子,其中dx1和dy1是球的起点相对于圆心的距离,dx2和dy2是球的终点相对于圆心的距离中心点。完整示例:高级坐标旋转演示/***高级坐标旋转演示**/window.onload=function(){constcanvas=document.getElementById('canvas');constcontext=canvas.getContext('2d');常量球=新球();球.x=300;球.y=200;//电弧变化速度constvr=0.05;//中心点位置设置在画布的中心constcenterX=canvas.width/2;constcenterY=canvas.height/2;//由于vr是固定的,所以可以先计算正弦和余弦constcos=Math.cos(vr);constsin=Math.sin(vr);(functiondrawFrame(){window.requestAnimationFrame(drawFrame,canvas);context.clearRect(0,0,canvas.width,canvas.height);//球与中心的距离constdx1=ball.x-centerX;constdy1=ball.y-centerY;//代入公式求球端点到中心点的距离constdx2=dx1*cos-dy1*sin;constdy2=dy1*cos+dx1*sin;//找到x2,y2ball.x=centerX+dx2;ball.y=centerY+dy2;ball.draw(context);}());};斜面反弹在前面的章节中,我们介绍了一种处理越界的方法就是反弹。由于边界是矩形,回弹面是垂直或水平的,所以可以直接反演对应轴的速度,但这种方法不适用于非垂直或水平的回弹面。坐标旋转的常见应用就是处理这种情况,将不规则方向的复杂问题简单化。基本思路:(旋转前后)利用旋转公式对整个系统进行旋转,将倾斜场景转化为水平场景;处理水平场景中的反弹;然后旋转回来。一个例子是落在一条线上的球。球在重力加速度的作用下下落,并在碰到斜坡时反弹。每次反弹都会失去速度。完整示例:bevelbounce示例window.onload=function(){constcanvas=document.getElementById('canvas');constcontext=canvas.getContext('2d');常量球=新球();//线类构造函数参数(起点x轴坐标,起点y轴坐标,终点x轴坐标,终点y轴坐标)constline=newLine(0,0,500,0);//设置重力加速度constgravity=0.2;//设置反弹系数constbounce=-0.6;球.x=100;球.y=100;行.x=0;行.y=200;line.rotation=10*Math.PI/180;constcos=Math.cos(line.rotation);constsin=Math.sin(line.rotation);(functiondrawFrame(){window.requestAnimationFrame(drawFrame,canvas);context.clearRect(0,0,canvas.width,canvas.height);ball.vy+=gravity;ball.x+=ball.vx;球。y+=ball.vy;//得到球和线的相对位置letx1=ball.x-line.x;lety1=ball.y-line.y;//旋转坐标系(反转)lety2=y1*cos-x1*sin;//根据旋转值进行弹跳if(y2>-ball.radius){//旋转坐标系(反向)constx2=x1*cos+y1*sin;//旋转速度(反向)constvx1=ball.vx*cos+ball.vy*sin;让vy1=ball.vy*cos-ball.vx*sin;y2=-ball.radius;vy1*=弹跳;//将所有东西回转(正向)x1=x2*cos-y2*sin;y1=y2*cos+x2*sin;ball.vx=vx1*cos-vy1*sin;ball.vy=vy1*cos+vx1*sin;ball.x=line.x+x1;ball.y=line.y+y1;}ball.draw(上下文);line.draw(上下文);}());};
