Robotlegs 2 Released

If you’ve been waiting for Robotlegs 2 you’ve been waiting a long time. Sorry about that! It’s been hard to find motivation in the face of the Flash Platform’s rapid decline. Fewer users, less feedback and less collaboration. And other things.

Regardless, after 8 public betas, RL2 is finally out! Huge props to all the contributors:

https://github.com/robotlegs/robotlegs-framework/contributors

As always, you can download the release over at:

http://www.robotlegs.org/

For general support please use the Knowledgebase:

http://knowledge.robotlegs.org/

And please report any issues you might discover:

https://github.com/robotlegs/robotlegs-framework/issues

Personal Thanks

Without getting too soppy I’d like to say a special thank you to @stray_and_ruby for pioneering much of the RL2 codebase and for putting up with me in my darker moments. Also, to @camillereynders for getting involved and pushing things forward. And to @OndinaDF for the incredible energy she injects into the support forum on a daily basis. Thank you.

RL2 Framework Size

Just a quickie. I thought it might be fun to calculate the size of the RL2 framework (when compiled in Release mode using the old compiler.. ‘cos ASC2 is still hella broken).

Here are some numbers (subject to change):

Compiled SWF Size:

Sprite as SWF: 286 bytes (non-debug, release compile)
+ Injector: 12416 bytes
+ Context: 21111 bytes
+ MVCS: 43633 bytes
Injector = 12130 bytes (11.8 KB)
Context = 8695 bytes (8.5 KB)
MVCS = 22522 bytes (22 KB)
Framework + Injector + MVCS all included = 43347 bytes (42.3 KB)

So, the framework is still pretty small. Thank goodness.

CheapPost – RL2 Donations

In the spirit of cheap and lazy blog posts, here is an excerpt from a mail I sent out in response to the question: “How can I donate to Robotlegs?”.

I’m so glad to hear that Robotlegs has been working well for you.

Thank you very much for the offer of a donation, but we don’t accept monetary donations. However, there are plenty of other ways to help the project. For example:

1. Write a blog post about your experiences with RL2
2. Write a tutorial on using RL2
3. Build a demo application and post the code to GitHub
4. Provide feedback on the API, and raise issues on GitHub
5. Sign up to the support forum and help to answer other people’s questions ( http://knowledge.robotlegs.org ).
6. Help us to design a new website! Or give advice on making a better website ( https://github.com/robotlegs/robotlegs.github.com ).
7. Submit pull requests to help improve the codebase
8. Write a cool extension and submit it

Have great weekend!

Speaking of the Robotlegs website…

The site is hosted on GitHub (with a simple CName tweek to point the domain to their servers) and is statically generated using Jekyll. As such, you can simply fork the repo and submit a pull request with your design or content tweaks.

CheapPost – Dispatch Speed

It seems that I’ve forgotten how to blog. Instead of fixing the problem directly I thought I might just share some content from emails that I’ve sent out.

This one touches on Robotlegs 2, Dispatch Speed and critical pathways in an application, and, more specifically, why it doesn’t matter that Events in AS3 are a little “slow”.

I’d recommend Robotlegs 2 – especially for modular designs. I was never happy with the modular solutions for RL1.

The library is stable (I’ve been using it in production for months); the only reason for the beta status is that I don’t feel like enough people have given feedback on the API. Also, I haven’t had much time lately to review all the code – but that should change over the holidays.

Regarding the MessageDispatcher – it is a fairly low level tool for synchronous and asynchronous message passing. It is used to bootstrap the framework for example, but it is not a replacement for Signals or Events. Each tool has its place. However, if you are worried about speed…

The Event system in the Flash Player is a very well thought out and well designed Observer pattern implementation. It is good at what it does: offering a way to observe objects. But the performance critical pathways through an application should not be implemented using an observer pattern. Which is why I don’t see Signals as a valid alternative to Events. They might be faster in some situations, but they are still observers. For ultimate speed make direct method calls! If you need an extra layer of abstraction, use callbacks.

Of course, I really need to write a detailed blog post about all of this, but the point is: Events/Signals are observers and you shouldn’t stick them in the middle of performance critical pathways. The performance sensitive aspects of a system should flow through direct method calls (and as few as possible!). For everything else, Events are good enough, and have much better tooling support than Signals if you use a modern IDE.

Haha, “I really need to write a detailed blog post about all of this”.. pffft.

Games And Entity Systems

Last week I delved into Ash – an ActionScript Entity System by Richard Lord:

https://github.com/richardlord/Ash

I built this little shooter:

http://www.boyblack.net/proto/hunted/TopDown.html

What’s That Then?

Entity Systems offer an approach to object design that fits well with games, where requirements and behaviours need to be tweaked or swapped out constantly. Traditional object oriented design falls over a little bit in that environment.

In an application (as opposed to a game), objects and collaborations are usually clearly defined and do not change after startup. Objects play specific roles, and for the most part, those roles don’t change much.

In a game, however, the behaviours of “actors” within the system can change significantly during gameplay. An enemy may be stunned, for a period, losing the ability to attack. The hero may pick up a weapon, become invincible, or learn to fly. Time may slow down, speed up, or change direction.

Class inheritance is obviously not a good choice here (it rarely is anyway). But actually, many object oriented design approaches are at odds with these requirements.

Ash

Ash breaks things down into Components, Entities, Nodes and Systems.

Components

Components are simple value objects:

public class Position
{
  public var x:Number;
  public var y:Number;
}

public class Display
{
  public var displayObject:DisplayObject;
}

Components do not contain any code, logic or behaviour. They store state, that’s it.

Entities

Entities are buckets that hold components:

const entity:Entity = new Entity()
  .add(new Position(5,5))
  .add(new Display(new SomeSprite()));

game.addEntity(entity);

An entity does not need a name or unique identifier – it is merely the sum of its components. Components can be added to it and removed from it at runtime, changing what the entity does and what role it plays.

Nodes And Systems

So, if components and entities do not contain any actual code, where does the logic go?

This is perhaps the biggest difference between the Entity System approach and typical object oriented programming. Normally, objects encapsulate and hide their data. They expose well defined APIs, but they keep their inner workings, and the data they operate on, private.

There are very good reasons for this, but what it means is that all the emphasis is placed on methods and message passing and not on the data. Sharing mutable data between objects in an object oriented system is almost always a bad idea. Somebody else may change your data “behind your back” and leave you in an invalid state.

In an Entity System data is kept separate from the systems that operate on that data. The data is not encapsulated. Any system may operate on any data that it wants to mutate.

In Ash, specifically, Systems operate on lists of Nodes. A Node is a combination of one or more Components:

public class RenderNode extends Node
{
  public var display:Display;
  public var position:Position;
}

When an entity is given both a Display and a Position component a Render node will be created for that entity. If either of those components is removed from the entity the Render node for that entity will be destroyed.

A System that processes such Render nodes might do this in its update loop:

var renderNode:RenderNode;
for (renderNode = _renderNodes.head; renderNode; renderNode = renderNode.next)
{
  var displayObject:DisplayObject = renderNode.display.displayObject;
  var position:Position = renderNode.position;
  displayObject.x = position.x;
  displayObject.y = position.y;
}

We loop through a linked list of nodes, access the components attached to those nodes, and do whatever it is we want to do with those components. We don’t care about the entities that those components are attached to.

A NodeList has signals for the addition and removal of nodes from the list which is handy when you need to prepare nodes before processing them. For example, in the RenderSystem we add DisplayObjects to the stage and remove them again when Render nodes are created and destroyed:

override public function addToGame(game:Game):void
{
  _renderNodes = game.getNodeList(RenderNode);
  _renderNodes.nodeAdded.add(addRenderNode);
  _renderNodes.nodeRemoved.add(removeRenderNode);
}

private function addRenderNode(node:RenderNode):void
{
  container.addChild(node.display.displayObject);
}

private function removeRenderNode(node:RenderNode):void
{
  container.removeChild(node.display.displayObject);
}

What’s It All Good For?

Adding and removing components from entities at runtime changes the nodes associated with those entities, in turn changing which systems operate on those entities. This effectively allows us to change the roles and behaviours of entities on the fly.

Imagine the hero – the character that you control in the game:

const entity:Entity = new Entity()
  .add(new Position())
  .add(new Motion())
  .add(new KeyControl(
    Keyboard.LEFT, Keyboard.RIGHT,
    Keyboard.UP, Keyboard.DOWN,
    Keyboard.Z, Keyboard.A))
  .add(new Gun())
  .add(new Display(new HeroView()));

By adding the KeyControl component the hero becomes user controlled. Later we could do this:

  entity.remove(KeyControl);
  entity.add(new AIControl());

Suddenly our main character is no longer under our control and is instead moved about by some AIControlSystem.

Hands On

To get to grips with all of this I built a simple game using Ash and Starling. It’s a top-down shooter with baddies that circle and attack you. You can check it out here:

http://www.boyblack.net/proto/hunted/TopDown.html

It takes a while to start feeling comfortable with the Entity System approach, and I’m certainly not there yet. But I have to say, it’s really fun! It forced me to approach problems from different angles, and helped me to build something pretty flexible.

Here’s a quick breakdown of the some of the core Components, Nodes and Systems I ended up with:

Components

Under each component is a list of the properties that make up the component

Bullet
  damage
  range

Display
  object
  layer

Enemy
  prey

Gun
  timeSinceLastShot
  bulletLifetime

Hero (marker class)

HeroControl
  leftKey, rightKey, upKey, downKey
  attackKey, runKey
  rotationSpeed

Life
  health, maxHealth
  stamina, maxStamina

Motion
  velocityX, velocityY
  friction

Position
  x, y, rotation

Predator
  prey

Prey
  predator

Stalker
  prey

Nodes

Under each node is a list of the components that define that node

BulletCollisionNode
  Bullet
  Position
  Motion

EnemyCollisionNode
  Enemy
  Life
  Position
  Motion

GunControlNode
  Gun
  HeroControl

HeroCollisionNode
  Hero
  Position

HeroControlNode
  HeroControl
  Position
  Motion

LivingNode
  Life

MovementNode
  Motion
  Position

PredatorNode (similar to PreyNode and StalkerNode)
  Predator
  Position
  Motion
  Life

RenderNode
  Display
 Position

Systems

BulletRangeSystem
  Operates on BulletCollisionNodes
  Destroys bullets after a given time threshold

CollisionSystem
  Operates on EnemyCollisionNodes, BulletCollisionNodes and HeroCollisionNodes
  Runs through the various collision nodes and damages enemies etc.

EnemyRadarSystem
  Operates on EnemyCollisionNodes
  Places markers around the edge of the screen showing you where enemies are (but only when there are very few enemies left)

GunControlSystem
  Operates on GunControlNodes and EnemyCollisionNodes
  Fires bullets from your gun and auto-aims at nearby enemies

HeroControlSystem
  Operates on HeroControlNodes
  Controls player movement

LifeSystem
  Operates on LivingNodes
  Removes entities when their health reaches zero

MovementSystem
  Operates on MovementNodes
  Applies velocity to position

PredatorSystem, PreySystem and StalkerSystem
  Operates on PredatorNodes, PreyNodes and StalkerNodes
  Updates the motion and position components of these nodes to control enemies in various ways
  Adding more of these kinds of systems will make the game more fun

RenderSystem
  Operates on RenderNodes
  Updates the position and rotation of display objects

WaveSystem
  Operates on EnemyCollisionNodes and HeroCollisionNodes
  Creates waves of enemies

Some Thoughts And Observations

Marker Classes

I ended up with some “marker” components. Marker classes generally make me feel uncomfortable, but they seem slightly less evil in an Entity System.

Garbage

Making an entity and adding a bunch of components to it creates a lot of objects. Consider the bullets in my game:

public function createUserBullet(gun:Gun, x:Number, y:Number, rotation:Number):Entity
{
  const speed:Number = 700;
  const velocityX:Number = speed * Math.cos(rotation);
  const velocityY:Number = speed * Math.sin(rotation);
  const entity:Entity = new Entity()
    .add(new Bullet(50, gun.bulletLifetime))
    .add(new Position(x, y, rotation, 6))
    .add(new Motion(velocityX, velocityY))
    .add(new Display(new BulletView(), Display.BULLET));
  _game.addEntity(entity);
  return entity;
}

We end up creating 6 throw-away objects for every bullet. The solution here is to implement object pooling, but that adds a lot of boilerplate. I’ll probably add pooling for the bullets, but avoid it for the other actors unless it becomes an issue.

Design

It’s challenging trying to decide how to slice up behaviours. Do I need a new system for this? Should I just add some extra code to an existing system? Do I need a new Node definition?

Where To?

Check out Richard’s blog posts:

1. http://www.richardlord.net/blog/introducing-ash
2. http://www.richardlord.net/blog/what-is-an-entity-framework
3. http://www.richardlord.net/blog/why-use-an-entity-framework

I found the Asteroids example in the Ash source really helpful:

https://github.com/richardlord/Ash/tree/master/examples/no-dependencies/asteroids/net/richardlord/asteroids

Flex App Scaling Issue

Just in case you were silly enough to deploy a fullscreen Flash/Flex app to the web, browse to it on a Flash enabled mobile device or tablet, and expect it to look nice:

1
2
3
<meta name="viewport" content="width=device-width, initial-scale=1.0,
minimum-scale=1.0, maximum-scale=1.0, user-scalable=no,
target-densitydpi=device-dpi"/>

hosted with ❤ by GitHub

<meta name="viewport" content="width=device-width, initial-scale=1.0,
  minimum-scale=1.0, maximum-scale=1.0, user-scalable=no,
  target-densitydpi=device-dpi"/>

To be fair, it’s not a Flash/Flex issue at all, but rather a mobile browser detail worth knowing about:

http://www.html-5.com/metatags/index.html#viewport-meta-tag

Essentially, mobile browsers assume a default viewport width of 980px at 72dpi for any given web page and scale the content according to the actual device DPI.

Good for HTML; probably not want you want for your fullscreen Flash/Flex app. Use the tag above to prevent scaling.

Level Up

Holy crap, it’s only a week away!

What surprised me most about the first Try { Harder } was just how intense the whole thing was. At other conferences you can often just sit back and learn at your own pace (provided the material is actually technical enough to keep you interested). T{H}2011 was different.

I remember feeling completely exhausted at the end of each day – but it was accompanied by that lovely feeling you get when you know you’ve worked and grown as much as you can in a single day. Sleep is pretty epic after days like that!

However, it wasn’t just the talks and workshops that did this, it was meeting and talking to those folks whose blogs you read. Those people who you chat to on twitter but haven’t met in real life. That was, perhaps, the best part for me.

Now, I’m not the most social person in the world at the best of times, so this aspect was also quite overwhelming. Fortunately the week started off with an amazing talk that helped put everyone at ease. I can’t share the details but everyone agreed: it was the perfect way to reduce the inevitable resultant anxiety of a bunch of smart nerds meeting each other for the first time. This is just one example of the thought that went into the conference as a whole.

Try { Harder } Level Up: 19th – 23rd March 2012

I believe there are a couple of spots left for T{H}LU. If you can, you should come join us next week. It’ll be fun!

http://www.tryharder.org.uk/level-up-2012/

Update: Pricing for freelancers has dropped to £699 (including accommodation).

Update2: JetBrains are supporting the event by offering personal licences of IntelliJ IDEA to all attendees!

Readme

Have I mentioned that I love GitHub?

When you put a readme file into a folder that file is formatted and presented nicely through GitHub’s file browser. For example:

https://github.com/visionmedia/uikit

Scrolling down a little we can see a nicely formatted readme file.

GitHub strongly recommends adding a readme file to the root of your repository, but what I didn’t realise until recently was that it works for any folder in your repo. GitHub already has the best online file browser out there, but this specific feature can turn your source tree into your documentation.

For Robotlegs 2 I decided to try it out:

Async
MessageDispatcher
Extensions

Almost every package in the entire repo has a readme file. The best way to learn about Robotlegs 2 is to browse the source and readme files on GitHub.