Escape Theory Gaming For Life… views are mine, and not affiliated with The White Agency or Nomad

3Jun/101

Flexperiment 1: Physics of a Bouncing, throwable ball.

Here is a simple bit of code that demonstrates simulated physics of a ball being thrown (written with my colleague Anthony http://www.creatistblog.com/):

The keystone of this experiment is the ENTER FRAME event function that tracks the motion of the ball, applying horizontal 'drag' and vertical 'gravity' as well as spelling out the boundaries of the ball's movement area. A simple hack forces the ball to stop in its tracks when it is at a certain speed and distance from the 'ground' or bottom of the screen. Understanding the physics of something like a bouncing ball helps me build on top of it with more features (such as a true collision detection system, or adding wind).

package {

 import flash.display.Graphics;
 import flash.display.Sprite;
 import flash.events.*;

 [ SWF( frameRate="60", width="420", height="420", backgroundColor="0x000000" ) ]
 public class BouncingBall extends Sprite {

 private var maxSpeed:Number = 100;
 private var radius:Number = 25;
 private var vx:Number;
 private var vy:Number;
 private var ball:Sprite;
 private var previousMouseX:Number=0;
 private var previousMouseY:Number=0;
 private var currentMouseX:Number;
 private var currentMouseY:Number;
 private var throwX:Number;
 private var throwY:Number;

 public function BouncingBall() {
 ball = new Sprite();
 ball.buttonMode=true;
 ball.addEventListener(MouseEvent.MOUSE_DOWN, ballDownHandler);
 ball.addEventListener(MouseEvent.MOUSE_UP, ballUpHandler);
 addChild( ball );
 ball.x = Math.random() * ( stage.stageWidth - radius );
 ball.y = Math.random() * ( stage.stageHeight - radius );
 vx = Math.random() * maxSpeed + 0.5;
 vy = Math.random() * maxSpeed + 0.5;

 var g:Graphics = ball.graphics;
 g.beginFill( 0xFF0000 );
 g.drawCircle( 0, 0, radius );
 g.endFill();

 addEventListener( Event.ENTER_FRAME, onClipEnterFrame, false, 0, true );
 }

 private function onClipEnterFrame( p_event:Event ):void {

 currentMouseX = this.mouseX;
 currentMouseY = this.mouseY;

 ball.x += vx;
 ball.y += vy;
 if ( vy != 0 ) vy += 0.5;
 if ( vx != 0 ) vx += (0-vx)*0.015;

 if ( ( ball.x <= radius && vx < 0 ) || ( ball.x >= stage.stageWidth - radius && vx > 0 ) ) {
 vx = -vx * 0.6;
 }
 if ( ( ball.y <= radius && vy < 0 ) || ( ball.y >= stage.stageHeight - radius && vy > 0 ) ) {
 vy = -vy * 0.6;    
 }

 if ( Math.abs( vx ) < 0.01 ) vx = 0;
 if ( Math.abs( vy ) < 0.1 && ball.y>=stage.stageHeight-radius-2){
 vy = 0;
 ball.y=stage.stageHeight-radius;
 }

 throwX = currentMouseX - previousMouseX;
 throwY = currentMouseY - previousMouseY;

 previousMouseX = currentMouseX;
 previousMouseY = currentMouseY;

 }

 public function ballDownHandler(e:MouseEvent):void{
 ball.startDrag(true);
 vy = vx = 0;
 }

 public function ballUpHandler(e:MouseEvent):void{
 ball.stopDrag();
 vx = throwX;
 vy = throwY - 0.6;
 }
 }
}
24May/101

Multiplayer Gaming Fundamentals

I know I've made several false-starts and empty promises for posting some game examples, but I swear this will change soon!

Something that I've wanted to build for a while is a multiplayer game using Flash. To understand how this will work, we will look at some fundamental concepts:

Connection Method

Peer-to-Peer: This form of connection creates a direct link between the players or users of your Flash application. No servers are required, lag is reduced (because data doesn't need to flow to a server). Despite these positive attributes, multiplayer games often use the alternative connection method below.

Client-Server: This setup is more often used in games because a server acts as an adjudicator in the gaming environment which is often highly competitive. Having a server also acts as a security measure against players attempting to hack the game or inject unwanted code into the application.

Flash Socket Connection Servers

Flash applications on different clients connect to each other by what are known as socket connections. When a client establishes a socket connection with a server, data can be transferred freely between the computers (without security interruptions). Some examples of Flash Servers are SmartFox, ElectroServer and Red5. I haven't decided on which server to use for my game yet, but hopefully I'll elaborate more on the different servers in another post.

Game Decision-Making

We've already talked about the different connection methods, so now we will apply this in an example. Lag is unfortunately a fact of the internet. No matter how fast the client connections are, there will always be at least some latency issues. Latency is the delay in data transfer due to the physical distance that the information needs to travel on top of the quality of the clients' connection. Let's consider the following scenario:

You are dueling another player in a fighting game. Both of you hold a sword and shield. Your opponent presses the 'attack' button, causing him to swing his sword toward your character.  As you see the sword approach, you wait for the very last moment before pressing the 'block' button to defend yourself. On your screen, you appear to have blocked the attack, but because of lag, your opponent doesn't receive information that you have blocked, and to him you received the hit.

In a peer-to-peer connection, this will cause both clients to disagree on the current state of the game. To solve this, the client-side code can disregard all 'hits' unless both computers agree on the outcome, but this opens up even more problems - for example your opponent can use a program to always ignore hits on himself, making it completely unfair for the other player.

For this reason, we use client-server connections. A server, who may be a third computer that contributes to even more lag, is better in a competitive game because it will decide on the current state of the game at all times. In the above example, the server will decide whether or not your opponent's hit was blocked, and broadcast the result for all the players to see.

This is not to say that servers are the only way to make games. It is plausible to create games that are purely peer-to-peer, but these are often non-competitive or just cooperative games where an adjudicator is not necessary.

19Apr/100

Interface Programming, using ‘implements’ instead of ‘overrides’

Suppose we are a Beastmaster, and have created  a class MonsterFarm whose list will contain several species of fantastic creatures. We want to create a Centaur and Human class, and populate the farm with one instance of each:

Human:

package
{
        public class Human
        {
                public function Human()
                {
                        //human here
                }
        }
}

Centaur:

package
{
        public class Centaur
        {
                public function Centaur()
                {
                        //Centaur here
                }
        }
}

MonsterFarm:

package
{
        public class MonsterFarm
        {
                var monsters:Array = [];

                public function MonsterFarm()
                {
                        trace('monster farm is open!');

                        var centaur:Centaur = new Centaur();
                        var human:Human = new Human();
                        monsters.push(centaur);
                        monsters.push(human);
                }
        }
}

We want to be able to call upon all the creatures within the farm to speak, so both the Human and Centaur will need a 'speak' method. Additionally, the farm will need to treat all creatures similarly, without having to know their Type.

The most straightforward solution would be to extend both the Human and Centaur classes from a common class like Creature, and then move the speak function into that class.

The problem now is that Centaurs and humans speak differently, so we'd probably create another speak() method in both the Centaur and human classes that override the method in Creature.

This is all well and good, but what happens if Centaur didn't extend from Creature, but instead extended from Monster (which in turn extends from EnemyCreature)? Since classes can only extend from a single class, we would need to work out an elaborate encapsulation and overriding method chain for all the speak-able creatures. Worse still, when we call all our creatures to speak() in the farm, we may no longer be able to call all Creatures anymore, but instead call their common parent which can only safely be assumed as Object.

Enter interfaces!

Unlike classes, interfaces define their methods and not their implementation, which means that it is up to each class to implement the methods themselves. This means that a class can implement multiple interfaces.

For our Centaur and Human, we create a new interface named ICharacterActions which will contain a speak() method:

package
{
        public interface ICharacterActions
        {
                function speak();
        }
}

Both the Centaur and Human classes can now 'implement' this interface, and promise to supply its methods similarly to an override (without the 'override' syntax). These must also be public methods!
Human:

package
{
        public class Human implements ICharacterActions
        {
                public function Human()
                {
                }
                public function speak() {
                        trace('Good Morrow!');
                }
        }
}

Centaur (note that this is extending from a class unrelated to Human!):

package
{
        public class Centaur extends Monster implements ICharacterActions
        {
                public function Centaur()
                {
                }
                public function speak() {
                        trace('neigh!');
                }
        }
}

Although the Centaur and Human classes have different parents, the MonsterFarm can still call them all to speak() by simply to their common interface: ICharacterActions

//in MonsterFarm
for each(var monster:ICharacterActions in monsters) {
        monster.speak();
}
//traces:
//neigh!
//Good Morrow!

With interfaces, we have opened up a myriad of possibilities for the MonsterFarm - we can populate it with any kind of creature, with only the speakable ones implementing the respective interface. We can also add additional interfaces and refine them further like 'ISpeak', 'IFight' so that speaking creatures need not also be fighting creatures, and vice-versa. The performance is also much quicker than overrides.

The catch?

Implementing an interface is like setting a contract - a creature that implements the ICharacterActions interface must contain all the methods defined in the interface or it will cause an error:

1044: Interface method * in namespace * not
implemented by class *.

Methods in interfaces must not have any curly braces '{}' that signify their implementation, so no 'default code' can be executed here (which doesn't matter, because you need to implement the method to avoid the 1044 error above anyway).

For a working example of today's files, download the 'Interface Programming Example' file from the files page.

12Apr/101

Class Diagrams, Documenting Applications and Maintaining Agility

Agile program development is characterised by strong Object-Oriented Programming, frameworks and a fluid design and development process. Although an agile development environment is highly favoured over the rigid waterfall model (especially in the world of Flash), agility can only be maintained over a long development period if our documentation, and pre-visualisation processes are also fluid.

In the waterfall software development model, everything is documented and planned extensively about all aspects of the application. This ensures that all developers know precisely what to build before they even need to start building. When the application is complete, there are very few, if any, ambiguous functions and cases that the application can't handle.

In practice, this is never an achievable case. Clients need to see iterations of your application to ensure that everything is what they wanted (and more often than not, the client doesn't even know what it is they want!).  Furthermore, no matter how extensively you plan the application, you will not spot all the unexpected cases, or the way the application will be handled by the user until it is actually sitting on a server somewhere to be tested on various browsers, platforms, accessibility tools, mobile phones and so forth.

This is the reason why developers adopt an agile development pattern. Frameworks such as MVC are adopted, giving all team-members an idea of where things should be without setting anything in stone. In this environment, new functions and workflows are much easier to implement regularly through multiple iterations until the client is satisfied with the result.

Removing the rigid 'master plan' in favour of agility is not without its pitfalls.

Developing for an application that has constantly varying functional specifications and scope mean that team members need to be constantly updated or risk working on an out-of-date specification with disastrous results for the entire project. Constant documentation is vital, and can only be fostered in a strong collaborative environment.

UML diagrams, or class diagrams, should be the starting point of any application planning. In order to maintain agility, these diagrams need not be populated with each and every single variable and function, but their purpose must be well-understood, and their relationships with other classes established through strict doctrines. When a developer proposes a new class, ideally he would conceptualise it with a diagram before passing it to the senior developer for feedback. The senior would then make any updates to this diagram that he sees necessary before the team proceeds with the approach.

This process can be very time-consuming, or very simple by just looking at the options available on the web:

YUML.ME

yuml.me is a web-based UML drawing tool that uses GET calls to generate attractive and legible diagrams. The beauty of this tool is that the only code required to build a diagram is written in the URL. Potentially, developers can email each other class and functional proposals via email with nothing but a yuml string that can generate a diagram from any computer with a browser and internet connection - no software required.

YUML.ME diagram

generated with the following string:/diagram/scruffy/class/edit/%5BOgre%5D+1-%3E*%5BWeaponHands%5D,%20%5BWeaponHands%5D++1-projectiles%3E*%5BRock%5D,%20%5BWeaponHands%5D-0..1%3E%5BSpikeyClub%5D.

To take this approach further, a project's readme file can contain a version-controllable yuml string to keep all documentation relevant and applicable to a specific yuml link.

Google Documents

Googledocs has a Drawing tool that supports collaborative drawing projects with simple but effective drawing tools. Images shared in Docs are easily editable from the Google environment. Although these diagrams are more powerful than the yuml strings, they take considerably more time to draw. Drawings generated in Googledocs can only be stored and version controlled as binary code as opposed to the yuml strings.

Both these approaches are quick, easy and effective ways to convey and document the ongoing iterations of your application, but obviously depend on external services with no guaranteed longevity. The important thing however is to garner a fluid documenting culture within the team, no matter the tool to avoid functional confusion as the project continues to grow.

For more on drawing class diagrams, look here.

8Dec/090

Pros and Cons of using Design Patterns

On the eve of the upcoming siege against a Troll stronghold, Sir Beefus Maximus spends the night pondering on two conflicting manuscripts: 'How to besiege an Ork stronghold' and 'Killing Trolls for dummies'.

We've talked about a couple of patterns in the past, which span from the tactical to strategic scopes of any given Flash project, but it's important to realise the purpose of a design pattern and to be mindful of their pitfalls.

Design patterns like MVC are scalable solutions for use in your Flash project, but even within the MVC discipline there are several frameworks that interpret MVC in their own unique way.

Adopting a pattern and framework is an easy solution for fixing or avoiding common problems that building from the ground-up may face.

Frameworks act as a skeleton, giving the developer a pre-planned structure to be populated with detail resulting in faster, more agile development.

Patterns and frameworks usually have a substantial following, which means that if you encounter any problems, chances are that the community would have as well - so you won't be alone when it comes to asking for help. Members of the community will also communicate difficult concepts and abstract terms easier.

Communities that support a framework will usually continue to improve upon it by making updates and better functionality.

There are also pitfalls of using frameworks to be mindful of, the most important of which is to avoid over-planning, or over-engineering. Sometimes, be careful with adopting unnecessarily complex frameworks for your particular problem, often you'll find that simple solutions work best.

Using a framework can cause your mind to become lazy and divert your attention from better solutions - you may find that once you adopt a framework, you redesign your application to fit it more perfectly. Following a framework may make it easier to maintain - but a balanced approach should be made when you find yourself changing your application to suit the framework (perhaps another framework exists that would suit your application better).

Later, we'll examine some examples of MVC frameworks in use for Flex and Flash, and discuss using them as opposed to building from the ground-up.