Odd numbers of object extraction from an array - actionscript-3

I'm trying to get 2 objects at a time form the array for now. but soon I will be using odd number of length and splicing items.
This works out perfectly so far with Even numbers in the Array, but I am not sure how to make it work with odd numbers. The way I think it may work is ask it to check the objects coming up next and if it is less than 2 than change the counters to 1. but I am not even sure how to put that in code specifically. I posted my code so far be
import flash.events.MouseEvent;
import flash.net.Socket;
var socket_Array_current_position = 0;
var socket_counter = 2;
var socket_Array: Array = new Array ();
socket_Array.push(socket_one, socket_two,socket_three, socket_four, socket_five, socket_six);
go_next_left.addEventListener(MouseEvent.CLICK, go_left);
go_next_right.addEventListener(MouseEvent.CLICK, go_right);
function go_left(going_left:MouseEvent)
{
if (socket_Array_current_position > 0)
{
socket_remove();
socket_Array_current_position -= socket_counter;
socket_x_position = 125;
socket_display();
}
}
function go_right(going_right:MouseEvent)
{
if (socket_Array_current_position < socket_Array.length-socket_counter)
{
socket_remove();
socket_Array_current_position += socket_counter;
socket_x_position = 125;
socket_display();
}
}
socket_display();
function socket_display()
{
var s = 0;
for (s; s < socket_counter; s++)
{
addChild(socket_Array[socket_Array_current_position + s]);
socket_Array[socket_Array_current_position + s].x = socket_x_position;
socket_Array[socket_Array_current_position + s].y = socket_y_position;
//socket_Array[s].addEventListener(MouseEvent.CLICK, picked);
socket_x_position = socket_x_position + 275;
}
}
function socket_remove()
{
var s = 0;
for (s; s < socket_counter; s++)
{
removeChild(socket_Array[socket_Array_current_position+s]);
}
}

I suppose that you want display X objects (in this case two) at a time from an array. Whatever length. I'm using Math lib. Consider that I didn't try the code below with sdk or Flash.
const X_START_POS:int = 125;
const COLUMN_WIDTH:int = 275;
const QTY_SCREEN:int = 2;
var socket_Array:Array = new Array();
var socket_Array_pos:int = 0;
var socket_Array_target:int = 0; // target is always right
var socket_Array_on_screen:Array = new Array();
// socket_Array.length must be >= QTY_SCREEN, always.
socket_Array.push(socket_one, socket_two, socket_three, socket_four, socket_five, socket_six);
go_next_left.addEventListener(MouseEvent.CLICK, go_left);
go_next_right.addEventListener(MouseEvent.CLICK, go_right);
socket_display();
function go_left(going_left:MouseEvent) {
socket_Array_target = Math.max(socket_Array_pos - QTY_SCREEN, 0);
socket_display();
}
function go_right(going_right:MouseEvent) {
socket_Array_target = Math.min(socket_Array_pos + QTY_SCREEN, socket_Array.length - QTY_SCREEN);
socket_display();
}
function socket_display() {
socket_remove();
socket_x_position = X_START_POS;
var limit:int = socket_Array_target + QTY_SCREEN;
for (var i = socket_Array_target; i < limit; i++) {
show_socket(socket_Array[i]);
socket_x_position += COLUMN_WIDTH;
}
socket_Array_pos = socket_Array_target;
}
function show_socket(asocket:DisplayObject) {
addChild(asocket);
asocket.x = socket_x_position;
asocket.y = socket_y_position;
socket_Array_on_screen.push(asocket); // remember me
}
function socket_remove() {
var qty:int = socket_Array_on_screen.length;
for (var s = 0; s < qty; s++) {
removeChild(socket_Array_on_screen.pop());
}
}

Related

Trouble with addChild/removeChild and display list order in ActionScript3

I am working on a project, which includes a Lake symbol that the player can throw stones into, which in turn causes octopi to rise out of the lake in the positions that each stone hits the lake.
There is also a symbol for the splash made by the stone which will appear after the stone hits and before the octopus appears.
It is likely that there will be many octopi on the screen at the same time and they need to be ordered in the display list so that the ones that should appear further back are behind the others.
Each instance of these symbols should only play once and then be removed.
My code for this makes use of the different add/remove child method alongside for loops, conditionals and arrays which I have put together with the help of various tutorials and forums.
The problem I have is that when you click on the lake two or more times in quick succession, the stone and the splash symbols aren't removed properly and often keep looping.
Here is the code I am using. Any ideas?
var stone:Stone;
var stoneSplash:StoneSplash;
var octopus1:Octopus1;
var octopus2:Octopus2;
var whichOctopus:Array = [addOctopus1, addOctopus2];
var octopusScale:Number;
var octopusContainer:MovieClip = new MovieClip;
lake.lakeHitArea.addEventListener(MouseEvent.CLICK, onClickLake);
//Add octopusContainer to the stage's display list just above the Lake
addChildAt(octopusContainer,getChildIndex(lake) + 1);
octopusContainer.x = 0;
octopusContainer.y = 0;
function onClickLake(e:MouseEvent):void
{
trace("CLICK");
throwStone(mouseX, mouseY);
}
function throwStone(stonePositionX:int, stonePositionY:int)
{
stone = new Stone();
stone.x = stonePositionX;
stone.y = stonePositionY;
addChild(stone);
addEventListener(Event.ENTER_FRAME, removeStone);
}
function removeStone(e:Event):void
{
var count:int = numChildren;
var children:Array = [count];
//load all the children of the component into an Array
for (var i:int=0; i<count/* -1*/; i++)
{
children[i] = getChildAt(i/* + 1*/);
}
for (i=0; i<count/* - 1*/; i++)
{
if (children[i] is Stone)
{
if (children[i].currentFrameLabel == "Splash")
{
stoneSplash = new StoneSplash();
octopusContainer.addChild(stoneSplash);
stoneSplash.x = children[i].x;
stoneSplash.y = children[i].y;
}
if (children[i].currentFrameLabel == "end")
{
octopusContainer.removeChild(stoneSplash);
var positionX:int = children[i].x;
var positionY:int = children[i].y;
addOctopus(positionX, positionY);
removeChild(children[i]);
}
}
}
}
function addOctopus(positionX, positionY)
{
var o:int = Math.round(randomNumber(0,1));
whichOctopus[o](positionX, positionY);
reorderDisplayList();
addEventListener(Event.ENTER_FRAME, removeOctopus);
}
function addOctopus1(positionX: int, positionY:int):void
{
// if (whichOctopus1 == true)
// {
// var octopus:* = octopus1_1;
// }
// else
// {
// octopus = octopus1_2;
// }
octopus1 = new Octopus1();
var octopus:DisplayObject = octopus1;
octopusContainer.addChild(octopus);
octopus.x = positionX;
octopus.y = positionY;
octopusScale = randomNumber(0.5,0.85);
octopus.scaleX = octopusScale;
octopus.scaleY = octopusScale;
trace("children = " + octopusContainer.numChildren);
testPosition(octopus);
}
function addOctopus2(positionX: int, positionY:int):void
{
// if (whichOctopus2 == true)
// {
// var octopus:* = octopus2_1;
// }
// else
// {
// octopus = octopus2_2;
// }
octopus2 = new Octopus2();
var octopus:DisplayObject = octopus2;
octopusContainer.addChild(octopus);
octopus.x = positionX;
octopus.y = positionY;
octopusScale = randomNumber(0.25,0.5);
octopus.scaleX = octopusScale;
octopus.scaleY = octopusScale;
trace("children = " + octopusContainer.numChildren);
testPosition(octopus);
}
function testPosition(octopus:Object):void
{
trace(octopus)
for (var i:int = 0; i < 200; i++)
{
if (lake.hitTestPoint(octopus.x + octopus.hitTestBox1.x * octopus.scaleX,octopus.y + octopus.hitTestBox1.y * octopus.scaleY,true))
{
break;
}
else
{
octopus.x++;
}
}
for (i = 0; i < 100; i++)
{
if (lake.hitTestPoint(octopus.x + octopus.hitTestBox2.x * octopus.scaleX,octopus.y + octopus.hitTestBox2.y * octopus.scaleY,true))
{
break;
}
else
{
octopus.y--;
}
}
for (i = 0; i < 200; i++)
{
if (lake.hitTestPoint(octopus.x + octopus.hitTestBox3.x * octopus.scaleX,octopus.y + octopus.hitTestBox3.y * octopus.scaleY,true))
{
break;
}
else
{
trace(i);
octopus.x--;
}
}
for (i = 0; i < 100; i++)
{
if (lake.hitTestPoint(octopus.x + octopus.hitTestBox1.x * octopus.scaleX,octopus.y + octopus.hitTestBox1.y * octopus.scaleY,true))
{
break;
}
else
{
octopus.y--;
trace(i);
}
}
}
function randomNumber(min:Number, max:Number):Number
{
return Math.random() * (max - min) + min;
}
function reorderDisplayList():void
{
//the number of children in our component
var count:int = octopusContainer.numChildren;
var children:Array = [count];
//load all the children of the component into an Array
for (var i:int=0; i<count; i++)
{
children[i] = octopusContainer.getChildAt(i);
}
//sort the Array children based on their 'y' property
children.sortOn("y", Array.NUMERIC);
//re-add the children to the component ;
//in the order of the sorted Array we just created.
//When we add the children using 'addChild' it will
//be added at the top of the component's displaylist
//and will automatically be removed from its original position.
for (i=0; i<count/* - 1*/; i++)
{
if (children[i] is Octopus1 || children[i] is Octopus2)
{
// trace("child = " + children[i] + " at i: " + i);
octopusContainer.removeChild(children[i]);
octopusContainer.addChild(children[i]);
}
}
}
function removeOctopus(e:Event):void
{
var count:int = octopusContainer.numChildren;
var children:Array = [count];
//load all the children of the component into an Array
for (var i:int=0; i<count/* -1*/; i++)
{
children[i] = octopusContainer.getChildAt(i/* + 1*/);
}
for (i=0; i<count/* - 1*/; i++)
{
if (children[i] is Octopus1 || children[i] is Octopus2)
{
trace(i);
trace("Is an octopus");
if (children[i].currentFrame >= 202)
{
octopusContainer.removeChild(children[i]);
}
}
}
}
I would greatly appreciate any advice to help me overcome this hurdle and continue with my project.
Thank you in advance.
Chris Collins.
Your issue (or at least one of them) is that your code will only remove the most recent StoneSplash. So if you click a bunch of times in between the splash and end animation , only the last clicked one will get removed.
This is because you are using a global var (stoneSplash) to reference the splash, and it gets overwritten to the new one. You need to either add a splash reference on the stone itself, or create a dictionary so you know which splash goes with which stone.
Here would be one way:
if (children[i].currentFrameLabel == "Splash")
{
stoneSplash = new StoneSplash();
MovieClop(children[i]).stoneSplash = stoneSplash; //add a reference the splash on the stone itself
Then later, instead of octopusContainer.removeChild(stoneSplash); do:
octopusContainer.removeChild(MovieClop(children[i]).stoneSplash);
This way your removing the correct splash that goes with this stone.
Here would be a much cleaner way to architect this instead of using an enter frame handler:
On your Stone class timeline, put the following code on your Splash and End frames respectively:
Splash frame: this.dispatchEvent(new Event("Splash"));
End frame: this.dispatchEvent(new Event("End"));
Listen for those events when you create a new stone instance:
stone = new Stone();
stone.x = stonePositionX;
stone.y = stonePositionY;
stone.addEventListener("Splash", splashHandler,false,0,true);
stone.addEventListener("End",removeStone,false,0,true);
addChild(stone);
Respond to those events appropriately:
function splashHandler(e:Event):void {
var stone:Stone = e.currentTarget as Stone;
stoneSplash = new StoneSplash();
//you need a reference to the splash from the stone class - it would be best to create a class file and add a public property called splashObj and then just use stone.splashObj = new StoneSplash();
MovieClip(stone).stoneSplash = stoneSplash; //so on the end event we can read this var to remove stoneSplash
octopusContainer.addChild(stoneSplash);
stoneSplash.x = stone.x;
stoneSplash.y = stone.y;
}
function removeStone(e:Event):void {
var stone:Stone = e.currentTarget as Stone;
octopusContainer.removeChild(MovieClip(stone).stoneSplash);
addOctopus(stone.x, stone.y);
removeChild(stone);
}

Flash only removing objects not created through code

I'm trying to make a simple game in Flash. So far, I've added a bunch of objects to the stage using addChild(objName);. However, now I'm trying to remove the objects completely. I don't want to have to cycle through every object's name and I'm sure there must be a more efficient way to select each object (maybe by index on the stage) and removeChildAt(index); it. However, when I try this, Flash only removes the objects that were manually placed by me on the stage. It doesn't remove the ones that were placed through code. I've done some searching and I tried multiple methods, all of which yield the same result. The one that most people agree on is this one:
while (numChildren > 0)
{
removeChildAt(0);
}
Can you help me figure out why this isn't removing anything that was coded onto the stage?
Thanks in advance :D
Edit: Here is my code for the frames:
Frame 1 (Randomly generates and displays the dots):
import flash.events.MouseEvent;
import fl.motion.easing.Linear;
var dotList = new Array(); var level:int = 3; var invisoDotList = new Array();
var loop:int;
var line:Line = new Line();
line.x = 274;
line.y = 187;
addChild(line);
for(loop = 0; loop < level; loop++)
{
var dot:Dot = new Dot();
var invisoDot:InvisoDot = new InvisoDot();
var tester:Boolean = true;
var xval:int = Math.floor(Math.random()*(1+520))+14;
var looper:int = 0;
while(looper < dotList.length)
{
if(Math.abs(xval - dotList[looper].x) > 30)//minimum spacing
{
looper++;
}
else
{
looper = 0;
xval = Math.floor(Math.random()*(1+520))+14;
}
}
dot.x = xval;
dot.y = 187;
invisoDot.x = xval;
invisoDot.y = 187;
invisoDot.alpha = 0;
dotList[loop] = dot;
invisoDotList[loop] = invisoDot;
addChild(invisoDot);
addChild(dot);
}
//trace(dotList); test to ensure that dots are added to the array
var nb1:NextButton = new NextButton();
nb1.x = 0;
nb1.y = 0;
nb1.alpha = 0;
addChild(nb1);
nb1.addEventListener(MouseEvent.CLICK, hideDots);
function hideDots(e:MouseEvent)
{
for(var loop:int = 0; loop < dotList.length; loop++)
{
dotList[loop].alpha = 0;//make dots disappear
}
line.alpha = 0;
nextFrame();
}
stop();
Frame 2 (Displays further instructions and contains a couple of methods that will be used later on):
import flash.events.MouseEvent;
removeChild(nb1);
var nb2:NextButton = new NextButton();
nb2.x = 0;
nb2.y = 0;
nb2.alpha = 0;
addChild(nb2);
nb2.addEventListener(MouseEvent.CLICK, next);
function next(e:MouseEvent)
{
nextFrame();
}
function clearStage()
{
while (numChildren > 0)
{
trace("before" + numChildren);
removeChildAt(0);
trace("after" + numChildren);
}
}
stop();
Frame 3 (Makes the dots disappear when they are clicked and keeps an accuracy count):
import flash.events.MouseEvent;
import flash.utils.Timer;
line.alpha = 1;
removeChild(nb2);
//setChildIndex(line,0);
var clicks:int = -1;
var passed:int = 0;
var fromLine:Boolean = false;
//trace(dotList.length);
stage.addEventListener(MouseEvent.CLICK, clickCount);
for(var loopvar:int = 0; loopvar < dotList.length; loopvar++)
{
//trace("loop");
dot = dotList[loopvar];
invisoDot = invisoDotList[loopvar];
dot.addEventListener(MouseEvent.CLICK, onClick);
invisoDot.addEventListener(MouseEvent.CLICK, onClick);
//trace("event");
}
//trace(dotList.length);
function onClick(e:MouseEvent)
{
//e.currentTarget.alpha = .5;
for(var hitcheck:int = 0; hitcheck < dotList.length; hitcheck++)
{
if(dotList[hitcheck].x == e.currentTarget.x)
{
dotList[hitcheck].alpha = 1;
}
}
//trace("check");
}
var numChanged:int = 0;
function clickCount(e:MouseEvent)
{
clicks++;
//trace(clicks);
numChanged = 0;
for(var index:int = 0; index < dotList.length; index++)//check whether the user has gotten all the dots
{
if(dotList[index].alpha == 1)
{
numChanged++;
}
}
if(numChanged == level)//if the user has gotten all the dots
{
/*trace("next screen for sucess");
trace(clicks);*/
line.visible = false;
for(loop = 0; loop < dotList.length; loop++)
{
dotList[loop].alpha = 0;//make dots disappear
}
if((clicks - level) == 1)
{
passed = 2
}
else if((clicks - level) == 0)
{
passed = 1;
}
passed = 1;
fromLine = true;
nextFrame();
}
else if((clicks - numChanged) >= 2)//this ends the session as soon as 2 mistakes are made
{
/*trace("next screen for failed number of clicks");
trace(clicks);*/
line.visible = false;
for(loop = 0; loop < dotList.length; loop++)
{
dotList[loop].alpha = 0;//make dots disappear
}
passed = 3;
fromLine = true;
nextFrame();
}
/*else if((clicks - level) >= 2)//if the user has made too many mistakes. This ends the session after the maximum number of tries have been used
{
trace("next screen too many clicks");
trace(clicks);
}*/
}
//trace("end");
stop();
Frame 4 (Generates the results table. A sidenote: there is a bug where "Okay" is never a result because in Frame 3, the value of passed never equals 2. Not sure why though):
import flash.text.TextFormat;
import flash.text.TextField;
var failFormat:TextFormat = new TextFormat();
failFormat.color = 0xFF0000;
failFormat.font = "Arial";
failFormat.size = 18;
var passFormat:TextFormat = new TextFormat();
passFormat.color = 0x00FF00;
passFormat.font = "Arial";
passFormat.size = 18;
var okayFormat:TextFormat = new TextFormat();
okayFormat.color = 0x808000;
okayFormat.font = "Arial";
okayFormat.size = 18;
var normalFormat:TextFormat = new TextFormat();
normalFormat.color = 0x000000;
normalFormat.font = "Arial";
normalFormat.size = 18;
var lineResults = new Array();
var squareResults = new Array();
trace(passed);
if(fromLine == true)
{
if(passed == 1)
{
lineResults[lineResults.length] = "Pass";
}
else if(passed == 2)
{
lineResults[lineResults.length] = "Okay";
}
else if(passed == 3)
{
lineResults[lineResults.length] = "Fail";
}
}
fromLine = false;
lineResults = lineResults.reverse();
squareResults = squareResults.reverse();
var loopLength:int = (lineResults.length >= squareResults.length) ? lineResults.length : squareResults.length;
var loopStart:int = 0;
if(loopLength > 11)
{
loopStart = loopLength - 12
}
var cb:CellBlock = new CellBlock();
cb.x = 283.05;
cb.y = 20.35;
addChild(cb);
var col1Head:TextField = new TextField();
col1Head.defaultTextFormat = normalFormat;
col1Head.text = "# of Dots";
col1Head.x = 114.95
col1Head.y = 8.3;
addChild(col1Head);
var col2Head:TextField = new TextField();
col2Head.defaultTextFormat = normalFormat;
col2Head.text = "Line";
col2Head.x = 259.95
col2Head.y = 8.3;
addChild(col2Head);
var col3Head:TextField = new TextField();
col3Head.defaultTextFormat = normalFormat;
col3Head.text = "Square";
col3Head.x = 381.95
col3Head.y = 8.3;
addChild(col3Head);
for(loop = loopStart; loop < loopLength; loop++)
{
var block:CellBlock = new CellBlock();
block.x = 283.05;
block.y = 20.35 + (loop - loopStart + 1)*33;
addChild(block);
var col2:TextField = new TextField();
var col3:TextField = new TextField();
var col1:TextField = new TextField();
/*col2.defaultTextFormat = passFormat;
col3.defaultTextFormat = okayFormat;*/
col1.defaultTextFormat = normalFormat;
switch(lineResults[loop])
{
case "Pass":
col2.defaultTextFormat = passFormat;
break;
case "Okay":
col2.defaultTextFormat = okayFormat;
break;
case "Fail":
col2.defaultTextFormat = failFormat;
break;
}
switch(squareResults[loop])
{
case "Pass":
col3.defaultTextFormat = passFormat;
break;
case "Okay":
col3.defaultTextFormat = okayFormat;
break;
case "Fail":
col3.defaultTextFormat = failFormat;
break;
}
//col2.text = "Pass";
col2.text = lineResults[loop];
col2.x = 260.95;
col2.y = block.y - 12;
addChild(col2);
//col3.text = "Okay";
try
{
col3.text = squareResults[loop];
}
catch(e:Error)
{
}
col3.x = 386.95;
col3.y = block.y - 12;
addChild(col3);
col1.text = String(loop + 1);
col1.x = 133.95;
col1.y = block.y - 12;
addChild(col1);
}
var nb4:NextButton = new NextButton();
nb4.x = 0;
nb4.y = 0;
nb4.alpha = 0;
addChild(nb4);
nb4.addEventListener(MouseEvent.CLICK, clearStage);
stop();
Frame 5 (Next frame which is a test to make sure that everything gets erased, which it doesn't):
removeChild(nb4);
stop();
This error:
ArgumentError: Error #1063: Argument count mismatch on Game_fla::MainTimeline/clearStage(). Expected 0, got 1. clearStage()
Occurs because your clearStage() method has been added as the click event handler of a button. If your clearStage() function is going to be used an an event handler, it needs to accept an "event" parameter. So you should define the function like this:
function clearStage(event:Event)
{
while (numChildren > 0)
{
trace("before" + numChildren);
removeChildAt(0);
trace("after" + numChildren);
}
}
As a side note, this means that if you want to also call clearStage() manually, that is use it without adding it as an event handler, that you'll need to include this event parameter... but you can just pass in a null, because your code doesn't need to actually use the event parameter:
clearStage(null);
I'm not sure I see anything else wrong. I'd start by adding that event parameter to your clearStage() function as I shown above.
I should also add I mostly worked in Flex or pure AS3, and am not super skilled in Flash CS6 and programming on the timeline :)
From memory, I don't think Flash re-orders when you remove a child. If you remove a child at index 0, every other child is still numbered 1 to x. childAt(0) is just null now. Keep that in mind with this sort of process.

How to call a variable of a function using concatenation (AS3)

I need to acess a variable inside this function using concatenation, following this example:
public function movePlates():void
{
var plate1:Plate;
var plate2:Plate;
var cont:uint = 0;
for (var i:uint = 0; i < LAYER_PLATES.numChildren; i++)
{
var tempPlate:Plate = LAYER_PLATES.getChildAt(i) as Plate;
if (tempPlate.selected)
{
cont ++;
this["plate" + cont] = LAYER_PLATES.getChildAt(i) as Plate;
}
}
}
EDIT:
public function testFunction():void
{
var test1:Sprite = new Sprite();
var test2:Sprite = new Sprite();
var tempNumber:Number;
this.addChild(test1);
test1.x = 100;
this.addChild(test2);
test2.x = 200;
for (var i:uint = 1; i <= 2; i++)
{
tempNumber += this["test" + i].x;
}
trace("tempNumber: " + tempNumber);
}
If i run the code like this, the line this["test" + i] returns a variable of the class. I need the local variable, the variable of the function.
Your loop on first step access plate0 this will cause not found error, if plate0 is not explicitly defined as class member variable or if class is not defined as dynamic. Same thing will happen for plate3, plate4, plate5... in case LAYER_PLATES.numChildren is more than 3.
EDIT:
Thanks to #Smolniy he corrected my answer plate0 is never accessed because cont is incremented before first access. So as he mentioned problem should be on plate3
You don't get the local variable with [] notation. your case has many solutions. You can use dictionary, or getChildAt() function:
function testFunction():void
{
var dict = new Dictionary(true);
var test1:Sprite = new Sprite();
var test2:Sprite = new Sprite();
var tempNumber:Number = 0;
addChild(test1);
dict[test1] = test1.x = 100;
addChild(test2);
dict[test2] = test2.x = 200;
for (var s:* in dict)
{
tempNumber += s.x;
//or tempNumber += dict[s];
}
trace("tempNumber: " + tempNumber);
};

setting the chances of occurrence of elements in an array

For example I have 3 elements in an array:
public function randomTile():Number
{
var tiles:Array = new Array(fire,ice,water);
var index:Number=Math.floor(Math.random()*tiles.length);
return tiles[index];
}
How to set the chances of occurrence of fire(70%), ice(10%), and water(20%)?
This should work for any number of elements and you can specify any chance value.
var tiles:Array = [
{"item":"fire", "chance":70 },
{"item":"ice", "chance":10 },
{"item":"water","chance":20}
];
var picked:Object = pickRandomByChance(tiles);
trace(picked.item);
public function pickRandomByChance(options:Array):Object
{
var copy:Array = [];
var range:Number = 0;
for (var i:int = 0; i < options.length; i++)
{
copy.push( { "item":options[i].item, "chance":options[i].chance } );
range += copy[i].chance;
if (i > 0)
copy[i].chance += copy[i - 1].chance;
}
var pick:Number = Math.floor(Math.random() * range);
for (i = 0; i < copy.length; i++)
{
if (pick <= copy[i].chance)
return copy[i];
}
return null;
}
There quite a few ways you could do this, and it largely depends of the scope of your project. If you just have the three elements, using a switch statement would be easy:
var rand:Number = Math.random();
switch(true){
case rand >= .3:
//use fire
break;
case rand >= .1
//use water
break;
default:
//use ice
}
Someone else may have a better way though

Create "changset" of two bytearrays

I have some binary data. I will change over time, some bytes get added here and there, some get changed. Overall most of the bytearray remains the same.
Is there any library, preferably Actionscript 3, that generats a "changeset" (is there a better name for this?) out of two bytearrays. Also it should let me apply a changeset to a bytearray and return the resulting new bytearray.
Does this make sense? I was not sure how to formulate my problem best.
EDIT for Clarification:
What i want is something that only emits changes, thus making the "changeset" as small as possible. So if only 1KB of a 1MB Binary have changed, the changeset should be a bytearray of about 1KB size.
EDIT:
Basically i need an AS3 Version of http://www.daemonology.net/bsdiff/ i think
I do not know any AS3 library for that but if I understood you right, coding this from scratch isn't as hard or time-consuming as you might think. Here is my (naive) approach on that. Maybe this already fits your needs.
Example output
Code
package {
import flash.display.Sprite;
import flash.events.Event;
import flash.utils.ByteArray;
public class Main extends Sprite {
public function Main():void {
if (stage)
init();
else
addEventListener(Event.ADDED_TO_STAGE, init);
}
private function createDiff(original:ByteArray, comparedTo:ByteArray):ByteArray {
var diff:ByteArray = new ByteArray();
var length:uint = Math.min(original.length, comparedTo.length);
original.position = 0;
comparedTo.position = 0;
for (var i:int = 0; i < length; i++) {
var byteOriginal:int = original.readByte();
var byteComparedTo:int = comparedTo.readByte();
if (byteOriginal != byteComparedTo) {
diff.writeByte(byteComparedTo - byteOriginal);
}
else {
diff.writeByte(0);
}
}
diff.compress();
return diff;
}
private function applyDiff(original:ByteArray, diff:ByteArray):ByteArray {
var result:ByteArray = new ByteArray();
diff.uncompress();
original.position = 0;
diff.position = 0;
var length:uint = Math.min(original.length, diff.length);
for (var i:uint = 0; i < length; i++) {
var byteOriginal:int = original.readByte();
var byteDiff:int = diff.readByte();
result.writeByte(byteOriginal + byteDiff);
}
return result;
}
private function init(e:Event = null):void {
removeEventListener(Event.ADDED_TO_STAGE, init);
// generate one random byte array and a slightly different variant
var length:uint = 128;
var a:ByteArray = new ByteArray();
var b:ByteArray = new ByteArray();
for (var i:int = 0; i < length; i++) {
var value:int;
value = 127 - Math.floor(Math.random() * 256);
a.writeByte(value);
if (value > 64) {
value = 127 - Math.floor(Math.random() * 256);
}
b.writeByte(value);
}
// create a diff and apply it to the original byte array for verification
var diff:ByteArray = createDiff(a, b);
var result:ByteArray = applyDiff(a, diff);
// trace the byte arrays
a.position = 0;
b.position = 0;
diff.position = 0;
result.position = 0;
var outputA:String = "";
var outputB:String = "";
var outputDiff:String = "";
var outputResult:String = "";
for (var k:int = 0; k < length; k++) {
outputA += a.readByte() + "\t";
outputB += b.readByte() + "\t";
outputDiff += diff.readByte() + "\t";
outputResult += result.readByte() + "\t";
}
trace("1st: \t" + outputA);
trace("2nd: \t" + outputB);
trace("diff:\t" + outputDiff);
trace("test:\t" + outputResult);
}
}
}