Distributing widths of a group of objects in AS3 - actionscript-3

Say I have a set of 5 MovieClips with same y locations but spread out x locations in ascending order (e.g obj1.x = 0, obj5.x = 10), is there an AS3 method that helps me distribute their widths like the option under Modify > Align in flash, so their x locations are equally spaced between 0 and 10?
Thanks

Here is a function I wrote many years ago that you may find useful. It assumes that the things you want to space out are the sole children of a parent/container. You pass that parent to this function as the first parameter (displayObj). Hopefully the comments at the start explain to you well enough what each parameter does, if not just comment and I'll clarify.
/**
* Distribte all the children of the specified display object on either x or y axis
* #param displayObj - the display oject whose children should be distributed
* #param onX - should it distribute along the x axis (true) or the y axis (false)
* #param spacing - how much space between children in pixels
* #param center - should the children be centered on the opposite axis
* #param startingX - default 0
* #param startingY - default 0
* #param fixedWidth - use a fixed width instead the automatic width of each child
* #param foldPoint - how far along before the item should fold and be a new row/col
*/
public static function distributeAxis(displayObj:Sprite,onX:Boolean = true,spacing:Number = 5, center:Boolean = false, startingX:Number = 0,startingY:Number = 0,fixedWidth:Number = 0, foldPoint:Number = 0):void {
//Loop Through Children
var tObj:DisplayObject;
var tNum :Number = (onX) ? startingX : startingY;
var tNum2 :Number = (onX) ? startingY : startingX;
var max :Number = 0;
var centeringArray:Vector.<DisplayObject>
if (center) {
centeringArray = new Vector.<DisplayObject>();
}
for(var i:int = 0; i<displayObj.numChildren;i++)
{
tObj = displayObj.getChildAt(i);
if (onX) {
if (foldPoint > 0 && tNum + tObj.width > foldPoint) {
tNum = startingX;
tNum2 += max + spacing;
if(center){
distributeAxisCenterIt(centeringArray, max, onX);
centeringArray = new Vector.<DisplayObject>();
}
max = 0;
}
if(tObj.height > max) max = tObj.height;
tObj.x = tNum;
tObj.y = tNum2;
if(fixedWidth > 0){
tNum += fixedWidth + spacing;
}else{
tNum += tObj.width + spacing;
}
if(center){
centeringArray.push(tObj);
}
}else{
if(tObj.width > max) max = tObj.width;
if (foldPoint > 0 && tNum + tObj.height > foldPoint) {
tNum = startingY;
tNum2 += max + spacing;
if(center){
distributeAxisCenterIt(centeringArray, max, onX);
centeringArray = new Vector.<DisplayObject>();
}
max = 0;
}
tObj.y = tNum;
tObj.x = tNum2;
if(fixedWidth > 0){
tNum += fixedWidth + spacing;
}else{
tNum += tObj.height + spacing;
}
if(center){
centeringArray.push(tObj);
}
}
}
if (center) {
distributeAxisCenterIt(centeringArray, max, onX);
}
}
private static function distributeAxisCenterIt(array:Vector.<DisplayObject>, max:Number, onX:Boolean = true):void {
for each(var tObj:DisplayObject in array){
if(onX){
tObj.y += ((max - tObj.height) * .5);
}else{
tObj.x += ((max - tObj.width) * .5);
}
}
}

You need to use this: AS3 Commons UI. It has all you could ever want:) with layout/align etc. and components
but if you want a code not a framework this is what I'm using for spreading items across given width in my own "framework":
/**
* Distributes all components using given value as a limit.
* #param p_nMaxWidth width of the area to spread items
*/
protected function spreadComponents(p_nMaxWidth:Number):void
{
if (numChildren == 0) return;
if (p_nMaxWidth < 0 || isNaN(p_nMaxWidth)) p_nMaxWidth = 600;
var _oItem:DisplayObject;
var dx:Number = 0;
var i:int;
var _nWidth:Number = calculateWidths();//get sum of all items widths
var _nStep:Number = (p_nMaxWidth - _nWidth - getChildAt(numChildren - 1).width) / (numChildren-1);
for (i = 0; i < numChildren; i++)
{
_oItem = getChildAt(i);
//if(m_bResetChildrenPosition) _oItem.y = 0;//this I was using to reset or keep intact the items y position
_oItem.x = Math.round(dx);
dx += _oItem.width + _nStep;
}
//as a precaution if rounding would give incorrect position (which should be for last item exactly at the p_nMaxWidth - width (right edge aligned)).
getChildAt(numChildren - 1).x = p_nMaxWidth - getChildAt(numChildren - 1).width;
updateDimension();
}
//
/**
* Utility method, returns width of all children (sum).
* #return
*/
protected function calculateWidths():Number
{
var _nWidth:Number = 0;
for (var i:int = 0; i < numChildren-1; i++)
{
_nWidth += getChildAt(i).width;
}
return _nWidth;
}
this code spreads items horizontaly across given width - left edge of first item is at start, right edge of last item is at the end of that "width".
best regards

Related

Optimum tile size/layout in a space

This is for an air app but I'm sure it's a common issue for other things.
I've really been struggling to work out the best way to size tiles in a grid. I've got something like the code below, which kind of works but the problem I'm having is that the whole thing scales down too much on small screens.
I'm trying to find an optimum way of scaling a number of tiles so they fit the screen and stay the largest size possible. I could implement scrolling but I'd like to avoid that.
Is there a less convaluted/more effective way of arranging and scaling tiles to fit in a space?
var scaleFactor:Number = Model.appScale * this.scaleX;
var gap:Number = 10 /scaleFactor;
var _width:Number = stage.fullScreenWidth / scaleFactor;
var sampleWidth:Number = sample.width;
var sampleHeight:Number = sample.height;
var _scale:Number = 1;
var colWidth:Number = sampleWidth + gap;
var totalWidth:Number;
var columns:Number = 0;
var rows:Number = 0;
do{
rows ++;
columns = Math.ceil(_children.length/rows);
totalWidth = columns * colWidth;
if(rows > Math.sqrt(_children.length) && totalWidth > _width)
_scale = (_width/totalWidth) * _scale;
totalWidth = columns * colWidth * _scale;
}
while(totalWidth > _width)
var top:Number = - ((rows * (sampleHeight + gap)) + (gap *2)) * _scale;
// if it's too big scale it down
var pt:Point = localToGlobal(new Point(0, 0));
if(Math.abs(top) > pt.y/scaleFactor){
_scale = (((pt.y - (bg.height + gap))/scaleFactor)/Math.abs(top)) * _scale;
top = -pt.y/scaleFactor;
}
var col:int = 0;
var row:int = 0;
for each(var button:MenuRenderer in _children)
{
Tweener.addTween(button,{
x : _0x + (((sampleWidth + gap) * _scale) * col),
y : top + (((sampleHeight + gap) * _scale) * row),
scaleX: _scale,
scaleY: _scale,
time: 0.05 * button.order,
transition: "easeInOut"
});
col ++;
if(col == columns)
{
row ++;
col = 0;
}
}

Properly hovering over isometric tile sprite

I have four classes: Room, TileGrid, HoverTile, and Tile.
Room is composed of walls and a TileGrid. TileGrid is made out of Tile. Currently, I use this code to generate a TileGrid out of Tiles:
this.mapArray = [[1,1,1,1,1,1,1],
[1,1,1,1,1,1,1],
[1,1,1,1,1,1,1],
[1,1,1,1,1,1,1],
[1,1,1,1,1,1,1],
[1,1,1,1,1,1,1],
[1, 1, 1, 1, 1, 1, 1]];
this._mapHeight = this.mapArray.length;
this._mapWidth = this.mapArray[0].length;
this._tileHeight = 23;
this._tileWidth = 46;
var initialX:Number = 260;
var initialY:Number = 150;
for (var isoY:int = 0; isoY < mapArray.length; isoY++)
{
for (var isoX:int = 0; isoX < mapArray[isoY].length; isoX++)
{
if (isoX == 0 && isoY == 0)
{
var _tile:Tile = new Tile();
_tile.x = initialX;
_tile.y = initialY;
this.addChild(_tile);
}
if (this.mapArray[isoY][isoX] == 1)
{
var _tile:Tile = new Tile();
_tile.x = initialX - (isoX * 20) - (isoY * 20);
_tile.y = initialY - (isoX * 10) + (isoY * 10);
addChild(_tile);
_tile.addEventListener(MouseEvent.MOUSE_OVER, updateHover);
}
}
}
My current issue is that I want to add a white square around the tile that a mouse is hovering over. The code I used to use wasn't sufficient, because transparent parts of the Tile sprite are still counted as part of it. So even if I'm pointing at another Tile2 (which is next to Tile1), for example, if I'm not far enough onto Tile2, it'll highlight Tile1.
So, here's the current code I'm using:
public function updateHover(e:MouseEvent):void
{
var mX:int = e.stageX - (_tileWidth / 2);
var tPoint:Point = pointToXY(mX, e.stageY);
var isoX = tPoint.x;
var isoY = tPoint.y;
if (isoX >= 0 && isoY >= 0)
{
if (isoY < mapArray.length)
{
if (isoX < mapArray[0].length)
{
tPoint = xyToPoint(isoX, isoY);
_tileHover.x = tPoint.x;
_tileHover.y = tPoint.y;
_tileHover.visible = true;
return;
}
}
}
_tileHover.visible = false;
}
public function pointToXY(x:int, y:int):Point
{
x -= 260;
y -= 150;
var pRatio:int = (_tileWidth / 2) / (_tileHeight / 2);
var tX:int = (y + x / pRatio) * (pRatio / 2) / (_tileWidth / 2);
var tY:int = (y - x / pRatio) * (pRatio / 2) / (_tileWidth / 2);
return new Point(tX, tY);
}
public function xyToPoint(x:int, y:int):Point
{
x -= 1;
var worldPoint:Point = new Point(0, 0);
worldPoint.x = (x * (_tileWidth / 2)) - (y * (_tileWidth / 2));
worldPoint.y = (x * (_tileHeight / 2)) + (y * (_tileHeight / 2));
worldPoint.x = worldPoint.x + (_tileWidth / 2);
worldPoint.y = worldPoint.y + (_tileHeight / 2);
worldPoint.x += 260;
worldPoint.y += 150;
return worldPoint;
}
Sorry I have to post so many code blocks. Now, 260 and 150 are the default starting point for the entire room. That said, I'm really confused on how to get the last two functions in particular to work so that they'll give me the correct answer. This is what I expected from using this code:
That would be perfect. But, again, I don't know why the code isn't working. The sizes are all correct and I believe the offset is, too. So, I'm
First, you should add the listener to this, not to _tile, because then you are locked to stage coordinates to determine the tile that's selected, which is not good. Second, your listener should be against MouseEvent.MOUSE_MOVE event, not over, this way you'll constantly get updated mouse coords to properly move your rectangle over tiles. And you have a minor error out there, you have a (0,0) tile created two times, one being inactive.
for (var isoY:int = 0; isoY < mapArray.length; isoY++)
{
for (var isoX:int = 0; isoX < mapArray[isoY].length; isoX++)
{
if (this.mapArray[isoY][isoX] == 1)
{
var _tile:Tile = new Tile();
_tile.x = initialX - (isoX * 20) - (isoY * 20);
_tile.y = initialY - (isoX * 10) + (isoY * 10);
addChild(_tile);
}
}
}
this.addEventListener(MouseEvent.MOUSE_MOVE, updateHover);
Also, it'll be better that you'd store (x,y) pairs on the array (as tiles, most likely), so that your initial array of zeroes and ones would transform into an array of Tile objects. To do that, you first do this:
this.tileArray=[];
for (var i:int=0;i<this.mapArray.length;i++)
this.tileArray.push(new Array(this.mapArray[i].length));
This will create an array of nulls that matches your mapArray by dimensions, that will serve as placeholder for created Tile objects. After you do this, you call this.tileArray[isoY][isoX]=_tile; to place the newly created tile to its place. After that, you can rewrite your listener to this:
public function updateHover(e:MouseEvent):void
{
var p:Point=pointToXY(e.localX,e.localY);
_tileHover.visible = false; // hide hover for now
if ((p.y<0) || (p.y>=tileArray.length)) return; // range error on Y
if ((p.x<0)||(p.x>=tileArray[p.y].length)) return; // range error on X
if (!tileArray[p.y][p.x]) return; // no tile
var _tile:Tile=tileArray[p.y][p.x];
_tileHover.x=_tile.x;
_tileHover.y=_tile.y; // no need to convert xyToPoint() we have coords stored in tile
_tileHover.visible=true;
}

Pairing a draggable object to a target object in AS3

I'm currently stuck with my approach below. I'm not entirely sure if using "hitTestObject" method is appropriate in pairing the pieces to their respective place. I was able to at least match the chess piece to their respective location (that's the best I can do and I feel i'm doing it wrong) but I'm now stuck in counting how many pieces are actually in their correct places. e.g. when I move the pawn to a different tile, it will still count as one, I also want to avoid duplicate counting, example, If pawn is already in the correct location, it will just count as 1, and if it was moved, then that count will be removed. Only count the pieces that are in the correct tile.
My goal here is to be able to make all the chess pieces draggable and determine if they're in their respective location. If ALL the chess pieces are in their location, it will trace or call a function.
Thank you!
import flash.events.Event;
import flash.display.MovieClip;
import flash.events.MouseEvent;
/* Declaring an X and Y variable to be used as a reset container */
var xPos: int, yPos: int;
/* Attaching event listeners for each chess piece */
addListeners(
king, queen, bishop_1, bishop_2, knight_1, knight_2, rook_1, rook_2,
pawn_1, pawn_2, pawn_3, pawn_4, pawn_5, pawn_6, pawn_7, pawn_8);
/* Getting the original x and y postion to be used as a reset */
function getPosition(currentTarget: Object): void {
xPos = currentTarget.x;
yPos = currentTarget.y;
}
/* Function to get the suffix value of an object. example, I need to get the value 4 from "pawn_4" */
function getLastCharInString($s: String, $pos: Number): String {
return $s.substr($s.length - $pos, $s.length);
}
/* A simple function that rotates the chess piece */
function lift(object: Object, rot: Number) {
object.rotation = rot;
}
function dragObject(e: MouseEvent): void {
getPosition(e.currentTarget);
lift(e.currentTarget, -10);
getChildByName(e.currentTarget.name + "_hs").alpha = 1;
e.currentTarget.startDrag();
}
/* This variable is supposed to hold the value of each piece that is correctly placed in each tile.
The total score should be 16 as there are 16 pieces. Only correcly placed piece should be added in the total score. */
var counter:int;
function stopDragObject(e: MouseEvent): void {
var curretTarget = e.currentTarget.name;
lift(e.currentTarget, 0);
/* Hide active hotspots */
getChildByName(e.currentTarget.name + "_hs").alpha = 0;
var multiplePieceSufix = Number(getLastCharInString(curretTarget, 1));
if (multiplePieceSufix >= 1) {
/* Boolean variables that checks whether the current piece is active*/
var isPawn: Boolean = false,
isBishop: Boolean = false,
isKnight: Boolean = false,
isRook: Boolean = false,
currentTargeName;
var widthDiff = getChildByName(e.currentTarget.name + "_hs").width - getChildByName(e.currentTarget.name).width / 2;
var heightDiff = getChildByName(e.currentTarget.name + "_hs").height - getChildByName(e.currentTarget.name).height / 2;
if (curretTarget.substr(0, 4) == "pawn") {
isPawn = true;
} else if (curretTarget.substr(0, 6) == "bishop") {
isBishop = true;
} else if (curretTarget.substr(0, 6) == "knight") {
isKnight = true;
} else if (curretTarget.substr(0, 4) == "rook") {
isRook = true;
}
if (isPawn == true) {
/* there are total of 8 pieces of pawn */
for (var w = 1; w < 9; w++) {
currentTargeName = this["pawn_" + w + "_hs"];
if (e.target.hitTestObject(currentTargeName)) {
/* For some reason the chess pieces are not aligning with their "_hs" version, I already checked their registry point and it seem to be normal.
so to fix, I had to manually add some hard coded values to adjust their location. */
e.currentTarget.x = currentTargeName.x - 8;
e.currentTarget.y = currentTargeName.y + currentTargeName.height;
}
}
} else if (isBishop == true) {
for (var x = 1; x < 3; x++) {
currentTargeName = this["bishop_" + x + "_hs"];
if (e.target.hitTestObject(currentTargeName)) {
e.currentTarget.x = currentTargeName.x - 9;
e.currentTarget.y = currentTargeName.y + currentTargeName.height - 18;
}
}
} else if (isKnight == true) {
for (var y = 1; y < 3; y++) {
currentTargeName = this["knight_" + y + "_hs"];
if (e.target.hitTestObject(currentTargeName)) {
e.currentTarget.x = currentTargeName.x - 8;
e.currentTarget.y = currentTargeName.y + currentTargeName.height;
}
}
} else if (isRook == true) {
for (var z = 1; z < 3; z++) {
currentTargeName = this["rook_" + z + "_hs"];
if (e.target.hitTestObject(currentTargeName)) {
e.currentTarget.x = currentTargeName.x - 8;
e.currentTarget.y = currentTargeName.y + 62;
}
}
}
} else {
if (e.target.hitTestObject(getChildByName(e.currentTarget.name + "_hs"))) {
/* Again, I'm not sure why the pieces are not aligning as intended.
modX and modY is a holder for the adjustment value. I'm not comfortable
seeing this approach myself, but I also run out of ideas how to fix it. */
var modX: Number, modY: Number;
if (e.currentTarget.name == "king") {
modX = 11;
modY = 53;
} else {
modX = 11;
modY = 29;
}
e.currentTarget.x = getChildByName(e.currentTarget.name + "_hs").x - modX;
e.currentTarget.y = getChildByName(e.currentTarget.name + "_hs").y + getChildByName(e.currentTarget.name + "_hs").height - modY;
}
}
/* This is supposed to add to the total score or count of how many pieces are placed correctly.
Thie problem with thi scounter, as it also counts any piece that is places to any "_hs" */
counter++;
trace(counter);
e.currentTarget.stopDrag();
}
function addListeners(...objects): void {
for (var i: int = 0; i < objects.length; i++) {
objects[i].addEventListener(MouseEvent.MOUSE_DOWN, dragObject);
objects[i].addEventListener(MouseEvent.MOUSE_UP, stopDragObject);
// hide hotspots
getChildByName( objects[i].name + "_hs" ).alpha = 0;
}
}
Source: Download the FLA here
--
Updates:
I have added comments in my code to clarify what I'm trying to accomplish.
I'm planning to do board game in flash which has similar function and behaviour to this. User can drag the object to a specified tile and check wether that object belongs there or not.
After reviewing your code, your question is quite broad. I'm going pair it down to what seems to be your main concern - the score / counting correctly moved pieces.
Right now, you do the following every time an object is dragged:
counter++;
This means that the counter will increment no matter where you drag the object, and no matter how times you drag the object. (so even if the piece was already in the correct spot, if you dragged it a second time it will still increment your counter).
What you need to do, is associate a flag with each object to indicate whether it is in the correct location or not, and set that flag to the appropriate value every time that object is done dragging.
Something like this:
//don't use target, use currentTarget
if (e.currentTarget.hitTestObject(currentTargeName)) {
e.currentTarget.correct = true; //since MovieClips are dynamic, you can just make up a property on them and assign a value to it.
//to fix your alignment:
e.currentTarget.x = currentTargeName.x + ((currentTargetName.width - e.currentTarget.width) * 0.5);
e.currentTarget.y = currentTargeName.y + currentTargeName.height;
}else{
//if the hit test is false, mark it as NOT correct
e.currentTarget.correct = false;
}
Then, later to know the current count, iterate over all the pieces and check their correct value. This would be much easier if all your pieces were in an array.
var allPieces:Array = [king, queen, bishop_1, bishop_2, knight_1, knight_2, rook_1, rook_2,
pawn_1, pawn_2, pawn_3, pawn_4, pawn_5, pawn_6, pawn_7, pawn_8];
function countCorrect():Boolean {
var ctr:int = 0;
for(var i:int=0;i<allPieces.length;i++){
if(allPieces[i].correct) ctr++;
}
return ctr;
}
trace(countCorrect() + " of " allPieces.length " are correct");
As an aside, this best way to do this would be with some custom class files. That would however require a complete refactoring of your code.
Also, you probably don't want to use hitTestObject, as even if a piece is mostly over a neighbor, it will still be true as long as 1 pixel of it's bound touch 1 pixel of the tile. Better would be to do a hitTestPoint on the tile, and pass in the center point of the piece (the the middle of the piece has to be touching the tile for it to count).
//a point that is the center of the events current target (the piece)
var point:Point = new Point();
point.x = e.currentTarget.x + (e.currentTarget.width * 0.5);
point.y = e.currentTarget.y - (e.currentTarget.height * 0.5);
if (currentTargetName.hitTestPoint(point)) {

How to position objects randomly on y-axis with a variable distance between each of the objects, which is always greater than a specific value?

I am placing 4 objects through a for-loop on the y-axis. Each object is placed randomly on the y-axis using the following method:
myObject.y = stage.stageHeight * Math.random();
The problem is sometimes the objects are too far from each other and other times they are over lapping each other. What I want to achieve is to always have some distance between each of the two objects. I want that distance to be always greater than a specific value. I have been trying to work this out for 2 days but couldn't figure it out.
Here is what I tried to get rid of overlapping:
function createObstacles():void
{
var currentElements:Array = [];
var myRect:Obstacle;
for(var k:int = 0; k < 4; k++)
{
myRect = new Obstacle();
addChild(myRect);
myRect.x = stage.stageWidth + 30;
myRect.y = stage.stageHeight * Math.random();
obstacles.push(myRect);
currentElements.push(myRect);
}
checkOverlap(myRect,currentElements);
}
function checkOverlap(rect:Obstacle, elements:Array)
{
for(var n:uint = 0; n < elements.length; n++)
{
if(rect.hitTestObject(elements[n]))
{
rect.y = stage.stageHeight * Math.random();
}
}
}
The elements still overlap. About always keeping a distance between each of the two objects, I just couldn't get my head around that. I googled but nothing relevant returned. Any kind of help would be greatly appreciated.
You can set the object's y based on the previous object'y value.
function createObstacles():void
{
var currentElements:Array = [];
var myRect:Obstacle;
var minDistance:int = 5;//the min distance between two objects
var maxDistance:int = 10;//the max distance between two objects.
for(var k:int = 0; k < 4; k++)
{
myRect = new Obstacle();
addChild(myRect);
myRect.x = stage.stageWidth + 30;
if (k == 0)
{
// make sure four objects in one page
myRect.y = stage.stageHeight/2 * Math.random();
}
else
{
var distance:int = (maxDistance - minDistance)*Math.random() + minDistance;
myRect.y = obstacles[k - 1].y + distance;
}
obstacles.push(myRect);
currentElements.push(myRect);
}
}

How to create stair effect

So Im trying to constantly add elements on the stage and those elements to have a specific X and Y
what i mean and what i want to get is a stairway effect (up and down) :
lets say 1st element is 100 pix above stage.Y
2nd element: Y is 1st element.y + 2nd element.height and its X position is 1st element.x + 2nd element.width(it appears immediately after we can see the whole body of 1st element)
3rd element : Y is 2st element.y + 3nd element.height and its X position is 2st element.x + 3nd element.width(it appears immediately after we can see the whole body of 2st element)
and the last element before the stairway effect goes down will be stage.stageheight - 100
like in this picture
Yet I dont know how to do this (I know i have to put it in a for loop and in there to have a if statement that checks every time for the up and down border (stage.stageHeight - 100 and stage.Y + 100) but i cant figure it out)
what i have so far is this
private var itemsToAnimate:Array = []
private var magnetBuff:Boolean = false;
private var block:Block = new Block();
private var stage_H:int = stage.stageHeight;
private var block_H:int = block.height;
public function AB_Main()
{
this.addEventListener(Event.ADDED_TO_STAGE, init);
}
private function init(evt:Event)
{
this.removeEventListener(Event.ADDED_TO_STAGE, init);
this.addEventListener(Event.ENTER_FRAME, onEveryFrame);
}
private function onEveryFrame(ev:Event):void
{
createItems()
animateItems();
}
private function animateItems():void
{
var itemToTrack:Block;
for(var i:uint = 0; i < itemsToAnimate.length; i++)
{
itemToTrack = itemsToAnimate[i];
itemToTrack.x -= 3;
if(itemToTrack.x < -50)
{
itemsToAnimate.splice(i, 1);
this.removeChild(itemToTrack);
}
}
}
private function createItems():void
{
if(Math.random() > 0.75)
{
var itemToTrack:Block = new Block();
itemToTrack.x = stage.stageWidth - 50;
itemToTrack.y = int( Math.random() * stage.stageHeight)
this.addChild(itemToTrack);
itemsToAnimate.push(itemToTrack);
}
}
and that gets me a random positioning blocks like in the picture
I think you could do something like this (writing it from my head without testing, I hope it will run ok):
function draw(min:Number, max:Number, horSpacing:Number, vertSpacing:Number):void {
var increasing:Boolean = true;
var lastY:Number = min + vertSpacing;
for(var i:int=0; i<100; i++) {
var c:Circle = new Circle(); //where Circle would be your dot with registration point in center
c.x = 20 + i * horSpacing; //hardcoded margin
c.y = (increasing) ? lastY - vertSpacing : lastY + vertSpacing;
lastY = c.y;
addChild(c);
if(c.y <= max) increasing = false;
if(c.y >= min) increasing = true;
}
}
draw(stage.stageHeight - 100, 100, 20, 20);
What you have here is a value that will constantly increase along the x axis and then another that will either be increasing or decreasing along the y axis, alternating when you touch the top or bottom. That's as simple as:
var increaseY:Boolean = true; // Whether we are moving up or down the y axis.
var position:Point = new Point(); // Position to place next item.
var move:int = 10; // How much we move along each axis.
var margin:int = 100; // Distance from top or bottom before alternating.
for each(var i:Sprite in itemsToAnimate)
{
i.x = position.x;
i.y = position.y;
if(increaseY) position.y += move;
else position.y -= move;
position.x += move;
if(position.y < margin || position.y > stage.stageHeight - margin)
{
// Reverse direction.
increaseY = !increaseY;
}
}
move can be adjusted to change the distance between each item along the path.