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:
As always, you can download the full sources here.