i'm trying to create a flash game, but i'm having trouble with my classes. i'm importing the classes on the main script. they're imported okay, i've tested it all. but i dont know how to use classes inside another class
this is what i've got so far:
class Class.Player {
public static var self:MovieClip;
public static var bullet:Class.Bullet;
function controls() {
//Shoot
if (Key.isDown(Key.SPACE)) {
bullet = new Bullet(100, 100);
}
}
it loads the class and declares the variable, but it claims "Bullet" is not an existing method. it is an existing method, and it works when i call it from the main script.
also, do i need to declare the class like public static var bullet:Class.Bullet;? it's the only way that works for me but wondered if there's a better way?
It looks like you are having problems with the naming of your classes. You don't have to call your classes Class.Name. Just use Name.
In your case, you could have a file called
Player.as
With this content:
package {
import flash.display.MovieClip;
public class Player extends MovieClip {
public private var bullet:Bullet;
public function Player(){
//constructor
}
function controls() {
//Shoot
if (Key.isDown(Key.SPACE)) {
bullet = new Bullet(100, 100);
}
}
}
}
And then a file called
Bullet.as
With this content:
package {
import flash.display.MovieClip;
public class Bullet extends MovieClip {
public function Bullet(x:Number, y:Number){
//constructor
}
}
}
You can read more information about creating and using custom classes here: http://www.flashandmath.com/bridge/intro/class.html
You're putting your package information in the Class name. I have no idea how this is even compiling for you (especially given that Class is a reserved word.
Your files should look more like:
package somePackage {//somePackage instead of the reserved word Class you were using
import someOtherPackage.Bullet;
public class Player extends MovieClip {
public var bullet:Bullet;
public function Player():void {
super();
//other constructor logic here
}
}
}
Related
This is my Main.as:
package {
import flash.display.MovieClip;
public class Main extends MovieClip {
public function Main() {
// Code here
}
public function myFunc() {
trace('!!!!');
}
}
}
When I try accessing it from another class using the following code, Flash throws me Error #2136:
package {
import flash.display.MovieClip;
import Main;
public class MyClass extends MovieClip {
public var m:Main;
public function MyClass() {
m = new Main();
m.myFunc();
}
}
}
EDIT: One more thing. The second class is attached to a MovieClip and exported on the first frame. I thought it made no difference, but someone in the comments have told me it does and apparently that's what's causing the error in the first place. In that case, how can I access the public function from a class attached to a MC?
Next time post the error message itself, most of us do not have Flash errors memorized by id. ;)
From the docs:
2136 The SWF file %1 contains invalid data.
This rings a bell for me. Your Main class is probably your document class. The document class is a special class that cannot be instantiated.
To access properties and methods of the document class instance from other code, you simply need a reference to the document class instance.
There are many ways you could get a reference, as it is really just a code dependency design question. Two common, easy solutions are:
1. Use the root property of any display object that is added as a child of the document class instance. Since the root property is typed to DisplayObject you need to cast to your document class to access its methods and property, for example: Main(root).myFunc().
2. Use the singleton pattern and assign a static public reference to the document class instance:
public class Main {
public static var main:Main;
public function Main() {
main = this;
}
public function myFunc():void { }
}
// usage:
Main.main.myFunc();
I have a parent class called 'main.as'. I am trying to get the child class to call main's function. They both reside in the same folder.
// main.as //
package {
public class main extends MovieClip {
public function main() {
var child:child_mc = new child_mc(this);
}
public function callFunction():void {
trace("Done it");
}
}
}
.
// child.as //
package {
import main;
public class child extends MovieClip {
private var main:MovieClip = new MovieClip();
public function child(main:MovieClip):void {
this.main = main;
main.callFunction();
}
}
}
This is the error I've been getting:
TypeError: Error #1006: callFunction is not a function.
so I tried doing a trace like this
trace(main.callFunction);
and it says undefined. Can someone tell me what I am missing. I get this feeling its a very basic thing that I have overlooked!
Your "child" package is defined as "main". I'm not even sure how it complied, let alone run to the point of showing the error message you got.
I believe the code below should do what you expected.
(I also took the liberty to rename the classes to use CamelCase (with initial caps) to adhere to best practices and to be easier to distinguish from variable names.)
Main.as
package {
public class Main extends MovieClip {
public function Main() {
var child:ChildMC = new ChildMC();
child.main = this;
}
public function callFunction():void {
trace("Done it");
}
}
}
EDIT: I just saw your comment that points out that child_mc is a MovieClip in the Library. I guess then that the child class is set as the Base Class of the child_mc?
If so, you cannot pass properties through the instantiator, you need to find another way to pass along the instance of the Main class to the Child class.
One way would be to add a setter, like the following:
Child.as (Base Class for ChildMC)
package {
public class Child extends MovieClip {
private var _main:Main;
public function Child() {
}
public function set main(main:Main):void {
this._main = main;
this._main.callFunction();
}
}
}
In Main.as I have the following:
package {
import flash.display.MovieClip;
public class Main extends MovieClip {
public var damage:Number;
public function Main() {
// constructor code
var char:Character = new Character();
addChild(char);
}
}
}
And I have another package called Character.as
package {
import flash.display.MovieClip;
public class Character extends MovieClip{
public function Character() {
trace(damage);
}
}
}
I need to be able to share the damage set in the main.as with the character. Is there any way to make the speed more global?
Why don't you make damage a public property of your Character and then it'll be easily accessible via your Main class like this :
char.damage = 100;
trace (char.damage);
To do this, just add the property to your Character class like so :
public class Character extends MovieClip {
public var damage:Number;
public function Character() {
trace(damage);
}
}
But given your comment, I take it you would rather everything just be global and accessible everywhere as opposed to applying OOP concepts.
If so... just define it as a public static in your Main class like this :
public static var damage:Number;
and to access it anywhere you do this :
Main.damage = 100;
trace(Main.damage);
There is another way of sending values through packages (This way is not really sharing variables, but it could be useful for you). What this code does is that the class Character creates a variable, and this variables gets an value from the Main package:
Change the character.as to this:
package {
import flash.display.MovieClip;
public class Character extends MovieClip{
public function Character(a:int) {
//output will be the integer 10
trace(a);
}
}
}
and main.as to:
package {
import flash.display.MovieClip;
public class Main extends MovieClip {
private var damage:int = 10;
private var char:Character = new Character(damage);
public function Main() {
}
}
}
Edit: Not useful for realtime applications, because the values of private var damage will only be send on initialization of private var char:Character = new Character(damage).
I'm learning AS3 and creating a simple 'Asteroids' game.
I have written a simple class of linear movement:
package {
import flash.display.MovieClip;
import flash.display.Stage;
import flash.events.Event;
public class lin extends MovieClip {
private var vx:Number=0;
private var vy:Number=0;
public function lin(x:Number,y:Number,sr:Number,spd:Number)
{
this.rotation=sr;
vy+=Math.sin(degToRad(sr))*spd;
vx+=Math.cos(degToRad(sr))*spd;
this.x=x+vx;
this.y=y+vy;
addEventListener(Event.ENTER_FRAME,loop,false,0,true);
}
public function loop(evt:Event)
{
y+=vy;
x+=vx;
if (outOfBounds())
kill();
}
public function outOfBounds():Boolean
{
return (x>stage.stageWidth || x<0 || y>stage.stageHeight || y<0);
}
public function kill():void
{
if(parent)
parent.removeChild(this);
removeEventListener(Event.ENTER_FRAME,loop);
}
public function degToRad (deg:Number)
{
return deg * Math.PI / 180;
}
}
}
And I need to set this behaviour of movement to several objects (LaserBeam, Asteroids)
I created a new MovieClip with class 'LaserBeam' and wrote this:
package {
import flash.display.MovieClip;
import flash.display.Stage;
import lin;
public class LaserBeam extends MovieClip {
public var LaserBeamInstance:lin;
public var LaserSPD=15;
public function LaserBeam(x,y,r) {
LaserBeamInstance=new lin(x,y,r,LaserSPD);
}
}
}
But when I try to run my game, it says:
Line 1 1203: No default constructor found in base class lin.
What should I do to make many different MovieClips share one behaviour?
Thanks in advance!
UPD: all project files is here
Try calling super() from your lin constructor. This is because it inherits from MovieCLip. Properties such as this.rotation won't be initialized until you call the MovieClip constructor with super()
You should also make the class name 'Lin' to follow the standard naming convention.
public function Lin(x:Number,y:Number,sr:Number,spd:Number)
{
super();
this.rotation=sr;
vy+=Math.sin(degToRad(sr))*spd;
vx+=Math.cos(degToRad(sr))*spd;
this.x=x+vx;
this.y=y+vy;
addEventListener(Event.ENTER_FRAME,loop,false,0,true);
}
I think you should try:
public function lin(x:Number = 1,y:Number = 1,sr:Number = 1,spd:Number = 1)
I don't know exactly what's happening, but I think that you have pointed you class "lin" as base class for some of your symbols in your library.
So, that symbols try to construct themselves by calling "lin" constructor, but of cause without any parameters.
BTW, Golden rule:
-variable names should start from lowercase letter
-names of classes and constructors from uppercase
In answer to your question:
What should I do to make many different MovieClips share one behaviour?
You should read about OOP patterns. This book is a great introduction.
http://www.amazon.com/First-Design-Patterns-Elisabeth-Freeman/dp/0596007124
In response to your error, I think you are not giving us the whole picture. The error refers to class lin being extended, but in the code there are no classes extending lin.
Does this work well as a Singleton in actionscript? i.e. are there any gotchas I should be aware of, and is it true that only one instance of AVManager would be created in this case:
Note that I do get the expected output (only one time of "instantiated first time" and numbers follow sequence):
instantiated first time! 1
FILE 1: 2
FILE 2: 3
and finally 4
Here are the files....
AV_CONFIG.as:
package {
public class AV_CONFIG {
public static var AVM:AVManager = new AVManager();
}
}
AVManager.as:
package {
import flash.events.EventDispatcher;
public class AVManager extends EventDispatcher {
public var someConstantData:uint = 1;
public function AVManager() {
trace('instantiated first time!', someConstantData);
}
}
}
Then:
File1.as:
package {
import AV_CONFIG;
import flash.display.Sprite;
public class File1 extends Sprite {
public function File1() {
AV_CONFIG.AVM.someConstantData++
trace('FILE 1:', AV_CONFIG.AVM.someConstantData);
}
}
}
File2.as:
package {
import AV_CONFIG;
import flash.display.Sprite;
public class File2 extends Sprite {
public function File2() {
AV_CONFIG.AVM.someConstantData++
trace('FILE 2:', AV_CONFIG.AVM.someConstantData);
}
}
}
Main.as (the DocumentClass):
package {
import AV_CONFIG;
import flash.display.Sprite;
public class Main extends Sprite {
public function Main() {
var f1:File1 = new File1();
var f2:File2 = new File2();
AV_CONFIG.AVM.someConstantData++
trace('and finally', AV_CONFIG.AVM.someConstantData);
}
}
}
Generally with singletons you want to:
Limit or dissolve the ability to create instances of that class.
Create a means of getting an instance of that class statically.
Example:
public class AvManager
{
private static var _instance:AvManager;
internal static var created:Boolean = false;
public function AvManager()
{
if(AvManager.created)
{
throw new Error("Cannot created instances of AvManager, use AvManager.instance.");
}
AvManager.created = true;
}
public static function get instance():AvManager
{
if(_instance == null)
{
_instance = new AvManager();
}
return _instance;
}
public function test():void
{
trace("Working.");
}
}
Where you could now use:
AvManager.instance.test(); // Working.
The biggest gotcha is allowing global access to something if its state can be changed. If this is a project where you expect the codebase to be maintained for longer than a week or so and you think it's likely to have more than 500 lines of code, I'd strongly suggest avoiding doing this--I can tell you from experience that in a large project it can be difficult to impossible to figure out which of the hundreds of Classes that have access to your Singleton made the change to its state that is causing a given bug.
Next, requirements have a way of changing. What if you suddenly need 2 AVManagers? You'll find that you've created so many baked-in references to your static that changing it will blow the entire project to heck. Again, I speak from experience here. If you use dependency injection (which is just a scary way of saying that Classes that need an AVManager have a property that is populated from the outside), then these types of changes become easy...just give them a different AVManager, done.
Finally, if you have any pretensions of wanting to do Test Driven Development, using globals/statics in this way will essentially make all that code untestable. You can't provide an alternate AVManager for testing, since all the Classes with a dependency on it are hard-wired to go get that specific one.
Good luck!
Yeah this works fine, a different method is to put an AVManager right in its own class file at the top:
private static var AVM:AVManager = new AVManager();
and get it when required with a function in the AVManager class like this:
public static function GetInstance():AVManager {
return AVM;
}
This setup isn't necessary but provides some nice little protection by disallowing direct access.
Good luck with your project.
See this code as an attempt for creating something different.
An other Singleton in AS3 :
First an Interface :
package test {
public interface Foo {
function func0():void;
function func1(arg:String):String;
}
}
And then a Singleton :
package test {
public class BASIC_FOO {
public static const BASIC_FOO:Foo = new BasicFoo();
}
}
import test.Foo;
class BasicFoo implements Foo {
public function func0():void {
}
public function func1(arg:String):String {
return arg;
}
}