返回“Flash基础理论课 - 目录”
第十三章介绍了一些基础的运动学以及正向与反向运动学之间的区别。前一章我们讲了正向运动学,本章就要学习与它关系紧密的反向运动学。涉及到的动作就是拖拽与伸展。
与正向运动学的例子相同,本章的例子也是从独立的关节开始建立系统。我们从单个关节开始,然后到多个关节。首先,我会给大家演示最简单的计算角度与位置的方法。只是在代码中使用基本的三角学进行大概的测算。最后,会给大家简要地介绍使用余弦定理的方法,这样计算出来的结果更加准确,但会消耗大量的计算——这就是所谓的权衡。
单物体的拖拽与伸展
前面说过,反向运动学系统可以分为两种不同的类型:拖拽与伸展。
当系统的自由端向目标点伸展时,系统的另一端——固定端,也许是动不了的,因此如果目标点位置超出了自由端运动的范围,那么自由端永远也不能到达目标点。举个例子,当我们试图抓住某个东西时,手指就朝着这个物体移动,手腕的转动会使我们的手指与目标位置越来越近,肘部,肩膀和身体其它的部分也都尽可能地伸展。有时,所有这些位置的组合将会使手指接触到物体;有时也许不行。如果物体是来回运动的,我们的肢体就要做出即时的反映不断调整位置,为了让手指能够尽可能地够到该物体。反向运动学将会告诉我们,如何设置所有这些零件的位置,达到最佳的伸展效果。
另一种反向运动学是在物体被拖拽的时候。这个例子中,自由端是被一些外部的力所拖动的。无论何时,系统其余的部分都紧随其后,它们会将自己放置到自然的可能位置上。可以想象成一个没有知觉死尸(对不起,这是我唯一能想到的)。抓住他的手然后拽着它走。
我们施加在对方手上的力,会传到手腕,肘部,肩膀,以及身体的其余部分,它们都沿着拖拽的方向移动。这个例子中,反向运动学将告诉我们所有的这些零件是如何随着拖拽组合成正确的位置。
最好的理解方法就是用例子程序加以说明,每个例子都使用一个关节。我们需要用到 Segment 这个类,因此要保证它在我们工作的工程或类路径中。
单关节伸展
对于伸展而言,所有关节都要能向目标旋转。目标,如果还没读懂我的意思,就把它想成鼠标。让关节向目标旋转,需要知道两点间 x,y 轴上的距离。然后就可以使用Math.atan2 求出该角度的弧度制。将它转换为角度制,就得到了关节的rotation。代码如下(可见 OneSegment.as):
package {
import flash.display.Sprite;
import flash.events.Event;
public class OneSegment extends Sprite {
private var segment0:Segment;
public function OneSegment() {
init();
}
private function init():void {
segment0 = new Segment(100, 20);
addChild(segment0);
segment0.x = stage.stageWidth / 2;
segment0.y = stage.stageHeight / 2;
addEventListener(Event.ENTER_FRAME, onEnterFrame);
}
private function onEnterFrame(event:Event):void {
var dx:Number = mouseX - segment0.x;
var dy:Number = mouseY - segment0.y;
var angle:Number = Math.atan2(dy, dx);
segment0.rotation = angle * 180 / Math.PI;
}
}
}
图 14-1 所示,运行结果。测试一下观察关节是如何跟随鼠标的。即使关节离得很远,它都像是快要抓住鼠标一样。
图14-1 单个关节向鼠标伸展