Cant access all children of element? - wpf

So i am adding some elements to a map control like this
foreach (var res in results)
{
if (res.geometry.location != null)
{
var pushpin = new Image();
pushpin.Name = "a";
BasicGeoposition bs = new BasicGeoposition { Latitude = res.geometry.location.lat, Longitude = res.geometry.location.lng };
pushpin.Source = new BitmapImage(uri);
pushpin.Height = 50;
pushpin.Width = 50;
myMap.Children.Add(pushpin);
MapControl.SetLocation(pushpin, new Geopoint(bs));
}
}
Now i want to remove elements names "a" form the control and i am using following code
int c = myMap.Children.Count;
for (int i = 0; i < c; i++)
{
if(myMap.Children.ElementAt(i) is Image)
{
var z = myMap.Children.ElementAt(i) as Image;
if(z.Name.Equals("a"))
{
myMap.Children.Remove(myMap.Children.ElementAt(i));
}
}
}
But always some elements are not getting removed ,for example the count of children is coming 21,but the loop is looping only 10 time.
How can i solve this problem?

try it with looping backwards so you dont mess up your collection during the loop.
int c = myMap.Children.Count - 1;
for (int i = c; i >= 0; i--)
{
if (myMap.Children.ElementAt(i) is Image)
{
var z = myMap.Children.ElementAt(i) as Image;
if(z.Name.Equals("a"))
{
myMap.Children.Remove(myMap.Children.ElementAt(i));
}
}
}

Related

Drag and Drop Arrays AS3

I'm trying to create a drag and drop game in Actionscript 3 using mostly arrays. I'm doing it on a simpler game first before going to the main game because I need to know how the codes work first.
The simpler game is just there are two squares and two circles. The two squares are on a different array while the two circles are in the same one. What should happen is that when either circles hit (hitTestPoint) the right square, their x and y becomes the center of the square. (like it clicks to the center). And when either circles hit the left square, it should return the circles to their last position (doesn't have to be their original position).
Here's the code:
package
{
import flash.display.MovieClip;
import flash.events.MouseEvent;
import flash.display.DisplayObject;
import flash.geom.Point;
import flash.events.Event;
public class MC_MAIN extends MovieClip
{
var mc1:mc_circle;
var mc2:mc_circle;
var mc3:mc_square;
var mc4:mc_square;
var Shapes:Array;
var Target:Array;
var WTarget:Array;
var newPlace:Point;
public function MC_MAIN()
{
// constructor code
init();
}
function init():void
{
Shapes = new Array ;
Target = new Array ;
WTarget = new Array ;
mc3 = new mc_square();
mc3.height = 75;
mc3.width = 75;
mc3.x = 400;
mc3.y = 200;
Target.push(mc3);
addChild(mc3);
mc4 = new mc_square();
mc4.height = 75;
mc4.width = 75;
mc4.x = 150;
mc4.y = 200;
WTarget.push(mc4);
addChild(mc4);
mc1 = new mc_circle();
mc1.height = 25;
mc1.width = 25;
mc1.x = 100;
mc1.y = 100;
Shapes.push(mc1);
addChild(mc1);
mc2 = new mc_circle();
mc2.height = 25;
mc2.width = 25;
mc2.x = 200;
mc2.y = 200;
Shapes.push(mc2);
addChild(mc2);
for (var i:int = 0; i<Shapes.length; i++)
{
Shapes[i].addEventListener(MouseEvent.MOUSE_DOWN, DRG);
Shapes[i].addEventListener(MouseEvent.MOUSE_UP, SDRG);
}
}
function DRG(e:MouseEvent):void
{
e.currentTarget.startDrag();
}
function SDRG(e:MouseEvent):void
{
e.currentTarget.stopDrag();
for (var m:int = 0; m<Shapes.length; m++)
{
newPlace = new Point(Shapes[m].x,Shapes[m].y);
}
trace(newPlace);
for (var a:int = 0; a<Target.length; a++)
{
for (var b:int = 0; b<Shapes.length; b++)
{
if (Target[a].hitTestPoint(Shapes[b].x,Shapes[b].y))
{
Shapes[b].x = Target[a].x;
Shapes[b].y = Target[a].y;
}
}
}
for (var c:int = 0; c<WTarget.length; c++)
{
for (var d:int = 0; d<Shapes.length; d++)
{
if (WTarget[c].hitTestPoint(Shapes[d].x,Shapes[d].y))
{
Shapes[d].x = newPlace.x;
Shapes[d].y = newPlace.y;
}
}
}
}
}
}
What happens is that the code for the left square doesn't work but their are no syntax errors. Nothing happens when either circles hit the left square.
And when I'm trying to trace the position of the circles, It just shows the x & y coordinate of only one of them. (I guess it's tracing the first object of the array which is at index 0. I'm just asking if I guessed right for this part.)
I is a bit difficult to follow the logic and there are some points that doesn't make much sense like:
for (var m:int = 0; m<Shapes.length; m++)
{
newPlace = new Point(Shapes[m].x,Shapes[m].y);
}
newPlace will be the position of the last shape in Shapes, so the loop is fairly useless.
I guess what you need is something like that:
public class MC_MAIN extends MovieClip
{
private leftSquares:Array;
private rightSquares:Array;
//more of the members from above
private startPos:Point;
//init the thing and add left and right squares
//to there respective Array
function DRG(e:MouseEvent):void
{
var t:DisplayObject = e.currentTarget;
//save the starting position
startPos = new Point(t.x,t.y);
t.startDrag();
}
function SDRG(e:MouseEvent):void {
var t:DisplayObject = e.currentTarget;
//find all squares from the left
//the target »hits«
var leftHits:Array = leftSquares.filter(
function (square:DisplayObject) {
return square.hitTestPoint(t.x, t.y);
});
//same for the right
var leftHits:Array = rightSquares.filter(
function (square:DisplayObject) {
return square.hitTestPoint(t.x, t.y);
});
//now you can apply the logic
//based on the hit Test result
//this way you can handle the case
//if it hits both, to throw an error
//or alike
if(leftHits.length > 0) {
//reset position
t.x = startPos.x;
t.y = startPos.y;
}
else if (rightHits.length > 0) {
//set the position tp the desired item in rightHits
}
else {
}
}
}
Please not that my Action Script skills haven't been used for a long time, so the code above might not compile. It is meant to illustrate the idea. Important are the following steps:
1. Save the starting position, to be able to reset it
2. Sort the `squares` in respective lists for left and right
3. Hit test both and apply the logic.

AS3 - Auto refreshing display after updating array

So, basically I'm reinventing the wheel by trying to make a sort of spreadsheet in flash for tracking member growth in a game. In this one section I'm adding member names to an array and then placing the names into dynamically created tiles with text fields attached to display the name.
I have a save button which saves the array, and if I save, close, and reopen, then I can see the members I have added. However, I would like it to refresh the stage as soon as the array is changed to reflect the changes made (update the spreadsheet). I will also be adding and removing other tiles dynamically, but I can extrapolate the solution to this problem to all of those later.
Here's the code I have to add members and create the display:
public var mainArray:Array = new Array;
public var i1:Number = 0;
public var memberBox:MovieClip = new MovieClip();
public var MAX_ROWS = 0;
public var MAX_COLS = 0;
public function Tracker() {
MAX_COLS = mainArray.length - 1;
addBtn.addEventListener(MouseEvent.CLICK, addFun); //atchaed to button on stage
public function addFun($e:MouseEvent):void{
mainArray[i1] = [];
mainArray[i1][0] = addNameTxt.text //attached to textfield on stage
i1++;
loadMembers();
public function loadMembers():void{
var multiDimensionalArray:Array = new Array();
//initalize the arrays
for (var row = 0; row <= MAX_ROWS; row++)
{
var boolArray:Array = new Array();
for (var col = 0; col <= MAX_COLS; col++){
boolArray.push(false);
}
multiDimensionalArray.push(boolArray);
}
//now we can set the values of the array as usual
for (var row = 0; row <= MAX_ROWS; row++)
{
for (var col = 0; col <= MAX_COLS; col++){
multiDimensionalArray.push(1); ;
}
}
//create a column of tiles based on mainArray length with a textfield attached to each
buildLevel(multiDimensionalArray);
}
public function buildLevel(s:Array){
var txtArray:Array = new Array();
memberBox.name = "tileHolder";
for(var i=0; i < MAX_ROWS + 1; i++){
for(var o=0; o < MAX_COLS + 1; o++){
var currentTile:MemberBox = new MemberBox();
currentTile.x = i*150;
currentTile.y = o*25;
currentTile.name = "b"+o;
memberBox.addChild(currentTile);
//currentTile.gotoAndStop(int(s[o][i]));
var memberTxt:TextField=new TextField();
currentTile.addChild(memberTxt);
memberTxt.width = 150;
memberTxt.height = 25;
txtArray[o] = memberTxt;
txtArray[o].text = mainArray[o][0];
}
}
memberBox.x = 60;
memberBox.y = 170;
addChild(memberBox);
}
}
The ideal solution would be to attach event listeners to the Array, however, Arrays don't fire events.
Solution #1: Managed Updates
Rather than allowing any piece of code to modify your array directly, write a function that handles updating your array. This way, you can know when to update the display at the same time.
public var mainArray:Array = new Array;
public var i1:Number = 0;
public var memberBox:MovieClip = new MovieClip();
public var MAX_ROWS = 0;
public var MAX_COLS = 0;
public function Tracker() {
MAX_COLS = mainArray.length - 1;
addBtn.addEventListener(MouseEvent.CLICK, addFun); //attached to button on stage
public function addFun(e:MouseEvent):void {
mainArray[i1] = [];
mainArray[i1][0] = addNameTxt.text //attached to textfield on stage
i1++;
loadMembers();
}
public function loadMembers():void {
var multiDimensionalArray:Array = new Array();
//initalize the arrays
for (var row = 0; row <= MAX_ROWS; row++) {
var boolArray:Array = new Array();
for (var col = 0; col <= MAX_COLS; col++) {
boolArray.push(false);
}
multiDimensionalArray.push(boolArray);
}
//now we can set the values of the array as usual
for (var row = 0; row <= MAX_ROWS; row++) {
for (var col = 0; col <= MAX_COLS; col++) {
multiDimensionalArray.push(1); ;
}
}
//create a column of tiles based on mainArray length with a textfield attached to each
buildLevel(multiDimensionalArray);
}
public function buildLevel(s:Array) {
var txtArray:Array = new Array();
memberBox.name = "tileHolder";
for (var i:int = 0; i < MAX_ROWS + 1; i++) {
for(var o=0; o < MAX_COLS + 1; o++) {
var currentTile:MemberBox = new MemberBox();
currentTile.name = i + "_" + o;
currentTile.x = i*150;
currentTile.y = o*25;
memberBox.addChild(currentTile);
//currentTile.gotoAndStop(int(s[o][i]));
var memberTxt:TextField=new TextField();
currentTile.addChild(memberTxt);
memberTxt.width = 150;
memberTxt.height = 25;
txtArray[o] = memberTxt;
txtArray[o].text = mainArray[o][0];
}
}
memberBox.x = 60;
memberBox.y = 170;
addChild(memberBox);
}
public function modifyArray(row:int, col:int, value:*):void {
// Update our array.
mainArray[row][col] = value;
// Update our tile.
var tile:MemberBox = memberBox.getChildByName(row + "_" + col);
tile.getChildAt(0).text = value;
}
}
When you actually modified your array, you'd do that with your function, rather than a direct mainArray[o][i] approach.
// Instead of this
mainArray[o][i] = "foo";
// You'd do this
modifyArray(o, i, "foo");
Update: I'm not sure how better to explain this, so I've posted working example that you can view. It contains the class, and the document code, the fla, and the swf with working updates to the spreadsheet. Let me know if that resolves the issue: SpreadSheet Test # Dropbox
Solution #2: Poll for Changes
Hold two versions of your array in memory. The first is the one you're actively editing, the second is an untouched duplicate to compare against the first. Every so often (once per second?) you iterate over the entire dataset and look for differences. When one is found, update the duplicate array and the displayed spreadsheet.
Here's an example of how you'd do that:
import flash.utils.*;
var last:Number = flash.utils.getTimer();
this.addEventListener("enterFrame", checkData);
var foo:Array = ["a", "b", "c"];
var fooBackup:Array = [];
function update():void {
var txt:TextField;
for (var i:int = 0; i < foo.length; i++) {
// If we don't have a representation of this index, create one.
if (!this.getChildByName("tile"+i)) {
txt = new TextField();
txt.name = "tile" + i;
txt.text = foo[i];
this[txt.name] = txt;
addChild(txt);
txt.y = i * 20;
}
// Update the data if inconsistent.
txt = this.getChildByName("tile"+i) as TextField;
if (fooBackup.hasOwnProperty(i) == false || foo[i] != fooBackup[i]) {
fooBackup[i] = foo[i]
txt.text = foo[i];
trace("Index " + i + " changed. Updated backup, and display.");
}
}
}
function checkData(e:Event):void {
var now:Number = flash.utils.getTimer();
// If the last time we checked is greater than a second, run the check again.
if (now - last > 1000) {
// Update last checked index;
last += 1000;
// For the sake of argument, let's randomly change an index to a random value.
foo[random(0, foo.length-1)] = random(-1000, 1000);
update();
}
}
function random(low:Number=0, high:Number=1):Number {
/* Returns a random number between the low and high values given. */
return Math.floor(Math.random() * (1+high-low)) + low;
}
Solution #3: Roll your own Array
As outlined by Adobe's Extending the Array class, you can subclass Arrays and from there add your own event dispatches when you add/remove entries. This is the more adventurous solution, and (in my humble opinion) the best as it maintains code consistency, while giving broad and efficient powers.

Use the same array to next frame

Im making a game and i complete the level1 at frame1.
When im trying to make the level2 to frame2 i dont know how to transfer my Arrays
to frame2.All the other buttons and functions are working(i copy the eventListeners to frame2)but my enemies wich are in Arrays does nothing!!
Thanks a lot!!!
import flash.events.Event;
stop();
//variables the helicopters
var enemy1Array:Array = new Array();
for (var e1:int = numChildren - 1; e1 >= 0; e1--)
{
var child:DisplayObject = getChildAt(e1);
if (child.name == "enemy1")
{
enemy1Array.push(child);
}
}
stage.addEventListener(Event.ENTER_FRAME, allloop);
function allloop(event:Event):void
{
//move the helicopters
for each(var enemy1:Sprite in enemy1Array)
{
enemy1.x = enemy1.x -= enemy1speed;
if(enemy1.hitTestObject(defense))
{
addChild(explotionbonus3);
explotionbonus3.gotoAndPlay(2);
explotionbonus3.x = enemy1.x;
explotionbonus3.y = enemy1.y;
enemy1.y = 1000;
score -=5;
scoretxt.text = String (score);
}
}
}

as3 how to remove/ move position of graphics from reset array

I am trying to reset a scene an move every thing to its original position the reset function resets the array adds the nape bodies back to the stage and attaches the graphics but the original graphics still are on the stage in whatever position they were in when reset was called
private var brickGraphic:MovieClip = new Brick();
private var brick:Body;
private var brickArray:Array;
private function setUp():void
{
brickArray = new Array ;
for (var i:int = 0; i < 10; i++)
{
var brick:Body = new Body(BodyType.DYNAMIC);
var brickShape:Polygon = new Polygon(Polygon.box(10,25));
var brickGraphic = new Brick();
brickGraphic.width = 10;
brickGraphic.height = 25;
addChild(brickGraphic);
brickGraphic.cacheAsBitmap = true;
brick.shapes.add(brickShape);
brick.position.setxy(450, ((ag ) - 30 * (i + 0.5)));
brick.angularVel = 0;
brick.shapes.at(0).material.elasticity = .5;
brick.shapes.at(0).material.density = 150;
brick.cbTypes.add(brickType);
brick.space = space;
brickGraphic.stop();
brick.userData.sprite = brickGraphic;
brick.userData.sprite.x = brick.position.x;
this.brickArray.push(brick);
}
private function reset():void
{
if (contains(brickGraphic)) removeChild(brickGraphic);
space.clear();
setUp();
}
}
this is the final issue i am having on this app and your help would be greatly appreciated
That's because you are not removing them with removeChild.
You need to call removeChild for each brickGraphic object you add to the stage.
Something like :
private function setUp():void
{
brickArray = [];
for (var i:int = 0; i < 10; i++)
{
var brick:Body = new Body(BodyType.DYNAMIC);
var brickShape:Polygon = new Polygon(Polygon.box(10,25));
var brickGraphic = new Brick();
brickGraphic.width = 10;
brickGraphic.height = 25;
addChild(brickGraphic);
brickGraphic.cacheAsBitmap = true;
brick.shapes.add(brickShape);
brick.position.setxy(450, ((ag ) - 30 * (i + 0.5)));
brick.angularVel = 0;
brick.shapes.at(0).material.elasticity = .5;
brick.shapes.at(0).material.density = 150;
brick.cbTypes.add(brickType);
brick.space = space;
brickGraphic.stop();
brick.userData.sprite = brickGraphic;
brick.userData.sprite.x = brick.position.x;
this.brickArray.push(brick);
}
}
private function removeAllBricks():void
{
for(var i:int=0; i<brickArray.length; i++)
{
var dp:DisplayObject = brickArray[i].userData.sprite as DisplayObject;
if(dp && dp.parent)
dp.parent.removeChild(dp);
}
}
private function reset():void
{
removeAllBricks();
space.clear();
setUp();
}

Actionscript 3: Trying to create a randomized array

im trying to create a randomized array that will change the position of my pictures(in the tilelist) each time the application is launched. Hope you understand what im looking for, and i dont really understand how to link code correctly here :/
I think its easier simply copying into flash and view from there
thanks :)
Here's my code:
flash.events.MouseEvent;
btn_back.addEventListener(MouseEvent.CLICK, ftilbake);
function ftilbake(evt:MouseEvent)
{
gotoAndStop(1);
}
var heroArray:Array = new Array();
var randomizeArray:Array = new Array();
createArrays()
function createArrays()
{
heroArray[0] = new Array("Rumble","Garen","Lulu","Corki","Warwick");
heroArray[1] = new Array("Bilder/Champions/Rumble.jpg","Bilder/Champions/Garen.jpg","Bilder/Champions/Lulu.jpg","Bilder/Champions/Corki.jpg","Bilder/Champions/Warwick.jpg");
heroArray[2] = new Array("Bilder/Champions/Rumble1.jpg","Bilder/Champions/Garen1.jpg","Bilder/Champions/Lulu1.jpg","Bilder/Champions/Corki1.jpg","Bilder/Champions/Warwick1.jpg");
heroArray[3] = new Array("the Mechanized Menace","the Might of Demacia","the Fae Sorceress","the Daring Bombardier","the Blood Hunter");
heroArray[4] = new Array(0,0,0,0,0);
heroArray[5] = new Array("Rumble.wav","Garen.wav","Lulu.wav","Corki.wav","Warwick.wav");
randomizeArray[0] = new Array();
randomizeArray[1] = new Array();
randomizeArray[2] = new Array();
randomizeArray[3] = new Array();
randomizeArray[4] = new Array();
//randomizing the positions in the array(?)
var randomPos:int = 0;
for (var i:int = 0; i < heroArray.length; i++)
{
randomPos = int(Math.random() * heroArray[0].length);
while (randomizeArray[randomPos][0] != null)
{
randomPos = int(Math.random() * heroArray.length);
}
}
}
var totalKlikk:int = 0;
for (var teller1:int = 0; teller1 <heroArray[0].length; teller1++)
{
leagueChamps.addItem({label:heroArray[0][teller1], source:heroArray[1][teller1]});
}
leagueChamps.columnWidth = 80;
leagueChamps.rowHeight = 80;
leagueChamps.columnCount = 5;
leagueChamps.rowCount = 1;
leagueChamps.direction = "horizontal";
leagueChamps.addEventListener(MouseEvent.CLICK, bildeKlikk);
function bildeKlikk(evt:MouseEvent)
{
var element:Object = leagueChamps.selectedItem;
var fil:String = element.source;
txtChHero.visible = false;
totalKlikk++;
if (totalKlikk <11)
{
for (teller1 = 0; teller1 <heroArray[0].length; teller1++)
{
if (heroArray[1][teller1] == fil)
{
heroArray[4][teller1]++;
if (heroArray[4][teller1] == 1)
{
txtBox1.visible = true;
txtBox2.visible = true;
leagueShow.source = heroArray[2][teller1];
txtBox1.text = heroArray[0][teller1];
txtBox2.text = heroArray[3][teller1];
}
if (heroArray[4][teller1] == 2)
{
txtBox1.visible = true;
txtBox2.visible = true;
leagueShow.source = heroArray[2][teller1];
txtBox1.text = heroArray[0][teller1];
txtBox2.text = heroArray[3][teller1];
heroArray[5][teller1].play();
}
if (heroArray[4][teller1] == 3)
{
bildeKlikk3();
}
}
}
}
else
{
txtChHero.visible = true;
txtChHero.text = "Du har klikket følgende mange ganger på de forskjellige bildene:";
txtH1.text = heroArray[4][0]
txtH2.text = heroArray[4][1]
txtH3.text = heroArray[4][2]
txtH4.text = heroArray[4][3]
txtH5.text = heroArray[4][4]
txtBox1.visible = false;
txtBox2.visible = false;
leagueShow.visible = false;
}
}
function bildeKlikk3()
{
txtBox1.visible = true;
txtBox2.visible = true;
leagueShow.source = heroArray[2][teller1];
txtBox2.text = "Ikke mer informasjon";
}
txtBox2.visible = false;
txtBox1.visible = false;
Array randomization is something which comes up very frequently in all my projects so I ended up creating a static method in my Array utility class for it.
It uses the Fisher–Yates shuffle which is supposed to be the most unbiased (and efficient?) algorithm for shuffling the content of an array. There could be faster ways of doing it (like using the array.sortOn() method, but I am not sure how unbiased a result they get compared to this one.)
The shuffle method:
/**
* shuffle the given array
* #param array
* #return
*/
public static function shuffle(array:Array):Array
{
var index :int;
var item :*;
var limit :int = array.length as int;
for (var i:int = limit-1; i >= 0 ; --i)
{
index = Math.floor(Math.random() * (i + 1));
item = array[index];
array[index] = array[i];
array[i] = item;
}
return array;
}
Example:
var myArray:Array = new Array("Red","Orange","Yellow","Green","Blue");
myArray = ArrayUtils.shuffle(myArray);
where ArrayUtils is the name of the Array Utility class I use. You can simply use the function directly if you don't want to use a utility class of course.
Try this
while (heroArray.length > 0) {
randomizeArray.push(heroArray.splice(Math.round(Math.random() * (heroArray.length - 1)), 1)[0]);
}
Just instatiate randomizeArray though, and don't fill it with empty Arrays like in ur source!
I recommend creating a single object to hold related data, and using a single Array/Vector of that object type.
To answer your question, randomizing an array is fairly easy to do with array.sort() and a random selection function. This method can also be used to randomize any array. you don't need to splice arrays or iterate either.
function sortOnRandom(a:Object, b:Object):Number{
if(Math.random() > 0.5){
return 1;
}else{
return -1;
}
}
myArray.sort(sortOnRandom);

Resources