Subscribe to GameFromScratch on YouTube Support GameFromScratch on Patreon
11. April 2013

I mentioned yesterday that i've become rather smitten with Codea but didn't exactly find the prospect of typing on the iPad screen appealing.  I could have hooked up a Bluetooth keyboard, but I don't want to carry one around with me, especially as the one I own is massive.  I didn't really feel like spending 50-100$ on a portable one, I generally can't stand them if I'm honest.  In the end I came up with the following solution and I actually rather like it.  There is a price tag attached with this setup though, about 16$  ( or 1416$ if you count the MacBook and iPad Mini…).  Which ironically enough is more than Codea costs!  I was going to buy the one app anyways for other reasons, so that was a non-factor for me.

 

Here is my Codea dev environment in action!

 

Codeonmac

 

Instead of using a Bluetooth Keyboard, I am using my MacBook as one using the application Type2Phone, a simple little application that acts like a virtual bluetooth keyboard.

Type2Phone

Connect and pair like a normal bluetooth device, then when the app has focused, anything types is sent to your iPad and the iPad's keyboard is hidden.  Type2Phone has a 4.99$ price tag, but it works very well and has plenty of options.  Even more important, it handles connects and disconnects very well.  There is a more expensive app called iKeyboard, the one you will find if you google.  It doesn't appear to be maintained, doesn't work with iOS6 and costs twice as much.  Use Type2Phone instead, even if it has a horrible name! :)  It's one of those slick little utilities that sets out to do one thing and does it well, I appreciate those.  If you are running on a PC, I am certain you will be able to find similar utilities, as long as you have bluetooth that is.

 

Now typing and looking at a different device is kinda awkward, so I decided to mirror my iPad's display to screen.  The easiest way to do this is with Reflector a 13$ purchase that runs on either Mac OS or Windows an enables you to mirror your iPad display on your desktop using Airplay.  So long as your network connection, the results are pretty solid.  In the above picture, I am out at a coffee shop with both devices tethered through my Android phone and it was a bit choppy at times when running a game or movie, but flawless when programming in Codea.  On my home network, it's simply flawless.

Here is Codea running mirrored on my desktop using Reflector.

Codea over airplay

 

Now, Reflector is a cool little application and one I was intended to purchase anyways ( it's one of the easiest ways to screen capture an iOS game at full speed without having to run the simulator.

 

Now you may be asking, why not just run the simulator?  At the end of the day, you can't beat running on the actual device, especially when it comes to motion controls and multitouch.  Plus, under this setup, all of my code exists in one place, on the device, no need to move from Mac to Dropbox to iPad for example, or the other various deployment mechanisms.  Plus at any time I can just pick up the device and go, the big strength of Codea.  This way, I can give myself a desktop like development experience when I am at home or have my laptop with me, but I can still take advantage of the iPad based nature of Codea when I am on the go.

 

There is one downside to this setup, and one I don't think I am going to be able to overcome…  you still need to touch the device… there is no mouse support in iOS ( unlike Android ) and Reflector is for display only.  You will find yourself clicking things in Reflector over and over until you get used to it.  If you know a way to control the touch screen on an iPad from a Mac, let me know!

 

You can see a video of the entire thing in process right here:


10. April 2013

Now that I am actually setting off to create a mobile game, it dawned on me I don't have any current iOS devices to develop and test on.  I have an iPad 1, that my daughter has pretty much co-opted, and an iPhone 3g, which is absolutely prehistoric at this point.  I have zero desire to own an iPhone ( wayyyyyyyyy too small for me ) so I decided to pick up this iPad mini last weekend.  I figured it was a good base-line target device, as it shares the same basic components as the iPad 2.  Besides, I was going to be buying one for ShadowRun eventually anyways!

 

Codea

Of course, with a shiny new toy, I pretty much spent the weekend playing with it.  So i've been installing the various games and applications that aren't available in Android land.  

 

One such application I eventually installed was Codea.

 

If you've never heard of it, Codea is a Lua based game development system that is run on the iPad.  That's right, it's a full IDE, code editor and game library that you run on your iPad to make games for your iPad.  As you may know I am a pretty big fan of Lua game engines and amazingly enough, Codea is pretty good.  After I installed it, the next couple hours just disappeared.

 

Codea comes with a pretty extensive number of demos and a great deal of art assets for you to get started with.  You also have the ability to publish to the app store.  The documentation is pretty good, although locating it from their website isn't immediately obvious.  You can take a look at the reference here, although it uses Sencha touch, so it will only run on webkit browsers ( Safari & Chrome ).  Again there are a number of demo applications with complete source code included as well.  Pretty much everything you need is actually included.  Perhaps coolest of all, there is even a book available, although only a chapter is dedicated to Codea.

 

So, what you may ask, is it like to program on an iPad?  Pretty freaking terrible actually.  I've never been a huge fan of the iOS keyboard, now imagine writing code with it.  Codea do have a toolbar that make accessing special character and navigating between text ( think Home and End ) easier, and it does help.  They've also made a number of things very touch friendly, like colour selection bringing up a colour select dialog or touch and drag to change a numeric value.  There are also drag and drop snippets that make the process quicker.  At the end of the day though, you still have to type a fair bit and with the onscreen keyboard it's kinda frustrating.  Codea does about everything it can to help you, but in the end, they are at the mercy of the device they run on.  You really want a bluetooth keyboard if you are going to do serious work, if only just to reclaim screen space.

 

I am actually rather hooked.  I can't see myself using Codea for a full release project, but as something to play or prototype with when out and about away from my PC it's great fun.  I think it would also be a good app for someone just learning the basics of programming.  This app is easily worth the 10$ cost.  As I am going to be playing with it a bit more, I might as well do a review… expect one shortly.


22. March 2013

The past several days I've been looking at the Loom Game Engine, which as of writing is still available for free, but for a limited time only.  Loom is an ActionScript based game development system with a bit of C# mashed in, built over top of the Cocos2D library, driven by a handy command line interface that supports live reloading of code as well as easy deployment to iOS and Android devices.

 

The series was a combination of tutorial, diary and review, documenting my experiences working with Loom.  The parts are:

 

Getting started

Running on Android

Hello World! and a bit more

Graphics

Input and Sound

 

 

The Results

Keep in mind, this is only my experiences after spending about 40 or so hours with the SDK.  I have pretty much zero prior ActionScript experiences and not a ton of experience with Cocos2D coming in.  This isn't strictly a review, there will be no score at the end, instead its my first impressions and nothing more.  Hopefully my time evaluating will make your own evaluation quicker.

 

So…  shall we jump in with the good, or the bad first?  Well, let's hit the good first.

 

The Good

 

Quick to download, install, configure and run.  Server side processing and CLI make it easy to get things up and running.  No need to set up a complicated toolchain, including Android and iOS dev environments.  Learn a few commands and you've got a project up and running on your device of choice.

Cocos2D.  If you know it and like it, you will like Loom.  In many ways you can think of Loom as Cocos2D++, powered by a slightly improved ActionScript.

Support.  It's stellar, seriously AAA stellar.  Most of the times I ran into a problem, the forums had my solution, which is pretty impressive for a new game engine.  The developers are very active on their forums and are willing to go a step beyond, it's very impressive.  My one support inquiry was answered, not just by someone from TheEngine.co, but also from someone in the community.

It's free right now.  That's always nice.  However, 7 days from today, it no longer will be.

LoomScript.  It's ActionScript.  Plus delegates from C#, plus the by value Struct type, plus type inference, plus reflection, plus being strongly typed.  In my experiences with the language, I enjoyed it, with a but*.

Development is rapid.  They release sprints, rapid iterations with well defined purposes.  Coupled with a very clear bug tracking/priority system.  This is good, I wish other projects *cough*Moai*cough* would adopt this attitude!

Documentation and samples.  There is a good amount of documentation, but far too much of its stubs, and a good 15 or more examples.  These are the key to learning, much more so than the documentation.

Source code is available.  If you are the C++ type, it's all there.  I only looked briefly, but it is clean enough.  I would hesitate to commit a serious project to a library I didn't have the source code for.  It's not a deal breaker by any means, but it buys a whole lot of peace of mind having source access.

 

The Bad

 

Cocos2D.  Every single time I ran into confusion or frustration, at the end of the day, Cocos2D was to blame.  The library is large, some might say bloated, and not entirely intuitive.  It often does things in a manner you wouldnt expect, and provides three ways to do things, even if one way is better. At times it's over-engineered and other times, it just sloppy.  Naming conventions can be pretty inconsistent, parts have been deprecated.  Then again, this is a Python library, ported to ObjectiveC, then C++ and now wrapped again so expect a certain number of warts.  Simply put though, if you hate Cocos2D, you will hate Loom.  If you've never used Cocos2D, expect a bit of a learning curve.

Documentation isn't as extensive as I would like.  LoomScript specifics are under documented, you need to glean what you can from the forums and examples, because the documentation isn't that extensive.  At the same time, when trying to puzzle out parameters for delegates (which Loomscript add over ActionScript), I had to drop down to the C++ source code level to figure things out.

Requires an internet connection.  You need to log in to build your app.  In this day and age, this generally isn't a huge problem, and you've got full source code if this really bothers you, but it can be an annoyance.  While evaluating I found my password was inexplicably reset and there was a DNS error one day that prevented the tools from working, so obviously there are downsides to requiring a server connection.  On the other side of this code, the simplicity of building for Android and iOS is enabled by the server based nature of Loom.

LoomScript extensions are nice, but confusing.  This is an area that really needs more documentation and focus in the examples.  The LoomScript changes can on occasion make existing Cocos2d-x wrong, these are the kinds of things they need to point out.

 

The Things I Would Change

 

There are two things I found… annoying I suppose is the word, while working with Loom.  Both things that can be easily fixed, and both wholly related to each other.

The first thing… in order to access the forums, you need to register.  Second, in order to access the documentation ( which is pretty good, but flawed as you can see above ), you need to run it locally, even though it's HTML based.

Why do these two things suck?  You handicap Google.  My workflow generally starts with going to Google, and I can't with Loom.  As a result of hiding your forums behind a password and your documentation being locally installed, I completely lose the ability to use Google.  Yes, the local help has search functionality, but it doesn't even approach what I can do with Google queries.

 

The Conclusion

 

This is pretty simply summarized…  If you don't like Cocos2D, you won't like Loom, it's that simple.

On the other hand, I am highly considering using Loom for my own upcoming game project, even though I have zero ActionScript background.  So, the fact I am willing to use it for my own project is probably as good of an endorsement as I can give.

 

Loom is certainly an interesting project, be sure to sign up before the price tag rises!


21. March 2013

In the prior section we looked at getting graphics on screen.  In this section we will look at how to control your game and play sound.

 

Let's jump right in with a touch example.

package

{

    import cocos2d.Cocos2DGame;

    import cocos2d.CCSprite;

    import cocos2d.Cocos2D;

 

    public class HelloWorld extends Cocos2DGame

    {

        public var sprites:Vector.<CCSprite>;

        public var cancelTouch:Boolean;

        override public function run():void

        {

            cancelTouch=false;

            sprites = new Vector.<CCSprite>();

            super.run();

            layer.onTouchBegan += onTouchBegan;

            layer.onTouchEnded += onTouchEnd;

        }

 

        public function onTouchBegan(id:int,x:Number,y:Number):void{

 

            for each(var s in sprites){

                if(s.hitTest_loomscript(x,y)){

                    System.Console.print("Hit");

                    layer.removeChild(s);

                    sprites.remove(s);

                    cancelTouch = true;

                }

            }

        }

 

        public function onTouchEnd(id:int, x:Number, y:Number):void

        {

            if(cancelTouch)

            {

 

                cancelTouch=false;

                return;

            }

 

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

            

            sprite.x = x;

            sprite.y = y;

            sprite.scale = 0.5;

            layer.addChild(sprite);

            sprites.push(sprite);

        }

 

    }

}

 

When we run the application, as we touch the screen, one of the following occurs.  If the space is empty, a sprite is added.  If the location touched contains a sprite already, that sprite is removed.

 

Selection

 

Let's take a quick look at what we did here.  We start off creating a Vector of CCSprites to hold our various sprite images.  The key part was in the Run() method was wiring up delegates for onTouchBegan and onTouchEnded, these methods will be called predictably enough when the screen is touched and when the screen is released.  When a touch occurs, we loop through the sprites in our vector and see if there is a sprite at that location already.  If there is we set cancelTouch to true to make sure the touch isn't handled again on onTouchEnded.  We then remove the sprite from the layer, and the vector. In onTouchEnd, we simply create a sprite at that location, add it to the scene and our vector.

 

As you can see, handling touch is pretty simple.  Using a combination of onTouchBegan, Ended, Moved and Cancelled and tracking the id and location of the touches ( passed as parameters to the delegate ) you can handle dragging, dropping, pinch, zooming etc.  The Iso demo is the key place to look at for ideas how to implement advanced touch functionality.  One thing I did find annoying though was finding the parameters for the various delegate calls, no idea where to figure them out.  I figured out the onTouchBegan/Ended parameters by finding them in samples.  Another option is to dig into the C++ source code, which you can download as a separate archive.  Fortunately the class names on the C++ side of things mirror the Loom/Cocos2d side of things.  In this case, look up the CCLayer source code, located at /loom/engine/cocos2dx/layers_scenes_transitions_nodes/CCLayer.cpp.  If you dig into the source code, you can puzzle out the parameters:

bool CCLayer::ccTouchBegan(CCTouch *pTouch, CCEvent *pEvent)

{

    if(_TouchBeganDelegate.getVM())

    {

        CCPoint localPoint = convertToNodeSpace(pTouch->getLocation());

 

        _TouchBeganDelegate.pushArgument(pTouch->getID());

        _TouchBeganDelegate.pushArgument(localPoint.x);

        _TouchBeganDelegate.pushArgument(localPoint.y);

        _TouchBeganDelegate.invoke();

        return true;

    }

}

 

I do wish there was an easier way to figure this stuff out, and it's quite possible there is, but I didn't find it.  It's nice to know you can drop to the source code if needed though.

 

Alright, so thats touch, let's take a look at using the accelerometer.  Let's jump right in with code:

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);

 

            layer.onAccelerate += function(x:Number, y:Number, z:Number) {

                if(sprite.x > 0 && sprite.y > 0 &&

                    sprite.x < Cocos2D.getDisplayWidth() && sprite.y < Cocos2D.getDisplayHeight())

                {

                    System.Console.print(x);

                    sprite.x += x * 5;

                    sprite.y += y * 5;

                }

                else

                {

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

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

                }

            }

        }

    }

}

 

 

 As you can see it's remarkably straight forward.  We draw a sprite centred to the screen, recycling the code we used a little while back.  The biggest difference is the onAccelerate delegate we assign to layer.  As you can see, this takes three values x,y and z.  These represent the amount of movement along each axis.  If you tilt your phone slightly up or down, Y will have a value like 0.01 or -0.0122332, depending on which direction.  The magnitude of the number ( between 0 and 1 I believe ) represents the speed of the motion.  So if you vigorously shake your phone, the numbers will be much higher then just tilting it.  If you run this code on your phone, the sprite will travel in whatever direction you tilt your phone until it gets to the screen edge, when it will go back to the centre.

 

So, thats touch and motion, now let's take a quick look at audio.

 

package

{

    import cocos2d.Cocos2DGame;

    import CocosDenshion.SimpleAudioEngine;

    import cocos2d.Cocos2D;

 

    public class HelloWorld extends Cocos2DGame

    {

        override public function run():void

        {

            super.run();

            SimpleAudioEngine.sharedEngine().preloadEffect("assets/gunshot.mp3");

 

            SimpleAudioEngine.sharedEngine().playBackgroundMusic("assets/song.mp3");

 

            layer.onTouchEnded += function (){

                SimpleAudioEngine.sharedEngine().playEffect("assets/gunshot.mp3");

            };

 

            layer.onKeyBackClicked += function (){

                if(SimpleAudioEngine.sharedEngine().isBackgroundMusicPlaying())

                    SimpleAudioEngine.sharedEngine().pauseBackgroundMusic();

                else

                    SimpleAudioEngine.sharedEngine().resumeBackgroundMusic(); 

            };

        }

    }

}

 

When you run this, it will automatically start playing the background music song.mp3.  If you tap the screen, it will play the sound effect gunshot.mp3 as many times as you press the screen.  Finally we wire up a delegate to handle pressing the back button on your device ( no clue what this does on iOS ), that either pauses background music playback, or resumes it.  It's the Cocos2d Denshion library that handles audio.  It handles formats other than mp3, but each time I tried to use a WAV file, it didn't work.  I seem to recall Denshion being kinda picky about file formats, so I'm not shocked.

 

As you can see, input and audio are both fairly simple with Loom.

 

That concludes our look at the Loom Engine.  Of course, we only scratched the surface of what it can do, but I hope you got a good idea of what working with Loom is like.  

 

Jump forward to the conclusion.


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.


AppGameKit Studio

See More Tutorials on DevGa.me!

Month List