Created
September 28, 2013 23:59
-
-
Save jpsarda/6747929 to your computer and use it in GitHub Desktop.
FSpeechBubble for Futile. Uses latest version of GoKit (which renamed almost all classes this way : Tween > GoTween)
Demo http://bonuslevel.org/experiments/futiletests/futiletests.html You need to include the following classes too :
Drawing polygons https://gist.github.com/wtrebella/5444072
Drawing lines https://gist.github.com/jpsarda/4573831
D…
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 UnityEngine; | |
using System.Collections; | |
using System.Collections.Generic; | |
using System; | |
using System.Linq; | |
using System.Text; | |
using System.Reflection; | |
public class FSpeechBubble : FContainer | |
{ | |
protected float _width,_height,_cornerRadius=10f; | |
protected int _cornerSegmentsCount; | |
protected float _pointerBaseSize=10f; | |
protected float _minSize,_bigCornerRadius; | |
protected Vector2 _point; | |
protected float _pointerMargin=10f; | |
//draw | |
//protected Color _borderColor=Color.white; //TODO | |
protected WTPolygonSprite _polygonSprite; | |
protected FDrawingSprite _borderSprite=null; | |
public FSpeechBubble () | |
{ | |
UpdateIntermediateValues(); | |
_polygonSprite=new WTPolygonSprite(null); | |
AddChild(_polygonSprite); | |
_borderSprite=new FDrawingSprite("Futile_White"); | |
AddChild(_borderSprite); | |
} | |
public void SetSizeAndPointer(float width,float height,Vector2 point,float pointerMargin) { | |
_width=width; | |
_height=height; | |
if (_width<_minSize) _width=_minSize; | |
if (_height<_minSize) _height=_minSize; | |
_point=point; | |
_pointerMargin=pointerMargin; | |
Update(); | |
} | |
public Color backgroundColor { | |
get { return _polygonSprite.color;} | |
set { | |
if (value!=_polygonSprite.color) { | |
_polygonSprite.color=value; | |
} | |
} | |
} | |
public float width { get { return _width; } } | |
public float height { get { return _height; } } | |
protected void Update() { | |
float halfWidth=_width*0.5f; | |
float halfHeight=_height*0.5f; | |
//Is point outside of the rectangle? | |
bool outside=true; | |
if ((_point.x-_pointerMargin<=halfWidth)&&(_point.x+_pointerMargin>=-halfWidth)) { | |
if ((_point.y-_pointerMargin<=halfHeight)&&(_point.y+_pointerMargin>=-halfHeight)) { | |
Debug.LogWarning("FSpeechBubble, the point is inisde the bubble."); | |
outside=false; | |
//return; | |
} | |
} | |
//All clockwise | |
Vector2[] segmentTop = new Vector2[] {new Vector2(-halfWidth+_cornerRadius, halfHeight),new Vector2(halfWidth-_cornerRadius, halfHeight)}; | |
Vector2[] segmentBottom = new Vector2[] {new Vector2(halfWidth-_cornerRadius, -halfHeight),new Vector2(-halfWidth+_cornerRadius, -halfHeight)}; | |
Vector2[] segmentLeft = new Vector2[] {new Vector2(-halfWidth, -halfHeight+_cornerRadius),new Vector2(-halfWidth, halfHeight-_cornerRadius)}; | |
Vector2[] segmentRight = new Vector2[] {new Vector2(halfWidth, halfHeight-_cornerRadius),new Vector2(halfWidth, -halfHeight+_cornerRadius)}; | |
Vector2[] cornerTopLeft=new Vector2[_cornerSegmentsCount+1],cornerTopRight=new Vector2[_cornerSegmentsCount+1],cornerBottomRight=new Vector2[_cornerSegmentsCount+1],cornerBottomLeft=new Vector2[_cornerSegmentsCount+1]; | |
for (int i=0;i<=_cornerSegmentsCount;i++) { | |
float angle=(float)Math.PI*0.5f*(float)i/(float)_cornerSegmentsCount; | |
cornerTopLeft[i]=new Vector2(-_cornerRadius*(float)Math.Cos(angle),_cornerRadius*(float)Math.Sin(angle)); | |
cornerBottomRight[i]=cornerTopLeft[i]*(-1); | |
} | |
for (int i=0;i<=_cornerSegmentsCount;i++) { | |
cornerTopRight[i]=new Vector2(-cornerTopLeft[_cornerSegmentsCount-i].x,cornerTopLeft[_cornerSegmentsCount-i].y); | |
cornerBottomLeft[i]=cornerTopRight[i]*(-1); | |
} | |
Vector2 centerCornerTopLeft=new Vector2(-halfWidth+_cornerRadius,halfHeight-_cornerRadius); | |
Vector2 centerCornerTopRight=new Vector2(halfWidth-_cornerRadius,halfHeight-_cornerRadius); | |
Vector2 centerCornerBottomRight=new Vector2(halfWidth-_cornerRadius,-halfHeight+_cornerRadius); | |
Vector2 centerCornerBottomLeft=new Vector2(-halfWidth+_cornerRadius,-halfHeight+_cornerRadius); | |
for (int i=0;i<=_cornerSegmentsCount;i++) { | |
cornerTopLeft[i]+=centerCornerTopLeft; | |
cornerTopRight[i]+=centerCornerTopRight; | |
cornerBottomRight[i]+=centerCornerBottomRight; | |
cornerBottomLeft[i]+=centerCornerBottomLeft; | |
} | |
if (outside) { | |
//Which part of the rectangle is the point? (8 zones) | |
if ((_point.x>=-halfWidth+_bigCornerRadius) && (_point.x<=halfWidth-_bigCornerRadius)) { | |
//top and bottom zones | |
if (_point.y<0) { | |
//bottom | |
segmentBottom=new Vector2[] {segmentBottom[0],new Vector2(_point.x+_pointerBaseSize*0.5f,segmentBottom[0].y),_point+new Vector2(0,_pointerMargin),new Vector2(_point.x-_pointerBaseSize*0.5f,segmentBottom[0].y),segmentBottom[1]}; | |
} else { | |
//top | |
segmentTop=new Vector2[] {segmentTop[0],new Vector2(_point.x-_pointerBaseSize*0.5f,segmentTop[0].y),_point-new Vector2(0,_pointerMargin),new Vector2(_point.x+_pointerBaseSize*0.5f,segmentTop[0].y),segmentTop[1]}; | |
} | |
} else if ((_point.y>=-halfHeight+_bigCornerRadius) && (_point.y<=halfHeight-_bigCornerRadius)) { | |
//left and right zones | |
if (_point.x<0) { | |
//left | |
segmentLeft=new Vector2[] {segmentLeft[0],new Vector2(segmentLeft[0].x,_point.y-_pointerBaseSize*0.5f),_point+new Vector2(_pointerMargin,0),new Vector2(segmentLeft[0].x,_point.y+_pointerBaseSize*0.5f),segmentLeft[1]}; | |
} else { | |
//right | |
segmentRight=new Vector2[] {segmentRight[0],new Vector2(segmentRight[0].x,_point.y+_pointerBaseSize*0.5f),_point-new Vector2(_pointerMargin,0),new Vector2(segmentRight[0].x,_point.y-_pointerBaseSize*0.5f),segmentRight[1]}; | |
} | |
} else { | |
//corners | |
Vector2 aim; | |
if (_point.x<0) { | |
if (_point.y<0) { | |
//bottom-left corner | |
aim=new Vector2(-halfWidth+_bigCornerRadius,-halfHeight+_bigCornerRadius); | |
InsertPointer(aim,ref segmentBottom,ref cornerBottomLeft,ref segmentLeft); | |
} else { | |
//top-left corner | |
aim=new Vector2(-halfWidth+_bigCornerRadius,halfHeight-_bigCornerRadius); | |
InsertPointer(aim,ref segmentLeft,ref cornerTopLeft,ref segmentTop); | |
} | |
} else { | |
if (_point.y<0) { | |
//bottom-right corner | |
aim=new Vector2(halfWidth-_bigCornerRadius,-halfHeight+_bigCornerRadius); | |
InsertPointer(aim,ref segmentRight,ref cornerBottomRight,ref segmentBottom); | |
} else { | |
//top-right corner | |
aim=new Vector2(halfWidth-_bigCornerRadius,halfHeight-_bigCornerRadius); | |
InsertPointer(aim,ref segmentTop,ref cornerTopRight,ref segmentRight); | |
} | |
} | |
//find intersection point-aim with the bubble | |
} | |
} | |
//Link all paths together | |
Vector2[][] paths=new Vector2[][] { segmentTop,cornerTopRight,segmentRight,cornerBottomRight,segmentBottom,cornerBottomLeft,segmentLeft,cornerTopLeft }; | |
int verticesCount=0; | |
foreach (Vector2[] path in paths) { | |
verticesCount+=path.Length-1; | |
} | |
Vector2[] vertices = new Vector2[verticesCount]; | |
int j=0; | |
//int l=0; | |
foreach (Vector2[] path in paths) { | |
for (int k=1;k<path.Length;k++) { //skip first point that is redundant with last point of previous path (could also skip last point, same result) | |
vertices[j]=path[k]; j++; | |
} | |
/* | |
Debug.Log("Path >>> "+l); l++; | |
for (int i = 0; i < path.Length; i++) { | |
Vector2 v = path[i]; | |
Debug.Log("Vertex " + i + ": " + v); | |
} | |
*/ | |
} | |
_polygonSprite.UpdateWithData(new WTPolygonData(vertices)); | |
//log | |
/* | |
Debug.Log("Total path >>> "+l); | |
Vector2[] originalVertices = _polygonSprite.polygonData.polygonVertices; | |
for (int i = 0; i < originalVertices.Length; i++) { | |
Vector2 v = originalVertices[i]; | |
Debug.Log("Vertex " + i + ": " + v); | |
} | |
*/ | |
_borderSprite.Clear(); | |
_borderSprite.SetLineJointStyle(FTDrawingJointStyle.BEVEL); | |
_borderSprite.SetLineThickness(1.5f); | |
_borderSprite.SetLineColor(new Color(0,0,0,1.0f)); | |
_borderSprite.PushTopBorder(1.5f,new Color(1.0f,1.0f,1.0f,0.0f),true); | |
_borderSprite.PushBottomBorder(1.5f,new Color(0.0f,0.0f,0.0f,0.0f),true); | |
Vector2[] originalVertices = _polygonSprite.polygonData.polygonVertices; | |
_borderSprite.MoveTo(originalVertices[0].x,originalVertices[0].y); | |
for (int i = 1; i < originalVertices.Length; i++) { | |
Vector2 v = originalVertices[i]; | |
_borderSprite.LineTo(v.x,v.y); | |
} | |
_borderSprite.Loop(); | |
} | |
protected bool FindClosestIntersection(Vector2 aim, Vector2[] path, out Vector2 intersection, out int lowerIdx) { | |
Vector2 diff=aim-_point; | |
intersection=Vector2.zero; | |
lowerIdx=-1; | |
float minDist=-1f; | |
for (int i=1;i<path.Length;i++) { | |
Vector2 seg0=path[i-1]; | |
Vector2 seg1=path[i]; | |
float S, T; | |
if ( VectorUtils.LinesIntersect(seg0, seg1, _point, aim, out S, out T ) ) { | |
if (S >= 0.0f && S <= 1.0f && T >= 0.0f /*&& T <= 1.0f*/) { //don't check T<=1 because the intersection go on after aim | |
Vector2 foundIntersection=_point+diff*T; | |
float dist=(foundIntersection-_point).magnitude; | |
if ((lowerIdx<0)||(dist<minDist)) { | |
minDist=dist; | |
lowerIdx=i-1; | |
intersection=foundIntersection; | |
} | |
} | |
} | |
} | |
return (lowerIdx>=0); | |
} | |
protected bool FindClosestIntersection(Vector2 aim, Vector2[][] paths, out Vector2 intersection, out int pathIdx, out int segmentLowerIdx) { | |
//Vector2 diff=aim-_point; | |
intersection=Vector2.zero; | |
pathIdx=-1; | |
segmentLowerIdx=-1; | |
float minDist=-1f; | |
for (int i=0;i<paths.Length;i++) { | |
Vector2[] path = paths[i]; | |
Vector2 foundIntersection; | |
int foundSegmentLowerIdx; | |
bool ret=FindClosestIntersection(aim,path,out foundIntersection,out foundSegmentLowerIdx); | |
if (ret) { | |
float dist=(foundIntersection-_point).magnitude; | |
if ((pathIdx<0)||(dist<minDist)) { | |
minDist=dist; | |
pathIdx=i; | |
segmentLowerIdx=foundSegmentLowerIdx; | |
intersection=foundIntersection; | |
} | |
} | |
} | |
return (pathIdx>=0); | |
} | |
protected bool InsertPointer(Vector2 aim, ref Vector2[] path0, ref Vector2[] path1, ref Vector2[] path2) { | |
Vector2 diff=aim-_point; | |
Vector2[][] paths=new Vector2[][] {path0,path1,path2}; | |
Vector2 foundIntersection; | |
int foundPathIdx; | |
int foundSegmentLowerIdx; | |
bool ret=FindClosestIntersection(aim,paths,out foundIntersection,out foundPathIdx, out foundSegmentLowerIdx); | |
if (ret) { | |
Vector2 dir=diff.normalized; | |
Vector2 orth=new Vector2(-dir.y,dir.x); | |
Vector2 point0=foundIntersection-orth*_pointerBaseSize*0.5f; | |
Vector2 point1=foundIntersection+orth*_pointerBaseSize*0.5f; | |
//Take into acount the pointerMargin | |
Vector2 correctedPoint=_point+dir*_pointerMargin; | |
//find intersections with point0 and point1 | |
Vector2 foundIntersection0; | |
int foundPathIdx0; | |
int foundSegmentLowerIdx0; | |
bool ret0=FindClosestIntersection(point0,paths,out foundIntersection0,out foundPathIdx0, out foundSegmentLowerIdx0); | |
if (ret0) { | |
Vector2 foundIntersection1; | |
int foundPathIdx1; | |
int foundSegmentLowerIdx1; | |
bool ret1=FindClosestIntersection(point1,paths,out foundIntersection1,out foundPathIdx1, out foundSegmentLowerIdx1); | |
if (ret1) { | |
if (foundPathIdx0<foundPathIdx1) { | |
int i; | |
Vector2[] path; | |
path=paths[foundPathIdx0]; | |
int pathPointsCount0=foundSegmentLowerIdx0+3; | |
Vector2[] newPath0=new Vector2[pathPointsCount0]; | |
i=0; | |
for (;i<pathPointsCount0-2;i++) { | |
newPath0[i]=path[i]; | |
} | |
newPath0[i]=foundIntersection0; i++; | |
newPath0[i]=correctedPoint; i++; | |
path=paths[foundPathIdx1]; | |
int pathPointsCount1=path.Length-foundSegmentLowerIdx1+1; | |
Vector2[] newPath1=new Vector2[pathPointsCount1]; | |
i=0; | |
newPath1[i]=correctedPoint; i++; | |
newPath1[i]=foundIntersection1; i++; | |
for (int j=foundSegmentLowerIdx1+1;j<path.Length;j++) { | |
newPath1[i]=path[j]; i++; | |
} | |
if (foundPathIdx0==0) { | |
path0=newPath0; | |
path1=newPath1; | |
} else { //foundPathIdx0==1 | |
path1=newPath0; | |
path2=newPath1; | |
} | |
return true; | |
} else if (foundPathIdx0==foundPathIdx1) { | |
if (foundSegmentLowerIdx0<=foundSegmentLowerIdx1) { | |
int i; | |
Vector2[] path=paths[foundPathIdx0]; | |
int pathPointsCount=path.Length-(foundSegmentLowerIdx1-foundSegmentLowerIdx0)+3; | |
Vector2[] newPath=new Vector2[pathPointsCount]; | |
i=0; | |
for (int j=0;j<=foundSegmentLowerIdx0;j++) { | |
newPath[i]=path[j]; i++; | |
} | |
newPath[i]=foundIntersection0; i++; | |
newPath[i]=correctedPoint; i++; | |
newPath[i]=foundIntersection1; i++; | |
for (int j=foundSegmentLowerIdx1+1;j<path.Length;j++) { | |
newPath[i]=path[j]; i++; | |
} | |
if (foundPathIdx0==0) { | |
path0=newPath; | |
} else if (foundPathIdx0==1) { | |
path1=newPath; | |
} else { //foundPathIdx0==2 | |
path2=newPath; | |
} | |
} | |
//else if (foundSegmentLowerIdx0==foundSegmentLowerIdx1) { | |
//} | |
} | |
} | |
} | |
} | |
return false; | |
} | |
//To call when _cornerRadius, or _pointerBaseSize changed | |
protected void UpdateIntermediateValues() { | |
_minSize=2*_cornerRadius+_pointerBaseSize; | |
_bigCornerRadius=_cornerRadius+_pointerBaseSize*0.5f; | |
_cornerSegmentsCount=(int)(_cornerRadius/2); if (_cornerSegmentsCount<4) _cornerSegmentsCount=4; | |
} | |
} |
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 UnityEngine; | |
using System.Collections; | |
using System.Collections.Generic; | |
using System; | |
using System.Linq; | |
using System.Text; | |
using System.Reflection; | |
/* | |
Usage : | |
FPseudoHtmlText text=new FPseudoHtmlText(Config.fontFile,"<style text-scale='1.25'>FSpeechBubble</style><br/><style text-scale='0.5'>Combined with a FPseudoHtmlText. How cool is that? <style text-color='#FF99FF'><br/><fsprite width='50' src='diamant'/>. With FSprites and FButtons inside, that's pretty cool! <fbutton src='yes' label='FButtons' scale='0.5' label-scale='0.5' color-down='#FF0000' action='MyMethodNameWithData' data='mybutttonid'/></style>",Config.textParams,200f,PseudoHtmlTextAlign.left,1f,this); | |
FSpeechBubbleManager.TransitionPop(FSpeechBubbleManager.Instance.Show(text,touch,10f)); | |
*/ | |
public class FSpeechBubbleManager | |
{ | |
static readonly FSpeechBubbleManager instance=new FSpeechBubbleManager(); | |
static FSpeechBubbleManager () {} | |
FSpeechBubbleManager() {} | |
public static FSpeechBubbleManager Instance { get { instance.Initialize(); return instance; } } | |
protected bool _initialized=false; | |
protected void Initialize() { | |
if (!_initialized) { | |
_initialized=true; | |
HandleResize(false); | |
Futile.screen.SignalResize += HandleResize; | |
} | |
} | |
protected void HandleResize(bool wasOrientationChange) | |
{ | |
_defaultContainer=Futile.stage; | |
float screenMargin=5f; | |
_defaultVisibleArea=new Rect(-Futile.screen.halfWidth+screenMargin,-Futile.screen.halfHeight+screenMargin,Futile.screen.width-screenMargin*2,Futile.screen.height-screenMargin*2); | |
} | |
protected Rect _defaultVisibleArea; | |
protected FContainer _defaultContainer=null; | |
protected float _defaultContentMarginX=5f,_defaultContentMarginY=5f; | |
protected float _defaultPointerLength=10f; | |
protected Color _defaultBackgroundColor=Color.white; | |
public Rect defaultVisibleArea { get { return _defaultVisibleArea; } } | |
public FContainer defaultContainer { get { return _defaultContainer; } } | |
public float defaultContentMarginX { get { return _defaultContentMarginX; } } | |
public float defaultContentMarginY { get { return _defaultContentMarginY; } } | |
public float defaultPointerLength { get { return _defaultPointerLength; } } | |
public Color defaultBackgroundColor { get { return _defaultBackgroundColor; } } | |
public FSpeechBubble Show(FPseudoHtmlText text,Vector2 point,float pointerMargin) { | |
return Show(text,text.width,text.height,point,pointerMargin); | |
} | |
public FSpeechBubble Show(FNode node, float width, float height, Vector2 point, float pointerMargin) { | |
return Show(node,width,height,_defaultContentMarginX,_defaultContentMarginY,point,_defaultPointerLength,pointerMargin,_defaultBackgroundColor,_defaultContainer,_defaultVisibleArea); | |
} | |
public FSpeechBubble Show(FNode node, float width, float height, float contentMarginX, float contentMarginY, Vector2 point, float pointerLength, float pointerMargin, Color backgroundColor, FContainer container, Rect visibleArea) { | |
FSpeechBubble bubble=new FSpeechBubble(); | |
bubble.backgroundColor=backgroundColor; | |
if (node!=null) { | |
if (node.container!=null) node.RemoveFromContainer(); | |
bubble.AddChild(node); | |
} | |
container.AddChild(bubble); | |
//size fo the bubble with content margin taken into account | |
float totalWidth=width+contentMarginX*2; | |
float totalHeight=height+contentMarginY*2; | |
float totalPointerLength=pointerLength+pointerMargin; | |
float verticalFreeWidth=0,verticalFreeHeight=0; | |
float horizontalFreeWidth=0,horizontalFreeHeight=0; | |
//Try first the space on top/bottom or left/right | |
//Determine which space is best suited | |
if (point.x<visibleArea.center.x) { | |
//more space on the right | |
verticalFreeWidth=visibleArea.xMax-point.x-totalPointerLength; | |
verticalFreeHeight=visibleArea.height; | |
} else { | |
//more space on the left | |
verticalFreeWidth=point.x-visibleArea.xMin-totalPointerLength; | |
verticalFreeHeight=visibleArea.height; | |
} | |
if (point.y<visibleArea.center.y) { | |
//more space on the top | |
horizontalFreeWidth=visibleArea.width; | |
horizontalFreeHeight=visibleArea.yMax-point.y-totalPointerLength; | |
} else { | |
//more space on the bottom | |
horizontalFreeWidth=visibleArea.width; | |
horizontalFreeHeight=point.y-visibleArea.yMin-totalPointerLength; | |
} | |
float verticalRemainingSurface=-1,horizontalRemainingSurface=-1; | |
float verticalHiddenSurface=0,horizontalHiddenSurface=0; | |
bool verticalFit=false,horizontalFit=false; | |
if ((totalWidth<=verticalFreeWidth)&&(totalHeight<=verticalFreeHeight)) { | |
verticalFit=true; | |
} else { | |
if (totalWidth>verticalFreeWidth) { | |
verticalHiddenSurface+=(totalWidth-verticalFreeWidth)*totalHeight; | |
} | |
if (totalHeight>verticalFreeHeight) { | |
verticalHiddenSurface+=(totalHeight-verticalFreeHeight)*totalWidth; | |
} | |
} | |
verticalRemainingSurface=verticalFreeWidth*verticalFreeHeight-totalWidth*totalHeight; | |
if ((totalWidth<=horizontalFreeWidth)&&(totalHeight<=horizontalFreeHeight)) { | |
horizontalFit=true; | |
} else { | |
if (totalWidth>horizontalFreeWidth) { | |
horizontalHiddenSurface+=(totalWidth-horizontalFreeWidth)*totalHeight; | |
} | |
if (totalHeight>horizontalFreeHeight) { | |
horizontalHiddenSurface+=(totalHeight-horizontalFreeHeight)*totalWidth; | |
} | |
} | |
horizontalRemainingSurface=horizontalFreeWidth*horizontalFreeHeight-totalWidth*totalHeight; | |
bool chooseHorizontal; | |
if (verticalFit && horizontalFit) { | |
if (verticalRemainingSurface>horizontalRemainingSurface) { | |
//choose vertical | |
chooseHorizontal=false; | |
} else { | |
//choose horizontal | |
chooseHorizontal=true; | |
} | |
} else if (horizontalFit) { | |
//choose horizontal | |
chooseHorizontal=true; | |
} else if (verticalFit) { | |
//choose vertical | |
chooseHorizontal=false; | |
} else { | |
if (verticalHiddenSurface<horizontalHiddenSurface) { | |
//choose vertical | |
chooseHorizontal=false; | |
} else { | |
//choose horizontal | |
chooseHorizontal=true; | |
} | |
} | |
if (chooseHorizontal) { | |
//horizontal | |
if (point.y<visibleArea.center.y) { | |
//more space on the top | |
bubble.y=point.y+totalPointerLength+totalHeight*0.5f; | |
} else { | |
//more space on the bottom | |
bubble.y=point.y-totalPointerLength-totalHeight*0.5f; | |
} | |
bubble.x=point.x; | |
if (bubble.x+totalWidth*0.5f>visibleArea.xMax) { | |
bubble.x=visibleArea.xMax-totalWidth*0.5f; | |
} else if (bubble.x-totalWidth*0.5f<visibleArea.xMin) { | |
bubble.x=visibleArea.xMin+totalWidth*0.5f; | |
} | |
} else { | |
//vertical | |
if (point.x<visibleArea.center.x) { | |
//more space on the right | |
bubble.x=point.x+totalPointerLength+totalWidth*0.5f; | |
} else { | |
//more space on the left | |
bubble.x=point.x-totalPointerLength-totalWidth*0.5f; | |
} | |
bubble.y=point.y; | |
if (bubble.y+totalHeight*0.5f>visibleArea.yMax) { | |
bubble.y=visibleArea.yMax-totalHeight*0.5f; | |
} else if (bubble.y-totalHeight*0.5f<visibleArea.yMin) { | |
bubble.y=visibleArea.yMin+totalHeight*0.5f; | |
} | |
} | |
bubble.SetSizeAndPointer(totalWidth,totalHeight,point-bubble.GetPosition(),pointerMargin); | |
return bubble; | |
} | |
public void RemoveFromContainer(AbstractGoTween tween) { | |
FNode node = ((tween as GoTween).target) as FNode; | |
if (node.container!=null) { | |
node.RemoveFromContainer(); | |
} | |
} | |
static public void TransitionPop(FNode node) { | |
node.scaleX=0; | |
node.scaleY=0.1f; | |
GoTweenConfig config0=new GoTweenConfig().floatProp("scaleX",1f); | |
config0.easeType=GoEaseType.ElasticOut; | |
Go.to(node,0.2f,config0); | |
GoTweenConfig config1=new GoTweenConfig().floatProp("scaleY",1f); | |
config1.easeType=GoEaseType.ElasticOut; | |
//config1.delay=0.15f; | |
Go.to(node,0.4f,config1); | |
} | |
static public void TransitionFadeOut(FNode node,float delay) { | |
GoTweenConfig config=new GoTweenConfig().floatProp("alpha",0f).onComplete(FSpeechBubbleManager.Instance.RemoveFromContainer); | |
config.easeType=GoEaseType.ExpoOut; | |
config.delay=delay; | |
Go.to (node,0.5f,config); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment