Var mistakenly resets itself in AS3 - actionscript-3

I am new to AS3. I have 2 files:
main.as:
package
{
import flash.display.*;
public class Main extends Sprite
{
public function Main()
{
var f0:Flower = new Flower("rose");
var f1:Flower = new Flower("daisy");
}
}
}
Flower.as:
package
{
public class Flower
{
public var namex:String;
public function Flower(name:String)
{
trace("Previous public var name: " + namex);
namex = name;
}
}
}
Basically, I get 2 nulls in my output. The first one I understand why; when I first trigger
var f1:Flower = new Flower("rose");
It calls the flower's function and demands a trace of a var which has not been set yet, so therefore we get a null. After the trace it sets the var with
namex = name;
which is the value string rose. but then, when I trigger the flower daisy, I am supposed(in my opinion) to receive this message: "Previous public var: rose", because when we triggered rose we told him to set public var namex to the value which we first supplied in main(rose).
So why do I get 2 nulls instead of 1 null, shouldn't the other be "Previous public var: rose";
Another thing, can I get a clear explanation about what
var f1:Flower = new Flower("rose");
does exactly? does it create an object? an instance? or is it only supplying a value(rose) to the function in flower.as?

Your code:
var f1:Flower = new Flower("rose");
Creates a new instance of an object of type Flower and assigns it to the variable f1. It passes the string "rose" to the constructor function of the Flower class.
As lansen says, each instance of a Flower will have it's own namex variable with an independent value.
At this point I think it would be more productive if you take a step back and learn some fundamentals of object oriented programming rather than banging your head against something you don't have a basic understanding of. This book is a pretty good place to start: Essential ActionScript 3.0.

Look here for Basic OOP tutorials : http://tv.adobe.com/watch/actionscript-11-with-doug-winnie/objectoriented-programming-episode-45/
Doug Winnie explane it pretty easy and good way ;)

but what does type "Flower" mean? I mean, I know there are types
called "MovieClip" etc... just not sure what it does when you give the
object name a type with the same name
It might have made more sense to you if your code had looked like this..?
import flash.display.*;
import Flower;
But "importing" Flower wasn't necessary here so it still works. Everything exists as code so behind the scenes imagine there is "MovieClip.as" file that Flash uses when you make a new MovieClip type variable. Advanced coders can even override the built-in functions with their own custom-made ones of same name etc..
So typical code is: variable Name : Type = new Type();
the brackets/braces in Type(); tell us its a function, so now that code will run a function with same name as Type, which in your Main.as code means do this.. "my variable f1 is made from Flower.as by the function public function Flower (name:String)". Here you are "initialising" the variable/type so that you can from now on create multiple AND "unique" instances of the same code under different reference names.
See if this example code helps you... (also shows a basic method of how to pass & retrieve information between your two classes
Main.as
package
{
import flash.display.*;
public class Main extends Sprite
{
public var f0 : Flower = new Flower("rose");
public var f1 : Flower = new Flower("daisy");
public function Main()
{
Do_Something1 (); //runs a function called...
}
public function Do_Something1 () : void
{
//trace namex directly from Flower class
trace("new f0 namex: " + f0.namex );
trace("new f1 namex: " + f1.namex );
//now change the contents of "namex" String in Flower class
f0.namex = "violet"; f1.namex = "bluebell";
//run function from each instance of Flower class
f0.check_renamed_Flower();
f1.check_renamed_Flower();
}
} //end class Main
} //end package
Flower.as
package
{
public class Flower
{
public var namex : String;
public function Flower( F_name:String) : void
{
trace("Previous public var name: " + F_name);
namex = F_name;
}
public function check_renamed_Flower() : void
{
trace( "changed var name: " + namex );
}
}
}
Hope it helps.

Related

AS3 - Problems with IExternalizable

So, i've been working with ByteArrays a lot recently and i'm running into some annoying problems that make me want to rip my hair out.
basically, i'm trying to save project data for an application that i'm making to compile characters for a game into one file. the project consists of custom objects, vectors, vectors of vectors, and even vectors of vectors of custom objects! i figured the best way to write all this data properly would be to use the IExternalizable interface with the readExternal and writeExternal commands. so here's what i'm doing.
i write all the project data to an object, then write that object into a ByteArray, and save it to a file:
// probject means project object !
mProbject= { };
// Register vector as class, just to prevent any errors about that just in case
registerClassAlias("vec_core.timeline.KeyFrame", Vector.<KeyFrame> as Class);
// single KeyFrame Object
mProbject.currentFrame = Main.getInstance().animationList.selectedItem.currentKeyFrame;
// a Vector.<Vector.<KeyFrame>>
mProbject.frames = Main.getInstance().animationList.keyFrameVectorVector;
// an unsigned int
mProbject.selectedItemIndex = Main.getInstance().animationList.entries.indexOf(Main.getInstance().animationList.selectedItem);
// Vector.<String>
mProbject.animationNames = Main.getInstance().animationList.animationNames;
// String
mProbject.projectPath = nativePath;
//String
mProbject.projectName = name;
mByteArray = new ByteArray();
mByteArray.writeObject(mProbject);
mByteArray.compress();
return mByteArray;
inside the KeyFrame class though, there is two more vectors of custom objects:
private var mHitboxes:Vector.<Hitbox>;
private var mHitboxSprites:Vector.<HitboxSprite>;
so i set up both of those classes and my KeyFrame class to use IExternalizable:
public class HitboxSprite extends Sprite implements IExternalizable
{
public function readExternal(input:IDataInput):void
{
trueBounds.x = input.readFloat();
trueBounds.y = input.readFloat();
trueBounds.width = input.readFloat();
trueBounds.height = input.readFloat();
mHitbox = input.readObject();
}
public function writeExternal(output:IDataOutput):void
{
output.writeFloat(trueBounds.x);
output.writeFloat(trueBounds.y);
output.writeFloat(trueBounds.width);
output.writeFloat(trueBounds.height);
output.writeObject(mHitbox);
}
}
public class Hitbox implements IExternalizable
{
public function readExternal(input:IDataInput):void
{
mName = input.readUTF();
mType = input.readUnsignedInt();
mEnabled = input.readBoolean();
mKnockback = input.readBoolean();
x = input.readFloat();
y = input.readFloat();
width = input.readFloat();
height = input.readFloat();
addMultipleTags(input.readUTF());
}
public function writeExternal(output:IDataOutput):void
{
output.writeUTF(mName);
output.writeUnsignedInt(mType);
output.writeBoolean(mEnabled);
output.writeBoolean(mKnockback);
output.writeFloat(mX);
output.writeFloat(mY);
output.writeFloat(mWidth);
output.writeFloat(mHeight);
output.writeUTF(getAllTags());
}
}
public class KeyFrame implements IExternalizable
{
public function readExternal(input:IDataInput):void
{
mID = input.readUnsignedInt();
mLabel = input.readUTF();
}
public function writeExternal(output:IDataOutput):void
{
output.writeUnsignedInt(mID);
output.writeUTF(mLabel);
}
}
but when it gets to the writeObject() method of the "root" ByteArray, i get the error:
[Fault] exception, information=ArgumentError: Error #2004: One of the parameters is invalid.
this is probably the single most annoying problem i've ever had. it seems like i've tried everything and nothing is working.
does anyone else have experience with this? am i doing something wrong??
i'd appreciate any help i can get on this. i just wanna continue making my game :<
Like mentioned in the comment section, you were looking for this. What rang the bell for me was the "Sprite" class you extended. That made me suspicious in the matter that you were trying to externalize visualizable content.

as3 #1009 error code provided. "Null Object reference"

hi I'm relatively new to as3 (this year) and I'm getting this error
typer error #1009 cannot access a property or method of a null object
reference. at FoodObject/collisionTest()
i was hoping anyone could help
package {
import flash.events.MouseEvent;
import flash.events.KeyboardEvent;
import flash.events.*
import flash.utils.*
import flash.display.Stage;
public class GameScene1 extends Scene {
//public variables
//character & scenery
public var mainChar: Character;
public var testFood: FoodObject;
//constructor is used to create all necessary objects for this scene and display them
public function GameScene1(gm_: Manager) {
//constructor
super(gm_);
trace("GameScene 1 constructor");
//character
mainChar = new Character;
addChild(mainChar);
mainChar.x = 200;
mainChar.y = 200;
testFood = new FoodObject;
addChild(testFood)
testFood.x = 50
testFood.y = 200
the food object class is here.
package {
import GameScene1
import flash.display.MovieClip;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.events.TimerEvent;
public class FoodObject extends MovieClip {
public var Game1:GameScene1;
public function FoodObject() {
//constructor code
this.addEventListener(Event.ENTER_FRAME, collisionTest)
}
public function collisionTest(e:Event)
{
if (this.hitTestObject(Game1.mainChar))
{
trace("it works")
}
}
}
}
game manager here:
package {
import flash.display.MovieClip;
public class Manager extends MovieClip {
//stores which scene is currently loaded
public var curScene:Scene=null;
public function Manager() {
//constructor
trace("Manager Construct")
GoToScene("menu");
}
public function GoToScene(name:String)
{
if (curScene) //there was a scene already
{
curScene.OnLeaveScene(); //call its OnLeaveScene function to remove all objects
removeChild(curScene);
}
if(name=="menu") curScene = new MenuScene(this);
if(name=="select") curScene = new SelectScene(this);
if(name=="game1") curScene = new GameScene1(this);
if(name=="game2") curScene = new GameScene2(this);
if(name=="game3") curScene = new GameScene3(this);
if(name=="credit") curScene = new CreditScene(this);
addChild(curScene);
}
}
Your problem is that the concerns of your classes are not separate:
Your Scene knows both the Character and the Food object, you instantiate both classes there, nothing wrong with that.
The problem starts when you are trying to do something in the Food object, that requires knowledge of the character. The thing is: the Food object doesn't know anything about the Character.
You can solve this by simply passing the reference of Character to your Food object. In order to do this, modify the constructor like so:
private var character:Character;
public function FoodObject(character:Character) {
//constructor code
this.addEventListener(Event.ENTER_FRAME, collisionTest)
this.character = character;
}
The usage of said constructor in your Scene changes as follows:
testFood = new FoodObject(mainCharacter);
This way, Food knows the character and can do stuff with it, for example do collision tests:
public function collisionTest(e:Event)
{
if (this.hitTestObject(character)) // ==== this line changed
{
trace("it works")
}
}
However, this raises an important issue: Why should Food know the Character at all?
Sure enough, you want to do the collision test, which requires both objects.
But why do you want to do it in the Food object?
Doing the collision check in Food is cumbersome, because you have to pass a reference to Character in order to do it there.
The much preferred way of doing this is to do the collision check where both objects participating in the check are already known.
In your case, this is the Scene.
Think about how easy it is to do the check in Scene:
testFood.hitTestObject(mainCharacter);
It's that simple, because everything you need is already there.
To recap:
The collision check requires knowledge of 2 objects that you want to
check.
In order to do the check in either one, you have to pass a reference
of the other. (Character to Food as seen above or the other way
round)
It is a lot easier to do the check in some place that already knows
both objects, because no reference have to be passed around.
Your original code failed because Game1 in FoodObject is never assigned a value and therefore remains null.
Invoking methods on null causes the error you experienced.
You forgot to take the instance of GameScene1 class using new keyword.
public var Game1:GameScene1;
public function FoodObject() {
//constructor code
var _manager:Manager = new Manager();
Game1 = new GameScene1(_manager)
this.addEventListener(Event.ENTER_FRAME, collisionTest);
}
public function collisionTest(e:Event):void{
....
}

Setting a TextField's text from a document class file

I've searched for a while, and nothing is working for me. I'm trying to make an idle game with my friend (who's doing graphics), and I'm just learning AS3 so I thought it'd be an easy-ish project to start with. I don't know how to make a health textbox that outputs the remaining health left. I searched for at least an hour and nothing I found has worked. Here's all my coding. I have numbers embedded for the textbox. The textbox's instance name is "health" so it's not too hard to find.
package {
import flash.display.MovieClip;
import flash.events.Event;
public class Main extends MovieClip {
public var originalValue:Number = 10;
public var remainingValue:Number = uint(originalValue);
public var clickDamage:Number = 1;
public var health:TextField = String(originalValue);
public var moneyCount:Number=0;
public var mineralValue:Number=5;
public var destroyedCount:Number=0;
mineral.addEventListener(MouseEvent.CLICK, takeDamage);
public function takeDamage(e:Event):void
{
remainingValue = remainingValue - clickDamage;
if (remainingValue <= 0) {
remainingValue = originalValue;
moneyCount += mineralValue;
destroyedCount++;
}
health.text=String(remainingValue);
}
}
}
All I have for symbols so far is my textbox(health) and my button(mineral). Also, what's the difference between an instance name for a textbox symbol, and the instance name for the textbox inside? Sorry if it's a bad question, I'm just really confused and it's ticking me off because I've been trying to work around this problem for a while.
I think your main issue is a lack of understanding of how class files work. I've reworked your class file below and added some comments:
package {
import flash.display.MovieClip;
import flash.events.Event;
public class Main extends MovieClip {
public var originalValue:Number = 10;
public var remainingValue:Number = 10; //no need to convert to uint
public var clickDamage:Number = 1;
public var health:TextField; //you can't assign a string to a text field var //health = String(originalValue);
public var moneyCount:Number=0;
public var mineralValue:Number=5;
public var destroyedCount:Number=0;
//mineral.addEventListener(MouseEvent.CLICK, takeDamage);
//in class files, you can't have lines of code outside of methods/functions create a constructor like below:
//the constructor function must match the name of class, and will run whenever you create an instance of this class
public function Main(){
mineral.addEventListener(MouseEvent.CLICK, takeDamage);
health.text = originalValue; //now assign the text to the text field
//this assumes you have a text field on the main timeline with the instance name of "health"
}
public function takeDamage(e:Event):void
{
remainingValue = remainingValue - clickDamage;
if (remainingValue <= 0) {
remainingValue = originalValue;
moneyCount += mineralValue;
destroyedCount++;
}
health.text= remainingValue.toString();
}
}
}
If (as may be gleamed from comment in your question), you have your health text field encapsulated in a symbol/movie clip, you'll need to access it like so:
myHealthSymbolInstanceName.myHealthTextBoxInstance.text = value;

AS3 - Accessing subclass of subclass

Im making this game, and I really want to access a "subclass of subclass". So I have something like this: MainClass > MonsterLibrary > SampleMonster.
I want to add this Sample Monster from MainClass, but I have to use it through MonsterLibrary, so I dont have to add monster by monster at my MainClass. Every monster respawn would be written in MonsterLibrary class.
I guess it should be something like this.
public class MainGame extends MovieClip {
public function MainGame() {
var mylibrary:MonsterLibrary = new MonsterLibrary();
mylibrary.MonsterLibrary();
Main class.
public class MonsterLibrary extends MovieClip {
#all var here.#
public function MonsterLibrary(){
var monster:SampleMonster = new SampleMonster(330,250);
addChild(monster);
}
MonsterLibrary class.
public class SampleMonster extends MonsterLibrary{
public function SampleMonster(startX:Number, startY:Number) {
//SETTING STARTING LOCATION
x = startX;
y = startY;
SampleMonster class.
I know Im doing it wrong, but I have no idea how to make this work. I keep getting this error ->
1061: Call to a possibly undefined method MonsterLibrary through a reference with static type MonsterLibrary.
You get that error because you're trying to directly call the constructor of MonsterLibrary:
public function MainGame()
{
var mylibrary:MonsterLibrary = new MonsterLibrary();
mylibrary.MonsterLibrary(); // <- wrong
...
}
The MonsterLibrary() function is the constructor of the MonsterLibrary class and it's called automatically when you use the new operator to create a new instance of the class.
If you want your MonsterLibrary class to act as a monster factory (a class that creates monster objects), create a new function that returns a monster:
...
public function CreateMonster ( sType:String ):SampleMonster
{
var oMonster:MovieClip = null; // you can use BaseMonster instead of MovieClip
if ( sType == "SampleMonster" )
{
oMonster = new SampleMonster ( ... );
... // initialize the monster here
}
...
return ( oMonster );
}
...
// get a monster and add it to the stage
var oMonster:MovieClip = oMonsterLibrary.CreateMonster ( "SampleMonster" );
oStage.addChild ( oMonster );
Note that MonsterLibrary doesn't need to extend MovieClip - it really doesn't need to extend any type (other than Object) since (I assume) it's not a visual object. Its purpose is to be a factory, not to be on the screen. oStage in the code above is your top-level display object - it could be the actual stage or a DisplayObject that acts as your stage.
The SampleMonster type shouldn't extend MonsterLibrary - a particular monster is not a library. Your monsters should derive either directly from MovieClip or (better) from a common base monster class; something like:
public class BaseMonster extends MovieClip
{
...
}
Then your SampleMonster can derive from this base monster:
public class SampleMonster extends BaseMonster
{
...
}
I'm confused at what you are trying to accomplish.
Are you looking to have the MonsterLibrary return a monster every time you call a method ?
ie you could have a method in MonsterLibrary class like this :
public function getMonster():SampleMonster
{
var monster:SampleMonster = new SampleMonster(330,250);
return monster;
}
Then your MainGame might look like this :
public class MainGame extends MovieClip {
public function MainGame() {
var mylibrary:MonsterLibrary = new MonsterLibrary();
var newMonster:SampleMonster = mylibrary.getMonster();
addChild(newMonster);
Going further you could have a parameter for the getMonster method to specify a monster type.
for example :
public function getMonster(monsterType:int):Monster
{
// create the appropriate monster and return it
}
Keep in mind that in your code adding the monster to the Display List of the MonsterLibrary, means it will never be seen UNLESS you add MonsterLibrary to the Display List of MainGame
Also you have SampleMonster extending MonsterLibrary, which is not going to work.
SampleMonster should probably extend MovieClip or Sprite or if you intend on having multiple monsters you'd want to have a base Monster Class that any specific monster might extend.

AS3 - Access variable in root from class

How to access a variable in the root timeline from within a class? There is a variable called myblocks in the root timeline I need to read the value from.
This is the related class part:
package myclasses
{
public final class Bcoder extends EventDispatcher
{
private function getBlocks():void
{
for (var i:int = _getNumBlocks; i--; ){
// how to get the myblocks value from here?
}}
This is from the root timeline: (ActionScript stands in a keyframe)
import myclasses.Bcoder;
var myblocks:Number=20
I think you might want to look at this: http://www.kirupa.com/forum/showthread.php?349086-AS3-Question-Accessing-a-main-timeline-variable-from-a-class
Furthermore, I'd like to mention that you should use either timeline coding or use a document class, with preference to the latter because this option is the strength of AS3 and will make your code much more structured.
This is complete nonsense and really bad practice. You should avoid this manner of coding!!!
This is really not OOP and make me think about bad AS1 /2 and 3 combined!!!
However this is possible if you have no class defined in Document properties as main Class.
ex :
in a foler "com", the class ObjectOnStage.as :
package com {
import flash.display.Stage;
import flash.display.Sprite;
import flash.events.Event;
public class ObjectOnStage extends Sprite{
public function ObjectOnStage() {
this.addEventListener(Event.ADDED_TO_STAGE,onAddedToStage,false,0,false);
this.addEventListener(Event.ACTIVATED,onActivate,false,0,false);
}
public function onAddedToStage(e:Event):void{
// will output null for both
trace("\n added " + e.target + "\n");
trace(e.target.parent["nonSense"]);
trace(e.target.parent["nonsense"]);
}
public function onActivate(e:Event):void{
// will output the values.
trace("\n added " + e.target + "\n");
trace(e.target.parent["nonSense"]);
trace(e.target.parent["nonsense"]);
}
}
}
On frame 1 of the Timeline :
import com.ObjectOnStage;
var nonSense:int = 1;
var nonsense:String = "This is a nonsense";
var oos:ObjectOnStage = new ObjectOnStage();
this.addChild(oos);
You'd better change the whole script!
Adobe should remove the possibility to write script on the Timeline since the export settings are set to AS3 and the strict mode should be always set to strict mode ON.
Also private constructors will be welcome in order to permit an usage of
MyClass.getInstance();
This will pemit something like:
package com {
public class MyMainObject {
private static var instanceOfMainObject;
private function MyMainObject(args:Vector.<String>){
// or MyMainObject(...args)
trace("new Instance of MyMainObject created with " + args.toString());
}
public static function main(args:Vector.<String>):void{
instanceOfMainObject = MyMainObject.getInstance(args);
trace("arguments.length = " + args.length);
for(var i:int = 0 ; i < args.length ; i++){
trace( i + " = " + args[i]);
}
}
public static function getInstance(args:Vector.<String>):MyMainObject{
var instance:MyMainObject = new MyMainObject(args);
return instance;
}
}
}
Now, this code throws an Error:
1153: A constructor can only be declared public.
Perhaps this will be the case in AS4 ???
If I understand it trough your comment you must pass the DisplayObjectContainer where your variables are declared to the class as argument.
Example :
in MyClass.as
package com {
import flash.display.DisplayObjectContainer;
import flash.events.EventDispatcher;
public class MyClass extends EventDispatcher{
public function MyClass(doc:DisplayObjectContainer) {
trace(doc["nonSense"]);
trace(doc["nonsense"]);
// but this is again not OOP even if you use the "class" KEYWORD.
}
}
}
on the timeline :
var nonSense:int = 1;
var nonsense:String = "This is a nonsense";
var mclss:MyClass = new MyClass(this);
Concerning EventDispatcher you can also read my answer about EventDispatcher here