Subscribe to GameFromScratch on YouTube Support GameFromScratch on Patreon

11. May 2012

 

In the last tutorial Working with Sprite Sheets I said that I would cover updating your scene in an upcoming tutorial. This is that tutorial.

 

In this tutorial we are going to cover three different ways that you can update your scene.  As you saw earlier it is possible to update things directly inside your game loop, either directly or using a timer.  However GameEngine2D has a number of superior scheduling options built in, and we will look at 3 different options.  The first is using a Node’s Schedule method, the second is to derive from Node and override Update() and using the Scheduler singleton.  The last is to declare a ActionBase derived object, to create a re-usable updater.  We are going to create 3 bouncing smiling faces, each controlled by a different system.

 

 

We are going to start with the following basic skeleton:

 

using System; using System.Collections.Generic; using Sce.Pss.Core; using Sce.Pss.Core.Environment; using Sce.Pss.Core.Graphics; using Sce.Pss.Core.Input; using Sce.Pss.Core.Imaging; // for Font using Sce.Pss.HighLevel.GameEngine2D; using Sce.Pss.HighLevel.GameEngine2D.Base; namespace Updating { public class AppMain { public static void Main (string[] args) { Director.Initialize(); Scene scene = new Scene(); scene.Camera.SetViewFromViewport(); Director.Instance.RunWithScene(scene); } } }

 

That is about as stripped down a functional program as you can make.  Be sure to add a reference to GameEngine2D.  The Imaging using statement is needed for the Font object that we will use later.  Nothing here should be new to you if you have gone through the earlier tutorials.

 

 

Alright, lets get started using the Schedule method.  First a quick explanation of how Update() works.  Remember in earlier tutorials when you called Director.Instance.Update()?  Well this triggers off a chain reaction of events.  This results in the current scene ( the one specified in the RunWithScene call ) having it’s Update call, which in turn results in all the (registered)Nodes in the Scene having their Update() methods called.  This process happens once per frame. Schedule() marks the node to be called during update, and provides a method to be called when the update occurs.  In this case we are going to declare that method using a Lambda.  Let’s take a look:

 

First off, we declare our sprite:

Texture2D texture = new Texture2D("/Application/smile.png",false); TextureInfo ti = new TextureInfo(texture); SpriteUV sprite = new SpriteUV(ti); sprite.Quad.S = new Vector2(128,128); sprite.Position = scene.Camera.CalcBounds().Center; sprite.Position = new Vector2(sprite.Position.X - 256,sprite.Position.Y); sprite.CenterSprite();

 

Everything here you’ve seen before.  The position is all relative to the middle of the screen.  We will be rendering 3 sprites, this one will be positioned off to the left. Now for the new stuff:

 

bool goingUp = true; sprite.Schedule( (dt) => { if(goingUp) { sprite.Position = new Vector2(sprite.Position.X, sprite.Position.Y + 3); if(sprite.Position.Y >= 390) goingUp = false; } else { sprite.Position = new Vector2(sprite.Position.X, sprite.Position.Y - 3); if(sprite.Position.Y <= 64) goingUp = true; } });

 

Schedule takes a (lambda) function that is called every time Update() is called.  dt is the elapsed time since Update() was last called, although we aren’t using it this time.  Our actual method is pretty straight forward, we have a bool that determines which direction we are going.  We add 3 to our Y direction until we get near the the top of the screen, then flip direction.  Otherwise we are going down, by decrementing by 3 until we get to the bottom.  ( 64 is half of our sprite height ).  The Schedule() method is probably the simplest way to update a Node ( SpriteUV is derived from Node ) object.

 

Next we look at handling updates by deriving from Node ( actually, SpriteUV again ) and overriding the Update() method.  Create a new class, I am calling mine BouncingSmile.cs but you can call it whatever you want.  Enter the following code:

 

 

using System; using Sce.Pss.Core; using Sce.Pss.Core.Graphics; using Sce.Pss.HighLevel.GameEngine2D; using Sce.Pss.HighLevel.GameEngine2D.Base; namespace Updating { public class BouncingSmile : SpriteUV { private bool _goingUp; public BouncingSmile () { Texture2D texture = new Texture2D("/Application/smile.png",true); this.TextureInfo = new TextureInfo(texture); this.Quad.S = new Vector2(128,128); _goingUp = true; } public override void Update (float dt) { if(_goingUp) { this.Position = new Vector2(this.Position.X, this.Position.Y + 3); if(this.Position.Y >= 390) _goingUp = false; } else { this.Position = new Vector2(this.Position.X, this.Position.Y - 3); if(this.Position.Y <= 64) _goingUp = true; } } } }

 

As you can see, the Update() method is basically identical to our lambda method earlier.  Otherwise we are basically just handling the creation of our sprite, just like we did back in the Hello World sample.

 

Now that we have a class with an Update() method defined, lets go back to AppMain.cs and put it to use.

 

BouncingSmile bs = new BouncingSmile(); bs.Position = scene.Camera.CalcBounds().Center; bs.CenterSprite(); Scheduler.Instance.ScheduleUpdateForTarget(bs,1,false);

 

We declare our BouncingSmile object object ( whose constructor took care of creating it’s Sprite ), then position it in the middle of the screen.  Finally we register our object so that it’s Update method is going to be called.  We do this using the Scheduler singleton.  ScheduleUpdateForTarget results in the target ( bs ) having it’s Update() called every frame.  In addition to the target to update, you pass in the priority ( how early in the Scheduler’s update phase it will be called ) and whether or not to start paused.  The end result of this is virtually identical to the earlier Schedule() method.  Our next method is much different however.

 

We are now going to create another class, this one called BounceAction.cs.  Create it, then add the following code:

 

using System; using Sce.Pss.Core; using Sce.Pss.HighLevel.GameEngine2D; using Sce.Pss.HighLevel.GameEngine2D.Base; namespace Updating { public class BounceAction : ActionBase { private bool goingUp; public BounceAction () { goingUp = true; } public override void Update (float dt) { base.Update (dt); if(goingUp) { this.Target.Position = new Vector2(this.Target.Position.X, this.Target.Position.Y + 3); if(this.Target.Position.Y >= 390) goingUp = false; } else { this.Target.Position = new Vector2(this.Target.Position.X, this.Target.Position.Y - 3); if(this.Target.Position.Y <= 64) goingUp = true; } } } }

 

We are creating a new class derived from ActionBase.  Actions are exactly what they sound like, runnable events.  ActionBase is the very base class of action types available.  Unlike our earlier examples, BounceAction isn’t actually tied to any single object, it can be applied to any Node derived object, making it very easy to create reusable/retargetable actions.  Once again, the code looks virtually identical to our prior examples. 

 

Now head back to AppMain.cs and add the following code:

 

Texture2D texture2 = new Texture2D("/Application/smile.png",false); TextureInfo ti2 = new TextureInfo(texture); SpriteUV sprite2 = new SpriteUV(ti); sprite2.Quad.S = new Vector2(128,128); sprite2.Position = scene.Camera.CalcBounds().Center; sprite2.Position = new Vector2(sprite2.Position.X + 256,sprite2.Position.Y); sprite2.CenterSprite(); BounceAction ba = new BounceAction(); ActionManager.Instance.AddAction(ba,sprite2); ba.Run();

 

The majority of that code is just us creating another sprite object.  The key part are the last three lines.  What we are doing here is creating a BounceAction, then registering it with the ActionManager singleton, applying it to our new sprite.  Finally we trigger our action to actually run.  Just like the Scheduler singleton, ActionManager is called once per frame.  The power of using ActionManager is that the action isn’t tied to the thing being acted upon.  There are some powerful things you can do with ActionManager, like queuing up actions up, or blending between actions, etc…

 

 

So there were three different different ways to handle updates with your PS Suite GameEngine2D node objects.  In a moment I will post the completed source for AppMain.cs.  There is however one new concept in the following code, Labels.  In the comments for my earlier Hello World example, I said there were better ways to actually display Hello World on screen, and that way is using the Label class.

 

In order to make a Label, you first need a Font, which in turn needs a FontMap texture. 

 

Font font = new Font(FontAlias.System,16,FontStyle.Bold); FontMap fontMap = new FontMap(font,512);

 

Then it is just a matter of creating your Label:

Label label1 = new Label("Derived from Node",fontMap); label1.Position = new Vector2(0,0);

 

Then add it to the scene to be displayed:

scene.AddChild(label1);

 

And that… is the easiest way to display text on screen.

 

Alright, now lets put everything together.

 

using System; using System.Collections.Generic; using Sce.Pss.Core; using Sce.Pss.Core.Environment; using Sce.Pss.Core.Graphics; using Sce.Pss.Core.Input; using Sce.Pss.Core.Imaging; // for font using Sce.Pss.HighLevel.GameEngine2D; using Sce.Pss.HighLevel.GameEngine2D.Base; namespace Updating { public class AppMain { public static void Main (string[] args) { Director.Initialize(); Font font = new Font(FontAlias.System,16,FontStyle.Bold); FontMap fontMap = new FontMap(font,512); Scene scene = new Scene(); scene.Camera.SetViewFromViewport(); //Center sprite BouncingSmile bs = new BouncingSmile(); bs.Position = scene.Camera.CalcBounds().Center; bs.CenterSprite(); Label label1 = new Label("Derived from Node",fontMap); label1.Position = new Vector2(bs.Position.X - 80, bs.Position.Y + 200); Scheduler.Instance.ScheduleUpdateForTarget(bs,1,false); //Left sprite Texture2D texture = new Texture2D("/Application/smile.png",false); TextureInfo ti = new TextureInfo(texture); SpriteUV sprite = new SpriteUV(ti); sprite.Quad.S = new Vector2(128,128); sprite.Position = scene.Camera.CalcBounds().Center; sprite.Position = new Vector2(sprite.Position.X - 256,sprite.Position.Y); sprite.CenterSprite(); bool goingUp = true; sprite.Schedule( (dt) => { if(goingUp) { sprite.Position = new Vector2(sprite.Position.X, sprite.Position.Y + 3); if(sprite.Position.Y >= 390) goingUp = false; } else { sprite.Position = new Vector2(sprite.Position.X, sprite.Position.Y - 3); if(sprite.Position.Y <= 64) goingUp = true; } }); Label label2 = new Label("Using lambda",fontMap); label2.Position = new Vector2(sprite.Position.X - 60, sprite.Position.Y + 200); //Right sprite Texture2D texture2 = new Texture2D("/Application/smile.png",false); TextureInfo ti2 = new TextureInfo(texture); SpriteUV sprite2 = new SpriteUV(ti); sprite2.Quad.S = new Vector2(128,128); sprite2.Position = scene.Camera.CalcBounds().Center; sprite2.Position = new Vector2(sprite2.Position.X + 256,sprite2.Position.Y); sprite2.CenterSprite(); BounceAction ba = new BounceAction(); ActionManager.Instance.AddAction(ba,sprite2); ba.Run(); Label label3 = new Label("ActionBase",fontMap); label3.Position = new Vector2(sprite2.Position.X - 50, sprite2.Position.Y + 200); scene.AddChild(sprite); scene.AddChild(bs); scene.AddChild (sprite2); scene.AddChild(label1); scene.AddChild(label2); scene.AddChild(label3); Director.Instance.RunWithScene(scene); } } }

 

And here is our finished application:

smilebounce

 

As always, you can download the entire project here. Oh, and this time I actually remember to test it on my Vita! Smile

Programming , , ,

11. May 2012

 

Alright, I have been programming long enough I shouldn’t have made this mistake, but… I did.  In the comments section for Working with Spritesheets, there were a couple comments about being unable to run on the device.  I swore when I was testing this I ran it on my actual Vita, but apparently I did not.

 

I really should have, because frankly it doesn’t work.  It just hangs and makes your Vita extremely unhappy with you in the process.  Running it through the debugger, I found it was dying a hideous death on this line:

XDocument doc = XDocument.Load ("application/" + imageDetailsFilename);

 

Hmm, nothing out of the ordinary there.  So off to Google I go!  Ends up that this is a bug in the SDK, welcome to the wonderful world of beta software!  From the same thread, the fix is fairly straight forward.  In Walker.cs change the beginning of the constructor to look like this:

 

//XDocument doc = XDocument.Load ("application/" + imageDetailsFilename); FileStream fileStream = File.Open( "/Application/" + imageDetailsFilename,FileMode.Open); StreamReader fileStreamReader = new StreamReader(fileStream); string xml = fileStreamReader.ReadToEnd(); fileStreamReader.Close(); fileStream.Close(); XDocument doc = XDocument.Parse(xml);

 

You will also need to add SYstem.IO to your using declarations. Now everything will work fine when deployed to an actual Vita.  Hopefully Sony fix the bug in Xdocument.Load soon.

 

 

In the future I will make sure I test all tutorials on my device before pushing them live!

Programming , ,

9. May 2012

 

As you may know, if you want to publish on MacOS or on any iOS devices, you need to use animage Apple computer.  This can represent a rather large expense to many Indie developers ( no, I am not going to get into the ancient Mac price war argument! ).  What if you want to test with a Mac, but can’t justify the cost ( or space like in my office ) of another computer?  Wouldn’t it be great if you could rent a Mac as you needed it?

 

Well, that is exactly what MacInCloud offers!  Basically they rent out Mac machines over the internet on a time share basis.  Even better, these Macs are obviously targeted towards (game) developers, as it comes pre-loaded with a ton of game development software. This sounds wonderful to me, as even though I own a Mac ( an iMac ), I am more often on the road than not and I have no desire to lug around two laptops with me.  I’ve tried remote desktop’ing into my home Mac on occasion, but the experience was never all that nice.  Let’s take a look at how well MacInCloud pull it off!

 

 

If you are the type that flips ahead to ruin the ending, click here to jump to the verdict.

What does it cost?

 

Well that depends.  There are 4 ways to pay, and each one has a serious impact on the cost.  First and most expensive, you can pay as you go, which as of the time this was written is 1$ per hour.  Next, you can rent for the entire day for 8$.  You can also rent by the week and month, these prices all depend on the amount of time you need per day.

 

Here is a breakdown of prices for renting per week and month.

 

  Weekly rental Monthly rental
3 hours a day usage 12$ 20$
5 hours a day usage 15$ 25$
8 hours a day usage 19$ 30$
Unlimited usage 22$ 49$

 

Weekly and monthly rentals both include the first day for free ( well, 1 cent ), you can think of this as a trial period.

Note, and this is very important. You will be rebilled automatically until you cancel your subscription using PayPal! Not a big deal, but something you should be aware of upfront.  This applies to daily, weekly and monthly plans, but not to pay as you go plans. I will cover canceling your subscription later on, the process is pretty simple but a tad confusing.

 

So picking the right pricing scheme is a very tricky process.  If you just need a couple hours, pay as you go is obviously the ideal plan, but gets pricey quick.  For example on the 8 hours monthly plan, assuming you maxed your usage out, your hourly rate would be just 13 cents an hour!  On the other hand, paying for hours you aren’t going to use is just stupid.  It’s a tricky balancing act deciding which plan is right for you.  Initially I am going to go with the monthly 5 hours a day plan.

 

Sign up process

 

Sign up is almost as simple as it gets.  First you need to create a site account here.  That is just a website account, your email and password only, not a subscription.  In my case I am going with a monthly subscription, and its simply a matter of going to the Pricing menu, selecting the plan you want  then click Subscribe.  This will bring you to PayPal ( which is the only payment option ).

 

Here is the line item as it appears in PayPal:

image

 

You initially are billed only a penny for your first day.  A bit of a warning, this kind of stuff can be problematic with Visa/Mastercard.  I’ve received calls from fraud protection when really small transactions are charged against my card.  Don’t sweat it, it’s not a bad thing if you receive this call, it’s just the banks computers being cautious, just warning you it might happen.  If you cancel in the first day, you will not be billed for the service.

image

 

You will now be redirected back to macincloud.com and presented with your Mac server name as well as your username and password.  This information will also have been mailed to whatever email account is linked with your PayPal account.  You are now signed up.

 

Logging In

 

There are two ways to log in to MacInCloud.  The easiest is to use their browser based client, which recommends you use Google Chrome.  I will start with this method.  Save your credentials from the the welcome email/page and head on over to http://www.macincloud.com/member-area/browserconnect.

 

image

 

This part of the process isn’t as obvious as it should be, as you currently have two sets of user names and passwords, the one you got when you signed up for the site and the one you got issued after paying.  They did a really poor job of telling you which username/password to use.  Coincidentally, it’s the site ( your email ) password you use here, not the one they assigned you.  Note to MacInCloud, you should really add some text to explain this!

 

Anyways, once you have logged in, you will be brought to this screen:

image

 

This is where you use the credentials they assigned you.

Somewhat annoyingly, these are the resolutions you are limited to:

image

 

My native resolutions are 1920x1080 and 1366x864, so these selections aren’t ideal for me.  This was one of the problems I had when remoting my personal iMac and I did find it irritating.  Also, given the fact you are using credentials that were assigned to you, it would be really nice if this screen had a “remember my username and password” option like the prior screen where you need it less.

 

You are greeted by this screen initially.

image

 

 

Then…

 

Well, then it doesn’t work.  It worked exactly once, I resized the window and I got a Java EOF error.  Since then I have been unable to log back in using the webclient.  I tried in Firefox and same problem, then I tried in IE9 and it simply isn’t supported.

 

So, if you are here for the web client… go elsewhere, it simply isn’t ready for prime time.  Plus in the very brief period of time I was connected, it was exceedingly slow.

 

 

Connecting using Remote Desktop

This is the main way to connect.  You download the zipped connection file in the welcome email, extract it and you are presented with the following options. 

 

image

 

Double click the selection that is most appropriate to you and your connection.

 

image

 

Use the provided username and password to log in.

 

And you are now at your desktop.  Can you tell by the fact the iPhone simulator is loaded already exactly what kind of developers they are targeting?

 

image

 

 

So what is installed already?

 

This is one area where MacInCloud really shines.  The following software was pre-installed:

  • Adobe DreamWeaver CS 5.5
  • Adobe Fireworks CS 5.1
  • Adobe Flash CS 5.5
  • Adobe Illustrator CS 5.1
  • Adobe InDesign CS 5.5
  • Adobe Media Encoder CS 5.5
  • Adobe Photoshop CS 5.1
  • Cocos2d 1.0.1
  • Corona SDK stable and development versions
  • Dropbox
  • Eclipse
  • Firefox
  • Chrome
  • GameSalad
  • Office 2011
  • MonoDevelop
  • OmniGraffle Professional
  • RhoStudio
  • Stonetrip
  • TestFlightSDK
  • TextWrangler
  • Titanium Studio
  • Xcode

 

Curiously absent?  Unity or any 3D applications.  Otherwise it’s pretty much a whose who of game development applications.

 

What the heck is going on here?

 

This may be one of those weird karma issues, but in my brief period trying to test this, my connection dropped… a lot.  Within an hour I had 10 disconnects from my ISP ( Rogers in Canada ).  For the record I haven’t had my internet connection drop in months, and I’ve experienced 10 in the last two hours?

 

Again, as I said, it might be horrifically bad timing…

 

Or MacInCloud and my ISP don’t play well together.  I know not to blame RDP, as I literally use it every day to remote control my servers.  However, when I used my Phone’s LTE connection, I didn’t have a single issue.

 

 

What’s the performance like?

 

Well, this is the biggie, isn’t it?  How well does it actually perform.

 

I tested with two devices, my home cable connection and my phone LTE connection.  The speed of your connection is obviously going to be a big factor, but both connections should be considered above average.

 

I can’t really describe how it performs, so instead I will screen capture both in action and let you judge for yourself.  I start each with a speedguide test so you can gauge my connection against your own.  To contrast, I remote desktop to one of my servers ( ironically enough, hosted by the same company MacInCloud use ) to compare against remote controlling a Windows server.  HD movie here.

 

Evaluating MacInCloud performance

One word, disappointing.

 

How do I quit?

 

Log in to your PayPal account.

 

On the main screen, locate your “My Recent Activity” part, click the details link:

image

 

Now in the subscription details, at the very top you should see:

image

 

Click the Cancel link

image

 

Click the Cancel Profile button.

 

And…

image

 

Your PayPal subscription is now canceled.    If you go back to your recent activity, it should now look like:

 

image

 

And now you will no longer be billed.

 

 

So then, what’s the verdict?

 

Not great I am afraid to say.  While making the screenshots on how to cancel, I went ahead and cancelled.  When I signed up I fully intended to go for the full month but the performance was just so appallingly bad.  Frankly when I remote controlled my iMac from home the performance was actually quite a bit better than with MacInCloud.com.

 

It is possible I just caught them on a bad bandwidth day, so you have little to lose for trying it yourself.  Perhaps in your case it will work better.  Both of my connections are quite quick and neither was even close to functional.

 

Now, if you just want to log into a Mac to compile your code and publish it to the AppStore, this service might prove useful.  However, to actually do any development, I just couldn’t see anyone having the patience. Actually debugging a running game I think would be simply impossible.

 

I hope MacInCloud.com massively increase the speed or that I caught them on a bad day, as their idea is brilliant.  The execution however leaves a lot to be desired.

 

You can of course try it for yourself, it won’t cost you a cent!  Well… it will cost you exactly one cent.

General

9. May 2012

 

 

A few days back I was contacted about translating some of my Vita tutorials into Spanish.  Well the results of that conversation are available here on IndiceVita.es.  This is my imagespritesheet tutorial translated into Spanish.  I believe they are going to translate more tutorials in the future, so if you prefer reading Spanish to English, be sure to check it out! You need to register to be able to access the forum.

 

Is the translation good?  Beats the heck out of me!  My Spanish abilities begin and end with “La cerveza, por favor”, which frankly has served me well! Smile

 

On this topic, if you are interested in translating any of my content to another language, either hosted on your own site or hosted here, feel free!  The only thing I ask in return is a link back to the original source tutorial ( AKA, credit ) and a link to the finished product, either emailed to me ( mike [at] gamefromscratch [dot] com ) or as a comment.  It’s always cool seeing something you’ve written in a different language… even if you are reading it through a half illegible Google translation!

General

9. May 2012

 

This post is waaayyyyyy off the topic of game development but it’s one of those things I have been fighting with for months so I figured I’d share the solution in case any of you are having the same issue.

 

Basically with one of my laptops I would often see my computer crawl to a screeching halt, to the point of nearly uselessness.  Generally the culprit would be MsMpEng.exe chewing away at my CPU, generally maxing out a core completely.  On occasion it would be Thunderbird ( my email client ) maxing out a core, but frankly this was pretty typical Thunderbird behavior( when indexing or downloading mail it used a lot of CPU ), so I would generally ignore it an expect it to go away.  Normally I would simply kill off the MsMpEng task as well as the msseces.exe ( which would simply restart MsMpEng if not killed ) and the problem would go away.  Not ideal killing off my anti-virus, but it’s one of those “I’ll look into it later” things.

 

Of course, later always became later until this morning when I simply got too fed up with it.  I was about half an inch away from just uninstalling Microsoft Security Essentials and going with a different anti-virus app.  This morning, both Thunderbird AND MsMpEng were taking turns maxing out my cores, so I finally put one and one together…  The fix is remarkably easy, in Microsoft Security Essentials, go to the Settings tab, select Exclude processes and add the Thunderbird.exe process like such:

 

 

image

 

 

Problem… finally… solved.

 

Alright, now that my computer is no longer acting like a 386 with the turbo button disabled, back to making games!

Totally Off Topic

Month List

Popular Comments