AS3 - Trying to declare the value of a Movie Clip - actionscript-3

Okay, I have the following code in my Bullet.as file:
public var impact:MovieClip;
public function Bullet():void
{
addEventListener(Event.ADDED_TO_STAGE, whenAdded);
}
function whenAdded(e:Event)
{
if(this is zArrow){
power = -1;
speed = 15;
impact = arrowImpact;
trace(impact);
}
if(this is Dice){
power = -Math.round(Math.random()*5 + 1);
speed = 10;
impact = diceImpact
}
}
See, I am trying to set the value of "public var impact:MovieClip" as the movie clip "arrowImpact" or "diceImpact". What I want is whenever a bullet collides with an enemy, it leaves an impact image behind and I'm trying to change what impact is shown depending on what bullet is colliding.
I am able to change all of the other variables like power and speed using this setup, but I can't declare which impact movie clip the "impact" movie clip variable is.

From the way I understand your question now, you want to pull these specific movie clips from the Library. If I am not mistaken. To do this, you need to pair each of the movie clips in the library to an AS class that extends MovieClip.
Make sure you check "Export for Actionscript" and create the class you want for each. Then, in your code for the Bullet, you can create a new instance of them. So have it say:
impact = new ArrowImpact)();
or DiceImpact depending on your classes.
Hope this is along the lines of what you wanted.
In order to use these, I would recommend creating a getImpact method along the lines of:
public function getImpactMC():MovieClip
{
return impact;
}
Then all you need to do in your main Document is addChild the proper impact from this method. However, be aware that you need to adjust the x and y values of the impactMC before adding it as a child on the stage to make sure that it displays in the proper position.
Glad this helps!

Related

AS3/ AIR Alternative to PrevFrame() (too slow if big movieclip)

I'm having a problem with prevFrame(). In my previous projects, I never had a trouble with it (usage is pretty straightforward), but this one... I don't understand. Everything does what it needs to do, but when I try to go to the prevFrame of my "main movieclip", it takes ages.
Some context: I'm making a dictionary for an ancient language (non-latin alphabet). There are 6.000 glyphs so I had to find a way to make such a complex "keyboard".
var gArray: Array = [gEmpty, clavierUI.g1, clavierUI.g2, clavierUI.g3, (...)
clavierUI.g50
]; //array contaning the buttons for the keyboard (50 instances of the same
//movieclip. This movieclip is made of 6.000 frames, each containing a
//glyph), the fnClavier function makes each of the fifty instances go to its
//respective frame)
var myXML2: XML = new XML();
var XML_URL2: String = "assets/glyphs.xml";
var myXMLURL2: URLRequest = new URLRequest(XML_URL2);
var myLoader2: URLLoader = new URLLoader(myXMLURL2);
myLoader2.addEventListener("complete", xmlLoaded2);
//import the codename for each glyph
function xmlLoaded2(event: Event): void {
myXML2 = XML(myLoader2.data);
}
var xml2: XMLList = myXML2.glyph.code;
function fnClavier(e: Event): void { //transforms the keyboard
for each(var glyph: MovieClip in gArray) {
glyph.gotoAndStop(gArray.indexOf(glyph) + (50 * (clavierUI.currentFrame - 1)));
//the seconde half (50 * (...) -1))) can be explained like that :
//50 = 50 keys by keyboard "page".
// clavier.currentFrame - 1 = modifier, tells which set of the 6000 glyphs
//needs to appear (and later, correspond with the codename from xml)
}
}
clavierUI.nextPage.addEventListener(MouseEvent.CLICK, fnNextPage);
function fnNextPage(e: Event): void {
clavierUI.nextFrame(); //no problem here, goes fast.
fnClavier(null);
}
clavierUI.prevPage.addEventListener(MouseEvent.CLICK, fnPrevPage);
function fnPrevPage(e: Event): void {
clavierUI.prevFrame(); //takes about 20secondes to go back.
fnClavier(null);
}
My code is probably far from being perfect (i'm still learning), but I don't know why it wouldn't work. Jumping around the frames and going to the next works perfectly, so anyone know why going back one frame takes forever?
Thank you.
You'd better use containers instead of frames. Frames get constructed and deconstructed each time you move between keyframes, while you con construct all the containers once and then display them as needed, one container at a time. I expect that Flash has optimization somewhere that constructs the next frame prior to it being shown via nextFrame() while an abrupt calling of prevFrame() forces Flash to construct it at once, and if it's very complex, it can take a lot of time.
You have 6000 glyphs? That's a lot, but not too much. You can create a set of containers, each holding 120 glyphs, for example. To do that, you create an array of Sprites, each having a grid of glyphs 12x10, there will be 50 of these. Then, when you need another page, display another sprite from the array. Also, if your glyph is a static vector object, you should convert it to vector graphics, and add as library item (Shape descendant, these eat less memory). If it's raster, use Bitmap and underlying BitmapData classes to use them.

Spawning and destroying things in AS3

Okay, so I am making a small game where the user picks randomly spawned flowers. When a flower is picked, it disappears and the user gets points.
Here is some of my code:
import flash.events.MouseEvent;
function makeFlower() {
var flower:Flower = new Flower();
addChild(flower);
flower.x = Math.random() * 500;
flower.y = Math.random() * 400;
}
function removeFlower(event:MouseEvent):void {
flower.pick();
}
setInterval(makeFlower, 2500);
addEventListener(MouseEvent.CLICK, removeFlower);
So in the above code, flower.pick() doesn't work because it's out of scope (how would I get it in-scope, by the way?)... that is one problem. But this problem got me questioning where the creation of the flower should happen. Would it be better to put addChild() in my constructor method?
And then the destruction part... the event listener which detects the flower being clicked... should this be separate (like how I have it) or should it be put into the Flower class? I am new to ActionScript and would like to know where things should be put.
Thanks!
try:
import flash.events.MouseEvent;
var flower:Flower;
function makeFlower() {
flower = new Flower();
addChild(flower);
flower.x = Math.random() * 500;
flower.y = Math.random() * 400;
flower.addEventListener(MouseEvent.CLICK, removeFlower);
}
function removeFlower(event:MouseEvent):void {
event.target.pick();
//removeChild(event.target); // active this to remove the clicked flower
}
setInterval(makeFlower, 2500);
Where you should handle things depends on quite a few factors, number one on my list would be if you're using the Flex framework or not, number two would be what is best for a given application. For your case it appears you're just using Flash IDE.
You'll want to have a collection of the flower objects your adding to the display tree. Then on click you'll want to use the target of the click to know which "flower" they picked, instead of arbitrarily removing some flower.
The other good thing about having a collection of the flowers is that you can actually just toggle the visibility (this also toggles the ability for a touch/click to interact with an object). Then you can have the Flower objects all created at once or at least re-used instead of having to be garbage collected and making a ton more objects (as pointed out by Daniel below the term is object pooling).
import flash.events.MouseEvent;
var allFlowers:Array = [];
var oldFlowers:Array = [];
function makeFlower() {
var flower:Flower;
if(oldFlowers.length>0) //if there's stale ones, already created but since picked
{
flower = oldFlowers.pop();//grab the last one from the list
flower.visible=true;//show it, update to position below should happen fast enough so you won't see it move
}
else
flower = new Flower();
allFlowers.push(flower);
addChild(flower);
flower.addEventListener(MouseEvent.CLICK, removeFlower); //Adding the listener directly to the Flower object, assuming it's a Sprite/MovieClip/InteractiveObject of some sort
flower.x = Math.random() * 500;
flower.y = Math.random() * 400;
}
function removeFlower(event:MouseEvent):void {
var clickedFlower:Flower = (event.target as Flower); //this is a local reference
clickedFlower.pick(); //assuming this toggles the visibility
oldFlowers.push(allFlowers.splice(clickedFlower,1)); //removing it from the "active array" putting it in the "stale array"
}
setInterval(makeFlower, 2500);
Ideally this would all be wrapped up in a class, really scoping variables just makes way more sense to me in the context of a class than just dangling in some block of code somewhere.
Since in your original code you declared that flower was a var and gave it the type of object stored at that var (Flower), it's scope is limited to the opening and closing curly braces for that function. In the case of the variables I defined they should be available so long as the object that contains the code is available.
There are three primary "scope modifiers" you can use when declaring variables or functions in a class in AS3 (namely public, protected, or private). Using public means the property/method (member) is accessible within the class definition (generally the file, something.as) as well as by anything else, if you make a variable public it can be modified by anything that uses the code, this can lead to un-predictable behavior of your application if change from the outside is unintended. Using protected means anything that inherits from or extends a class can access/use the protected member, but nothing that just has an instance of the object can access these members (hence the term access modifier). The third level is private which means only code within that class (across all methods) can access the member but no inheriting/sub-classes of the class can access the member. This is essentially an implementation of the concept generally termed encapsulation in computer science. There's a lot more detail, but really it's already getting too long for a decent SO post.

How can I give flash stage instances unique properties in Flash Professional to pass to AS3 script?

I've started building a rough game engine framework in Flash Professional and I'm curious how I can create objects in the Flash library that I'm able to drag onto the stage and assign properties that are accessible from AS3.
Example:
I want to create a switch object (e.g. a light switch), so that when the player interactes with it, it triggers something specific in code such as a light in the room turns on.
I understand that Flash has built in UI components that you can define properties within the Flash Professional environment (see image below), and I'm wondering if there's a way to create my own custom style components so that I can essentially have my level file open in flash (.fla) and then drag a switch component from my library, and type in some information such as what light it is controlling, and any other information I want.
(above is an example of the type of parameter control I'm looking for)
I've read a bit about extending the flash UIComponent class but I feel that that's not the right approach because it's overkill for what I want. All I want is to pass some basic parameters from a library stage instance into AS3. I do not want to pass data via the instance name because this seems very messy if I want to have more complex interaction.
Thanks!
I would create a "switch" movie clip and export it to actionscrip, same with a "light" movie clip. The in the main class .as file I would inset them into the stage, using addChild (clips) and then add a click listener to the "switch" movie clip to control the "light".
This can be easily done.
Component(s) are wrong approach in my opinion.
Firstly you would want to setup Actionscript linkage / label your Library item.
In Library Panel.
- Right Click on "yourMC" >> click "Properties".
- In Properties dialog Tick "Export for Action Script"
- Then Name your Class eg "yourMC_Class"
now MC is ready to be referenced in your code.
next you would want to Dynamically add your "yourMC" from library to stage.
which can be done like such.
// first reference library item
var yourMC_ref:yourMC_Class = new yourMC_Class();
// Then load dynamic mc item into var
var your_MC_OBJ = yourMC_ref;
// then add your MC to stage.
this.addChild(your_MC_OBJ);
your_MC_OBJ.x = 200;
your_MC_OBJ.y = 100;
in a nutshell that's how I add library items to stage.
Obviously thats the basic function / code.
In a project I would have all code in an external class, in which case you would just set vars as public vars
public var yourMC_ref:yourMC_Class = new yourMC_Class();
public var your_MC_OBJ = yourMC_ref;
and the last 3 lines of code into a public function
public function ADD_First_MC()
{
this.addChild(your_MC_OBJ);
your_MC_OBJ.x = 200;
your_MC_OBJ.y = 100;
}
Now 'your_MC_OBJ' can be used in more complex ways.
eg. to create a light switch there are many options depending on how you need to approch functionality.
eg. Apply a different MC library item to "your_MC_OBJ"
play specific frame within MCs.
However If it was me I would just use mouse function to switch light on or off using addChild removeChild.
eg.
public var LightON = 0;
public var yourMC_ref:yourMC_Class = new yourMC_Class();
public var your_MC_OBJ = yourMC_ref;
then create a public function that handles on / off events
public function LightON_OFF()
{
if(LightON == 1)
{
this.addChild(your_MC_OBJ);
your_MC_OBJ.x = 200;
your_MC_OBJ.y = 100;
}
if(LightON == 0)
{
this.removeChild(your_MC_OBJ);
}
}
Hope this helps.
So, for what you want, while it may not be the best way to do what you want, I understand it's your experience you are constructing.
Use components, yes...in the following way (the most simple one):
Create a Movie Clip
Right-click it in library
Click on "Component Definitions"
Add a property, set a name, a variable name (var test, for this matter) and a default value
Click OK
Open your movie clip
Open code for the first frame and declare the variable without an initial value (var test:String;)
Trace it's value ( trace( test ); )
Go back to the stage root
Drag and drop the item from library to stage
Test it (Cmd/Ctrl + Enter) (maybe it will print null, dunno why, it ignores the default value sometimes)
Select your component on stage
Open the properties panel (Windows > Properties)
Go to Component Parameters on this panel and change the property value
You should see the value traced on console
And, I think, like this you can use properties from components for what you want, like using a String and getting the controlled mc by its name.
Good luck
I think what people are trying to say is that you can have the whole thing is data driven, and so you can combine the IDE with the data to come up with your final game.
But consider this ... it might be what you want.
If you have, for instance, a BaseSwitch Class:
public Class BaseSwitch extends MovieClip {
private var _lightName:String;
private var _light:Light;
public function get lightName():String {
return lightName;
}
public function set lightName(value:String):void {
if (value != _lightName) {
_lightnName = value;
//Note I don't advocate having children reach into their parents like this,
//but you sound like you don't want the parent involved in the process, so
//this is one way you could do it.
if (parent.hasOwnProperty(lightName) && parent[lightName] is Light) {
_light = parent[lightName];
} else {
trace('Could not find light', _lightName);
}
}
}
//other code to listen for gestures and operate the light
}
Now, when you want a switch to operate a specific light name, create a library instance and set its base class to BaseSwitch. When you close the dialog where you set the base Class, you'll notice that it gives you a dialogue that it couldn't find the Class in the Class path and one will be generated. You're going to replace it with a Class that sets the lightName. Create a new AS3 Class in the root directory with the same name as your library instance. It should look something like this:
public class SpecificSwitch {
public function SpecificSwitch() {
super();
lightName = 'theSwitch';
}
}
Other possible choices involve having the parent Class match up instances of switch with instances of light based on name, so if it finds a light1 and a light1Switch, it either gives a reference to the light to the switch or it simply sets up a mapping in its own event listening system.

I can't seem to access automatically named objects (instance##) placed on the stage in AS3, am I missing something?

I have a movieclip in the library that is added to the stage dynamically in the document class's actionscript. This movieclip contains many many child images that were imported directly from photoshop at their original positions (which must be preserved).
I do not want to manually name every single image instance, as there are dozens upon dozens.
I have already gone through and manually converted the images to symbols, as apparently flash won't recognize the "bitmap" objects as children of a parent movieclip in AS3 (numChildren doesn't see the bitmaps, but it sees the symbols).
I have an array filled with references to the dozens of children, and I loop through it, checking if each one is under the mouse when clicked. However, somehow, it is not detecting when I click over the items unless I manually name the child symbols (I tested by manually naming a few of them -- those ones became click-sensitive.)
I have already done trace() debugging all throughout the code, verifying that my array is full of data, that the data is, in fact, the names of the instances (automatically named, IE instance45, instance46, instance47, etc.), verifying that the function is running on click, verifying that the code works properly if I manually name the symbols.
Can any one see what's going wrong, or what aspect of flash I am failing to understand?
Here is the code:
//check each animal to see if it was clicked on
private function check_animal_hits():void
{
var i:int = 0;
var animal:Object = this.animal_container;
for (i=0; i<animal.mussels.length; i++)
{
if (this.instance_under_cursor(animal.mussels[i].name))
{
var animal_data = new Object();
animal_data.animal = "mussel";
this.send_data(animal_data);
}
}
}
Here is the code for the instance_under_cursor() method:
// Used for finding out if a certain instance is underneath the cursor the instance name is a string
private function instance_under_cursor(instance_name)
{
var i:Number;
var pt:Point = new Point(mouseX,mouseY);
var objects:Array = stage.getObjectsUnderPoint(pt);
var buttons:Array = new Array ;
var o:DisplayObject;
var myMovieClip:MovieClip;
// add items under mouseclick to an array
for (i = 0; i < objects.length; i++)
{
o = objects[i];
while (! o.parent is MovieClip)
{
o = o.parent;
}
myMovieClip = o.parent as MovieClip;
buttons.push(myMovieClip.name);
}
if (buttons.indexOf(instance_name) >= 0)
{
return true;
}
return false;
}
Update:
I believe I have narrowed it down to a problem with getObjectsUnderPoint() not detecting the objects unless they are named manually.
That is the most bizarre way to find objects under mouse pointer... There is a built-in function that does exactly that. But, that aside, you shouldn't probably rely on instance names as they are irrelevant / can be changed / kept solely for historical reasons. The code that makes use of this property is a subject to refactoring.
However, what you have observed might be this: when you put images on the scene in Flash CS, Flash will try to optimize it by reducing them all to a shape with a bitmap fill. Once you convert them to symbols, it won't be able to do it (as it assumes you want to use them later), but it will create Bitmpas instead - Bitmap is not an interactive object - i.e. it doesn't register mouse events - no point in adding it into what's returned from getObjectsUnderPoint(). Obviously, what you want to do, is to make them something interactive - like Sprite for example. Thus, your testing for parent being a MovieClip misses the point - as the parent needs not be MovieClip (could be Sprite or SimpleButton or Loader).
But, if you could explain what did you need the instance_under_cursor function for, there may be a better way to do what it was meant to do.

ActionScript 3: Bullet Ricocheting

I've been having a problem with my Actionscript code. I am fairly new to Flash and AS3, so I apologize if my code seems crude or rudimentary, but I'm doing this as best as I can.
Well, in this project I'm trying to get a bullet to ricochet off a wall once. If it hits a wall again after ricocheting, the bullet will disappear.
I've created a for loop which moves the bullets, in an array. At the same time, I try to keep track of each bullet's individual number of ricochets. This works fine when I shoot a first bullet - it will ricochet and then disappear after hitting another wall. However, every bullet I fire after that disappears on the first wall it hits, before it has ricocheted. I've tried to get this to work but I just can't seem to do it.
I would be grateful if somebody could show me the problem, or suggest a change to my code.
Here is a link to my code as it is now.
Thanks, to anybody who helps.
Here are some suggestions I have:
1: Create a Bullet class that tracks its own collisions against walls. I'd also move the clearBullet() method into the bullet class itself.
public class Bullet extends Sprite
{
public var collisions:int = 0;
public var xv:Number = 0;
public var yv:Number = 0;
public function clear():void
{
if(parent)
parent.removeChild(this);
}
}
2: Update your loop to deal with this new info.
for each(var i:Bullet in bulletholder)
{
// Move bullet.
// Check for collision.
// When there is a collision, do this:
i.collisions ++;
if(i.collisions >= 2)
{
var n:int = bulletholder.indexOf(i);
bulletholder.splice(n, 1);
i.clear();
}
else
{
// Deal with changing bullet position.
}
}
I see at least a couple of problems with your code:
Your ricochetcount is clearly out of sync. i.e. you need to delete an element from that array as well.
When you delete an element from the bulletholder array (via clearBullet), you're still incrementing i, which means you end up inadvertently skipping an element.
Also I'm not sure why you need clearBullet(). You already have the index i as well as a reference to the bullet object right there in the main loop.