Im currently learning as3 but I come from several years of as2 experience, so what I was used to do is attach movieclips using string with a numeric variable to get the right identifier like this and maybe I was thinking about using eval here but of course its not available in as3 so here is what I was doing in as2:
currentlevel=1;
myString = "levelMc"+currentlevel;
And then of course use the constructed string in "attachMovie" function to get the right clip attached.
attachMovie(myString,myString+mydepth,mydepth);
But I see in as3 all is about classes and all different so I cant seem to find a way to dynamically get the right class name for the child to be added, is there an actual way to make that possible? because as far as I have gone I see that I should get the class name to make new object and then put that in "addChild" so therefore I cant find a way to pass any kind of dynamically constructed string or element refering my needed clip there, is it still possible?.
Thanks beforehand for any clues =)
EDIT I added the attachmovie call as a clarifying line, I know all you got what I was asking but as I cant find a right approach I prefer to clarify. Additionally I shouldnt have mentioned the "eval" here, sorry, I just can ask my as2 with string usage
EDIT Solved, thanks to you all guys, you saved me, I wish I could give you all kudos because all of your ideas and tips are awesome and really helpful, I marked that answer as correct because it was the one that lead me to getDefinitionByName which is what Im going to use in the end, but as said all tips and ideas to face new as3 world will help me greatly, so as said I wish I could give reputation to you all, thanks a lot =)
You still can set a name for your object, for instance:
var mc : MovieClip;
for (var i : int = 0; i < 5; i++) {
mc = new MovieClip();
mc.name = "myMc"+ i;
addChild(mc);
}
and you can get a specific child using:
this["myMc1"] as MovieClip
or
this["myMc"+ i] as MovieClip;
How about a simple array?
Because if you only need to access a set of levels in a ascending numeric fashion, this approach is easier.
var levels:Array = new Array();
levels[0] = //your level1 movieclip
levels[1] = //your level2 movieclip
...
function jumpToLevel(index:int):void{
//remove added levels beforehand
removeChildren(); //assuming the only children you added to this displaylist
//are levels, otherwise you will need another approach
addChild(levels[index]);
}
In AS2, we would store information about instances in instance name - button_0, button_1, etc. In AS3, you don't need/use instance names for anything other than keeping your code clear to you and to reference stuff you create by hand.
Use arrays to reference your instances. So, if you're making buttons, you create a button and push it into an array of buttons. Then just reference it as aMyButtons[i] instead of mcMyButtons["button_" + i]
Here's example code.
function fCreateButtons(): void {
var i: int = 0;
for (i = 0; i < 5; i++) {
var mcNewButton: McButton = new McButton();
mcNewButton.x = i * 200;
mcNewButton.iButtonNumber = i;
mcNewButton.tMain.text = "About Us";
mcNewButton.bButton.addEventListener(MouseEvent.MOUSE_DOWN, fButtonPress);
mcNewButton.bButton.addEventListener(MouseEvent.MOUSE_OVER, fButtonOver);
mcNewButton.bButton.addEventListener(MouseEvent.MOUSE_OUT, fButtonOut);
aButtons.push(mcNewButton);
}
}
function fButtonPress(e: MouseEvent): void {
var iButtonNumber: int = e.currentTarget.parent.iButtonNumber;
trace("fButtonPress(): iButtonNumber: " + iButtonNumber);
}
This is how you'd add the buttons to a holder clip and remove them.
mcButtonsHolder.addChild(aButtons[i]);
mcButtonsHolder.removeChild(aButtons[i]);
Well as I said above I managed to solve it finally using getDefinitionByName which is the closer I think I can get to "eval", that function managed to bring dinamycally formed class name to be used to call the new clips on run time which is perfect for me, at least make the code cleaner and easier to change if needed. As I said in last edit, thanks a lot to you all who helped, all your tips and ideas will be of great use for me in the as3 time, wish I could give you all reputation, thanks a lot =).
Related
I'm surprised I don't know how to do this, but as it turns out I really don't; simply put, I'm trying to make a side-scrolling shooter game, a basic one and in it, I have 50 stars spawned on-screen through a "for" loop upon the game starting. There is a function which does this and a listener is at the beginning. Problem is, when you lose the game and go back to main menu, 50 more stars would be spawned, which isn't what I want. So, I'm trying to make an "if" statement check at the beginning, so that the game checks whether there is an instance/movie clip of the star object/symbol before determining whether the function that spawns stars should be called out with a listener. So, how do I do this? I looked through some other checks and they didn't help as the codes presented were vastly different there and so I'm just getting errors.
Let me know if a better explanation is needed or if you would like to see some of the code. Note that the game overall already has a lot of code, so just giving all of it would probably not be helpful.
I suggest you rethink your approach. You're focusing on whether stars have been instantiated. That's ok but not the most basic way to think about it.
I would do this instead
private function setup():void{
loadLevel(1);
addListeners();
loadMusic();
// etc...
// call all functions that are needed to just get the app up and running
}
private function loadLevel(lev:int):void{
addStars();
// call all functions that are needed each time a new level is loaded
}
private function restartLevel():void{
// logic for restarting level,
// but this *won't* include adding star
// because they are already added
}
There are other ways to do this but this makes more sense to me than your approach. I always break my game functions into smaller bits of logic so they can be reused more easily. Your main workhorse functions should (IMHO) primarily (if not exclusively) just call other functions. Then those functions do the work. By doing it this way, you can make a function like resetLevel by assembling all the smaller functions that apply, while excluding the part about adding stars.
Here's what I did to solve my problem... Here's what I had before:
function startGame():void
{
starsSpawn();
//other code here
}
This is what I changed it to:
starsSpawn();
function startGame():void
{
//other code here
}
when you said existance, so there is a container, i named this container, (which contain stars , and stars was added to it) as starsRoot, which absolutely is a DisplayObject (right?)
now, to checking whole childrens of a DisplayObject, we have to do this :
for (var i:int=0; i<starsRoot.numChildren; i++) {
var child = starsRoot.getChildAt[i];
}
then, how to check if that child is really star!?
as you said
whether there is an instance/movie clip of the star
so your stars's type is MovieClip, and they don't have any identifier (name), so how to find them and make them clear from other existing movieclips. my suggestion :
define a Linkage name for stars from library, thats a Class name and should be started with a capital letter, for example Stars
now, back to the code, this time we can check if child is an instance of Stars
for (var i:int=0; i<starsRoot.numChildren; i++) {
var child = starsRoot.getChildAt[i];
if (child is Stars) {
// test passed, star exist
break;
}
}
I have an issue with removing old elements from my lists. I tried using the methods clear() and removeAllElements() and removeAll() wherever I could but that does not seem to clear them.
To help you understand the situation a little bit better:
d1 is an ArrayList that contains all available devices in our program.
availList2 and availList3 are using the DefaultListModel.
We wanted to make it so that when the user loads the products from the proper text file, if he did that a second time the products already listed in our gui would be overwritten with the ones in the original text file. However we ended up having duplicates of the products, even though we used the clear() method in both the d1 (ArrayList) and the JList.
Any useful tips or possible causes would be appreciated. Thank you very much in advance.
if(ev.getSource() == load_availables) {
int returnVal = chooser.showOpenDialog(mainApp.this);
if(returnVal == JFileChooser.APPROVE_OPTION) {
d1.returnDevices().removeAll(d1.returnDevices());
availList2.clear();
availList3.clear();
//availList2.removeAllElements();
//availList3.removeAllElements();
File file = chooser.getSelectedFile();
read.ReadDevices(file);
for(int i = 0; i < read.Size(); i++) {
d1.add_AvailableDevices(read.get(i));
}
}
}
If the list is not cleared then I would suggest you don't have the proper reference to the DefaultListModel that is being used by the JList when you invoke the clear() method.
Start by the reading the section from the Swing tutorial on How to Use Lists.
Download the ListDemo code and play with it. Change the "Fire" button to use the clear() method on the DefaultListModel to prove to yourself that is all you need to do.
Once you see the code working then you figure out how your code is different from the ListDemo working version.
Right, I am trying to make a game and I would like a bit of code that whenever I place makes something applies to all objects. For example I have: A background, Lamp, Player and Text. I would like it so I don't have to make the Lamp, Background and Text a symbol but have one bit of code that refers to them whenever I type it, so I don't have to list them all individually.
If you are looking to affect a specific, known set of display objects, you could add them into an array when they get created, and then use that array as your collection of objects to do whatever you need to.
Code here is procedural, not OOP, but should give you the gist. If you paste this into an FLA file and create the three objects (instances names) you'll have a decent sample of what this approach may be able to help you work with.
This can become more advanced, creates asa its own AS3 class, and be made smarted to handle whatever visual display changes that might be needed. But you only need ot make it as complicated as suits your needs.
var myDisplayObjs_arr:Array = [];
function addObj(obj:DisplayObject):void{
myDisplayObjs_arr.push(obj);
}
function affectObjs(config:Object):void{
// config object that includes things like alpha, colorTransform, whatever
for (var i:int = 0; i<myDisplayObjs_arr.length; i++){
var dispObj:DisplayObject = myDisplayObjs_arr[i];
if (config.alpha) {
dispObj.alpha = config.alpha;
}
if (config.scaleX) {
dispObj.scaleX = config.scaleX;
}
}
}
addObj(lamp);
addObj(background);
addObj(header_txt);
// Call affectObjs(), passing it an object of some basic changes
affectObjs({alpha:.5, scaleX:2});
hey im having issues removing my enemy blocks. at the moment if i hit everyone of them everything is fine but when i avoid one i get an error message of
ArgumentError: Error #2025: The supplied DisplayObject must be a child of the caller.
at flash.display::DisplayObjectContainer/removeChild()
at EnergyJump/onTick()
at flash.utils::Timer/flash.utils:Timer::_timerDispatch()
at flash.utils::Timer/flash.utils:Timer::tick()
here is my code i have:
public function onTick( timerEvent:TimerEvent ):void
{
//if ranrom number is than than i
if ( Math.random() < i )
{
//place block on stage at location X=550, Y=330
var randomX:Number = Math.random() * 550;
var newBlock:Blocks = new Blocks( 550, 335 );
army.push( newBlock );
addChild( newBlock );
//increase speed of spawn
i = i + 0.0001;
}
//move blocks in correct direction
for each ( var block:Blocks in army )
{
block.move();
//if block is hit then remove health and remove child object
if ( avatar.hitTestObject( block ) )
{
hp.checkHP(20);
army.splice(army.indexOf(block), 1);
removeChild( block );
}
}
}
can anyone help me, i dont really know what slice is to be honest or how to use it...
You should have a look at the documentation for Array.splice() here.
The first argument needs to be the index (0, 1, 2 etc.) of the item you want to remove, not the item itself. Flash is trying to read block as an integer, but it defaults to 0, so instead of removing the block that has been hit it's just removing the first block in the list. Try this instead:
army.splice(army.indexOf(block), 1);
I assume you have some code which is clearing any remaining blocks in the list at the end of the game, but because the wrong blocks are being removed from the list it's trying to remove some that were actually hit already.
Are you sure there is a corresponding addChild() call for each of those objects that has been made before the call to removeChild()? There's not enough code being shown, at the moment, to be able to really tell what's going on, but also make sure removeChild() isn't being called more than once on the same object without addChild() being called in between each time.
Okay, I had a quick look through your files. It's getting a bit off topic for this question, but I'll list the problems I found. In general though you need to look at the parts Flash is complaining about and make sure you're really working with the right variables (eg. if you write block, try to make sure you know which block Flash is going to look at, and remember that the order matters when you change things.)
It's easy to accidentally remove the wrong items or try to use things that are null, so check each line and think about what each variable actually is at that point (maybe try tracing the variables out too).
In avatarEnterFrame you're checking for blocks that have gone off the side of the screen, but you haven't added a for each loop like in onTick, so when you use block there Flash is looking at your main public var block:Blocks; instead of the blocks in army.
In onPowerTick you need to adjust your splice in the same way as before, so that you remove the powerups object you're checking instead of the item at 0.
In restartGame you're setting gameOverScreen to null just before trying to remove it, so Flash doesn't know what to remove. Make sure you leave setting it to null until you're done with everything else.
I'll post a separate answer for your game over screen problem so that it's in the right place.
I'm trying to recreate the effect seen on this page: http://flupie.net/blog/2010/12/typewriter-effect-with-textanim-as3/ (example #2)
But without all the separate files.
The reason why I dont just use that code, is because A) It uses text that's in a string, and I want to be able to apply the effect to textfields. B) It uses separate .as files, and I want it all to be 1 file (I want to upload this on DeviantArt later, and as far as I know, you can only upload the .swf)
So is it possible to recreate that matrix style typewriter effect, without resorting to separate .as files and apply it to textfields? I'm really more of a designer than a programmer, so this is just a little too much for me.
EDIT: To get some more clarification on what I intend to achieve. I want to build a character sheet for a fictional character (think: name, appearance, background, etc) and since this character is in the future, I want to give it a futuresque feeling. So the end result will contain several separate textfields and possibly some images. All these textfields should "run" at the same time. Perhaps I'll also add some more "pages" but I'm assuming this is done by just adding another frame to the timeline and a button to link to it.
I'm currently trying to decipher the code linked above, since that is precisely what I'm aiming to achieve, font and glow effects included.
I've written a class (just for you! - but it's quite simple and I'm bored...) which you can use to achieve this effect. Obviously, it's in your interest to take a look at this code at some point, but I'll show you how to use it - and it's very simple - without knowing how it works:
In flash, create a new ActionScript file, copy the code below into it and save it as TypeFX.as - in the SAME directory as your .fla project file:
package {
import flash.utils.Timer;
import flash.text.TextField;
import flash.events.TimerEvent;
public class TypeFX {
private var timer:Timer;
private var text:String;
private var pos:int = 0;
private var field:TextField;
public function TypeFX(field:TextField, speed:int = 200, text:String = null) {
// constructor code
this.field = field;
if(text != null)
{
this.text = text;
}
else
{
this.text = field.text;
}
field.text = '';
timer = new Timer(speed, this.text.length);
timer.addEventListener(TimerEvent.TIMER,update);
timer.addEventListener(TimerEvent.TIMER_COMPLETE,kill);
timer.start();
}
private function update(e:TimerEvent):void
{
pos++;
field.text = text.substr(0,pos);
}
private function kill(e:TimerEvent):void
{
timer.removeEventListener(TimerEvent.TIMER,update);
timer.removeEventListener(TimerEvent.TIMER_COMPLETE,kill);
timer.stop();
timer = null;
text = null;
field = null;
}
}
}
Again, you don't need to understand that to use it, but it's quite simple when broken down, you might enjoy looking at how it works.
Now, take a TextField you want to apply a typewriter effect to - make sure it's set as 'Dynamic Text' and give it an instance name. For example's sake, let's call it myField - now, open the Actions panel. You can apply this effect in a couple of ways:
If you want to create a typewriter effect with the text which is already in the field (it'll clear it, then type it out), add the following code to the actions panel:
new TypeFX(myField);
This will type out the text which was present in the field with a 200ms interval between letters - if you want to change this interval, add a second argument:
new TypeFX(myField,500);
This increases the delay to 500ms
You can also send a string to type out, as opposed to using the text already in the field (this is recommended, it'll be easier to read later, trust me!):
new TypeFX(myField, 500, "The text to type into the field");
Just note that if you are using this method (passing a string) you need to specify a time (eg 500 above), you can't leave it blank like you can if you're just using the field text.
Hope this helps, let me know if you get stuck!