ActionScript 3 Adding images; different positions - function

In short, I have clickable objects with varying colours. I want these colours upon being clicked to appear in my placeholders (there will be 6). I currently have managed to code so that upon clicking any colour it is placed in the first placeholder.
In what way am I able to code to recognise that the first placeholder has been filled and that once filled, the second placeholder should become the target?
Preferably until the 6th has been filled and then stopped, so that the user can see all 6.
I am thinking something like a for loop would be fitting, but I am not sure how to go about it.
So far it's looking something like this:
//Placeholder
var placeHolder1:MovieClip = new MovieClip();
placeHolder1.x = 20;
placeHolder1.y = 245;
stage.addChild(placeHolder1);
//Placeholder2 (UNUSED CURRENTLY)
var placeHolder2:MovieClip = new MovieClip();
placeHolder2.x = 60;
placeHolder2.y = 245;
stage.addChild(placeHolder2);
//Click and select colours
var newBlue:cBlue = new cBlue();
numBlue.addEventListener(MouseEvent.CLICK, fBlue)
function fBlue(e:MouseEvent){
placeHolder1.addChild(newBlue);
}
var newRed:cRed = new cRed();
numRed.addEventListener(MouseEvent.CLICK, fRed)
function fRed(e:MouseEvent){
placeHolder1.addChild(newRed);
}

First, you probably want to learn about Arrays (or Vectors). Arrays/Vectors are lists, so you would put all your placeholders into an array:
var placeHolders:Array = [placeHolder1, placeHolder2];
Though, since there is a formula to your place holder creation, you probably would want to do this in a loop to make it DRYer (Don't Repeat Yourself)
This loop would create 10 place holders and add them to the array:
var placeholders:Array = new Array();
for(var i:int=0; i < 10; i++){
var placeHolder = new Sprite(); //if your not using timelines, just use Sprite instead of MovieClip as it's less overhead
placeHolder.x = 20 * (i + 1); //i starts at 0, and goes to 9
placeHolder1.y = 245;
stage.addChild(placeHolder); //add it to the display list
placeholders.push(placeHolder); //add it to the array
}
Now (continuing to be DRY), attached the same event listener to all your color buttons:
numBlue.addEventListener(MouseEvent.CLICK, selectColor);
numRed.addEventListener(MouseEvent.CLICK, selectColor);
In that event handler I've called 'selectColor' (see code comments)
function selectColor(e:Event):void {
//get the first element in the array
var placeHolder:Sprite = placeholders.shift(); //shift removes the first item from the array, and returns it
placeHolder.addChild(e.currentTarget); //e.currentTarget refers to item that you attached the event listener to, in this case either numBlue or numRed
}
So to summarize, this gets the first placeholder in the array, remove that item from the array, then adds color button that was clicked as a child of that placeholder.

Related

How to create a button that makes a new text field appear on screen?

I've been having trouble getting this button to work. I want it so that whenever you click it, a new text field pops up that you can type stuff in. This is supposed to be for a trivia-like game, where the user inputs their own questions and answers. Here's the code so far...
This is the text field's properties -
QuestionTextField = new TextField();
QuestionTextField.defaultTextFormat = SmallTextFormat;
QuestionTextField.textColor = 0x660000;
QuestionTextField.x = stage.stageWidth * 0.1;
QuestionTextField.y = 200;
QuestionTextField.width = stage.stageWidth * 0.8;
QuestionTextField.height = 20;
QuestionTextField.selectable = false;
QuestionTextField.type = TextFieldType.INPUT;
QuestionTextField.border = true;
QuestionTextField.multiline = true;
QuestionTextField.wordWrap = true;
And this is the function that is supposed to create a new text field every time the button is clicked-
private function AddQuestionButtonClicked(m:MouseEvent){
for(var i = Questions.length; i>=1; i--){
container_buttonsMC.addChild(QuestionTextField);
Questions.push(QuestionTextField);
QuestionTextField.y += 20
}
}
Notes : "Questions" is an array that holds the number of text fields there are, container_buttonsMC holds all of the buttons on that are on the game's main menu.
The problem is that whenever I click it, it 1. Doesn't actually create a new text field, but instead moves it a certain amount of pixels down, and 2. It sort of duplicates the text field's position...if that makes ANY sense at all. If I click on the button once, it will move the text field down by 20 pixels. If I click on it again, it will move it down by 40 pixels, then by 80, and so on...
I also traced the length of the array, and surprisingly enough, the number that appeared would double every time I clicked it. However, only one text field is visible (apparently). It probably has something to do with the for loop's action, but I don't know for sure. Does anyone have an idea as to what the problem is? (Thanks in advance, I'm still new to AS3 and programming in general)
First, each need to create a new textfield every time you click the button, rather than adding it to the stage. With what you have at the moment, you only created one text field.
Secondly, you only want to do add one more text field, right? So instead of using a loop, which will create multiple new text fields, just create one extra text field and add it to the list.
The code will look something like
private function AddQuestionButtonClicked(m:MouseEvent){
var QuestionTextField:TextField = new TextField()
QuestionTextField.defaultTextFormat = SmallTextFormat;
QuestionTextField.textColor = 0x660000;
QuestionTextField.x = stage.stageWidth * 0.1;
QuestionTextField.y = 200;
QuestionTextField.width = stage.stageWidth * 0.8;
QuestionTextField.height = 20;
QuestionTextField.selectable = false;
QuestionTextField.type = TextFieldType.INPUT;
QuestionTextField.border = true;
QuestionTextField.multiline = true;
QuestionTextField.wordWrap = true;
// You can adjust the 50 here to control the spacing between text fields
QuestionTextField.y += 50 * Questions.length
container_buttonsMC.addChild(QuestionTextField);
Questions.push(QuestionTextField);
}

If two sprites are visible, do something (AS3)

I'm creating a memory like game. I built all the desktop, the cards generation. I now have two cards of each.
I'm trying to do the pairs delete system.
my function to show the color to find looks like this :
private function onClick(e:MouseEvent):void
{
if (vueDos)
{
vueDos = !vueDos;
faceCarte = new Sprite();
faceCarte.graphics.lineStyle(2,0x000000,.5);
faceCarte.graphics.beginFill(clr);
faceCarte.graphics.drawRoundRect(8,8,this.width - 16, this.height - 16, 10,10);
faceCarte.graphics.endFill();
var _t:TextField = new TextField();
_t.selectable = false;
_t.antiAliasType = "advanced";
_t.autoSize = "left";
_t.defaultTextFormat= new TextFormat(maFont.fontName,24,0x000000);
_t.text = couleur;
_t.x = (this.width - _t.width)/2
_t.y = (this.height - _t.height) >> 1;
faceCarte.addChild(_t);
faceCarte.cacheAsBitmap = true;
this.addChild(faceCarte);
}
if(!vueDos)
}
Does it exist a function wich see if the color of the card is visible (faceCarte), and limit the visibles carte to two then removeChild faceCart.
Thank you in advance
You have to make such a function yourself. It'll be better to assign a couleur property to the card itself, instead of putting it into the TextField and forgetting. This way you'll be able to open first card, get that property, then open second card and compare that one's property with what you received, if match, both cards will be removed.

Changing text with AS3 in a for loop - works for first one, others don't

I have a movieclip called Tab that has two text-fields: named toptxt and bottomtxt. When I create new instances of Tab in a for loop and change the text, only the first instance's text is changed. The rest is the default text in the movieclip.
Here is the code I am using:
for(var i = 0; i < 5; i++){
var newTab = new Tab();
newTab.toptxt.text = nameArray[i]; //nameArray is fine
trace(newTab.toptxt.text); //returns expected value, textfield isn't
newTab.bottomtxt.text = jobs[i];
bottom.addChild(newTab); //bottom is a class var.
newTab.x = i * (newTab.width + 3);
}
Even if I change nameArray[i] to "Test", only the first one works.
This problem does not occur if I don't do it in for loops, however I'd like to do it in a for loop.
Here is a screenshot of the problem: http://i.imgur.com/hgPZ5.png
Pull your declaration of var newTab = new Tab(); outside of the for loop, so your code looks like this:
var newTab:Tab;
for(var i:int = 0; i < 5; i++){
newTab = new Tab();
newTab.toptxt.text = nameArray[i]; //nameArray is fine
trace(newTab.toptxt.text); //returns expected value, textfield isn't
newTab.bottomtxt.text = jobs[i];
bottom.addChild(newTab); //bottom is a class var.
newTab.x = i * (newTab.width + 3);
}
Actionscript is becoming confused when you create an instance and assign newTab as a pointer to it, instead of creating a pointer or reference initially, and then creating new instances and adding them to your displayList.
Also, trace your output of nameArray[i] and confirm that those values are correct (i.e. trace(nameArray[i]);. It's possible the data isn't set properly earlier in your code.

erasing a layer where mouse is over it

I got the following question.
i added the following elements to the stage:
homeBg = new HomeBg();
homeMask = new HomeDrawBg();
addChild(homeBg);
addChild(homeMask);
I allready instantiated them in the beginning of the document. But my problem is the following. the homeBg layer is a image, the homeMask layer is the same image but it has a pencil scetch look. What i want is that wherever i move my mouse, the homemask layer should be erased so the bottom layer becomes visible(only where the mask is erased). So how can i tell the mask layer to erase itself if the mouse is over it?
Answer attempt 2
You can use the blendMode property of a display object to achieve this. Here's the code (tested):
// set the eraser width (diameter)
var eraserWidth:int = 20;
//get the HomeMask library item
var homeMask:HomeMask = new HomeDrawBg();
homeMask.blendMode = BlendMode.LAYER;
addChild(homeMask);
// create the eraser shape
var eraser:Shape = new Shape();
eraser.graphics.beginFill(0x000000);
eraser.graphics.drawCircle(0,0,eraserWidth/2);
eraser.blendMode = BlendMode.ERASE;
homeMask.addChild(eraser);
homeMask.addEventListener(MouseEvent.MOUSE_MOVE,mouseOverMask);
function mouseOverMask(evt:MouseEvent):void
{
eraser.x = homeMask.mouseX;
eraser.y = homeMask.mouseY;
}
There are a couple of important bits here.
Firstly, you must set the blendMode of the thing you want to erase to BlendMode.LAYER.
Secondly (and this is what has tricked me before) your eraser, with BlendMode.ERASE, must be a child of the object you're wanting to erase.
Have a look on the following:http://www.piterwilson.com/personal/2008/05/07/bitmapdata-erasing-in-as3-with-custom-brush-shape/

Re-stacking MovieClips in an Array

I was trying to make a similar thing with the game SameGame (ie. the block above the removed blocks fall downward). Before trying this with an Array that contains MovieClips, this code worked (tried it with int values). With MovieClips on the array, it seems not working the same way.
With int values, example:
popUp(0, 4): Before: 1,2,3,4,5,6,7,8,9,10; After: 1,2,3,4,6,7,8,9,10
But with MovieClips:
popUp(0, 4): Before: 1,2,3,4,5,6,7,8,9,10; After; 1,2,3,4
// Assume the numbers are movieclips XD
Basically, it strips everything else, rather than just the said block >_<
Here's the whole method. Basically, two extra arrays juggle the values above the soon-to-be removed value, remove the value, then re-stack it to the original array.
What could be wrong with this? And am I doing the right thing for what I really wanted to emulate?
function popUp(col:uint, row:uint)
{
var tempStack:Array = new Array();
var extraStack:Array = new Array();
tempStack = IndexArray[col];
removeChild(tempStack[0]);
for(var ctr:uint = tempStack.length-(row+1); ctr > 0; ctr--)
{
removeChild(tempStack[ctr]);
extraStack.push(tempStack.pop());
trace(extraStack);
}
tempStack.pop();
for(ctr = extraStack.length; ctr > 0; ctr--)
{
tempStack.push(extraStack.pop());
//addChild(tempStack[ctr]);
}
IndexArray[col] = tempStack;
}
PS: If it's not too much to ask, are there free step-by-step guides on making a SameGame in AS3 (I fear I might not be doing things right)? Thanks in advance =)
I think you just want to remove an element and have everything after that index shift down a place to fill what you removed. There's an inbuilt function for this called splice(start:uint, length:uint);
Parameters:
start - the index to start removing elements from
length - the amount of elements to remove
var ar:Array = ["hello","there","sir"];
ar.splice(1, 1);
ar is now -> ["hello", "sir"];
As per question:
Here's an example with different types of elements:
var ar:Array = [new MovieClip(), "some string", new Sprite(), 8];
ar.splice(2, 1);
trace(ar); // [object MovieClip], some string, 8
And further example to display the indexes being changed:
trace(ar[2]); // was [object Sprite], is now 8