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

 

I am not sure if you have ever tried running a WebGL game on a mobile browser…  it either doesn’t work at all, or performs appallingly bad depending on the browser.  Mobile browsers already present an interesting performance problem for 2D canvas based games that products like Ludei’s CocoonJS attempts to solve.  Essentially it is a stripped down browser optimized for speed, that your HTML5 application runs in.  Today, they have announced they have added WebGL support!  This means your HTML5 WebGL applications can now be deployed to iOS and Android as a fully accelerated application.

 

From their press release (pdf link):

“We’ve already made HTML5 cross-platform 2D game development a reality,” said Ludei CEO
Eneko Knorr. “Now we are unlocking the door for the thousands of Web game developers who
want to publish great 3D games on mobile and reach consumers through the most popular app
stores. Our 3D rendering allows today’s most popular mobile devices to run a 3D HTML5 game
with the same great user experience and performance that native gamers are used to.”


Ludei will support 3D game development via the open WebGL standard. WebGL is the browser
equivalent of OpenGL, the industry standard for deploying powerful 3D animated games. The
addition of 3D rendering on the Ludei platform means for the first time, WebGL runs on every
iOS and Android device, so developers don’t have to worry about which devices currently have
built-in 3D support to handle their complex, HTML5 mobile animated games. Now 3D game
developers, including those that historically publish console and PC games, can use Ludei’s
technology to deliver their 3D titles cross-platform to Google Play, Apple App Store and more.

 

So, if you are an HTML5 game developer and want to bring your WebGL game to iOS and Android with native level performance, be sure to check this out.

News


22. March 2013

 

So, some exciting personal news today, I can finally unveil what I've been working on the last several months, my new book PlayStation Mobile Cookbook!  A special thanks to my reviewers and supporters at Sony and the entire team at Packt, it was a pleasure working with you all on this book.

 

If you have never read one of Packt's "cookbook style" books, its basically composed of a series of recipes illustrating how to perform a particular task

followed by a detailed description of what's happening as well as various tips and tricks.  In this case, its contains over 60 different sample applications illustrating how to do… well, just about everything you want to with the PlayStation Mobile SDK.  If you've run through any of my tutorials, you should have a pretty good idea of what to expect.

 

For a better idea of the contents of the book, here is the Table of Contents:

 

  • Preface

 
  • Chapter 1: Getting Started

    • Introduction
    • Accessing the PlayStation Mobile portal
    • Installing the PlayStation Mobile SDK
    • Creating a simple game loop
    • Loading, displaying, and translating a textured image
    • "Hello World" drawing text on an image
    • Deploying to PlayStation certified Mobile Android devices
    • Deploying to a PlayStation Vita
    • Manipulating an image dynamically
    • Working with the filesystem
    • Handling system events
 
  • Chapter 2: Controlling Your PlayStation Mobile Device

    • Introduction
    • Handling the controller's d-pad and buttons
    • Using the Input2 wrapper class
    • Using the analog joysticks
    • Handling touch events
    • Using the motion sensors
    • Creating onscreen controls for devices without gamepads
    • Configuring an Android application to use onscreen controls
 
  • Chapter 3: Graphics with GameEngine2D

    • Introduction
    • A game loop, GameEngine2D style
    • Creating scenes
    • Adding a sprite to a scene
    • Creating a sprite sheet
    • Using a sprite sheet in code
    • Batching a sprite with SpriteLists
    • Manipulating a texture's pixels
    • Creating a 2D particle system
 
  • Chapter 4: Performing Actions with GameEngine2D

    • Introduction
    • Handling updates with Scheduler
    • Working with the ActionManager object
    • Using predefined actions
    • Transitioning between scenes
    • Simple collision detection
    • Playing background music
    • Playing sound effects
 
  • Chapter 5: Working with Physics2D

    • Introduction
    • Creating a simple simulation with gravity
    • Switching between dynamic and kinematic
    • Creating a (physics!) joint
    • Applying force and picking a physics scene object
    • Querying if a collision occurred
    • Rigid body collision shapes
    • Building and using an external library
 
  • Chapter 6: Working with GUIs

    • Introduction
    • "Hello World" – HighLevel.UI style
    • Using the UI library within a GameEngine2D application
    • Creating and using hierarchies of widgets
    • Creating a UI visually using UIComposer
    • Displaying a MessageBox dialog
    • Handling touch gestures and using UI effects
    • Handling language localization
 
  • Chapter 7: Into the Third Dimension

    • Introduction
    • Creating a simple 3D scene
    • Displaying a textured 3D object
    • Implementing a simple camera system
    • A fragment (pixel) shader in action
    • A vertex shader in action
    • Adding lighting to your scene
    • Using an offscreen frame buffer to take a screenshot
 
  • Chapter 8: Working with the Model Library

    • Introduction
    • Importing a 3D model for use in PlayStation Mobile
    • Loading and displaying a 3D model
    • Using BasicProgram to perform texture and shader effects
    • Controlling lighting using BasicProgram
    • Animating a model
    • Handling multiple animations
    • Using bones to add a sword to our animated model
 
  • Chapter 9: Finishing Touches

    • Introduction
    • Opening and loading a web browser
    • Socket-based client and server networking
    • Accessing (Twitter) data over the network using REST and HttpWebRequest
    • Copying and pasting using Clipboard
    • Embedding and retrieving a resource from the application assembly
    • Configuring your application using PublishingUtility
    • Creating downloadable content (DLC) for your application
 
  • Appendix: Publishing Your Application

    • Introduction
 
  • Index

 

The book is quite literally at the printers right now, I'll post more details once it's available on Amazon, on Safari Books Online or in stores for purchase.  It should be in the next couple of days.  You can of course order the book on the Packt website.

 

Are trying to figure out what to get your grandmother for her birthday?  I have the perfect recommendation! :)

 

Hope you enjoy the book!


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