Subscribe to GameFromScratch on YouTube Support GameFromScratch on Patreon
26. April 2012

 

I am noticing from search traffic that this is an extremely common question, people seem to want to know if you can use C++ with the PS Studio SDK.VitaCpp

 

 

Simple answer and you aren’t going to like it.

 

 

No, no you can’t.

 

 

 

I wouldn’t hold your breath either, it’s the mono runtime behind the scenes that is providing the portability across devices.  If you want native C++ support you need to have access to the full development suite.  Even becoming a PSN developer to develop PSN Mini games requires well over 1000$.

 

 

 

If for some reason you prefer C++’s syntax over C# ( this may in fact be a sign of insanity by the way… ), you *might* and I emphasize *might* be able to take advantage of this project CPlusPlus, at some point, but even then you would have to write pure CIL code.  Without native access, there would be very little point using C++ in this situation.

 

 

 

Therefore for all intents and purposes, no you cannot use C++ with PlayStation Suite. C# is the only game in town and I wouldn’t expect to see that change any time soon. 

Programming


26. April 2012

 

In this tutorial we are going to manually manage the game loop manually.  Additionally we are going to look at the various ways of handling input from the gamepad.  This tutorial builds on the code we developed in the previous tutorial.  As you may recall, we created a “Hello World” sprite and centered it to the camera.  This time, we are going to give the user the ability to control the sprite’s position and size using the gamepad.

 

 

Let’s get straight to the code:

 

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.HighLevel.GameEngine2D; using Sce.Pss.HighLevel.GameEngine2D.Base; using Sce.Pss.Core.Imaging; namespace HelloWorld { public class AppMain { public static void Main (string[] args) { Director.Initialize(); Scene scene = new Scene(); scene.Camera.SetViewFromViewport(); var width = Director.Instance.GL.Context.GetViewport().Width; var height = Director.Instance.GL.Context.GetViewport().Height; Image img = new Image(ImageMode.Rgba,new ImageSize(width,height),new ImageColor(255,0,0,0)); img.DrawText("Hello World", new ImageColor(255,0,0,255), new Font(FontAlias.System,170,FontStyle.Regular), new ImagePosition(0,150)); Texture2D texture = new Texture2D(width,height,false,PixelFormat.Rgba); texture.SetPixels(0,img.ToBuffer()); img.Dispose(); TextureInfo ti = new TextureInfo(); ti.Texture = texture; SpriteUV sprite = new SpriteUV(); sprite.TextureInfo = ti; sprite.Quad.S = ti.TextureSizef; sprite.CenterSprite(); sprite.Position = scene.Camera.CalcBounds().Center; scene.AddChild(sprite); Director.Instance.RunWithScene(scene,true); bool gameOver = false; while(!gameOver) { Sce.Pss.HighLevel.GameEngine2D.Director.Instance.Update(); if(Input2.GamePad.GetData(0).Left.Release) { sprite.Rotate(Sce.Pss.HighLevel.GameEngine2D.Base.Math.Deg2Rad(90)); } if(Input2.GamePad0.Right.Release) { sprite.Rotate(Sce.Pss.HighLevel.GameEngine2D.Base.Math.Deg2Rad(-90)); } if((Sce.Pss.Core.Input.GamePad.GetData(0).Buttons & GamePadButtons.Up) == GamePadButtons.Up) { sprite.Quad.S = new Vector2(sprite.Quad.S.X += 10.0f,sprite.Quad.S.Y += 10.0f); sprite.CenterSprite(); } if((Sce.Pss.Core.Input.GamePad.GetData(0).Buttons & GamePadButtons.Down) == GamePadButtons.Down) { sprite.Quad.S = new Vector2(sprite.Quad.S.X -= 10.0f,sprite.Quad.S.Y -= 10.0f); sprite.CenterSprite(); } if(Input2.GamePad0.Circle.Press == true) gameOver = true; Sce.Pss.HighLevel.GameEngine2D.Director.Instance.Render(); Sce.Pss.HighLevel.GameEngine2D.Director.Instance.GL.Context.SwapBuffers(); Sce.Pss.HighLevel.GameEngine2D.Director.Instance.PostSwap(); } Director.Terminate(); } } }

 

 

 

The top portion of the code is completely unchanged, our new additions start at the line:

Director.Instance.RunWithScene(scene,true);

 

The key addition here is the second parameter “true”.  This bool is telling the Director singleton that we are going to handle the game loop ourselves, this means we need to call 4 methods manually ( described in a moment ).  Next up we create a bool gameOver, which is going to control when we exit our game loop.  Obviously we don’t want to exit right away, so we default it to false.  Speaking of game loops, that’s what the while line does, loops over and over until gameOver is set to true.

 

Now in each iteration of our loop, there are four methods we have to call, Update(), Render(), GL.Context.SwapBuffer() and PostSwap().  Update() tells the director we have moved on to the next frame, Render() draws the frame, SwapBuffers displays what Render() drew on the backbuffer to the screen (makes it visible) and finally PostSwap() tells the director we’ve finished swapping buffers and it must be called after SwapBuffers().  Those four combined represent a complete game loop, all the rest of the code handles input from the game pad.

 

Just to make something perfectly clear here, I am using 3 different ways to check for input, *you won’t do this in your code*.  I am just doing it to illustrate all of your different options in one example.  You should just pick one ( probably Input2 ) and use only it.  Lets look at them one at a time.

 

if(Input2.GamePad.GetData(0).Left.Release) { sprite.Rotate(Sce.Pss.HighLevel.GameEngine2D.Base.Math.Deg2Rad(90)); }

 

 

This method is the most likely way you will deal with Input.  Input2 is a wrapper around the Input object to make things a bit simpler.  GetData takes a parameter telling it which control ( controller 1, controller 2, etc ) you want to poll, returning a GamePadData object, representing the state the controller is in.  We are then checking if the “Left” button has been released.  In the case Left is released, we then rotate our sprite 90 degrees.  Rotate takes an angle value in radians, so we use the Math.Deg2Rad() helper function to convert from degrees to radians.  Of course you could have passed the radian value in instead of converting, 1.5709633 is 90 degrees in radians, it’s just a bit harder to look at.

 

if(Input2.GamePad0.Right.Release) { sprite.Rotate(Sce.Pss.HighLevel.GameEngine2D.Base.Math.Deg2Rad(-90)); }

 

 

This if statement is almost identical to the last one, but instead of using GetData(0), we use a handy alias (GamePad0) that represents exactly the same thing.  The only other difference is, in this case we are checking to see if the “Right” button has been released, and we are rotating by a negative value ( the other way ) if it is.

 

 

if((Sce.Pss.Core.Input.GamePad.GetData(0).Buttons & GamePadButtons.Up) == GamePadButtons.Up) { sprite.Quad.S = new Vector2(sprite.Quad.S.X += 10.0f,sprite.Quad.S.Y += 10.0f); sprite.CenterSprite(); } if((Sce.Pss.Core.Input.GamePad.GetData(0).Buttons & GamePadButtons.Down) == GamePadButtons.Down) { sprite.Quad.S = new Vector2(sprite.Quad.S.X -= 10.0f,sprite.Quad.S.Y -= 10.0f); sprite.CenterSprite(); }

 

 

This time we are using Input directly, using Input instead of Input2.  As you can see, the results are a bit more “raw”.  In this case we have to use bit masking to determine if a given button is pressed and there is no Released option.  In this case we are checking for the “Up” and “Down” buttons.  In the event that the user is pressing Up or Down, we are modifying the Scale of the quad our hello texture is pasted on.  Remember initially Quad.S is equal to the size of the screen in pixels.  If we press Up, we scale the image up 10 pixels in size, if we press down, we shrink it by 10 pixels in size.

 

 

Finally, we check ( using the Input2 method ), if the user has pressed the Circle button, in which case we set gameOver to true, causing our loop to exit and our program to end.

 

 

One thing to notice at this point is how we scaled the sprite.  Unlike rotate, we didn’t call a method, instead we modified the Quad.S(cale) property.  The actual transformation matrix of a node ( which SpriteUV is derived from ) is actually determined combining the Position, Scale, Skew and Rotation+Angle+RotationNormalize properties.  Therefore modifying any of these properties will translate the node accordingly.

 

 

Now run our game, if we press left or right, we rotate 90 degrees, while pressing up or down scales the images.  Finally press Circle to exit.

 

 

helloworld2

 

 

One last thing I suppose needs covering… how exactly do you press Left, Right, or Circle on the simulator?

Left directional key
Cursor key: ←

Up directional key
Cursor key: ↑

Right directional key
Cursor key: →

Down directional key
Cursor key: ↓

Square button
Alphabet: A

Triangle button
Alphabet: W

Circle button
Alphabet: D

Cross button
Alphabet: S

SELECT button
Alphabet: Z

START button
Alphabet: X

L button
Alphabet: Q

R button
Alphabet: E

 

 

Sadly, you cannot currently emulate the analog sticks using the simulator.  Obviously you can on the Vita device.

 

EDIT: Oops, forgot to include the project source code, which you can download here.

Programming


24. April 2012

 

 

There is a charter somewhere that states all tutorial series must start with the ubiquitous Hello World tutorial, and who am I to break the charter?  So that is exactly what we are going to do here, a simple Hello World. This is as much about getting up and running with PS Studio than it is about C# coding, as there are a couple small gotchas.  By the end of this tutorial you should be able to create, configure and run an application.  In future tutorials, I will assume you have these abilities.

 

If you haven’t already, download and install PlayStation®Suite SDK from here.  The install is pretty straight forward, take the defaults, next next next, done.  If you want some idea of what you just installed check out this post.  Now fire up PssStudio from your start menu.  Once loaded, select File->New-Solution, like this:

 

image

 

 

In the “New Solution” dialog, on the left hand side expand C# then select PlayStation Suite.  Select PlayStation Suite Application on the right, then fill in whatever name you want ( I  am using HelloWorld ).  This should automatically fill in Solution Name, it is your choice if you want to create a subdirectory or not, in this case I will.  Fill out the dialog like this:

 

image

 

 

Click OK, and your solution will be created.  Now we need to add an app.cfg file to your application, or it will fail to run.  Note, this is not that same as a .NET application configuration file.  In the Solution Explorer, right click your project name ( HelloWorld in my case ), then select Add->New File… like such:

 

 

image

 

 

Choose Misc on the left, then Empty Text File, name it app.cfg and click New.

 

image

 

The newly created file will open in the text editor, fill it in with the following:

 

memory: resource_heap_size : 16384 managed_heap_size : 16384 input: gamepad : false touch : false motion : false

 

 

This file is telling what kind of machine your application is targeting.  If you forget this step, the simulator pss.exe will just max out a CPU core, never responding.  Now in the Solution panel, locate and double click AppMain.cs, this is where our application code will reside.

 

image

 

 

The actual process of doing Hello World on Vita is actually incredibly involved, as you need to do almost everything yourself.  In this example however, I am going to take advantage of GameEngine2D, which is an included 2D Game engine that makes many of the drudge worthy tasks much easier.  That means we need to add a reference to GameEngine2D.  Adding a reference is simply saying “I am going to use the code included in this library” In order to add a reference to GameEngine2D, right click on References and choose Edit References… like such:

 

image

 

Then a dialog will pop up, locate Sce.Pss.HighLevel.GameEngine2D and check the box to it’s left.  Then click OK.

 

image

 

 

Now we can add a using entry to tell our code to use the newly referenced library.  This is where we run into a bug in MonoDevelop ( PS Studio ).  Look at the following auto-completion screenshot:

 

image

 

 

Hmmm… where is HighLevel?  We added the reference, it should be there.  Well, on adding a new reference it seems the intellisense/auto-completion isn’t updated properly.  I live by auto-complete so this is a big deal to me.  Simply close and re-open your solution and presto:

 

 

image

 

 

Thankfully, you don’t really need to add references all that often, so while it’s inconvenient to have to exit and restart, its not the end of the world.  PS Studio loads quickly enough to barely notice.

 

 

Alright, finally time for the code!

 

 

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.HighLevel.GameEngine2D; using Sce.Pss.HighLevel.GameEngine2D.Base; using Sce.Pss.Core.Imaging; namespace HelloWorld { public class AppMain { public static void Main (string[] args) { Director.Initialize(); Scene scene = new Scene(); scene.Camera.SetViewFromViewport(); var width = Director.Instance.GL.Context.GetViewport().Width; var height = Director.Instance.GL.Context.GetViewport().Height; Image img = new Image(ImageMode.Rgba, new ImageSize(width,height), new ImageColor(255,0,0,0)); img.DrawText("Hello World", new ImageColor(255,0,0,255), new Font(FontAlias.System,170,FontStyle.Regular), new ImagePosition(0,150)); Texture2D texture = new Texture2D(width,height,false, PixelFormat.Rgba); texture.SetPixels(0,img.ToBuffer()); img.Dispose(); TextureInfo ti = new TextureInfo(); ti.Texture = texture; SpriteUV sprite = new SpriteUV(); sprite.TextureInfo = ti; sprite.Quad.S = ti.TextureSizef; sprite.CenterSprite(); sprite.Position = scene.Camera.CalcBounds().Center; scene.AddChild(sprite); Director.Instance.RunWithScene(scene); } } }

 

 

PHEW!  Pretty long for a Hello World eh?  Truth of the matter is, had I not used GameEngine2D it would have easily been 4 or 5 times longer!  We will cover what is going on behind the scenes ( the stuff GameEngine2D is handling ) in a later post.  For now, just assume this is the way it works, at least while you are getting started.  Now lets take a quick walk through the code and look at what’s happening here.

 

First we add our additional includes, Sce.Pss.HighLevel.GameEngine2D and Sce.Pss.HighLevel.GameEngine2D.Base.  Our app consists of a single method, Main, as the event loop is actually managed by the Director.

 

Speaking of which, that is what the first line does, initializes the Director singleton.  A singleton is a globally available object that is allocated on it’s first use.  Director is the heart of your game, even though most of the complexity is hidden away.  Remember, you have full source code for GameEngine2D available if you want to peek behind the curtain.

 

Next up we create a Scene.  Again, Scene is an abstraction provided by GameEngine2D which can be thought of as a collection of visible “stuff”, the bits and pieces that compose what we want to display to the user and the Camera used to display them.  We then call SetViewFromViewport() which creates a camera sized to the window. Generally without GameEngine2D, you would have to do this yourself, setting up an orthographic project.

 

The next two lines get the width and height, as reported by the Director’s OpenGL context.  We then create an Image the same dimensions as our viewport.  The Image class is used to hold binary image data, such as from a PNG or JPG file, but in this case we are create a new blank image.  Once we create our Image, we call it’s DrawText method to draw our “Hello World” message.  ImageColor represents the color we want to draw the image ( red in this case ), Font represents the font to draw the text in ( there aren’t really many options here ), while ImagePosition represents the location within the image to draw the text at.

 

Now that we have created an image, we need to create a texture out of it.  Textures are most often thought of as the images mapped around 3D objects and in a way, that is still what we are doing here.  GPUs have no concept of image files or pixels, they deal only with textures.  That is why we copy our image data into the texture, using the SetPixels method of Texture2D and the ToBuffer() method of Image, to turn the images pixel data into an array Texture2D can use.  At this point we are done with our Image, so we Dispose() it.

 

We next create a TextureInfo object and assign our newly created Texture to it.  TextureInfo caches UV location information about the texture, as well as taking ownership of the texture itself.  More importantly, it’s a TextureInfo object that Sprite expects, so that is what we create.  Speaking of sprite, that is what we create next in the form of a SpriteUV.

 

Since modern GPUs don’t really deal with pixels anymore, everything is pretty much made out of textured polygons and SpriteUV is no exception.  It is essentially a rectangular polygon that faces the camera with our image textured on it, all sprites are.  Next up we set the sprite’s Quad ( the rectangle the texture is plastered to ) to be equal to the size of our texture, which in this case is the same size as our view.  We now position our sprite smack in the middle of the view.

 

Now that we created our Image data, copied that image data into a Texture2D that was then assigned to a TextureInfo object, which in turn was assigned to a SpriteUV, we are now ready to add that fully textured sprite to our scene, which we do by calling AddChild().  Yeah, it sounds very convoluted, but you will find it natural very soon and generally you just load your textures from file anyways, greatly simplifying this process.

 

Anyways, now that we have our scene populated with our texture, which is the same size as the screen, we go ahead and tell the Director to do it’s thing, via RunWithScene().  You can think of this as the game loop, although the internals of what it’s doing are hidden from you.

 

 

Don’t worry, it’s really not as complicated as it seems.  Now lets take a look at the fruits of our labour.  To run it in PS Studio, select the Run menu and either choose Start Without Debugging or Start Debugging, depending if you want to be able to debug or not, like such:

 

image

 

 

And presto, all our hard work resulted in…

 

image

 

May not be much to look at, but you successfully created a game you can run on a Vita!

 

Speaking of which, if you need details of running on an actual device instead of in the simulator, read this post.

 

The complete project file for this tutorial are available for download here.

 

 

 

Continue on to Hello World Part 2: Hello Harder.

Programming


22. April 2012

 

 

This post is going to take a look at what’s included with the PS SDK, PlayStation Suite Studio and all the various included tools and tutorials.  So if you are wondering what is included in the PSSDK or have downloaded it and are trying to figure out what exactly you’ve got, this post is for you!  It assumes you’ve installed to default directories, so if you haven’t you have to adjust all locations accordingly.

 

 

image

 

 

Where is everything?

 

 

The PS Suite SDK installs to two different locations.  First check out

C:\Users\Public\Documents\Pss

This is where all the documentation and samples are installed.  The samples are amazingly comprehensive, but we will cover that later.  The samples are in the “samples” sub-directory.  The documentation are in the “doc\en” sub-directory.  The most important file is pss_sdk_doc_e.chm, which is the primary source of documentation and should soon become your best friend.  On the other hand “index.html” brings up the html document, which appears to be system generated class reference documentation and duplicates a lot of the information in the chm file.  Of course, both of these can be launched from the start menu.  Just do yourself a favour now, open pss_sdk_doc_e.chm now and leave it open! Winking smile

 

 

The next important folder is C:\Program Files (x86)\SCE\Pss, assuming you are running a 64 bit Windows ( drop the (X86) if not ).  The mono and software directories can be pretty much ignored.  Within the “target\win32” is pss.exe, which is the PlayStation Suite simulator which of course can be launched from Studio.  The source directory contains 4 helper libraries with full source code, GameEngine2D, Model, Physics2D and UI.  Most are documented in the main documentation already, so I won’t go into further details on these.

 

Perhaps most important is the tools sub-directory and the key files being:


 

adb This is the Android debugging bridge, it’s normally part of the Android SDK, but apparently PSS uses it for debugging too.

AnimationConverter This command line application is used to convert animations authored in Adobe Flash into a PS Suite compatible format.

OscCustomizeTool This tool is used to create onscreen joystick controls for Android ( but not the simulator or Vita ).  The output is a cfg file.

PssStudio This is where the Studio is located, which is a customized version of MonoDevelop and we will see it in more details later.

ModelConverter Is a command line utility to convert from dae, fbx, xsi and x formats to mdx format for use in PS Suite, I will cover this process in an upcoming tutorial.

Vita This folder contains the device driver needed for your computer to see your Vita.

ShaderConverter Used to convert cg shaders to a PS compatible formats.

UIComposer Used for making GUIs, will look at this in a bit more detail later

 


 

Playstation Suite Studio

 

 

This is where the magic happens.  PlayStation Suite Studio is a modified version of MonoDevelop, which is a code editor, project manager and debugger all in one.  You create, debug and compile your code all from within Studio, which is capable of launching the Simulator or deploying and debugging on your actual device.  This is as screenshot Studio in action:

 

image

 

On the left is the project manager window, to the right is the tabbed area where you edit or debug your source code.  The windows change based on your current activity.  Perhaps the most important modifications to MonoDevelop, are the new PlayStation Studio specific projects.

 

image

 

Until the Visual Studio add-in is released, PlayStation Suite Studio is where you are going to spend the majority of your waking hours.  I will cover parts of it in more detail in later tutorials.

 

 

 

PlayStation Suite UI Composer

 

 

UI Composer is where you put together your User Interfaces, which are then saved in .uic XML format.  If you are familiar with building UIs in Visual Studio, Interface Builder, Qt Designer or various other similar UI generators, you will feel right at home here.  Here is a shot of UI Composer in action:

 

image

 

 

There’s a pretty good selection of widgets available, illustrated below:

 

image

 

 

UI Composer can be used to generate Scenes, Panels, Dialogs and ListPanels.  Once you have drawn your UI, you then “Build” it, which then generates cs code to be included in your project.  The code generated uses partial classes, meaning you can add your code, but if you make changes, it will not overwrite them.

 

 

 

OscCustomizeTool

 

 

This is a neat tool for creating onscreen controls for Android tablets.  The end result is a cfg file that controls how the, um, controls will be created.  However it doesn’t work on Vita ( makes sense… ) and doesn’t work on the simulator ( doesn’t make sesne ), so I haven’t really got a chance to use it.  The UI seems quite evident though, you pick what capabilities to enable:

 

image

 

 

Then you select the layout and form factor you want to use:

 

image

 

I look forward to trying this out a bit more, so hopefully they will add compatibility with the simulator, even if just single touch at first ( or better yet, give the ability to remote control using a device, or map to a keyboard ).

 

 

The Demos

 

 

Ok, wow, this is the part Sony really got right.  There are full source code demos, many many many demos.

 

 

As to the demos, there are lots of little ones you would expect to demonstrate individual aspects, such as playing music, math usage, clipboard, storage, networking, physics, input, UI, model loading, imaging, etc.  Then some are extremely impressive and detailed, like the following:

 

 

A flight game:

image

 

 

A Arkanoid-ish Game:

image

 

 

A 3D Tower defense game:

image

 

 

A fully 3D RPG!

image

 

 

A 3D R-Type style game:

image

 

 

An Angry Birds Style game:

image

 

 

A 2D Side Scroller:

image

 

 

A Puzzle Game:

image

 

 

An RSS Reader:

image

 

 

And many more.  Seriously Sony, bang up job on the samples!  This is where you will spend a lot of your time, reading through the source examples, which I need to warn are often documented in Japanese, as are some of the tooltips.

 

 

The SDK

 

So that’s the tools and demos included, what about the actual code libraries themselves?  Well, PlayStation Suite SDK is based on Mono, so you get most of the libraries you would expect from it, which means most of the .NET runtime which is pretty comprehensive.

 

Additionally, as I mentioned earlier, they provided full sample projects, including a 2D Game Engine and a physics implementation.  On top, here is the class hierarchy of the current SDK:

 

 

 

ClassListPS

 

Over all, I am extremely impressed with what is included.  I wish Visual Studio support was ready, but PlayStation Studio (MonoDevelop) is pretty impressive if a bit sloppy at times.  You basically have everything you need to get started, it’s just a matter of finding it.

 

 

In a nutshell, that’s what you get when you install PlayStation Suite SDK. If you are just starting out, I highly recommend you jump into the CHM help file, or more importantly, start running through the samples.  There is a ton of great content in there and they have been my main source of information so far, as the documentation can be a bit… lacking at times.

General


20. November 2011

 

 

Handling game time is problem that almost all games have to deal with.  A very good question recently came up in my C++ game from scratch tutorial about why I didn’t normalize the players movements which reminded me of a post on the subject.

 

 

Years ago Shawn Hargreaves of XNA ( and Allegro ) fame blogged about how XNA handles the Update and Render loops.  I simply post it here again because it is one of the most succinct posts I have encountered on the subject.  So, if you are looking into creating a game and need to figure out how to implement the game loop, I recommend you give it a read.

 

By default XNA runs in fixed timestep mode, with a TargetElapsedTime of 60 frames per second. This provides a simple guarantee:

  • We will call your Update method exactly 60 times per second
  • We will call your Draw method whenever we feel like it

 

Digging into exactly what that means, you will realize there are several possible scenarios depending on how long your Update and Draw methods take to execute.

 

The simplest situation is that the total time you spend in Update + Draw is exactly 1/60 of a second. In this case we will call Update, then call Draw, then look at the clock and notice it is time for another Update, then Draw, and so on. Simple!

 

What if your Update + Draw takes less than 1/60 of a second? Also simple. Here we call Update, then call Draw, then look at the clock, notice we have some time left over, so wait around twiddling our thumbs until it is time to call Update again.

 

What if Update + Draw takes longer than 1/60 of a second? This is where things get complicated. There are many reasons why this could happen:

 

  1. The computer might be slightly too slow to run the game at the desired speed.
  2. Or the computer might be way too slow to run the game at the desired speed!
  3. The computer might be basically fast enough, but this particular frame might have taken an unusually long time for some reason. Perhaps there were too many explosions on screen, or the game had to load a new texture, or there was a garbage collection.
  4. You could have paused the program in the debugger.

 

We do the same thing in response to all four causes of slowness:

  • Set GameTime.IsRunningSlowly to true.
  • Call Update extra times (without calling Draw) until we catch up.
  • If things are getting ridiculous and we are too far behind, we just give up.

If you think about how this algorithm deals with the four possible causes of slowdown I listed above, you'll see it handles them all rather well:

  1. Even if the computer is too slow to run Update + Draw inside a single frame, chances are that Update + Update + Draw will fit into two frames. The game may look a little jerky, but it will still play correctly. If the programmer is particularly smart they might even notice that we set IsRunningSlowly, and automatically reduce detail or turn off special effects to speed things up.
  2. If the computer is way too slow (ie. if the Update method alone is too slow to fit into a single frame) there isn't really much we can do, other than set IsRunningSlowly, cross our fingers, and hope the game might do something clever in response to that. Most of the time, though, if you find yourself in this situation you just need a faster computer!
  3. If a particular frame happens to take unusually long, we automatically call Update some extra times to catch up, after which everything carries on as normal. The player may notice a slight glitch, but we automatically correct for this to minimize the impact.
  4. Pausing in the debugger will leave the game a long way behind where the clock says it should be, so our algorithm will give up, accept that it has lost some time, and continue running smoothly from the time execution was resumed.

 

 

Shawn’s blog in general is a very good read, but this this post in particular is one that I seem to keep coming back to.

 

For the record, Pang from the C++ tutorial does not gracefully handle hitting a breakpoint ( it adds a layer of unwanted complexity for learning purposes ), so will do downright stupid things when it hits a breakpoint causing it to pause for a while.  I believe on the next frame it will cause your movement to be really really really far.  It would be as simple as adding if(elapsedTime > someReallyBigValue) startTimeOver() if you really wanted to fix this.

 

 

Sorry for digging up the past, now back to your regular broadcast!

Programming


GFS On YouTube

See More Tutorials on DevGa.me!

Month List