AS3: случайная точка неправильной формы - PullRequest
1 голос
/ 25 сентября 2011

У меня есть MovieClip с неправильной формой, такой как эта:

enter image description here

Мне нужно создать случайную точку на этой фигуре.

Я могу использовать грубую силу, генерируя точки внутри ограничительной рамки, а затем нажимая кнопку «Тестирование», чтобы увидеть, находятся ли они на неправильной форме. Однако я уверен, что есть более эффективный способ решения этой проблемы.

Каков наиболее эффективный способ создания случайной точки неправильной формы?

Ответы [ 2 ]

2 голосов
/ 25 сентября 2011

Если вы думаете о фигурах, не имеющих блобов, ясно, что проверяет случайный пиксель, попробуйте еще раз, метод не очень хороший способ.Ограничивающая область может быть огромной по сравнению с областью формы.

sorry - just paint, no vector graphic.

Чтобы повысить эффективность, вы можете получить получение вектора BitmapDataформа.Он должен содержать все пиксели ограничительной рамки. Обновление - было бы хорошо, если бы мы могли выбрать случайную точку и удалить ее из вектора, если она не находится внутри фигуры.К сожалению, вектор содержит только цвет пикселей, а не позицию, которая является неявной и правильной, только если мы не изменим длину вектора.Поскольку нам не нужно знать фактический цвет, мы можем опустить все прозрачные пиксели и сохранить внутри позиции пикселя в качестве его значения в векторе.Таким образом, нам не нужно создавать новый объект для каждого пикселя фигуры (это будет довольно дорого!).

var v:Vector.<uint> shapeBoxBitmap.getVector(shapeBoxBitmap.rect);
var pixelNum:int = v.length;
for(var i:uint = 0; i < pixelNum; i++) {
    if( v[i] && 0xFF000000 == 0) { // transparent pixel, outside off shape
       v.splice(i,1);
    } else {
      v[i] = i;
    }
}

//get random point
var randomPixel:int = v[Math.floor(Math.random()*v.length)];
var point:Point = new Point(randomPixel%shapeBitmap.width,int(randomPixel/shapeBitmap.width));
2 голосов
/ 25 сентября 2011

Вы упомянули hitTest, но я предполагаю, что вы имели в виду hitTestPoint () .

Если это так, функция, получающая выбранные вами случайные точки, будет выглядеть примерно так:

function getRandomPointsInClip(target:MovieClip,numPoints:int):Vector.<Point>{
    var points:Vector.<Point> = new Vector.<Point>(numPoints,true);
    var width:Number = target.width,height:Number = target.height;
    for(var i:int =  0; i < numPoints ; i++){
        var point:Point = new Point(target.x+Math.random() * width,target.y+Math.random() * height);
        if(target.hitTestPoint(point.x,point.y,true)) points[i] = point;//is the random coord inside ?
        else i = i-1;//nope, go back one step - > retry above until it is inside
    }
    return points;
}

Другое, на что я намекал в своем комментарии, включает в себя циклическое прохождение непрозрачных пикселей в растровых данных вашего объекта. Этот метод гарантирует, что у вас не будет много дубликатов, в отличие от предыдущего метода, но это также означает, что у вас меньше контроля над количеством созданных точек и имеется дополнительная память, используемая для создания растрового изображения. Тем не менее, в целях документации, вот функция:

function getGridPointsInClip(target:MovieClip,res:int,offset:Number = 3):Vector.<Point>{
    var points:Vector.<Point> = new Vector.<Point>();
    var x:int,y:int,alpha:int,w:int = int(target.width),h:int = int(target.height);
    var bmd:BitmapData = new BitmapData(w,h,true,0x00FFFFFF);bmd.draw(target);
    var pixels:Vector.<uint> = bmd.getVector(bmd.rect),numPixels:int = w*h;
    for(var i:int = 0; i < numPixels; i+=res) {
        x = i%bmd.width;
        y = int(i/bmd.width);
        alpha = pixels[i] >>> 24;
        if(alpha > 0) points.push(new Point(x+random(-offset,offset),y+random(-offset,offset)));
    }
    return points;
}
function random(from:Number,to:Number):Number {
    if (from >= to) return from;
    var diff:Number = to - from;
    return (Math.random()*diff) + from;
}

А вот базовый тест:

var pts:Vector.<Point> = getRandomPointsInClip(mc,300);
//var pts:Vector.<Point> = getGridPointsInClip(mc,100,4);
for(var i:int = 0 ; i < pts.length; i++) drawCircle(pts[i].x,pts[i].y,3,0x009900);

function getRandomPointsInClip(target:MovieClip,numPoints:int):Vector.<Point>{
    var points:Vector.<Point> = new Vector.<Point>(numPoints,true);
    var width:Number = target.width,height:Number = target.height;
    for(var i:int =  0; i < numPoints ; i++){
        var point:Point = new Point(target.x+Math.random() * width,target.y+Math.random() * height);
        if(target.hitTestPoint(point.x,point.y,true)) points[i] = point;//is the random coord inside ?
        else i = i-1;//nope, go back one step - > retry above until it is inside
    }
    return points;
}
function getGridPointsInClip(target:MovieClip,res:int,offset:Number = 3):Vector.<Point>{
    var points:Vector.<Point> = new Vector.<Point>();
    var x:int,y:int,alpha:int,w:int = int(target.width),h:int = int(target.height);
    var bmd:BitmapData = new BitmapData(w,h,true,0x00FFFFFF);bmd.draw(target);
    var pixels:Vector.<uint> = bmd.getVector(bmd.rect),numPixels:int = w*h;
    for(var i:int = 0; i < numPixels; i+=res) {
        x = i%bmd.width;
        y = int(i/bmd.width);
        alpha = pixels[i] >>> 24;
        if(alpha > 0) points.push(new Point(x+random(-offset,offset),y+random(-offset,offset)));
    }
    return points;
}
function random(from:Number,to:Number):Number {
    if (from >= to) return from;
    var diff:Number = to - from;
    return (Math.random()*diff) + from;
}
function drawCircle(x:Number,y:Number,radius:Number,color:uint):void{
    graphics.lineStyle(1,color);
    graphics.drawCircle(x-radius,y-radius,radius);
}

НТН

...