A first look at Google’s new IDE Android Studio

15. May 2013

 

So, it is now available for download, although the version is 0.1, so expect some warts!  Oh, the “it” in question is Google’s new IDE for Android development based on IntelliJ by Jetbrains, a developer I am a huge fan of.

 

Now I am going to take a tour of the IDE.

 

Welcome screen:

image

 

New Project Screen

image

 

New Project Part 2

image

 

New Project Part 3

image

 

New Project Part 4

image

 

Code Editing Window / Code tips

image

 

 

Error Dialog

image

 

Debug device chooser

image

 

 

Debug Window

image

 

 

GUI Editing

image

 

Screen size options:

image

 

 

Theme selector

image

 

 

Multiple Device preview

image

 

I experienced no crashes, everything was very intuitive and quick, other than initial loading.  I’m initially quite impressed.  IF you are wondering, this IDE *ONLY* works for Android projects.

News ,




Google announce Android Studio… RIP Eclipse

15. May 2013

Today during the Google IO event there was an announcement that both shocked and pleased me.  They are releasing a new IDE for Android development.  Best of all, it's based on IntelliJ, easily my favourite Java IDE.

 

AndroidStudio

(Photo's are from Verge )

 

One of the coolest new features is the addition of a tool allowing you to see your code running on a multitude of different devices at the same time:

Verge super wide

 

I can say easily one of the things I hate most about Android development is Eclipse, which is pretty much the defacto tool for Android. You could always work in IntelliJ or Netbeans, but it was never quite as seamless and always seem to have a gap or two in functionality.  Any news that might potentially keep me away from the hateful IDE that is Eclipse is great news to me!

 

You can read more about the announcement over at The Verge.  As of yet, no downloads are available on Googles websites.

 

 

Edit: Download link now available.  Also, so hands on screenshots available here.

News , ,




A closer look at the Loom Game Engine: The Conclusion

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!

, ,




A closer look at the Loom Game Engine, Part Five: Input and Sound

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.

, ,




A closer look at the Loom Game Engine, Part Four: Graphics

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.

, ,