HeadsUp Poker - a Loom game
- HeadsUp Poker
Update 13/08/2013: HeadsUp has now had a slap of makeup and is available on the Google Play store - check out the post.
I was pretty excited when Loom was announced, and with the closure of Qozmo, and some free time before my next gig kicked off, I decided to try it out. The result: HeadsUp Poker.
About the game
I wanted to do a mobile-y single player poker game ever since I got the BlackBerry PlayBook. All the poker games for it were multiplayer (understandable, as you don't have to worry about AI), which is nice, but sometimes I want to be able to dip in and out of a game. I always feel it's slightly impolite to try and bluff another human being whilst on the toilet.
The original idea was for a proper 10-man table, but I ditched it for a simpler 1v1 version to speed up the development time. In hindsight through, it probably wouldn't have made a whole pile of difference.
In HeadsUp, you choose one of four ex-Qozmo members as your opponent, each with their own aggressiveness and intelligence, giving you a different challenge each time you play.
So what's Loom like?
This was originally an exercise in learning the Loom workflow, and their AS3/C#/Lua language, LoomScript. It's almost identical to AS3 but with some additional stuff such as delegates and proper generics. It's very easy to just start coding if you know AS3, and backporting is pretty easy; after the Loom version was done, it took me about a day to get the AS3 version ready.
The actual Loom codebase suffers from a lack of documentation - there's plenty of examples, but when you're new to it all, and especially new to cocos2d, it can be a bit frustrating. As there's no IDE (though an Eclipse version is in the works as of writing, and Philippe Elsass is adding FlashDevelop support), it's a bit hard to explore classes and follow calls; you pretty much end up opening files manually and searching for it.
There's also a few bugs with the code; my biggest problems came from getters and setters not working properly (especially when overridding) (should be fixed in sprint 23), and ternary operators (the
: followed by
this.someProperty always seems to crash). Nothing too crazy for a product in, what I'm going to assume is a beta phase, but test often, as sometimes the error messages are cryptic as hell.
Loom has of course, lots of good points. The vaunted live-reload makes working with GUI code, and pushing to devices much easier. The team behind it are pretty awesome as well. They're super responsive on Twitter and the forums, and they're releasing updates all the time. As of writing, you've still 8 days to get a free Indie license (worth $500), so definitely try it out.
AS3 to Cocos2d
A large part of Loom is the rendering, and they've chosen cocos2d to head up that task. If you're new to cocos2d, there's a few gotcha's that I ran across when developing the game:
- There's no
For a 2D engine, this is super weird. I ended up writing my own getter/setters with code like:which is ugly, but it works, if the bounds are right. If you do this, you'll need to recalculate it every time the scale, rotation etc changes.
var rect:CCRect = this.boundingBox(); this.m_width = rect.getMaxX() - rect.getMinX(); this.m_height = rect.getMaxY() - rect.getMinY();
(0,0)is in the bottom-left corner of the screen, not the top-left. If memory serves me from OpenGL etc, I think Flash is the odd one out here. Still, you need to plus instead of minus, and if you're porting/backporting, remember to switch them.
opacityand it's from
255, because going from
0-100would be too logical
CCNodes have a function,
setAnchorPoint(), which lets you set the equivalent of the registration point. Quite handy, though it works in relative coordinates (so, again,
(0,0)would be bottom-left), not absolute. The default is also
(0.5, 0.5)(I don't know why), i.e. the center of the image, not top-left like in Flash, which added to there being no
heightproperties, means you tend to do a lot of guesswork when positioning, or hardcode everything.
- You can
CCNodes together to build up a hierarchy, though this doesn't take the anchor point of the parent
CCNodeinto account, rather positioning everything from
(0,0)on the parent (i.e. its bottom-left corner). Because, logic
- Speaking of child-parent relationships,
opacityisn't taken into account, meaning if you fade the parent, the child will still be at 100%. This might be similar for filters, but I didn't try them. Scaling and rotating work as expected.
- Textfields are essentially bitmaps, so if you have the same font in two different sizes, you either scale it (which can look blurry), or you embed two different sizes. The whole text side of cocos2d isn't great compared to Flash.
- There's currently no way (correct me if I'm wrong) to get the current date/time. This has the added side effect of
Math.random()returning the same values on subsequent runs, as it seems to be seeded with a hardcoded value. This made it a bit awkward to make a poker game with proper shuffling :) Fixed in sprint 23
You can write your own wrappers for Loom classes for these issues, but you need to extend each class and re-implement them all, which is a bit of a pain.
I can't say I'm a big fan of cocos2d. Maybe it's because I'm not as familiar with it, but I prefer the Flash rendering, which I think gives a crisper image (aside from text, which Flash wins hands-down due to its vector rendering). Here's a side-by-side comparison of the cards (which admittedly suffer as the source image is already scaled), cocos2d on the left, Flash on the right:
Flash gives a much shaper image. If we scale it to see more detail:
You can see how blurry it is around the bottom of the King card, and on the corner of the money stack. For a 2D rendering engine, this isn't great. Perhaps there's a way of changing the aliasing - this is my first time using cocos2d, so I'm not sure.
Another annoying rendering issue that kept cropping up is artifacts. For the money stacks, I saved out 10 images for notes stacked on top of each other, 1 to 10. I'd then use 10 of these images on top of one another to give me 100 possible displays, for 0-100% of the player's stack. Cocos2d would render artifacts where these images would join (the pale horizontal lines):
And again to the side of the deck image:
These have more chance of appearing if you scale your images. Apparently it's a known issue, and suggested fixes include adding
0.5 to the position, but it's a fudge at best.
All-in-all it was pretty good to test. Loom is a nice tool if you're looking for a cross platform solution - it's currently targeting Windows, OSX, iOS, Android and Ouya. The similarity between LoomScript and AS3 is obviously a pretty big plus if you're looking to get something running quickly.
You can of course play the game - let me know if you find any bugs. You can also download the loom source files and play around with it. It was built with the
1.0.401 version of the Loom CLI and sdk version
Oh, and if you're like "Hey, where's the sfx and music?", there aren't any, because I really don't like working on that part :)