Tuesday, February 22, 2011

RoughBall; AS3 closures


The match subgame is now very advanced.
You can play vs yourself, perform all actions and score touchdowns. Basically play a real match, but it never ends.
Here red is about to score another TD after having KOed all poor blue players.
Running the game in Firefox.
I'm tempted to start doing the match AI... but experience teached that it is the wrong path to choose, at least for me. I love writing AI, but I'll get tangled in AI details and the game will seem to stall.
I could focus on polishing/improving the match subgame, but that can wait.
I should focus on quick progress, so I'll start writing the campaign subgame.


AS3 closures are basically inline functions you write as objects. You pass them around as parameters to other functions and have fun. Like C# lambdas, but a bit more constrained from what I understand due to scope problems. They are not like "real" LISP lambdas, as you can't build code as data.

Tween engines are like programmable animation managers. Animations are objects called tweens. You tell the tween engine to move this sprite over here in two seconds and glow it red once there and stuff like that. It then handles everything for you at each frame. Tweens make use of callbacks to notify you when the animation is updated, completed etc...
I use TweenMax by Greensock.

So what's their use?

Most of the time you use closures as callbacks for events : interface events, tween events...
Rogue Survivor made me fall in love with closures/lambdas, and while they are quite an un-OOP way to do things, I tend to use and abuse them. I like having different concepts available in one language.

In AS3, I found they are highly useful to coordinate logic, interface and animation(tweens).
For instance, here's the current code to make a pawn perform a movement action by following a path.
RoughBall code in FlashDevelop

movePawn() performs a single move.
As the pawn sprite is moved with a tween, the move happens over several frames. The callback onDone is called when the move is completed.

doMove() implements the move action.
The process is controlled by the nextStep closure which call movePawn to make a single move step when appriorate, grab the ball, check for TD and end the move.
Since a closure is a function, it can call itself if needed (recursion) or pass itself as parameter to another function. It asks movePawn to perform a step and register itself as a callback, to resume the movement when a move step in completed. Remember all this happens over several frames, without needing to explicitly write it in code, as everything ends up linked to the tween engine which handles it for you.

Basically you can think of it as a thread without having the hassle to write thread specific code.

Coordinating logic, animation and user input has always been a headache or a chore for me and I love how Flash makes it so easy.
No need of threading or state machines! Me like!(*)

In another part of the code I use different paradigms.
A classic State Machine for the main match flow (phase and subphases).
And a weird thing I made up to control the game flow that also make use of closures by basically building "scripts" of closures at runtime, kinda like you would write CONS lambda code on the fly in LISP. I might describe it later(**).

(*)... until I run into problems I overlooked, like scope or it crashes :)
(**) see (*).

End of post.

No comments:

Post a Comment