Ok this is not very complicated but it's not simple too. You may have knowledge in what is a class and an object and how it woks. I explain it a little in my tut, but I know that somebody else has working on a tut talking about this. So look about it.
Because of the lenght of the code I divided my tut in several part. But you have to keep in mind that you CAN'T separate some code to the rest WITHOUT rewritting it. So this tut, execpt if you use it "as is", is here just to show you a good way to make a game (not necessary a spacegame). Try to understand and don't copy/paste code!!!!
I give you the working fla. The better way to really understand is to open the fla, looking which methods are call in the begining of the game (here frame 5), and follow the code like the ActionScript do. Have the printed tut near you and let's go. But it's my opinion, so do as you want!
HOW TO LOAD DECOR AND MADE A MAP OF IT
BUT IF YOU DON'T WANT TO USE CLASS AND OBJECT LOOK THIS TUT TOO. YOU'LL FIND SOME INTERESTING WAY (i think) TO I.E LOAD DYNAMICALLY BACKGROUNDS AND SCROLL IT.
Before looking for the code, we have to made the different MC to make the game working.
The first one is the ship.
![]()
This one is divided in three frame:
Look at the fla to see how are each MCs.
The second one is the MC timer.
It's simply a timer. Just write timer and convert it to a MC. The code under is on it.
[as]//each time the MC display one of this frame.
onClipEvent (enterFrame) {
// take the new time
_root.newtime = getTimer();
// define the time between oldtime and newtime. Use to now if the player can firing one missile again.
_root.timer = _root.newtime - _root.oldtime;
}[/as]
Note that you can made it with ActionScript (AS). create a MC with _root.createEmptyMovieClip("clipName", depth).
So the code after will be:
[as]// AS way to define the onClipEvent(EnterFrame)
_root.clipName.onEnterFrame = function () {
_root.newtime = getTimer();
_root.timer = _root.newtime - _root.oldtime;
}[/as]
The last one are the missile clip.
In my example I made 2 different missile. One simple
(default one) and one who explose
. You can make your own, but you always have to follow this way to made them, else they'll "don't work". You have to make a MC for each missile. For each MC you have to get 2 frames. The first one is the default one, the second one (Frame Label: explose) containing a graph (or a MC) of the explosion of the missile. In each frame you have to put this code : stop(); . Look at the fla to see how it works.
I've made too a specific MC for the "explose missile". This graph will follow the spaceship. Here the MCrepresents the limit of the explose missile. Look at the fla to see it, it's the bid res circle.
Note that all the MCs I've made are in my scene. I used to do this. In that case I see all the clip which are in my scene. If you don't want to have this clip on your scene, put a linkage name in their properties (on the library window) and each time I use MC.dupplicateMovieclip(newName,depth) use attachmovieClip(linkageName, newName, depth). See on the Flash help to see how it works!CLASS FOR THE SHIP.
OK, now we're looking for the code and explain it.
[as]
// ***********************************
// **FONCTION MYSHIP******************
// ***********************************
// we made the var MyShip exist
function MyShip() {
}
// and we define it as a lower class of the MovieClip class. In that case, the class
// MyShip inherit all the methods and properties of its upper class (here MovieClip).
MyShip.prototype = new MovieClip();
// ***********************************
// Now we define the methods of the MyShip class. Here is the method who init the weapon
// of the spaceship.
MyShip.prototype.InitArmes = function(MuniSimple, MuniChercheur, MuniExplosion, MuniTriple, MuniTripleCherche) {
// we've made an 2D array(see MyShip.prototype.Init()). In this one you have to put
// all the name of the MC you've created for your weapon. I.e you have 3 weapons, each
// graph has to be in a different //MC. So you've got 3 MC. I.e simple, explosion and seek.
// The second dimension of the array is for the bullets of each weapon. Ok?
this.MesArmes = [[simple, chercheur, explosion, triple, triplechercheur], [MuniSimple, MuniChercheur, MuniExplosion, MuniTriple, MuniTripleCherche]];
// define wich clip is active. Don't forget that "this" refer to the object who call
// the method.
this.MissileActif = (this.MesArmes[0][0]);
};
// ***********************************
// Here we init the different var use by an object of this class. This method
// have 4 parameter: coords, rotation and speed.
MyShip.prototype.Init = function(U, L, R, W, F, x, y, angle, VitesseMax) {
this.Up = U;
this.Left = L;
this.Right = R;
this.weapon = W;
this.firing = F;
this._x = x;
// abscisse du vaisseau
this._y = y;
// ordonn?e du vaisseau
this._rotation = angle;
// rotation angle in degree
this.MaxSpeed = VitesseMax;
// Max Speed
this.MonAngle = (Math.PI/180*this._rotation);
// rotation angle in radian
this.Vivant = true;
// is my spaceship still there
this.AlreadyRun = false;
// is my spaceship already in accelerate movement
this.Fin = false;
// let me know if a tween motion is ending, i.e the tween of the explosion of the sapceship
this.SpeedX = 0;
// Speed in 0x
this.SpeedY = 0;
// Speed in 0y
this.AngleTourne = 10;
// angle which be soustract or add to the present spaceship's angle. This var'll be call when you push Left or Right key.
this.CheckPointX = this._x;
// X of CheckPoint
this.CheckPointY = this._y;
// Y of CheckPoint
// this two under lines are here because we can tell to flash which
// part of the scenery is the "root" one (in which your spaceShip appears)
this.Ligne = Number(monLevel.Rligne);
// this put the SpaceShip on the correct line
this.Colonne = Number(monLevel.Rcolonne);
// this put the SpaceShip on the correct col
_root.carte.attachmovie("SmallNavette", [this._name+"Small"], 100);
// create an empty MC called youObjectName+Small
// Array with the name of the missile and the number of bullets -1 == infinite
this.MesArmes = new Array();
// mon tableau d'armes
this.MissileActif = "";
// l'arme active
};
// ***********************************
// this method check if the selected weapon always have bullets, if true it return TRUE else FALSE
MyShip.prototype.CheckMunitions = function() {
// we're looking for the selected weapon
for (t=0; t<=(this.MesArmes[0].length-1); t++) {
if ((this.MesArmes[0][t]) == this.MissileActif) {
// we find it so we look if this weapon always have bullets
if ((this.MesArmes[1][t]>0) || (this.MesArmes[1][t] == -1)) {
return (true);
break;
} else {
return (false);
}
}
}
};
// ***********************************
// This method remove 1 bullet to the number of bullet of the selected weapon
MyShip.prototype.EnleveTir = function() {
for (t=0; t<=(this.MesArmes[0].length-1); t++) {
// looking for the selected weapon
if (((this.MesArmes[0][t]) == this.MissileActif) && ((this.MesArmes[1][t])<>-1)) {
// if find and if number is not -1 (which is for infinite bullets), we remove 1 bullets to the number of bullet of the selected weapon
this.MesArmes[1][t] -= 1;
break;
}
}
};
// ***********************************
// this method is called when the player want to change weapon. It looks for the next weapon who have bullets, else select the default weapon (infinite bullets).
MyShip.prototype.ChangeArmes = function() {
var oldposition = -1;
// define the old and new position out of the array
var newposition = -1;
var OK = false;
// ok let us know if we found a weapon
for (t=0; t<=(this.MesArmes[0].length-1); t++) {
// looking for the place of the selected weapon
if ((this.MesArmes[0][t]) == this.MissileActif) {
oldposition = t;
// so we have the old place (the last weapon used)
newposition = oldposition;
// init new position to check the place after
break;
// use to break the script, in that case if the weapon have the first place the script will not look for the other.
}
}
while (OK == false) {
newposition++;
if (newposition>(this.MesArmes[0].length-1)) {
// if we reach the end of the array, we'll come back to the beginning, in that case ALL the place will be check
newposition = 0;
}
if ((this.MesArmes[1][newposition])<>0) {
// if the place we are got a weapon with bullets so we define this weapon as the active weapon
this.MissileActif = (this.MesArmes[0][newposition]);
// now if the weapon use specific graph wich have to follow the spaceship, we'll attach movie to the MC Suiveur (follow in french).
switch (this.MissileActif) {
case simple :
_root.Suiveur.Armes.unloadMovie();
// clear the MC Suiveur
break;
case explosion :
_root.Suiveur.attachmovie("cercle", "Armes", 0);
// attach the graph to the clip Suiveur
}
OK = true;
// we've found a weapon so Ok == true.
}
}
};
// ***********************************
// This method is used to move the SpaceShip object.
MyShip.prototype.deplacement = function(MonDecor) {
if (this.Vivant == true) {
// the spaceShip is still alive.
if (Key.isDown(this.Left)) {
this._rotation -= this.AngleTourne;
}
if (Key.isDown(this.Right)) {
this._rotation += this.AngleTourne;
}
if (Key.isDown(this.Up)) {
if ((this._rotation>=-90) && (this._rotation<=+90)) {
// if my _rotation property is between -90 and 90 then the nose of my space ship is turn to the right so we add the cos to the vector SpeedX (some tuts are about
// vector and Math function. Look about it if you have some troubke understanding how it works.
if (this.SpeedX<this.MaxSpeed) {
// if the XSpeed isn't the MaxSpeed so we add the cos to the X vector
this.SpeedX += Math.cos(this.MonAngle);
}
} else if (this.SpeedX>-this.MaxSpeed) {
// the nose of the spaceShip is turn to the left so we substract the cos to the vector if the cos isn't -MaxSpeed. Here I
// may to use the Math.abs function, but I find better to see the minus sign... for more understanding.
// so I ADD the cos, because the cos is already negative. (look at your old Math lesson).
this.SpeedX += Math.cos(this.MonAngle);
}
if ((this._rotation>=-180) && (this._rotation<=0)) {
// the same thing as above, execpt we work with the sinus
if (this.SpeedY>-this.MaxSpeed) {
this.SpeedY += Math.sin(this.MonAngle);
}
} else if (this.SpeedY<this.MaxSpeed) {
this.SpeedY += Math.sin(this.MonAngle);
}
if (this.AlreadyRun == false) {
// check if my Ship is alredy run else put the state to run
this.gotoAndStop("run");
this.AlreadyRun = true;
}
} else {
if (this.AlreadyRun == true) {
// the player don't press the Up key so the SpaceShip stop and we go to the state STOP
this.gotoAndStop("stop");
this.AlreadyRun = false;
}
}
// set the _x and _y position and the _rotation of the SpaceShip
this._x += this.SpeedX;
this._y += this.SpeedY;
this.MonAngle = (Math.PI/180*this._rotation);
// Moving the following MC, for the specific graph for the selected weapon. i.e for the weapon explosion.
Suiveur._x = this._x;
Suiveur._y = this._y;
// Call function to scroll decor (if necessary). In that case if my spaceShip is one the edge of the scene we made action (that we will see after)
scrollDecor(this, Mondecor);
// This two lines move my small spaceship on the map. The +1 and +2 at the and of the two lines is for coords correction
// I have a pb with that. Don't know how to resolve it so I use this correction.
_root.carte[this._name+"Small"]._x = (60*(this.Colonne-1))+this._x/10+1;
_root.carte[this._name+"Small"]._y = (60*(this.ligne-1))+this._y/10+1;
// check if a wall is where the spaceship is
checkcolision(this, this, MonDecor);
// is the spaceship cross a checkpoint. See the "laoding scenery" part and come again here to understand why
// I do that and hox it works
// I look for the wall and checkpoint which are ONLY on the active part of the scenery
// I use the var maxmur and maxcheck init in the part themselves
for (c=0; c>=MonDecor["L"+this.Ligne+"_"+this.Colonne]["maxcheck_"+this.Ligne+"_"+this.Colonne]; c++) {
if (this.hitTest(Mondecor["L"+this.Ligne+"_"+this.Colonne]["check"+c])) {
Mondecor["L"+this.Ligne+"_"+this.Colonne]["check"+c]._name = ["old"+c];
// my last checkpoint coords are the coords of the last crossed checkpoint
this.CheckPointX = Mondecor["L"+this.Ligne+"_"+this.Colonne]["old"+c]._x;
this.CheckPointY = Mondecor["L"+this.Ligne+"_"+this.Colonne]["old"+c]._y;
// my checkpoint dissappear to become a star
Mondecor["L"+this.Ligne+"_"+this.Colonne]["old"+c].gotoAndStop("effet");
}
}
if (Key.isDown(this.Firing)) {
// the spaceship firing a missile (active missile). Call a method of the class Amissile. We'll see that later.
this.MissileActif.InitMissile(this, MonDecor);
}
if (Key.isDown(this.Weapon)) {
// if the weapon key is press then we change the active weapon.
this.ChangeArmes();
}
} else if (this.Vivant == false && this.Fin == true) {
// if my spaceship is not alive (so the player is dead) and
// the tween of the SpaceShip explosion is ending so I go to the last
// CheckPoint coords and set the speed vector to 0
this._x = this.CheckPointX;
this._y = this.CheckPointY;
this.SpeedX = 0;
// Y speed
this.SpeedY = 0;
// X speed
this.Fin = false;
// end of the anim
this.Vivant = true;
}
};
// ***********************************
// in each frame I call the deplacement method of the object created by the clas MyShip.
MyShip.prototype.onEnterFrame = function() {
this.deplacement(_root.decor);
};
// ***********************************
// to associate a class with a symbol. You have to put a name in the linkage
// area (property of the symbol in the Library Window). Here I put nav. So I
// associate the symbol nav with the clas MyShip. In that case each MC created
// with the nav symbol can use SEPARATLY all the method and properties of
// the class MyShip.
Object.registerClass("nav", MyShip);
[/as]
NOW YOU CAN HAVE AS MANY INSTANCE (OBJECT CREATED WITH) OF THE CLASS MYSHIP AS YOU WANT. SO YOU CAN HAVE FOR EXAMPLE 2 PLAYERS. YOU ONLY HAVE TO DEFINE THE PARAMETER TO INIT IT. (Up, Left, Right, _x, _y, _rotation, MaxSpeed).
CLASS AMISSILE
Ok, let's start!
First of all you have to create your class. Here is the way to proceed!
// Make the var AMissile exist
function AMissile() {};
// and define it as a lower class of the class Movieclip.
AMissile.prototype = new MovieClip();
"MyClass.prototype = new Aclass()" is use to create a class MyClass from the upper class Aclass. Ok ?
Now, you have to write the methods of this class. The first one setting all the var used by the object to they're default value.
Understanding that this var is created for each object created with this class.
// creating the methods InitMissile
AMissile.prototype.InitMissile = function (porteur, MonDecor) {
// and setting the var
this.vitesse = 0; //missile's speed
this.Vivant = false; //missile isn't "alive"
this.CopieMissile (porteur, MonDecor);
}
You'll see that I calling another method in the InitMissile. Simply to have less code to write after. In that case to create and move a missile I only have to "InitMissile" it and let's go!
So here is the CopieMissile method which dupplicate the missiles. (Don't forget that the method created here is for all objects or lower class of the class AMissile)
// create the method CopieMissile for the class AMissile. "Porteur" is the spaceship having this messile, "MonDecor" is the decor
AMissile.prototype.CopieMissile = function (porteur, MonDecor) {
/* I've got a timer in my main scene telling how many times spend since the last call.
so I look if I can firing one more missile (times between two fire is upper than a certain time that you choose, here tempsTir)
the if instruction can be proceed if the var have just been set; oldtime == 0 */
if (_root.timer > _root.tempsTir || _root.oldtime == 0) {
// niveau is an integer telling me the depth of the MC dupplicated
_root.niveau++;
//present is the number of ACTIVE missile which are in the scene (used after in my tut)
_root.present ++;
//duplicate Missile
this.duplicatemovieclip(porteur.ligne+""+porteur.colonne+"Missile"+_root.niveau, _root.niveau);
//bullet - 1. EnleveTir take away one bullet of my weapon/missile
porteur.EnleveTir();
//Property of Missile. define the _x and _y pos of the missile. In that case it seems to be firing by the spaceship (here porteur).
_root[porteur.ligne+""+porteur.colonne+"Missile"+_root.niveau]._x = porteur._x;
_root[porteur.ligne+""+porteur.colonne+"Missile"+_root.niveau]._y = porteur._y;
_root[porteur.ligne+""+porteur.colonne+"Missile"+_root.niveau]._rotation = porteur._rotation;
/*And now I move my missile. But if you look we don't have any method called deplacementMissile.
Look under to see why! Joy of the OOP.*/
_root[porteur.ligne+""+porteur.colonne+"Missile"+_root.niveau].deplacementMissile (porteur, MonDecor);
// redefine my oldtime and newtime
oldtime = getTimer();
newtime = oldtime;
//check if we already have bullet -- we will see that methods later.
if (porteur.CheckMunitions() == false) {
porteur.ChangeArmes();
}
}
};
And now here is the coolest code. We'll made as much lower class as Missile/weapon we have. For the example I've made two type of missile (so two lower class). One use by default by the player, and another one. Why because each missile have it's own behaviour. Here is the code!
[as]//As before, I create my lower class SimpleMissile from the class AMissile,SO HERE YOU HAVE TWO INSTANCE OF THE CLASS AMISSILE. YOU CAN MAKE NOW YOUR OWN. I'LL BE HAPPY TO SEE ONE OF YOURS. TELL ME IF I CAN USE IT, BECAUSE I'M OUT OF IDEA AND HAVEN'T GOT THE TIME TO LOOK FOR NEW ONE.
THANX!
LOADING THE SCENERY
Ok, I'm pretty proud to show you how I'm loadind the scenery in my game. The way I use allow you to have a larger and longer scenery as you want.
![]() | ![]() |
| line1,col1 | line1,col2 |
![]() | ![]() |
| line2,col1 | line2,col2 |
Ok, you have to put your wall. Make a rectangle and convert it to a MC. Now place all your wall and named them mur1, mur2, mur3, and so on(mur is the french word for wall). Do the same thing with the checkpoint with check1, check2. For each part you begin to wall1 and check1 (if any).
Now we have to set the var of each fla. There is as many var as object in your scenery you want to interact with. So here we have only two object: wall and checkpoint. So there is two var: maxmur and maxcheck. maxmur is for the max number of wall in the part, maxcheck max number of checkpoint in the part. Now, the var MUST be different for each part, so we named it like this (you'll understand why latter):
maxmur_1_1 for the part line 1 col 1, maxmur_2_1 for the line 2 col 1 and so on.
maxcheck_1_1 for the part line 1 col 1, and so on.
So you have here 4 swf named 1_1, 1_2, 2_1, 2_2. This is your level1 so put this 4 swf in a folder named level1, and add a text file with this on it:
ligne=2&colonne=2&Rligne=1&Rcolonne=1&
It let flash know how many line and col you got and the part where your spaceship is (here is the first line -Rligne- and first col -Rcolonne-).
Now here is the code for the decor (this code is in your main fla, not in the scenery fla, ok?!).
//This function init the limit. You can if you want pass parameter to the function to made the limit dynamic.
function InitVarDecor () {
H = 0; //Upper limit
B = 600; // Lower Limit
G = 0; //Left Limit
D = 600; //Right limit
}
/* This function load the decor you created before (all the L_C.swf).
The parameter numlevel is the number of the level.*/
function LoadDecor (numlevel) {
//depth of the clip dupplicated inside the MC we'll made
var niv = 0;
/* increment niveau and create an empty MC called decor, which will contains all the
part of of your scenery*/
niveau++;
_root.createEmptyMovieClip("decor",niveau);
/*create an empty Mc called carte. This MC will contain the jpg of your scenery's part*/
niveau++;
_root.createEmptyMovieClip("carte",niveau);
/*we move the carte to 610 410 because it will be the coord of my grid*/
_root.carte._x = 610;
_root.carte._y = 410;
/*I create a nex LoadVar object which will contain all my var loaded from the info.txt
file. So monLevel will have all the info about the level you load*/
monLevel = new LoadVars();
//loading the info.txt file
monLevel.load("level"+numlevel+"/info.txt");
//if the load is ending
monLevel.onLoad = function (succes) {
//if load with succes
if (succes) {
//while we're not at the end of the scenery lines
for(j=1; j<=monLevel.ligne; j++) {
niv++;
//while we're nit at the end of the scenery cols
for(i=1; i<=monLevel.colonne; i++) {
/* I create a new empty MC and named it i.e for the first one L1_1
(first line first col)*/
_root.decor.createEmptyMovieClip("L"+j+"_"+i,niv);
/* I define its X and Y pos. Why 600*(i or j -1)? Because the height and
width of the MC equal 600 and the first one is on the 0,0 coord. Ok?!
Don't forget that the "center" is on the UPPER LEFT CORNER.
That's why I get 0,0.*/
_root.decor["L"+j+"_"+i]._x = 600*(i-1);
_root.decor["L"+j+"_"+i]._y = 600*(j-1);
// I load the swf in the MC. i.e 1_1.swf is load in the L1_1 MC.
_root.decor["L"+j+"_"+i].loadMovie("level"+numlevel+"/"+j+"_"+i+".swf");
/*This code is for the map. I create an empty MC which receive the jpg
of the part we made. i.e the part 1_1(.swf) I create the
L1_1 (but onthe carte MC) and load the jpg on it.*/
_root.carte.createEmptyMovieClip("L"+j+"_"+i,niv);
/*my carte (french word for map) is 10 times smaller than my decor.
I do the same than above but now for the carte clip*/
_root.carte["L"+j+"_"+i]._x = 0 + 60*(i-1);
_root.carte["L"+j+"_"+i]._y = 2 + 60*(j-1);
//And then I load jpg on it
_root.carte["L"+j+"_"+i].loadMovie("Level"+numlevel+"/"+j+"_"+i+".jpg");
niv++;
}
}
/* this two lines are here to move the decor to the correct
part of the scenery. Rligne is the var telling on which line your spaceship
will appear, Rcolonne is the var telling on which col your spaceship
will appear*/
_root.decor._x -=600*(monLevel.Rcolonne-1);
_root.decor._y -=600*(monLevel.Rligne-1);
// I init the var of the decor
InitVarDecor();
} else {
trace ("Nom chargé")
}
}
}
/*************************************/
/* this function scroll the decor and set up the new coord of the spaceship*/
function ScrollDecor (objet, MonDecor) {
// if the center of my object > D
if (objet._x > D) {
for (m=niveau-20;m<=niveau;m++) {
_root[objet.ligne+""+objet.colonne+"Missile"+m].removeMovieClip();
}
//I move my X decor
MonDecor._x -= 600;
//I add 1 to the var telling us in which cols is my spaceShip
objet.Colonne += G + 1;
//I redefine my X object. My object get out by the right, so it appears by the Left
objet._x = 1;
} else if (objet._x < G) {
for (m=niveau-20;m<=niveau;m++) {
_root[objet.ligne+""+objet.colonne+"Missile"+m].removeMovieClip();
}
//Same thing as above but for the left side
MonDecor._x += 600;
objet.Colonne -= 1;
objet._x = D - 1;
};
if (objet._y > B) {
for (m=niveau-20;m<=niveau;m++) {
_root[objet.ligne+""+objet.colonne+"Missile"+m].removeMovieClip();
}
//same thing as obove but for the lower side
objet._y = H + 1;
objet.ligne += 1;
MonDecor._y -= 600;
} else if (objet._y < H) {
for (m=niveau-50;m<=niveau;m++) {
_root[objet.ligne+""+objet.colonne+"Missile"+m].removeMovieClip();
}
//same thing as above but for the upper side
objet._y = B - 1;
objet.ligne -= 1;
MonDecor._y += 600;
};
}
SOME OTHER LITTLE THINGS
Some things to tell you.
THAT'S ALL
If you have some remark, or feedback plz mail me to [email:xxlm@netcourrier.com]