Gaming Your Way

May contain nuts.

The last day...

So today is the last day I should be working on GMM. I've got a bit of a confession to make ( Well two actually ).

The first one is that today isn't actually the real deadline. I don't know when that is, I think 4 weeks or so away. That's when the client starts emailing a lot more and things start getting slightly strained. That's when clients are still firing off "It's perfect. Can we just alter...". That's when you're sick to death of it. The deadline is when you realise you've really under quoted on this job as you're still killing yourself trying to get it done on time. It's when you regret having those couple of lazy days and when you realise that the next job isn't already in the bag yet, so you've got both a game you're pretty jaded with to finish off, you've also got to whore yourself around to make sure the following months bills are paid.

Then why have I been counting today as the deadline ? Because you need to work to the budget and not the timeline ( Where possible ). You have your day rate and you divide the budget by that, that's how many days work it is.
When I started off trying to get into the industry and was just writing games to learn my art, I always did that even then ( Although my day rate was a lot less in those days. A couple of years experience and some shiny awards bumped that up ). It stops feature creep and ensures the game is done, not 95% done but good enough to release.

Now with GMM there was very little budget. No where near enough to do what was needed. Sometimes projects are like that, and sometimes you have to take a short term hit for a longer term gain. After seeing the assets and chatting to the client I knew I wanted to do this, so the hit in my pocket wasn't an issue ( Or rather not enough of an issue ).
So I did the above budget/dayRate=days formula, and then multiplied it by 2. I thought it would be possible to still make the game everything it should be in that timescale ( 10 working days ). In effect after day 5 I was making a "loss", and every day spent on it after today ( It's day 10 already ) I would be making a loss on my cheaper rate.

It's hardly the end of the world. I still think Flash developer wages are stupidly inflated compared to real life. A loss when earning good amounts is still better than a lot of people having to dig holes in the street or change patients bedding. It's all relative.
I speak to quite a few London based freelancers who charge a lot more per day than I do. That's great if you're working on some big ass media campaign where there is a silly budget involved. Rip the arse out of it, but personally I'd rather do the odd job that doesn't make as much rather than this rigid "£xxx" per day.
GMM is going to be a good little game, and if I'd stuck rigidly to my day rate then either I wouldn't have got the job or I would have had 5 days to do it, which would have resulted in a crap game ( 3 days to make it, a day to test and debug and a day for client amends. Hardly the most time in the world to make something shine ).

I think that's one of the key reasons why there are so many piss poor adver-games out there ( Don't believe me ? Check out thefwa. Filter it to show games, and have a play. They will look great, but tell me how many you'd play more than once. Or even how many you enjoyed playing. Or even how many you admire as examples of good gameplay ).
It's mainly due to the lack of good coders, never mind good game coders. This shortage means that either designers "Who can code a little" are making very pretty but very empty games, or agencies are getting freelance coders on board who know they can charge £xxx a day and sometimes it means there's not enough budget to make a good game, just enough to cover their costs and have something come out the other end ( There are of course other factors, clients with no concept of games, designers with no concept of games etc. ).

I don't think there's anyone to blame, and I don't mean it as a blankit critisim of freelancers ( Far far from it ) I'm just trying to put into lots of words that sometimes the art should come first.

Right I mentioned at the start that I had two confessions. The second is that the game isn't done yet. In fact the to do list has hardly been dented.

The "hidden baddies" proved to be a real bitch to get working, and as soon as I post this up ( And after a smoke, obviously ) I'm back onto the baddie bots ( Pac Man ghosts ) which I spent just under 4 hours on yesterday and need at least a couple more hours today to finish off.

Squize.

And on the 8th day...

It's all got a bit blurry what's been done when. That's what happens when your diary slips, it just merges into whole big lump of vague memory.

I finished off the last entry about adding a play again button to the game complete screen. That's done, so the whole ability to play the game from start to finish and start again is in. Feeling like a proper game now.

I spent a long time adding the trap doors to the game. The traps themselves were straight forward enough, I just had a real problem getting rid of them once they were triggered. It all worked fine, you'd fall down a hole, recover, leave the screen but when you came back the trap would be there again. Glaring at you. It was just a silly mistake on my behalf, but took ages to find.

After that the water traps were pretty straight forward, they just used a lot of the same code. The only slight snag with these was the falling down splat on your face animation. It's a big bigger than normal ones and in one direction there would be a depth sorting issue with the players arm sticking out too far. A quick kludge check, and it's all good.

I also added in the preloader and a pause mode, and it's always nice to test the "Quit to menu" option and it works first time. No nasty code running in the background that I'd forgotten to kill.

After showing it to the client there was a bit of an issue about the control scheme, so a quickly knocked up controls page ( Only if you've skipped the instructions, and lets face it you will. I know I would ) was dropped in there at the start of the game.

Just out of interest ( And the fact that it looks like I've done very little for 3 days so I need to pad this post out a little with some boring filler ), below is the output from our sweet notifier app which tracks all that we do

Attract Mode: 13mins
Class Structure: 10mins
Dummy Trap: 1:22
Game Complete: 58mins
HUD: 1:10
Instructions: 51mins
Level Complete: 40mins
Level Design: 1:09
Level Plotter: 7:06
Level Structure: 45mins
Pause Mode: 30mins
Player: 5:32
Preloader: 34mins
Tiles: 1:55
Transition: 25mins
TrapDoors: 3:00
WaterTraps: 1:21

All that added up should come to 49 ( 7*7 ) hours, and if it doesn't it shows that I've been a bit lazy :)
( I know it won't even be close as the last couple of days I've been sorting out the tax man and dealing with the joys of tooth ache, so the work has had to take a bit of a back seat to those ).

This coming Wednesday is my deadline. I think it's going to be a bit tight, there's some big routines to do before then, and my to do list reads as follows:

* Instructions
* Power-ups
* Bots
* Dummys
* Hidden bad guys throwing dummys
* Sounds
* Player health
* Game Over ( After losing all health )
* Owls

( I know with no real concept of what the game is that's as vague as hell, sorry, my hands are tied as always. Power-ups are collectables which you can shoot at the Bots, who are going to be pacman ghosts. Dummy's are obstacles that are triggered by hidden traps which block your path, and that the Bots can push around. Everything else I think is clear enough, oh apart from the owls :) ).
So 3 days to do all that, fix any bugs ( I've noticed a couple with the fore-ground plotter ) and shoe horn in any ammends from the client.

This is why I can't give up smoking yet.

Squize.

4

A quick little ol' recap of what was done yesterday ( On GMM ).

I designed the first level ( Using the always easy Mappy ) which took quite a while, and I think it's going to need some tweaking. It gets tricky if you leave / enter a screen on the tiles near the rear corner as you really can't see where the hell you are ( Esp. if there's a big tree slap bang in the middle of the screen ).
I'm hoping it's just a case of tweaking it slightly rather than re-doing it as today I'm at the half way point and there's very little time to dive in and re-do a whole level. Speaking of which, I'm going to hold off designing the next 4 levels until all the baddies / traps are in and working as it'll make a big difference.

Having a working level in place also highlighted a bug, where I'd miss-counted the number of tiles before changing screen, so you could walk out of one screen and straight into a wall on another. Not good.

Added some more tiles to the tileset. I think there's a couple more but they're only minor wall variations now.

Biggest job of the day was putting the level exit in there. I had a wealth of sorting issues with it ( It's huge ) and for a while I got that sinking "The depth sorting is screwed" feeling. I had visions of having to chop up this large vector object, which would have taken ages. Luckily I took the easy option and just changed the tiles alignment and that fixed it a treat ( All the "Bigger than one" tiles are aligned so the bottom right ( SE ) tile is aligned to the other normal tiles. With the exit I just altered it to being the back left tile aligned there. It would break if walking down the side of it, but some well placed wall tiles on the map stop that ever happening. Iso is so hard to explain in words, so thanks for fighting your way this far ).
So the exit is displayed, next up was getting it working. The exit is two tiles wide, so I just have to check the players x/y to the two exit x/y positions. Easy. Oh shit, the player needs masking as he walks through the exit door ( Remember the depth sorting is a big fat cheat, he can't really pass beneath tiles correctly ).
Creating a mask and positioning it correctly didn't actually take that long, it was just one of those [ Many during development ] moments of "ffs, I really don't need this".

With the player being able to complete a level now, next up was to do the level complete screen. I didn't actually get any assets for this so I just knocked up something nice and simple using the format for the game complete screen.
With the level complete screen done ( See how it all rolls into one ) it made sense to do the level bumping code, and with that the loading next level stuff.
Right from day 1 the game's been able to load and parse maps, so this was just a case of a couple of extra call backs ( No events in this game ) and figuring a way of showing that the next level was being loaded whilst you bask in the glory of the level complete screen.
Rather than add a spinner or loading bar, the level data is quite small, just over 10k atm, so I just hide the "Play next level" button until it's loaded. Lazy I know, but the majority of people have a nice fat connection these days so the wait will be a couple of seconds at most ( Plus the levels will be buffered internally once loaded, so the pause will only be there the first time you play it ).

Keeping this theme of rolling from one aspect to another, next up was the game complete screen. I just shoved some times and a bit of score in there and it's all but done.
I called it a night before finishing the "Play again?" button, so that's where I'm starting today. Right now infact. So until tomorrow, bye kids.

Squize.

How to really *#$&! things up in a flash game project

I've been silent the last couple of weeks, too silent I reckon, but ... yet again I've been oompha-loompha'ing for various projects.

One of this projects really raised the bar in several ways (I think I'll do a rundown afterward - deadline is tomorrow, really, no way of extending it, even for a few minutes).

So for now let us assume we're dealing with a purely hypothetic project (as this is not about what all went wrong during the assignment).

This fantasy project should contain this:
- a menu, 3 languages, able to load in various games
- multi language support for the games (which have been done by someone else)

As I'm used to work with Flash's strings panel it was a logical choice to use, basically you can set it to "auto" mode and all assigned Textfields will be replaced at runtime with the associated one, you can also set a new language while running and everything is fine.

Or so I thought.

The menu worked fine, but then I got the first game ... oh, now we Imagine the first game ...
Some files ...
- one 150MB fla, called "library" - LIBRARY? yes.
- one 90MB called "game" ...
- a few more files (levels), each around 90MB

OK, library mustn't mean something bad.

Or so I thought.

Library in this case means something bad. BAD. BAD. BAD.
It meant: shared library (for those of you lucky enough to have not heard about it yet ... read about here.)
Oh when you're back from reading about it, you surely think "oh, that is nice"

WAIT! Don't ever even think about thinking "oh, that is nice" when it comes to shared libraries. They are EVIL!
It's the foot and mouth disease of Flash's features.

(imagine using one)
You'll first notice that you lose control about preloading - shared libs work like things exported to the first frame BUT without being able to detect their size.

Fast forward now ...

So you have the menu using Flash's strings panel, working, now it's time to load in the first game ...
I chose to use the good old and trusty loadMovie method instead of the MovieclipLoader class. So it was just a simple load and detect the size, start when done.

OR SO I THOUGHT.

Well, I knew from other project that when loading an swf that uses Locale, the newly loaded swf (using Locale, too) replaces the language data from the holder swf. This is OK and it makes sense if you think about the fact that a static class is assigned to _global in AS2. So the game used the same language files the menu does ... easy.

The dirty details ...

The game loads in a couple of external mp3 files, so I had to take care of that, too - easy enough, so no problem there too..
This is what we see:
- loading starts, use getBytesLoaded / getBytesTotal to see when it's done ...
- tracing shows 140k of swf to load, fair enough.
- after loading that, nothing happened. For 900k nothing happened - Flash was loading in the shared lib.
- then I was able to watch the mp3 files loading and afterward start the game - finally.

The problem is that the user might think that the game isn't loading at all when the shared lib is loaded - THERE IS NO WAY OF WATCHING IT LOADING!!!!!!
First I thought I could trick my way out of it by loading the shared lib FIRST and then hope the cache would kick in when the game is later loaded - nice try buddy. No, it doesn't work (at least not very well).

I ended up by using a faked (and then real) file list to load the game, basically it shows that there are 2 files to load.
First the swf is loaded, then while waiting for it to load the shared lib, I fake a progress and later I add the mp3 files to that list also to watch them loading, too.

Now that this is off the list ...

Yehaa the game is loaded and ready to to be played ...
- level one works ...
- the "level done" screen pops up AND ... it is definitely NOT in the language I've been using in the menu. WTF?

In fact the game was now all in German, whereas I selected English for the menu.

WHY? What happened. I had no idea.

A lengthy search using your fav. search engine did not give us anything.

OK, so we're on our own again (hey, after all this is Flash).

Let the tracing begin ...

First thing I checked was the language set using Locale.getDefault():
- startup: "de" (because of my desktop language)
- set it to "en"
- (checking, yes now everything is "en")
- load game: still "en"
- play game: still "en"
- show level done: still ... "en"

BUT IT FUCKING SHOWS ALL FUCKING STRINGS IN FUCKING GERMAN!

More fast forward ...

A few hours later I have lost a good deal of hair, brain and energy and of course all the trouble is caused by ...  right . the shared library.
It seems like it overwrites the language data with it's own values but doesn't report it to Locale (so you can see it).

And they lived happily ever after ...

I ended up, oh, we "would" (we still imagine the project you know) with loading the game, loading all external files and THEN reload the language file.

nGFX

ps: next time I tell you about the joys of using art based levels that consist of over 900 vector based drawings, movieclips and components ... which take almost 10 minutes to copy and move ... joy.

Day 3

I didn't touch GMM yesterday, so to keep up the constant supply of development highs and lows I thought I'd write up today's instalment whilst it's still fresh.

Today's objective was to be able to move from one screen to another, and joy of joys, you can. It was quite straight forward, took a little while to keep track of all the sets of coords I've got to use ( The local map position, ie the tile at 0,0 on the screen, the local player position within the current screen and the player's position within the whole map ) but nothing too painful. Messed up the re-positioning of the sprite a few times ( You leave the screen at the far right you should be repositioned on the left of the next screen ) but that was where the coords above were just not clicking into place in my head.

Once that was working it needed a quick and simple transition from moving from one screen to another. A quick use of draw(), and a tweened mask and it was all done and works nicely ( Same way as the transitions are done in both Fuel-Factory and Toxic Shock. Grab a bitmap of the current screen, attach a mask to it, run the effect ).

Finally I tried adding the big ass tree tiles. These bad boys took a while, but only 'cause I'd got the keyframe order out of sync ( The tiles are old school, laid out on keyframes like the good old pre-bitmapData days ).
Once that was working they went in there a treat and with no depth sorting issues with the player ( I'll have to be careful where I position the "wall" tiles around them though, as they are huge and it could cause problems, but nothing a little bit of forward thinking won't fix, and a million times easier than splitting the tile up into 32px wide strips ).

And I think that's it. Doesn't sound like much, but it's coming along nicely. Weekend off so Monday will be spent adding the exit to the maze and testing for it, so it should almost be a game then. If by day 5 all the level progression, game over, game complete stuff is done I'll be really happy and bang on target.

Also early next week Olli should be posting about a new complete project that he's been working on for a super sexy huge name client who we're obviously really pleased to be working with.

Squize.

The morning after the night before ( II )

I did write a great entry, quite possibly the greatest prose ever written, but I / the blog messed up and it was lost.

Instead you'll have to make do with the usual shit quality of writing.

Where did day 2 take me with GMM ( That's it's code name from now on ) ?

I added in all the "surround" tiles. In a usual iso game the playfield is a diamond shape. To fill this up a little and to keep it more inline with the look & feel images I've filled this area in with tiles that will be on other screens ( If that makes sense ). Hint of blur and darkened up a little and it looks pretty damn sweet.

Next up was the player. He's in. He walks. He stops at walls. All good.

After that, the dreaded nasty depth sorting. It's not something I'm usually very good add, I always struggle to get it spot on, so I had a bit of research around how other people do it. I found the way I normally do it, ie depth=mc.x+mc.y*playField.width, and a really nice looking way which calculated the z-depth correctly.
My solution was to do something totally different.
All the tiles have a big healthy gap in their depths so I can drop sprites in-between them without there being any sort of clash of depths ( as2, no depth management here ). The player sprite finds out which tile his on, gets it's depth, and make sure his depth is higher. As simple as that.
When moving the player sprite looks at the next tile and grabs it's depth, so it's always at the correct depth ( I wish I could find a way to explain this without using the word depth so often ). There was a slight issue when moving in directions which would mean the next tile would have a lower depth than the one he's standing on ( ie, moving up, or NE ), that was fixed by only updating his depth halfway through the walk cycle.

It all seems nice and solid so far, and quite simple to do. I'm just hoping it doesn't trip over when there are bigger / taller tiles in there.

Then there was a slight bug with the actual movement. He'd drift off course ever so slightly every move, which meant that after no time at all he'd be quite a way off the tile he was meant to be on. Olli came up with the fix, which is another simple one, the player just finds out which tile he's on when he's finished his walk cycle and then aligns himself to that. Piece of piss.

I think that's it. I'm sure I wrote a lot more first time, but it's never as fun second time around. Today has been spent working on an old project which is like an albatross hanging around my neck, so no new update tomorrow ( I know I've only lasted 2 days, but to be fair I'm not missing a day out as such ). Maybe I'll post some trite eye-candy here to fill the gap.

Squize.

Dear Kitty

I started a new project yesterday so I thought it would be a good time to see how long I can maintain a diary of it's development. It's only got 2 weeks ( 10 working days ) allocated to it, so surely I can write something new and interesting every day for 10 days... well interesting is pushing it a little bit.

Starting a project is always a double edged sword. Cool, it's a new project with all the possibilities that go with it. Shit, it's a new project so I've got to set up all my usual classes for the millionth time.

To touch on things without giving anything away, it's an iso maze game. Before kicking off it was agreed it wouldn't scroll as the dev time is so tight, so it's just going to be a flick screen game like the old greats such as Head over Heels and Knightlore.

Day 1 is setting up classes. This game is going to be done in as2 ( Due to the tight deadline, did I mention that ? ) as although I've fallen for as3 at last, it's still a ball ache for a lot of things.
I've already received all the assets ( All of them. Up front. Amazing ) and there's lots of nested animated movieclips, which as2 does well, and as3 doesn't, so that helped swing me towards as2 for this one.

Hello fdt and mtasc, I've missed you bad boys. Still quicker and better than Flex. Things that are tripping me up though are Void ( It took forever to get used to void, and now going back it's taking just as long ) and _alpha, _x, _y etc. Any property with an _ basically.
It's amazing how quickly I've lost the habit of using those.

Code wise we've got the core classes in place ( Player, GameController, Master ( enterFrame mainloop ) ) and I've ripped the map loading routines from Toxic Shock ( External map files are a million billion times easier to work with ) so the game can load in it's data.
The biggest routine of the day after the LevelHandler is the LevelPlotter. I've only ever done 1 iso game before, Fuel Factory, and I'd forgotton what a pain it is to align the tiles correctly.

By the time I called it a day, we have a title screen ( No instructions button yet, and a missing anim, but almost done ), a swf that loads in it's own data and parses it, the game HUD with working timer and a 10x10 grid of iso tiles plotted. Good start to it, and I'm aiming to hit it hard again today.

Squize.

Distance Based Broadphase

Collisions, they're always a part of my games that I'm never happy with. Not so much the actual this sprite has hit that sprite part ( The narrowphase of the check ), but the broadphase, ie deciding which checks are needed and which we can just ignore.

Different genres require different ways to test for collisions. For a long time now I've been using grid based checks ( As far back as this old beauty ) in arena based shoot'em ups. Simple enough, you split the screen up into overlapping sectors, and store each baddie in the sector it's occupying.
So let's say we've split the screen up into quarters, you check each baddie's position, and store it in one of the four arrays you've set aside for each sector. Then you can run through your bullets and see which sector they're in, so in theory you're only testing the baddies which are nearest to the bullet ( There's no point testing a bullet against a baddie which is on the other side of the screen ) which in an ideal world will reduce the checks by 75%. Not bad.

The problem I've always had with this is that it feels costly to maintain. I've always just cleared the sector arrays at the start of the baddie movement routines, I've never been clever enough to come up with a way to maintain it "properly". Therefore I could have baddies that have only moved a pixel or two since the last frame, there's no way they're going to have changed sectors, but I've had to treat them afresh.
That can't be good, but like I've said, I've never been able to come up with a clever way of negating that, so I've always just done it that big dumb way.

Recently quadtrees ( Check here for a great example, and an overview by the always excellent 8bitrocket can be found here ) and octtrees are very in vogue with Flash developers, so being a bandwagon jumper I thought I'd have a bit of that.

Again, I couldn't think of really good way to maintain the structure every frame, and it felt like you'd need a lot of objects to make it worthwhile ( Or just use it as a generic collision system for every game, but I'm not a fan of that. Collisions are a weird beast where very rarely does one hat fit all ).

One aspect that all the collision methods I mentioned above have, is shown below,

dbB1.png

I'm going to generalise a bit here, but let's say we've drilled down into the correct sector / node / whatever. Our bullet is travelling along that path ( Pick which ever direction you feel more comfortable with, in my head it's going up and right ). Chances are it's never going to hit that baddie ( I know the baddie could in theory move enough to come into collision with it, but we're generalising for a second ).
So we've gone to quite a bit of effort to narrow down our collision checks, and then we're still running a check per bullet every frame when most of the time it's not going to hit ( Think of your accuracy rating at any game that checks such things. 75% is pretty good in a game. That means that 25% of all the bullets are going to miss, yet we're having to test 100% of the bullets a 100% of the time ).

This all felt a bit sucky in my head. A lot of cpu time spent on something that wouldn't happen.

Let's talks about "Distance Based Broadphase". I made that up, it's more than likely already been around for years with a different name and I've just happened across a similar idea, but it explains what it is pretty well.

I've approached it in a different way than how I normally set up the whole bullets / baddies stuff. Using DBB every baddie has an array of all the player bullets ( Well a linked list for speed ), and every time the player shoots that new bullet is shoved into that array.
During the baddies main loop it runs through all the bullets it has in it's array and checks it's distance to it ( The narrowphase checks are just your bog standard circle to circle collisions ). If it's distance has increased, then the bullet is moving away from the baddie, and it won't hit it.

dbB2.png

So looking at that diagram above, lets say the bullet is flying up to the top left. The broadphase will keep checking as the distance from the bullet to the baddie is decreasing every frame, ie it's getting closer. It's possible that it could hit it, so it's worth checking.
Once the bullet goes past the sweet spot, it's moving away from the baddie. It'll never ever hit it, so we just remove it from the array and the baddie won't check for it again.

Whilst there's a possability of a collision it's worth checking, so it's not so costly ( If you're shooting at baddies from a distance then it's going to incur a cost until the bullet goes past the sweet spot, ie 'til the bullet gets to a point where it's not going to hit the baddie. The greater the distance the more the tests as it will take a while to actually get to the sweet spot ).
Going back to the first diagram, the bullet ( If moving to the top right ) is moving away from the baddie right from the start, so it's thrown away.
In effect we're checking the general direction until we get to the point of a hit, or a miss.

Now I've done some generalisation here. In real life your baddie will be flying around throwing some great shapes. For that, you just increase the size of the sweet spot to take it into account. If you have a fixed speed for a baddie you could work out exactly the sweet spot's size ( That is you'd work out if the baddie moving at it's max speed in a straight line to the bullets path how big the area to check would be ), or if you're lazy like me you just increase the size of the sweet spot by subtracting some pixels from the distance and testing it til it stops breaking.

Hopefully I've made some sense, it's proved to be quite a fair bit to explain. As always please feel free to post a comment if you have any questions or if I've got anything wrong. I'm sure I'll be editing this soon enough to clear things up.

Squize.

Faster atan2

In the recent theme of speed testing I thought I'd better double check my atan2 results, and comparing the below method to the built in one I got the following:

runAtan2():  2161
runAtan2Quicker():  1159

( For more about how I test this stuff, please check this recent post )

Phew, something actually working quickly as it's meant to.

The following method is based on code by Jim Shima, http://dspguru.com/comp.dsp/tricks/alg/fxdatan2.htm

private static var coeff_1:Number = Math.PI / 4;
private static var coeff_2:Number;
private static var r:Number;
private static var angle:Number;
private static var absY:Number;

//--------------------------------------------------------------------------
public static function atan2(y:Number,x:Number):Number{
    coeff_2 = 3 * coeff_1;
    absY=y;
    if (absY < 0) absY = -absY;                    //Math.abs
    if(x>=0){
        r= (x - absY) / (x + absY);
        angle = coeff_1 - coeff_1 * r;
    } else {
        r = (x + absY) / (absY - x);
        angle = coeff_2 - coeff_1 * r;
    }
    return y < 0 ? -angle : angle;
}

I've used static properties / method 'cause it's part of my MathX class ( So if you're going to set up a similar way, create a class called MathX and then the usage would be,

var value:Number=MathX.atan2(y,x);

Exactly the same as the built in method ).

Squize.

Pythagorean Theorem, how quick are you ?

I'm becoming a bit of a speed testing slut with as3, and seeing how this function is used in so many games, I thought I'd have a play and see which actually is the quickest way to do this.

Point.distance() seems to have everything going for it, but does it ?

import flash.utils.getTimer;
import flash.geom.Point;

var time:Number;

var point1:Point=new Point(100,100);
var point2:Point=new Point(200,200);

var dist:Number;
var dx:Number;
var dy:Number;

function runPythagorean():void{
    time = getTimer();
    for (var i:int = 0; i < 10000000; i++) {
         dx = point2.x-point1.x;
         dy = point2.y-point1.y;
         dist = Math.sqrt(dx*dx + dy*dy);
    }
    trace("runPythagorean(): ", (getTimer()-time));
}

function runDistance():void{
    time = getTimer();
    for (var i:int = 0; i < 10000000; i++) {
         dist = Point.distance(point1,point2);
    }
    trace("runDistance(): ", (getTimer()-time));
}

runPythagorean();
runDistance();

Slap that into Flash, and be surprised at the huge difference between the two ( For those of you who prefer just to look rather than get involved, on my machine I got the following:

runPythagorean():  1452
runDistance():  10485

Not really neck and neck ).

So the distance method is a none starter ( What the hell does Flash do behind the scenes ? It's only returning a Number, it shouldn't need to be doing anything other that the code in the runPythagorean() method ).

Don't know if I've posted about it here before either, but avoid Rectangle.intersects() for the same reasons too.

Whilst I was testing I thought I'd do the old shortcut of:

var sq:Function=Math.sqrt;
dist = sq(dx*dx + dy*dy);

Again, another surprise,

runPythagorean():  1464
runPythagoreanWithShortCut():  2824

Finally, I finished off with some "quicker" versions of sqrt, ie

//---------------------------------------------------------------------------------------
function sqrt(w:Number):Number{
// Fast Math sqrt function from
// http://osflash.org/as3_speed_optimizations#as3_speed_tests
    var thresh    : Number = 0.002;
    var b:Number = w * 0.25
    var a:Number;
    var c:Number;
    
    if (w == 0) return 0;
    
    do {
        c = w / b;
        b = (b + c) * 0.5;
        a = b - c;
        if (a < 0) a = -a;
    }
    while (a > thresh);
    
    return b;
}
        
//---------------------------------------------------------------------------------------
function fsqrt(w:Number):Number{
// SUPA fast but not very accurate sqrt
// Fast Math sqrt function from
// http://osflash.org/as3_speed_optimizations#as3_speed_tests
    var thresh    : Number = 2;            //1
    var b:Number = w * 0.25
    var a:Number;
    var c:Number;
    
    do {
        c = w / b;
        b = (b + c) * 0.5;
        a = b - c;
        if (a < 0) a = -a;
    }
    while (a > thresh);
    
    return b;
}


I've got both of these in my MathX class, which is a collection of quicker alternatives to the built in methods and various other little math based utils.
This test made me think I was going a bit mental,

runPythagorean():  1452
runQuickSqrt():  3514
runQuickFSqrt():  3237

Now I've not done these tests over and over and averaged them out, 'cause to be honest the results really aren't close enough to warrant it. Please feel free to try these out yourselves and post the results back here. Maybe those last two methods should be inlined rather than wrapped in functions, but I've really not got the inclination to try it out.

Squize.