Thursday, November 27, 2008

Flash Tutorial: Part 3 of 21

If you have skipped lessons, use the PREVIOUS POST bar on the right side to navigate to the correct lesson.

There are no pictures in this post yet (as of Thursday, Nov 27). I will make some up if I feel like it later, or if someone tells me some part is confusing.

Welcome to Lesson 3! First, we’re going to organize our project a bit more. Some of these are optional, but I recommend doing them all.

1.1 – Timeline frames
First, instead of having the project timeline only being 1 frame, I would make it have more, say, 7 frames. So add frames, and turn frame 7 into a keyframe, and move the code and objects there. Now when you run the project, the first 6 frames will be blank, and on frame 7 you can finally see the character and move him around.

The reason for these 6 blank frames in the beginning are for furture game objects, such as the title screen, the title menu, any cutscenes, and the flash preloader. I usually set aside 10 frames for those, but for now, you can have 6 frames… or 3 frames… or 10 frames… or 20 frames… it’s up to you.

Protip: For now, since there is no preloader or titlescreen, you can save a bit of time each time you test the project by going to frame 1 or 2 and put in
gotoAndPlay(9);

so you don’t have to sit through frames 3-8.

1.2 – Timeline layers

On the timeline, create and add a few more layers, and create a keyframe on frame 10 on each. Name these layers as follows: “code”, “gc”, “code_objects”, and “main”. In the future you can add more layers. Move your “main” to the “main” layer, and the moveTimer to the “code_objects” layer. Move the actionscript code to the code layer, and move the code layer to the topmost layer.

I generally like to keep the code layer blank, and just have the actionscript there.

1.3 – MoveTimer

Make another layer in the moveTimer, and separate the code and the image into the two layers. Now, we’re going to make a slight change to MoveTimer. We programmed it one way in the previous lesson to make it more understandable, but now we’re going to change that so it works better.

In Frame 3, remove the code, so that it doesn’t go back to frame 2.

At the top of Frame 2, write

stop();
this.onEnterFrame = function()
{

And at the bottom, close the bracket.

}

What this does is it will stop Flash at frame 2, and then the “onEnterFrame” code will run, and it will run on every frame. It does the same thing as the first method, except that it’s easier to use, later when we might want to stop the moveTimer. Run the project to make sure it works the same.

Those are enough organization changes for now.

Wall Touching

I hope you’ve been working hard on the wall problem. So after experimenting with it, you probably have noticed that you can’t just use hitTest to detect walls, because once you detect a wall, it’s already too late.

So maybe you can undo your move… so you might’ve had something like this:

if (Key.isDown(Key.LEFT))
{ _root.main.player._x-= moveSpeed;
if (_root.main.player.hitTest(_root.main.ledge))
{ _root.main.player._x+=moveSpeed;
}
}

So you would move the player left regardless of whether or not he was touching the wall, and then you check if he is now touching the wall. If he isn’t, then no problems. If he is, then “no way buddy! You’ve gone past the line. Go back to where you came from!”

So that’s great. Note that instead of +=10 or ++, we’ve upgraded to use a variable. Declare and initialize the variable in frame 1 of moveTimer, and then you can use it as you please.

Now, let’s turn the above into a function, and make it more robust so it can be used for both the y direction and x direction. So back in frame 1 of moveTimer, declare this function

function CheckWalls(xm,ym)
{ _root.main.player._x+=xm;
_root.main.player._y+=ym;
if (_root.main.player.hitTest(_root.main.ledge))
{ _root.main.player._x-=xm;
_root.main.player._y-=ym;
}
}

And you would call it depending on your different directions with parameters (moveSpeed,0), (-moveSpeed,0), (0,moveSpeed) and (0,-moveSpeed). Got it? Good. Test it out!

If it works, great. If it doesn’t, I hope you find your mistakes. In the future, you’ll have to make this function be able to work with multiple walls. Read the challenge section at the end of this article for more details. I mean, I could tell you how to do it now, but isn’t it better to make you learn it?

Globalcode

We’re going to use this soon, so let’s make it. Make a new movieclip symbol, in the same way like moveTimer, and put it on the stage on the gc layer. Unlike all the other objects in the timeline that only exist on frame 10, make globalcode exist on all frames.

Open up globalcode, and put a keyframe on frame 100. on it, put

stop();

Give it an instance name of “gc”, and we’re ready to continue.

Dynamically Creating Movieclips

Before Dynamically making something, we’re going to create a regular bullet and test it out, and make it act like we want it to act.

Task 1: Make a bullet (could be anything, for example, a green circle). For now, test it out by putting it on the screen, and make it move horizontally quickly. Do not modify moveTimer for this.

Newbie help: In MoveTimer, if we held a button down, every frame moveTimer would tell _root.main.player’s _x property (or _y property) to change. We can make it so that an object can tell itself to change. For that, we can use this._x or just simply _x.

Test it out. If it doesn’t work, then… umm… you did something wrong, or you’re missing something. Try again!

Challenge 1: Make the bullet accelerate.

Task 2: Modify the moveTimer so that when you press the space bar, the bullet resets itself to the player’s position. Feel free to nudge the bullet up and down and left and right as necessary*.

* - more on that later

Challenge 2: If you made the bullet accelerate in challenge 1, then make it behave as you want here.

Now whenever you press space, the bullet will reappear where you are, and then travel right.

Now, it’s time to teach you about dynamically making movie clips. We’ll do this pretty quickly without getting into too much mumbo-jumbo.

First, open your library, and right-click on your bullet, and select “Linkage”. In the window that appears, select “Export for Actionscript”, and then that other thing will automatically get selected for you. You can type in anything you want in Identifier, just like you can type anything you want as an instance name. For now, keep it bullet.

Go back into moveTimer, where you hit Space, and replace the code in there with

_root.gc.CreateBullet();

Why? Because I think bullet creation is a generic thing, and that it shouldn’t belong in the moveTimer. This function will get more complicated as we continue, and we don’t want to complicate the moveTimer too much.

Go back into your globalcode, and create a function:

function CreateBullet()
{
trace(“I’m making a bullet”);
}

See if it works.

On Frame 1 of globalcode, put in

var bulletIndex = 0;

Now… the new code.

function CreateBullet()
{
_root.main.attachMovie(“bullet”,”b”+bulletIndex, 200+bulletIndex);
_root.main[“b”+bulletIndex]._x = _root.main.player._x;
_root.main[“b”+bulletIndex]._y = _root.main.player._y;
bulletIndex++;
if (bulletIndex >= 300)
{ bulletIndex = 0;
}
}

OKAY, LET’S BREAK IT DOWN.
- attachMovie is a flash code that.. attaches a movie clip.
- _root.main.attachMovie means that we’re attaching the movie clip the _root.main.
- The first parameter of attachMovie, “bullet”, is which movieclip we’re attaching; remember, it’s not the instance name, or the movieclip name, but it’s the identifier we typed in before.
0 The second parameter is the new instance name we’re giving to the bullet we’re making. In this case, the first bullet we make is “b0”, the second “b1”, and so on. I hope you understand this >_>
- The third parameter is the Depth of the new object. Let’s take a minute to talk about depths.

///////////////////////////////

Everything on the stage has a depth. The depth determines how it will appear to the user, or what overlaps what. Each object’s depth is unique – no two objects share the same depth. If two objects try to share the same depth, the first object ceases to exist.

Movieclips that are dynamically created are assigned depths, between 1 and, like, 1.6 million or something. Movieclips that are already on the stage (such as player, main, moveTimer, etc) have depths between -1 and like, -255,000.

You can find the depth of an object by using its getDepths(); function, or you can give it a Depth by using its swapDepths(someNum) function.

Objects with positive depths can be removed dynamically. Also, objects with positive depths… tend to… linger on the screen. But that’s something more advanced that we’ll talk about later.

/////////////////

function CreateBullet()
{
_root.main.attachMovie(“bullet”,”b”+bulletIndex, 200+bulletIndex);
_root.main[“b”+bulletIndex]._x = _root.main.player._x;
_root.main[“b”+bulletIndex]._y = _root.main.player._y;
bulletIndex++;
if (bulletIndex >= 300)
{ bulletIndex = 0;
}
}

Back to the bullet. So here we give it a depth of 200+bulletIndex, so the first bullet will have a depth of 200, the second 201, etc. Note that the player’s depth is negative, so the bullets (which have positive Depth) will always appear on top of the player.

That completes the attachMovie function. Next you want to set the new bullet’s attributes, or properties.

This is just something you have to remember, when you want to combine a variable and a non-variable into finding an object. So _root.main, as usual, then instead of a period, you open up a square bracket, and type in everything as you want it to appear (so “b”+bulletIndex), and then close the bracket, put the period, and then the property.

So now we set its x and y position to the player, otherwise they’d be zero. You can also set other variables here too. So if on frame 1 of bullet, you have

var xSpeed; //without assigning it

then in CreateBullet you can have

_root.main[“b”+bulletIndex].xSpeed = 7;

Try that out. Declare the variable in the bullet, and assign it in CreateBullet, and use the variable to determine how the bullet moves.

Does it work? I hope so! Continuing on…

Next we increment the bulletIndex. If we don’t do this, then we would just keep spitting out b0’s, instead of going on to b1’s and so on. And then the depth would never change, so our old bullet keeps being reused.

Lastly, we put a limit on the number of bullets we have. We could let it go onto infinity, but… we’d rather not. If you want, you can variabalize the 300 into a variable so you can change it (and refer to it) when you want to.

So… does it work? I hope so!

Okay, so right now, when you create a bullet, it keeps going and doesn’t disappear, until you replace it. But of course, bullets should disappear. You’ve created the bullet dynamically, so it makes sense if you can remove it dynamically. And you can.

In your code which tells the bullet to travel right every frame, you can put in more code, such as checks on whether or not the bullet should die or not. See if you can follow this:

if (_x > 700)
{ delete this.onEnterFrame;
removeMovieClip(this);
}

The delete command is optional in this case, but you can probably guess what it does. The removeMovieClip is another flash function, and it’s pretty self explanatory. It takes in one parameter, which is the movieclip which requires removing, in this case, the bullet is removing itself.

Got it? Good.

Challenge: Make it so that there’s a firing delay of about half a second in between shots.

Challenge: Make it so that the bullet fires in different directions, depending on which way you are facing.

Challenge: If you did the challenge above, then add additional bounds for removing the bullet as necessary. Remember, at this point, you should already be using a lot of variables, so you can easily change things as needed.

Player Nesting/Depth and Animation

We’ll touch briefly on this before the lesson ends. You will probably want to add animation to your player pretty soon, rather than having this blue box walk around. It doesn’t even have a face! So, first, spend a few seconds or minutes or hours drawing or importing the graphics you want. You probably want

Graphic for facing up
Graphic for facing down
Graphic for facing left
Graphic for facing right

Optionally, you can have

Graphic for walking up (and etc)
And/or
Graphic for Shooting up (and etc)

For now, I’ll assume you only need the first 4. Now, let’s talk about Nesting, or Depths.

I was going to make pictures for all of them, but instead, at least for now, I only have pictures for what I'm using in my current game, at the bottom of this section.

It’s really a personal choice, or if you can foresee the future, then you can figure out what’s the best way to do it. So you can have this:

#1111
Your player object can be all the graphics that the player need to go through. So your player object looks like this:

And if you want to change its animation, you would use

_root.main.player.gotoAndPlay(“runright”);

#2222
Each of your specific player animations have their own movie clip. So if you want to change its animation, you would use

_root.main.player.gotoAndStop(“runright”);

#3333
Your player object may have some code, so inside the player object, you have a player_graphic movieclip, which looks like your player from #2222. If you want to change its animation, you would use

_root.main.player.graphic.gotoAndStop(“runright”);

Hitboxes

For now, your player is a square, but if you’re making a 2d-sidescroller, it’s usually not a great idea for a hitbox to encompass the whole player. Part of it is due to the way Flash’s hitTest works; it basically takes the bounding box of the player. So instead we make a hitbox, which is just a transparent rectangular shape, which we'll name "hitbox". But like the graphic, you have several options:

#1111: The whole player is the hitbox

So when you want to have it hit something, you would use

_root.main.player.hitTest();

#2222 There’s a hitbox that’s constant inside the player

So no matter what animation the player has, the hitbox is some fixed area, so

_root.main.player.hitbox.hitTest();

#3333 Each different animation has a fixed hitbox for the entire animation

_root.main.player.graphic.hitbox.hitTest();

#4444 If you’re crazy enough, each different frame in each different animation has its own hitbox.

_root.main.player.graphic.graphic.hitbox.hitTest();

And so on. It’s up to you. For my latest project, I used #3333 for the player animations, and #3333 for the hitboxes.


In the pic above:
1. This is what my "player" object looks like:
2. It's two layers, with two frames total; a graphic at the bottom encompassing both frames (not two keyframes), and two actionscript frames. The first frame is in #3:
3. The first actionscript frame - declaring and assigning a few variables.
4. The second actionscript frame - stop();
5. The graphic layer is just an instance of the object "playergraphic"
6. In my "player" folder, I have, player, playergraphic, and a few other player movieclips.
7. These are some of the sprites I'm using in my game. They're in a different folder than the player folder for better organization.


In the pic above:
1. This is the playergraphic movieclip. It's composed of 3 layers; first layer is blank, just has the different names for the different keyframes. The second layer is the graphic for the particular animation, and the third layer is the hitbox. Note that there is no actionscript anywhere in this movie clip.
2. So, some animation frames just have the bitmap/gif of megaman, because he's not animated.
3. Meanwhile, some animation frames hold different movieclips. If you go into that movieclip,
4. you'll see that it's composed of several keyframes, each which holds an unanimated bitmap/gif. It will loop through these gifs as long as this movieclip is showing.
5. The third layer is the hitbox, which should be transparent but for these pictures I made them slightly visible. The hitbox is different depending on which animation your character is doing.


Challenge: Incorporate the 4 (or more) graphics into your game.

This basically brings us to the end of the lesson. I have an asterisk above which I need to take care of… sigh.

So the asterisk was back when we created the bullet, and it wasn’t centered on the player; it appeared at the top left co-ordinates of the player. FOR NOW, we will keep most of the things like this, but you might have a different opinion. Anyway, there are two… philosophies on this.

Basically, whether or not the 0,0 reference point is at the top left of the object, or at the center. If it’s at the center, then yeah, the bullet would appear in the center of the player, because that is the player’s x and y.

Maybe it’s because as I learned flash, I didn’t know about hitTest, so I used my own way of testing whether or not two objects collided, and it was easier this way. But, whatever, we will keep it like this.

Challenge: Make the bullet appear at the center of the player, without changing the bullet’s or the player’s center reference point.

And that’s it for Lesson 3. Here are all the challenges:

Challenge: Make the bullet appear at the center of the player, without changing the bullet’s or the player’s center reference point.

Challenge: Make the bullet accelerate.

Challenge: Make a firing delay of about half a second between bullets.

Challenge: Make the bullet travel in the 4 directions, depending on which way the player is facing.

Challenge: If the bullet can go in more directions, add additional bounds for removing the bullet.

Challenge: Incorporate graphics into the player so that it has a different graphic for each direction.

Challenge: Multiple Walls. Take note on how we dealt with the special bullets. You might want to make a few more functions in MoveTimer. Use a for loop (or if you want to be extra special, a do/while loop).

Assume 10-15 walls. Don’t go crazy trying to detect 200 walls every frame.

Syntax for For Loop and Do While Loop

for (var i=0; i < style="font-weight: bold;">In the lessons to come: Answers to challenges, scrolling, “quadrants”, Wait, Item Class, Enemy class, Projectile class, and more.

0 Comments:

Post a Comment

<< Home