AS3 - Access variable in root from class - actionscript-3

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

Related

An if statement isn't checking if a variable has increased in amount or not

I am programming in AS3 on flash develop. I am using a program called flashpunk that adds in multiple presets for classes that i can use to make it easier to program. I have an if statement that is supposed to add a new graphic when a variable equals 1. If the user presses one on their keyboard then that variable does increase by 1. But when the variable increases by 1 and the if statement is supposed to check if it is one it doesn't add a new graphic like it's supposed too. I do have the if statement and the variable in different classes and i am not sure if i can do that, here is the code. The if statement that doesn't work is the one that is supposed to add a new background1.
Chapter
package
{
import net.flashpunk.Entity;
import net.flashpunk.World;
import net.flashpunk.utils.Input;
import net.flashpunk.utils.Key;
public class Chapter extends World
{
public var mainmenu:MainMenu;
public var background1:Background1;
public function Chapter()
{
mainmenu = new MainMenu();
add(mainmenu);
background1 = new Background1();
if(mainmenu.YesNo == 1)
{
add(background1);
}
}
}
}
MainMenu
package
{
import flash.events.TimerEvent;
import flash.utils.Timer;
import net.flashpunk.Entity;
import net.flashpunk.graphics.Image;
import net.flashpunk.utils.Input;
import net.flashpunk.utils.Key;
import net.flashpunk.FP;
public class MainMenu extends Entity
{
[Embed(source = "net/MainScreen.png")]
private const SPRITE1:Class;
public var YesNo:int = 0
private var sprite1:Image = new Image(SPRITE1);
public function MainMenu()
{
graphic = sprite1;
sprite1.centerOrigin();
x = 200
y = 150
layer = 150
}
override public function update():void
{
if (Input.pressed(Key.DIGIT_1))
{
YesNo = YesNo + 1;
}
trace(YesNo);
}
}
}
The problem is that your code is in a World class constructor. Flashpunk's idea of game objects is that Entities are added to Worlds. Once added, World runs update() method every frame in which it also runs every Entity's update() as well. Yours if statement in a constructor will always yield false as update wasn't yet executed.
If I understand correctly you want to add background entity after user will press 1. You can do it like this:
// in MainMenu class
override public function update():void
{
if (Input.pressed(Key.DIGIT_1))
{
world.add(new Background1());
}
}
If you want to hold reference to this entity you could:
override public function update():void
{
if (Input.pressed(Key.DIGIT_1))
{
Chapter(world).background1 = new Background1(); // note the casting of World to Chapter
world.add(Chapter(world).background1);
}
}

Access of undefined property issues in AS3

I am having a bit of trouble with some AS3. First time using this language and have more experience with web development then OOP so am getting a bit confused.
I am trying to make it so that when someone clicks a 'powerbutton' which is a "movieclip" symbol within flash then another symbol should then become visible. This is all being done within the Kitchen class.
The code for the main class is which i got from a youtube tutorial video i followed;
package {
import flash.display.MovieClip;
import flash.events.MouseEvent;
import flash.geom.Point;
import flash.events.Event;
import Kitchen
public class DragFood extends MovieClip
{
protected var originalPosition:Point;
var myKitchen:Kitchen
public function DragFood() {
myKitchen = new Kitchen;
originalPosition = new Point (x, y);
buttonMode = true;
addEventListener (MouseEvent.MOUSE_DOWN, down);
}
protected function down (event:MouseEvent):void
{
parent.addChild(this);
startDrag();
stage.addEventListener (MouseEvent.MOUSE_UP, stageUp);
}
protected function stageUp (event:MouseEvent):void
{
stage.removeEventListener (MouseEvent.MOUSE_UP, stageUp);
stopDrag();
if (dropTarget)
{
if(dropTarget.parent.name == "bowl")
{
trace("The " + this.name + " is in the bowl");
this.visible = false;
} else {
returnToOriginalPosition();
}
} else {
returnToOriginalPosition();
}
}
protected function returnToOriginalPosition():void
{
x = originalPosition.x;
y = originalPosition.y;
}
}
}
Within it i call the other class;
import Kitchen
public class DragFood extends MovieClip
{
protected var originalPosition:Point;
var myKitchen:Kitchen
The code for the kitchen class is;
package {
import flash.display.MovieClip;
import flash.events.MouseEvent;
import flash.events.Event;
public class Kitchen extends MovieClip
{
// This is a function. This particular function has the same name as our class and therefore will be executed first
public function Kitchen()
{
// This is a "call" to another function that is defined later in the program.
init();
trace("Hello world");
}
public function init():void
{
// If we want an object (on the screen or otherwise) to be notified about an event we must add a listener for that event to that object.
// We also need to specify what happens everytime the event we are listening for happens.
PowerButton.addEventListener(MouseEvent.CLICK, handleButtonClicks);
}
//This function is called when the oven on button recieves a click.
public function handleButtonClicks(event:MouseEvent):void
{
OvenOn.visible = true;
trace("the oven is being switched on");
}
}
}
The issue i keep getting is that OvenOn and PowerButton are giving me a undefined access issue and im not sure how to fix it. I have found posts on similar subjects like - Access of Undefined property? Actionscript 3
but im not quite sure how to apply it to my issue if anyone could offer any help that would be great.
When you're programming on the timeline, code is referencing the local namespace, and objects you make there (movieclips, textfields, etc.) are automatically instantiated in that namespace so that you can simply call OvenOn.visible = true. However, for each class, their local namespace is whatever is inside the class, so unless you actually created a property on your class called OvenOn, it will most definitely give you Access of Undefined Property errors.
Think of each class as its own island. For them to touch eachother, they need some sort of connection. That connection can be made once the parent instantiates the class in its own namespace. For example...
var foo:String = "Hello!";
var bar:MyClass = new MyClass();
// At this point, whatever code runs inside of MyClass has no concept of foo, or how to access it.
addChild(bar);
// Now that we've added it to the stage, the bar has some properties that have automatically been populated such as "root", "parent", or "stage".
foo.someProperty = "World";
// Since this namespace has a variable pointing to the instance, we can change properties on that class.
Now that we've instantiated MyClass on the stage, we can reference parent properties the class didn't know about. Mind you, this is not necessarily best practice.
package
public class MyClass extends MovieClip {
var someProperty:String = "cheese";
public function MyClass() {
trace(parent.foo) // this will fail
addEventListener(Event.ADDED_TO_STAGE, test);
}
public function test(e:Event):void {
trace(this["parent"].foo); // this will succeed
}
}
}
If you absolutely must change something that is not part of your Kitchen class, pass either the parent of OvenOn or that object specifically as a property of Kitchen. You could do this a couple ways.
with the Constructor...
var something:*;
public function MyClass(someObject:*) {
something = someObject;
}
public function test():void {
something.visible = false;
}
...or by Assigning the Property...
var bar:MyClass = new MyClass();
bar.something = OvenOn;
bar.test(); // will turn off the OvenOn now that 'something' is pointing to it.

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 - Error 1119 - Does not detect my static class altogether

Context: I began learning AS3 a week ago. All my files are in the same folder, and the path is set to . (by default anyway), so all classes should logically detect each other. But as it turns out, I have a class with a lot of public static var, and every time I call these in my other class, I get Error 1119
Access of possibly undefined property isKeyJump through a reference with static type Function.
The class with static variables is called Cont for 'Control'; it's basically meant to check which keys are pressed, just pressed, or pressed twice rapidly. I made the class to organize the code, essentially.
I declare all my variables like this:
public static var isKeyRight:Boolean = false;
And if that wasn't sufficiently explicit, I even wrote this in the constructor (I was tired):
public function Cont()
{
Cont.isKeyRight = false;
... }
But that didn't solve the issue at all. It appears the problem is independent from the class itself; it's just that my other class does not detect Cont.
I tried import Cont; but that also didn't change a thing. My 44 lines of Error 1119 look like this:
if (standing && Cont.isKeyJump) vacc = _jumpAcc;
I even made sure to instantiate the instance of Cont before that of my other class, to make sure that the definitions were at least there. But that would probably make an error after compilation if that was the issue, not during.
The bulk:
Other Class: (The one with 44 errors)
package {
import flash.display.MovieClip;
import flash.events.Event;
public class PersonnagePrincipal extends Physical {
//INITIALISATION
...
//CONSTRUCTOR
public function PersonnagePrincipal(life:Number = 100, focus:Number = 100, lifeMax:Number = 100, focusMax:Number = 100)
{
super();
...
}
// GET & SET
public function set life(life:Number):void { _life = (life > lifeMax) ? lifeMax : life; }
...
// UPDATE
override public function update(event:Event)
{
move_physical();
if (standing && Cont.isKeyJump) vacc = _jumpAcc;
...
And Cont:
package {
import flash.events.Event;
import flash.events.KeyboardEvent;
import flash.ui.Keyboard;
import flash.display.MovieClip;
import flash.utils.*;
public class Cont extends MovieClip
{
// Key codes
public static var isKeyRight:Boolean;
public static var isKeyJump:Boolean;
...
//CONSTRUCTOR
public function Cont()
{
Cont.isKeyRight = false;
Cont.isKeyJump = false;
...
if (stage) { init(); }
else { this.addEventListener(Event.ADDED_TO_STAGE, init); }
}
//POST-CONSTRUCTOR
private function init(e:Event=null)
{
this.removeEventListener(Event.ADDED_TO_STAGE, init);
...
}
EDIT: Well, taking all the code from Cont and into PersonnagePrincipal does solve the synthax errors (given that I get rid of the Cont.) ... But now my code is a lot less sexy and flexible.
EDIT 2: I made the class PersonnagePrincipal empty, and it worked. Stranger still, when I put the line public var control:Cont = new Control in Main, it works, while it generates a compile time error in PersonnagePrincipal. What?

gotoAndStop(); will not work right

I wrote this code for a game im making, Im just learning, There are no compiler errors but when i run the code it fails with no errors. I have a line where i would like to goto a specified frame so the code is Button_Object.gotoAndStop(Local_Frame) but it looks as if the program just skips over it. I have tried to put _root.gotoAndstop(Local_Frame) and stage.gotoAndStop(Local_Frame) but these both give compiler errors the error it gives is
C:\Users\Nathan\Desktop\Matching Game\ClickSolver.as,
Line 34 1120: Access of undefined property _root.
I do see the trace statements. As a side note im trying to access the the main time line, not the objects timeline.
here's the code
package {
import flash.display.MovieClip;
import flash.events.MouseEvent;
import flash.utils.Timer;
import flash.events.TimerEvent;
public class ClickSolver {
private var Button_Object:MovieClip;
private var Check_Object:MovieClip;
private var Score:Number = 0;
private var Local_Frame:Number = 0;
private var Local_Timer:Timer = new Timer(1000,3);
public function ClickSolver(ButtonObject:MovieClip, CheckObject:MovieClip, Frame:Number) {
Local_Frame = Frame;
Button_Object = ButtonObject;
Check_Object = CheckObject;
Button_Object.buttonMode = true;
trace(Button_Object.name);
trace(Check_Object.name);
Local_Timer.start();
trace(Local_Timer.currentCount);
Button_Object.addEventListener(MouseEvent.CLICK, Object_Button_Clicked);
Button_Object.addEventListener(MouseEvent.MOUSE_OVER,Button_Mouse_Over);
Button_Object.addEventListener(MouseEvent.MOUSE_OUT, Button_Mouse_Out);
Local_Timer.addEventListener(TimerEvent.TIMER_COMPLETE, TimerIsDone);
}
private function TimerIsDone (event:TimerEvent):void{
trace("Timer is done");
Local_Timer.stop();
Local_Timer.reset();
Button_Object.gotoAndStop(Local_Frame);
}
private function Button_Mouse_Out (event:MouseEvent):void{
Button_Object.alpha = 1;
}
private function Button_Mouse_Over (event:MouseEvent):void{
Button_Object.alpha = 0.75;
}
private function Object_Button_Clicked (event:MouseEvent):void{
Score++;
Check_Object.visible = false;
Button_Object.gotoAndStop(Local_Frame);
trace("Score: " + Score);
trace("Frame: " + Local_Frame);
}
}
}
_root isn't supported in AS3.
Try
MovieClip(root).gotoAndStop(local_Frame);
PS. A common naming convention for you code is to name variables using lower camelCase (i.e. start with a lowercase letter) and name classes with upper CamelCase (i.e. start with an uppercase letter).
This will make your code easier to read and allow you to instantly see which items are variables and classes.