Subscribe to GameFromScratch on YouTube Support GameFromScratch on Patreon

10. August 2012

 

I received a comment from a Cocos2D-HTML developer saying that the API is complete for the upcoming beta release, so that I could update the tutorials on this site.  So today I jumped in to see exactly what changed and the answer is quite a bit!  In the process of updating the code to work with the newest Cocos2D code, I went through a great deal of pain tracking down those changes.  This post is to illustrate what has changed, so you don’t have to go through the same process.

 

The code being ported is the example code from this tutorial.

Changes:

 

Filename changes

 

I encountered a few filename changes ( which JavaScript can make exceedingly annoying to find ).  First off, a few files have had their casing changed, which you won’t notice you are working in Windows, but under Linux you will.  Mostly it’s a matter of files being renamed from cc to CC.  Additionally the folder keypad_dispatcher is now keyboard_dispacter, and CCKeypadDelegate.js and CCKeypadDispatcher.cs have been renamed to CCKeyboardDelegate.js and CCKeyboardDispatcher.cs respectively.

 

Function changes

 

ccp is now Point

ccc2/3/4/ is now Color2B,Color3B,Color4B

Layer.setIsRelativeAnchorPoint has been removed.

Director.sharedDirector() is now Director.getInstance();

setIsTouchEnabled() is simply isTouchEnabled()

setIsKeypadEnabled() is now isKeyboardEnabled()

 

Events have been renamed, for example:

ccTouchesEnded is now onTouchesEnded

 

The Keyboard delegate have renamed events from:

keyDown and keyUp to onKeyDown and onKeyUp

cc.key.[name] is now cc.KEY.[name]

cc.Touch ( the value passed to touch handlers ) has changed from .locationInView() to .getLocation()

cc.AudioManager.sharedEngine() is now cc.AudioEngine.getInstance();

cc.Log is now cc.log

 

Bootstrap change

 

This is where the biggest changes occurred.  The startup process is completely different.  First of all, library loading is no longer the responsibility of the  application, it is instead handled by jsloader.js.

 

This changes cocos2d.js massively:

cocos2d.js

(function () {
    var d = document;
    var c = {
        COCOS2D_DEBUG:2, //0 to turn debug off, 1 for basic debug, and 2 for full debug
        box2d:false,
        showFPS:true,
        frameRate:60,
        tag:'gameCanvas', //the dom element to run cocos2d on
        engineDir:'../cocos2d/',
        appFiles:['MyFirstApp.js']
    };
    window.addEventListener('DOMContentLoaded', function () {
        //first load engine file if specified
        var s = d.createElement('script');
        s.src = c.engineDir + 'platform/jsloader.js';
        d.body.appendChild(s);
        s.c = c;
        s.id = 'cocos2d-html5';
        //else if single file specified, load singlefile
    });
})();

If you haven’t seen this syntax before, it is basically an anonymous function that will execute at the end of declaration ( because of the () it ends in ).  The majority of what is going on here is the creation of a configuration file ‘c’, where a number of settings are, um, set.  tag is the name of the canvas element in your html file, engineDir is where you installed cocos2D to, appFiles are additional files you write ( in addition to your main.js ).  Basically every file you create needs to be added to this array.  It then adds an event that will be fired once the DOM has been populated, which will then create a new <SCRIPT> tag in your HTML document, then pass in the path to the jsloader, which will then load all of the cocos2D libraries, as well as anything your specified in the appFiles array.  Finally it stores the configuration settings in ‘c’ in the newly created script tag.

 

In a change I disagree with, the framework now forces you to add a file named main.js, which will be called by jsloader at the end of the loading process.  IMHO, this should be added as part of the configuration you set above.  This file replaced AppDelegate.js from the tutorials.  Let’s take a look at the new main.js:

var cocos2dApp = cc.Application.extend({
    config:document.querySelector('#cocos2d-html5')['c'],
    ctor:function (scene) {
        this._super();
        this.startScene = scene;
        cc.COCOS2D_DEBUG = this.config['COCOS2D_DEBUG'];
        cc.setup(this.config['tag']);
        cc.Loader.shareLoader().onloading = function () {
            cc.LoaderScene.shareLoaderScene().draw();
        };
        cc.Loader.shareLoader().onload = function () {
            cc.AppController.shareAppController().didFinishLaunchingWithOptions();
        };
        cc.Loader.shareLoader().preload([
        ]);
    },
    applicationDidFinishLaunching:function () {
        // initialize director
        var director = cc.Director.getInstance();
        director.setDisplayStats(this.config['showFPS']);
        director.setAnimationInterval(1.0 / this.config['frameRate']);
        director.runWithScene(new this.startScene());

        return true;
    }
});
var myApp = new cocos2dApp(MyFirstAppScene);

Things have changed a fair bit here, but the process is pretty much the same.  First thing to notice is it pulls the configuration data ‘c’ and stores it in the variable config, which is then used to setup cocos2D.  The next major thing to notice is we now create an instance of our app, and pass in the scene to start with. 

 

Now let’s take a look at the changes to MyFirstApp.cs:

var MyFirstApp = cc.Layer.extend({
    init:function()
    {
        this._super();

        var s = cc.Director.getInstance().getWinSize();

        var layer1 = cc.LayerColor.create(new cc.Color4B(255, 255, 0, 255), 600, 600);
        //layer1.setPosition(new cc.Point(s.width/2,s.height/2));
        //layer1.setIsRelativeAnchorPoint(true);
        layer1.setAnchorPoint(new cc.Point(0.5,0.5));

        
        var helloLabel = cc.LabelTTF.create("Hello world", "Arial", 30);
        helloLabel.setPosition(new cc.Point(s.width/2,s.height/2));
        helloLabel.setColor(new cc.Color3B(255,0,0));
        var rotationAmount = 0;
        var scale = 1;
        helloLabel.schedule(function()
            {
                this.setRotation(rotationAmount++);
                if(rotationAmount > 360)
                    rotationAmount = 0;
                this.setScale(scale);
                scale+= 0.05;
                if(scale > 10)
                    scale =1;
            });

        layer1.addChild(helloLabel);
        this.addChild(layer1);

        
        return true;
    }

});

var MyFirstAppScene = cc.Scene.extend({
    onEnter:function(){
        this._super();
        var layer = new MyFirstApp();
        layer.init();
        this.addChild(layer);
    }
})

 

Things have changed a bit here.  First we now extend a scene to create a new object MyFirstAppScene.  This in turn creates a layer and adds it to itself.  The onEnter event is called when the scene is activated ( via RunWithScene ).  Otherwise all of our changes are those described above ( function renames, removal, etc… ).

 

 

I hope that helps you port your existing code to the newest codebase.  All of the changes are improvements ( except perhaps the whole forced main.js thing, I still don’t like that ), so it is worth the pain.  I hope to get the tutorials all updated shortly, but unfortunately, these changes more or less will result in complete re-writes of 3 tutorials, so it might take a bit! Sad smile

Programming , ,

8. August 2012

I just finished publishing the GameFromScratch 3D Engine round-up.  This is a guide to the top game engines in use by game developers today, that are available to be licensed. There are a total of 20 engines on the list, and for each one it includes the platforms it runs on, the platforms it can target, the price, sample games, the books available if any, key websites ( generally the forum and wiki or documentation pages if available ), programming language supported and example games published with the engine.

 

I have a similar round-up in the works for 2D game engines, which I hope to publish shortly.  Additionally, I have already published a similar document for HTML5 game engines.  I made the horrific mistake of authoring the guide in Word ( what was I thinking!??! ), and as a result the fonts are a little wonky in Chrome.  Hopefully I can find and kill this annoying trait.

 

If I made any mistakes, or I missed a key engine, please let me know.  Hopefully you find the 3D engine round-up useful!

News, Programming, Design , , , ,

7. August 2012

logo_powered_black

I wrote sometime back about RIM’s open-source Gameplay SDK.  GamePlay is a complete 3D engine that targets Blackberry OS 10/PlayBook OS, Android, iOS, Windows and MacOS X.  They just announced the release of 1.4 and it’s full of some pretty nice additions:

 

New features

  • Lua script bindings on all public interfaces of the framework.
  • Script binding generator tool for creating user-defined Lua script bindings from Doxygen XML.
  • AI state machine for AI programming/scripting on game objects.
  • Virtual gamepad input support with custom theming using UI system.
  • Optimizations using NEON math for mobile platforms.
  • Compressed texture support for DXT, PVRTC, ATC and ETC1.
  • Improved modular shaders with support for #include in shaders and new light map support.
  • Optimizations and Improvements to the UI system such as inertial scrolling and scrollbars.
  • Pre-built versions of the gameplay-encoder and gameplay-luagen tools.
  • Optimizations in animation and physics.
  • Fixes to support Maya 2012/2013 COLLADA DAE_FBX export.
  • FBX 2013 format support.

 

The also announced their roadmap for future versions:

The ‘next’ branch features for v1.5, v1.6, v1.7

  • Linux support.
  • Vehicle physics.
  • AI path finding with navigation meshes.
  • Physical Gamepad input for Xbox 360, Wii, and Bluetooth® HID controllers.
  • Terrain.
  • Scene editor tool.

 

 

You can read the full announcement here or head over here to get started.  Lua scripting is a very nice addition, especially for those that prefer not to work at the C++ level ( include me in that camp! ).  Terrain and scene editing tools will go a long way towards helping adoption.

 

Nice work GamePlay team! 

 

If I could make a suggestion if anyone on the team is listening, I would recommend a rebrand at this point.  Gameplay is an apt name, but it is incredibly generic, meaning that your discoverability is going to be abysmal.  You’ve created a great product here, it would be a shame that people didn’t use it simply because they couldn’t find it!  Just adding a second word the next name (Gameplay NEXT GameplayGO Gameplay-A-GoGo) would help a ton and allow you to keep your existing documentation, website, etc… unchanged.

News ,

2. August 2012

 

I don’t often get excited about unreleased products, and up until this point I have never gotten all too excited about a Kickstarter project ( although I really look forward to a possible Planescape sequel! ), especially a hardware package that sounds too good to be true.  “The first truly immersive virtual reality headset for video games” is pretty ambitious.

 

Then I read the quotes:

 

  • "What I've got now, is, I honestly think the best VR demo probably the world has ever seen"
    John Carmack, id Software

  • "Needless to say, I'm a believer... We're extremely excited here at Epic Games to get the Unreal Engine integrated with Oculus"
    Cliff
    Bleszinski, Design Director Epic Games

  • "I think this will be the coolest way to experience games in the future. Simply that... that big"
    David Helgason, CEO Unity

  • "I’m really looking forward to getting a chance to program with it and see what we can do.”
    Michael Abrash, Valve

  • "It looks incredibly exciting, if anybody’s going to tackle this set of hard problems, we think that Palmer’s going to do it. So we’d strongly encourage you to support this Kickstarter.”
    Gabe Newell, President and Owner Valve

When it come to video game name dropping… that’s a pretty impressive list!

 

Now about the device itself:

occrift

It’s called The Oculus Rift  ( ugh ) and its tentative specs are:

Head tracking: 6 degrees of freedom (DOF) ultra low latency
Field of view: 110 degrees diagonal / 90 degrees horizontal
Resolution: 1280x800 (640x800 per eye)
Inputs: DVI/HDMI and USB
Platforms: PC and mobile
Weight: ~0.22 kilograms

 

Perhaps most important, and the thing that got my interest, it’s coming out of the box with Unity and Unreal engine support.  That could move it from being a fringe curiosity, to being a device with an actual future.

 

Ultimately this all came about from their kickstarter campaign, attempting to raise 250,000$ to make developer kit’s available.  Well, that goal is WAYYYYYYY passed, and as of writing they are pushing the million dollar mark. A pledge of 275$ or more got you early access to the device and the SDK, although they are sold out, so I don’t know why I bothered mentioning that! Smile 

 

That said, pledging 300$ or more gets you:

EARLY RIFT DEVELOPER KIT + DOOM 3 BFG: Try the Rift for yourself now! You'll receive a developer kit, perfect for the established or indie game developer interested in working with the Rift immediately. This also includes a copy of Doom 3 BFG and full access to our Developer Center for our SDK, docs, samples, and engine integrations! (Please add $30 for international shipping)

 

300$ really isn’t that much, well within reach of many indie developers.  Of course, it’s a pretty big long shot, although if you are working with Unreal or Unity in the first place, the Oculus Rift really isn’t that much of a risk.

 

What do you think?  Is this the future of gaming?  There were some rumours that next Xbox was going the VR route.  I also seem to recall reading Steam had something in the works too ( ironically, Michael Abrash, who was quoted, was the person I believed was leading the effort).  Personally though, it makes me sick… literally.  I have tried a couple of VR rigs in the past, and beyond a few minutes play I start getting dizzy.  Let’s hope that doesn’t hold true with the Oculus Rift. Oh, and that’s a terrible name.

News ,

31. July 2012

 

I had intended to end this series on part 4, all I had left to do was add a layer of persistence because Heroku didn’t keep files for more than a few hours, which was a pretty heavy limitation.  So I looked into various storage options, and I ended up going with CouchDB.  The process was a bit more involved ( and interesting ) than I suspected, so I decided to add another post in the series.  This part covers setting up cloud based database, and changing our code to persist to the database.

 

First off, I went to IrisCouch.com and signed up for a free database.  They provide (free!) cloud hosted CouchDB installs, including a full Futon management system, pictured below:

image

 

You can use this interface to create new databases, configure security etc.  It’s a bit tricky at times to navigate, but it gets the job done.

 

I created a new database called firstthis, then immediately secured it ( by default your website is publically accessible to everyone! ).  CouchDB works by storing information in documents instead of tables in a traditional database.  Instead of updating individual fields, you update the data in your document then replace the entire thing.  Tracking the newest revision becomes incredibly important when working with CouchDB.  Perhaps most key of all, CouchDB adds two fields to your data, _id and _rev.  _rev represents the newest revision, while _id represents the unique key.  In our case, for our user settings, we are going to use their email address as the key.  We simply store the files variable from our script to the server.  Here is a sample of files stored in CouchDB ( shown in the iriscouch admin page ):

 

image

 

As you can see, its simply our JavaScript variable, with an _id and _rev added. 

 

When you sign up for IrisCouch, you are given a URL where your database server is located, in the form of yoursite.iriscouch.com.

 

Now let’s take a look at the code differences.  It is pretty thoroughly documented ( combined with the above explaination ), so I won’t go into a lot of detail.  CouchDB is accessed using REST requests, but I instead used a node library Nano for access.  This was a bit of a double edged sword, as it took away a great deal of the complexity and grunt work, however it also removed me a step away from the well documented CouchDB. 

 

All of the code changes are in server.js

var express = require('express'), server = express.createServer(), im = require('imagemagick'), nano = require('nano')('http://Serapth:meat32ball@gfs.iriscouch.com'), db_name = "firstthis", db = nano.use(db_name), userEmail = 'mike@gamefromscratch.com', fs = require('fs'), files = { files:{}}; // Helper functions for getting and inserting docs in couchDB using nano function get_doc(docName,res){ db.get(docName,function(err,body){ if(!err) { res(body); } }); }; // There is no update in CouchDB. Just inserts, inserts and more inserts. // If you don't have the most current rev ( or it isn't a new insert ), an error (HTTP409) will occur. // TODO: Real error handling, attempt to get latest file, get it's rev, then try inserting again function insert_doc(doc,docname, tried) { db.insert(doc,docname, function (error,val,newval) { if(error) { return console.log(error); } // The insert will result in an updated rev, update our local files var to the most current rev. return files._rev = val.rev; }); } // Setup server static paths server.use('/cocos2d', express.static(__dirname + '/cocos2d') ); server.use('/cocosDenshion', express.static(__dirname + '/cocosDenshion') ); server.use('/classes', express.static(__dirname + '/classes') ); server.use('/resources', express.static(__dirname + '/resources') ); // Install the bodyParser middleware, which enables form data to be parsed when an upload occurs. server.use(express.bodyParser()); // Handle requests for / by returning index.html server.get('/', function(req,res){ res.sendfile('index.html'); console.log('Sent index.html'); }); // Handle requests for /settings by returning settings.html server.get('/settings',function(req,res){ res.sendfile('settings.html'); console.log('Send settings.html'); }); // Handle requests for images will be the form of site.com/image/imagename.png // Fetchs the image data from CouchDB and returns to user server.get('/image/:name', function(req,res){ if(files.files[req.params.name]) { res.contentType(files.files[req.params.name].contentType); db.attachment.get(userEmail + "/" + files.files[req.params.name].name,files.files[req.params.name].name).pipe(res); } }); // Uses ImageMagick to get image dimensions and return them as JSON data // This is to work around the requirement for Cocos2D sprites to know dimensions before loading image server.get('/imageSize/:name',function(req,res){ im.identify(files.files[req.params.name].path,function(err,features){ if(err) throw err; else res.json({ "width":features.width, "height":features.height }); }); }); // This gets the photo data, which is contained in our files variable. Simply return it JSON encoded server.get('/getPhotos', function(req,res){ res.json(files.files); }); // Erase all images : TODO: Remove images from database as well!!!! server.get('/clearAll', function(req,res){ files.files = {}; res.statusCode = 200; res.send(""); }) // Unfortunately there is no easy way to tell when a multi file upload is complete on the server, On('end') isnt called // Therefore we call /doneUpload from the client once we are done uploading. // Once we are done uploading files, we save our updated Files var up to couchDB, then get it again so it again immediately to have the most current rev server.get('/doneUpload', function(req,res){ insert_doc(files,userEmail,files._rev,0); get_doc(userEmail,function(res) { files = res; }); res.statusCode = 200; res.sendfile('settings.html'); }) server.post('/upload',function(req,res){ // This method is going to be called for each attached file. // Add the file details to files.files[] with the key set to the filename files["files"][req.files.Filedata.name] = { "name":req.files.Filedata.name, "path":req.files.Filedata.path, "size":req.files.Filedata.size, "contentType":req.files.Filedata.type, "description":req.body.description }; // Now read the file from disk and insert the file data in our CouchDB as an attachment named "emailAddress/filename.png" fs.readFile(req.files.Filedata.path,function(err,data){ if(!err){ db.attachment.insert(userEmail + "/" + req.files.Filedata.name,req.files.Filedata.name,data,req.files.Filedata.type , {}, function(err,body){ console.log(body); res.statusCode = 200; res.send(""); }); } }); }); server.listen(process.env.PORT || 3000); // Check the couchDB for an entry keyed to the users email address. If one exists, copy it into our files var get_doc(userEmail,function(results){ if(results){ files = results; } });

 

Now when you upload images, they will be stored to your CouchDB database on IrisCouch.  When you restart Node, it will automatically grab and populate files from the database. Note, the application from parts 1-4 aren’t updated to use this new code.

Keep in mind, this code isn’t production ready… error handling is sparse, there is no authentication, it would be easy to exploit with a DoS attack for example.  However, if you are interested in storing data from your Node App in a CouchDB database, I hope this sample was useful.

Programming , , ,

Month List

Popular Comments

PlayStation Mobile Tutorial: Creating scene transitions
Subscribe to GameFromScratch on YouTube Support GameFromScratch on Patreon


20. June 2012

 

This tutorial is going to cover creating transition effects between your GameEngine2D scenes.  It is actually going to be rather short and mostly code, as the subject is actually quite simple and consistent between different effects.

 

All right, lets just right in.  First of all, when need our main application.  This is going to perhaps be the simplest one we have created to date, and all of the code should be familiar to you by now.  Create a new file named AppMain.cs as follows:

 

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; namespace SceneTransitions { public class AppMain { public static void Main (string[] args) { Director.Initialize(); Scene1 scene1 = new Scene1(); Director.Instance.RunWithScene(scene1); } } }

 

All we are doing is Initializing the Director object, creating our custom scene of type Scene1 and telling it to run.  This literally is about the shortest PlayStation Mobile application you can create.

 

Now lets take a look at Scene1.cs

using System; using Sce.Pss.Core.Graphics; using Sce.Pss.HighLevel.GameEngine2D; using Sce.Pss.HighLevel.GameEngine2D.Base; namespace SceneTransitions { public class Scene1 : Scene { Texture2D texture; TextureInfo ti; public Scene1 () { this.Camera.SetViewFromViewport(); texture = new Texture2D("/Application/pic1.png",false); ti = new TextureInfo(texture); SpriteUV sprite = new SpriteUV(ti); sprite.Quad.S = ti.TextureSizef; sprite.Position = new Sce.Pss.Core.Vector2(0,0); this.AddChild(sprite); this.ScheduleUpdate(1); this.RegisterDisposeOnExitRecursive(); } ~Scene1 () { ti.Dispose(); texture.Dispose(); } public override void Update (float dt) { if((Sce.Pss.Core.Input.GamePad.GetData(0).ButtonsDown & Sce.Pss.Core.Input.GamePadButtons.Cross) == Sce.Pss.Core.Input.GamePadButtons.Cross) { if(Director.Instance.CurrentScene.IsRunning) Director.Instance.ReplaceScene(new Scene2()); } } } }

 

We are declaring a new class Scene1, which is derived from GameEngine2D.Scene. In this scene, in the constructor we are setting the camera to be sized to the viewport, creating a texture from our image pic1.png ( oh yeah, you need to add 3 images to your project, I picked three PS Vita wallpapers I downloaded off the net, you can use whatever files you want, but I assume you name them pic1.png pic2.png and pic3.png ) then create a sprite out of it.  This is all stuff we have done in prior tutorials.  We now add the sprite to our scene, and schedule this scene to receive updates.  Finally we call this.RegisterDisposeOnExitRecursive().  This function call is key, as it tells the Director to dispose of this scene when it is replaced.  If you do not call this, we will quickly run out of memory.

 

Next up is our destructor.  TextureInfo and Texture are both classes that you are expected to manage destruction of yourself ( they implement IDisposable ).  So in the destructor, which is called when our scene is replaced, we need to dispose of both of these items.  ( Actually I believe TextureInfo will take care of Texture2D, but don’t quote me on that ).

 

Next up is our Update() method.  As we have seen in the past, this method is called once every frame and is where your scene’s logic should be located.  In this case, we are waiting on the user hitting the Cross button ( or S key if using the simulator ), in which case we tell the Director to Replace the scene with a new created Scene2, which we will now create.

 

Create a file named Scene2.cs with the following code ( which is going to look extremely familiar… )

 

using System; using Sce.Pss.Core.Graphics; using Sce.Pss.HighLevel.GameEngine2D; using Sce.Pss.HighLevel.GameEngine2D.Base; namespace SceneTransitions { public class Scene2 : Scene { Texture2D texture; TextureInfo ti; public Scene2 () { this.Camera.SetViewFromViewport(); texture = new Texture2D("/Application/pic2.png",false); ti = new TextureInfo(texture); SpriteUV sprite = new SpriteUV(ti); sprite.Quad.S = ti.TextureSizef; sprite.Position = new Sce.Pss.Core.Vector2(0,0); this.AddChild(sprite); this.ScheduleUpdate(1); this.RegisterDisposeOnExitRecursive(); } ~Scene2() { ti.Dispose(); texture.Dispose(); } public override void Update (float dt) { if((Sce.Pss.Core.Input.GamePad.GetData(0).ButtonsDown & Sce.Pss.Core.Input.GamePadButtons.Cross) == Sce.Pss.Core.Input.GamePadButtons.Cross) { if(Director.Instance.CurrentScene.IsRunning) { Director.Instance.ReplaceScene( new TransitionCrossFade( new Scene3() ) { Duration = 4.0f, Tween = (x) => Sce.Pss.HighLevel.GameEngine2D.Base.Math.PowEaseOut( x, 3.0f )} ); } } } } }

 

So, basically it’s a cut and paste job of Scene1, just with a different texture file, and a different looking replace scene call.  I will look closer at that in a second.  Notice too that here we are creating a Scene3 in our Update() call, lets go ahead and create it next.

 

Create Scene3.cs

 

using System; using Sce.Pss.Core.Graphics; using Sce.Pss.HighLevel.GameEngine2D; using Sce.Pss.HighLevel.GameEngine2D.Base; namespace SceneTransitions { public class Scene3 : Scene { Texture2D texture; TextureInfo ti; public Scene3 () { this.Camera.SetViewFromViewport(); texture = new Texture2D("/Application/pic3.png",false); ti = new TextureInfo(texture); SpriteUV sprite = new SpriteUV(ti); sprite.Quad.S = ti.TextureSizef; sprite.Position = new Sce.Pss.Core.Vector2(0,0); this.AddChild(sprite); this.ScheduleUpdate(1); this.RegisterDisposeOnExitRecursive(); } ~Scene3() { ti.Dispose(); texture.Dispose(); } public override void Update (float dt) { if((Sce.Pss.Core.Input.GamePad.GetData(0).ButtonsDown & Sce.Pss.Core.Input.GamePadButtons.Cross) == Sce.Pss.Core.Input.GamePadButtons.Cross) { if(Director.Instance.CurrentScene.IsRunning) { Director.Instance.ReplaceScene( new TransitionSolidFade( new Scene1() ) { Duration = 1.0f, Tween = (x) => Sce.Pss.HighLevel.GameEngine2D.Base.Math.PowEaseOut( x, 3.0f )} ); } } } } }

Again, another cut and paste job, with just the texture file name changed, and a different ReplaceScene() call, this time creating a Scene1, basically creating an infinite application that shows Scene1, then button press, shows Scene2, button press, shows Scene3, button press, shows Scene1, repeat over an over.

 

Now lets look at the key differences between how the transitions work:

 

Scene1:

Director.Instance.ReplaceScene(new Scene2());

Scene2:

Director.Instance.ReplaceScene( new TransitionCrossFade( new Scene3() ) { Duration = 4.0f, Tween = (x) => Sce.Pss.HighLevel.GameEngine2D.Base.Math.PowEaseOut( x, 3.0f )} );

Scene3:

Director.Instance.ReplaceScene( new TransitionSolidFade( new Scene1() ) { Duration = 1.0f, Tween = (x) => Sce.Pss.HighLevel.GameEngine2D.Base.Math.PowEaseOut( x, 3.0f )} );

 

The transition from the first screen, does nothing, it simply transition to the next scene with no visual effect.  Your first image will simply be replaced with your second image.

 

Scene2 however, transitions by creating a new temporary scene, a TransitionCrossFade, which is essential a short lived scene that goes between Scene2 and Scene3 and causes a cross fade effect.  As you can see, we provide a Tween method which controls the rate at which the fade will occur.  A tween are not simply the people responsible for the bizarre success of the Twilight franchise, its actually short had for inbetween, which is essentially just a function that is going to be called over and over during a transition until it is completed.  Tweens are quite common in the animation world. 

 

Scene3 works almost identically to Scene2, but instead of a cross fade, it’s a solid fade.  You can see the difference in the video of this application in action.  There is one very important thing to be aware of here… these temporary scenes, TransitionCrossFade and TransitionSolidFade, if you try to replace them before they have completed running, your application will crash!  Truth is, in real life you won’t be switching scenes this quickly, so it should be a non-issue, but it is something you should be aware of.  If you want to witness this first hand, load this code up in the simulator and just repeatedly hit S, you will crash soon enough.

 

Now, let’s take a look at our code in action:

 

Transition between scenes on the PlayStation Vita Simulator

 

As always, you can download the full sources here.

Programming , , ,

blog comments powered by Disqus

Month List

Popular Comments