Last active
July 23, 2017 16:36
-
-
Save jpsarda/6221653 to your computer and use it in GitHub Desktop.
FScrollContainer for Unity3D Futile 2D game engine.
To test it you need to change a few things in the Futile code :
* _theSingleTouchable must be protected and not private
* Update() must be declared virtual.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using UnityEngine; | |
using System.Collections; | |
using System.Collections.Generic; | |
/* | |
A serie of 4 classes extending Futile classes in order to manage scrollable containers with scrollable buttons. | |
Use : | |
public void TestScrollContainer() | |
{ | |
// Create a vertically scrollable container of width 30, height 200, and scrollable height 600 | |
FScrollContainer scroll=new FScrollContainer(30,200); | |
scroll.SetContentSize(30,600); | |
AddChild(scroll); | |
//Add 4 sprites with different colors in the contentContainer (different colors in order to see them scrolling) | |
FSprite scrollSprite; | |
scrollSprite=new FSprite("Futile_White"); | |
scrollSprite.color=new Color(1f,0f,0f); | |
scrollSprite.scaleX=30f/scrollSprite.textureRect.width; | |
scrollSprite.scaleY=150f/scrollSprite.textureRect.height; | |
scrollSprite.y=-300f+75f; | |
scroll.contentContainer.AddChild(scrollSprite); | |
scrollSprite=new FSprite("Futile_White"); | |
scrollSprite.color=new Color(0f,1f,0f); | |
scrollSprite.scaleX=30f/scrollSprite.textureRect.width; | |
scrollSprite.scaleY=150f/scrollSprite.textureRect.height; | |
scrollSprite.y=-300f+150f+75f; | |
scroll.contentContainer.AddChild(scrollSprite); | |
scrollSprite=new FSprite("Futile_White"); | |
scrollSprite.color=new Color(1f,0f,0f); | |
scrollSprite.scaleX=30f/scrollSprite.textureRect.width; | |
scrollSprite.scaleY=150f/scrollSprite.textureRect.height; | |
scrollSprite.y=-300f+150f*2+75f; | |
scroll.contentContainer.AddChild(scrollSprite); | |
scrollSprite=new FSprite("Futile_White"); | |
scrollSprite.color=new Color(0f,1f,0f); | |
scrollSprite.scaleX=30f/scrollSprite.textureRect.width; | |
scrollSprite.scaleY=150f/scrollSprite.textureRect.height; | |
scrollSprite.y=-300f+150f*3+75f; | |
scroll.contentContainer.AddChild(scrollSprite); | |
//Add a scrollable blue button in the center of the contentContainer | |
FScrollButton button=new FScrollButton("Futile_White", "Futile_White", null, null); | |
button.SetColors(new Color(0f,0f,1f),new Color(0f,0f,0.5f)); | |
button.SignalRelease += HandleScrollButtonRelease; | |
scroll.contentContainer.AddChild(button); | |
} | |
private void HandleScrollButtonRelease (FButton button) | |
{ | |
Debug.Log ("SCROLL BUTTON CLICK"); | |
} | |
*/ | |
public class FNodeEnablerForScrollSingleTouch : FNodeEnabler | |
{ | |
protected FNode _node=null; | |
protected FTouchManager _touchManager=null; | |
public FNodeEnablerForScrollSingleTouch(FNode node) | |
{ | |
FSingleTouchableInterface singleTouchable = node as FSingleTouchableInterface; | |
if(singleTouchable == null) | |
{ | |
throw new FutileException("Trying to enable scroll single touch on a node that doesn't implement FSingleTouchableInterface"); | |
} | |
_node = node; | |
} | |
override public void Connect() | |
{ | |
_touchManager=null; | |
FContainer parent=_node.container; | |
//Find a FScrollContainer in the tree of upper container, if so subscribe to its touch manager, otherwise subscribe to futile's touch manager | |
while (parent!=null) { | |
FScrollContainer scrollContainer=parent as FScrollContainer; | |
if (scrollContainer!=null) { | |
_touchManager=scrollContainer.touchManager; | |
Debug.Log ("FScrollContainer found"); | |
break; | |
} | |
parent=parent.container; | |
} | |
if (_touchManager==null) { | |
_touchManager=Futile.touchManager; | |
} | |
_touchManager.AddSingleTouchTarget(_node as FSingleTouchableInterface); | |
} | |
override public void Disconnect() | |
{ | |
if (_touchManager!=null) _touchManager.RemoveSingleTouchTarget(_node as FSingleTouchableInterface); | |
} | |
} | |
public class FScrollTouchManager : FTouchManager | |
{ | |
protected bool _isScrolling=false; | |
public FScrollTouchManager () : base() | |
{ | |
} | |
override public void Update() | |
{ | |
if (_isScrolling) return; | |
base.Update(); | |
} | |
virtual public bool isScrolling | |
{ | |
get | |
{ | |
return _isScrolling; | |
} | |
set | |
{ | |
if (value!=_isScrolling) { | |
_isScrolling=value; | |
if(_theSingleTouchable != null) | |
{ | |
_theSingleTouchable.HandleSingleTouchCanceled(new FTouch()); | |
_theSingleTouchable=null; | |
} | |
} | |
} | |
} | |
} | |
public class FScrollButton : FButton | |
{ | |
public FScrollButton (string upElementName, string downElementName, string overElementName, string clickSoundName) : base(upElementName, downElementName, overElementName, clickSoundName) | |
{ | |
DisableSingleTouch(); // Because we need the button already added to the stage to decide which touch manager to register with | |
} | |
override public void HandleAddedToStage() | |
{ | |
EnableScrollSingleTouch(); | |
base.HandleAddedToStage(); | |
} | |
override public void HandleRemovedFromStage() | |
{ | |
DisableScrollSingleTouch(); | |
base.HandleRemovedFromStage(); | |
} | |
public void EnableScrollSingleTouch() | |
{ | |
DisableSingleTouch(); | |
DisableScrollSingleTouch(); //clear any old ones first | |
AddEnabler(new FNodeEnablerForScrollSingleTouch(this)); | |
} | |
public void DisableScrollSingleTouch() | |
{ | |
RemoveEnablerOfType(typeof(FNodeEnablerForScrollSingleTouch)); | |
} | |
} | |
public class FScrollContainer : FContainer, FSingleTouchableInterface | |
{ | |
protected FScrollTouchManager _touchManager; | |
protected FContainer _contentContainer; | |
protected float _width=0f,_height=0f; | |
protected float _contentWidth=0f,_contentHeight=0f; | |
protected Vector2 _scrollingSpeed=Vector2.zero; | |
protected bool _isTouchDown=false,_oneMoreUpdate=false; | |
protected Rect _hitRect; | |
protected Vector2 _totalScroll=Vector2.zero; | |
public FScrollContainer (float width, float height) : base() | |
{ | |
_contentWidth=_width=width; | |
_contentHeight=_height=height; | |
_hitRect.width = _width; | |
_hitRect.height = _height; | |
_hitRect.x = -0.5f*_width; | |
_hitRect.y = -0.5f*_height; | |
_touchManager=new FScrollTouchManager(); | |
_contentContainer=new FContainer(); | |
AddChild(_contentContainer); | |
} | |
public FContainer contentContainer { | |
get { return _contentContainer; } | |
} | |
public FTouchManager touchManager { | |
get { return _touchManager; } | |
} | |
virtual public void SetContentSize(float width, float height) { | |
_contentWidth=width; | |
_contentHeight=height; | |
} | |
override public void HandleAddedToStage() | |
{ | |
Futile.touchManager.AddSingleTouchTarget(this); | |
Futile.instance.SignalUpdate += HandleUpdate; | |
base.HandleAddedToStage(); | |
} | |
override public void HandleRemovedFromStage() | |
{ | |
Futile.touchManager.RemoveSingleTouchTarget(this); | |
Futile.instance.SignalUpdate -= HandleUpdate; | |
base.HandleRemovedFromStage(); | |
} | |
public void HandleUpdate() { | |
if (_isTouchDown) { | |
_touchManager.Update(); | |
} else { | |
if (_oneMoreUpdate) { | |
_touchManager.Update(); | |
_oneMoreUpdate=false; | |
} | |
if (_touchManager.isScrolling) { | |
_scrollingSpeed*=0.9f; | |
if (_scrollingSpeed.sqrMagnitude<4) { | |
_scrollingSpeed=Vector2.zero; | |
_touchManager.isScrolling=false; | |
} else { | |
_scrollingSpeed*=0.9f; | |
Move(); | |
} | |
} | |
} | |
} | |
virtual protected void CheckContentBorders() { | |
if (_contentContainer.x-_contentWidth*0.5f>-_width*0.5f) { | |
_contentContainer.x=-_width*0.5f+_contentWidth*0.5f; | |
} else if (_contentContainer.x+_contentWidth*0.5f<_width*0.5f) { | |
_contentContainer.x=_width*0.5f-_contentWidth*0.5f; | |
} | |
if (_contentContainer.y-_contentHeight*0.5f>-_height*0.5f) { | |
_contentContainer.y=-_height*0.5f+_contentHeight*0.5f; | |
} else if (_contentContainer.y+_contentHeight*0.5f<_height*0.5f) { | |
_contentContainer.y=_height*0.5f-_contentHeight*0.5f; | |
} | |
} | |
virtual protected void Move() { | |
Vector2 memoPos=new Vector2(_contentContainer.x,_contentContainer.y); | |
_contentContainer.x+=_scrollingSpeed.x; | |
_contentContainer.y+=_scrollingSpeed.y; | |
CheckContentBorders(); | |
_scrollingSpeed.x=_contentContainer.x-memoPos.x; | |
_scrollingSpeed.y=_contentContainer.y-memoPos.y; | |
} | |
virtual public bool HandleSingleTouchBegan(FTouch touch) | |
{ | |
_scrollingSpeed=Vector2.zero; | |
_isTouchDown = false; | |
Vector2 touchPos = this.GetLocalTouchPosition(touch); | |
if(_hitRect.Contains(touchPos)) | |
{ | |
_isTouchDown = true; | |
_totalScroll=Vector2.zero; | |
return true; | |
} | |
return false; | |
} | |
virtual public void HandleSingleTouchMoved(FTouch touch) | |
{ | |
if (_isTouchDown) { | |
_scrollingSpeed=touch.deltaPosition; | |
Move(); | |
if (!_touchManager.isScrolling) { | |
//_totalScroll+=_scrollingSpeed; | |
//better to add deltaPosition, if we move the finger to scroll and content doesn't scroll becasue we are on the border, we might click on a button not on purpose | |
_totalScroll+=touch.deltaPosition; | |
if (_totalScroll.sqrMagnitude>25f) { //set the touchManager in scroll mode after 5 pixels moved | |
_touchManager.isScrolling=true; | |
} | |
} | |
} | |
} | |
virtual public void HandleSingleTouchEnded(FTouch touch) | |
{ | |
_isTouchDown=false; | |
_oneMoreUpdate=true; | |
} | |
virtual public void HandleSingleTouchCanceled(FTouch touch) | |
{ | |
_isTouchDown=false; | |
_oneMoreUpdate=true; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment