如何在 Actionscript 3 中正确缩放旋转对象?
不幸的是,这是一个需要解释的相当复杂的问题,所以请不要因为文字墙而灰心——它的存在是有原因的。 ;)
我正在开发一个 Flash 转换管理器,用 Actionscript 3 编写。用户可以在屏幕上放置对象,例如矩形。
然后可以选择并变换该矩形:移动、缩放或旋转。
因为默认情况下 Flash 围绕对象的左上角旋转,并且我希望它围绕中心旋转,所以我为每个显示对象(例如矩形)创建了一个包装器设置。
这就是包装器的设置方式:
//the position wrapper makes sure that we do get the top left position when we access x and y
var positionWrapper:Sprite = new Sprite();
positionWrapper.x = renderObject.x;
positionWrapper.y = renderObject.y;
//set the render objects location to center at the rotation wrappers top left
renderObject.x = 0 - renderObject.width / 2;
renderObject.y = 0 - renderObject.height / 2;
//now create a rotation wrapper, at the center of the display object
var rotationWrapper:Sprite = new Sprite();
rotationWrapper.x = renderObject.width / 2;
rotationWrapper.y = renderObject.height / 2;
//put the rotation wrapper inside the position wrapper and the render object inside the rotation wrapper
positionWrapper.addChild(rotationWrapper);
rotationWrapper.addChild(renderObject);
现在,可以直接访问和设置对象的 x 和 y:mainWrapper.x 或 mainWrapper.y。可以从此主包装器的子级设置和访问旋转:mainWrapper.getChildAt(0).rotation。最后,可以通过获取旋转包装器的子级并直接访问显示对象来检索和设置显示对象的宽度和高度。
关于如何访问它们的示例:
//get wrappers and render object
var positionWrapper:Sprite = currentSelection["render"];
var rotationWrapper:Sprite = positionWrapper.getChildAt(0) as Sprite;
var renderObject:DisplayObject = rotationWrapper.getChildAt(0);
这非常适合所有初始转换:移动、缩放和旋转。
然而,当您首先旋转对象(例如 45 度)然后缩放它时,就会出现问题。缩放后的对象形状变形并且无法按应有的方式缩放。
例如,当您向左缩放时会发生这种情况。向左缩放基本上是向对象添加 n 宽度,然后将位置包装器的 x 坐标也减少 n:
renderObject.width -= diffX;
positionWrapper.x += diffX;
这在对象不旋转时有效。但是,如果是这样,位置包装器将不会旋转,因为它是旋转包装器的父级。这将使位置包装器水平向左移动,同时对象的宽度沿对角线增加。
我希望这是有道理的,如果没有,请告诉我,我会尽力详细说明。
现在,问题是:我应该使用不同类型的设置、系统或结构吗?我是否应该使用矩阵,如果是这样,旋转后如何保持静态宽度/高度?或者如何修复当前的包装系统以在旋转后进行缩放?任何帮助表示赞赏。
This is unfortunately a quite complex issue to explain, so please don't get discouraged by the wall of text - it's there for a reason. ;)
I'm working on a transformation manager for flash, written with Actionscript 3. Users can place objects on the screen, for example a rectangle.
This rectangle can then be selected and transformed: move, scale or rotate.
Because flash by default rotates around the top left point of the object, and I want it to rotate around the center, I created a wrapper setup for each display object (eg. a rectangle).
This is how the wrappers are setup:
//the position wrapper makes sure that we do get the top left position when we access x and y
var positionWrapper:Sprite = new Sprite();
positionWrapper.x = renderObject.x;
positionWrapper.y = renderObject.y;
//set the render objects location to center at the rotation wrappers top left
renderObject.x = 0 - renderObject.width / 2;
renderObject.y = 0 - renderObject.height / 2;
//now create a rotation wrapper, at the center of the display object
var rotationWrapper:Sprite = new Sprite();
rotationWrapper.x = renderObject.width / 2;
rotationWrapper.y = renderObject.height / 2;
//put the rotation wrapper inside the position wrapper and the render object inside the rotation wrapper
positionWrapper.addChild(rotationWrapper);
rotationWrapper.addChild(renderObject);
Now, the x and y of the object can be accessed and set directly: mainWrapper.x or mainWrapper.y. The rotation can be set and accessed from the child of this main wrapper: mainWrapper.getChildAt(0).rotation. Finally, the width and height of the display object can be retreived and set by getting the child of the rotation wrapper and accessing the display object directly.
An example on how I access them:
//get wrappers and render object
var positionWrapper:Sprite = currentSelection["render"];
var rotationWrapper:Sprite = positionWrapper.getChildAt(0) as Sprite;
var renderObject:DisplayObject = rotationWrapper.getChildAt(0);
This works perfectly for all initial transformations: moving, scaling and rotating.
However, the problem arises when you first rotate an object (eg. 45 degrees) and then scale it. The scaled object is getting out of shape and doesn't scale as it should.
This for example happens when you scale to the left. Scaling left is basically adding n width to the object and then reduce the x coord of the position wrapper by n too:
renderObject.width -= diffX;
positionWrapper.x += diffX;
This works when the object is not rotated. However, when it is, the position wrapper won't be rotated as it is a parent of the rotation wrapper. This will make the position wrapper move left horizontally while the width of the object is increased diagonally.
I hope this makes any sense, if not, please tell me and I'll try to elaborate more.
Now, to the question: should I use a different kind of setup, system or structure? Should I maybe use matrixes, if so, how would you keep a static width/height after rotation? Or how do I fix my current wrapper system for scaling after rotation? Any help is appreciated.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
这看起来你应该使用变换矩阵
看看这篇很棒的帖子
http://gasi.ch/blog/zooming-in-flash-flex/< /a>
This looks like you should be using the transform matrix
have a look at this great post
http://gasi.ch/blog/zooming-in-flash-flex/
怎么样:
此外,您还可以踢出
rotationWrapper
并直接在positionWrapper
上执行旋转。除此之外,我建议你看看 senulous 的 tranformtool 和 sephiroth 的修改。
编辑:您基本上要寻找的是具有任意中心的任意向量的尺度变换。有了这个,剩下的就微不足道了。对于第一个问题:创建一个矩阵 M,将中心移动到 0.0 并将向量旋转到 x 轴上。将 M 与 x 尺度乘以向量的长度和 M 的倒数相连接,得到的矩阵应该满足您的需要。当然你可以直接用笔和纸计算结果矩阵,但这应该足够了
what about this:
also, you can kick out
rotationWrapper
and perform rotations onpositionWrapper
directly.apart from that, I suggest you have a look at senocular's tranformtool and sephiroth's modifications.
edit: what you're basically looking for is a scale transformation by an arbitrary vector with an arbitrary center. with that, the rest is trivial. for the first problem: create a matrix M that moves the center to 0.0 and rotates the vector onto the x axis. concat M with an x-scale by the vector's length and the inverse of M and the resulting matrix should do what you need. of course you can calculate the resulting matrix with pen and paper directly, but this should be good enough