AlecMcE.com

Coding on the Flash Platform

Archive for the ‘tdd’ Category

Gotcha – transform.matrix and scaleX/Y

View Comments

I came across this gotcha for the first time today. Praise-be to ASUnit, without which this could have been extremely difficult to unearth:

// given two sprites called "a" and "b"...

a.transform.matrix = new Matrix(-.5, 0, 0, -.5, a.x, a.y);
b.scaleX = b.scaleY = -.5;

trace(a.scaleX, a.scaleY, b.scaleX, b.scaleY); // outputs: 0.5, 0.5, -0.5, -0.5

Both clips have been scaled by -0.5, but because the transform was used to produce the scale for a, the scaleX/Y variables do not reflect the object’s true scale.

Now, just to confuse yourself, add a third sprite to the stage:

// given another sprite called "c"...

c.transform.matrix = new Matrix(-.5, 0, 0, -.5, c.x, c.y);
c.scaleX = c.scaleY = -.5;

Curiouser and curiouser! This needed a more complete experimentation…

The Flash plugin is required to view this object.

The source for this experiment can be found here: scaleAndTransform. The buttons call the following methods:

function onGo(event:Event):void
{
	a.transform.matrix = new Matrix(-.5, 0, 0, -.5, a.x, a.y);

	b.scaleX = b.scaleY = -.5;

	c.transform.matrix = new Matrix(-.5, 0, 0, -.5, c.x, c.y);
	c.scaleX = c.scaleY = -.5;
}

function onResetScale(event:Event):void
{
	a.scaleX = a.scaleY = 1;
	b.scaleX = b.scaleY = 1;
	c.scaleX = c.scaleY = 1;
}

function onResetTransform(event:Event):void
{
	a.transform.matrix = new Matrix(1, 0, 0, 1, a.x, a.y);
	b.transform.matrix = new Matrix(1, 0, 0, 1, b.x, b.y);
	c.transform.matrix = new Matrix(1, 0, 0, 1, c.x, c.y);
}

What Is Going On?

If you apply a transformation matrix then a scale, the magnitude of the scale is applied, but the direction is determined by the product of the transformation and the scalar… which is to say that:

a.realScaleX = (a.transform.matrix.a * a.scaleX > 0 ? 1 : -1) * a.scaleX;

If however you apply a scale then a transformation, the scale is defined by the transformation only!

a.realScaleX = a.transform.matrix.a;

Bug?

Does this qualify as a bug? I haven’t thought about this for long enough. The conditions in which a transformation matrix rotates and skews the MovieClip confuse me; how would I define scaleX and scaleY in that scenario? I need to give this some thought; perhaps you the community can give me some help! I am reluctant to call anything a bug immediately now, after my experience with my The Problem With Vector.<T> post, where I was just plain wrong!

A similar bug exists in Adobe JIRA: UIComponent.scaleX, scaleY differ from transform.matrix.a,d. You’ll need an account to look at this – it’s free, and once you’ve got it you can pester Adobe with your bugs too.

Written by alec

February 23rd, 2010 at 9:00 am

Posted in as3, gotcha, math, tdd

RobotLegsPong Part 1 – Overview

View Comments

Introduction

RobotLegsPong attempts to combine RobotLegs application framework with the as3signals event model and a Frame-Ticker (as well as a pinch of ASUnit unit-testing) to create a ‘game’.

It is an open-source project, available on GitHub as an example of using RobotLegs together with these other technologies.

Source Code: github/alecmce/RobotLegsPong

RobotLegsPong is not a very good game; it is playable only in the loosest sense. Bats require to be dragged in order to move (and there is no computer-logic to play against), so you could not really play against an opponent. The purpose of the exercise was to see what structure a game like Pong would take within the RobotLegs framework.

The purpose of this article is to describe the particulars of the technologies and why I chose them. In a follow-up article, I will look in more detail how RobotLegsPong is wired up.

Why I Chose These Technologies

RobotLegs

The RobotLegs framework is a lightweight, flexible application framework that allows coders to spend less time wiring up their application, and more time working on its functionality.

Frameworks are often criticised because they force developers to write code in a particular way, which might be inappropriate for a particular context. I have used Cairngorm, Pure MVC, as well as some proprietary frameworks, and have found that all of them do some things well, and do other things clumsily. So far I have not found this problem with RobotLegs, because most of the time it gets out of the way and lets you code; in fact, it does more than that: it reduces the amount of code you have to write.

as3signals

RobotLegs comes with an application event bus, but I have decided to circumvent that and use as3signals instead. as3signals allows you to define an object which acts as an event dispatcher within an application.

I like as3signals because describing an event as a Signal object allows my event model to be described through interfaces. as3signals is supposed to be fast too. Then again, interfaces are slow. The relative speeds of the approaches is interesting, but not a significant factor in my decision making process.

Frame-Ticker

The frame-ticker is a simple idea: rather than creating multiple enter-frame event listeners, each creating event objects, create one enter-frame listener and a main game loop iterating through those methods that need to be called per-iteration.

This implementation came out of a discussion on Twitter that I was involved in on the fringes; I wrote about it in a previous blog post.

ASUnit

Unit testing enables developers to test portions of their code in isolation, so that they can be confident that every method works exactly as the developer intended. They also represent a secondary form of documentation-in-code; if you want to know how I meant a method to work, reading the unit test will tell you almost everything you need to know (including, if a good test is missing, what I didn’t consider).

That said, I have not unit tested every method; in this example I have only unit-tested the geometric logic for the bats. This is bad practice, however under time constraints I think that it is most important to unit test what is complex, mathematical or ambiguous, since this is where behaviour is most likely to fall down.

[Inject]

The ‘trick’ to using RobotLegs is that you do not need to inject dependent objects into classes when you contruct them; this is done automatically. This code:

public class Dependee {}

public class MyExample
{
	public var dependee:Dependee;

	public function MyExample(dependee:Dependee)
	{
		this.dependee = dependee;
	}
}

becomes this code:

public class Dependee {}

public class MyExample
{
	[Inject]
	public var dependee:Dependee;
}

The metadata tag [Inject] has the effect of automatically injecting the dependee into the class when it is constructed. This isn’t much on the face of it, but it is enough. It feels to me as though a quarter of my code is actually just wiring up classes so that they each have access to the classes that they need to function, or passing objects around methods. The [Inject] tag lets me shift all of that wiring into the RobotLegs framework.

Context

There is a little more to the RobotLegs story however; how should RobotLegs react when it comes across an [Inject] tag? It could construct a new Dependee object, or it could be that I want only one Dependee object to be injected wherever the [Inject] tag is found. This is where the Context class becomes meaningful.

In the PongContext, different classes are wired up in different ways. Their definitions are defined by adding injector mappings and the mediatorMap mappings in the startup method.

public class PongContext extends Context
{
	override public function startup():void
	{
		...
		injector.mapSingleton(DragMechanism);
		injector.mapSingletonOf(Geometry, GeometryModel);
		injector.mapClass(BatGeometry, BatGeometryModel);
		...
	}
}

injector.mapSingleton

injector.mapSingleton(DragMechanism)

mapSingleton indicates that only one instance of the class entered should be constructed. In this case, just one DragMechanism will be created, and injected whenever this is found:

[Inject]
public var mechanism:DragMechanism;

injector.mapSingletonOf

injector.mapSingletonOf(Geometry, GeometryModel);

mapSingletonOf extends the mapSingleton idea to interfaces and their implementing classes. In this case the Geometry interface is mapped to the GeometryModel class. The injection is called as follows:

[Inject]
public var model:Geometry;

No reference to the GeometryModel is needed in any class other than the PongContext. This allows a very pure use of interfaces across the application.

injector.mapClass

injector.mapClass(BatGeometry, BatGeometryModel)

injector.mapClass works a little differently; whenever a BatGeometry interface is flagged to be injected, a new instance of BatGeometryModel is constructed and injected into the class, so the following code is used to create the injection:

Each BatMediator needs its own BatGeometry object. By using the mapClass method, multiple BatGeometryModel objects will be constructed, one for each time the following code is found:

[Inject]
public var model:BatGeometry;

Mediators and Components

public class PongContext extends Context
{
	override public function startup():void
	{
		...
		mediatorMap.mapView(Background, BackgroundMediator);

		addChild(new Background());
	}
}

mediatorMap references a slightly different aspect of the application: your view objects. The mediatorMap allows users to define associations between display objects and Mediators. These two parts comprise the View aspect of the standard MVC pattern.

The DisplayObject – in this case Background – is the asset that you want to be visible on the stage. In my pong example this is essentially just a Sprite, though it might just as well have been imported as a graphical asset in a SWC.

The Mediator is associated with the DisplayObject so that when an instance of the DisplayObject is created, the corresponding Mediator is also constructed. The BackgroundMediator looks something like this:

public class BackgroundMediator extends Mediator
{
	[Inject]
	public var view:Background;

	override public function onRegister():void
	{
		...
	}
}

The DisplayObject Background is injected into the BackgroundMediator when it is constructed. The DisplayObject can then be manipulated. It is an elegant solution that separates display object from UI logic.

addChild(new Background());

is all that is needed to wire the entire DisplayObject/Mediator combination.

RobotLegs & Tickers

The RobotLegs structure is particularly useful for wiring up a Ticker-based application because one ticker can be mapped as a singleton, and injected to all those methods that need to iterate every frame:

public class PongContext extends Context
{
	override public function startup():void
	{
		...
		injector.mapSingletonOf(Ticker, EnterFrameTicker);
		...
	}
}

RobotLegs with as3signals

I really like the style of event dispatching that as3signals provides, but my implementation demands that if one class requires another class then it must flag it to be injected, and then the signal wired up in a method flagged as [PostConstruct] (see GeometryModel). This doesn’t feel like the right solution.

Integrating as3signals with RobotLegs is beyond the scope of this article. It looks like Joel Hooks and Robert Penner are making inroads into this problem through as3signals’ Google Group. I look forward to seeing what they come up with.

Written by alec

January 19th, 2010 at 7:01 am

Posted in as3, library, opinion, tdd

Tagged with , , ,

ASUnit – A Conventional Problem

View Comments

There are several conventions involved in unit-testing. If you use FDT, this structure will be familiar to you. If not, you should get the picture anyway:

A standard structure for a unit-tested project in FDT

TestRunner does one thing: starts the unit-test framework by adding the AllTests TestSuite. That AllTests will then in-turn add all of the AllTests in the next level of packages (in this case, just the one AllTests in the alecmce package). This happens recursively through the entire package tree. Any tests that lie in the same package as an AllTests are added by that AllTests, so alecmce.topsecret.AllTests is responsible for adding alecmce.topsecret.ThisClassWillChangeYourLifeTest.

This convention works really well. More and more people are adopting unit-testing while developing their tools/frameworks. Their tests are published alongside their tools/frameworks, so that you can be confident that they work as anticipated, and so that you can use the tests as a form of documentation for the known working functionality of the tools/frameworks.

Suppose you want to import a tool/framework into your project. For example (as it was the reason that this problem arose), let’s suppose I want to add as3signals into my project. Since it has a suite of tests, in case I need to make changes to the library, I want to add those tests to the suite of tests that I run. I download the framework from github and add it to my lib folder, adding the src and test folders as source folders:

A file-system with as3signals added as a library

There’s a problem here. There are two classes in the default package called AllTests. First there’s mine, which is responsible for adding alecmce.AllTests, then there’s also as3signal’s which is responsible for adding org.AllTests.

There is no way to differentiate between them; they conflict:

Error: Can not resolve a multiname reference unambiguously. AllTests

The convention of creating a class called AllTests in each package is clean and simple in the one-library environment. If you import multiple projects then the convention breaks down. Of course, there are other ways of importing libraries into yours: you could package them up as swcs (or else, use the swc provided), or you could create separate projects in FDT and link the projects together (assuming you use FDT of course – though I’m sure other environments can work similarly).

For me, that diminishes the point of using unit-testing. I want to have all the code that goes into my project tested all the time. While I don’t expect to change signals, I want to be able to reassure myself that everything is still working as I anticipate it to for all the code, every time I run my tests.

A change in convention?

If instead of AllTests I called my tests TopsecretAllTests or AllTests_topsecret and the signals tests were called SignalsAllTests or AllTests_signals the class ambiguity would disappear. It is feasible however that two people could end up using the same project name under different packages. Then, maybe two people would end up with AllTests_topsecret classes and the ambiguity would persist.

The guaranteed solution is to append the full package name onto each AllTests class: AlllTests_alecmce_topsecret is a candidate. Then, two tests’ packages would only conflict if the packages themselves conflict (in which case the tests are the least of their problems). However, this seems like over-kill.

Unfortunately, because the AllTests convention is the convention, this problem is thorny. Even if the AllTests_topsecret pattern is an acceptable work-around, it will not be adopted by people until the need arises, and then, probably, any number of different practises will emerge. The existing norms are well known, well documented and in common practise. It is, effectively, a problem without a solution.

Written by alec

October 29th, 2009 at 11:32 am

Posted in as3, opinion, tdd

Detecting Class-Recursion in AS3

View Comments

This article has arisen because I found that every now and again while I was writing unit tests for my code, I would find myself coming across stack overflows caused by an infinite recursion of classes. The unit-testing framework didn’t provide a very helpful error message informing me what was going wrong. I decided if I could amend the framework so that it gave me a message which I could resolve easily. It turns out to be harder than it first appeared.

The Recursive Problem

It is unlikely that you would ever write a class like this:

class Recursive
{
	public function Recursive()
	{
		new Recursive();
	}
}

However, there is a context where it’s not as unlikely as you’d think. One of the more annoying aspects of test-driven development is the creation of test suites and test classes to reflect each of the packages in your source folder. By convention each package contains an AllTests test suite which adds all the tests within that package. Below is an example:

package mypackage
{
	import asunit.framework.TestSuite;
	import mypackage.subpackage.AllTests;

	public class AllTests extends TestSuite
	{
		public function AllTests()
		{
			addTest(new mypackage.AllTests());
			addTest(new ExampleTestCase());
		}
	}
}

If you spotted the deliberate mistake, award yourself ten points. mypackage.AllTests was supposed to add mypackage.subpackage.AllTests as a test suite, but it inadvertently added itself. This will cause a stack overflow in ASUnit. It will tell you that:

Could not create and run test suite: Error: Error #1023: Stack overflow occurred.

It’s accurate, but not massively informative. We can do better than that.

A Generic Solution

I wanted to approach the problem generically before applying any solution to the ASUnit framework. How, then, can you detect that a constructor method calls another instance of the same method?

In AS2 there was an arguments.caller object, which would have allowed me to access the referring method. describeType could be used to inspect the caller and the current method, and check whether they’re the same… unfortunately, arguments.caller is not supported in AS3, as the AS3 Language Reference explains.

However, it is still possible to discover information about the methods in the stack of currently-called elements: by creating (but not throwing) an error. As long as you are running Flash in the debug player, then you can inspect that stack trace created by the error, and determine the sequence of constructions.

Check out the github repository for this approach

The main class in this repository is the RecursionWatcher.as file. The workhorse method is the stackIndicatesRecursion method which takes a generated error and inspects the stack trace that it produces to determine whether class-recursion is taking place.

A Solution for ASUnit?

So far this I’ve created this solution generically in its own repository, and I haven’t tried to integrate it into ASUnit. Some issues need to be thought through:

  • Should this sort of solution be integrated into the TestCase or TestSuite class?
  • What are the speed implications of adding this? What sort of speed reduction is the extra functionality worth?
  • Can the functionality be put into a class which decorates the TestCase, minimising the footprint of the core code changes?

I will be approaching integrating this work into the latest versions of ASUnit in the next few weeks, but I would like to guage whether this is the most appropriate course of action to take, and whether it’s even worth putting this sort of test into the framework. All comments welcome!

Written by alec

October 25th, 2009 at 9:40 pm

Posted in as3, tdd, tools

Tagged with

Isometric Fun – Cuboids

View Comments

The Flash plugin is required to view this object.

Test Driven Development is a wonderful thing. When I am calm, not under the pressure of deadlines and working most effectively, I would argue that TDD is the optimal way of working. Unfortunately, UI testing does not sit easily within TDD. To really check that graphical code works, you need to see it.

I was working back through isometry logic that I did almost a year ago, revisiting and writing fresh libraries for a project that my company is working on. I found myself needing to visually test that rendering cuboids in isometric space works exactly as I expect it to. It’s one thing for ASUnit to ‘run green’ in the test cases that I could pre-calculate, and quite another to see all these lovely cuboids drawn out. These tests are useful additions to the suite of work, and I thought it was fun enough to share.

Written by alec

October 15th, 2009 at 11:33 pm

Posted in animation, as3, tdd

Tagged with