Jacks_Depression

Jacks_Smart Loop

Posted: 2009-10-03 15:25:21

A year or so ago I read an interesting article about the many different approaches to a main loop. I wish I could share it with you but it seems I lost it. Either way, its no relevant to this post. I just happened to be on my mind a lot as I was coming up with the movement engine for Smart Defense. That right, another post on Smart Defense. Majority of the traffic to my blog is interested in this little side project of mine. But who would not be interested in an open source flex/flash strategy game.

I am back to work on it since everything else has dried up and I hope explain it while I am working on it. That way, when finishing the project up, I don't have to write a ton of documentation. In this post, I want to cover how all "movable" objects get from A to B and beyond. Starting with my main loop...

Flex and Flash will not cooperate nicely if you attempted a formal Main loop.

while(true)
{
    renderFrame();
]

Thats not how it was designed. Flash is intended to take the nitty gritty out of animation, and as its success shows, it is doing a damn good job. As such, you do not need to worry about is frame rates, swap buffers, and graphic languages. Except, that brings a whole now can of worms into the picture. If Flash is managing all that on its own, where are you supposed to put all your game-like code? Well, thankfully, their main loop fires off an event on every cycle, so you can tack you code on to it. That would be, the well known onEnterFrame.

Application.application.systemManager.addEventListener(Event.ENTER_FRAME, idle);

The concept of an idle event is also something well known in game programming. The Idle event is called repeatedly, without end. This is the same concept as a main loop, just doing it through an event rather than the loop it self.

So then I ask the question that earns me the big bucks: I know Flash/Flex runs on a fixed frame rate. What happens when the execution of rendering the frame takes longer then the gap between frames? Simply, the frame rate slows down. So the fixed frame rate is not fixed at all. It just is given an upper limit. It renders as fast as it can without going over that number.

What does this mean for Smart Defense? It means that having the game move slow is out of the question. I assume things will get rather hectic on the battle field. I am assuming that half the people who play this game will not meet the upper limit of the frame rate.

If I thought every person who played this game would be making at the same frame rate, then I would of simply made each "movable" sprite move a fixed distance every frame. This would be a lot easier to program. But since I have higher standard than that, I have done things a little different. Graced with the knowledge of the true meaning of vectors, I decided to put them into action. The term "Vector" is tossed around a lot these days for things I would not deem appropriate. From hence forth, if I use the term vector, I am referring to this definition: A formula that will return a point on an axis given other axises. For instance, in Smart Defense, I calculate a "movable" sprite's X and Y location based on time. A lot of other data points come into play. But that is the basis of the vectors I am using.

So, lets jump a little more into the code.

public function idle(e:Event):void
{
    for(var r:int = 0; r < this.runners.length; r++)
        this.runners[r].updateLocation();
}

So far, pretty easy. On every frame the list of "runners" is gone through and updated in no particular order. I will spare you the "runner" management code. Its pretty simple. I will assume you can do that much on your own. Also, "runners" are not the only things that are "moveable" to I gave them a common "moveable" subclass.

public function updateLocation():void
{
    var timeTravled:Number = secondsFromOrigin();
    var distanceTravled:Number = (timeTravled * this.moveSpeed);
   
    var location:Point = this.pointOnLeg(distanceTravled);
    this.x = location.x;
    this.y = location.y;
}

Much more complicated now. First we get the number of seconds elapsed since it was placed in the world. Then to get the units (or distance) the "moveable" object has traveled. The movement speed is stored as units (pixels in this instance) per second. For instance, a movement speed of 5 pixels per second is stored as a 5. Then we calculate the vector.

Think for a second the number of possibilities we have already opened up. Time is not constrained. In fact, time is not even a factor in the vector function. With this you can have a game where you rewind, fast forward and pause all game activity. So, the game is mostly independent of time.

import flash.utils.*;
public function secondsFromOrigin():Number
{
    return getTimer() / 1000.0;
}

This is just to get the seconds elapsed since last frame, so we can make up for slower computers. Now finally, the vector function you have been waiting for.

public function pointOnLeg(distance:Number):Point
{
    var precentTravled:Number = 1.0 - ((1.0 / this.legDistance) * distance);
    return Point.interpolate(this.legOrigin, this.legGoal, precentTravled);
}

In my version, I have the "moveable" sprite going through way-points. The information for each is cached within the sprite. So, we simply find how far along its journey it has traveled, then we place it there with some Flash magic. See the documentation on Point.interpolate if you wanna know more about how it works. You have the basics for moving sprites around in Flash/Flex completely independent of frame rate.

My next challenge is to see if I can move a sprite along a curved vector.

More in Smart Defense soon.