Subscribe to GameFromScratch on YouTube Support GameFromScratch on Patreon
19. March 2013

In part 3 we created a simple Loom application. 

In this section, we are going to look at how to draw graphics using the Loom game engine.  I am going to make use of a sprite sheet I obtained here.  Feel free of course to substitute whatever image you want.  Keep in mind, I have no rights to that image, so neither do you!  If you are the author and want it removed, let me know and I will.

 

Anyways, lets jump right in and draw a single sprite centred on screen.

 

package

{

    import cocos2d.Cocos2DGame;

    import cocos2d.CCSprite;

    import cocos2d.Cocos2D;

 

    public class HelloWorld extends Cocos2DGame

    {

        override public function run():void

        {

            super.run();

            var sprite = CCSprite.createFromFile("assets/robin.png");

            

            sprite.x = Cocos2D.getDisplayWidth()/2;

            sprite.y = Cocos2D.getDisplayHeight()/2;

            layer.addChild(sprite);

        }

    }

}

 

The code is pretty much identical to our Hello World code earlier.  As you can see, CCSprite elements ( CCNode derived more accurately ) objects are positioned relative to their centre by default, while the positioning is relative to the bottom left corner of the screen.

Run this code and you will see:

Loom Sprite Example

 

As you can see from the bottom corner, we are running at 60 FPS, but considering we aren't doing anything, thats not really all that impressive.

 

 

Let's see what happens when we dial it up to 1000.

package

{

    import cocos2d.Cocos2DGame;

    import cocos2d.CCSprite;

    import cocos2d.Cocos2D;

 

    public class HelloWorld extends Cocos2DGame

    {

        override public function run():void

        {

            //var sprites:Array = new Array();

            var sprites = new Vector.<CCSprite>(); 

            var i:int = 0;

 

            for(i = 0; i < 1000; i++){

                var sprite = CCSprite.createFromFile("assets/robin.png");    

                sprite.x = Math.random() * Cocos2D.getDisplayWidth();

                sprite.y = Math.random() * Cocos2D.getDisplayHeight();

 

                sprites.push(sprite);

            }

 

            for each( var spr in sprites){

                layer.addChild(spr);     

            }

 

            super.run();

        }

    }

}

 

This code shows one of the differences from ActionScript.  In comments you can see how the ActionScript array would work.  Since LoomScript is typed you can't do this, so instead your create a Vector of type CCSprite.  Once created though, its functionally identical to an array, at least on the surface.  We simply loop a thousand times, randomizing the position within the screen limits.  We then loop through all of the sprites ( yes, I realize I could have simply done this in the first for loop ) in the array and add them to our layer.  This is an area I found a bit odd, from my C++ warped programming mind, I couldn't re-use the name sprite in my foreach scope because it recognized the previous variable 'sprite' as being in local scope.  I don't know if this odd scoping is an ActionScript thing, or LoomScript thing.

Here is our application running:

A Flock of Robins

 

Down to 24FPS… hmm, 1000 sprites isn't an unrealistic amount, let's see if we can't speed that up a bit.  Generally there is a sprite batching system available, for when you are drawing similar images over and over, and Loom is no exception.

Here is the same application using CCSpriteBatchNode:

package

{

    import cocos2d.Cocos2DGame;

    import cocos2d.CCSprite;

    import cocos2d.Cocos2D;

    import cocos2d.CCSpriteBatchNode;

 

    public class HelloWorld extends Cocos2DGame

    {

        override public function run():void

        {

            //var sprites:Array = new Array();

            var sprites = new Vector.<CCSprite>(); 

            var i:int = 0;

 

            var spriteBatch = CCSpriteBatchNode.create("assets/robin.png");

            layer.addChild(spriteBatch);

            for(i = 0; i < 1000; i++){

                var sprite = CCSprite.createFromFile("assets/robin.png");    

                sprite.x = Math.random() * Cocos2D.getDisplayWidth();

                sprite.y = Math.random() * Cocos2D.getDisplayHeight();

 

                sprites.push(sprite);

            }

 

            for each( var spr in sprites){

                spriteBatch.addChild(spr);     

            }

 

            super.run();

        }

    }

}

 

 

 Now when we run this newly updated version:

 

Sprites using spritebatching

 

A net gain of 13FPS.  Of course, there are probably a few thousand optimizations I could perform, but its nice to see the most common ones are in there.

 

Up until this point, we've only used one sprite in our sprite sheet.  Let's take a look at performing an animation using them all.

Here again is our source image:

Robins

 

The image is 1200x1570 in dimension and contains a 5x5 grid of sprites ( except the last three that is ).

 

Let's take a look at the code behind animating a sprite sheet ( or texture atlas, pick your poison ):

package

{

    import cocos2d.Cocos2DGame;

    import cocos2d.CCSprite;

    import cocos2d.Cocos2D;

    import cocos2d.CCAnimation;

    import cocos2d.CCSpriteFrame;

    import cocos2d.CCRect;

    import cocos2d.CCPoint;

    import cocos2d.CCSize;

    import cocos2d.CCAnimationCache;

 

    public class HelloWorld extends Cocos2DGame

    {

 

        public var sprite:CCSprite;

        

        public var currentFrame:int;

 

        public var lastFrameTime:Number;

        public var elapsedTime:Number;

 

 

        override public function run():void

        {

            lastFrameTime = 0;

 

            var animation:CCAnimation;

 

            currentFrame = 0;

            sprite = CCSprite.create();

            sprite.x = Cocos2D.getDisplayWidth()/2;

            sprite.y = Cocos2D.getDisplayHeight()/2;

 

            animation = CCAnimation.animation(); // Why not createAnimation()?

 

            var frameRect:CCRect;

            var frameSize:CCSize;

            frameSize.width = 240;

            frameSize.height = 314;

 

            for(var i =0; i < 5; i++){

                for(var j =0; j < 5; j++){

                    if(i == 4 && j > 1)

                        break;

                    frameRect.setRect(j * frameSize.width, i * frameSize.height, frameSize.width, frameSize.height);

                    var frame = CCSpriteFrame.create("assets/robins.png",frameRect,false,new CCPoint(), frameSize);

                    animation.addSpriteFrame(frame);

                }

            }

            CCAnimationCache.sharedAnimationCache().addAnimation(animation, "fly");

 

            layer.addChild(sprite);

            super.run();

        }

 

        override public function onTick():void {

            var thisFrameTime:Number = Platform.getTime();

            var delta:Number = thisFrameTime - lastFrameTime;

            

            lastFrameTime = thisFrameTime;

            elapsedTime += delta;

 

            if(elapsedTime > 100){

                elapsedTime = 0;

                sprite.setDisplayFrameWithAnimationName("fly",currentFrame);

                

                if(currentFrame > 20){

                    currentFrame = 0;

                }

                else{

                    currentFrame++;

                }

            }

        }

    }

}

 

Now when you run the application, you should see:


RobinFlight

 

The heart of this code is a pair of loops that create a Rect representing the location of the frame within the parent image.  Each frame is created as a CCSpriteFrame, all using the same source image file as well as the newly created rect for the frames location within the sprite sheet.  We then add each CCSpriteFrame to the CCAnimation variable with the call addSpriteFrame().

 

Now that our CCAnimation is fully populated, we add it to a global animation cache by calling CCAnimationCache.sharedAnimationCache().addAnimation(), passing in our newly created CCAnimation, as well as a string that we will access it by later.

 

This is an area I found quite annoying to deal with Loom, or more specifically Cocos2D.  I don't really like the idea of using global managers if I don't have to, so I attempted to just keep a CCAnimation locally and use it to populate my CCSprite each frame.  You can't, or at least, you can't easily.  All (Cocos2D, not Loom) samples you will find either lead to a deprecated method in CCSprite, or down a wild goose chase of Animation related functionality in Cocos2D.  There seem to be a dozen ways to perform animations, little of which work with each other.  The Cocos2D library is definite need of streamlining!  I also ran into inconsistent naming conventions, like the above mentioned CCAnimation.animation() call.  The convention generally is CCAnimation.create() or CCAnimation.createAnimation(), and I believe both exist, so why break with the naming convention here?  This is one of those things I ran into with Cocos2d-html and it's frustrating and makes learning and working with the SDK harder.  This isn't a bash on Loom, it's functionality it inherited from Cocos2D, but one is thoroughly tied to the other.

 

Our remaining code is the onTick handler, which will be called every iteration of the game loop.  We want to advance to the next frame after 100 milliseconds have elapsed, so we figure out how much time has elapsed since the prior frame and add it to our running total.  Once 100ms is reached, we advance to the next frame in the animation we cached earlier, with the call sprite.setDisplayFrameWithAnimationName().


As you can see though, once you puzzle out the convoluted hierarchy of classes provided by Cocos2D, drawing a sprite, drawing a sprite from a sprite sheet, and animating between frames is a rather easy task in Loom.

 

I did run into another snag, specific to LoomScript, on using the TimeManager class in place of Platform.getTime(), but truth of the matter, it's probably me not understanding dependency injection.  It's the first time I haven't been able to puzzle something out myself, which is rather impressive for a new library.  It is also the first time I have personally used their support forum.  It's been less than an hour since I posted, and I've already received a useful reply, so I have to give them thumbs up for that!

 

In the next part we will look at controlling your application and maybe a bit more, as we near the end of this tour.


12. March 2013

This is part 3, the following are links for part one and part two in this series.

 

Alright, we've installed the tools, got an editor up and going and now how to run the generated code, both on our computers and on device ( well… Android anyways… I don't currently have an iOS developer license from Apple ), so now the obvious next step is to take a look at code.

 

Let's get one thing clear right away…  I know nothing about ActionScript, never used it, and I didn't bother taking the time to learn how.  As unfair as that sounds, frankly when it comes to scripting languages, I rarely bother learning them in advance… I jump in with both feet and if they are good scripting languages, you can generally puzzle them out with minimal effort.  This is frankly the entire point of using a scripting language.  So today is no different.  This may mean I do some stupid stuff, or get impressed by stuff that makes you go… well duh.  Just making that clear before we continue… now, lets continue...

 

LoomScript

 

 

Apparently LoomScript is ActionScript with a mashup of C# and a smattering of CSS.  ActionScript is itself derived or based on JavaScript.  I know and like JavaScript and know and like C#, so we should get along fabulously.

 

Let's look at the specific changes from ActionScript.

 

First are delegates, a wonderful feature of C#.  What exactly is a delegate?  In simple terms it's a function object, or in C++ terms, a function pointer.  It's basically a variable that is also a function.  This allows you to easily create dynamic event handlers or even call multiple functions at once.

Next was type inference, think the var keyword in C# or auto keyword in C++ 11. 

They added support for the struct data type.  This is a pre-initialized and copy by value (as opposed to reference) class.  I am assuming this is to work around an annoyance in ActionScript programming that I've never encountered.

They also added C# style Reflection libraries.  I assume this is confined to the System.Reflection namespaces.  If you are unfamiliar with Reflection in C# land, it's a darned handy feature.  In a nutshell, it lets you know a heck of a lot about objects at runtime, allowing you to query information about what "object" you are currently working with and what it can do.  It also enables you load assemblies and execute code at runtime.  Some incredibly powerful coding techniques are enabled using reflection.  If you come from a C++ background, it's kinda like RTTI, just far better with less of an overall performance hit. 

Finally they added operator overloading.  Some people absolutely love this feature…  I am not one of those people.  I understand the appeal, I just think it's abused more often than used well.  This is an old argument and I generally am in the minority on this one.

 

Hello World

 

 

Now let's take a look at creating the iconic Hello World example.

 

First is the loom.config file, it was created for us:

{

  "sdk_version": "1.0.782",

  "executable": "Main.loom",

  "display": {

    "width": 480,

    "height": 320,

    "title": "Hello Loom",

    "stats": true,

    "orientation": "landscape"

  },

  "app_id": "com.gamefromscratch.HelloLoom",

  "app_name": "HelloWorld"

}

 

This is basically the run characteristics of your application.  This is where you set application dimensions, the title, the application name, etc.  Initially you don't really even have to touch this file, but it's good to know where it is and to understand where the app details are set.

 

Pretty much every application has a main function of some sort, the entry point of your application and Loom is no exception.  Here is ours in main.ls

package

{

    import cocos2d.Cocos2DApplication;

 

    static class Main extends Cocos2DApplication

    {

        protected static var game:HelloWorld = new HelloWorld();

 

        public static function main()

        {

            initialize();

            

            onStart += game.run;

        }

    }

}

 

Here we are creating a Cocos2DApplication class Main, with one member, our (soon to be created) Cocos2DGame derived class HelloWorld.

We have one function, main(), which is our app entry point, and is called when the application is started.  Here you can see the first use of a delegate in LoomScript, where you assign the function game.run to the delegate onStart, which is a property of Cocos2DApplication.  In a nutshell, this is the function that is going to be called when our app is run.  We will look at HelloWorld's run() function now.

Speaking of HelloWorld, lets take a look at HelloWorld.ls

package

{

    import cocos2d.Cocos2DGame;

    import cocos2d.Cocos2D;

    import UI.Label;

 

 

    public class HelloWorld extends Cocos2DGame

    {

        override public function run():void

        {

            super.run();

 

            var label = new Label("assets/Curse-hd.fnt");

            label.text = "Hello World";

            label.x = Cocos2D.getDisplayWidth()/2;

            label.y = Cocos2D.getDisplayHeight()/2;

            

            System.Console.print("Hello World! printed to console");

 

            //Gratuitous delegate example!

            layer.onTouchEnded += function(){

                label.text = "Touched";

            }

            

            layer.addChild(label);

        }

    }

}

 

We start off with a series of imports… these tell Loom what libaries/namespaces we need to access.  We added cocos2d.Cocos2D to have access to Cocos2D.getDisplayWidth() and Cocos2D.getDisplayHeight().  Without this import, these methods would fail.  We similarly import UI.Label to have access to the label control.

 

Remember about 20 seconds ago ( if no btw… you may wish to get that looked into… ) when we assigned game.run to the Cocos2DApplications onStart delegate?  Will, this is where we define the run method.

 

The very first thing it does is calls the parent's run() method to perform the default behaviour.  Next we create a Label widget using the font file Curse-hd.fnt (that was automatically added to our project when it was created ).  We set the text to "Hello World" and (mostly) centre the label to the screen by setting its x and y properties.  You may notice something odd here, depending on your background…  the coordinate system.  When working with Cocos2D, there are a couple things to keep in mind.  First, things are positioned relative to the bottom left corner of the screen/window/layer by default, not the top left.  Second, nodes within the world are by default positioned relative to their centre.  It takes a bit of getting used to, and can be overridden if needed.

Next we print "Hello World was printed to the console" to demonstrate how to print to the console.  Then we follow with another bit of demonstrative code.  This is wiring a delegate to the layer.onTouchEnded property.  This function is going to be called when the screen is released, as you can see, this is an anonymous function, unlike run we used earlier.  When a touch happens, we simply change the label's text to Touched.  Finally we add the label to our layer, inherited from Cocos2DGame.

 

Run the code and you will see:

Loom2

 

While if you check out your terminal window, you will see:

 

Loom1

As you can see, Hello world is also displayed to the terminal.

 

Now lets take a look at one of the cool features of Loom.  Simply edit an .ls file in your text editor of choice and if you are currently running your project, if you flip back to the terminal window you will see:

 

Loom3

 

Loom is automatically updating the code live as you make changes.  This is very cool feature.  Ironically though, in this particular case, it's a useless one as all of our code runs only when the application is first started.  However in more complicated apps, this will be a massive time saver.

 

On top, this is also how you can easily detect errors… let's go about creating one right now.  Instead of label.Text, we are going to make an error, label.Txt.  Save your code and see what happened in the Terminal window:

 

Loom4

 

As you can see the error and line number are reported live in the Terminal without you having to stop and run your application again.

 

 

Pretty cool over all.  In the next part, we will look at more real world code examples.

 

You can read the next part dealing with graphics right here.


25. February 2013

 

Samsung and Chillingo have launched their 100% indie campaign.

image

 

Basically they are offering developers (initially) 100% of revenue of games sold in their app store.  As of writing, there are just under 7 days remaining to submit the (note, not your) application if you are interested.

 

I have a couple Samsung phones and I have to say, I never liked their app store. That said, if you are developing or developed an Android game, I can think of few reasons not to submit it.  Another sales outlet is always a nice thing, as of course are 100% royalty rates.

 

Very few details exist right now, so be sure to read the fine print… when you find it.  You can sign up here.

News


22. February 2013

 

Monotouch and Monodroid ( long since renamed ) are two products that I have *almost* purchased half a hundred times.  If you’ve not heard of them, they are a native port of C# and most of the .NET libraries to iOS and Android.  They have been having a good run and are the underpinnings of a number of very successful projects, such as PlayStation Mobile and Unity3D.  I really like .NET too but… and there is always a BUT.

 

It was 400$ for the basic version.  That’s 400$ for each platform too by the way.  That’s a pretty hard pill to swallow, especially when most of the competing products are free.  Or frankly, you could pick up the full Unity package for less than that!  Monotouch always offered a trial version, but it was limited to the emulator/simulator and if you have ever used the Android emulator on Windows, you know how vile that is!

 

Well, great news! 

 

First off, there is now a free version available that lets you deploy to device!  That said, you can’t p/Invoke to 3rd party code.  I honestly am not sure how much of a limitation that is.  Generally that means you can’t run native code, but still can run .NET assemblies.  If that’s the limitation, it isn’t a huge one.  If it means no libraries though… well, that’s a bit more painful.  I wonder if you can run Monogame, libGDX or PlayN in the free version?  Will look into that and get back to you.

 

Second, there has been a price drop.  It’s now 299$ per platform, per year.  Somehow, that 100$ makes a huge difference for me.  I don’t really like annual subscriptions though, I really wish people would move back towards version releases…  All the same, cheaper is always nice.

 

Third, there’s a new IDE, Xamarin Studio.

382920489522

A little too XCode for my tastes, but I’ll be sure to check it out.  MonoDevelop is nice enough, but never really felt… comfortable if that makes sense.

 

Fourth, and this one is a biggie to many people.  You can build for iOS from Visual Studio on Windows.  Don’t get too excited, you still need a networked Mac to run the native toolchain, but you can do 99% of your work, debugging and testing in Visual Studio.

 

 

Very cool developments!  You can read more about it here.

 

EDIT:

 

A few points of clarification.

First is regarding the 299/year.  It’s not as bad as it sounds, the tools continue to work after a year is up, just no more updates.  That is much more reasonable and developer friendly.

Second is more details on the free version:

Xamarin Starter allows developer to build and publish simple apps, which contain no more than 32k of compiled user code (IL), and which do not call out to native third party libraries (i.e., developers may not P/Invoke into C/C++/Objective-C/Java.

Still not sure where that would leave Monogame, as it isn’t a native library, but it does no doubt make pInvoke calls to OpenGL.

General News Programming


21. January 2013

 

This one is a big one.  If you have never heard of it, monoGame started life as a way to port XNA applications to the various Mono targets (including iOS and Android), built on top of OpenGL.  With Microsoft basically retiring XNA, monoGame has basically become the future of XNA.

The biggest and most obvious addition in this release is 3D support, but there are a number of other great new features:image

 

What's New?
  • 3D (many thanks to Infinite Flight Studios for the code and Sickhead Games in taking the time to merge the code in)
  • New platforms: Windows 8, Windows Phone 8, OUYA, PlayStation Mobile (including Vita).
  • Custom Effects.
  • PVRTC support for iOS.
  • iOS supports compressed Songs.
  • Skinned Meshs
  • VS2012 templates.
  • New Windows Installer
  • New MonoDevelop Package/AddIn
  • A LOT of bug fixes
  • Closer XNA 4 compatibility
  •  

    The also added a new installer that will install a binary release of Monogame on Windows for use with Visual Studio.  MonoDevelop users can update with the Add-in Manager.

    Head on over here for the release announcement.

     

    Nice work Monogame team!

    News


    GFS On YouTube

    See More Tutorials on DevGa.me!

    Month List