To test out my newly ported PureMVC++ implementation I decided to write an example webserver. I’ve always wanted to write one, and I didn’t realize just how easy it is (to make a VERY rudimentary version).
The server parses your http request and then spits it back out at you, with some nice html.
That’s it! Source code is here:
I had some time over the past month to port the popular PureMVC application architecture from AS3, to C++. I learned a ton about C++ and it turned out to be a rather smooth process. The code is up on github.
Differences in the C++ version
- Notification names and types are ints!
- At first I used strings for notification names and types, just like in other ports. I did this until I was writing the first sample application. At that moment I realize in C++ you can’t switch on strings! There’s no support for writing a switch statement on the type std::string. I simply didn’t know that. So code like this just won’t compile:
trace("not gonna happen");
trace("also not gonna happen");
trace("this one gets evaluated");
C++ only allows you to switch on ints, so to save us from having to write something like this:if(note->getName() == "notthisstring")
cout << "not gonna happen";
else if(note->getName() == "northisstring")
cout << "also not going to happen";
I decided to make note names and types ints. This way we can enumerate our notification names and types like so:class n_name
STARTUP, // triggers the app startup sequence
SET, // sets something
GET, // makes a request to get something
DISPLAY, // display something
QUIT // quit the app
and then handle the notification with ints:int name = note->getName();
cout << "Startup the app!";
cout << "Shutdown...";
- IFacade no longer contains a registerCommand method
- I tried my best to figure out a way to implement stateless commands in C++. The way the AS3 version accomplishes this is by passing around references to classes. In that port handling references to classes in an abstract way is easy because AS3 has built in type introspection. In order to do the same thing in C++ we’d have to depend on something from the boost library. That’s not an option. Instead I gave Facade a templated method to replace IFacade’s registerCommand (conveniently called registerCommand). So instead of calling registerCommand(noteName, CommandClassName), one makes a call like this: registerCommand<CommandClassName>(noteName). This calls a special template function created by the compiler that adds CommandClassName to a templated Observer, which is added to the View’s observer list.
That covers it for now. In the coming weeks I’ll probably be adding example code to this post, as well as example applications to the repo. If you’re interested in the project, keep up to date with the repo at github and soon we’ll have a repo at PureMVC.org. I’ve added some temporary documentation for you to use as well.
Let’s pretend you have an application that lets users create shapes to be used in a physics simulation and that the user must click on the screen to set the vertices of the shape. Many physics engines only support convex polygons, or shapes that don’t have inlets, bites, or coves, basically shapes that don’t have inward facing edges. With this limitation we have to be able to restrict [read as "guide"] the user to make only convex polygons. For this we are going to need an algorithm that takes an unordered set of points and finds the convex hull that encloses those points. This way the user can click and add points at random, if desired, and your program will keep track of what points create a convex polygon, while the others are thrown away [or dealt with however you see fit].
The Graham Scan Algorithm is a process of ordering a random set of points and then calculating jumps to the points in that set that constitute a convex polygon. In this algorithm there are three steps. First is to find a corner point, usually the topmost, leftmost point in the set. The second step is to order all other points by the polar angle between the corner point and the point in question. The last step is to traverse the set, taking each proceeding subset of three points (n, n-1, n-2) to determine whether the angle made by these three points is a left turn, right turn, or a straight line. If the turn made is our desired turn [which is usually left - but in Flash it's right, due to the flipped y-axis] then we add that point to the convex hull. If the turn is not our desired turn, we get rid of that point and move on.
Here is an example that shows first the data set drawn from point to point. Each successive line gets progressively whiter. In the second step we find the corner point, order the other points and then show the outer polygon.
Here’s the code for the class:
* Use this class freely - 2009 blog.efnx.com
public class GrahamScan extends Object
* The Graham scan is a method of computing the convex hull of a finite set of points
* in the plane with time complexity O(n log n). It is named after Ronald Graham, who
* published the original algorithm in 1972. The algorithm finds all vertices of
* the convex hull ordered along its boundary. It may also be easily modified to report
* all input points that lie on the boundary of their convex hull.
public function GrahamScan()
* Returns a convex hull given an unordered array of points.
public static function convexHull(data:Array):Array
return findHull( order(data) );
* Orders an array of points counterclockwise.
public static function order(data:Array):Array
// first run through all the points and find the upper left [lower left]
var p:Point = data;
var n:int = data.length;
for (var i:int = 1; i < n; i++)
if(data[i].y < p.y)
//trace(" d.y < p.y / d is new p.");
p = data[i];
else if(data[i].y == p.y && data[i].x < p.x)
//trace(" d.y == p.y, d.x < p.x / d is new p.");
p = data[i];
// next find all the cotangents of the angles made by the point P and the
// other points
var sorted :Array = new Array();
// we need arrays for positive and negative values, because Array.sort
// will put sort the negatives backwards.
var pos :Array = new Array();
var neg :Array = new Array();
// add points back in order
for (i = 0; i < n; i++)
var a :Number = data[i].x - p.x;
var b :Number = data[i].y - p.y;
var cot :Number = b/a;
if(cot < 0)
// sort the arrays
pos.sortOn("cotangent", Array.NUMERIC | Array.DESCENDING);
neg.sortOn("cotangent", Array.NUMERIC | Array.DESCENDING);
sorted = neg.concat(pos);
var ordered :Array = new Array();
for (i = 0; i < n; i++)
if(p == sorted[i].point)
* Given an array of points ordered counterclockwise, findHull will
* filter the points and return an array containing the vertices of a
* convex polygon that envelopes those points.
public static function findHull(data:Array):Array
var n :int = data.length;
var hull:Array = new Array();
hull.push(data); // add the pivot
hull.push(data); // makes first vector
for (var i:int = 2; i < n; i++)
while(direction(hull[hull.length - 2], hull[hull.length - 1], data[i]) >= 0)
private static function direction(p1:Point, p2:Point, p3:Point):Number
// > 0 is right turn
// == 0 is collinear
// < 0 is left turn
// we only want right turns, usually we want right turns, but
// flash's grid is flipped on y.
return (p2.x - p1.x) * (p3.y - p1.y) - (p2.y - p1.y) * (p3.x - p1.x);
Here’s a quick nested tuple [list of head and tail, where tail is the list minus the head]. I wrote this for a current project I’m working on. It works with any parameters except one array. If you only pass one array, it will convert your one array into a list of Tuples.
* Tuple is a list of variables. Really it is a head and a tail, where the tail
* is also a Tuple. (Tuple(n)=head + Tuple(n-1))
public function __construct($args = null)
if(! (is_array($args) && func_num_args() == 1))
// get all the arguments and package them as an array
$args = func_get_args();
// take the first element and use that as the head of the list
$this->head = array_shift($args);
// if there are still args left, make a new list and use that as tail
// pass the remainder
$this->tail = new Tuple($args);
Here’s some usage and output:
$list = new Tuple(1, 2, 3, 4);
That prints out:
[head] => 1
[tail] => Tuple Object
[head] => 2
[tail] => Tuple Object
[head] => 3
[tail] => Tuple Object
[head] => 4
I’ve been working on another game lately, it’s called Machinista – it’s a game where you control motors in a 2D physics simulation. The entire thing is built around Box2D, which is a great physics system. Last night I worked on using Brownian Bridge fractals for explosions – check it out! Use keys W, A, S, D and shift+click to control the tank and make explosions, respectively.
My friend Judah and I are going to collaborate on an album of 30 30 second songs, and will be releasing it August 1st, 2009.
A friend and I were talking about deadlines, as we’re often thrown into a rushed project together, and I came up with this equation which seems to accurately model a coming deadline in the information industry.
Lately I’ve been working on a game with some of my free time. It’s a slow process made a little bit faster through the use of Box2D, which is a great 2D physics lib. In my game the user controls a robot that wheels around and smashes other robots. I decided that I would write some functions for drawing geometric primitives, and that I would draw everything into one sprite, or two, depending on how many layers I’d need. In an attempt to squeeze out some more frames per second I switched these functions over to use flash 10+ IGraphicsData API. It’s interesting, to say the least. When using the new API we loose the ability to easily draw rectangles and circles. We can still use familiar functions like moveTo, lineTo and curveTo – so I’ve written a function that draws a circle using these. It uses some fun almost calculus [parametrization of a curve in so many points] minus any derivatives or integrals. Is that still calculus? Meh. Here’s what happens:
We create a new GraphicsStroke [the line], a new GraphicsSolidFill [the fill], a new GraphicsPath [the path] and an IGraphicsData Vector to store them all in.
_stroke.fill = new GraphicsSolidFill(0xFF00FF, 1);
var _fill :GraphicsSolidFill = new GraphicsSolidFill(0xF0F0F0, 1);
var _path :GraphicsPath = new GraphicsPath();
var _graph :Vector.<IGraphicsData> = new Vector.<IGraphicsData>()
Now what we’ll need to do is populate the path with some commands and some points. To do this, we can use GraphicsPath’s familiar functions moveTo, lineTo and curveTo. These functions will fill path.command and path.data with commands and data, respectively. The parameters to each command are stored in the data array, where as a number representing each command are stored in the command array. You can read more about it here. So here is a function that will fill your path with points and commands to form a circle.
var twoPI:Number = Math.PI * 2;
var curve:Number = 1 + 1/(numPoints*1.75);
path.moveTo((_x + r), _y);
for (var i:int = 1; i <= numPoints; i++)
var th :Number = twoPI * i/numPoints;
var thm :Number = twoPI * (i-0.5)/numPoints;
var px:Number = (_x + r * Math.cos(th));
var py:Number = (_y + r * Math.sin(th));
var hx:Number = (_x + r * curve * Math.cos(thm));
var hy:Number = (_y + r * curve * Math.sin(thm));
path.curveTo(hx, hy, px, py);
In this function _x and _y represent the center of the circle, r is the radius and path is your GraphicsPath. numPoints refers to the number of points you’d like to use for approximating your circle. The more points, the more “perfect” the circle will look, although more points will tax your frameRate. We can get a pretty nice looking circle with 8 points. 4 looks a little boxy, but around 8 is nice. Experiment. Here’s the next step – we’ll add the points to our path and then add the stroke, fill and path to our Vector and then have a sprite draw our graphics data:
r_addCircle(150, 50, 50, _path, 4);
r_addCircle(250, 50, 50, _path, 6);
r_addCircle(350, 50, 50, _path, 8);
_graph.push(_stroke, _fill, _path);
var sprite:Sprite = new Sprite();
This should draw 4 circle approximations of different resolution. This is what it looks like:
You can see that as n [numPoints] increases, the closer to an actual circle our object becomes. I hope this entry helps some of you out there save a little time.