- Home /
Question by
ryanjerskine · Jul 24, 2012 at 08:23 AM ·
touchtouchscreenswipegallerygesture
Help with Uniflow Gallery swipe
I downloaded Uniflow Gallery from the asset store and it has been pretty good other than the fact that the swipe does not work on my Elo Touchscreen. The first swipe works fine but then after the first swipe, as soon as I touch anywhere else on the screen it acts like i swiped again. It makes navigation pretty much impossible but I have heard no reply from bento-studio so I am turning to help on here. So far I'm having trouble disecting the scripts as I've only done a couple games in Unity so far. Here are and I think the problem is in one of them.
/* Bento Studio / 2012 / Uniflow / v1.1a
*
* Uniflow is an Unity clone of a well-known 3D gallery UI.
*
* UniflowGallery:
* This component creates and handles a collection of thumbnails
* animated with pre-defined transitions.
*
* v1.0
* Initial Release
* v1.1
* Added fully working zoom, handlers.
* Fixed weird zoom rotation effect (by computing shortest rotation)
* Fixed Editor Inspector bug (gallery set as dirty at every frame)
* v1.2
* Minor bug fix
* Reuploading to Unity Asset Store...
*/
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class UniflowGallery : MonoBehaviour {
///// DELEGATES /////
// Delegate called when the foreground thumbnail has changed.
public delegate void OnSelectedThumbnailUpdate( UniflowGallery a_rGallery, UniflowThumbnail a_rThumbnailPrevious, UniflowThumbnail a_rThumbnailSelected );
// Delegate called when a click occurs on the current thumbnail.
// The delegate return value specifies if the gallery should zoom the thumbnail.
// Return a_rGallery.zoomThumbnailOnClick to use the default behaviour.
// If several delegates are handled, they all must return true to make the gallery zoom.
public delegate bool OnThumbnailClickEvent( UniflowGallery a_rGallery, UniflowThumbnail a_rThumbnailClicked );
// Delegate called when a zoom-in effect on the current thumbnail starts.
public delegate void OnThumbnailZoomInEffectStart( UniflowGallery a_rGallery, UniflowThumbnail a_rThumbnailZoomedIn );
// Delegate called when a zoom-in effect on the current thumbnail ends.
public delegate void OnThumbnailZoomInEffectEnd( UniflowGallery a_rGallery, UniflowThumbnail a_rThumbnailZoomedIn );
// Delegate called when an zoom-out effect on the current thumbnail starts.
public delegate void OnThumbnailZoomOutEffectStart( UniflowGallery a_rGallery, UniflowThumbnail a_rThumbnailZoomedOut );
// Delegate called when an zoom-out effect on the current thumbnail ends.
public delegate void OnThumbnailZoomOutEffectEnd( UniflowGallery a_rGallery, UniflowThumbnail a_rThumbnailZoomedOut );
// Delegate called when a recentering event is about to start.
// The return value specifies if Uniflow should recenter from a thumbnail to another.
// If several delegates are handled, they all must return true to allow recentering.
// Return true to use the default behaviour.
public delegate bool OnRecenteringEvent( UniflowGallery a_rGallery, UniflowThumbnail a_rThumbnailFrom, UniflowThumbnail a_rThumbnailTo );
// Delegate called when the gallery performs a recentering to a thumbnail.
// The delegate return value specifies if the gallery should avoid this recentering.
// Return true to use the default behaviour
// If several delegates are handled, they all must return true to make the gallery recenter.
public delegate void OnRecenteringEffectStart( UniflowGallery a_rGallery, UniflowThumbnail a_rThumbnailFrom, UniflowThumbnail a_rThumbnailTo );
// Delegate called when the gallery has ended its recentering.
public delegate void OnRecenteringEffectEnd( UniflowGallery a_rGallery, UniflowThumbnail a_rThumbnailSelected );
///// STATIC / CONST VARS /////
// The material used on thumbnail during zoom
public static Material ms_oZoomedThumbnailMaterial;
// The path of the zoom material
public const string mc_oZoomMaterialPath = "mat_UniflowThumbnailAlwaysVisible";
public const string mc_oThumbnailPrefabPath = "prefab_UniflowThumbnail";
public const string mc_oBackgroundPrefabPath = "prefab_UniflowBackground";
public const string mc_oGizmoIconPath = "icon_Uniflow.png";
///// ENUM /////
public enum EUniflowGalleryLayout
{
Horizontal,
Vertical,
DiagonalUpLeft,
DiagonalUpRight,
JukeboxLeft,
JukeboxRight
}
///// PUBLIC VARS /////
public bool zoomThumbnailOnClick = true;
public Color ambientColor = Color.grey;
public List<Texture2D> photoList;
// Left
[HideInInspector]
public Vector3 leftFlippingPosition;
[HideInInspector]
public Vector3 leftFlippingRotation;
[HideInInspector]
public float leftFlippingScale;
// Centered
[HideInInspector]
public Vector3 centeredFlippingPosition;
[HideInInspector]
public Vector3 centeredFlippingRotation;
[HideInInspector]
public float centeredFlippingScale;
// Right
[HideInInspector]
public Vector3 rightFlippingPosition;
[HideInInspector]
public Vector3 rightFlippingRotation;
[HideInInspector]
public float rightFlippingScale;
///
///// PUBLIC SETTERS/GETTERS /////
public int selectedThumbnailAtStart
{
set
{
int iPhotoCount = photoList.Count;
if( iPhotoCount > 0 )
{
iPhotoCount = iPhotoCount - 1;
}
m_iSelectedThumbnailAtStart = Mathf.Clamp( value, 0, iPhotoCount );
}
get
{
return m_iSelectedThumbnailAtStart;
}
}
public int selectedThumbnail
{
get
{
return m_iSelectedThumbnailIndex;
}
set
{
if( m_bCanScroll == true )
{
// Computes the new gallery position according to the thumbnail index
int iIndexToGo = Mathf.Clamp( value, 0, m_iThumbnailCount - 1 );
// Recenters gallery to selected thumbnail
StartRecentering( iIndexToGo );
}
}
}
public float thumbnailRatio
{
set
{
m_fThumbnailRatio = Mathf.Clamp( value, float.Epsilon, float.MaxValue );
}
get
{
return m_fThumbnailRatio;
}
}
public float thumbnailSpacing
{
set
{
m_fThumbnailSpacing = Mathf.Clamp( value, float.Epsilon, float.PositiveInfinity );
}
get
{
return m_fThumbnailSpacing;
}
}
public float planeColliderSize
{
get
{
return m_fPlaneColliderHalfSize * 2.0f;
}
set
{
m_fPlaneColliderHalfSize = Mathf.Clamp( value * 0.5f, float.Epsilon, float.PositiveInfinity );
}
}
public EUniflowGalleryLayout galleryLayout
{
get
{
return m_eGalleryLayout;
}
set
{
///// Flipping reset /////
// Position offsets
leftFlippingPosition = Vector3.zero;
centeredFlippingPosition = Vector3.zero;
rightFlippingPosition = Vector3.zero;
// Rotation offsets
leftFlippingRotation = Vector3.zero;
centeredFlippingRotation = Vector3.zero;
rightFlippingRotation = Vector3.zero;
// Scale factors
leftFlippingScale = 0.0f;
centeredFlippingScale = 0.0f;
rightFlippingScale = 0.0f;
switch( value )
{
case EUniflowGalleryLayout.Horizontal:
{
// Left
leftFlippingPosition.x = -0.75f;
leftFlippingRotation.y = -80.0f;
// Center
centeredFlippingPosition.z = -0.5f;
// Right
rightFlippingPosition.x = 0.75f;
rightFlippingRotation.y = 80.0f;
}
break;
case EUniflowGalleryLayout.Vertical:
{
// Left
leftFlippingPosition.x = -0.75f;
leftFlippingRotation.y = -80.0f;
leftFlippingRotation.z = -90.0f;
// Center
centeredFlippingPosition.z = -0.5f;
centeredFlippingRotation.z = -90.0f;
// Right
rightFlippingPosition.x = 0.75f;
rightFlippingRotation.y = 80.0f;
rightFlippingRotation.z = -90.0f;
}
break;
case EUniflowGalleryLayout.DiagonalUpLeft:
{
// Left
leftFlippingPosition.x = -0.75f;
leftFlippingRotation.y = -80.0f;
// Center
centeredFlippingPosition.z = -0.5f;
centeredFlippingRotation.z = -45.0f;
// Right
rightFlippingPosition.x = 0.75f;
rightFlippingRotation.y = 80.0f;
}
break;
case EUniflowGalleryLayout.DiagonalUpRight:
{
// Left
leftFlippingPosition.x = -0.75f;
leftFlippingRotation.y = -80.0f;
// Center
centeredFlippingPosition.z = -0.5f;
centeredFlippingRotation.z = 45.0f;
// Right
rightFlippingPosition.x = 0.75f;
rightFlippingRotation.y = 80.0f;
}
break;
case EUniflowGalleryLayout.JukeboxLeft:
{
// Left
leftFlippingPosition.x = -0.75f;
leftFlippingRotation.y = -90.0f;
leftFlippingRotation.z = -270.0f;
// Center
centeredFlippingPosition.z = 1.5f;
centeredFlippingRotation.y = -90.0f;
// Right
rightFlippingPosition.x = 0.75f;
rightFlippingRotation.y = -90.0f;
rightFlippingRotation.z = -270.0f;
}
break;
case EUniflowGalleryLayout.JukeboxRight:
{
// Left
leftFlippingPosition.x = -0.75f;
leftFlippingRotation.y = -90.0f;
leftFlippingRotation.z = -270.0f;
// Center
centeredFlippingPosition.z = -1.5f;
centeredFlippingRotation.y = -90.0f;
// Right
rightFlippingPosition.x = 0.75f;
rightFlippingRotation.y = -90.0f;
rightFlippingRotation.z = -270.0f;
}
break;
}
m_eGalleryLayout = value;
}
}
public OnSelectedThumbnailUpdate onSelectedThumbnailUpdateHandler
{
get
{
return m_dOnSelectedThumbUpdateHandler;
}
set
{
m_dOnSelectedThumbUpdateHandler = value;
}
}
public OnThumbnailClickEvent onThumbnailClickEventHandler
{
get
{
return m_dOnThumbClickEventHandler;
}
set
{
m_dOnThumbClickEventHandler = value;
}
}
public OnThumbnailZoomInEffectStart onThumbnailZoomInEffectStartHandler
{
get
{
return m_dOnThumbZoomInEffectStartHandler;
}
set
{
m_dOnThumbZoomInEffectStartHandler = value;
}
}
public OnThumbnailZoomInEffectEnd onThumbnailZoomInEffectEndHandler
{
get
{
return m_dOnThumbZoomInEffectEndHandler;
}
set
{
m_dOnThumbZoomInEffectEndHandler = value;
}
}
public OnThumbnailZoomOutEffectStart onThumbnailZoomOutEffectStartHandler
{
get
{
return m_dOnThumbZoomOutEffectStartHandler;
}
set
{
m_dOnThumbZoomOutEffectStartHandler = value;
}
}
public OnThumbnailZoomOutEffectEnd onThumbnailZoomOutEffectEndHandler
{
get
{
return m_dOnThumbZoomOutEffectEndHandler;
}
set
{
m_dOnThumbZoomOutEffectEndHandler = value;
}
}
public OnRecenteringEvent onRecenteringEventHandler
{
get
{
return m_dOnRecenteringEventHandler;
}
set
{
m_dOnRecenteringEventHandler = value;
}
}
public OnRecenteringEffectStart onRecenteringEffectStartHandler
{
get
{
return m_dOnRecenteringEffectStartHandler;
}
set
{
m_dOnRecenteringEffectStartHandler = value;
}
}
public OnRecenteringEffectEnd onRecenteringEffectEndHandler
{
get
{
return m_dOnRecenteringEffectEndHandler;
}
set
{
m_dOnRecenteringEffectEndHandler = value;
}
}
public bool isZoomed
{
get
{
return m_bZoomMode;
}
}
public bool isScrolling
{
get
{
return m_bIsUserScrolling;
}
}
public float flippingDuration
{
get
{
return m_fFlippingDuration;
}
}
public float zoomingDuration
{
get
{
return m_fZoomingDuration;
}
}
///// PRIVATE VARS /////
[HideInInspector]
[SerializeField]
private float m_fPlaneColliderHalfSize = 1.5f;
[HideInInspector]
[SerializeField]
private float m_fThumbnailRatio = 1.0f;
[HideInInspector]
[SerializeField]
private int m_iSelectedThumbnailAtStart = 0;
[HideInInspector]
[SerializeField]
private int m_iSelectedThumbnailIndex = 0;
[HideInInspector]
[SerializeField]
private EUniflowGalleryLayout m_eGalleryLayout = EUniflowGalleryLayout.Horizontal;
// Scrolling settings
private float m_fScrollingThreshold = 7.0f;
private float m_fMinDistanceToSwipe = 175.0f;
private float m_fSwipeLowPassFilter = 10.0f;
// Thumbnail settings
[HideInInspector]
[SerializeField]
private float m_fThumbnailSpacing = 0.35f;
/// Animation stuff
// Time to recenter gallery to selected thumbnail. Constant.
private float m_fRecenteringDuration = 0.25f;
// Flipping animation duration
private float m_fFlippingDuration = 0.45f;
private float m_fZoomingDuration = 0.3f;
/// Handlers
private OnSelectedThumbnailUpdate m_dOnSelectedThumbUpdateHandler;
private OnThumbnailClickEvent m_dOnThumbClickEventHandler;
private OnThumbnailZoomInEffectStart m_dOnThumbZoomInEffectStartHandler;
private OnThumbnailZoomInEffectEnd m_dOnThumbZoomInEffectEndHandler;
private OnThumbnailZoomOutEffectStart m_dOnThumbZoomOutEffectStartHandler;
private OnThumbnailZoomOutEffectEnd m_dOnThumbZoomOutEffectEndHandler;
private OnRecenteringEvent m_dOnRecenteringEventHandler;
private OnRecenteringEffectStart m_dOnRecenteringEffectStartHandler;
private OnRecenteringEffectEnd m_dOnRecenteringEffectEndHandler;
// The thumbnail components to display and manage
private List<UniflowThumbnail> m_rThumbnails;
private int m_iThumbnailCount;
// UI Effect component which will recenter gallery on selected thumbnail
private UIEffectTransformRelativeCoords m_rUIEffectRecentring;
// Base position is the origin position of the gallery:
// no scrolling, first thumbnail selected
private Vector3 m_f3BasePosition;
// The scrolling offset is added to base position in order to
// make gallery scrolling
private float m_fScrollingOffset = 0.0f;
///// Gallery state /////
// Set to true when the gallery needs to be recentred on selected thumbnail
private bool m_bIsRecenteringPending = false;
private bool m_bZoomMode = false;
private bool m_bCanScroll = true;
///// Input state /////
// Set to true when the user makes the gallery scrolling (by mouse/touch input)
private bool m_bIsUserScrolling = false;
private bool m_bIsUserSwipePending = false;
private bool m_bUserScrolledEnough = false;
private bool m_bUserInput = false;
private int m_iIndexScrollingStartedOn;
private float m_fSwipeMovement = 0.0f;
private float m_fSwipeScrollingFactor = 0.2f;
private float m_fMaxScrollingThresholdToNextThumbnail;
private Vector3 m_f3FirstInputPosition;
private Vector3 m_f3PreviousInputPosition;
///// Gallery coords saves /////
private Transform m_rCachedTransform;
private float m_fCachedScaledRightMagnitude;
private float m_fSavedThumbnailSpacing;
private Vector3 m_f3SavedLocalBasePosition;
private Vector3 m_f3ZoomModeWorldPosition;
private Quaternion m_oSavedLocalRotation;
private Quaternion m_oZoomModeWorldRotation;
// Prefab references
private GameObject m_rGalleryBackground;
private GameObject m_rThumbnailPrefab;
private GameObject m_rGalleryBackgroundPrefab;
private Vector3 localRight
{
get
{
if( m_rCachedTransform.parent != null )
{
return m_rCachedTransform.parent.InverseTransformDirection( m_rCachedTransform.right ).normalized;
}
else
{
return m_rCachedTransform.right;
}
}
}
public void Awake( )
{
if( ms_oZoomedThumbnailMaterial == null )
{
ms_oZoomedThumbnailMaterial = Resources.Load( mc_oZoomMaterialPath, typeof( Material ) ) as Material;
}
m_rCachedTransform = transform;
m_f3BasePosition = m_rCachedTransform.localPosition;
m_fCachedScaledRightMagnitude = Vector3.Scale( m_rCachedTransform.localScale, Vector3.right ).magnitude;
// Recentering component initialisation
m_rUIEffectRecentring = gameObject.AddComponent<UIEffectTransformRelativeCoords>( ) as UIEffectTransformRelativeCoords;
m_rUIEffectRecentring.Init( );
// Creates a delegate which warns gallery when recentering has finished
m_rUIEffectRecentring.effectEndedDelegate += new UIEffectTemplate.EffectEndedDelegate( this.EndOfRecenteringEffect );
// Load thumbnail prefab
m_rThumbnailPrefab = Resources.Load( mc_oThumbnailPrefabPath, typeof( GameObject ) ) as GameObject;
// Thumbnails creation
m_iThumbnailCount = photoList.Count;
m_rThumbnails = new List<UniflowThumbnail>( );
// Commented due to Flash Export incompatibility
//m_rThumbnails.Capacity = m_iThumbnailCount;
// Adds thumbnails
for( int iPhotoIndex = 0; iPhotoIndex < m_iThumbnailCount; ++iPhotoIndex )
{
AddThumbnailToGallery( m_rThumbnailPrefab, iPhotoIndex );
}
// Gallery background Initialization
m_rGalleryBackgroundPrefab = Resources.Load( mc_oBackgroundPrefabPath, typeof( GameObject ) ) as GameObject;
m_rGalleryBackground = Instantiate( m_rGalleryBackgroundPrefab, Vector3.zero, m_rGalleryBackgroundPrefab.transform.localRotation ) as GameObject;
UniflowZoomBackground rZoomBackgroundComponent = m_rGalleryBackground.GetComponent<UniflowZoomBackground>( ) as UniflowZoomBackground;
rZoomBackgroundComponent.Init( this );
m_rGalleryBackground.active = false;
// Maximum distance the user have to scroll
m_fMaxScrollingThresholdToNextThumbnail = m_rThumbnailPrefab.renderer.bounds.size.x;
}
// Sets initial state of the gallery, e.g. sets thumbnails transform
public virtual void Start( )
{
m_f3PreviousInputPosition = Input.mousePosition;
m_iSelectedThumbnailIndex = m_iSelectedThumbnailAtStart;
// Adjusts gallery position to the selected thumbnail
m_fScrollingOffset = ThumbnailIndex2ScrollingOffset( m_iSelectedThumbnailIndex );
// Animates/sets thumbnails before selected thumbnail
UpdateUnselectedThumbnails( 0,
m_iSelectedThumbnailIndex - 1,
UniflowThumbnail.EThumbnailFlippingAnimation.Left,
true );
// Animates/sets thumbnails after selected thumbnail
UpdateUnselectedThumbnails( m_iSelectedThumbnailIndex + 1,
m_iThumbnailCount - 1,
UniflowThumbnail.EThumbnailFlippingAnimation.Right,
true );
// Animates/sets selected thumbnail
UpdateSelectedThumb( m_iSelectedThumbnailIndex, true );
m_rCachedTransform.localPosition = CurrentGalleryLocalPosition( );
}
// Gallery update is performed AFTER thumbnails updates
void LateUpdate ()
{
Vector3 f3InputPosition = Vector3.zero;
Vector3 f3InputMovement = Vector3.zero;
// Computes the scrolling offset according to the platform inputs
switch( Application.platform )
{
// Consoles
case RuntimePlatform.WiiPlayer:
case RuntimePlatform.XBOX360:
case RuntimePlatform.PS3:
{
Debug.LogWarning( "/!\\ !!! Uniflow Gallery: consoles are not supported !!! /!\\" );
}
break;
// Tactil smartphones / tablets => touchscreen
case RuntimePlatform.IPhonePlayer:
case RuntimePlatform.Android:
{
if( Input.touchCount > 0 )
{
Touch oFirstTouch = Input.touches[ 0 ];
if( m_bUserInput == false )
{
m_f3PreviousInputPosition.x = oFirstTouch.position.x;
m_f3PreviousInputPosition.y = oFirstTouch.position.y;
m_f3PreviousInputPosition.z = 0.0f;
m_f3FirstInputPosition = m_f3PreviousInputPosition;
}
m_bUserInput = true;
f3InputPosition.x = oFirstTouch.position.x;
f3InputPosition.y = oFirstTouch.position.y;
f3InputMovement = f3InputPosition - m_f3PreviousInputPosition;
m_f3PreviousInputPosition = f3InputPosition;
}
else
{
m_bUserInput = false;
}
}
break;
// PC / Mac => mouse
default:
{
if( Input.GetMouseButton( 0 ) )
{
if( m_bUserInput == false )
{
m_f3FirstInputPosition = Input.mousePosition;
}
m_bUserInput = true;
f3InputPosition = Input.mousePosition;
f3InputMovement = f3InputPosition - m_f3PreviousInputPosition;
}
else
{
m_bUserInput = false;
}
m_f3PreviousInputPosition = Input.mousePosition;
}
break;
}
float fScrollingMovement = ManageInputScrolling( f3InputPosition, f3InputMovement, m_bUserInput );
ScrollGallery( fScrollingMovement );
UpdateGallery( );
}
// Instantiates the given prefab as a thumbnail
public GameObject AddThumbnailToGallery( GameObject a_rThumbnailPrefab, int a_iIndex )
{
// Prefab instancing
GameObject rThumbnailGameObject = Instantiate( a_rThumbnailPrefab, Vector3.zero, Quaternion.identity ) as GameObject;
// Retrieves Thumbnail component in the prefab, if any, creates it otherwise
UniflowThumbnail rThumbnailComponent = rThumbnailGameObject.GetComponent<UniflowThumbnail>( );
if( rThumbnailComponent == null )
{
rThumbnailComponent = rThumbnailGameObject.AddComponent<UniflowThumbnail>( );
}
///// Sets transform properties. Parent and scaling are set first. /////
rThumbnailGameObject.transform.parent = m_rCachedTransform;
// Scale thumbnail according to specified ratio
Vector3 f3ScaleRatio = new Vector3( m_fThumbnailRatio, 1.0f, 1.0f );
rThumbnailGameObject.transform.localScale = Vector3.Scale( f3ScaleRatio, a_rThumbnailPrefab.transform.localScale );
// Thumbnail placement in gallery, according to its index
rThumbnailGameObject.transform.localPosition = ThumbnailLocalPositionFromIndex( a_iIndex );
rThumbnailGameObject.transform.localRotation = a_rThumbnailPrefab.transform.rotation;
// Clones the thumbnail material used in zoom mode
Material rZoomedThumbnailMaterial = Instantiate( ms_oZoomedThumbnailMaterial ) as Material;
rZoomedThumbnailMaterial.mainTexture = photoList[ a_iIndex ];
// Sets photo texture to thumbnail material
rThumbnailGameObject.renderer.material.mainTexture = photoList[ a_iIndex ];
// Inits thumbnail component
rThumbnailComponent.Init( this, a_iIndex, rZoomedThumbnailMaterial );
// Finally, adds it to the gallery!
m_rThumbnails.Add( rThumbnailComponent );
// Desactivate thumbnail if gallery inactive or disabled (in order to follow Unity guidelines)
if( enabled == false || gameObject.active == false )
{
rThumbnailGameObject.SetActiveRecursively( false );
}
return rThumbnailGameObject;
}
// Flips thumbnails in index range [ start ... end ] and sets them as "unselected"
private void UpdateUnselectedThumbnails( int a_iStartIndex,
int a_iEndIndex,
UniflowThumbnail.EThumbnailFlippingAnimation a_eThumbnailAnimation,
bool a_bForceEndOfAnimation )
{
UniflowThumbnail rThumbComponent;
for( int iThumbnailIndex = a_iStartIndex; iThumbnailIndex <= a_iEndIndex; ++iThumbnailIndex )
{
rThumbComponent = m_rThumbnails[ iThumbnailIndex ];
rThumbComponent.Flip( a_eThumbnailAnimation, a_bForceEndOfAnimation );
rThumbComponent.selected = false;
}
}
// Flips given thumbnail and sets it as "selected"
private void UpdateSelectedThumb( int a_iThumbIndex, bool a_bForceEndOfAnimation )
{
UniflowThumbnail rThumbComponent = m_rThumbnails[ a_iThumbIndex ];
rThumbComponent.Flip( UniflowThumbnail.EThumbnailFlippingAnimation.Centered, a_bForceEndOfAnimation );
rThumbComponent.selected = true;
}
// Computes 1:1 scrolling (even in zoom mode)
// Sets m_bIsScrolling value accordingly
private float ManageInputScrolling( Vector3 a_f3RawInputPosition, Vector3 a_f3RawInputMovement, bool a_bUserInput )
{
float fScrollingMovement = 0.0f;
m_bIsUserScrolling = false;
// Any user interaction?
if( a_bUserInput == true )
{
Camera rMainCamera = Camera.mainCamera;
Vector3 f3PreviousRawInputPosition = a_f3RawInputPosition - a_f3RawInputMovement;
// Screen -> World rays
Ray oPreviousRawInputRay = rMainCamera.ScreenPointToRay( f3PreviousRawInputPosition );
Ray oRawInputRay = rMainCamera.ScreenPointToRay( a_f3RawInputPosition );
// Plane computation
Vector3 f3CameraToGalleryWorldVector = m_rCachedTransform.position - rMainCamera.transform.position;
Vector3 f3WorldDownToGallery = Vector3.Cross( m_rCachedTransform.right, f3CameraToGalleryWorldVector );
Vector3 f3WorldNormalPlane = Vector3.Cross( m_rCachedTransform.right, f3WorldDownToGallery );
Plane oScrollPlane = new Plane( f3WorldNormalPlane.normalized, m_rCachedTransform.position );
// Performs 2 raycasts from input position against computed gallery plane collider
float fPreviousRawInputDistance;
float fRawInputDistance;
// Performs 2 raycasts from input positions to gallery box collider
if( oScrollPlane.Raycast( oPreviousRawInputRay, out fPreviousRawInputDistance ) == true &&
oScrollPlane.Raycast( oRawInputRay, out fRawInputDistance ) == true )
{
// Adds movement to cumulated scrolling
// This mecanism defines a dead/tolerance zone around user input
// to prevent little unwanted scrollings (when clicking, typically)
if( m_bUserScrolledEnough == false )
{
m_bUserScrolledEnough = Vector3.Distance( m_f3FirstInputPosition, a_f3RawInputPosition ) >= m_fScrollingThreshold;
m_iIndexScrollingStartedOn = m_iSelectedThumbnailIndex;
}
// Computes hit points from ray origins + ray direction * distance from plane ( p = o + dt )
Vector3 f3PreviousInputHitPoint = oPreviousRawInputRay.origin + oPreviousRawInputRay.direction * fPreviousRawInputDistance;
Vector3 f3InputHitPoint = oRawInputRay.origin + oRawInputRay.direction * fRawInputDistance;
// Projects
Vector3 f3InputHitPointToBasePositionVector = f3InputHitPoint - m_rCachedTransform.position;
Vector3 f3InputHitPointProjectedOnGalleryRail = m_rCachedTransform.position + Vector3.Project( f3InputHitPointToBasePositionVector, m_rCachedTransform.right );
float fHitPointGalleryRailDistance = Vector3.Distance( f3InputHitPointProjectedOnGalleryRail, f3InputHitPoint );
if( fHitPointGalleryRailDistance <= m_fPlaneColliderHalfSize )
{
// World scrolling vector
Vector3 f3WorldScrollingMovement = f3InputHitPoint - f3PreviousInputHitPoint;
// The final scrolling value is computed with the dot product
// between the scrolling vector and the local right gallery unitary vector
fScrollingMovement = Vector3.Dot( f3WorldScrollingMovement, m_rCachedTransform.right );
// True if scrolling movement is above threshold
m_bIsUserScrolling = m_bUserScrolledEnough;
// SWIPE
float fRawSwipeMovement = a_f3RawInputMovement.magnitude / Time.deltaTime;
if( fRawSwipeMovement >= m_fMinDistanceToSwipe )
{
m_bIsUserSwipePending = true;
m_fSwipeMovement = fScrollingMovement / Time.deltaTime;
}
else if( fRawSwipeMovement >= m_fSwipeLowPassFilter ) // Low Pass filter
{
m_bIsUserSwipePending = false;
}
}
}
}
else
{
// Resets cumulated scrolling
m_bUserScrolledEnough = false;
}
return fScrollingMovement;
}
// Performs gallery scrolling
// float a_fScrollingMovement: represent gallery displacement (factor of .right unitary vector)
public void ScrollGallery( float a_fScrollingMovement )
{
if( m_bCanScroll == true )
{
if( m_bIsUserScrolling == true )
{
// Stops any recentering
if( m_rUIEffectRecentring.isPlaying == true )
{
StopRecentering( );
}
// Adds user scrolling to current scrolling offset
m_fScrollingOffset += a_fScrollingMovement;
if( m_bZoomMode == true )
{
m_fScrollingOffset = Mathf.Clamp( m_fScrollingOffset, ThumbnailIndex2ScrollingOffset( m_iThumbnailCount - 1 ), 0.0f );
}
Vector3 f3CurrentLocalPosition = CurrentGalleryLocalPosition( );
Vector3 f3CurrentScrollingOffsetVector = f3CurrentLocalPosition - m_f3BasePosition;
// Sets new gallery position
m_rCachedTransform.localPosition = f3CurrentLocalPosition;
// Sets the new position where to start recentring from
// (kind of hack, see finalPosition setter)
m_rUIEffectRecentring.finalPositionOffset = f3CurrentScrollingOffsetVector;
m_bIsRecenteringPending = true;
}
else if( m_bIsRecenteringPending == true || m_bIsUserSwipePending == true )
{
// Start recentering to selected thumbnail
int iThumbnailIndexToRecenterTo = m_iSelectedThumbnailIndex;
if( m_bIsUserSwipePending == true )
{
if( m_bZoomMode == true )
{
float fRecenteringDuration = m_fRecenteringDuration;
float fCurrentScrolling = CurrentScrolling( );
float fScrollingDifference = ThumbnailIndex2ScrollingOffset( iThumbnailIndexToRecenterTo ) - fCurrentScrolling;
int iScrollingDifferenceSign = (int) Mathf.Sign( fScrollingDifference );
int iSwipeMovementSign = (int) Mathf.Sign( m_fSwipeMovement );
if( fScrollingDifference == 0.0f || iScrollingDifferenceSign != iSwipeMovementSign )
{
iThumbnailIndexToRecenterTo = iThumbnailIndexToRecenterTo - iSwipeMovementSign;
iThumbnailIndexToRecenterTo = Mathf.Clamp( iThumbnailIndexToRecenterTo, 0, m_iThumbnailCount - 1 );
float fDistanceToThumbnail = ThumbnailIndex2ScrollingOffset( iThumbnailIndexToRecenterTo ) - fCurrentScrolling;
if( fDistanceToThumbnail != 0.0f )
{
float fRecenteringWithSwipeMovementDuration = Mathf.Abs( fDistanceToThumbnail / m_fSwipeMovement );
fRecenteringDuration = Mathf.Min( fRecenteringWithSwipeMovementDuration, fRecenteringDuration );
}
}
StartRecentering( iThumbnailIndexToRecenterTo, fRecenteringDuration, gkInterpolate.EaseType.EaseOutSine );
}
else
{
// Simulates inertia
float fSwippedScrollingDistance = m_fSwipeMovement * m_fRecenteringDuration * m_fSwipeScrollingFactor;
float fSwippedScrollingOffset = CurrentScrolling( ) + fSwippedScrollingDistance;
iThumbnailIndexToRecenterTo = ScrollingOffset2ThumbnailIndex( fSwippedScrollingOffset );
StartRecentering( iThumbnailIndexToRecenterTo );
}
m_bIsUserSwipePending = false;
m_fSwipeMovement = 0.0f;
}
else
{
// Computing gap between two thumbnails.
float fScrollingThresholdToNextThumbnail = m_fCachedScaledRightMagnitude * m_fThumbnailSpacing;
float fCurrentScrolling = CurrentScrolling( );
float fScrollingDifference = ThumbnailIndex2ScrollingOffset( m_iSelectedThumbnailIndex ) - fCurrentScrolling;
int iScrollingDifferenceSign = (int) Mathf.Sign( fScrollingDifference );
int iIndexDifference = m_iSelectedThumbnailIndex - m_iIndexScrollingStartedOn;
int iIndexDifferenceSign = (int) Mathf.Sign( iIndexDifference );
if( fScrollingThresholdToNextThumbnail > m_fMaxScrollingThresholdToNextThumbnail )
{
fScrollingThresholdToNextThumbnail = m_fMaxScrollingThresholdToNextThumbnail;
}
// The distance the user have to scroll to the next thumbnail is the half of the gap
fScrollingThresholdToNextThumbnail = fScrollingThresholdToNextThumbnail * 0.5f;
if( fScrollingDifference != 0 && Mathf.Abs( fScrollingDifference ) >= fScrollingThresholdToNextThumbnail )
{
if( iIndexDifference == 0 || iScrollingDifferenceSign == iIndexDifferenceSign )
{
iThumbnailIndexToRecenterTo = iThumbnailIndexToRecenterTo + iScrollingDifferenceSign;
iThumbnailIndexToRecenterTo = Mathf.Clamp( iThumbnailIndexToRecenterTo, 0, m_iThumbnailCount - 1 );
}
}
StartRecentering( iThumbnailIndexToRecenterTo );
}
}
}
}
private void UpdateGallery( )
{
int iPreviousSelectedThumbnailIndex = m_iSelectedThumbnailIndex;
float fCurrentScrolling = CurrentScrolling( );
// Computes selected thumbnail index from current scrolling
m_iSelectedThumbnailIndex = ScrollingOffset2ThumbnailIndex( fCurrentScrolling );
// Animates thumbnails if needed
// Must consider the direction where the gallery is moving and if several thumbnails
// may be animated simultaneously in case of the new selected thumbnail is too far away from the previous one
if( m_iSelectedThumbnailIndex != iPreviousSelectedThumbnailIndex )
{
UpdateSelectedThumb( m_iSelectedThumbnailIndex, false );
if( iPreviousSelectedThumbnailIndex < m_iSelectedThumbnailIndex )
{
UpdateUnselectedThumbnails( iPreviousSelectedThumbnailIndex,
m_iSelectedThumbnailIndex - 1,
UniflowThumbnail.EThumbnailFlippingAnimation.Left,
false );
}
else
{
UpdateUnselectedThumbnails( m_iSelectedThumbnailIndex + 1,
iPreviousSelectedThumbnailIndex,
UniflowThumbnail.EThumbnailFlippingAnimation.Right,
false );
}
// Warns that the selected thumbnail has been updated
if( m_dOnSelectedThumbUpdateHandler != null )
{
m_dOnSelectedThumbUpdateHandler( this, m_rThumbnails[ iPreviousSelectedThumbnailIndex ], m_rThumbnails[ m_iSelectedThumbnailIndex ] );
}
}
}
/////////////// ZOOM ///////////////
// Called when the user is zooming on a thumbnail
public void SetupThumbnailZoom( )
{
bool bShouldZoom = false;
if( m_bIsUserScrolling == false && m_rUIEffectRecentring.isPlaying == false && m_bUserScrolledEnough == false )
{
// Avoids calling OnThumbnailClickedEvent handlers for nothing
bShouldZoom = ShouldZoom( );
}
if( bShouldZoom == true )
{
if( m_rUIEffectRecentring.isPlaying == true )
{
StopRecentering( );
}
m_bIsUserSwipePending = false;
UniflowThumbnail rSelectedThumbnailComponent = m_rThumbnails[ m_iSelectedThumbnailIndex ];
// Enters zoom mode
if( m_bZoomMode == false )
{
// Enables zoom mode
m_bZoomMode = true;
// Disables scrolling during zoom effect
m_bCanScroll = false;
// Enables background
UniflowZoomBackground rZoomBackground = m_rGalleryBackground.GetComponent<UniflowZoomBackground>( ) as UniflowZoomBackground;
rZoomBackground.FadeIn( );
// Computes thumbnail position in front of camera
Camera rMainCamera = Camera.mainCamera;
float fScaledThumbnailHeight = m_rThumbnailPrefab.renderer.bounds.extents.y * m_rCachedTransform.localScale.y;
float fScaledThumbnailWidth = m_rThumbnailPrefab.renderer.bounds.extents.x * m_fThumbnailRatio * m_rCachedTransform.localScale.x;
float fDistanceFromCamera;
// Computes distance = height / tan (FOV/2)
// according to dominant component (width or height)
if( rMainCamera.aspect <= m_fThumbnailRatio * m_rCachedTransform.localScale.x )
{
// Width case
fDistanceFromCamera = UniflowUtils.DistanceToCameraFromFrustumWidth( rMainCamera, fScaledThumbnailWidth );
}
else
{
// Height case
fDistanceFromCamera = UniflowUtils.DistanceToCameraFromFrustumHeight( rMainCamera, fScaledThumbnailHeight );
}
// The world position
m_f3ZoomModeWorldPosition = rMainCamera.transform.position + rMainCamera.transform.forward * fDistanceFromCamera;
// Set rotation as facing main camera (i.e. same rotation + 180deg.)
m_oZoomModeWorldRotation = Quaternion.AngleAxis( 180.0f, rMainCamera.transform.up ) * rMainCamera.transform.rotation;
// Thumbnail zoom
rSelectedThumbnailComponent.ZoomIn( m_f3ZoomModeWorldPosition, m_oZoomModeWorldRotation );
if( m_dOnThumbZoomInEffectStartHandler != null )
{
m_dOnThumbZoomInEffectStartHandler( this, rSelectedThumbnailComponent );
}
}
else
{
// Disables zoom mode
m_bZoomMode = false;
// Disables scrolling (to avoid unwanted scrolling during zoom-out effect)
m_bCanScroll = false;
// Restores gallery settings (position, scrolling, spacing)
m_f3BasePosition = m_f3SavedLocalBasePosition;
m_fThumbnailSpacing = m_fSavedThumbnailSpacing;
m_fScrollingOffset = ThumbnailIndex2ScrollingOffset( m_iSelectedThumbnailIndex );
// Hides gallery background
UniflowZoomBackground rZoomBackground = m_rGalleryBackground.GetComponent<UniflowZoomBackground>( ) as UniflowZoomBackground;
rZoomBackground.FadeOut( );
// Update thumbnails
for( int iThumbnailIndex = 0; iThumbnailIndex < m_iThumbnailCount; ++iThumbnailIndex )
{
UniflowThumbnail rThumbnailComponent = m_rThumbnails[ iThumbnailIndex ];
// Repositions thumbnail
rThumbnailComponent.Replace( ThumbnailLocalPositionFromIndex( iThumbnailIndex ) );
// Disables zoomed state
rThumbnailComponent.isZoomed = false;
}
// Animates/sets thumbnails before selected thumbnail
UpdateUnselectedThumbnails( 0,
m_iSelectedThumbnailIndex - 1,
UniflowThumbnail.EThumbnailFlippingAnimation.Left,
true );
// Animates/sets thumbnails after selected thumbnail
UpdateUnselectedThumbnails( m_iSelectedThumbnailIndex + 1,
m_iThumbnailCount - 1,
UniflowThumbnail.EThumbnailFlippingAnimation.Right,
true );
// Animates/sets selected thumbnail
UpdateSelectedThumb( m_iSelectedThumbnailIndex, true );
// Repositions gallery
m_rCachedTransform.localRotation = m_oSavedLocalRotation;
m_rCachedTransform.localPosition = CurrentGalleryLocalPosition( );
//
m_rUIEffectRecentring.startPosition = m_f3BasePosition;
m_rUIEffectRecentring.startRotation = m_rCachedTransform.localRotation;
m_rUIEffectRecentring.finalPositionOffset = m_fScrollingOffset * this.localRight;
// Zooms out selected thumbnail
rSelectedThumbnailComponent.ZoomOut( m_f3ZoomModeWorldPosition, m_oZoomModeWorldRotation );
if( m_dOnThumbZoomOutEffectStartHandler != null )
{
m_dOnThumbZoomOutEffectStartHandler( this, rSelectedThumbnailComponent );
}
}
}
}
public void PostZoomInSetup( )
{
if( m_bZoomMode == true )
{
Camera rMainCamera = Camera.mainCamera;
UniflowThumbnail rSelectedThumbnailComponent = m_rThumbnails[ m_iSelectedThumbnailIndex ];
Transform rThumbnailTransform = rSelectedThumbnailComponent.transform;
rThumbnailTransform.parent = null;
// Saves previous base position/rotation
m_f3SavedLocalBasePosition = m_f3BasePosition;
m_oSavedLocalRotation = m_rCachedTransform.localRotation;
Vector3 f3ZoomVector = m_f3ZoomModeWorldPosition - ThumbnailWorldPositionFromIndex( m_iSelectedThumbnailIndex );
if( m_rCachedTransform.parent != null )
{
m_f3BasePosition += m_rCachedTransform.parent.InverseTransformDirection( f3ZoomVector );
}
else
{
// Both in world coords => just add
m_f3BasePosition += f3ZoomVector;
}
m_rCachedTransform.localRotation = Quaternion.AngleAxis( 180.0f, rThumbnailTransform.up ) * rThumbnailTransform.localRotation;
m_rCachedTransform.localPosition = CurrentGalleryLocalPosition( );
rThumbnailTransform.parent = m_rCachedTransform;
// Saves current spacing
m_fSavedThumbnailSpacing = m_fThumbnailSpacing;
if( rMainCamera.aspect <= m_fThumbnailRatio * m_rCachedTransform.localScale.x )
{
// Wider than screen
float fScaledThumbnailWidth = m_rThumbnailPrefab.renderer.bounds.extents.x * m_fThumbnailRatio;
m_fThumbnailSpacing = 2.0f * fScaledThumbnailWidth;
}
else
{
// Taller than screen
// Need to compute screen width in world coord.
float fTanHorizontalFOV = Mathf.Tan( UniflowUtils.HorizontalFOV( rMainCamera ) * 0.5f );
float fScaledThumbnailHeight = m_rThumbnailPrefab.renderer.bounds.extents.y * m_rCachedTransform.localScale.y;
float fDistance = UniflowUtils.DistanceToCameraFromFrustumHeight( rMainCamera, fScaledThumbnailHeight );
m_fThumbnailSpacing = 2.0f * ( ( fTanHorizontalFOV * fDistance ) / m_fCachedScaledRightMagnitude );
}
m_fScrollingOffset = ThumbnailIndex2ScrollingOffset( m_iSelectedThumbnailIndex );
for( int iThumbnailIndex = 0; iThumbnailIndex < m_iThumbnailCount; ++iThumbnailIndex )
{
UniflowThumbnail rThumbnailComponent = m_rThumbnails[ iThumbnailIndex ];
rThumbnailComponent.Flip( UniflowThumbnail.EThumbnailFlippingAnimation.Zoom, true );
rThumbnailComponent.Replace( ThumbnailLocalPositionFromIndex( iThumbnailIndex ) );
rThumbnailComponent.isZoomed = true;
}
m_bCanScroll = true;
m_rCachedTransform.localPosition = CurrentGalleryLocalPosition( );
m_rUIEffectRecentring.startPosition = m_f3BasePosition;
m_rUIEffectRecentring.startRotation = m_rCachedTransform.localRotation;
m_rUIEffectRecentring.finalPositionOffset = m_fScrollingOffset * this.localRight;
if( m_dOnThumbZoomInEffectEndHandler != null )
{
m_dOnThumbZoomInEffectEndHandler( this, rSelectedThumbnailComponent );
}
}
}
public void PostZoomOutSetup( )
{
// Animates/sets selected thumbnail
m_bCanScroll = true;
if( m_dOnThumbZoomOutEffectEndHandler != null )
{
m_dOnThumbZoomOutEffectEndHandler( this, m_rThumbnails[ m_iSelectedThumbnailIndex ] );
}
}
private void ToggleGalleryBackground( bool a_bEnable )
{
if( a_bEnable == true )
{
Vector3 f3LastThumbnailPosition = ThumbnailLocalPositionFromIndex( m_iThumbnailCount - 1 );
Vector3 f3GalleryCenter = f3LastThumbnailPosition * 0.5f;
f3GalleryCenter.z = f3GalleryCenter.z + 0.1f;
Vector3 f3GalleryBackgroundScale = Vector3.one;
f3GalleryBackgroundScale.x = m_fThumbnailRatio * m_iThumbnailCount;
m_rGalleryBackground.transform.localPosition = f3GalleryCenter;
m_rGalleryBackground.transform.localScale = f3GalleryBackgroundScale;
m_rGalleryBackground.active = true;
}
else
{
m_rGalleryBackground.active = false;
}
}
private bool ShouldZoom( )
{
bool bShouldZoom = zoomThumbnailOnClick;
if( m_dOnThumbClickEventHandler != null )
{
bShouldZoom = true;
UniflowThumbnail rSelectedThumbnailComponent = m_rThumbnails[ m_iSelectedThumbnailIndex ];
foreach( OnThumbnailClickEvent dThumbnailClickEventHandler in m_dOnThumbClickEventHandler.GetInvocationList( ) )
{
bool bHandlerValue = dThumbnailClickEventHandler( this, rSelectedThumbnailComponent );
bShouldZoom = bShouldZoom && bHandlerValue;
}
}
return bShouldZoom;
}
/////////////// RECENTRING ///////////////
// Configs & starts UIEffect component to perform a recentering to
// the given thumbnail
private void StartRecentering( int a_iThumbnailIndex )
{
StartRecentering( a_iThumbnailIndex, m_fRecenteringDuration, gkInterpolate.EaseType.EaseOutCirc );
}
private void StartRecentering( int a_iThumbnailIndex, float a_fRecenteringDuration, gkInterpolate.EaseType a_eEasing )
{
if( ShouldRecenter( a_iThumbnailIndex ) == true )
{
if( m_rUIEffectRecentring.isPlaying == true )
{
// Sets scrolling offset to current recentering scrolling
m_fScrollingOffset = CurrentScrolling( );
}
// Computes scrolling offset
float fRecenteringScrollingOffset = ThumbnailIndex2ScrollingOffset( a_iThumbnailIndex );
m_rUIEffectRecentring.Pause( );
// HACK: force previous position offset update... *sigh*
m_rUIEffectRecentring.time = m_rUIEffectRecentring.duration;
m_rUIEffectRecentring.finalPositionOffset = m_fScrollingOffset * this.localRight;
m_rUIEffectRecentring.time = m_rUIEffectRecentring.duration;
///
m_rUIEffectRecentring.finalPositionOffset = fRecenteringScrollingOffset * this.localRight;
m_rUIEffectRecentring.duration = a_fRecenteringDuration;
m_rUIEffectRecentring.easing = a_eEasing;
m_rUIEffectRecentring.Restart( );
if( m_dOnRecenteringEffectStartHandler != null )
{
m_dOnRecenteringEffectStartHandler( this, m_rThumbnails[ m_iSelectedThumbnailIndex ], m_rThumbnails[ a_iThumbnailIndex ] );
}
}
// Recentering no more pending
m_bIsRecenteringPending = false;
}
// Stops recentering and sets scrolling offset to current recentering
private void StopRecentering( )
{
m_fScrollingOffset = CurrentScrolling( );
m_rUIEffectRecentring.Pause( );
m_bIsRecenteringPending = false;
if( m_dOnRecenteringEffectEndHandler != null )
{
m_dOnRecenteringEffectEndHandler( this, m_rThumbnails[ m_iSelectedThumbnailIndex ] );
}
}
// Called when recentering has ended
// Sets scrolling offset ot final recentering
private void EndOfRecenteringEffect( bool a_bEffectPlayedForward )
{
m_bIsRecenteringPending = false;
m_fScrollingOffset = CurrentScrolling( );
if( m_dOnRecenteringEffectEndHandler != null )
{
m_dOnRecenteringEffectEndHandler( this, m_rThumbnails[ m_iSelectedThumbnailIndex ] );
}
}
private bool ShouldRecenter( int a_iThumbnailIndex )
{
bool bShouldRecenter = true;
if( m_dOnRecenteringEventHandler != null )
{
UniflowThumbnail rFromThumbnailComponent = m_rThumbnails[ m_iSelectedThumbnailIndex ];
UniflowThumbnail rToThumbnailComponent = m_rThumbnails[ a_iThumbnailIndex ];
foreach( OnRecenteringEvent dRecenteringEventHandler in m_dOnRecenteringEventHandler.GetInvocationList( ) )
{
bool bHandlerValue = dRecenteringEventHandler( this, rFromThumbnailComponent, rToThumbnailComponent );
bShouldRecenter = bShouldRecenter && bHandlerValue;
}
}
return bShouldRecenter;
}
/////////////// UTILS ///////////////
// Index / scrolling / positions computations
private float CurrentThumbnailFloatIndex( )
{
float fCurrentScrollingOffset = CurrentScrolling( );
float fScaledSpacing = - m_fThumbnailSpacing * m_fCachedScaledRightMagnitude;
return fCurrentScrollingOffset / fScaledSpacing;
}
private Vector3 ThumbnailLocalPositionFromIndex( int a_iThumbnailIndex )
{
return a_iThumbnailIndex * m_fThumbnailSpacing * Vector3.right;
}
private Vector3 ThumbnailWorldPositionFromIndex( int a_iThumbnailIndex )
{
return m_rCachedTransform.localToWorldMatrix.MultiplyPoint( ThumbnailLocalPositionFromIndex( a_iThumbnailIndex ) );
}
private Vector3 CurrentGalleryLocalPosition( )
{
return m_f3BasePosition + m_fScrollingOffset * this.localRight;
}
// Computes the selected thumbnail index from given scrolling offset
private int ScrollingOffset2ThumbnailIndex( float a_fScrollingOffset )
{
// Checks if the gallery is currently scrolled further than its origin
if( a_fScrollingOffset < 0.0f )
{
float fScaledSpacing = - m_fThumbnailSpacing * m_fCachedScaledRightMagnitude;
float fScrolling = a_fScrollingOffset + ( fScaledSpacing * 0.5f );
return Mathf.Clamp( Mathf.FloorToInt( fScrolling / fScaledSpacing ), 0, m_iThumbnailCount - 1 );
}
else
{
return 0;
}
}
// Computes scrolling offset from given thumbnail index
private float ThumbnailIndex2ScrollingOffset( int a_iThumbnailIndex )
{
return - a_iThumbnailIndex * m_fThumbnailSpacing * m_fCachedScaledRightMagnitude;
}
// Computes current scrolling offset
// Always in range [-infinity .. 0.0]
private float CurrentScrolling( )
{
Vector3 f3ScrollingVector = m_rCachedTransform.localPosition - m_f3BasePosition;
return Mathf.Clamp( Vector3.Dot( this.localRight, f3ScrollingVector ), float.NegativeInfinity, 0.0f );
}
/////////////// EDITOR ///////////////
// Draws plane collider limits in editor
private void OnDrawGizmos( )
{
Camera rMainCamera = Camera.mainCamera;
Vector3 f3WorldPosition = transform.position;
Vector3 f3WorldRight = transform.right;
Vector3 f3CameraToGalleryWorldVector = f3WorldPosition - rMainCamera.transform.position;
Vector3 f3WorldLineOrigin = f3WorldPosition + Vector3.Project( -f3CameraToGalleryWorldVector, f3WorldRight );
Vector3 f3WorldUpToGallery = Vector3.Cross( f3WorldRight, f3CameraToGalleryWorldVector );
f3WorldUpToGallery = f3WorldUpToGallery.normalized;
Vector3 f3WorldPointOnMaxPlaneLimit = f3WorldLineOrigin + m_fPlaneColliderHalfSize * f3WorldUpToGallery;
Vector3 f3WorldPointOnMinPlaneLimit = f3WorldLineOrigin - m_fPlaneColliderHalfSize * f3WorldUpToGallery;
///// Draws Gizmos /////
// Plane limits
Gizmos.color = Color.green;
Gizmos.DrawLine( f3WorldPointOnMinPlaneLimit - 5.0f * f3WorldRight, f3WorldPointOnMinPlaneLimit + 5.0f * f3WorldRight );
Gizmos.DrawLine( f3WorldPointOnMaxPlaneLimit - 5.0f * f3WorldRight, f3WorldPointOnMaxPlaneLimit + 5.0f * f3WorldRight );
// Draws gallery origin
Vector3 f3CubeScale = transform.localScale;
f3CubeScale.x *= m_fThumbnailRatio;
f3CubeScale.y *= 1.0f;
f3CubeScale.z *= 0.1f;
Gizmos.matrix = transform.localToWorldMatrix;
Gizmos.color = Color.red;
Gizmos.DrawWireCube( Vector3.zero, f3CubeScale );
}
}
And here is the second script which is just a listener:
using UnityEngine;
using System.Collections;
[AddComponentMenu( "GUI/Click Event Manager" )]
public class ClickEventManager : MonoBehaviour
{
public bool drawDebugRays;
private static ClickEventManager ms_rInstance;
private bool m_bTouchScreen;
private bool m_bInputWasPreviouslyPressed;
private Collider m_rFirstPressedCollider;
private Collider m_rPreviousHoveredCollider;
void Awake( )
{
if( ms_rInstance == null )
{
ms_rInstance = this;
//DontDestroyOnLoad( this );
}
else
{
Debug.LogWarning( "/!\\ !!! Click Manager: instance already exists !!! /!\\" );
Destroy( this );
}
}
// Use this for initialization
void Start ()
{
m_rFirstPressedCollider = null;
m_rPreviousHoveredCollider = null;
m_bInputWasPreviouslyPressed = false;
switch( Application.platform )
{
// Smartphones / tablets
case RuntimePlatform.IPhonePlayer:
case RuntimePlatform.Android:
{
m_bTouchScreen = true;
}
break;
// Consoles
case RuntimePlatform.PS3:
case RuntimePlatform.WiiPlayer:
case RuntimePlatform.XBOX360:
{
Debug.LogWarning( "/!\\ !!! Virtual Tour Indicator: consoles are not supported !!! /!\\" );
}
break;
// Desktop PCs/Macs
// As Unity doesn't support touch screen on these devices yet,
// we can assume reading the mouse input only
default:
{
m_bTouchScreen = false;
}
break;
}
}
// Update is called once per frame
void Update ()
{
Vector3 f3InputPosition = Vector3.zero;
bool bInputIsCurrentlyPressed = false;
// Reading input: touch screen or mouse according to the device
// Touch screen
if( m_bTouchScreen == true )
{
if( Input.touchCount > 0 )
{
Touch oFirstTouch = Input.touches[ 0 ];
f3InputPosition.x = oFirstTouch.position.x;
f3InputPosition.y = oFirstTouch.position.y;
switch( oFirstTouch.phase )
{
case TouchPhase.Began:
case TouchPhase.Moved:
case TouchPhase.Stationary:
{
bInputIsCurrentlyPressed = true;
}
break;
}
}
}
else
{
// Mouse
f3InputPosition = Input.mousePosition;
bInputIsCurrentlyPressed = Input.GetMouseButton( 0 );
}
RaycastHit oInputRaycastHitInfo;
Ray oInputRay = Camera.mainCamera.ScreenPointToRay( f3InputPosition );
bool bIsColliding = Physics.Raycast( oInputRay, out oInputRaycastHitInfo, Mathf.Infinity );
Collider rCollidedElement = oInputRaycastHitInfo.collider;
// Hovering?
if( bIsColliding == true )
{
if( m_rPreviousHoveredCollider != rCollidedElement )
{
if( m_rPreviousHoveredCollider != null && m_rPreviousHoveredCollider != m_rFirstPressedCollider )
{
m_rPreviousHoveredCollider.SendMessage( "OnHoverEvent", false, SendMessageOptions.DontRequireReceiver );
}
if( m_rFirstPressedCollider != rCollidedElement )
{
rCollidedElement.SendMessage( "OnHoverEvent", true, SendMessageOptions.DontRequireReceiver );
m_rPreviousHoveredCollider = rCollidedElement;
}
}
}
else
{
if( m_rPreviousHoveredCollider != null && m_rPreviousHoveredCollider != m_rFirstPressedCollider )
{
m_rPreviousHoveredCollider.SendMessage( "OnHoverEvent", false, SendMessageOptions.DontRequireReceiver );
m_rPreviousHoveredCollider = null;
}
}
// Input is clicking something
if( m_bInputWasPreviouslyPressed != bInputIsCurrentlyPressed )
{
m_bInputWasPreviouslyPressed = bInputIsCurrentlyPressed;
if( bIsColliding == true )
{
// The first collider where the user pressed is the same where the user has un-pressed
// => it's a click!
if( m_rFirstPressedCollider == oInputRaycastHitInfo.collider )
{
DrawDebugRay( oInputRay, Color.green );
System.Diagnostics.Debug.Assert( bInputIsCurrentlyPressed == false, "/!\\ !!! Impossible case occurred !!! /!\\" );
if( bInputIsCurrentlyPressed == false )
{
m_rFirstPressedCollider.SendMessage( "OnClickEvent", SendMessageOptions.DontRequireReceiver );
m_rFirstPressedCollider = null;
}
}
else if( bInputIsCurrentlyPressed == true )
{
// The user is starting is pressing over this collider
m_rFirstPressedCollider = oInputRaycastHitInfo.collider;
DrawDebugRay( oInputRay, Color.blue );
}
else if( m_rFirstPressedCollider != null )
{
// The user has pressed in the void...
// Release the collider if any
m_rFirstPressedCollider.SendMessage( "OnHoverEvent", false, SendMessageOptions.DontRequireReceiver );
m_rFirstPressedCollider = null;
DrawDebugRay( oInputRay, Color.blue );
}
}
else
{
if( bInputIsCurrentlyPressed == false && m_rFirstPressedCollider != null )
{
m_rFirstPressedCollider.SendMessage( "OnHoverEvent", false, SendMessageOptions.DontRequireReceiver );
m_rFirstPressedCollider = null;
}
DrawDebugRay( oInputRay, Color.red );
}
}
}
private void DrawDebugRay( Ray a_oRayToDraw, Color a_oRayColor )
{
if( drawDebugRays == true )
{
Debug.DrawRay( a_oRayToDraw.origin, a_oRayToDraw.direction, a_oRayColor, 5.0f );
}
}
}
Comment