How to randomly swap shapes' positions in specific locations - actionscript-3

HELP! I'm trying to create a memory game and I'm not too sure how to randomize the shapes' positions in set x and y locations. They can't overlap so they must be randomized in 12 different locations every time the user starts the program.

Store your x and y positions in arrays
var xArray=new Array();
var yArray=new Array();
xArray[0]=50;
yArray[0]=50;
xArray[1]=100;
yArray[1]=50;
xArray[2]=150;
yArray[2]=50;
...
Create an array of values for each of your shapes
var valueArray=new Array(0,1,2.....);
Shuffle the values in this array - as3 random array - randomize array - actionscript 3
Set you shape's positions
shape0.x=xArray[valueArray[0]];
shape0.y=yArray[valueArray[0]];
shape1.x=xArray[valueArray[1]];
shape1.y=yArray[valueArray[1]];
shape2.x=xArray[valueArray[2]];
shape2.y=yArray[valueArray[2]];

try that:
function randomSort(a:*, b:*):Number
{
if (Math.random() < 0.5) return -1;
else return 1;
}
// Push 12 positions as new Point() in an array.
var positions:Array = [ new Point(12, 42), new Point(43, 56), new Point(43,87) ]; // ...add 12 positions
var mcs:Array = [mc1, mc2, mc3]; // ...add 12 mcs
positions.sort(randomSort);
// link randomized position to MovieClips:
for (var i:int = 0, l:int = positions.length; i < l, i++ ) {
var mc:MovieClip = mcs[i];
var point:Point = positions[i];
mc.x = point.x;
mc.y = point.y;
}

Related

how to select random objects to display on a fixed position in adobe flash

I am working on a flash project and I want to select random objects from a number of objects.
For example if I have 15 objects and I want to randomly select just 4 objects and display them on the stage at fixed position.
I have searched different forums and the problems discussed on different forums are about changing the random position of objects
Note that I don't want to randomize objects position on stage I want to select random objects from multiple objects
I have no idea how to do this.
Please help me if anyone can.
The best thing is to put those objects into array, and then get random element from it.
Here is a quick example:
var objects:Array = new Array[obj1, obj2, obj3, obj4, obj5];
var random:Object = objects.splice(int(Math.random() * objects.length), 1)[0];
Have in mind that these are predefined objects - you must populate the array by yourself. Another thing is that this splices the array, which means it removes items from it.
Good luck!
Similar to Andrey Popov's answer but step by step instead of one line:
//an array of symbols
var objects:Array = new Array(red,blue,green);
//Number you need
var needed:Number = 2;
for (var i:Number = 0;i< needed;i++){
var randomPos = int(Math.random()*objects.length);
//Insert fixed position here
objects[i].x = 0;
//remove object from array
objects.splice(i,1);
}
You need some algorithm to get unique N objects from the object pool. For example try this one:
function getItemsFrom(list:Array, count:uint):Array {
var result:Array = [];
var needed:uint = count;
var available:uint = list.length;
while (result.length < count) {
if (Math.random() < needed / available) {
result.push(list[available - 1]);
needed--;
}
available--;
}
return result;
}
//Simple test, and some results are: [16,9,7,5], [14,13,10,1], etc
var test:Array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16];
for(var i:uint = 0; i < 20; ++i){
trace(getItemsFrom(test, 4));
}
After you will get array of objects, place them where you want.
//Place items vertically at (5,5);
var startX:int = 5;
var startY:int = 5;
//Vertical padding between items
var paddingY:int = 10;
//Current Y position
var posY:int = startY;
//Ger 2 random unique items from the given collection "someListWithItems"
var itemsToPlace:Array = getItemsFrom(someListWithItems, 2);
var item:DisplayObject, i:uint, len:uint = itemsToPlace.length;
for (i; i < len; ++i) {
item = itemsToPlace[i];
item.x = startX;
item.y = posY;
//Offset current position on height of object, plus padding
posY += item.height + paddingY;
//Add item to the display list
addChild(item);
}

HitTest Multiple MovieClips with Array

I have a MovieClip exported to ActionScript called smallGainPoints. What i want to do is create multiple instances of this MovieClip on the stage in a linear or diagonal path. When this is accomplished i want a hitTestObject to take place between the Points array and the Player. The points are added to stage where i would want them to be, but the HitTest wont initiate.
Here is how i set up the Functions:
This Function is added in my Gameloop which is called from an onEnterFrame handler:
private function checkPlayerHitPoints():void
{
for (var j:int = 0; j < aPointsArray.length; j++)
{
//get current points in j loop
var currentPoints:smallGainPoints = aPointsArray[j];
//test if player is hitting current point
if (player.hitTestObject(currentPoints))
{
//remove point on stage
currentPoints.destroyPoints()
//remove point from array
aPointsArray.splice(j, 1);
nScore += 5;
updateHighScore();
}
}
}
Im not sure if i did this right but i want to add multiple instances of the points in a line so the player can gather as much points as possible. So i created a function and set the positions then added the function in my constructor as so addPointsToStage() so it doesn't loop every frame.
private function addPointsToStage():void
{
for (var i = 0; i < nPoints; i++)
{
points = new smallGainPoints();
stage.addChild(points);
points.x = (stage.stageWidth / 2);
points.y = (stage.stageHeight / 2);
points = new smallGainPoints();
stage.addChild(points);
points.x = (stage.stageWidth / 2) + 200;
points.y = (stage.stageHeight / 2);
}
This is how I initiated the array:
public var points:smallGainPoints;
private var nPoints:Number = 5;
private var aPointsArray:Array;
Then in my Constructor i added:
aPointsArray = new Array();
So the points are added to the stage but the hittest doesnt work. Please help!
In your addPointsToStage method, you never add your smallGainPoints object to the array.
After this line:
points = new smallGainPoints();
Push the new points object onto the aPointsArray array:
aPointsArray.push(points);
EDIT:
A better way to add your points in a row might be like this:
private function addPointsToStage():void
{
var startPoint:Point = new Point(stage.stageWidth / 2, stage.stageHeight / 2);
var spacing:Number = 50;
for (var i = 0; i < nPoints; i++)
{
points = new smallGainPoints();
aPointsArray.push(points);
addChild(points);
points.x = startPoint.x + (spacing * i);
points.y = startPoint.y;
}
}
This for loop will add a bunch of smallGainPoint objects in a row, starting from the center of the screen and going right.

AS3 which item in an array has the lower value?

I’m trying to make a game like tower defence in AS3 and currently cant find solution to check which item in an array has the lower value of distance between enemy and turret, in order to choose which enemy to attack first.
I'm really stuck with this problem and asking for your help.
Here is a short code:
var enemyArray:Array = new Array();
var turretArray:Array = new Array();
addEventListener(Event.EnterFrame, loop);
// adding enemies
for(var i:int=0; i<3; i++){
var enemy:Enemy = new Enemy();
...
...
enemyArray.push(enemy);
addChild(enemy);
}
// adding turret
for(var t:int=0; t<2; t++){
var turret:Turret = new Turret();
...
...
turret.destinationX = 0;
turret.destinationY = 0;
turret.distance = 0;
turretArray.push(turret);
addChild(turret);
}
// loop
function loop(event:Event):void{
for(var j:int=enemyArray.length-1; j>=0; j--){
for(var k:int=turretArray.length-1; k>=0; k--){
// getting destination
turretArray[k].destinationX = turretArray[k].x - enemyArray[j].x;
turretArray[k].destinationY = turretArray[k].y - enemyArray[j].y;
// getting distance between turret and enemy
turretArray[k].distance = Math.sqrt(turretArray[k].destinationX*turretArray[k].destinationX+turretArray[k].destinationY*turretArray[k].destinationY);
// here i need to get min value from all turrets distance
}
}
}
Looks like you just need to be keeping track of the lowest value you've found as you go rather than overwriting it every time (if I've understood your code, correctly).
// loop
function loop(event:Event):void{
for(var k:int=turretArray.length-1; k>=0; k--)
{
turretArray[k].distance = -1;
for(var j:int=enemyArray.length-1; j>=0; j--)
{
var dx = turretArray[k].x - enemyArray[j].x;
var dy = turretArray[k].y - enemyArray[j].y;
var dist = Math.sqrt(dx * dx + dy * dy);
if(dist < turretArray[k].distance || turretArray[k].distance < 0)
{
turretArray[k].distance = dist;
turretArray[k].destinationX = dx;
turretArray[k].destinationY = dy;
}
}
}
}
Here, we store the initial distance value found in turretArray[k].distance, and only overwrite that if we find a lower one. We set it to -1 each time so we can tell if it's been set, yet, or not.
This is the equation you want:
http://www.mathopenref.com/coorddist.html
sqrt( (turret1X - turret2x)^2 + (turret1Y - turret2Y)^2 )

AS3: Random Point on Irregular Shape

I have a MovieClip holding an irregular shape such as this one:
I need to generate a random point on this shape.
I can use brute force by generating points within the bounding box and then hitTesting to see if they reside on the irregular shape. However, I'm sure there's a more efficient way to tackle this problem.
What is the most efficient way to generate a random point on an irregular shape?
You mentioned hitTest, but I assume you meant hitTestPoint().
If so, a function go get the random points you mention, would look a bit like this:
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;
}
The other I hinted at in my comment involves looping through non transparent pixels in a bitmap data of your object. This method would insure you don't have many duplicates, as opposed to the previous method, but it also means, you have less control over the number of points created and there's extra memory used for creating the bitmap. Still, for documentation purposes, here is the function:
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;
}
And here'a very basic test:
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);
}
HTH
If you think of some non-blob like shapes, it's clear the check random pixel, try again method isn't really a good way. The bounding box area could be huge compared to the shape area.
What you could do to improve the effectiveness is getting a vector of the BitmapData of the shape. It should contain all pixels of the bounding box. Update - it would be nice now if we could pick a random point, and remove it from the vector if it isn't inside the shape. Unfortunately the vector only contains the pixels' colour, not the position which is implicit and only correct if we don't change the vector's length. Since we don't need to know the actual colour, we can omit all transparent pixels and store an inside pixel's position as it's value in the vector. This way we don't need to create a new object for each pixel of the shape (that would be quite expensive!).
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));

8 queens problem

I am trying to solve the 8 queens problem (where you select a space and it will put down 8 queens so that none of them will hit each other) but i am having trouble making the chess board.
right now i have this
var chessBoard:Array = new Array();
chessBoard["row1"] = [1,0,1,0,1,0,1,0];
chessBoard["row2"] = [0,1,0,1,0,1,0,1];
chessBoard["row3"] = [1,0,1,0,1,0,1,0];
chessBoard["row4"] = [0,1,0,1,0,1,0,1];
chessBoard["row5"] = [1,0,1,0,1,0,1,0];
chessBoard["row6"] = [0,1,0,1,0,1,0,1];
chessBoard["row7"] = [1,0,1,0,1,0,1,0];
chessBoard["row8"] = [0,1,0,1,0,1,0,1];
and i need to know two things
a) will i be able to use this for the problem (will i be able to have it check if any queens will collide by its array coordinates)
b) how do i draw the squares on the chess board to correspond with the numbers
var chessBoard:Array = new Array();
// Setup the array
for(var i:int = 0; i < 4; i++)
{
chessBoard.push(new Array(1,0,1,0,1,0,1,0));
chessBoard.push(new Array(0,1,0,1,0,1,0,1));
}
// Size of the tile
var tileSize:int = 20;
function createChessBoard():void
{
// Itterate through the "chessBoard"-array
for(var i:int = 0; i < chessBoard.length; i++)
{
// Itterate through the arrays in the "chessBoard"-array
for(var j:int = 0; j < chessBoard[i].length; j++)
{
// Create new tile
var tile:Sprite = new Sprite();
// Create the color variable and check to see what value to put
// in it dependingin the value of the current itteration - 1 or 0
var tileColor:int = chessBoard[i][j] * 0xffffff;
// Tile-coloring-setup-thingie-routine
tile.graphics.beginFill(tileColor);
tile.graphics.drawRect(0, 0, tileSize, tileSize);
tile.graphics.endFill();
// Tile positioning
tile.x = j * tileSize;
tile.y = i * tileSize;
// Adding tile to the displaylist
addChild(tile);
}
}
}
// Run function
createChessBoard();
You can assume that cell is black when sum of its coordinates is odd and white if even:
function getColor(x, y) {
return (x + y) % 2 == 0 ? 0 : 1;
}
// or even
function getColor(x, y) {
return (x + y) % 2;
}
You could start with creating a Square class, this would enable you to give specific properties to each Square. You want to avoid having two pieces on one square for instance, you want to set the color, also you would need to know the coordinates such as a1, c4 etc...
To draw your Chessboard, you could create rows of Squares.
private function squares:Array = [];
private function addRow( black:Boolean , _y:int , rowName:String ):void
{
for( var i:int ; i < 8 ; ++i )
{
var sq:Square = new Square();
//alternate colors
if( black )
sq.color = 0;
else
sq.color = 0xffffff;
black = !black;
sq.x = i* sq.width;
sq.y = _y;
//save square Chess coordinates
sq.coord = {letter: rowName , number: i + 1}
addChild(sq);
//add the Square instance to an Array for further reference
squares.push( sq );
}
}
Then simply add the rows
private function createBoard():void
{
var black:Boolean;
var letters:Array = [ a , b , c , d , e , f , g , h ]
for( var i:int ; i < 8 ; ++i )
{
addRow( black , i * squareSize , letters[i] );
black = !black;
}
}
To add a Queen to a specific Square instance , use the squares Array.