Subscribe to GameFromScratch on YouTube Support GameFromScratch on Patreon


Home > News >

10. June 2013

 

The Apple World Wide Developer conference is currently going on and generally there isn’t all that much of interest to game developers.  This year is a bit of an exception as they added SpriteKit to OSX Maverick (10.9) as well as an upcoming release of iOS.  SpriteKit seems to be a combination of sprite library and physics engine.  In their own words:

Sprite Kit provides a graphics rendering and animation infrastructure that you can use to animate arbitrary textured images—sprites. Sprite Kit uses a traditional rendering loop that allows processing on the contents of each frame before it is rendered. Your game determines the contents of the scene and how those contents change in each frame. Sprite Kit does the work to render frames of animation efficiently using the graphics hardware. Sprite Kit is optimized to allow essentially arbitrary changes to each frame of animation.

Sprite Kit also provides other functionality that is useful for games, including basic sound playback support and physics simulation. In addition, Xcode provides built-in support for Sprite Kit, allowing complex special effects and texture atlases to be easily created and then used in your app. This combination of framework and tools makes Sprite Kit a good choice for games and other apps that require similar kinds of animations. For other kinds of user-interface animation, use Core Animation instead.

Followed by:

Sprite Kit is available on iOS and OS X. It uses the graphics hardware available on the hosting device to efficiently composite 2D images together at high frame rates. Sprite Kit supports many different kinds of content, including:

  • Untextured or untextured rectangles (sprites)

  • Text

  • Arbitrary CGPath-based shapes

  • Video

Sprite Kit also provides support for cropping and other special effects, allowing these effects to be applied to all or a portion of the content. All of these elements can be animated or changed in each frame. You can also attach physics bodies to these elements so that they properly support forces and collisions.

By supporting a rich rendering infrastructure and handling all of the low-level work to submit drawing commands to OpenGL, Sprite Kit allows you to focus your efforts on solving higher-level design problems and creating great gameplay.

So basically it’s a 2D game engine competing with the likes of Cocos2D.  Of course, if you use SpriteKit you will be tied to iOS/OS/X and the newest release at that.  If you are an Apple only shop, this isn’t a big deal, but if you work cross platform or are targeting older hardware, this new library is pretty much useless for now.

 

If you have an Apple ID, you can log in and read the documentation here.

News , , ,

blog comments powered by Disqus

Month List

Popular Comments

March 2012
Subscribe to GameFromScratch on YouTube Support GameFromScratch on Patreon

30. March 2012

 

 

Unity is certainly getting more and more popular, and with the (limited time) release of Unityunity3d1 iOS and Android for free, the number of people interested in Unity is sure to rise.  Along with the increase in popularity of Unity, there has been an influx of Unity books.

 

 

Therefore I put together this post to compile all of the books and their primary details into a single page.  This makes picking out which book to buy/read as easy as possible.

 

 

Hope you find it useful.  I am trying to keep this post as comprehensive as possible, so if I missed a book or made a mistake, please let me know!

 

 

 

The Unity Book Round-up

General ,

29. March 2012

 

If you frequent developer related forums, this question probably caused your eyes to roll and the bile to rise in your throat.  People with absolutely no development experience get the game creation bug and of all things want to start with MMOs.  Amazingly enough, there is now a very simple answer…  start here.

 

 

 

 

See, the folks over at Mozilla decided to create an HTML5 MMO to showcase the use of Web Sockets a technology for easy two way communication between a webpage and server ( that isn’t without it’s controversy ).  Additionally it makes use of HTML features including Canvas, local storage, web workers and audio.  Node is used on the server side.  Here is the game in action on my desktop:

 

 

 

image

 

It is graphically simple, but when I played there were 73 other players online and it played fairly flawlessly.  I also fired it up on my Android Phone ( Samsung Galaxy Note ) and here are the results:

 

SC20120329-103613

 

Encouraging….

 

export_03

 

 

And… failure.  It never leaves the connecting to server screen.  Perhaps it’s just me, but for now it simply doesn’t work on my phone.  Will try later on my ICS tablet and iPhone, it may just be launch day jitters so I will try again later.

 

 

 

Failures aside, why am I talking about a primitive browser based MMO on this site?  Well, that’s because Mozilla made the complete source code available on GitHub!

 

 

Here for example is the code from character.js for defining the players character.  As you can see, once you get over the Javascriptisms, it’s quite clean and easy to follow:

 

define(['entity', 'transition', 'timer'], function(Entity, Transition, Timer) { var Character = Entity.extend({ init: function(id, kind) { var self = this; this._super(id, kind); // Position and orientation this.nextGridX = -1; this.nextGridY = -1; this.orientation = Types.Orientations.DOWN; // Speeds this.atkSpeed = 50; this.moveSpeed = 120; this.walkSpeed = 100; this.idleSpeed = 450; this.setAttackRate(800); // Pathing this.movement = new Transition(); this.path = null; this.newDestination = null; this.adjacentTiles = {}; // Combat this.target = null; this.unconfirmedTarget = null; this.attackers = {}; // Health this.hitPoints = 0; this.maxHitPoints = 0; // Modes this.isDead = false; this.attackingMode = false; this.followingMode = false; }, clean: function() { this.forEachAttacker(function(attacker) { attacker.disengage(); attacker.idle(); }); }, setMaxHitPoints: function(hp) { this.maxHitPoints = hp; this.hitPoints = hp; }, setDefaultAnimation: function() { this.idle(); }, hasWeapon: function() { return false; }, hasShadow: function() { return true; }, animate: function(animation, speed, count, onEndCount) { var oriented = ['atk', 'walk', 'idle']; o = this.orientation; if(!(this.currentAnimation && this.currentAnimation.name === "death")) { // don't change animation if the character is dying this.flipSpriteX = false; this.flipSpriteY = false; if(_.indexOf(oriented, animation) >= 0) { animation += "_" + (o === Types.Orientations.LEFT ? "right" : Types.getOrientationAsString(o)); this.flipSpriteX = (this.orientation === Types.Orientations.LEFT) ? true : false; } this.setAnimation(animation, speed, count, onEndCount); } }, turnTo: function(orientation) { this.orientation = orientation; this.idle(); }, setOrientation: function(orientation) { if(orientation) { this.orientation = orientation; } }, idle: function(orientation) { this.setOrientation(orientation); this.animate("idle", this.idleSpeed); }, hit: function(orientation) { this.setOrientation(orientation); this.animate("atk", this.atkSpeed, 1); }, walk: function(orientation) { this.setOrientation(orientation); this.animate("walk", this.walkSpeed); }, moveTo_: function(x, y, callback) { this.destination = { gridX: x, gridY: y }; this.adjacentTiles = {}; if(this.isMoving()) { this.continueTo(x, y); } else { var path = this.requestPathfindingTo(x, y); this.followPath(path); } }, requestPathfindingTo: function(x, y) { if(this.request_path_callback) { return this.request_path_callback(x, y); } else { log.error(this.id + " couldn't request pathfinding to "+x+", "+y); return []; } }, onRequestPath: function(callback) { this.request_path_callback = callback; }, onStartPathing: function(callback) { this.start_pathing_callback = callback; }, onStopPathing: function(callback) { this.stop_pathing_callback = callback; }, followPath: function(path) { if(path.length > 1) { // Length of 1 means the player has clicked on himself this.path = path; this.step = 0; if(this.followingMode) { // following a character path.pop(); } if(this.start_pathing_callback) { this.start_pathing_callback(path); } this.nextStep(); } }, continueTo: function(x, y) { this.newDestination = { x: x, y: y }; }, updateMovement: function() { var p = this.path, i = this.step; if(p[i][0] < p[i-1][0]) { this.walk(Types.Orientations.LEFT); } if(p[i][0] > p[i-1][0]) { this.walk(Types.Orientations.RIGHT); } if(p[i][1] < p[i-1][1]) { this.walk(Types.Orientations.UP); } if(p[i][1] > p[i-1][1]) { this.walk(Types.Orientations.DOWN); } }, updatePositionOnGrid: function() { this.setGridPosition(this.path[this.step][0], this.path[this.step][1]); }, nextStep: function() { var stop = false, x, y, path; if(this.isMoving()) { if(this.before_step_callback) { this.before_step_callback(); } this.updatePositionOnGrid(); this.checkAggro(); if(this.interrupted) { // if Character.stop() has been called stop = true; this.interrupted = false; } else { if(this.hasNextStep()) { this.nextGridX = this.path[this.step+1][0]; this.nextGridY = this.path[this.step+1][1]; } if(this.step_callback) { this.step_callback(); } if(this.hasChangedItsPath()) { x = this.newDestination.x; y = this.newDestination.y; path = this.requestPathfindingTo(x, y); this.newDestination = null; if(path.length < 2) { stop = true; } else { this.followPath(path); } } else if(this.hasNextStep()) { this.step += 1; this.updateMovement(); } else { stop = true; } } if(stop) { // Path is complete or has been interrupted this.path = null; this.idle(); if(this.stop_pathing_callback) { this.stop_pathing_callback(this.gridX, this.gridY); } } } }, onBeforeStep: function(callback) { this.before_step_callback = callback; }, onStep: function(callback) { this.step_callback = callback; }, isMoving: function() { return !(this.path === null); }, hasNextStep: function() { return (this.path.length - 1 > this.step); }, hasChangedItsPath: function() { return !(this.newDestination === null); }, isNear: function(character, distance) { var dx, dy, near = false; dx = Math.abs(this.gridX - character.gridX); dy = Math.abs(this.gridY - character.gridY); if(dx <= distance && dy <= distance) { near = true; } return near; }, onAggro: function(callback) { this.aggro_callback = callback; }, onCheckAggro: function(callback) { this.checkaggro_callback = callback; }, checkAggro: function() { if(this.checkaggro_callback) { this.checkaggro_callback(); } }, aggro: function(character) { if(this.aggro_callback) { this.aggro_callback(character); } }, onDeath: function(callback) { this.death_callback = callback; }, /** * Changes the character's orientation so that it is facing its target. */ lookAtTarget: function() { if(this.target) { this.turnTo(this.getOrientationTo(this.target)); } }, /** * */ go: function(x, y) { if(this.isAttacking()) { this.disengage(); } else if(this.followingMode) { this.followingMode = false; this.target = null; } this.moveTo_(x, y); }, /** * Makes the character follow another one. */ follow: function(entity) { if(entity) { this.followingMode = true; this.moveTo_(entity.gridX, entity.gridY); } }, /** * Stops a moving character. */ stop: function() { if(this.isMoving()) { this.interrupted = true; } }, /** * Makes the character attack another character. Same as Character.follow but with an auto-attacking behavior. * @see Character.follow */ engage: function(character) { this.attackingMode = true; this.setTarget(character); this.follow(character); }, disengage: function() { this.attackingMode = false; this.followingMode = false; this.removeTarget(); }, /** * Returns true if the character is currently attacking. */ isAttacking: function() { return this.attackingMode; }, /** * Gets the right orientation to face a target character from the current position. * Note: * In order to work properly, this method should be used in the following * situation : * S * S T S * S * (where S is self, T is target character) * * @param {Character} character The character to face. * @returns {String} The orientation. */ getOrientationTo: function(character) { if(this.gridX < character.gridX) { return Types.Orientations.RIGHT; } else if(this.gridX > character.gridX) { return Types.Orientations.LEFT; } else if(this.gridY > character.gridY) { return Types.Orientations.UP; } else { return Types.Orientations.DOWN; } }, /** * Returns true if this character is currently attacked by a given character. * @param {Character} character The attacking character. * @returns {Boolean} Whether this is an attacker of this character. */ isAttackedBy: function(character) { return (character.id in this.attackers); }, /** * Registers a character as a current attacker of this one. * @param {Character} character The attacking character. */ addAttacker: function(character) { if(!this.isAttackedBy(character)) { this.attackers[character.id] = character; } else { log.error(this.id + " is already attacked by " + character.id); } }, /** * Unregisters a character as a current attacker of this one. * @param {Character} character The attacking character. */ removeAttacker: function(character) { if(this.isAttackedBy(character)) { delete this.attackers[character.id]; } else { log.error(this.id + " is not attacked by " + character.id); } }, /** * Loops through all the characters currently attacking this one. * @param {Function} callback Function which must accept one character argument. */ forEachAttacker: function(callback) { _.each(this.attackers, function(attacker) { callback(attacker); }); }, /** * Sets this character's attack target. It can only have one target at any time. * @param {Character} character The target character. */ setTarget: function(character) { if(this.target !== character) { // If it's not already set as the target if(this.hasTarget()) { this.removeTarget(); // Cleanly remove the previous one } this.unconfirmedTarget = null; this.target = character; } else { log.debug(character.id + " is already the target of " + this.id); } }, /** * Removes the current attack target. */ removeTarget: function() { var self = this; if(this.target) { if(this.target instanceof Character) { this.target.removeAttacker(this); } this.target = null; } }, /** * Returns true if this character has a current attack target. * @returns {Boolean} Whether this character has a target. */ hasTarget: function() { return !(this.target === null); }, /** * Marks this character as waiting to attack a target. * By sending an "attack" message, the server will later confirm (or not) * that this character is allowed to acquire this target. * * @param {Character} character The target character */ waitToAttack: function(character) { this.unconfirmedTarget = character; }, /** * Returns true if this character is currently waiting to attack the target character. * @param {Character} character The target character. * @returns {Boolean} Whether this character is waiting to attack. */ isWaitingToAttack: function(character) { return (this.unconfirmedTarget === character); }, /** * */ canAttack: function(time) { if(this.canReachTarget() && this.attackCooldown.isOver(time)) { return true; } return false; }, canReachTarget: function() { if(this.hasTarget() && this.isAdjacentNonDiagonal(this.target)) { return true; } return false; }, /** * */ die: function() { this.removeTarget(); this.isDead = true; if(this.death_callback) { this.death_callback(); } }, onHasMoved: function(callback) { this.hasmoved_callback = callback; }, hasMoved: function() { this.setDirty(); if(this.hasmoved_callback) { this.hasmoved_callback(this); } }, hurt: function() { var self = this; this.stopHurting(); this.sprite = this.hurtSprite; this.hurting = setTimeout(this.stopHurting.bind(this), 75); }, stopHurting: function() { this.sprite = this.normalSprite; clearTimeout(this.hurting); }, setAttackRate: function(rate) { this.attackCooldown = new Timer(rate); } }); return Character; });

 

 

 

So now, the next time somebody asks you “I want to create an MMO, now what?”, you have an easy answer.  Send them over to Browser Quest.

 

 

Oh, and for the record… starting your game development career off with an MMO is still a right stupid idea! Smile

 

 

EDIT: As per a comment on reddit, this code doesn’t appear to be released under a specific license yet.  Keep that in mind before using any of this code in your own project.  Of course, this should be rectified shortly.

News ,

23. March 2012

 

 

Have you ever read a technical book and thought to yourself “Man, the author of this book must be a gigantic jerk!”?  I can honestly say, I never have until now!

 

 

This review of sorts covers two different Javascript books I’ve read recently; two very different books with two very different goals.  As I have been working with Node and more recently Appcelerator, I decided I needed to polish up my Javascript skills, as things are much different these days than the DOM manipulation I traditionally used Javascript for.  I started out by searching for “Javascript closure” on Safari Books Online and it brought me to Javascript: The Good Parts, it was short and I was suffering insomnia so I read it that evening.  The book left me with so many questions that I ended up reading/contrasting it against Javascript: The definitive guide.  Aside from both books being about Javascript and both having colons in their titles, these two books couldn’t be further apart!

 

 

 

Let’s start with the Javascript: The Good Parts review.

 

 

First off, it’s worth mentioning the author, Douglas Crockford.  If you’ve never heard of him, he is the guy originally responsible for drafting the JSON standard and Yahoo’s head JavascriptJavascriptTheGoodParts guy, responsible for projects like the yUI library.  Simply put, this man knows his stuff when it comes to the topic.  Sadly, he knows it too and doesn’t let you forget it.  Many times in the book he pushes his opinion as fact, and often on very odd things ( like never use ++ operators ).  He often makes sweeping statements that really don’t work in a black and white world.  That said, if you can get over the personality ( or you aren’t sensitive to such things ), this is a wonderful little book.

 

 

I do mean little too, as this book weighs in at a mere 176 pages.  Amazingly enough there is a ton packed in to those 176 pages and even more amazingly, a great deal of it could be pruned and would make this a superior book ( such as the regular expressions chapter ).  A good example of what could be pruned out completely are the absolutely bizarre charts this book is littered with.  Here is one for example:

 

 

whitespace

 

 

That chart was meant to explain Javascripts whitespace rules… did it help you, even slightly?  You could have more concisely and effectively conveyed all of that information in a sentence or two.  I found that over and over, the author being overly clever or complicated leaves the reader baffled on what should be a pretty simple concept.  He does the exact same thing with code examples too, consider this code sample regarding inheritance:

 

var Cat = function (name) { this.name = name; this.saying = 'meow'; }; // Replace Cat.prototype with a new instance of Mammal Cat.prototype = new Mammal( ); // Augment the new prototype with // purr and get_name methods. Cat.prototype.purr = function (n) { var i, s = ''; for (i = 0; i < n; i += 1) { if (s) { s += '-'; } s += 'r'; } return s; }; Cat.prototype.get_name = function ( ) { return this.says( ) + ' ' + this.name + ' ' + this.says( ); }; var myCat = new Cat('Henrietta'); var says = myCat.says( ); // 'meow' var purr = myCat.purr(5); // 'r-r-r-r-r' var name = myCat.get_name( ); // 'meow Henrietta meow'

 

 

Notice how half of it is taken up by a purr() method which is overly convoluted and has nothing to do with the lesson at hand.  It simply causes the reader to have to dedicate a few more cycles to deciphering an example ( which is completely irrelevant to the topic at hand ), while allowing the author to feel just a little bit more clever. 

 

These kinds of things happen over and over and it makes reading the book more difficult than it should be, for no good reason.  The other major problem with trying to decipher the code samples in this book are the errors, my god the errors!  See every technical book is going to have a certain number of errors, but for a 176 page book, this one has far more then it’s share.  Just take a look at the errata.  Nothing makes learning a new concept more difficult than following code that doesn’t work!  When you are new to a subject, you assume the code you are working from is correct and it’s your newbishness that is the source of the problem.  That often simply isn’t true with this book, when you read it, if you encounter problems be sure to check the errata before you bash your head off the wall with frustration.

 

 

Next up is determining who this book’s audience is, which is a problem the author obviously struggled with.  Consider the following two paragraphs taken from the preface:

 

This is a book about the JavaScript programming language. It is intended for            programmers who, by happenstance or curiosity, are venturing into JavaScript for the   first time. It is also intended for programmers who have been working with JavaScript at a novice level and are now ready for a more sophisticated relationship with the language. JavaScript is a surprisingly powerful language. Its unconventionality presents some challenges, but being a small language, it is easily mastered.

 

Followed a paragraph later by:

 

This is not a book for beginners. Someday I hope to write a JavaScript: The First Parts book, but this is not that book. This is not a book about Ajax or web programming. The focus is exclusively on JavaScript, which is just one of the languages the web developer must master.

 

Let me put this in the simplest terms possible This is not a book for beginners!  If you are “venturing into Javascript for the first time”, well frankly you are absolutely screwed if this is the book you chose!

 

 

So I’ve dumped on this book pretty good, it’s short, the author comes across arrogant and I seem to hate at least half of it, so why the hell am I bothering to mention it to you?  That’s because the remaining half of this book is downright excellent.  It basically is the Javascript equivalent of Effective C++, which is one of the best technical books ever written.

 

 

Javascript as a language is an absolute minefield waiting to explode killing ( or at least mentally scaring ) the developer.  It lacks the data hiding facilities that basically every other language in existence has.  More so, it has extremely dangerous but seemingly benign constructs like new and == that are just waiting there to attack you.  Finally, the scoping rules are almost as byzantine as you’d expect from C++! It is far too easy to make a variable global, or mute out an existing variable leading to undesired behavior ( bugs ).  This book helps you to navigate that minefield, probably better than any other book in existence.

 

 

More to the point, most people simply use Javascript wrong ( now there I go sounding arrogant! Winking smile ).  But simple fact is, years of browser based DOM manipulation code written to mimic traditional OO code has lead to many people forming extremely bad habits, myself included.  This book does a very good job of showing you the intricacies of the language, as well as effective work arounds for perceived faults.  Some of these “faults” I disagree with, but I certainly did learn from the exercises anyways.

 

 

So in the end, do I recommend this book?  That’s a tricky one.  I really don’t like the way it is written, I am not keen on the way he teaches ( the choice of illustrations and code examples ), the excessive errors certainly don’t help.  That said, I learned a ton reading this book, in a very short period of time.  Besides, it’s less than 20 bucks!  So in the end, yes I do recommend you read it, much like Effective C++, it will make you a better Javascript programmer.  But for learning the language or as a first book, certainly not.  Fortunately in the regard, we have another book!

 

 

 

Javascript: The Definitive Guide review.

 

 

If Javascript has a bible ( like K&R C for the C Programming Language ), it’s this book.  The Definitive Guide is a much more traditional book, much longer at 1032 pages and with a much more traditional price tag.  This part of the review is going to be much shorter, as essentiallyJavascriptTheDefinitiveGuide there is a lot less to say.  The authors writing style in much more approachable than Javascript:The Good Parts and the code examples are far easier to digest.

 

 

One up or downside to this book, depending on your needs, is the amount of browser/DOM related content.  While Good parts effectively had no content pertaining to using Javascript in the browser ( an area extremely well documented in books and online ), the same is not true for this book.  Fully half of this book is on “client side” Javascript programming.  Then again, even at 50%, this is still a 1000+ page book, so you still got another 500 pages of non-client side Javascript.  Just remember, if you are using Javascript outside of the browser, if it starts with document. it probably isn’t supported.

 

 

The book is basically broken down into 4 sections.  The first is Core Javascript, which covers the language itself, regardless to how it is used.  This section is where you cover concepts like reserved words, objects, arrays etc.  The second is Client Side Javascript, which basically covers using Javascript in the browser, covering topics such as the DOM, jQuery, HTML5, etc.  The final two sections are reference sections for both the core and client side libraries.  These sections are strictly for reference.  Truth is though, with the sad state of the internet on this subject, a handy book reference is quite a useful thing.

 

 

For learning the language and your goto reference book, it’s really hard to beat Javascript: The Definitive Guide.  Taken in tandem, these two books are all you would need to succeed at Javascript development.  The Definitive Guide to get you started, and as a reference as you go along.  Then read Best Parts, to make you a better developer… if you are willing to put up with some annoying attitude that is!

Programming ,

22. March 2012

 

 

Adobe has recently made Photoshop CS 6 available as beta, which will last until CS6 is PSCS6released.  In order to activate, you need to have an Adobe ID ( freely available ) within 7 days of installing.  The Mac installer is now 64bit only and weighs in at just under 1GB, while the Windows install is closer to 1.7GB.

 

 

 

The biggest new features in Abobe’s own words are:

 

  • Content-Aware Patch — Patch images with greater control using the newest member of the Content-Aware family of technologies. Choose the sample area you want to use to create your patch, and then watch Content-Aware Patch magically blend pixels for a stunning result.
  • Blazingly fast performance and a modern UI — Experience unprecedented performance with the Mercury Graphics Engine, which gives you near-instant results when you edit with key tools such as Liquify, Puppet Warp, and Crop.* Plus, a refined, fresh, and elegant Photoshop interface features dark background options that make your images pop.
  • New and re-engineered design tools — Create superior designs fast. Get consistent formatting with type styles, create and apply custom strokes and dashed lines to shapes, quickly search layers, and much more.

 

 

The content aware tools are easily the biggest new feature, and look pretty impressive as demonstrated in this video:



Another good video showing off the new features is Russel Brown's 6 favorite new features:

 

 



Lynda.com have also made a number of tutorials freely available for CS6.


So, if you are interested in Photoshop CS6, or just want a free copy for a limited time, head on over to labs.adobe.com and give it a download.

News, Art

21. March 2012

 

 

As my journey with Appcelerator continues, I’ve run into another annoyance, and the fix wasn’t immediately obvious.  Titanium Studio ships with an Android 2.2 image pre-configured, although I am trying to develop for Ice Cream Sandwich ( Android 4 ).  The problem is, every time I launch my application, it would ignore the running emulator ( launched using AVD Manager ) and launch it’s own. This is really irritating, as the Android emulator takes forever to load.  ( About a minute for 2.2, and well over 5-10 minutes for ICS, on an i7 machine with 12GB of RAM! ) to say nothing of the fact their emulator image is for a phone, not a tablet.

 

 

It seemed no matter what I did, it would still load a new instance of the emulator, regardless to if I had one running already.  The answer isn’t as intuitive as you would think.  My first thought was it would be under Debug Configurations, which can be accessed by right clicking tiapp.xml in your project, choosing Debug As –> Debug Configurations…  which brings up the screen below:

 

 

image

 

 

 

Ah, this looks promising, change Android API level to Android 4.0, click Apply then debug.   Still loads the pre-configured 2.2 emulator. Sad smile  Ok, so that wasn’t it.

 

 

In the end, it comes down to how you build your project.  In Project or Package Explorer, double click tiapp.xml to bring the property editor up.  Search for the “Deployment Targets” section, then click the configure link, like this:

 

 

image

 

 

In the dialog that pops up, there is a selection for “Default Android SDK:”.  This is the value you need to change:

 

image

 

 

Now I click debug and behold!  Ice Cream Sandwich goodness!

 

image

 

 

 

Well… that was intuitive.  Not really something you can blame Appcelerator for, nor Titanium Studio ( although again Eclipse/Google Android tools make things far too complicated! ) in the end.  That said, if I could debug on a physical device, I wouldn’t have to deal with the terrible Android emulator in the first place!

 

 

Anyways, finally after a few days of messing about with configuration and install issues, finally, time for some coding!

General

Month List

Popular Comments