PDA

View Full Version : [AS3] Platform Game Advice


aaron_da_killa
03-18-2009, 09:41 PM
Hey.

I'm trying to make a platform game but I need some advice about how it should be structured.

For example, should the document class of the game be the youngest child so to speak and or should all the other classes be children of the document class?

At the moment, I have three classes, a Document Class, a Player Class which handles things like player movement, jumping, scrolling and a platform class which at the moment handles collison detection and collison reaction (making the player stand ontop of the platform, making the player stop when hitting the side of the platform).

It seems that no matter what way I arrange the classes, I get problems.

Could somebody give me a general overview of how a non tile based platform game should be arranged.

If anybody has any more questions about the way I've structured my game, please let me know.

Thanks in advanced

bluemagica
03-19-2009, 09:35 AM
the document class is in reality neither an exact parent or a child, but by its use, it can act as both! A parent child relationship occurs when one class "inherits" properties from another class, but it is hardly ever needed to inherit from the document class!

Anyway, the structure of the game can be made in any way, where your goal is to keep the classes independent of each other as much as possible! So you can do something like,

Document class - handles preloader, menu, and every element that is outside the core gameplay!

Game class - this class will handle the actual gameplay, for example, "player" and "bullet" are two separate classes inside game class, so its the job of game class to check for collision between them. Game class can look inside itself, but a class, like player class here, shouldn't look outside itself!

--Sub classes-
player - player movements, key press, AI . (I generally use player for both player and NPC)
object - defines properties of objects like solid platform, spring, traps,....
weapons - self explanatory
enemy - ""

interactions between the objects of subclass should be handled by their parent, the game class!

aaron_da_killa
03-19-2009, 10:31 AM
Yay, a reply, thanks Bluemagica.

That's an interesting approach that I haven't considerd before with this Game Class idea. I would have to make all movieclips on the stage accesible from Game Class, how would I do this? Maybe add them to the stage from Game Class?

bluemagica
03-19-2009, 11:05 AM
yep exactly, you add all the things in the actual gameplay, from within the game class, and you initiate the game class from the document class! there can be another class (which isn't exactly a OOP way), a global class, which makes communicating between classes easier...like telling the "score" from the game class to document or scene_manager class so that it can be shown at the end of game, or player preferences, etc!

aaron_da_killa
03-19-2009, 10:41 PM
Alrghty, thanks again buddy.

So, if this GameEngine class isn't linked to the DocumentClass which is as the name suggests the document class of this game, then how would I do I call movieclip instances on the stage via their instance name in GameEngine or its children?

I uploaded an image of my current class structure.

Edit:

Alrighty, here is one for ya. I have a movieclip with the instance name player on the stage. That movieclip is linked to the PlayerCode class by using the following linkage properties:

Class: PlayerCode
BaseClass: flash.display.MovieClip

I can use the keyword "player" to refer to that movieclip instance in the Class PlayerCode but I can't use it elsewhere, not even in DocumentClass which is the projects document class! Not even in DocumentClass! Why is that?Alrghty, thanks again buddy.

So, if this GameEngine class isn't linked to the DocumentClass which is as the name suggests the document class of this game, then how would I do I call movieclip instances on the stage via their instance name in GameEngine or its children?

I uploaded an image of my current class structure.

bluemagica
03-20-2009, 03:54 AM
lol, i don't think you have completely understood yet! In the structure, everything dosent have a need to have a parent or "extend" a class, an "include" will be better!
Take my advice, and use StarUML (freeware), its a great software to plan your class structure, and with an extra plugin, it can generate as3 code for your class structure....


back to your question, class name and instance name are not the same and every object instance, exits within its parent scope, so if you create a player from gameEngine, DocumentClass on the outside, and bulletClass on the inside can't see it directly...they will both need to use a reference!for documentClass, say you did something like

var game:gameEngine = new gameEngine("level1","player1",5); //lvl,name,lives
game.init();

and in gameEngine you did something like

public var player:Player = new Player();
player.x = player.y = stage.stageWidth/2;

From documentClass you can access player by:- game.player
similarly, for bullet:- MovieClip(parent).player


theres another tiny trick:
var player:Player = new Player();
player.name = P1;

then you can use
var player = game.getChildByName(P1);

aaron_da_killa
03-20-2009, 10:57 PM
Thanks again Bluemagica.

Just two questions and then I'm going to see if I can fix this problem.

everything dosent have a need to have a parent or "extend" a class, an "include" will be better!

Right, so just like I say "import flash.display.object", I can say "import DocumentClass" and that means that in whatever class I import that to, I can access all of DocumentClass' functions/methods, variables and movieclips that belong too it say?

Question 2, I'm a little bit confused about what you mean classes on the inside and classes on the outside, could you explain that a bit for me when/if you have a free moment.

bluemagica
03-21-2009, 04:30 AM
1) with include, you can access only "public" stuff, say class A looks like:

package script
{
import flash.display.*;
class A extends Sprite //A is inheriting from sprite class
{

public var age:Number = 9; //public variable

public function A() //public function + constructor
{
show_name();
}
private function show_name() //private function
{
trace("PLAYER1");
}
}
}


So in call B you can do:

package script //simply means the as file is in "script" folder
{
import script.A;

public class B
{
public function B()
{
trace(A.age); //9
A.age = 10; // modifying the public variable temporarily
trace(A.age); //10
A.show_name() //error, can't access private
var abc = new A(); //show_name() called
}
}
}


This code is just to show you the use of public and private, but there an be few errors since i wrote this without testing!



2) inside and outside simply means their visibility, you are creating the player class, within the gameEngine class, so its inside the gameEngine, means for any instance of player, gameEngine will be its parent! Similarly, documentClass lies outside gameEngine!

aaron_da_killa
03-21-2009, 01:30 PM
Argh!

Alrighty, about your answer to question one.

I am trying to access a variable exactly as you accessed the variable age from class A except I get this error:

1119: Access of possibly undefined property gravity through a reference with static type Class.

Now, what I am doing is exactly what you have done in that example except for three things:

1) My fla and *.as files are placed in the same location so my package doesn't have a name. Meaning the equivalent of my import statement on your example looks like this: import A; (I doubt its this because I get no errors saying could not find specified class)

2) Class B in the example doesn't extend anything, however the equivalent of Class B in my set up extends movieclip

3) Class B belongs to a movieclip in the library with an instance placed on the stage, hence the need for #2.

So which one of these things is causing that error? Other than those 3 things, both your example and my setup are the exact same!

bluemagica
03-21-2009, 04:21 PM
try
var a = new A();
trace(a.gravity);

aaron_da_killa
03-22-2009, 12:22 AM
try
var a = new A();
trace(a.gravity);

Crap, that gives me run time errors:

Error: Error #2136: The SWF file file:///F|/Multimedia%20Major%20Project/Game/Untitlegrd%2D1.swf contains invalid data.
at CollisonDetection$iinit()
at flash.display::Sprite/flash.display:Sprite::constructChildren()
at flash.display::Sprite$iinit()
at flash.display::MovieClip$iinit()
at GameEngine$iinit()

I removed the fact that this class (B) belongs to a movieclip in the libary and removed the extends in class B and added this to my class A (still talking in the context of your example):


var b = new B();
b.init();


I than tried the following combinations each separated by a comment:


var a = new GameEngine();
a.trace(gravity);
//
var a = new GameEngine();
trace(a.gravity);
//
trace(GameEngine.gravity);
//
GameEngine.trace(gravity);
//
trace(gravity);


All gave errors. Honestly, its as if the import statement isn't doing anything. It give me an error if I type in a fictional class, but if I add class A to it, it acknowledges the fact that its there but doesn't do anything.

bluemagica
03-22-2009, 07:44 AM
I will make you a sample later today!

aaron_da_killa
03-22-2009, 08:07 AM
I will make you a sample later today!

Cheers buddy :) :) ! What a nice birthday present :cool:.

I've been reading up about inheritance and composition (extends vs import) and I think I need to use alot more import and alot less extending off other classes. The only problem is that import seems to have a null effect. Maybe I'm just doing something wrong. And with using extends, I'm having trouble getting things to work and be able to access movieclips off the stage at the same time.

bluemagica
03-22-2009, 06:18 PM
I have attached a zip.
Open the fla in flash CS3/cs4 IDE, and test it there so that you can view the trace results....if you just see the trace first before reading the code, it will be easier for you to understand!

aaron_da_killa
03-23-2009, 01:33 AM
Thanks alot for that buddy. One thing I did experiment with was I commented out the import statements in both Main and A and the code seemed to work anyway!

Also, do you think you could look at this attatched example and tell me whats wrong and how to fix it? Thanks again mate :)!

bluemagica
03-23-2009, 04:36 AM
Do not extend the document class

aaron_da_killa
03-23-2009, 05:49 AM
Whoa thanks alot buddy. This is starting to look promising, one small problem though. If I have any other movieclips on the stage I get this runtime error:

TypeError: Error #1006: init is not a function.
at DocumentClass$iinit()

Edit:

No Idea what I did but I deleted that third movieclip and placed it on the stage again and now it works :S.

Edit 2:

Mmmmm, I'm getting that error again now but this time there is no third movieclip. Perhaps this error randomly occurs?


Edit 3:

Alrighty, I've reduced my game to be essentially the exact same as the example you gave me and I can not for the life of me figure out why I'm getting the same error. Everything is just as you did it!

If you could download example3.zip and find out what's going on that would be awesome. Thanks!

Edit 4:

Heh, I changed the line "MovieClip(getChildAt(0)).init();" to read "MovieClip(getChildAt(1)).init();" in example 3 and it works now. I don't entirely understand what this line of code does, but I understand why changing that value fixed the problem. Perhaps instead of using getChildAt there is another method that results in the same thing or before this line of code is called I could set player/playerContainer (face/ff) index to 1 or something? What do you think?

bluemagica
03-23-2009, 07:10 AM
Start creating instances through code rather than placing them manually, that wayyou will get more control and better understand those errors!

getChildAt(0) means get whatever instance is in 0th position on the display list, i used it as a makeshift. Just recode your file to place all instances through addChild!

aaron_da_killa
03-23-2009, 07:16 AM
Start creating instances through code rather than placing them manually, that wayyou will get more control and better understand those errors!

getChildAt(0) means get whatever instance is in 0th position on the display list, i used it as a makeshift. Just recode your file to place all instances through addChild!

Yeah? You sure there is no work around? Part of the reason I wanted to use classes is so I could do all the level design in the flash IDE without having to change the code every time I want to add a platform or an npc or even tweak the their position.

bluemagica
03-23-2009, 07:26 AM
that comes later, first you need to understand how to work with the display list.....i also do design's in the FlashIDE, otherwise it will be real slow to place stuff through code, but after the placing you have to "access" those through code, and so if you don't understand how to work with the display list through code, you will have trouble!

aaron_da_killa
03-23-2009, 08:38 AM
that comes later, first you need to understand how to work with the display list.....i also do design's in the FlashIDE, otherwise it will be real slow to place stuff through code, but after the placing you have to "access" those through code, and so if you don't understand how to work with the display list through code, you will have trouble!

Alrighty, thanks Bluemagica. One other question, it seems that my player movieclip inside the container (or face inside ff in the context of your example) is only available in the init() function. How can I make it available for the whole class (ClassInit in the context of your example) not just one function in that class, and thus making it available to any children of this class.

Thanks

bluemagica
03-23-2009, 09:04 AM
In what i made ff is not a container, it is a reference to face. init() is a function to recieve this reference....after recieving the reference, you can just put it in a variable and use throughout the class! You see, in the example, I am getting the reference as "DocumentClass.ff", so as long as you have imported it, you can access ff at any class and at any point!

BTW: we don't extend or import the document class normally, we use document class to start of the game and create the basic requirements!

aaron_da_killa
03-23-2009, 10:14 AM
Ah, yes ofcourse! Thanks again.

Another thing, I'm experimenting for learning purposes using this method but with multiple movieclips on the stage. I'm looking for a different way instead of using getChildAt because this seems to be causing conflict with movieclips on different layers, perhaps I could use instance names instead?

bluemagica
03-23-2009, 10:24 AM
I told you already, getChildAt is a makeshift way i used back there cause i was changing the instance names for experiment! You shouldn't use it much....in real situation you will use an instance name and even more, a reference! see, you named your instance "face", which is a reserved word, so just to be on the safe side i used getChildAt(). The closest thing to this you will probably use is getChildByName()!

This is why i asked you to code everything and get familiar with the various ways of controlling the display list before going manual!

aaron_da_killa
03-24-2009, 12:45 AM
Ah yes, I understand :p. Could you give me an example of using the instance name instead of getChildAt. I'm not certain if I should be calling the movieclip or the variable its inside.

Thanks in advanced!

bluemagica
03-24-2009, 06:37 AM
It's useless trying to help, if you are not gonna try what i say.....anyway, "ms" is a instance name, and i am controlling it through game.as

aaron_da_killa
03-24-2009, 08:10 AM
Hmmm, that's quite an interesting example. I'm now considering making my game inside an entire movieclip as you have done, would solve one of the problems I am having.

I have a question about that example, keeping that whole structure, is it possible to make ms have its own class (linkage properties: class: ms, BaseClass: flash.....MovieClip). I tried making this class for ms:


package{
import flash.display.*;
import flash.events.*;


//I would like to use extends because I will need to reference via instance names movieclips inside of the game movieclip later on
public class ms extends game{
public function ms(){
//moves mc almost off stage, just to test if this class is working!
this.y = 250;
this.x = 250;
}
}
}


and I get this error:

1046: Type was not found or was not a compile-time constant: ms.

I honestly feel that if the above question was answered, I can finally commence work on my platform game again which is due in roughly 3 months. I've spent the last 3 weeks or so agonizing over this whole classes problem I'm having and making art assets for the game.

It's useless trying to help, if you are not gonna try what i say

=( I am doing what you say, Everything you have said I have tried. As for the whole not having anything on the stage and adding them in the code, I sort of feel it adds a little bit more to the confusion, but I think with this example I get what you mean ;). I didn't know you could have movieclips inside a movieclip in the library (as you have done with "game") nor did I know that the library updates, so if I added to mc movieclips inside game it would update in the library.

Thanks for your assistance, patience and support! :)

bluemagica
03-24-2009, 09:37 AM
Hmm no matter what i say, it seems you are set on using extend! I wont use it where not needed...so heres the updated example!

The reason for your using "extend" is not OOP way! Why are you trying to access something in the parent scope from within the child and not from the parent itself is beyond me....however in this example i am accessing stuff from game from ms...so i hope you will understand!

aaron_da_killa
03-24-2009, 09:57 AM
Hehe, you sure the contents of that zip file is correct? :o

Edit: Why I am trying to access stuff in the parent from the child is because I need this in my collision detection class and other classes. For example, I need to access the player in the collision detection class which the only way I can figure out how to do is using extends.

Honestly, the import statement doesn't work for me or something. That first example file you gave me, I commented out the import statements and the thing worked, I've also helped people with small problems that include the use of import statements in their code, I commented them out and it also worked for me. Its as if my Flash IDE (Flash CS3) automatically includes the import statements or something!

bluemagica
03-24-2009, 10:02 AM
yes

aaron_da_killa
03-24-2009, 10:06 AM
yes

Really? But you have the Main class which is from an earlier example and your missing the Game class. The code seemed to work though...

bluemagica
03-24-2009, 10:15 AM
Flash automatically searches the root folder of the project for the classes, it will throw errors if it cant find them there, thats why its safe too include paths!

Also you need to change a your game structure to incorporate proper OOP! Don't say there isn't any way of checking collision from parent....if your stucture wont do it, then think of one that does!

aaron_da_killa
03-25-2009, 05:12 AM
Thanks, but now game dosen't have an as file =(. When I create this file called game.as:


package
{
import flash.display.*;
import flash.events.*;

public class game extends MovieClip
{
public function game()
{
this.y = 30;
}
}
}


I get this error:

1046: Type was not found or was not a compile-time constant: TextField.

Anyway, I think you've taught me enough stuff now to commence work on my game, if the above question could be answerd than I defiantly can commence work on my game.

Thanks a bunch man!

bluemagica
03-25-2009, 05:29 AM
I have already updated the last zip, see it!
And for textfield, you need import the flash text class in game.as!

aaron_da_killa
03-25-2009, 06:32 AM
Bluemagica, I love you buddy. Thanks so much for your assistance! I am very very close to getting this to work, after this problem, I can't imagine any other possible problems. I actually realized something, in my player class (which no longer relates to the document class) I was trying to add event listeners to the stage rather than "this" as I see in your example. This is probably the reason I have been having so many problems, just when I think I have it figured out, I got this runtime error I could never explain! I fixed it up and it worked perfectly!

Except one thing, now my player character doesn't respond to keyboard input. I have tested and found that these:


this.addEventListener(Event.ENTER_FRAME, moveChar);
this.addEventListener(Event.ENTER_FRAME, triggerListner);
this.addEventListener(Event.ENTER_FRAME, playerJump);
this.addEventListener(Event.ENTER_FRAME, startScroll);


work however these two do not:


this.addEventListener(KeyboardEvent.KEY_DOWN, checkKeysDown);
this.addEventListener(KeyboardEvent.KEY_UP, checkKeysUp);


Any ideas?

bluemagica
03-25-2009, 06:53 AM
Its simple, player is a movieclip nested inside a mc on stage....and since events normally propagate in bubble manner, your player can't recieve the events!

In other words, either your player needs to have focus always(not much good), or assign the keyboard listeners to stage! This is the reason we generally create a keyboard class with listeners set to stage and use it as needed!

Oh another thing! It's a really bad practice to use multiple listeners for same event like you have done with your Enterframe......Use just one enterframe listener and call all functions from within the functions of that listener!


this.addEventListener(Event.ENTER_FRAME, eframe);
stage.addEventListener(KeyboardEvent.KEY_DOWN, chkKeyDown);
stage.addEventListener(KeyboardEvent.KEY_UP, chkKeyUp);

private function eframe(e:Event)
{
moveChar();
triggerListener();
playerJump();
startScroll();
}


Also remember, if you are going to place the player by code, don't set up this listeners in the constructor, cause the stage property is available after an instance is on stage!

aaron_da_killa
03-25-2009, 07:50 AM
Alrighty, one minor problem, I can think of a work around for this but I would prefer not to use the work around. Anyway...

I have no problem calling generic movieclips from other classes, in the context of your latest example, we can easily call ttext from the ms1 class. However, what if ttext belonged to a class of its own like ms1 has its own ms class. How then do we call ttext from ms1?

Continue reading if you want an elaboration (not necessary)

See, here is my current hierarchy of movieclips:

game(player, level(all Platform instances)) - if that makes any sense

I can call level from Player (class) and Game (class) easily, however I am having difficulty calling player (movieclip) from the Platform (class) and Game (class) because player (movieclip) belongs to its own class called Player.

So how do I do this?

Thanks in advanced!

bluemagica
03-25-2009, 08:18 AM
parent.parent, or stage.game.player

aaron_da_killa
03-25-2009, 08:30 AM
Ah, parent.parent works fine. I did this before but obviously player musn't have been created yet or something. I had to first declare the variable and define it later on.

Thanks ;)