Wednesday, December 03, 2008

Flash Tutorial: Part 4 of 21

In this Lesson: Multiple Walls, "Quadrants", Scrolling, Flash Placements, and Wait

if (Key.isDown(Key.LEFT))
{            if (CheckWalls(-moveSpeed,0) ????)
            {            MovePlayer(-moveSpeed,0);
            }
}

The ???? up there can be any number of things. It could be == true, == false, or, what I am using right now, is > 20.

Protip: If you have a boolean value, you don't need to compare it to anything in an if statement. I mean, if(amIDoneYet == true) is the same as if(amIDoneYet).

Newbie tip: Useful syntax for if statements include ==, >, <, >=, <=, !=, &&, and ||.

In the last lesson, you used the square brackets to tell flash to modify different objects' properties, where the object's name was a combination of constant and variable name (for example, "enemy"+i).

So if you can modify a property like that, you can surely access the object like that. So instead of using hitTest with ledge, you can now do it with ledge0, ledge1, ledge2, etc. Therefore, you now modify your CheckWalls method to look something like this below. I'm using the method that returns an integer.

function CheckWalls(xs,xy)
{
            var hittingWall = 50;
            _root.main.player._x+=xs;
            _root.main.player._y+=ys;
            for (var i=0; i < _root.gc.numLedges; i++)
            {            if (_root.main.player.graphic.hitbox.hitTest(_root.main["ledge"+i]))
                        {            hittingWall = i;
                        }
                        
            }
            _root.main.player._x-=xs;
            _root.main.player._y-=ys;
            return hittingWall;
}

//you can return true, or false, but I'm returning an integer instead - because it's more useful than just a boolean value. You can do whichever you want.


Protip: This is a tip that I know about, and I SHOULD use more, but I don't... but I should >_>. By now, your code would probably be a bit different than mine. I have _root.main.player.graphic.hitbox, while you might just have _root.main.player. So what can you do? You can use a variable. In your first frame of globalcode, or if you want, first frame of _root, you can try:

var gamePlayer = _root.main.player.graphic.hitbox;

That's right. You can put objects or movieclip refernces into variables. Try it out if you want.


and of course, the MovePlayer function is

function MovePlayer(xs,xy)
{            _root.main.player._x+=xs;
            _root.main.player._y+=ys;
}

Try it out. Make multiple ledges (maybe 4-10) and see if it works. Make them different sizes, make some of them connect, do whatever. Remember to name them properly and assign any variables correctly.

"Quadrants"

I'm not sure how other programmers deal with this, but I call them quadrants. Long story short, if you're making a big game, you'll probably have over a thousand walls.. and you're not going to tell Flash to check for a thousand walls every frame. That's 30,000 operations per second, which is pretty inefficient, considering that you'll probably only see 1-20 walls on the screen at any given time. My solution: Quadrants.

A quadrant is a section of the game, and each quadrant has a finite amount of walls (among other things). So when you do the loop, instead of checking for 1000 walls, maybe instead you'll look for 10, 15, or 20. If you're making a zelda game where each screen is unconnected to other screens, maybe 1 quadrant is one screen. If you're making a sidescroller, maybe your quadrants aren't as specified.

FIRST, if you're already making another game that wouldn't need to use quadrants, save it as something else. If you're going to use this tutorial to the fullest, you're gonna want to make quadrants, but there's no point doing that if you're having a game that doesn't need it. If you've already started on another game idea, you may want to start a second game idea that would use these quadrants.

Now, we can start implementing quadrants. First, go into your globalcode, and use one of these:

var cq = 1;                        //current quadrant
_global.cq = 1;                        //current quadrant

The above is for the sidescroller. If you're make a zelda game, you may want to use this:

var cx = 1;
var cy = 1;

or

_global.cx = 1;
_global.cy = 1;

//note you can use 0 instead of 1, it's up to you

If you're making a zelda game, you'll probably need a 2dimensional quadrant... space... thing...

Next, you'll want to rename your current ledges so they make use of this information. So some ideas are:

q1ledge0
q1l1

or

q1x1yledge0
q1x1yl0
q1x1yw0

or whatever. Ledge, Wall, whatever. Only bad thing about ledge is that the lowercase L looks like a 1, so you may want to start using the w.

FROM THIS POINT ON, WE'RE WORKING WITH A ZELDA GAME, so WE'LL USE THE TWO-DIMENSIONAL QUADRANT SYSTEM.

Now you need to apply it in the code. I would usually apply a CHALLENGE here, but instead, I'll type it out. However, you should have a good idea of what you need to do before you scroll down.

The old usage was: _root.main["ledge"+i]

The new usage is below - try to figure it out before you scroll down:







_root.main["q"+_root.gc.cx+"x"+_root.gc.cy+"y"+"w"+i]

The +"y"+"w"+ is redundant above, but I just wanted to break it down for you. Fix it to just +"yw"+, unless you like it the old way.

After this, try out your game. If done correctly, everything should still work.

Now we're going to test other quadrants. Change the names of the some of the walls so that it has a different quadrant number, so for example, change
q1x1yw3 to q2x1yw3.

Test the game, and you should be able to go through that wall now.

Now, make a new object, like a rectangle or something, put it into your main, and give it the usual onEnterFrame loop, with

if (this.hitTest(_root.main.player.graphic.hitbox))
{            _root.gc.cx = 2;
}

And another one to change it back

if (this.hitTest(_root.main.player.graphic.hitbox))
{            _root.gc.cx = 1;
}

Test the project. If it works properly, then you can just hit the new object and it will change quadrants for you, and thus enable and disable different walls for you.

For the time being, you probably don't have to worry about quadrants too much, unless you want a big playable level. At least, you should do some scrolling first.

Scrolling

Task 1: Go into your main and place your player at the center, which should be about 300,220.

Challenge: Make it so that when you move around, the player stays at the center of the screen, and everything else scrolls.

Hint 1: Edit some code in the moveTimer.

Challenge 2: After you get this to work, you can try to make scrolling work the way you want it to.

Flash Placements

I'm not sure how other programmers deal with this either... but long story short, the flash stage editing document... doesn't have infinite width or height. I mean, if you zoom out, you can see the boundaries. You can try putting some walls around, try moving them off the boundaries, and you'll make the bounds a bit bigger, but eventually, it stops.

Of course, you don't want to stop the level there. You want it to keep going. How do you do it? Mass Moving.

You create a portion of level where you can, and then you use code to move it.

First of all, in main, make a second frame, with stop(); at the top. This second frame is a keyframe for the actionscript, BUT NOT for anything else. Everything else should just be there on frame 2, not have a keyframe.

This is a precaution we're putting in... flash is a bit confusing with things existing in different frames...

For now, this code can be used on frame 1, so we'll put it there. Ya know what... I'll give you some piece of code, and I'll just pretend you can understand it.

for (var i=0; i < _root.gc.numLedges; i++)
{            this["q4x1yw"+i]._x+=3000;
            this["q4x1yw"+i]._y+=700;
}

Quite straight forward I think, or I hope.

Wait

Wait is another function made by me, which I learned from other places. I think you can use it as a function, but I just retype the whole thing whenever I need to use it. We use this when we need to time something, or we have a cutscene and we need it to stop at a part for a few frames, and so on.

Anyway, for this part, make a new project. As usual, Actionscript 2.0, Flash Player 7.0, 30fps, etc.

Make an object (circle or square or whatever, doesn't matter). You can make a moveTimer, or you can put code into the object itself, doesn't matter since it's a test project.

Our goal is to make a little movie, where the circle starts at the top left corner, waits there for 2 seconds, then moves to the right for exactly 2 seconds, and then stops and waits there for 2 seconds, and then goes down for 1 second, and then stops.

You might already know how to do this. Anyway, we're not going to use the moveTimer for this, and we'll just put everything into the movieclip itself.

On the first frame, just declare a variable:

var timeWait = 60;

protip: If you want, you can put the 2nd frame in the first frame, but for organization, we'll do it this way.

When the movie clip plays, it will play the first frame, and then get to the second frame. On the second frame, we stop it, and:

stop();

this.onEnterFrame = function()
{            //do nothing
            timeWait--;
            if (?????)
            {            ?????
                        ?????
            }
}

Take a few minutes or seconds to think about it, then scroll down.



stop();

this.onEnterFrame = function()
{            //do nothing
            timeWait--;
            if (timeWait <= 0)
            {            delete this.onEnterFrame;
                        play();
            }
}

So for 60 frames (2 seconds), you do absolutely nothing, and then you can go onto the next frame, where you might have



timeWait = 60;
stop();
this.onEnterFrame = function()
{            _x+=2;
            timeWait--;
            if (timeWait <= 0)
            {            delete this.onEnterFrame;
                        play();
            }
}

Get it? Good.

Challenge: Complete the rest of the steps to make this move as described, or do whatever you want!

Protip: In all cases so far, we've used this.onEnterFrame following a stop(); You don't need to use stop();, but for our purposes, we've used stop(); Maybe later on you can try it without stop();.

0 Comments:

Post a Comment

<< Home