As well as being cross platform, CocosSharp is a Portable Class Library. A Portable Class Library is not just a class library that avoids non portable things, it also includes tooling support. Tell the compiler which .NET targets you want to support (i.e. a profile) and it will complain if you try to use something that won’t work. All of the source code is available, for all Cocos version so you can inspect it to see what happens. CocosSharp source code is on Github.
Although Xamarin isn’t free, you can get it on a monthly subscription for the Indie version at $25 a month. You’ll still need a Mac of course and be a registered Apple developer to deploy to iOS devices/App store. All of the Cocos family are open source and mostly use MIT licences which means you can create open source or commercial software with them.
Start by creating an empty project, in my case I’ve called it TNSGame, short for The New Stack Game. Now use Nuget and enter CocosSharp. You’ll see a big list of packages but we only need the iOS ones. After you click Add Package you’ll see a new entry for Packages in the Solution list and a new set of references under the From Packages folder. Specifically box2d, CocosSharp, ICSharpCode.SharpZipLib, Lidgren.Network, and two MonoGame references. Chipmunk isn’t there yet but is promised soon.
CocosSharp Architecture of iOS Apps
Everything starts just like in non Cocos Apps in the AppDelegate class. However here things differ, your FinishLaunching method should look something like this:
var application = new CCApplication ();
application.ApplicationDelegate = new GameAppDelegate ();
Now we need to create a GameAppDelegate class in GameAppDelegate.cs and override the ApplicationDidFinishLaunching method. Add this code.
class GameAppDelegate : CCApplicationDelegate
public override void ApplicationDidFinishLaunching(CCApplication application, CCWindow mainWindow)
var bounds = mainWindow.WindowSizeInPixels;
CCScene.SetDefaultDesignResolution(bounds.Width, bounds.Height, CCSceneResolutionPolicy.ShowAll);
application.PreferMultiSampling = false;
application.ContentRootDirectory = "Content";
var gameScene = new GameScene(mainWindow);
There are many classes and you can see them documented in the online Mono Documentation. My one and only criticism is that the reference documentation needs more work, it has gaps in it and explaining how things like mapping screen coordinates to world coordinates works would help.
For our purposes we can focus on just five related classes that will do most of the work. These are CCSprite, CCLayer, CCScene, CCNode and CCLabel. CCSprite displays an image and can be relocated, resized and rotated. It can have child nodes. A CCNode is the base class for all visual objects in CocosSharp although it’s never displayed. All of the rotation, resizing of CCSprites happens in CCNode. The other four classes here all inherit from CCNode. CCLayer is a container for CCSprite and all visual objects must be part of a visual tree rooted by a CCScene.
A game can have multiple CCScenes and these are managed by a CCDirector instance but we won’t be covering that. However only one scene can be running at a time.
The game is very simple; it’s just to flick a golf ball into a hole. Given time it could be turned into a half decent golf game but my purpose is just to show what can be done so consider it the worst golf game in the history of computer golf games. One hole no trees, bunkers or any other type of interesting terrain!
From the CocosSharp perspective, it doesn’t use the Box2d physics engine but applies a drag to the velocity components to slow the ball down. If you can sink it in three you are better than me! To sink it, it must be stopped or moving very slowly just about 10-15 pixels below the bottom of the red flag.
Apart from the usual App graphics (default image and App icons) there are just three used: the golfcourse, ball and flag. All three are handled as sprites. Having the flag as a sprite lets me do a collision test between it and the ball. All sprites are setup in the GameScene Constructor. The Course sprite is slightly different because it’s scaled up to the whole iPhone screen. The flag sprite has to be placed about 232 pixels right and 115 down into the course image in the tiny green. Because the image might be scaled, these offsets have to be also scaled. Unfortunately it was only after I’d finished I that I realised I didn’t scale the ball speed so on an iPhone 6/6+ it takes more strokes.
CCNodes and thus CCSprites can have an anchor point defined. This is important because it affects the collision detection and the anchor point for the flagpole was chosen to be Middle Bottom.
The CCSprite’s constructor has an overload where a graphic is specified. As usual on iOS graphics have to be in png format, but with CocosSharp, they also have to be located in a folder called Content and the parameter to the constructor should leave off the .png.
A CCLabel is used to display the number of strokes taken. When specifying the position of the label, you might notice that the vertical position is defined as mainLayer.VisibleBoundsWorldspace.MaxY – 35. The significance of this is that the origin coordinates 0,0 are taken as the bo0ttom left of the screen so MaxY-35 is 35 pixels from the top.
CCNodes have a Schedule method that can fire off events at 60 fps or lower frequency. The majority of the action i.e. moving the ball takes places in the RunGameLogic method. This does three things: first it updates the ball’s position. Motion is smoothed by multiplying the two velocity components by the frameTimeInSeconds parameter that all scheduled events get. I imagine that the 1/60th of a second between two successive events is not always exact so this compensates for that.
The second thing done is check to see if the ball hit the hole. This is done by collision checking; if the two sprites rectangles intersect and the ball is moving slowly enough it’s in the hole. It’s a bit crude but works well here. If the ball does go in the hole then the third part is to display a message, stop the ball moving and set the isOver flag which prevents further game action.
I used another scheduler running at 10 calls per second to apply friction to the ball, reducing it’s velocity components to 98% and then stop it below a fixed speed.
CocosSharp has a number of user input methods. I added two handler methods for when Touch starts and ends and calculate the “force” of the stroke by measuring how far the user moved his finger, scaling the two components (x and y) and then capping it at 50 pixels. This sets the ball’s X and Y velocities. The touch handlers pass in an array of touches so if you move your finger while touching the screen, it stores each touch. As I was only interested in the start and end touch events, I just use the first touch coordinate in either case.
I’m very impressed with CocosSharp. From installing it to finishing this simple game took me six hours, but of course I’ve only touched the surface of it and didn’t go anywhere near sprite batch updates, particle systems, sound and music playing, switching between scenes, tilemaps, physics engines and more. It worked straight out of the box and I only had one silly crash due to an unitialized object. I developed it in the simulator and tested it on an iPhone 5 running iOS 8 and a 4S running 7.1. It ran flawlessly on both.
Xamarin have done a lot of changes to Cocos2d-XNA to improve the code quality and if you have Cocos2D experience with other versions of the framework, you should read their key differences document. They’re not very big changes but it’s mainly functionality that’s been moved between some high level classes for example CCWindow takes over rendering from CCDirector.
The full project source code of the game is on The NewStack Github account.
Feature image via Flickr Creative Commons.