how to change private var in imported action script - actionscript-3

Hi guys am trying to change a var in an imported as file. Can anyone help point me out.
This is the original code in externalfile.as
private function SetNewPosition()
{
this.newX = this.GetRandomXPosition();
this.newY = this.GetRandomYPosition();
this.totalDistance = this.GetDistance();
var time:Number = this.totalDistance / this.speed;
speedX = (this.newX - this.x)/time;
speedY = (this.newY - this.y)/time;
}
Am trying to change the newX and newY from the Main.as Do share how i can fix this thanks!

I suppose, newX and newY variables are private in your .as file.
To change a variable by another .as you must follow one of two ways:
First:
Change the modifier of your variable (from private to public)
Second:
Define property get/set on your variable, so your variable remains private and you can manage the result sent by another .as file. For example if your newX can't be negative and in your Main.as you try to put a value less than zero, in your set property you can decide to put its value to zero, or apply an absolute value and so on.

You might want to ask yourself WHY you need Main to have access to the newX and newY variables. If Main is resetting the location of an external.as instance, you could add a 'reset' method to external.as which would keep newX and newY encapsulated. The aim is to try and keep any procedural coding with regard to external.as 'inside' that Class. If actions involving external.as can be run 'in private' inside the Class, that's where the code should be added. But if Main.as absolutely NEEDS access, add setter and getter methods for both newX and newY, eg...
public function set newX(value:Number):void {
this.newX = value;
}
public function get newX():Number {
return this.newX
}

Related

Making a simple tamagoci game getting no compiler errors but receiving no output

Kind of new Actionscript and I'm just trying to make a simple tamagoci game. I've wrote all the code out but and receiving no compiler errors but for some reason I'm also not receiving any output messages for my mouse event listeners. Here is all my code, I really can't find the problem and any help would be greatly appreciated. Thanks.
package{
import flash.display.MovieClip;
import flash.events.MouseEvent;
public class Main extends MovieClip{
public var feedButton:MovieClip;
public var tamagoci:MovieClip;
public var disButton:MovieClip;
public var dietButton:MovieClip;
public function Main() {
this.init();
}
private function init():void {
this.feedButton.addEventListener(MouseEvent.MOUSE_DOWN, onfeedMouseDownHandler);
this.disButton.addEventListener(MouseEvent.MOUSE_DOWN, ondisMouseDownHandler);
this.dietButton.addEventListener(MouseEvent.MOUSE_DOWN, ondietMouseDownHandler);
}
private function onfeedMouseDownHandler(event:MouseEvent)void{
this.tamagoci.scaleX += 0.1;
this.tamagoci.scaleY += 0.1;
}
private function ondisMouseDownHandler(event:MouseEvent)void{
this.tamagoci.gotoAndPlay(5);
}
private function ondietMouseDownHandler(event:MouseEvent)void{
this.tamagoci.scaleX -= 0.1;
this.tamagoci.scaleY -= 0.1;
}
Are you using Flash Professional?
You're declaring your variable types in your class here;
public var feedButton:MovieClip;
public var tamagoci:MovieClip;
public var disButton:MovieClip;
public var dietButton:MovieClip;
But then in your constructor, all you are doing is running init();
public function Main() {
this.init();
}
So, this could one of a few things. The most likely is that you have declared your variables, but you haven't initialised them. You've created the variables to hold your objects, but according to your code, they're empty. More specifically, a variable or class property that doesn't assign an object to a variable of an object type will contain a default value of null.
You could prove this in your code by simply putting a condition inside your init(); method;
if(tamagoci == null){
trace("I haven't been assigned an object of type class yet!")
}
So it could be 1 of these 3 things:
1: If you have written your own classes for these class properties/variables, then you need to instantiate them with the new keyword. The general syntax is;
variable_name = new ClassName(parameter_1, parameter_2);
If you are using classes you have written yourself, you have to create an instance of the object, assign it to a variable, and then add it to the stage using addChild();. For example, lets say you've written your own Tamagoci class;
tamagoci = new Tamagoci();
tamagoci.x = 100; // set the x location
tamagoci.y = 200; // set the y location
addChild(tamagoci);
Notice the use of Tamagoci. This is just an example, but this is the class name, which shouldn't be confused with variable/property name. It could just have easily been;
tamagoci = new MovieClip();
But then, this is just an empty MovieClip. It needs a property to display on the screen. A Shape, A Bitmap, or another container class object like MovieClip or Sprite (container classes allow you to nest display objects inside them). But on a basic level, it must contain a visual component to appear on the stage.
2:
Have you made Main your document class? This is the class which will get automatically called when your Flash movie plays. To set this, click on your stage, and in the properties dialogue box on the right, under PUBLISH, type in the name of your class, which is "Main".
3:
If you have created MovieClips in your library in Flash Professional, then you need to go to your library, right click the MovieClips, and select properties. From there, you need to make sure Export for Actionscript is ticked.
Now, if you click on your MovieClips on the stage, then open the Properties tab in the top right of Flash Professional's default layout, then right at the top should be a text field, and if you hover over it, Instance name will pop up as a tool tip. This is where you name your stage objects. Once that is done, you have access to them in your timeline.
If this is how you've done this, then you don't need to declare the variables in your main class, as they are already declared on your stage by Flash Professional and instantiated automatically.

How to choose which child class to instantiate dynamically

My current project is in as3, but this is something I am curious about for other languages as well.
I'm attempting to use a factory object to create the appropriate object dynamically. My LevelFactory has a static method that returns a new instance of the level number provided to the method. In the code calling that method, I am able to dynamically create the buttons to call the levels like so:
for (var i:int = 1; i < 4; i++) {
var tempbutton:Sprite = createButton("Level " + i, 25, 25 +(60 * i), start(i));
_buttons.push(button);
}
This code just creates a simple button with the given arguments (ButtonText, x, y, function). It's working fine. The buttons are created, and clicking on one of them calls this method with the appropriate argument
private function start(level:int):Function {
return function(e:MouseEvent):void {
disableButtons();
newLevel = LevelFactory.createLevel(level);
addChild(newLevel);
}
}
This is all working fine; I'm just providing it for background context. The question I have is this: Is it possible to dynamically choose the type of object that my static function returns? Currently, I have am doing it as follows
public static function createLevel(level:int):Level {
var result:Level;
switch(level) {
case 1: result = new Level1(); break;
case 2: result = new Level2(); break;
//etc
}
return result;
}
I should note that all of these Level1, Level2, etc. classes extend my base level class. (Yay polymorphism!) What I would like to do is be able to do something along the lines of
public static function createLevel(level:int):Level {
var result:Level;
var levelType:String = "Level" + level;
return new levelType();
}
Obviously it's not going to work with a string like that, but is there any way to accomplish this in as3? What about other languages, such as Java or Python? Can you dynamically choose what type of child class to instantiate?
Update:
import Levels.*;
import flash.events.*;
import flash.utils.*;
public class LevelFactory
{
public static function createLevel(level:int):Level {
var ref:Class = getDefinitionByName('Levels.' + 'Level' + level) as Class;
var result:Level = new ref();
return result;
}
}
Update/Edit: getDefinitionByName seems to be what I'm looking for, but it has a problem. It seems that the compiler will strip unused imports, which means that unless I declare each subclass in the code ahead of time, this method will get a reference error. How can I get around the need to declare each class separately (which defeats the purpose of dynamic instantiation)?
Yes, you sure can, and it's very similar to the string thing that you've provided. The only thing that you are missing is the getDefinitionByName method: http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/utils/package.html#getDefinitionByName()
You can generate whatever class name you want, and what this method does is that it searches for that class in it's namespace, and if it finds it - it returns it as a class:
var ClassReference:Class = getDefinitionByName("flash.display.Sprite") as Class;
var instance:Object = new ClassReference();
This piece of code will instantiate a Sprite. This way you can instantiate your classes without all those switches and cases, especially when you have to make a hundred levels :)
Hope that helps! Cheers!
Edit:
In your case, the code should be:
var ref:Class = getDefinitionByName('com.path.Level' + index) as Class;
var level:Level = new ref(); // it will actually be Level1 Class
Since Andrey didn't quite finish helping me out, I am writing up a more complete answer to the question after much research.
getDefinitionByName definitely has the use I am looking for. However, unlike its use in Java, you HAVE to have a hard reference to the class you want instantiated somewhere in your code. Merely imported the class is not enough; the reason for this is that the compiler will strip the reference from any unused import to save space. So if you import the package of classes you want to choose dynamically but don't have a hard reference to them, the compiler will de-reference them. This will lead to a run-time error when the program cannot find the appropriate reference to your class.
Note that you don't actually have to do anything with the reference. You just have to declare a reference so that it can be found at run-time. So the following code will work to eliminate the switch-case statement and allow me to dynamically declare which class I am using at run-time.
{
import Levels.*;
import flash.events.*;
import flash.utils.*;
/**
*
* Returns the requested level using the createLevel class
* ...
* #author Joshua Zollinger
*/
public class LevelFactory
{
Level1, Level2, Level3, Level4, Level5, Level6, Level7;
public static function createLevel(level:int):Level {
var ref:Class = getDefinitionByName('Levels.Level' + level) as Class;
var result:Level = new ref(); // it will actually be the correct class
return result;
}}}
The obvious downside to this is that you still have to have a hard-coded reference to every class that can be instantiated like this. In this case, if I try to create a Level8 instance, it will through a run-time error because Level8 is not referenced. So every time I create a new level, I still have to go add a reference to it; I can't just use the reference dynamically.
There are supposedly ways around this that I have not tested yet, such as putting the code for the classes in a separate SWF and importing the SWF at run-time or using outside libraries that will have different functionality. If anyone has a solid way to get a truly dynamic reference that doesn't require a hard coded reference anywhere, I would love to hear about it.
Of course, it's still a lot cleaner this way; I don't have a extensive switch case statement to pack all the levels. And it's easier and faster to add a reference to the list than creating a new case in a switch. Plus it is closer to dynamic programming, which is usually a good thing.

How can I make a function to make a child of an object in the library based on the variables supplied?

I'm trying to do a little project for my class and though I know how to do it the long way I'd prefer to do it in a more intuitive way so that I can avoid having to copy and paste a load of essentially the same code. The idea is to have a function which will create an instance of a class object with it's own unique name, set it's position/size/etc, and then add that child to the stage. Looking at this (what I have now) might help out a little bit.
//Set up variables for all deco pieces
var decoGreen:GreenBall;
var decoRed:RedBall;
var decoStar:Star;
var decoFlower:Flower1;
var decoYellow:YellowBall;
var decoBlue:BlueBall;
//Functions to allow easier object placement
function makeDeco(posX:Number, posY:Number, decoName:String, rootClass:Object):void
{
decoName = new (rootClass)();
decoName.x = posX;
decoName.y = posY;
addChild((decoName));
}
makeDeco(90,320,"greenBall",GreenBall)
Now obviously this code doesn't work and it's pretty rough right now but I think it's sufficient to understand what I'm trying to accomplish here. Thanks for any and all who attempt to decipher my mess! :D
You are pretty close from what I can tell and if I understand your question, it would simply be using the getDefinitionByName class
function makeDeco(posX:Number, posY:Number, decoName:String):void
{
var DecoClass:Class = getDefinitionByName(decoName) as Class;
var deco:DisplayObject = new DecoClass();
deco.x = posX;
deco.y = posY;
addChild((deco));
}
makeDeco(90,320,"greenBall")
You don't need to define the variables initially like you did, granted they've all set to "Export as actionscript" in the library. For example calling a string of "greenBall" would mean you have a movie clip in the library with a class name of greenBall

Declaring Stage in external class function and using it in other class?

what I'm trying to achieve is making a "centerItem"-method that centers your object on the stage. I would like to add this method in my Misc class file, and use it everywhere in my application. I already tried it like below but this didn't work:
public static function centerItem(item:*):void
{
item.x = (stage.stageWidth - item.width) >> 1;
item.y = (stage.stageHeight - item.height) >> 1;
}
and calling it like this:
Misc.centerItem(myObjectToPlaceOnStage);
But when I try it out, it just gives me an error. I already looked on the web but I didn't find any constructive solutions. I hope someone might find a solution/hack
If your object is already added on the stage, you can access its stage property :
public static function centerItem(item:DisplayObject):void
{
item.x = (item.stage.stageWidth - item.width) >> 1;
item.y = (item.stage.stageHeight - item.height) >> 1;
}
By the way, I've typed your item parameter to DisplayObject, so you are sure that it has width, height and stage properties.

ActionScript 3 name property is not returning the right name...?

I experienced a problem with the name property in as3, I created this "dot" movieclip and I exported to a class,
then I anonymously created a bunch of dots using a loop. I assigned numbers as name to each dots
private function callDots(num:Number):void
{
for (var i = 0; i < subImagesTotal[num]; i++)
{
var d:Dot = new Dot();
d.x = i*23;
d.y = 0;
d.name = i;
dotContainer.addChild(d]);
}
}
so far so good, I checked that if I trace the name here, I will get the number I want.
However, it's not giving me the numbers if I trace it in other functions.
I added all of my dots to "dotContainer", and if I click on one of the dots, it will call this function
private function callFullSub(e:MouseEvent):void
{
var full_loader:Loader = new Loader();
var temp:XMLList = subImages[sub];
var full_url = temp[e.target.name].#IMG;
full_loader.load(new URLRequest(full_url));
full_loader.contentLoaderInfo.addEventListener(Event.INIT, fullLoaded);
}
e.target.name is suppose to be numbers like 1 or 2, but it's giving me "instance66" "instance70" and I
have no idea why. Because I did the same thing with loaders before and it totally worked.
Any ideas? Thanks.
christine
The e.target returns the inner most object clicked on, this could be a TextField, another MovieClip or posibly a shape (I'm not 100% of the last one) inside the "Dot".
To prevent this you could try to set the mouseChildren property to false on the Dot's when you add them. This should insure that nothing inside the dots can dispatch the click event, and thus the Dot's should do it.
Perhaps you could also in the event handler verify the target type with code like this:
private function callFullSub(e:MouseEvent):void
{
if(!e.target is Dot)
throw new Error("target in callFullSub is not Dot but: " + e.target.toString());
//The rest of you code here
}
The answer is [e.currentTarget.name] I perform this all the time!
Should return "Dot1" "Dot2", etc.
If the value you wish to return is a number or other data type other than a string (name of object) use [e.currentTarget.name.substr(3,1).toString()]
Should return 1, 2, etc.
Navee
I tried to reproduce your problem first with Flex using runtime created movieClips and then with Flash using Dot movieClip symbols exported for ActionScript. Neither application exhibited the problem.
You may already know names like "instance66" "instance70" are default enumerated instance names. So, whatever is dispatching the MouseEvent is NOT the dot instance. Perhaps you are unintentionally assigning callFullSub to the wrong targets, maybe your containers? Try assigning it to dot instance right after you create them, like this:
private function callDots(num:Number):void
{
for (var i = 0; i < subImagesTotal[num]; i++)
{
var d:Dot = new Dot();
d.x = i*23;
d.y = 0;
d.name = i;
d.addEventListener(MouseEvent.CLICK, callFullSub);
dotContainer.addChild(d]);
}
}
Be sure to temporarily comment out your original assignment.
Try this might work,..
d.name = i.toString();
You have not shown enough of your code for me to be able to give you a DEFINATE answer, I will however say this.
//After you create each loader you need to set its mouseEnabled
//property to false if you do not want it to be the target of
//Mouse Events, which may be superseding the actual intended target;
var full_loader:Loader = new Loader();
full_loader.mouseEnabled = false;
//Also you could name the loaders and see if what comes back when you click is the same.
ALSO! Add this to your Mouse Event handler for CLICK or MOUSE_DOWN:
trace(e.target is Loader); //If traces true you have an answer
I believe that the mouse events are being dispatched by the Loaders.
please provide more of your code, the code where the Loader.contentLoaderInfo's COMPLETE handler fires. I assume this is where you adding the loaders to the display list as I cannot see that now.