Dependent text fields - actionscript-3

I want to have text fields which are dependent of each other. E.g there's two input text fields like angular frequency(ω) and ordinary frequency(f), ω=2πf. If I change one, the other changes. How can I do that? Second thing, how can I check if text field is empty?
if (field.text=="")... // doesn't work

There are 2 ways of doing this. You can either have some sort of update function that is called at every frame checking for the current value of each field with what they used to be and seeing if something changed then react to that.
private var tf1 : TextField = new TextField();
private var tf2 : TextField = new TextField();
private var tf1LastVal : String = "";
private var tf2LastVal : String = "";
public function update() : void
{
if(tf1.text != tf1LastVal)
{
tf2.text = //put your logic here
tf1LastVal = tf1.text;
}
else if(tf2.text != tf2LastVal)
{
tf1.text = //put your logic here
tf2LastVal = tf2.text;
}
}
The other, and better way (in my opinion) of doing this is by adding event listeners to your TextFields
//add this where you construct your TextFields
tf1.addEventListener(Event.CHANGE, onTf1Change);
tf2.addEventListener(Event.CHANGE, onTf2Change);
//end
private function onTf1Change(e : Event) : void
{
tf2.text = //your logic here;
}
private function onTf2Change(e : Event) : void
{
tf1.text = //your logic here;
}

Related

Randomise an array from actionscript

public class Hangman extends Sprite {
private var textDisplay:TextField;
private var phrase:String = "Recycled"
private var phrase:String = "Stamped"
private var phrase:String = "grandpa"
"What I want to do here is to randomise the "phrase:String", so that the phrase outcome will be either recycled, stamped or grandpa.
private var shown:String;
private var numWrong:int;
public function Hangman() {
// create a copy of text with _ for each letter
shown = phrase.replace(/[A-Za-z]/g,"_");
numWrong = 0;
...codes*
}
public function pressKey(event:KeyboardEvent) {
// get letter pressed
var charPressed:String = (String.fromCharCode(event.charCode));
// loop through nd find matching letters
var foundLetter:Boolean = false;
for(var i:int=0;i<phrase.length;i++) {
if (phrase.charAt(i).toLowerCase() == charPressed) {
// match found, change shown phrase
shown = shown.substr(0,i)+phrase.substr(i,1)+shown.substr(i+1);
foundLetter = true;
}
}
// update on-screen text
textDisplay.text = shown;
// update hangman
if (!foundLetter) {
numWrong++;
character.gotoAndStop(numWrong+1);
}
}
}
}
I hope someone can help me on this one. Thank you.
You cannot have the same variable being instantiated with the same name... if you want, use an array to keep the possible words...
var phrase:Array = [ "Recycled", "Stamped", "grandpa", ...];
Then, use a Random function to select a number from 0, up to array size, then use that word...
var word = phrase[Math.floor(Math.random()*phrase.length)];

Actionscript 3 Call to a possibly undefined method

Here is the problem, the object is moved together with the clicked object. I want it to be moveable following the mouse pointer, but let the clicked object stays. so when an object is clicked, there will be 2 objects in the stage(the static and moving one).
I think I've figured it out by adding a new object to be moved. in function onClickHero I've tried movingHero = new heroes but it says "call to a possibly undefined method heroes". My question is there any other way how to make another clone of the clicked object since I made it in array? And why does movingHero = new heroes doesn't work?
I'm still amateur at classes. Sorry if it's messed up. Thanks for helping.
package {
import flash.display.MovieClip
import flash.events.MouseEvent
import flash.events.Event
import flash.display.Sprite
public class Hero {
private var heroesArray:Array;
private var heroContainer:Sprite = new Sprite;
private var hero1:MovieClip = new Hero1();
private var hero2:MovieClip = new Hero2();
private var moveHero:Boolean = false;
private var movingHero:MovieClip;
private var _money:Money = new Money();
private var _main:Main;
public function Hero(main:Main)
{ _main = main;
heroesArray = [hero1,hero2];
heroesArray.forEach(addHero);
}
public function addHero(heroes:MovieClip,index:int,array:Array):void
{
heroes.addEventListener(Event.ENTER_FRAME, playerMoving);
heroes.addEventListener(MouseEvent.CLICK, chooseHero);
}
public function playerMoving(e:Event):void
{
if (moveHero == true)
{
movingHero.x = _main.mouseX;
movingHero.y = _main.mouseY;
}
}
public function chooseHero(e:MouseEvent):void
{
var heroClicked:MovieClip = e.currentTarget as MovieClip;
var cost:int = _main._money.money ;
if(cost >= 10 && moveHero == false)
{
_main._money.money -= 10;
_main._money.addText(_main);
onClickHero(heroClicked);
moveHero = true;
}
}
public function onClickHero(heroes:MovieClip):void
{
movingHero = heroes;
heroContainer.addChild(movingHero);
}
public function displayHero(stage:Object):void
{
stage.addChild(heroContainer);
for (var i:int = 0; i<2;i++)
{
stage.addChild(heroesArray[i]);
heroesArray[i].x = 37;
heroesArray[i].y = 80+i*70;
heroesArray[i].width=60;
heroesArray[i].height=55;
heroesArray[i].buttonMode = true;
}
}
}
}
EDIT: I've tried to make movingHero = new Hero1(); but since I don't know which hero will be clicked so I can't just use Hero1 from library. and If I use movingHero = heroClicked I only get the value of hero1 which is a var from Hero1 movieclip. So, is there any way to call the movie clip from library the same as which hero was clicked in stage?
You seemingly want to clone an object while not knowing its type. If that object also containg game logic, it's not the best idea to say spawn new heroes of either type, this might make a mess of your code. But if not, you can get the exact class of the object given, and make an object of that class via the following code:
public function onClickHero(heroes:MovieClip):void
{
if (!heroes) {
trace('heroes is null!');
return;
}
var heroClass:Class = getDefinitionByName(getQualifiedClassName(heroes)) as Class;
movingHero = new heroClass(); // instantiate that class
heroContainer.addChild(movingHero);
// movingHero.startDrag(); if needed
}
Don't forget to clean up the movingHero once it's no longer needed.

Adding a dynamically created DataGrid as child or element does not work

I am trying to develop an application in AS3. What I am really trying to achieve is to have only one datagrid and having it show, you say, three different set of datas. (the real count will be changing dynamically, and it does not matter as the problem is not relevant with this) Yes, it has to be only one datagrid because of you know, I need a compact interface.
The class "Sonuc" has three properties which are string versions of inputs from constructor. A typical "Sonuc" object is something like this.
var sonuc1:Sonuc = new Sonuc(1,1,false);
//sonuc1.num = "1"
//sonuc1.type = "1"
//sonuc1.isTrue = "No"
The reason that I have informed you about "Sonuc" class is that I wanted you to know that class was not something too complicated. And x.mxml is the test mxml where I only load the class for testing purposes.
This is what I have coded so far
public class ResultInterface extends UIComponent
{
private const desiredWidth:int = 250;
private const desiredHeight:int = 150;
private const sonuc1:Sonuc = new Sonuc(1,1,false);
public var tablo:DataGrid = new DataGrid();
public var kolonArray:Array = new Array ();
public var sonucArray:Array = new Array ();
public var currentIndex:int = new int ();
public var prevButon:Button = new Button();
public var nextButon:Button = new Button();
public function ResultInterface():void
{
currentIndex = 0;
super();
tablo = new DataGrid();
width=desiredWidth+40;
height=desiredHeight+60;
this.tablo.width = desiredWidth;
this.tablo.height = desiredHeight;
this.tablo.x = 20;
this.tablo.y = 40;
prevButon.x = 10;
prevButon.y = genislik/2 - 10;
prevButon.width =
prevButon.height = 10;
nextButon.x = genislik +20;
nextButon.y = genislik/2 -10;
nextButon.width =
nextButon.height = 10;
var referansColl:ArrayCollection = new ArrayCollection();
sonucArray.push(referansColl);
tablo.dataProvider = sonucArray[currentIndex];
var sampleCol:DataGridColumn = new DataGridColumn();
sampleCol.dataField = "num";
sampleCol.headerText = "Number";
var sampleCol2:DataGridColumn = new DataGridColumn();
sampleCol2.dataField = "type";
sampleCol2.headerText = "Type";
var sampleCol3:DataGridColumn = new DataGridColumn();
sampleCol3.dataField = "isTrue";
sampleCol3.headerText = "Is it true?";
kolonArray.push(sampleCol,sampleCol2,sampleCol3);
tablo.columns = kolonArray;
this.addElement(tablo); //**** this is the problematic line
this.addChild(oncekiButon);
this.addChild(sonrakiButon);
}
public function getNewSonuc(incoming:Sonuc):void
{
sonucArray[currentIndex].addItem(incoming);
}
public function newTablo():void
{
var newTablo:ArrayCollection = new ArrayCollection();
currentIndex = sonucArray.push(newTablo);
}
public function prev(evt:Event):void //I haven't written event listeners yet
{
if(currentIndex > 0)
currentIndex--;
nextButon.enabled = true;
if(currentIndex == 0)
prevButon.enabled = false;
}
public function birSonrakine(evt:Event):void
{
if(currentIndex < sonucArray.length)
currentIndex++;
prevButon.enabled = true;
if(currentIndex == sonucArray.length)
nextButon.enabled = false;
}
in this version, I get a syntax error "call to a possibly undefined method addElement"
I also tried having the base class as "Sprite" and "Canvas"
when I used addChild instead of addElement, then I get runtime error "addChild is not available to this class"
when I just commented the problematic line out, everything was loaded perfectly but the datagrid itself.
Note that error occurs before sending in some data (Sonuc) to datagrid.
and when I tried with canvas and with addelement, I get "Cannot access a property or method of a null object reference" with some weird functions and classes and packages.
1009: Cannot access a property or method of a null object reference.
at mx.styles::StyleProtoChain$/initProtoChainForUIComponentStyleName()[E:\dev\4.y\frameworks\projects\framework\src\mx\styles\StyleProtoChain.as:358]
at mx.styles::StyleProtoChain$/initProtoChain()[E:\dev\4.y\frameworks\projects\framework\src\mx\styles\StyleProtoChain.as:171]
at mx.core::UIComponent/http://www.adobe.com/2006/flex/mx/internal::initProtoChain()[E:\dev\4.y\frameworks\projects\framework\src\mx\core\UIComponent.as:10926]
at mx.core::UIComponent/regenerateStyleCache()[E:\dev\4.y\frameworks\projects\framework\src\mx\core\UIComponent.as:10989]
at mx.core::UIComponent/http://www.adobe.com/2006/flex/mx/internal::addingChild()[E:\dev\4.y\frameworks\projects\framework\src\mx\core\UIComponent.as:7465]
at mx.core::UIComponent/addChild()[E:\dev\4.y\frameworks\projects\framework\src\mx\core\UIComponent.as:7162]
at mx.controls.listClasses::ListBase/createChildren()[E:\dev\4.y\frameworks\projects\mx\src\mx\controls\listClasses\ListBase.as:3772]
at mx.controls::DataGrid/createChildren()[E:\dev\4.y\frameworks\projects\mx\src\mx\controls\DataGrid.as:1143]
at mx.core::UIComponent/initialize()[E:\dev\4.y\frameworks\projects\framework\src\mx\core\UIComponent.as:7634]
at mx.core::UIComponent/http://www.adobe.com/2006/flex/mx/internal::childAdded()[E:\dev\4.y\frameworks\projects\framework\src\mx\core\UIComponent.as:7495]
at mx.core::Container/http://www.adobe.com/2006/flex/mx/internal::childAdded()[E:\dev\4.y\frameworks\projects\mx\src\mx\core\Container.as:3974]
at mx.core::Container/addChildAt()[E:\dev\4.y\frameworks\projects\mx\src\mx\core\Container.as:2618]
at mx.core::Container/addChild()[E:\dev\4.y\frameworks\projects\mx\src\mx\core\Container.as:2534]
at mx.core::Container/addElement()[E:\dev\4.y\frameworks\projects\mx\src\mx\core\Container.as:2981]
at genel.siniflar::ResultInterfaceArayuz()[C:\Users\Ege\Adobe Flash Builder\brainswift2\src\genel\siniflar\ResultInterface.as:95]
at x()[C:\Users\Ege\Adobe Flash Builder\brainswift2\src\x.mxml:27]
at _x_mx_managers_SystemManager/create()[_x_mx_managers_SystemManager.as:54]
at mx.managers.systemClasses::ChildManager/initializeTopLevelWindow()[E:\dev\4.y\frameworks\projects\framework\src\mx\managers\systemClasses\ChildManager.as:311]
at mx.managers::SystemManager/initializeTopLevelWindow()[E:\dev\4.y\frameworks\projects\framework\src\mx\managers\SystemManager.as:3057]
at mx.managers::SystemManager/http://www.adobe.com/2006/flex/mx/internal::kickOff()[E:\dev\4.y\frameworks\projects\framework\src\mx\managers\SystemManager.as:2843]
at mx.managers::SystemManager/http://www.adobe.com/2006/flex/mx/internal::preloader_completeHandler()[E:\dev\4.y\frameworks\projects\framework\src\mx\managers\SystemManager.as:2723]
at flash.events::EventDispatcher/dispatchEventFunction()
at flash.events::EventDispatcher/dispatchEvent()
at mx.preloaders::Preloader/timerHandler()[E:\dev\4.y\frameworks\projects\framework\src\mx\preloaders\Preloader.as:542]
at flash.utils::Timer/_timerDispatch()
at flash.utils::Timer/tick()
I really need your help folks, please answer as soon as possible.
Well, I tried calling "addElement" from outside of the constructor, and it worked. However I don't know what did exactly cause this error and I know that my solution is not a legitimate one. And I would like to learn proper solution to this problem.
changes to resultInterface.as
// this.addElement(tablo); **** this is the problematic line, we have commented it out
this.addChild(oncekiButon);
this.addChild(sonrakiButon);
changes to x.mxml
public function onCreationComplete(evt:Event):void
{
showResult.addElement(showResult.tablo);
addElement(showResult);
}

Make Objects behave like Radio Buttons in AS3

I would like to implement a very simple way to store a variable containing the last specific "CustomObject" I clicked. I'd like clicks on other objects to be ignored. Take the following sample code for example, given CustomObject extends MovieClip:
//Code within the Document Class:
var square1:CustomObject = new CustomObject();
var square2:CustomObject = new CustomObject();
var square3:CustomObject = new CustomObject();
var triangle1:DifferentObject= new DifferentObject();
square1.x=100; square2.x=200; square3.x=300;
addChild(square1);
addChild(square2);
addChild(square3);
addChild(triangle1);
//Code within the CustomObject Class:
this.addEventListener(MouseEvent.CLICK,radioButtonGlow);
public function radioButtonGlow(e:MouseEvent):void
{
var myGlow:GlowFilter = new GlowFilter();
myGlow.color = 0xFF0000;
myGlow.blurX = 25;
myGlow.blurY = 25;
this.filters = [myGlow];
}
This works great for whenever I click on squares- they light up exactly as expected. However, I'd like to implement a functionality that:
1) Stores the last square I clicked into a variable in the document class
2) Removes the glow from all other squares when I click on another one
Any feedback is greatly appreciated!
I suggest creating a class that acts as a collection of CustomObject instances and manages them in that manner (i.e. ensuring only one of that collection can be selected, etc).
Sample:
public class CustomCollection
{
// Properties.
private var _selected:CustomObject;
private var _items:Array = [];
// Filters.
private const GLOW:GlowFilter = new GlowFilter(0xFF0000, 25, 25);
// Constructor.
// #param amt The amount of CustomObjects that should belong to this collection.
// #param container The container to add the CustomObjects to.
public function CustomCollection(amt:int, container:Sprite)
{
for(var i:int = 0; i < amt; i++)
{
var rb:CustomObject = new CustomObject();
rb.x = i * 100;
_items.push(rb);
container.addChild(rb);
}
}
// Selects a CustomObject at the specified index.
// #param index The index of the CustomObject to select.
public function select(index:int):void
{
for(var i:int = 0; i < _items.length; i++)
{
if(i == index)
{
_selected = _items[i];
_selected.filters = [GLOW];
continue;
}
_items[i].filters = [];
}
}
// The currently selected CustomObject.
public function get selected():CustomObject
{
return _selected;
}
// A copy of the array of CustomObjects associated with this collection.
public function get items():Array
{
return _items.slice();
}
}
Then you can revise your code in the document class to something like:
var collection:CustomCollection = new CustomCollection(3, this);
collection.select(1);
You will need to add your own logic for the click event that deals with selecting the buttons. I suggest adding an index property to each CustomObject as well as a reference to the collection it was added to. That way, you can simply add the click event into the CustomObject class and have the handler function something like:
private function _click(e:MouseEvent):void
{
_collection.select(index);
}

Apply a Function Dynamically in AS3

I'm trying to set up some default callbacks for listeners dynamically, and I'm not having much success at the moment.
Array:
var URLLoader_SharedCallbacks:Array = new Array();
URLLoader_SharedCallbacks.push(new Array (HTTPStatusEvent, HTTPStatusEvent.HTTP_STATUS, "URLLoader_HTTPStatus"));
URLLoader_SharedCallbacks.push(new Array (IOErrorEvent, IOErrorEvent.IO_ERROR, "URLLoader_IOError"));
URLLoader_SharedCallbacks.push(new Array (Event, Event.OPEN, "URLLoader_Open"));
And then:
function URLLoader_SharedCallbacks_Add(ul:URLLoader):void
{
for each(var arr:Array in this.URLLoader_SharedCallbacks)
{
var fnc:Function = function(evt:arr[0])
{
trace("evt = " + evt)
}
if(!this[ul].hasEventListener(arr[2]))
{
this[ul].addEventListener(fnc);
}
}
}
Suggestions?
even if you need to get anything very specific from this events imho the best choice is to the following:
private function handler(e:Event): void{
switch(e.type){
case IOErrorEvent.IO_ERROR:
//treat it like IOErrorEvent
break;
case Event.CLOSE:
//treat it like Event.CLOSE
break;
case HTTPStatusEvent.HTTP_STATUS:
//treat it like HTTPStatusEvent
break;
}
}
and about dynamical generation, if it's really the only solution:
create 2 arrays - for dispatchers and for listener functions. and one more to hold descriptions of dispatcher-listener pairs. or you may store dispatcher with listener and description in an Object and have an array of such objects, or maybe develop a specific data structure...
anyway:
private var funcArray: Array = new Array();
private var loaderArray: Array = new Array();
private var infoArray: Array = new Array();
private function createListener():Function {
var fn:Function = function(e:Event): void { switch((e as Event).type) { case IOErrorEvent.IO_ERROR: /*treat it like IOErrorEvent*/ break; case Event.CLOSE:/*treat it like Event.CLOSE*/ break; case HTTPStatusEvent.HTTP_STATUS: /*treat it like HTTPStatusEvent*/ break; }};
return fn;
}
private function createURLLoader(url: String, description: String = 'i never care'):void{
var urlo:URLLoader = new URLLoader();
var fun: Function = createListener();
urlo.addEventListener(IOErrorEvent.IO_ERROR, fun);
urlo.addEventListener(Event.CLOSE, fun);
urlo.addEventListener(HTTPStatusEvent.HTTP_STATUS, fun);
var info: Object = { 'url' : url , 'description' : description );
urlo.load(new URLRequest(info['url']))
funcArray.push(fun);
loaderArray.push(urlo);
infoArray.push(info);//mention that arrays have always equal length and dispatcher, listener and descrition are stored under the same index
}
/*when data is loaded/loading timeout is over/loading failed: we need to be careful
killing our anonimous vars: */
private function killEmAll(i:int):void{//i is the index for arrays
(loaderArray[i] as URLLoader).removeEventListener(IOErrorEvent.IO_ERROR, (funcArray[i] as Function));
(loaderArray[i] as URLLoader).removeEventListener(Event.CLOSE, (funcArray[i] as Function));
(loaderArray[i] as URLLoader).removeEventListener(HTTPStatusEvent.HTTP_STATUS, (funcArray[i] as Function));
(loaderArray[i] as URLLoader).close();//just to be sure ;)
loaderArray.splice(i, 1);
funcArray.splice(i, 1);
infoArray.splice(i, 1);
}