PlayStation Mobile Tutorial: Pinching, Tapping, Dragging and Flicking…

 

In this tutorial we are going to look at the various Gesture detectors built into the UI layer of the PlayStation Mobile SDK.  They all work fairly consistently, so this tutorial is going to be pretty light in explanation. 

 

There are 6 gesture detectors built in to the PS SDK; FlickGestureDetector, DragGestureDetector, TapGestureDetector, LongPressGestureDetector, PinchGestureDetector and DoubleTapGestureDetector.  DoubleTapGestureDetector barely works on the simulator and doesn’t work at all on the actual Vita, so we aren’t going to use it. 

 

Let’s just right in to coding, in this tutorial we are going to create an ImageBox UI widget that you can use with all these various GestureDetectors to flick, scale and drag all over the screen.  Here is 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.UI; namespace UIEffects { public class AppMain { private static GraphicsContext _graphics; private static ImageBox _imageBox; private static Label _label; private static FlickGestureDetector _flickGestureDetector; private static DragGestureDetector _dragGestureDetector; private static TapGestureDetector _tapGestureDector; private static LongPressGestureDetector _longPressGestureDetector; private static PinchGestureDetector _pinchGestureDetector; static private bool quit = false; private static float _origWidth; private static float _origHeight; private static float _origX; private static float _origY; // Note, no housecleaning, all event handlers leak! public static void Main(string[] args) { _graphics = new GraphicsContext(); UISystem.Initialize(_graphics); Sce.Pss.HighLevel.UI.Panel dialog = new Panel(); dialog.Width = _graphics.GetViewport().Width; dialog.Height = _graphics.GetViewport().Height; _label = new Label(); _label.Width = dialog.Width; _label.Height = 35; _label.Font = new Sce.Pss.Core.Imaging.Font(Sce.Pss.Core.Imaging.FontAlias.System,32,Sce.Pss.Core.Imaging.FontStyle.Regular); _label.SetPosition(0,0); _label.HorizontalAlignment = HorizontalAlignment.Center; _label.TextColor = new UIColor(0,0,0,255); _imageBox = new Sce.Pss.HighLevel.UI.ImageBox(); _imageBox.Image = new ImageAsset("/Application/image.png"); _imageBox.PivotType = PivotType.MiddleCenter; _imageBox.Width = _imageBox.Image.Width;///2; _imageBox.Height = _imageBox.Image.Height;///2; _imageBox.SetPosition(dialog.Width/2,//-_imageBox.Width/2, dialog.Height/2);///2-_imageBox.Height/2); _origWidth = _imageBox.Width; _origHeight = _imageBox.Height; _origX = _imageBox.X; _origY = _imageBox.Y; _flickGestureDetector = new FlickGestureDetector(); _flickGestureDetector.Direction = FlickDirection.Horizontal; _flickGestureDetector.FlickDetected += delegate(object sender, FlickEventArgs e) { if(e.Speed.X < 0) // Left new MoveEffect(_imageBox,800f,0f,_imageBox.Y,MoveEffectInterpolator.Elastic).Start (); else new MoveEffect(_imageBox,800f,dialog.Width,_imageBox.Y,MoveEffectInterpolator.Elastic).Start (); _label.Text = "Flicked"; }; _dragGestureDetector = new DragGestureDetector(); _dragGestureDetector.DragDetected += delegate(object sender, DragEventArgs e) { var newPos = new Vector2(e.Source.X,e.Source.Y) + e.Distance; e.Source.SetPosition(newPos.X,newPos.Y); _label.Text = "Dragged"; }; _tapGestureDector = new TapGestureDetector(); _tapGestureDector.TapDetected += delegate(object sender, TapEventArgs e) { e.Source.SetPosition(dialog.Width/2,dialog.Height/2); _label.Text = "Tapped"; }; _longPressGestureDetector = new LongPressGestureDetector(); _longPressGestureDetector.MinPressDuration = 3000f; _longPressGestureDetector.LongPressDetected += delegate(object sender, LongPressEventArgs e) { MessageDialog.CreateAndShow(MessageDialogStyle.Ok,"Press results", "Hey, let go of me! " + (e.ElapsedTime/1000).ToString() + " seconds elapsed!"); _label.Text = "Long pressed"; }; _pinchGestureDetector = new PinchGestureDetector(); _pinchGestureDetector.PinchDetected += delegate(object sender, PinchEventArgs e) { Vector2 newSize = new Vector2(e.Source.Width * e.Scale,e.Source.Height * e.Scale); e.Source.SetSize(newSize.X,newSize.Y); _label.Text = "Pinched"; }; _imageBox.AddGestureDetector(_flickGestureDetector); _imageBox.AddGestureDetector(_dragGestureDetector); _imageBox.AddGestureDetector(_tapGestureDector); _imageBox.AddGestureDetector(_longPressGestureDetector); _imageBox.AddGestureDetector(_pinchGestureDetector); dialog.AddChildLast(_imageBox); dialog.AddChildLast(_label); Sce.Pss.HighLevel.UI.Scene scene = new Sce.Pss.HighLevel.UI.Scene(); scene.RootWidget.AddChildLast(dialog); UISystem.SetScene(scene,new SlideTransition(2000.0f,FourWayDirection.Left,MoveTarget.NextScene,SlideTransitionInterpolator.Linear)); while(!quit) { _graphics.SetClearColor(255,255,255,0); _graphics.Clear(); if((GamePad.GetData(0).Buttons & GamePadButtons.Cross) == GamePadButtons.Cross) { //Reset _imageBox.SetSize(_origWidth,_origHeight); _imageBox.SetPosition(_origX,_origY); } if((GamePad.GetData(0).Buttons & GamePadButtons.Triangle) == GamePadButtons.Triangle) { quit = true; } UISystem.Update(Touch.GetData(0)); UISystem.Render(); _graphics.SwapBuffers(); } } } }

 

 

First we create our Graphics context and initialize our UISystem, then create a Panel named dialog that is going to be our active window.  We then create a label for output purposes, as well as an ImageBox that is going to contain our Jet sprite ( oh yeah… add an image to your project Smile I am reusing the Jet sprite from the last tutorial but you can use anything ).  The Image property of our ImageBox contains an ImageAsset, which we construct by simply passing it the filename of the graphic we want to use.  Next we store the original location of the _imageBox, so we can revert back to defaults later if desired.

 

The first gesture detector we are going to look at is the FlickGestureDetector.  This controls rapidly sliding your finger in one direction on the screen… think Angry birds.  The heart of the flick handling is the FlickDetected delegate, repeated here:

 

_flickGestureDetector.FlickDetected += delegate(object sender, FlickEventArgs e) { if(e.Speed.X < 0) // Left new MoveEffect(_imageBox,800f,0f,_imageBox.Y,MoveEffectInterpolator.Elastic).Start (); else new MoveEffect(_imageBox,800f,dialog.Width,_imageBox.Y,MoveEffectInterpolator.Elastic).Start (); _label.Text = "Flicked"; };

 

All we are doing here is detecting if the speed is a positive or negative value.  If it is a negative value, it means we are flicking right to left, otherwise it is left to right.  Obviously if you were interested in velocity, you would take the actual value into account.  We indicated with the line:

    _flickGestureDetector.Direction = FlickDirection.Horizontal;

that we are only interested in flicking along the horizontal axis.  Therefore any vertical flicks are going to be ignored. 

 

The direction simply determines what the Y coordinate is going to be in our MoveEffect call, either 0 ( far left ) or dialog.Width ( far right ).  MoveEffect causes the passed widget ( _imageBox ), to be moved over time (800ms in this case) to the passed coordinates.  The MoveEffectInterpolator determines how the move is going to happen, we choose Elastic which will cause it to have a bit of a spring effect.  For no effect at all, choose the Linear interpolator.  Essentially, if we flick left, we send the jet to the left side of the screen, while if we flick right, we send the jet to the right side of the screen.

 

Next up is the DragGestureDetector.  Dragging is when you tap, hold, then move the widget.  If we detect a drag, we simply want to translate our _imageBox location to the position the user dragged to.  We accomplish this with this code:

 

_dragGestureDetector = new DragGestureDetector(); _dragGestureDetector.DragDetected += delegate(object sender, DragEventArgs e) { var newPos = new Vector2(e.Source.X,e.Source.Y) + e.Distance; e.Source.SetPosition(newPos.X,newPos.Y); _label.Text = "Dragged"; };

 

As you can see, the various Gesture detectors use remarkably similar handlers.  In this case all we do is get the current position of the dragged widget ( the value in e.Source will be the widget being acted upon ) and add the distance it’s been dragged.

 

Now we add a TapGestureDetector.  In the event of a tap, we simply want to relocated the sprite back to the center of the screen.  Here is the code:

 

_tapGestureDector = new TapGestureDetector(); _tapGestureDector.TapDetected += delegate(object sender, TapEventArgs e) { e.Source.SetPosition(dialog.Width/2,dialog.Height/2); _label.Text = "Tapped"; };

 

Nothing really new there.  Again, e.Source represents the Widget object that is being tapped.  When a tap occurs we simply set it’s location to the center of the screen and log the tapped activity.

 

Next up is the LongPressGestureDetector.  A long press is a tap, followed by a hold for a given threshold of time, in our case 3000 milliseconds.  Once the long press occurs and hits the threshold, the delegate is fired.

 

_longPressGestureDetector = new LongPressGestureDetector(); _longPressGestureDetector.MinPressDuration = 3000f; _longPressGestureDetector.LongPressDetected += delegate(object sender, LongPressEventArgs e) { MessageDialog.CreateAndShow(MessageDialogStyle.Ok,"Press results", "Hey, let go of me! " + (e.ElapsedTime/1000).ToString() + " seconds elapsed!"); _label.Text = "Long pressed"; };

 

In the delegate, all we do is pop up a MessageDialog window.  There are two ways of working with MessageDialog, you can create one directly and then show it, or like we’ve done here, you can use the static CreateAndShow method.

 

Finally we have the PinchGesture Detector.  A pinch is a two finger concurrent tap, followed by either sliding your fingers closer together, or further apart.  Ultimately the value of most importance is the e.Scale, which determines if they pinched larger ( out ) or smaller ( in ) and how much.  By multiplying the e.Scale value against the widget’s current size, it will either scale larger or smaller.

 

_pinchGestureDetector.PinchDetected += delegate(object sender, PinchEventArgs e) { Vector2 newSize = new Vector2(e.Source.Width * e.Scale,e.Source.Height * e.Scale); e.Source.SetSize(newSize.X,newSize.Y); _label.Text = "Pinched"; };

 

One really confusing thing I ran into is the PinchGestureDetector’s PinchEndDetector is never fired!  Be aware of this; although truth is, you don’t really need it in the end.  As I mentioned at the beginning, there is also a DoubleTapGestureDetector, but it doesn’t work.

 

Finally, we wire all of these GestureDetectors to our ImageBox widget using this code:

_imageBox.AddGestureDetector(_flickGestureDetector); _imageBox.AddGestureDetector(_dragGestureDetector); _imageBox.AddGestureDetector(_tapGestureDector); _imageBox.AddGestureDetector(_longPressGestureDetector); _imageBox.AddGestureDetector(_pinchGestureDetector);

 

You can have multiple widgets using the same gestures, and as you can see in this example, a single widget can have multiple detectors attached.  The remaining code is all stuff we have covered in prior tutorials.

 

Here is the result in action.  Since the Simulator doesn’t support multitouch, I took a video of my Vita in action.

 

Pinching, zooming, tapping, dragging and pressing on the PlayStation Vita with the PSSDK

 

 

Once again, you can download the full project here.

Programming PSSDK PlayStation Mobile


Scroll to Top