CocosSharp – The Game Loop

This post is part of my Mobile Game Development series. Start at the beginning to catch up. This series was inspired by the things I learned developing a new game for Android and iOS called Mirror Maze.


I’ve talked a lot in this series about the foundation, building blocksvarious different node implementations that come out of the box with CocosSharp, and how to implement your own custom node. That will get you going with a CocosSharp application, but it will be static at this point. A game with nothing but static graphics isn’t all that cool, so you probably want to get things moving around a bit.

In game development, there is the concept of the Game Loop. The game loop is the chunk of code that gets called repeatedly, usually around 60 times per second, which drives the game. It processes things like user input, game state, and collision detection, then handles updating the nodes and rendering the game frame. The game loop is where all the magic happens.

In CocosSharp, each node has the capability of implementing its own game loop. There is a method provided by the root class CCNode, called Schedule, which takes an Action and schedules it to run for every cycle.

I typically implement a method called Process for scheduling. The Process method needs to take a float as a parameter, which represents the number of seconds that have passed since the last time Process was called. Remember that this method will be called somewhere around 60 times per second, so the actual value of the seconds parameter will be somewhere in the neighborhood of 0.016667. Don’t expect a whole second or more to have passed since the last call.

Adding Movement

Having a game loop that doesn’t do anything is no fun. Let’s draw a circle and move it across the screen.

The code above creates a CCDrawNode, draws a blue circle with it, then positions it in the middle on the left of the screen. Once the game loop begins, the circle will move one unit to the right every time through the loop. At this point, the circle will move right off the screen and continue to move to the right for the entire time the application is running. We can add some more processing to have the circle bounce within the visible bounds of the screen.

In the first change above, I added a member variable called Movement. When Movement is positive, the circle will move to the right. When Movement is negative, the circle will move to the left.

In the second change above, I updated the Process method to use the new Movement variable for the circle’s position and added logic to reverse the movement direction when the circle’s bounding box starts to move outside the visible bounds of the layer.

Now, you can run the code above as long as you want and just watch the ball move back and forth across the screen indefinitely.

Pause() and Resume()

The game loop will run continuously until the node is removed from the scene. However, there are times you won’t want the game loop to run. Perhaps you want your player to be able to pause the game and resume it right where they left off, without your game doing processing that would change the game’s state. That is why CCNode also provides Pause() and Resume() methods. Calling Pause() will stop the game loop from being called until the Resume() method is called.

To be clear, however, calling Pause() will only pause the game loop. It will not prevent any touch interactions you may have added from being handled. You’ll want to keep that in mind when you start working with touches, if you leverage the Pause and Resume methods.

With the concept of the game loop, you can now start to do some interesting things with your game. However, most games will need some sort of touch interaction. In the next post, we’ll take a look at how you can add that touch interaction.

Share

CocosSharp – BoundingBox Explained

This post is part of my Mobile Game Development series. Start at the beginning to catch up. This series was inspired by the things I learned developing a new game for Android and iOS called Mirror Maze.


BoundingBox is a property on CCNode that describes the rectangular box at the boundary of the node. BoundingBox is of type CCRect, which has some really useful properties: MinX, MaxX, MinY, MaxY, and Center (a CCPoint).

It’s important to understand exactly what BoundingBox represents and what it doesn’t. Much like Position, BoundingBox is relative to the node’s parent. In fact, Position is a big part in calculating the node’s BoundingBox. Position, AnchorPoint, and ContentSize are all factored in to the node’s final BoundingBox. However, BoundingBox does NOT factor in any rotation or scale that has been applied to the node. It may seem strange that those seemingly key transforms are not factored in because it can be very useful to know what the bounding box of a node is after rotating and scaling it. And that is why there are a couple more flavors of BoundingBox that you can make use of.

BoundingBoxTransformedToParent does pretty much what you would expect based on the name. It returns the bounding box of the node relative to the parent AFTER applying positioning and all transformations (scale and rotation). If you don’t do any transformations on a node, this property will return the exact same result as BoundingBox would.

BoundingBoxTransformedToWorld returns the bounding box of the node relative to the world space, after applying positioning and all transformations. When you want to compare the bounding box of one node versus another node, this is likely the property you want to use. It will give you a more “real” version of the bounding box because the coordinates will be in relation to the coordinates of all the other nodes in the world space, whether they are children of the same parent or not.

It’s very important to understand exactly which bounding box property you want to use when you need to reference the bounding box of a node. I wish I could give you more direction around which one to use in what scenario, but the reality is that it is highly dependent on the specifics of your app and what you are trying to accomplish with it. Based on my experiences so far, I can say that I found myself using BoundingBoxTransformedToWorld in most cases, but not all. I tend to want to know where the node is in the world, rather than relative to the parent, when I grab the bounding box.

Working with the bounding box of a node is something you will likely do a LOT throughout the development of your game. Whether it’s for collision detection, relative positioning of other nodes, or reacting to touch interaction, this is one of the more important properties you will need to understand. The best way to really wrap your head around it is to play around with it or set a breakpoint and inspect the results of the different bounding box properties at different times within your application.

Share

I was on the Gone Mobile Podcast!

Recently, I had the opportunity to chat with the guys over at the Gone Mobile podcast about my experiences with CocosSharp, my Mobile Game Development series, and the game that started it all, Mirror Maze. I rambled on for nearly an hour, but it was a lot of fun. We talked about how I got started with mobile game development, how it’s a fun thing I do on the side (and not my day job), as well as some of the basics of working with CocosSharp. Check it out and let me know what you think!

Gone Mobile 41: Mobile Game Development and CocosSharp with Brent Edwards

Share

CocosSharp – All About Positioning

This post is part of my Mobile Game Development series. Start at the beginning to catch up. This series was inspired by the things I learned developing a new game for Android and iOS called Mirror Maze.


Positioning in CocosSharp can get pretty mind bending at times. This is because CCNode has Position as a property and everything your user will see in your app will derive from CCNode, which means everything has a position. Couple that with the fact that there will likely be varying degrees of nesting with these nodes, each containing their own Position, and things can get quite hairy. So, let’s talk about the main components that are involved with positioning: Position, Anchor Point, Rotation, and ContentSize.

CCNode’s Position property is of type CCPoint. CCPoint is a simple struct with x and y properties, each of type float. Now remember, your game’s dimensions are logical dimensions that don’t necessarily map to pixels. Therefore, the positioning used in CocosSharp uses floats for coordinates so that you can have much more precision than integers would provide.

In CocosSharp, the origin, coordinate (0, 0), starts in the lower-left corner of the screen. Increasing the x coordinate value moves the node to the right and decreasing the x coordinate value moves the node to the left. Increasing the y coordinate value moves the node up and decreasing the y coordinate value moves the node down.

You may have noticed the phrasing that I used for the origin, that it “starts in the lower-left corner”. CocosSharp has the concept of cameras which can be moved around, changing where in the world space the user is able to see. So the origin starts in the lower-left corner, but cameras may move around, making it seem as though the origin moved. I’ll talk about the concept of cameras in a future post in this series.

CCNode’s AnchorPoint defines where on the node the position actually refers to. By default, the anchor point is at the center of the node. The AnchorPoint property is also of type CCPoint, but uses it differently than Position does. The values of the x and y properties are treated as percentage values, rather than explicit values. Therefore, the AnchorPoint default value is (0.5, 0.5), which, again, is the center of the node. Going around the horn we have:
Lower-Left: (0.0, 0.0)
Upper-Left: (0.0, 1.0)
Upper-Right: (1.0, 1.0)
Lower-Right: (1.0, 0.0)

Fortunately, there are predefined static properties for you to use. These static properties are all part of the CCPoint class and are named CCPoint.Anchor*.

CCNode’s Rotation property is pretty straight-forward. The type is float and defines how much the node is rotated in degrees. A positive value rotates the node clockwise and a negative value rotates the node counter-clockwise, all around the AnchorPoint.

CCNode’s ContentSize property is what tells CocosSharp how big your node is. ContentSize is of type CCSize, which has a Width and Height property. When you start getting into custom nodes, making sure this ContentSize property is accurate is key to keeping positioning correct in your game.

When applying changes to any of these properties, it’s important to remember that the changes are always relative to the node’s parent. If the parent is the root node, then all the property values can be taken at face value. However, let’s say the node’s parent is another node, and the parent node has changes applied to any of its properties. The parent’s changes are applied first. Then, the child node’s changes are applied to the child, relative to the newly re-positioned parent. To help make this more clear, let’s look at an example.

NodeA is added to the root layer. NodeB is added as a child to NodeA. The following code sets this up:

Now, let’s say that NodeA has a position of (10, 20) applied. Then NodeB has a position of (25, 35) applied.

Now, as far as NodeB is concerned, it’s position is (25, 35). However, what the user actually sees, due to the parent node’s changes being applied first, the user sees NodeB with a position in the world space of (35, 55). The concept of a node’s world space is conceptually pretty simple: Where in the world space of your game is the node, after all positioning is applied to the node and all parent nodes.

This example is simple on purpose, to ease into the concept of world space. It doesn’t take long for things to get much more difficult to calculate, for instance by adding rotation to NodeA. Thankfully, you don’t have to calculate it on your own. CCNode has the concept of BoundingBox. However, fully understanding BoundingBox requires a more in depth discussion. In my next post, I’ll dive in to all things BoundingBox.

Share

CocosSharp – Implementing a Custom CCNode

This post is part of my Mobile Game Development series. Start at the beginning to catch up. This series was inspired by the things I learned developing a new game for Android and iOS called Mirror Maze.


You can do quite a lot with the node implementations that CocosSharp provides out of the box. However, sometimes you’ll find that you need to do something custom. As a general rule, you’ll want to implement your own custom node any time you start adding several children to a CCNode instance or want a collection of nodes to be considered a logical unit. Implementing your own CCNode is a breeze, since it already provides a ton of functionality that you can leverage right out of the box. As with most things in CocosSharp, though, there are some things you should be aware of to make your life a little easier when you do implement custom nodes.

One reason why you’d want to make your own custom node is that you want to group other nodes together. An example of this from Mirror Maze is each collection of mazes in the level selection menu.

Menu

I developed a simple container UI element, essentially a rectangle with rounded corners, as the background, then added a label toward the top and a bunch of circle buttons below it for choosing which level to jump to. The game contains several of those maze collections, so I wanted to make something that I could re-use.

The custom node I created for that menu is nothing more than a collection of child nodes. However, I can add that menu node to my layout and position it how I like, without having to individually position the background, the header label, and all the buttons. They all move as a unit when I move the menu node.

When I implement a custom node, there are two or three things that I always do. The first two are mandatory and the third is optional, depending on the needs of the node.

Step 1: Constructor

The first thing I do is instantiate any children that will be there for the life of the node. I do this in the constructor of the custom node. If I need to reference any of the children at a later point, for positioning or anything else, I also add a member variable for that child node.

If you have absolute positioning to do for any of these children, meaning positioning that doesn’t depend on anything else, you can set that positioning in the constructor as well. However, at the time that the constructor is ran, the node hasn’t actually been placed into the parent’s scene yet. That is important because that means the node also does not have any size or position associated with it yet.

Step 2: Content Size

The second thing I do, and arguably most important, is to make sure to keep ContentSize updated. ContentSize is the property that tells CocosSharp how big the node actually is. ContentSize factors heavily into positioning and BoundingBox, which I will cover later in this series. It’s important to update ContentSize to reflect the total size of all the children in the node whenever you finish adding children or something that would affect the size changes. ContentSize is of type CCSize, which has Width and Height properties (both floats). This step is one of the things I really wish I knew sooner. You’re welcome.

Step 3: Positioning (Optional)

In a lot of cases, the child nodes I add to a custom nodes need to be placed relative to other child nodes or the parent’s VisibleBounds. VisibleBounds is a property that CCNode provides that returns the bounding box of the visible world. Basically the bounds of what the user can see. In Mirror Maze, I used the VisibleBounds a lot to position children somewhere along the outside of the visible boundary. Since the node hasn’t been placed in the scene yet at the time of that the constructor code is run, this brings us to the third thing I generally do when implementing a custom node: override AddedToScene.

AddedToScene is the method that CCNode will call once the node has actually been added to the scene, which means that it will start to have sizing and positioning available to it. VisibleBounds will always return a default rect before the node is added to the scene, so AddedToScene is the first time you can start to use VisibleBounds.

The above code positions SomeSprite in the bottom-left corner and SomeDrawNode in the bottom-right, then sets the ContentSize to be the full width of the VisibleBounds and the height of SomeSprite (the taller of the two child nodes).

Overriding AddedToScene isn’t always necessary. If you are placing all of your child nodes at specific coordinates that aren’t affected by whether the node has been added to the scene or not, you can skip this step and just stick with the first two steps, putting your positioning in the constructor.

After following the steps that I follow above, you’ll have a usable custom node. If all you want to do is group other nodes together, you’re good to go. If you want to add further functionality, this is where you can go nuts. In my next post, we’ll learn about how positioning works in CocosSharp.

Share

CocosSharp – Using CCLabel

This post is part of my Mobile Game Development series. Start at the beginning to catch up. This series was inspired by the things I learned developing a new game for Android and iOS called Mirror Maze.


There’s already documentation on CCLabel available from the CocosSharp team, so this won’t be a comprehensive post on the topic. However, there are some things I’d like to point out.

When I developed Mirror Maze, I wanted to use a custom font to give the game its own unique look-and-feel. There are a lot of places online to find free fonts which have licenses that allow usage in your projects. Using the font that I chose in CocosSharp was easy and just required making sure everything was set up as the engine expected.

The Setup

As I covered in the Foundation post, your GameView should be configured to look for your assets in the Content folder. One of the folders within the content folder is for your fonts and is aptly named, “Fonts”. Without this setup code, CocosSharp will never know where to find your font files, so make sure you have it configured properly before moving on.

Next, copy the .ttf file for your font to the Content/Fonts folder for both Android and iOS projects. I found that Xamarin Studio properly set the BuildAction for Android to AndroidAsset for me, but I had to manually set the BuildAction for iOS to BundleResource. Double check each of those to make sure yours is set correctly also, or CocosSharp won’t find the font at runtime. You’ll know whether you did this correctly when you run your game. CocosSharp will not error out when it can’t find your font, but it will revert to the default font.

Usage

Once you have your font included in your platform-specific projects, you can put it to use with a label instance.

Let me break this down a bit.

Parameter 1: “Hello World”
This is the initial text displayed by the label. It can be changed at run-time, which we will talk about in a bit. It’s important to note that, for sizing purposes, you have to have a value for this. Starting with an empty string will give you a width and height of 0, which can be problematic when it comes time to properly position the label, particularly if you are doing vertical positioning. If you have to start with dummy text, then change it at run-time, do it.

Parameter 2: “Fonts/myfont.ttf”
This is the location of the font file to use, within the Content folder. The file extension isn’t supposed to be required, but I found in practice that it is.

Parameter 3: 40 * Constants.FontSizeMultiplier
This is the font size. You can have this be a fixed size, but I found that font sizes need to scale just like sprite graphic files do. I covered the reasoning behind this in the Foundation post. Constants.FontSizeMultiplier is a static float that is set during the initial startup code.

Parameter 4: CCLabelFormat.SystemFont
This is the type of font being used. When you use your own font file that is included in the projects, you will use CCLabelFormat.SystemFont.

Making Run-Time Changes

Now that you’ve got an instance of a label, you can position it just like any other node. You may also find the need to update that label with different text, or even colors, at run-time. Either of these are simple to change.

The code above changes the text of the label. As simple as this is, there’s a gotcha that I found in practice with this: Every time I’ve changed the text of a label after it has been initially instantiated, I’ve found that a few bytes of memory are leaked. I haven’t taken the time yet to dive into the CocosSharp code to see why that might be the case, but I found it to be consistently true. A few bytes of memory leaked may not seem like a big deal. Do that enough times, however, and eventually the device can run out of memory, causing your game to crash. Just something to keep in mind.

The code above changes the color of the label to red. What’s important to note there is that the color in this case uses the CCColor3B struct, which is different from CCDrawNode (which uses CCColor4B). CCColor3B and CCColor4B both are very similar. However, in practice, I found that a label with a custom color will render as a slightly different color from the CCDrawNode rendered with the “same” custom color. Again, I haven’t looked into the CocosSharp code to find out why this is the case, but it is noticeable if you place the two next to each other.

That wraps up our discussion of CCLabel as well as the provided implementations of the CCNode class. In my next post, I’ll talk about what it takes to implement your own custom CCNode class.

Share

CocosSharp – Learning To Use CCDrawNode

This post is part of my Mobile Game Development series. Start at the beginning to catch up. This series was inspired by the things I learned developing a new game for Android and iOS called Mirror Maze.


Earlier in this series, I talked about CCSprite for graphic file and frame-based animation needs. Sometimes you just want to draw your own stuff in code. There can be a lot of reasons why you’d want to do that and I certainly did for several elements within Mirror Maze. Enter CCDrawNode.

CCDrawNode provides methods to draw a number of 2D shapes, such as lines, circles, and rectangles. It’s pretty straightforward to call these methods, but there are some gotchas to be aware of.

Drawing a Line

Let’s start with the the most simple command: drawing a line.

The code above instantiates a CCDrawNode, then draws a blue line with a width of 1 unit from the point (0, 0) to the point (10, 10). While this is straight-forward, there are some things to be aware of here.

First, the points used here, (0, 0) and (10, 10) are relative to the Draw Node’s origin and has nothing to do with it’s position. To explain why that is important, let me give an example.

The code above has two different draw nodes that both draw a blue line from (0, 0) to (10, 10). However, drawNode2 has a position of (20, 0). What the user will actually see is two diagonal blue lines of the same length and angle, one drawn from (0, 0) to (10, 10) and one drawn from (20, 0) to (30, 10). How is that possible since they both used the same coordinates to draw? Because the draw node’s origin is always the same, but the draw node itself is moved by the position.

The whole concept of positioning with CocosSharp is complex enough that I will have an entire post coming up that will cover only positioning. For now, just think of drawing to the draw node as you would drawing on a piece of paper. You can draw on that paper however you like, then move that paper around the table. The drawing is always the same relative to the paper, but the paper itself can be moved to a different position on the table.

Drawing a Rectangle

The next drawing command I want to talk about is drawing a rectangle. There are several different DrawRect methods available with CCDrawNode, so I’ll show the one I use the most.

The code above draws a filled blue rectangle at (0, 0) with a width of 20 and a height of 10. This is self-explanatory and the only thing I have to add is to keep in mind the paper/table metaphor from above with the line. The rectangle can be drawn wherever you want it to be on the “paper”, then the paper can be moved on the “table”.

Drawing a Circle

Drawing a circle is simple to do, but requires a little explanation to fully understand what is going on.

The code above draws a yellow circle at (0, 0), with a radius of 10. Here’s the catch: the position you provide to draw the circle is is the center of the circle. That may seem like what you would expect, but the ramification of that is that the circle will actually be drawn into -x and -y ranges. If you’ve been happily drawing lines and rectangles starting at (0, 0) and then you decide to draw a circle at (0, 0), you’ll find that the circle may not look like it’s drawn in the correct place. To draw the circle to match the expectations set by the line and rectangle commands, you’ll need to modify your position to account for the size of the radius.

Now you’ll draw a circle where you probably expected it to go in the first place.

CCDrawNode provides several more draw commands for you to play around with, but this is enough for you to get a decent start. Just remember to know the difference between where you are drawing on the draw node versus where that draw node is actually positioned and you’ll be in good shape.

Share

CocosSharp – Getting to Know CCSprite

This post is part of my Mobile Game Development series. Start at the beginning to catch up. This series was inspired by the things I learned developing a new game for Android and iOS called Mirror Maze.


In my last post, I talked about CCNode, the root class for all visible elements in CocosSharp. In this post, I’d like to talk about a class that inherits from CCNode, which I expect you will find yourself making use of quite often: CCSprite.

Let’s say that you want to make a graphic in your favorite graphic editor, output a graphic file, then display that graphic in your game. You would want to use CCSprite to pull this off. First things first, though. That graphic file has to get pulled into your project. Earlier in this series, I talked about how graphic files get put into both your Android and iOS projects, under Content > Images > Hd|Ld. I also mentioned that they have to be placed into both your Android and your iOS projects because each platform includes them in the final package differently. In Android, you need to make sure the Build Action for each file within the Content folder is set to AndroidAsset. In iOS, the Build Action needs to be set to BundleResource.

A quick note here: I found Xamarin Studio didn’t like to set the Build Action properly for iOS references automatically. I had to change each one of them myself to BundleResource.

In that same post, I talked about how you initialize the Game View to know where to look for assets. CCSprites are one of the elements that will put that to use. One of the constructors for CCSprites takes, as a parameter, the name of a file to render. That filename can include the file extension if you like, but it’s good practice not to. In fact, you could include the full path to the file too, if you wanted. Again, it’s good practice not to. Just the name is enough. CocosSharp will look in the folders specified in that initialization for file names matching the one you provide. This allows the engine to pick up either the High Density file or the Low Density file, depending on the pixel density of the device the game is running on.

There are two steps that need to occur for your sprite to be created and added to the active layer. First, you instantiate the sprite. Second, you add the sprite as a child to the current layer (or node).

Doing that, and nothing more, will render your sprite in the current layer at the position (0, 0), which is the lower-left corner of the screen. We will cover positioning much more in a later post. For now, (0, 0) is good enough for us. So now you’ve got a static sprite in your game and that may be exactly what you need. If that is the case, awesome. Carry on and make an great game. Mirror Maze v1, for example, only uses static sprites.

Sprites can do more than display static images, though. Sprites can also do frame-by-frame animation, kind of like cartoons. Why would you want to do something like this? Maybe your game involves a character that has a standing graphic when sitting idle, then needs to walk or run when moving around. The standing graphic is a single frame, but the walking or running animation will be a series of frames in order for the user to see a smooth animation.

There’s four steps to animate your sprite.

Step 1: Design each frame in your graphic editor and output those frames into individual graphic files. This involves your graphic editor program. As I mentioned previously, I use Inkscape. Design your animation frames however you choose, then output them each into their own individual graphic files making sure that each file is the same dimension. This is important so that the animation will look smooth. Also important is how you name the files. You’ll want to name them with a consistent naming scheme, such as “WalkingX”, where X is the number of that file in the sequence.

Step 2: Package those individual graphic files into a sprite sheet. There are a number of ways you can do this, but I used a handy tool called Texture Packer. Texture Packer has a lot of features that you can pay for, but the free version has enough functionality to create a nice sprite sheet for you. What you’ll find from the output of this is that a sprite sheet is actually two things: the graphic file containing all the sprites in a single sheet and the .plist file that specifies where each frame resides in that sprite sheet graphic file. Also remember that you will want to create different sized sprite sheets for your Hd and Ld folders.

Step 3: The output files from Step 2 need to be imported into your respective Images folders for each platform. Remember that Android needs to reference the files as AndroidAsset and iOS needs to reference the files as BundleResource.

Step 4: This is where you create the sprite instance and put that sprite sheet to use. The following code creates a CCSprite, loads up the sprite sheet in a CCSpriteSheet instance, then creates a forever repeating animation with all the sprites whose filename contains “walk” and adds it to the sprite as an Action.

You can also change to a single, static image for the sprite by setting the SpriteFrame:

Now you are free to start making characters in your game that have a little more “character” by creating frame-based animations.

In my next post, I’ll take a look at another CCNode child object that allows you to draw things.

Share

CocosSharp – The Building Blocks

This post is part of my Mobile Game Development series. Start at the beginning to catch up. This series was inspired by the things I learned developing a new game for Android and iOS called Mirror Maze.


Let’s talk about some of the elements that make up the building blocks of your CocosSharp game: CCNode, CCScene, and CCLayer. All of your elements will either be one of these types or will derive from one of them.

CCNode is the base class for all things visual. It provides a ton of functionality out of the box and you can instantiate one directly, if you want. All the other types ultimately derive from CCNode. There’s a lot to understand about CCNode, but I want to cover a couple of other key things first, so we’ll come back to this one shortly.

CCScene is the root element of what you see on the screen. A Scene is a logical collection of functionality in your application. You can have as many scenes as you want in your application, but only one will ever be showing at a time. Well, technically you can have CCScenes stacked up, but that’s really frowned upon because hidden scenes will consume resources and potentially slow your game down. CCGameView has a Director which controls which CCScene is currently being displayed. You can supposedly transition from one scene to another with a nice fade, or some other such transition. However, I was never able to make that work and treated it as essentially a hard cut from one scene to the next. In Mirror Maze, I have a MenuScene and a GameScene. The MenuScene handles displaying the game options and letting the user select which maze to start with. The GameScene does everything related to the actual game play.

The next element in the hierarchy is CCLayer. CCLayer essentially represents the concept of a layer. Your app can have as many layers as you want, but each scene needs at least one. The layer itself isn’t a visible element. Think of it more like a clear surface that you can place things on. The things you place on it are visible, but the layer itself is not. Layers can be handy for grouping things that you want to show/hide or move as a group.

Now, let’s say that you want to add a layer, but you want that layer to have a solid color background instead of being clear. CCLayerColor is your buddy. You can select a predefined color from the CCColor4B static properties, or you can create your own with RGBA values. Placing a CCLayerColor instance on top will cover up everything beneath it.

Ok, let’s get back to talking about CCNode. CCNodes aren’t visible in and of themselves, but they can contain children which are visible. What CCNodes DO provide are the ability to be positioned, scaled, and rotated. CCNodes have an inherent ContentSize (how wide and tall the contents of the node are) which, coupled with position, can give you the BoundingBox of the node. Think of the BoundingBox as the footprint of the node. The BoundingBox is a bit of an animal itself, so I’m planning to write up a post specifically to help understand just that.

While it’s totally acceptable to instantiate a CCNode instance and put it to use, you’re more likely going to either use one of the child types provided out of the box or create your own classes that inherit from CCNode and provide your own functionality.

In the next few posts, I’ll dive into some of these child types and implementing your own node types.

Share

CocosSharp – The Foundation

This post is part of my Mobile Game Development series. Start at the beginning to catch up. This series was inspired by the things I learned developing a new game for Android and iOS called Mirror Maze.


Getting started with anything new can be daunting and CocosSharp is no exception. I certainly felt a little overwhelmed as I started to play around with test applications. Once I started to get an understanding of how CocosSharp works, I found it easier to focus on what I needed to learn one part at a time. My hope with this post is to help you gain enough understanding of the basics to be able to do the same.

As I said earlier in this series, CocosSharp is an implementation of the Cocos2D game engine. That’s important to remember because documentation on CocosSharp can sometimes be lacking. However, it opens up the door if you can find examples of what you are looking for with Cocos2D, then translate it to CocosSharp. That being said, Xamarin does have some CocosSharp documentation available to check out.

A quick note before I go any further. For the purposes of this series, I’ll be talking about CocosSharp in the context of Android and iOS. However, CocosSharp will run on many more platforms than just those two. Most of the topics I plan to discuss should apply to all the platforms CocosSharp is available on, though.

CocosSharp has a Game View (CCGameView) that will be placed either in your MainActivity for Android or your main ViewController for iOS. That Game View will contain your entire game. That means your app lives entirely in a single Activity or view. All navigation between “pages” within the game is only logical navigation. As far as your device is concerned, your app doesn’t navigate anywhere.

That Game View will need to be initialized in order to know how big your design resolution is and where to look for things. In some examples you’ll see that initialization code copied into each platform’s project, but I found it was the same code and moved it into my common project.

Below is my initialization code for Mirror Maze, followed by how it gets wired up in an Android Activity and an iOS ViewController.

What is Design Resolution?

The design resolution topic is rather interesting. You specify the resolution of the Game View by giving it a width and a height. That is the logical size, not the pixel size. CocosSharp will take that resolution and scale it to fit whatever size device your app is running on. That means that all the sizing and positioning you do in your application doesn’t necessarily directly relate to the actual pixels on the device. This fact is actually really cool. It takes away the need to handle different sized devices in your code. There are some drawbacks, however. The first is that you can’t make your game look different on tablets vs phones, at least not without a lot of extra work. Second, if your defined resolution doesn’t fit perfectly on the device that your app is running on, you will get what is known as “letterboxing”.

Letterboxing is where there are bars either above and below or to the left and to the right of your Game View. That is because your Game View will size your game to fit the device’s physical aspect ratio, position it in the center of the screen, then fill in any remaining space with a default color (black on Android and white on iOS). I found that to be rather annoying when I was getting serious about my game’s look-and-feel, but I did find a way to change the color of the bars to blend into my app. Don’t worry, I’ll share that in a later post.

The design resolution doesn’t need to match your physical device’s actual resolution. I learned this the hard way. I thought it needed to match the width and height to the pixel, so I added code that made the design resolution dynamically match the device when the app started up. All that did was make my aspect ratio goofed up on any device other than the one I targeted first, causing things to be sized and positioned wrong within my game. Take my word for it: don’t do that. Instead, pick an aspect ratio that you want to work with, then find a comfortable size with that aspect ratio to set your Game View. A smaller design resolution will make a 10×10 sized object look bigger and a bigger design resolution will make that same object look smaller. What resolution you choose will depend on your app’s UI needs.

Asset Location

The other thing your Game View setup code will need to do is tell the Game View where to look for assets, such as image files for sprites, audio files, and fonts. Most of the examples you see will show the Images folder containing two sub-folders: Hd and Ld. Hd is for High density devices and Ld is for Low density devices. You can also write your app to have more options than that, if you like. I found that the image files I needed for Hd were twice the pixel size as those I needed for Ld. Which brings me to another interesting point: use vector-based graphics for your source. I used Inkscape to create my graphics. That allowed me to resize easily, without losing image quality.

Another lesson I learned regarding the Hd vs Ld concept was that fonts also need to be different sizes for your labels to be scaled correctly on different sized devices. The way I handled this is to add a static property called FontSizeMultiplier, which I set along with the Game View initialization stuff. For Hd devices, the multiplier is 2.0. For Ld devices, the multiplier is 1.0. Then, every label would have whatever font size I wanted to use * that multiplier. Now all my labels are sized as I expect them to be. I didn’t even notice this was an issue until I tried testing my app on a tablet, instead of the usual phone, and saw that all the labels were way too small.

One thing that isn’t immediately clear until you look at a sample project is that the Images folder (containing Hd and Ld), as well as the Fonts and Sounds folders all reside within a Content folder. That Content folder is NOT part of the common project where most of your code will go. This is because the files contained within the Content folder need to be included in the output generated by each platform’s project. Android references those files differently than iOS does. As a result, both the Android project and the iOS project have a Content folder containing your sounds, images, and fonts. On Android, the Content folder resides within the Assets folder. On iOS, the Content folder resides in the root.

Since you will likely be using the same files on both Android and iOS, it makes sense to only create those files once, then reference them in both places. I did this by adding all the files to my Android project, then adding them as Links in my iOS project. Believe me, you’ll want to do something similar so save yourself the headache of double maintenance.

In the next post we’ll start taking a look at the classes you’ll be working with to build CocosSharp games.

Share