大家好!我正在尝试动态添加(以及稍后删除)三角形内的一些动画片段。一个movieclip里面的简单movieclip不能正常工作(最后它是一个正方形)。绘制三角形很简单,addChild方法也很清晰。艰难的部分来了。这是我正在努力开发的代码:
btn_toys_2.confirm.addEventListener(MouseEvent.MOUSE_UP, confirmToys);
import flash.display.Graphics;
var point1:Point = new Point(466, 65);
var point2:Point = new Point(370, 540);
var point3:Point = new Point(570, 540);
var vertices:Vector.<Number> = Vector.<Number>([point1.x, point1.y, point2.x, point2.y, point3.x, point3.y]);
var triangle:Sprite = new Sprite();
triangle.graphics.beginFill(0x00ff00, 1);
triangle.graphics.drawTriangles(vertices);
triangle.graphics.endFill();
addChild(triangle);
function confirmToys(e:MouseEvent){
var toy:MovieClip = new shar_001;
triangle.addChild(toy);
toy.x = Math.random()*30;
toy.y = Math.random()*30;
}
“玩具”电影剪辑由于某种原因放在三角形外(0-30 x轴和0-30 y轴)。 重要的是让“玩具”出现在三角形内,不一定要成为一个动画片段。解决这个问题的方法也很棒! 提前谢谢!
答案 0 :(得分:2)
这种情况正是这样发生的,因为您已将三角形锚点设为零。你这样做了
addChild(triangle);
这将始终将添加的孩子放在(0,0)。三角形没有出现的唯一原因是因为你通过使point
s大于零来添加空像素的缓冲。相反,您将使用
addChild(triangle);
triangle.x = 370;
triangle.y = 65;
您希望三角形左上角所在的点为(370,65)。您应该将三角形点设为(96,0),(0,475),(200,475)。现在,三角形的左上角位于舞台上的(0,0)处。现在在将三角形添加到舞台后将三角形设置为(370,65)。现在,三角形锚点仍然是三角形的左上角,而不是舞台,因此当您添加玩具时,它将参考您期望的点。
// let the minimum x and y be zero, and adjust the others relative to that.
var point1:Point = new Point(96, 0);
var point2:Point = new Point(0, 475);
var point3:Point = new Point(200, 475);
var toyArray:Array = new Array();
var vertices:Vector.<Number> = Vector.<Number>([point1.x, point1.y, point2.x, point2.y, point3.x, point3.y]);
var triangle:Sprite = new Sprite();
triangle.graphics.beginFill(0x00ff00, 1);
triangle.graphics.drawTriangles(vertices);
triangle.graphics.endFill();
addChild(triangle);
// position anchor point on stage
triangle.x = 370;
triangle.y = 65;
function confirmToys(e:MouseEvent){
var p:Point = new Point(Math.random()*triangle.width,Math.random()*triangle.height);
if (isInsideTriangle(Point1,Point2,Point3,p))
{
var toy:MovieClip = new shar_001;
triangle.addChild(toy);
toyArray.push(toy);
toy.x = p.x;
toy.y = p.y;
}
}
private function isInsideTriangle(A:Point,B:Point,C:Point,P:Point):Boolean {
var planeAB:Number = (A.x-P.x)*(B.y-P.y)-(B.x-P.x)*(A.y-P.y);
var planeBC:Number = (B.x-P.x)*(C.y-P.y)-(C.x - P.x)*(B.y-P.y);
var planeCA:Number = (C.x-P.x)*(A.y-P.y)-(A.x - P.x)*(C.y-P.y);
return sign(planeAB)==sign(planeBC) && sign(planeBC)==sign(planeCA);
}
private function sign(n:Number):int {
return Math.abs(n)/n;
}
根据您要使用的方法,从三角形中移除玩具应该非常简单。我添加了一个toyArray,您可以迭代删除它们。
答案 1 :(得分:1)
检查一个位置是否在所需的边界内,如果它不是肯定的解决方案,则拒绝它。但是,这会使程序无法确定性,因为您永远不知道在找到边界内的位置之前需要多少次尝试。
这是否意味着程序可以永远运行?可能是的,但这是不可能的,它不会发生。根据三角形填充的边界框的大小,它仍会产生相当多的失误。错过必须检查,拒绝并再次尝试。
我没有建议反对这个策略,因为它可能是一个性能问题(实际上它可能是一个),而是因为它似乎忽略了这一点:如果找到三角形中的位置,让&# 39; s就是这么做的。所有这些试错,测试和拒绝都是违反直觉的。
您只有一个内置的伪随机数生成器:Math.random()
。
这会产生0到1之间的均匀分布的随机数。(让我们忽略边界是否是可能的值)
要创建2D分发,只需简单地使用其中两种即可。
现在,均匀分布的问题是它是均匀的。要形成非矩形形状,必须应用变换。
考虑三角形的两个边是两个向量。通过以随机方式线性组合这两个向量,可以找到三角形中的随机点。
显然,对于未变换的随机数,这将为随机点产生菱形边界。为了补偿向量在一个点处相遇并在另一个方向上发散的事实,将平方根应用于一个随机数。这背后的数学并不是太复杂,但也不是微不足道的。我选择在这里省略它。有关更多信息,请提出一个新问题,math.se可能是一个很好的地方。
这是一个完整的示例代码,用作文档类,将1000个圆圈放入三角形边界:
package
{
import flash.display.Shape;
import flash.display.Sprite;
import flash.geom.Point;
public class Main extends Sprite
{
public function Main()
{
var distribution:EvenDistribution2DTriangleBoundary = new EvenDistribution2DTriangleBoundary(new Point(100, 100), new Point(400, 50), new Point(250, 350));
for (var i:int = 0; i < 1000; ++i)
{
// create an object in each iteration of the loop
var circle:Shape = new Shape();
//add some graphics (this is unnecessary if you use a library symbol)
circle.graphics.beginFill(0xff0000, .6);
circle.graphics.drawCircle(0, 0, 3);
circle.graphics.endFill();
// add it to the display list
addChild(circle);
// reposition it with the help of the distribution object
distribution.positionDisplayObject(circle);
}
}
}
}
import flash.display.DisplayObject;
import flash.geom.Point;
internal class EvenDistribution2DTriangleBoundary
{
private var u:Point;
private var v:Point;
private var position:Point;
public function EvenDistribution2DTriangleBoundary(a:Point, b:Point, c:Point)
{
// consider corner "a" as the position of the triangle, this is arbitrary decision, but has to be consistent with the rest of this constructor
position = a;
// create two vectors from the corner that is the position to the other two corners respectively
u = b.subtract(a);
v = c.subtract(a);
}
public function getRandomPosition():Point
{
// random position formula with two random variables: position + (u + (v-u) * random1) * sqrt(random2)
var r1:Number = Math.random();
// the sqrt transforms the probability density function of the even distribution f(x) = 1 into a triangle g(y) = 2y
var r2:Number = Math.sqrt(Math.random());
// applying the above formula to create an evenly distributed random position within the triangle
return position.add(new Point((u.x + (v.x - u.x) * r1) * r2, (u.y + (v.y - u.y) * r1) * r2));
}
// convenience function to position a display object at a random position in the triangle
public function positionDisplayObject(object:DisplayObject):void
{
var position:Point = getRandomPosition();
object.x = position.x;
object.y = position.y;
}
}
创建随机分布是它自己的一个类。为了简单测试,它是一个内部类,因此整个示例是一个进入单个文件的类。当然,在生产代码中,这应该更好地组织起来。
以下是我得到的4个结果:
似乎我需要将所有的帧/时间轴代码(以及很多!)转移到外部类
尽管建议,但这不是必要的。您最终应该只使用基于类的代码,但当然在项目中进行转换并不是非常实用。
在上面的示例中,有两个类:Main
和EvenDistribution2DTriangleBoundary
。你只对后者感兴趣。 Main
就是使用其他课程,创建和展示圈子等等:它是一个演示。
要在项目中使用EvenDistribution2DTriangleBoundary
,请在与名为EvenDistribution2DTriangleBoundary.as
的.fla文件相同的目录中创建一个新文本文件,其中包含以下内容:
package
{
import flash.display.DisplayObject;
import flash.geom.Point;
public class EvenDistribution2DTriangleBoundary
{
private var u:Point;
private var v:Point;
private var position:Point;
public function EvenDistribution2DTriangleBoundary(a:Point, b:Point, c:Point)
{
position = a;
u = b.subtract(a);
v = c.subtract(a);
}
public function getRandomPosition():Point
{
var r1:Number = Math.random();
var r2:Number = Math.sqrt(Math.random());
return position.add(new Point((u.x + (v.x - u.x) * r1) * r2, (u.y + (v.y - u.y) * r1) * r2));
}
public function positionDisplayObject(object:DisplayObject):void
{
var position:Point = getRandomPosition();
object.x = position.x;
object.y = position.y;
}
}
}
现在,您可以像项目中的任何其他类一样使用该类。例如,您可以将Main
的构造函数中的代码添加到时间轴中,它应该可以正常工作:
var distribution:EvenDistribution2DTriangleBoundary = new EvenDistribution2DTriangleBoundary(new Point(100, 100), new Point(400, 50), new Point(250, 350));
for (var i:int = 0; i < 1000; ++i)
{
// create an object in each iteration of the loop
var circle:Shape = new Shape();
//add some graphics (this is unnecessary if you use a library symbol)
circle.graphics.beginFill(0xff0000, .6);
circle.graphics.drawCircle(0, 0, 3);
circle.graphics.endFill();
// add it to the display list
addChild(circle);
// reposition it with the help of the distribution object
distribution.positionDisplayObject(circle);
}
您应该会看到一个红色圆圈的三角形,类似于我在上面的结果图片中发布的那些。这有用吗?