as3 addChild生成三角形

时间:2016-07-07 14:08:15

标签: actionscript-3 flash

大家好!我正在尝试动态添加(以及稍后删除)三角形内的一些动画片段。一个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轴)。 重要的是让“玩具”出现在三角形内,不一定要成为一个动画片段。解决这个问题的方法也很棒! 提前谢谢!

2 个答案:

答案 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个结果:

4 results

  

似乎我需要将所有的帧/时间轴代码(以及很多!)转移到外部类

尽管建议,但这不是必要的。您最终应该只使用基于类的代码,但当然在项目中进行转换并不是非常实用。

在上面的示例中,有两个类:MainEvenDistribution2DTriangleBoundary。你只对后者感兴趣。 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);
}

您应该会看到一个红色圆圈的三角形,类似于我在上面的结果图片中发布的那些。这有用吗?