I'm in need of some help. To start with, what I have is an interaction where you fill out 5 text boxes in response to 2 questions. Each of the 5 answers must be filled out as input text and then checked against an array of acceptable responses when the done button is clicked. Also, there are two type differences in the fields. So the first three answer fields belong to a range of acceptable responses in the array: Type A and the next two questions to Type B. It's possible to fill out the correct responses in any order, so long as the typing is correct.
What I can't seem to figure out is why the textFields aren't translating to Strings.
import flash.text.TextField;
import flash.events.MouseEvent;
stop();
//*--------------------------------------------
//
// THINGS YOU CAN CHANGE
//
//*--------------------------------------------
var a_inputType:Array = new Array("Doggie Day Spa", "Deb's Dog Walking Service", "Pet Market", "Pampered Pet", "TLC Grooming"); //All recognized type responses, Type A listed before Type B
var n_typeA:Number = new Number(3); //Sets the range for Type A
//*--------------------------------------------
//
// PAGE SETUP
//
//*--------------------------------------------
var n_typeB:Number = new Number(a_inputType.length - n_typeA +1); //Finds the range of Type B
var a_testArray:Array = new Array(); //Holds push data from submit button
var a_correctArray:Array = new Array(); //Creates an array to run a final test against
for(var c = 0; c<=a_inputType.length-1; c++){ //Loop populates the array
a_correctArray.push(1);
}
var inputField1:TextField = new TextField(); //Creates the Text Fields
var inputField2:TextField = new TextField();
var inputField3:TextField = new TextField();
var inputField4:TextField = new TextField();
var inputField5:TextField = new TextField();
var txtString1:String = new String(); //Creates the strings for translating the input text
var txtString2:String = new String();
var txtString3:String = new String();
var txtString4:String = new String();
var txtString5:String = new String();
for(var f = 1; f<=a_inputType.length; f++){ //Assigns them properties, locations, and adds a listener for text
var fieldBuilder = "inputField"+f;
var fieldFinder = "txt_pos"+f;
addChild(this[fieldBuilder]);
this[fieldBuilder].border = false;
this[fieldBuilder].width = 290;
this[fieldBuilder].height = 25;
this[fieldBuilder].x = this[fieldFinder].x;
this[fieldBuilder].y = this[fieldFinder].y;
this[fieldBuilder].type = "input";
this[fieldBuilder].multiline = true;
this[fieldBuilder].text = "";
this[fieldBuilder].addEventListener(TextEvent.TEXT_INPUT, function (){
var stringBuilder = "txtString"+f;
this[stringBuilder] = this[fieldBuilder].text;
});
}
//*--------------------------------------------
//
// FUNCTIONS
//
//*--------------------------------------------
function SUBMIT(event:MouseEvent):void{
for(var t=1; t<=a_inputType.length; t++){ //Loop establishes checks for each String against an input type
if(t<=n_typeA){ //if/else divides the textfields into two ranges: typeA and typeB
checkTypeA(this["txtString"+t], a_inputType); //sends the array of correct responses and the captured String to checkTypeA
}else{
checkTypeB(this["txtString"+t], a_inputType); //sends the array of correct responses and the captured String to checkTypeB
}
}
var TEMPSELECT = a_testArray.toString(); //reduces the testArray recieving push data into a String
var TEMPCORRECT = a_correctArray.toString(); //reduces the correctArray from scene set-up into a String
if(TEMPSELECT == TEMPCORRECT){ //compares the strings and determines a trace response
trace("correct");
}else{
trace("incorrect");
}
}
function checkTypeA(value:String, arr:Array){ //Checks the String against all the array values within the specified range for type A
for (var a=1; a<=n_typeA; a++){ //determines the range
if (arr[a]==value){ //checks the value
a_testArray.push(1); //if true, generates a push value for a testArray to be checked later
}
}
}
function checkTypeB(value:String, arr:Array){
for (var b = n_typeA; b<=n_typeB; b++){
if (arr[b-1]==value){
a_testArray.push(1);
}
}
}
//*--------------------------------------------
//
// BUTTONS
//
//*--------------------------------------------
done_bttn.addEventListener(MouseEvent.CLICK, SUBMIT); //Launches the SUBMIT function when "Done" is pressed.
Upon further investigation I've noticed that the loop isn't terminating when it reaches 5. It keeps regurgitating TextFields over and over again with the same variable names and instancing. Because of this, the addChild is dumping input fields one on top of one another in the flash file (which makes editing a text field impossible since your always clicking on a new field positioned directly on top of the one you just edited).
The trace on the loop comes back like this:
inputField1
txt_pos1
inputField2
txt_pos2
inputField3
txt_pos3
inputField4
txt_pos4
inputField5
txt_pos5
inputField1
txt_pos1
inputField2
txt_pos2
inputField3
txt_pos3
inputField4
txt_pos4
inputField5
txt_pos5
inputField1
txt_pos1
inputField2
txt_pos2
and so on.... how can I stop this looping behavior. I've tried if/else breaking and that's not working.
The context of the this keyword changes when you call it from a local function. You can easily verify it if you add trace(this) to your anonymous function. It will trace out [object global]. Two solutions come to mind, store a reference of this in a variable:
var self:MovieClip = this;
for(var f = 1; f<=a_inputType.length; f++){
//...
this[fieldBuilder].addEventListener(TextEvent.TEXT_INPUT, function (){
var stringBuilder = "txtString"+f;
self[stringBuilder] = self[fieldBuilder].text;
});
}
Or declare a new function:
for(var f = 1; f<=a_inputType.length; f++){
//...
this[fieldBuilder].addEventListener(TextEvent.TEXT_INPUT, myFunction);
}
function myFunction(t:TextEvent){
var stringBuilder = "txtString"+f;
this[stringBuilder] = (t.target as TextField).text;
}
Related
I tried to show a random number in three movieclip boxes below(blue, yellow, red) when push button(grey box). to make random numbers I use math.ceil and I keep it in a var. I make 3 var (so I've 3 formula random number). after that, I want to call that 3 var into 3 new var randomly (hasil,hasil2,hasil3). last, i put the 3 new var into random dynamic text. the dynamic text is in three movieclip boxes.
these the formula random number
mtk = Math.ceil(Math.random()*10);
mtk1 = Math.ceil(Math.random()*20);
mtk2 = mtk+mtk1;
these the dynamic text
mc.jwb1.text = hasil.toString();
mc.jwb2.text = hasil2.toString();
mc.jwb3.text = hasil3.toString();
I tried to call the 3 var in 3 random numbers use 2 arrays, but I still confused about how to call them or you have better idea, Please tell me?
var mc:jwb = new jwb();
var mtk:Number;
var mtk1:Number;
var mtk2:Number;
var hasil:int;
var hasil2:int;
var hasil3:int;
btn.addEventListener(MouseEvent.CLICK, button);
function button(e:MouseEvent):void{
addChild(mc);
}
Batas_mc.addEventListener(Event.ENTER_FRAME, batas);
function batas(e:Event):void{
mc.x = 270;
mc.y = 130;
mtk = Math.ceil(Math.random()*10);
mtk1 = Math.ceil(Math.random()*20);
mtk2 = mtk+mtk1;
//Array object acak
var P:Array = [mtk, mtk1, mtk2];
var M:Array = [hasil, hasil2, hasil3];
while (M.length){
// Get the last MovieClip and remove it from the list.
var Batumc2:MovieClip = M.pop();
// Produce a random Point.
var anIndex:int = Math.random() * P.length;
var aPo = P[anIndex];
// Remove the selected Point from its list.
P.splice(anIndex, 1);
// Move the selected MovieClip to the selected Point coordinates.
Batumc2 = aPo;
}
mc.jwb1.text = hasil.toString();
mc.jwb2.text = hasil2.toString();
mc.jwb3.text = hasil3.toString();
}
var myArray:Array = new Array();
var myMC:MovieClip = new MovieClip();
myMC.myArray = myArray;
trace(myMC.myArray[10]); //Output: undefined
var newMC:MovieClip = new MovieClip();
newMC.myOtherArray = myMC.myArray;
newMC.myOtherArray[10] = [];
newMC.myOtherArray[10][0] = 100;
trace(myMC.myArray[10]); //Output: 100
Why does that happen, and is there any way to avoid it?
EDIT:
Found a function that can clone associative arrays here.
Here is the function (from the above link):
function clone(source:Object):*
{
var myBA:ByteArray = new ByteArray();
myBA.writeObject(source);
myBA.position = 0;
return(myBA.readObject());
}
Does making the function return type "*" mean that it can be any type? or is it something specific to objects/arrays?
It's because you have passed a reference of the original array to the new clip. Arrays, as objects, are not primitives and therefore will always be referenced.
If you would like to clone an array, keeping the original intact, use this method:
var b:Array = a.concat();
b will be a new array. a can modified without changing b.
i have a problem witch i cant solve, and i wanted to ask what am i doing wrong. The idea should be that when i create the textfield i want to read from it, but it doesnt
function click2(e:MouseEvent):void{
e.currentTarget.removeEventListener(MouseEvent.CLICK, click2);
fx=e.target.x+400;
fy=e.target.y+300;
var i:int;
i=2;
trace(str);
trace(e.target.name);
var line:Shape = new Shape();
line.graphics.lineStyle(1,0xFF0000,2);
line.graphics.moveTo(sx,sy);
line.graphics.lineTo(fx,fy);
this.addChild(line);
var inputField:TextField = new TextField();
inputField.border = true;
inputField.type = TextFieldType.INPUT;
inputField.width = 23;
inputField.height = 18;
inputField.x = (sx+fx)/2;
inputField.y = (sy+fy)/2;
inputField.multiline = false;
inputField.maxChars = 3;
inputField.restrict = "0-9";
str=inputField.text;
addChild(inputField);
}
In this code i create a line, and near it appears a textfield , where you need to input the value of the line, but i can`t get it , when i want to trace the STR value, it is null,the text should be written by the user and i should read it ...
If you want to check the data the user added to the textinput you have to listen for the change-event. After that you can access the provided text.
function click2(e:MouseEvent):void{
...
inputfield.addEventListener(Event.CHANGE, checkInput);
}
function checkInput(e:Event):void {
//receive input value and validate it
var textfield:TextField = e.target as TextField;
var str:String = textfield.text;
...
}
I am currently building a project where I have a map with a number of ship and aircraft. What I am trying to achieve is to check the Line of Sight distance between them.
I have set up a LOS Calculator which checks the height of one platform and the height of a second platform then gives a response. That works fine.
I then wanted to addCircle based on the result from this calculator. So if the result was 10 it would draw a circle 10cm in radius. If the result was 100 then it would draw it at 100, you get the picture. This works.
My problem now is that I need to be able to click on one platform either before or after I have made the calculation and the .addCircle be added to that movieClip. I have set up an array to store the movieclips instance names and traced that. I have added a field on stage so that you can click on a platform and it will recognise the platform clicked. I am just lost as to how to get the circle into the movieClip that has been clicked.
I am very new to AS3 so this is starting todo my head in. Any help would be greatly appreciated.
The code I have is attached below. I hope I have inserted this properly. Thanks again
import flash.events.MouseEvent;
import flash.display.MovieClip;
stage.focus=ht1;
// creation of array containing movieclips and code that adds the clicked movieclip to Array-platformClicked
var platformArray:Array = [arunta_mc, f15_mc];
var platformClicked = [];
var selectedPlatform:MovieClip = new MovieClip();
for(var i:int = 0; i < platformArray.length; i++) {
platformArray[i].buttonMode = true;
platformArray[i].addEventListener(MouseEvent.CLICK, item_onClick);
}
function item_onClick(event:MouseEvent):void {
var selectedPlatformArray:Array = platformArray.filter(checkName);
selectedPlatform = selectedPlatformArray[0];
myText.text = event.currentTarget.name + " was clicked";
var platformClicked = String(event.currentTarget.name);
trace(platformClicked);
}
function checkName(item:MovieClip, index:int, array:Array):Boolean
{
return(item.name == platformClicked);
}
//setup of LOS Calculator code
var counter:Number=1;
operator_txt.text = "+";
ht1.restrict="-0123456789.";
ht2.restrict="-0123456789.";
var myresult:Number;
var test = [];
//start of code when equal button is pressed
equal_btn.addEventListener(MouseEvent.CLICK, equalhandler);
var newCircle:Shape = new Shape();//defines circle to be drawn
function equalhandler(event:MouseEvent):void{
newCircle.graphics.lineStyle(1, 0x000000);
newCircle.graphics.beginFill(0x435632);
newCircle.alpha = .1;
//start of result code
result_txt.text = String(int((1.23*(Math.sqrt(Number(parseFloat(ht1.text)+parseFloat(ht2.text)+""))))));
var test = String(int((1.23*(Math.sqrt(Number(parseFloat(ht1.text)+parseFloat(ht2.text)+""))))));
trace(test);
//end of result code
newCircle.graphics.drawCircle(0,0,test);//add circle based on LOS calculation
newCircle.graphics.endFill();
//var selectedPlatform:MovieClip = selectedPlatformArray[0];
selectedPlatform.addChild(newCircle);//this is where I need to add newCircle to the movieClip that is clicked
trace(selectedPlatform);
//trace(platformClicked);
}
//start of code for the clear button
clear_btn.addEventListener(MouseEvent.CLICK, clearhandler);
function clearhandler(event:MouseEvent):void{
ht1.text=ht2.text=result_txt.text="";
removeChild(newCircle);
var test = [];
}
You can use the filter() method to check each item's name, like so:
var selectedPlatformArray:Array = platformArray.filter(checkName);
and somewhere in your code, define the checkName function
function checkName(item:MovieClip, index:int, array:Array):Boolean
{
return (item.name == platformClicked);
}
selectedPlatformArray will now contain all elements that return true for the checkName function, and as long as you don't have multiple MovieClips with the same name the array should only contain one element, which you can retrieve simply by accessing the first element of the array:
var selectedPlatform:MovieClip = selectedPlatformArray[0];
Alternatively, you can also use the getChildByName() function, like so:
var selectedPlatform:MovieClip = stage.getChildByName(platformClicked);
However this depends on where the objects are added to, and if they're not all in the same container (or not added at all), then this isn't the best option. It's a quick and simple solution for small projects though.
Anyway, whatever method you use you can then easily add the circle to it in your equalHandler function as usual:
selectedPlatform.addChild(newCircle);
I'd recommend checking out the documentation for both filter() and getChildByName(), to get a better understanding of how they work, since my examples only showed how you'd use them in this specific situation.
Complete code that you should have:
import flash.events.MouseEvent;
import flash.display.MovieClip;
stage.focus=ht1;
// creation of array containing movieclips and code that adds the clicked movieclip to Array-platformClicked
var platformArray:Array = [arunta_mc, f15_mc];
var platformClicked:String = "";
var selectedPlatform:MovieClip = new MovieClip();
for(var i:int = 0; i < platformArray.length; i++) {
platformArray[i].buttonMode = true;
platformArray[i].addEventListener(MouseEvent.CLICK, item_onClick);
}
function item_onClick(event:MouseEvent):void {
var selectedPlatformArray:Array = platformArray.filter(checkName);
selectedPlatform = selectedPlatformArray[0];
myText.text = event.currentTarget.name + " was clicked";
platformClicked = String(event.currentTarget.name);
trace(platformClicked);
}
function checkName(item:MovieClip, index:int, array:Array):Boolean
{
return(item.name == platformClicked);
}
//setup of LOS Calculator code
var counter:Number=1;
operator_txt.text = "+";
ht1.restrict="-0123456789.";
ht2.restrict="-0123456789.";
var myresult:Number;
var test:String = "";
//start of code when equal button is pressed
equal_btn.addEventListener(MouseEvent.CLICK, equalhandler);
var newCircle:Shape = new Shape();//defines circle to be drawn
function equalhandler(event:MouseEvent):void{
newCircle.graphics.lineStyle(1, 0x000000);
newCircle.graphics.beginFill(0x435632);
newCircle.alpha = .1;
//start of result code
result_txt.text = String(int((1.23*(Math.sqrt(Number(parseFloat(ht1.text)+parseFloat(ht2.text)+""))))));
test = String(int((1.23*(Math.sqrt(Number(parseFloat(ht1.text)+parseFloat(ht2.text)+""))))));
trace(test);
//end of result code
newCircle.graphics.drawCircle(0,0,test);//add circle based on LOS calculation
newCircle.graphics.endFill();
//var selectedPlatform:MovieClip = selectedPlatformArray[0];
selectedPlatform.addChild(newCircle);//this is where I need to add newCircle to the movieClip that is clicked
trace(selectedPlatform);
//trace(platformClicked);
}
//start of code for the clear button
clear_btn.addEventListener(MouseEvent.CLICK, clearhandler);
function clearhandler(event:MouseEvent):void{
ht1.text=ht2.text=result_txt.text="";
selectedPlatform.removeChild(newCircle);
test = "";
}
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.