AS3 do 3 random stops, that are never equal to one another - actionscript-3

I have 3 movieclips, each one has 7 frames and labels that play different images, I want to stop each one randomly, but never have them equal the same frame. I was thinking array.push once its called, but I dont know how to do that. So I have this so far:
function startGame(event:MouseEvent)
{
addChild(level6_mc);
addChild(inGameNav_mc);
level6_mc.gotoAndPlay(2);
var timer = setTimeout(startAgain, 1000);
startAgain();
}
// level 6
function startAgain()
{
var randomNumber:Number= Math.floor(Math.random()*7);
var door1 = level6_mc.door1_mc;
var door2 = level6_mc.door2_mc;
var door3 = level6_mc.door3_mc;
door1.gotoAndStop(randomNumber);
door2.gotoAndStop(randomNumber);
door3.gotoAndStop(randomNumber);
}
there has to be an easy way for this, I just cant figure it out. I have been looking all over the net for a solution, but every method is just so complicated. Can anyone help me find a simple solution, and if you tell me to use an array can you please give example. Thanks in advance

I would opt for an approach like this:
function startGame(event:MouseEvent){
addChild(level6_mc);
addChild(inGameNav_mc);
level6_mc.gotoAndPlay(2);
var timer= setTimeout(startAgain, 1000);
startAgain();
}
function startAgain(){
var randomFrames:Array = getRandomFrames(3);
var door1 = level6_mc.door1_mc;
var door2 = level6_mc.door2_mc;
var door3 = level6_mc.door3_mc;
door1.gotoAndStop(randomFrames[0]);
door2.gotoAndStop(randomFrames[1]);
door3.gotoAndStop(randomFrames[2]);
}
/*
Given input of 3, the return should be an array of integers randomly
chosen from the array defined by `frames`. An example would be `[5,2,7]`
*/
function getRandomFrames(var $frameCount:Number):Array {
var frames:Array = [1, 2, 3, 4, 5, 6, 7]
var randomFrames:Array = new Array(Math.min($frameCount, frames.length));
var pos:Number = 0;
for (var i:int = 0; i < randomFrames.length; i++)
{
pos = int(Math.random() * frames.length);
randomFrames[i] = frames.splice(pos, 1)[0];
}
return randomFrames
}
I don't have Flash on this machine, so I can't test. But the idea is that you have an array of frame numbers, 1-7 and you randomly choose 3 of those numbers to be your stop frames.

Since its a small frame count, you can splice the frames out of an array:
function startGame(event:MouseEvent){
addChild(level6_mc);
addChild(inGameNav_mc);
level6_mc.gotoAndPlay(2);
var timer= setTimeout(startAgain, 1000);
startAgain();
}
//level 6
function startAgain(){
var door1 = level6_mc.door1_mc;
var door2 = level6_mc.door2_mc;
var door3 = level6_mc.door3_mc;
var stopsAt:Array = [1,2,3,4,5,6];
door1.gotoAndStop(stopsAt.splice(Math.random()*stopsAt.length, 1)[0]);
door2.gotoAndStop(stopsAt.splice(Math.random()*stopsAt.length, 1)[0]);
door3.gotoAndStop(stopsAt.splice(Math.random()*stopsAt.length, 1)[0]);

var prevNum:int = 0;
function startGame(event:MouseEvent)
{
addChild(level6_mc);
addChild(inGameNav_mc);
level6_mc.gotoAndPlay(2);
var timer = setTimeout(startAgain, 1000);
startAgain();
}
// level 6
function startAgain()
{
var randomNumber:int= getRandomNumber(7,prevNum);
prevNum = randomNumber;
var door1 = level6_mc.door1_mc;
var door2 = level6_mc.door2_mc;
var door3 = level6_mc.door3_mc;
door1.gotoAndStop(randomNumber);
door2.gotoAndStop(randomNumber);
door3.gotoAndStop(randomNumber);
}
function getRandomNumber(length:int,previousNumber:int):int
{
var currentNumber:int;
do{
currentNumber = Math.floor(1+Math.random()*length);
}while(currentNumber==previousNumber);
return currentNumber;
}

Related

how to call just 2 value in array randomly specific location flash

I've 3 mc. I want to call 2 of them on stage randomly in specific locations. I don't know how to call them. I just tried with array. I think array is the best way but still confused.
this's code I tried :
import flash.geom.Point;
var Batumc:batu_mc = new batu_mc(); // creates a instance of the movieclip, i.e, an object
var Batumc1:L = new L();
var Pisangmc:pisang_mc = new pisang_mc();
var Batumc2:MovieClip = new MovieClip();
var Status:int = 0;
button.addEventListener(MouseEvent.CLICK, tombol);
function tombol(e:MouseEvent):void{
//addChild(Batumc);
//addChild(Batumc1);
//addChild(Pisangmc);
var P:Array = [new Point(80.2, 100), new Point(260, 100), new Point(430, 100)];
var M:Array = [Batumc, Batumc1, Pisangmc];
//random benda
var benda:int = Math.random()*M.length;
// Remove the selected benda from its list.
M.splice(benda, 1);
while (M.length){
// Get the last MovieClip and remove it from the list.
Batumc2 = M.pop();
trace(Batumc2);
// Produce a random Point.
var anIndex:int = Math.random() * P.length;
var aPo:Point = P[anIndex];
// Remove the selected Point from its list.
P.splice(anIndex, 1);
// Move the selected MovieClip to the selected Point coordinates.
Batumc2.x = aPo.x;
Batumc2.y = aPo.y;
addChild(Batumc);
addChild(Batumc1);
addChild(Pisangmc);
}
Status = 1;
}
button.addEventListener(Event.ENTER_FRAME, frame);
function frame(e:Event):void{
if(Status == 1 ){
removeChild(Batumc2);
Status = 0;
}
}
when i run this code, sometimes 3 mc appear again
I think the problem is with this line:
M[i] = P.splice(randomPos, 1);
You assign M[i] (array of mc) with value from P (array of points), so M[i] = array with point and not an mc.
If you want to avoid such issues you can use Vectors instead of arrays. Its more efficient and also must contain the type you declared.
Vector class Docs.
To use the vector, instead of:
var P:Array = [...];
var M:Array = [...];
Do:
var P:Vector.<Point> = new <Number>[...];
var M:Vector.<MovieClip> = new <MovieClip>[...];
And the rest is just like arrays (pop, push, slice, ...)
To remove item from M, just splice M, i don't understand why you need to iterate over M.
M.splice(randomPos, 1);
Try getDefinitionByName
var myClass:Class = getDefinitionByName("Class_Name") as Class;
var classInstance:MovieClip = new myClass as MovieClip;
addChild(classInstance);
You just have to determine the specific location in the array for the mc'c, beside that you can get the classes from the library like this;
var locations:Array = [{xpos:100, ypos:12} , {xpos:30, ypos:50} , {xpos:400, ypos:28}, ......];
for(var i:uint=0; i<YOUR_MCS_LENGTH; i++) {
var myClass:Class = getDefinitionByName("Batumc"+i) as Class;
var mc:MovieClip = new myClass as MovieClip;
mc.x = locations[i].xpos;
mc.y = locations[i].ypos;
}
I have followed your advice #Özgün Sandal, but I get this error
ReferenceError: Error #1065: Variable Batumc10 is not defined.
at global/flash.utils::getDefinitionByName()
at nyoba9_fla::MainTimeline/frame1()
this my code :
import flash.utils.getDefinitionByName;
import flash.geom.Point;
var Batumc:batu_mc = new batu_mc(); // creates a instance of the movieclip, i.e, an object
var Batumc1:L = new L();
var Pisangmc:pisang_mc = new pisang_mc();
var P:Array = [new Point(80.2, 100), new Point(260, 100), new Point(430, 100)];
var M:Array = [Batumc, Batumc1, Pisangmc];
for(var i:uint=0; i<M.length; i++) {
var myClass:Class = getDefinitionByName("Batumc1"+i) as Class;
var mc:MovieClip = new myClass as MovieClip;
// Produce a random Point.
var anIndex:int = Math.random() * P.length;
var aPo:Point = P[anIndex];
// Remove the selected Point from its list.
P.splice(anIndex, 1);
mc.x = aPo.x;
mc.y = aPo.y;
}
where's my fault?

Make movieclips appear randomly in AS3

Right now I have six mice places in spesific places on the stage. These mice move based on adjustments made on the timeline inside the movieclip itself. What I aim to do is to start these six movieclips randomly based on a timer. This task im currently struggeling with..
Here is my code;
var clipArray:Array = new Array();
clipArray[0] = musx0_mc;
clipArray[1] = musx1_mc;
clipArray[2] = musx2_mc;
clipArray[3] = musx3_mc;
clipArray[4] = musx4_mc;
clipArray[5] = musx5_mc;
var i:int = 0;
var musTimer:Timer = new Timer(100);
musTimer.addEventListener(TimerEvent.TIMER, playMus);
function playMus(event:TimerEvent):void
{
for(i=0; i<clipArray.length; i++)
{
var randomMus:Number = Math.floor(Math.random()*100);
clipArray[randomMus].play();
}
}
musTimer.start();
It seems that you want to get 0 to 5 random number.
//var randomMus:Number = Math.floor(Math.random()*100); // returns 0 to 99
var randomMus:int = Math.floor(Math.random()*6); // returns 0 to 5
Maybe this code works.
var clipArray:Array = new Array();
clipArray[0] = musx0_mc;
clipArray[1] = musx1_mc;
clipArray[2] = musx2_mc;
clipArray[3] = musx3_mc;
clipArray[4] = musx4_mc;
clipArray[5] = musx5_mc;
var musTimer:Timer = new Timer(100);
musTimer.addEventListener(TimerEvent.TIMER, playMus);
function playMus(event:TimerEvent):void
{
//for(i=0; i<clipArray.length; i++) // What is this loop??
//{
//var randomMus:Number = Math.floor(Math.random()*100);
var randomMus:int = Math.floor(Math.random()*6);
clipArray[randomMus].play();
//}
}
musTimer.start();

Error joining AS2 with AS3

I have problems joining two scripts into one.
This is main part of the script: AS3.
And this is already joined script.
And here is part of the code that I need to import (AS2) :
stop();
var banners:Array = new Array();
var imagePaths:Array = new Array();
var links:Array = new Array();
var bodyTexts:Array = new Array();
var imageTime:Number;
var numberOfBanners:Number;
var isRandom:String;
var showHeader:String;
var bannersXML:XML = new XML();
bannersXML.ignoreWhite = true;
bannersXML.load("banners.xml");
bannersXML.onLoad = function(success) {
if (success) {
trace("XML LOADED");
imageTime = parseInt(this.firstChild.firstChild.firstChild)*1000;
numberOfBanners = parseInt(this.firstChild.childNodes[1].firstChild);
isRandom = this.firstChild.attributes["isRandom"];
showHeader = this.firstChild.childNodes[2].attributes["showHeader"];
var bannerSequence:Array = new Array();
if (isRandom == "true") {
//Make a random sequence
while (bannerSequence.length<numberOfBanners) {
newRandomNumber = random(numberOfBanners);
//Make sure that the random one chosen is not already chosen
for (var i = 0; i<=bannerSequence.length; i++) {
if (newRandomNumber != bannerSequence[i]) {
alreadyThere = false;
} else {
alreadyThere = true;
break;
}
}
//Add only random values that aren't in the array
if (!alreadyThere) {
bannerSequence.push(newRandomNumber);
}
}
} else {
for (var i = 0; i<numberOfBanners; i++) {
bannerSequence.push(i);
}
}
}
//Read XML in the Random Order Chosen
for (var i = 0; i<numberOfBanners; i++) {
banners.push(this.firstChild.childNodes[2].childNodes[bannerSequence[i]].firstChild.firstChild.toString());
bodyTexts.push(this.firstChild.childNodes[2].childNodes[bannerSequence[i]].childNodes[1].firstChild.nodeValue);
imagePaths.push(this.firstChild.childNodes[2].childNodes[bannerSequence[i]].childNodes[2].firstChild.nodeValue);
links.push(this.firstChild.childNodes[2].childNodes[bannerSequence[i]].childNodes[3].firstChild.nodeValue);
}
play();
};
//Start the image counter at 0
var imageCounter = 0;
I get erorr in this part of the code
function doRandArray(a:Array):Array {//make random array
var nLen:Number = a.length;
var aRand:Array = a.slice();
var nRand:Number;
var oTemp:Object;
for (var i:Number = 0; i < nLen; i++) {
oTemp = aRand[i];
nRand = i + (random(nLen – i));
aRand[i] = aRand[nRand];
aRand[nRand] = oTemp;
}
return aRand;
}
When I run it, I get an error in this place:
nRand = i + (random(nLen – i));
Scene 1, Layer 'Layer 1', Frame 1, Line 265 1084: Syntax error: expecting rightparen before i.
as2 random(random(nLen – i)); is generate 0,1,...nLen-i-1. not floating only int value.
correct as3 code is int(Math.random()*(nLen-i)); or Math.floor(Math.random()*(nLen-i));
as2: random()
as3: Math.random()
In ActionScript 3 the random function is a little bit different from what it was in as2 code, just change the offending line to:
nRand = i + Math.random()*(nLen-1);
This should fix all errors and work just the same.
EDIT: as #bitmapdata.com indicated, for this to run the same as in as2 the random value must be truncated (stripped of its decimal values). Besides the couple of possibilities he suggested, I would personally just change nRand's type to uint on declaration:
var nRand:uint;
You can also change the iterator type to var i:uint. Less memory usage is always good ;)

randomize buttons on in as3 from array

I'm pretty novice to flash 5.5, im trying to build a quiz for my elementary students.
So far I have made the layout, created the image buttons, and I used to as3 to advance the quiz.
So what I'm, looking for is the ability to shuffle the image buttons/answers. Here is a sample of what i have so far.
the red ______
apple (button of apple) boy (button of boy) pineapple (button with pineapple)
In my example, the pictures are buttons, the correct answer is apple. I have tried to create an array, after hours of google searches. This is my code, I'm doing something wrong but I have no idea what. Please help.
Please help.
function Main() {
var button:Array = [];
button.push("choice1");
button.push("choice2");
button.push("choice3");
ShuffleArray(button);
trace(button);
}
function ShuffleArray(button:Array)
{
for (var i:int = button.length-1; i >=0; i--)
{
var randomIndex:int = Math.floor(Math.random()*(i+1));
var itemAtIndex:Object = button[randomIndex];
button[randomIndex] = button[i];
button[i] = itemAtIndex;
thanks in advance.
thanks in advance.
Try something more like this:
protected var button:Array=[choice1, choice2, choice3];//note no quotes, puts in the actual objects
function Main() {
super();
randomArray=shuffleArray(button);
var prevX:int = 0;
var space:int = 10;
//places the buttons from left to right in the order
//they were in the random array
//uses existing y
for (var i:int=0; i<randomArray.length; i++) {
var btn:DisplayObject = randomArray[i] as DisplayObject;
btn.x = prevX;
prevX = btn.x + btn.width + space;
}
}
protected function shuffleArray(inArray:Array):Array {
//create copy of array so as not to alter it
var tempArray = new Array().concat(inArray);
//resultarray (we'll be destroying the temp array)
var resultArray:Array = [];
while(tempArray.length>0) {
var index:int = int(Math.random() * tempArray.length);
//delete object from random location and put it into result array
resultArray.push(tempArray.splice(index, 1)[0]);
}
return resultArray;
}
Note this assumes you're using a document Class and that your buttons are already on the stage at the same y position.

Closure problem? - passing current value of a variable

I'm trying to pass the current value of a variable when an a dynamically generated navigation 'node' is clicked. This needs to just be an integer, but it always results in the last node's value.. have tried some different methods to pass the value, a custom event listener, a setter, but I suspect it's a closure problem.. help would be appreciated ;-)
function callGrid():void {
for (var i:Number = 0; i < my_total; i++) {
var gridnode_url = my_grid[i].#gridnode;
var news_category= my_grid[i].#category;
var newstitle = my_grid[i].#newstitle;
var news_content = my_grid[i]..news_content;
var news_image = my_grid[i]..news_image;
var gridnode_loader = new Loader();
container_mc.addChild(gridnode_loader);
container_mc.mouseChildren = false;
gridnode_loader.load(new URLRequest(gridnode_url));
gridnode_loader.contentLoaderInfo.addEventListener(Event.COMPLETE, gridLoaded);
gridnode_loader.name = i;
text_container_mc = new MovieClip();
text_container_mc.x = 0;
text_container_mc.mouseEnabled = false;
var textY = text_container_mc.y = (my_gridnode_height+18)*y_counter;
addChild(text_container_mc);
var tf:TextSplash=new TextSplash(newstitle,10,0,4 );
container_mc.addChild(tf);
tf.mouseEnabled = false;
tf.height = my_gridnode_height;
text_container_mc.addChild(tf);
var text_container_mc_tween = new Tween(text_container_mc, "alpha", Strong.easeIn, 0,1,0.1, true);
gridnode_loader.x = (my_gridnode_width+5) * x_counter;
gridnode_loader.y = (my_gridnode_height+15) * y_counter;
if (x_counter+1 < columns) {
x_counter++;
} else {
x_counter = 0;
y_counter++;
}
}
}
function gridLoaded(e:Event):void {
var i:uint;
var my_gridnode:Loader = Loader(e.target.loader);
container_mc.addChild(my_gridnode);
_xmlnewstarget = my_gridnode.name;
//||||||||||||||||||||||||||||||||||||||||
//when a particular grid node is clicked I need to send the current _xmlnewstarget value to the LoadNewsContent function...
//||||||||||||| ||||||||||||||||||||||||
my_tweens[Number(my_gridnode.name)]=new Tween(my_gridnode, "alpha", Strong.easeIn, 0,1,0.1, true);
my_gridnode.contentLoaderInfo.removeEventListener(Event.COMPLETE, gridLoaded);
my_gridnode.addEventListener(MouseEvent.CLICK, loadNewsContent);
}
function loadNewsContent(e:MouseEvent):void {
createNewsContainer();
getXMLNewsTarget();
news_category = my_grid[_xmlnewstarget].#category;
var tfnews_category:TextSplash=new TextSplash(news_category,20,16,32,false,false,0xffffff );
tfnews_category.mouseEnabled = false;
newstitle = my_grid[_xmlnewstarget].#newstitle;
var tftitle:TextSplash=new TextSplash(newstitle,20,70,24,false,false,0x333333 );
news_container_mc.addChild(tftitle);
tftitle.mouseEnabled = false;
news_content = my_grid[_xmlnewstarget]..news_content;
var tfnews_content:TextSplash=new TextSplash(news_content,20,110,20,true,true,0x333333,330);
news_container_mc.addChild(tfnews_content);
tfnews_content.mouseEnabled = false;
news_image = my_grid[_xmlnewstarget].#news_image;
loadNewsImage();
addChild(tfnews_category);
addChild(tftitle);
addChild(tfnews_content);
var news_container_mc_tween = new Tween(news_container_mc, "alpha", Strong.easeIn, 0,1,0.3, true);
news_container_mc_tween.addEventListener(Event.INIT, newsContentLoaded);
}
I'm not going to try to read your code (try to work on your formatting, even if it's just indenting), but I'll provide a simplified example:
for (var i = 0; i < my_total; i++) {
var closure = function() {
// use i here
}
}
As you say, when closure is called it will contain the last value of i (which in this case would be my_total). Do this instead:
for (var i = 0; i < my_total; i++) {
(function(i) {
var closure = function() {
// use i here
}
})(i);
}
This creates another function inside the loop which "captures" the current value of i so that your closure can refer to that value.
See also How does the (function() {})() construct work and why do people use it? for further similar examples.
Umm, as mentioned above, the code is a bit dense, but I think you might have a bit of type conversion problem between string and integers, is the "last value" always 0? try making these changes and let me know how you get on.
// replace this gridnode_loader.name = i;
gridnode_loader.name = i.toString();
// explictly type this as an int
_xmlnewstarget = parseInt(my_gridnode.name);
// replace this: my_tweens[Number(my_gridnode.name)] = new Tween(......
my_tweens[parseInt(my_gridnode.name)] = new Tween();
Oh and I think it goes without saying that you should massively refactor this code block once you've got it working.
Edit: after further study I think you need this
//replace this: my_gridnode.addEventListener(MouseEvent.CLICK, loadNewsContent);
var anonHandler:Function = function(e:MouseEvent):void
{
loadNewsContent(_xmlnewstarget);
};
my_gridnode.addEventListener(MouseEvent.CLICK, anonHandler);
Where your loadNewsContent has changed arguements from (e:MouseEvent) to (id:String)
Firstly, you do not need to call addChild for the same loader twice (once in callGrid) and then in (gridLoaded). Then you can try putting inside loadNewsContent: news_category = my_grid[int(e.target.name)].#category;instead of news_category = my_grid[_xmlnewstarget].#category; As _xmlnewstarget seems to be bigger scope, which is why it is getting updated every time a load operation completes.