using System; using FairyGUI; using FairyGUI.Utils; using UnityEngine; /// /// Achieving the effect of turning over books. Use virtual mechanism to support unlimited pages. Support covers. /// public class FairyBook : GComponent { /// /// /// /// /// public delegate void PageRenderer(int index, GComponent page); /// /// /// public PageRenderer pageRenderer; /// /// /// public static float EffectDuration = 0.5f; /// /// /// public enum Paper { Soft, Hard } public enum CoverType { Front, Back } enum CoverStatus { Hidden, ShowingFront, ShowingBack } enum CoverTurningOp { None, ShowFront, HideFront, ShowBack, HideBack } enum Corner { INVALID, TL, BL, TR, BR } GComponent _pagesContainer; string _pageResource; int _pageWidth; int _pageHeight; int _pageCount; int _currentPage; Paper _paper; int _turningTarget; float _turningAmount; CoverTurningOp _coverTurningOp; GPath _turningPath; GComponent[] _objects; GGraph _mask1; GGraph _mask2; GObject _softShadow; int[] _objectIndice; int[] _objectNewIndice; Corner _draggingCorner; Vector2 _dragPoint; float _touchDownTime; GComponent _frontCover; GComponent _backCover; Vector2 _frontCoverPos; Vector2 _backCoverPos; CoverStatus _coverStatus; EventListener _onTurnComplete; public override void ConstructFromXML(XML xml) { base.ConstructFromXML(xml); _pagesContainer = GetChild("pages").asCom; if (_pagesContainer == null) { Debug.LogError("Not a valid book resource"); return; } GComponent obj1 = _pagesContainer.GetChild("left").asCom; GComponent obj2 = _pagesContainer.GetChild("right").asCom; if (obj1 == null || obj2 == null || obj1.resourceURL != obj2.resourceURL || obj1.width != obj2.width || obj2.x != obj1.x + obj1.width) { Debug.LogError("Not a valid book resource"); return; } obj1.displayObject.home = this.displayObject.cachedTransform; obj2.displayObject.home = this.displayObject.cachedTransform; _pagesContainer.RemoveChild(obj1); _pagesContainer.RemoveChild(obj2); _frontCover = GetChild("frontCover") as GComponent; if (_frontCover != null) _frontCoverPos = _frontCover.position; _backCover = GetChild("backCover") as GComponent; if (_backCover != null) _backCoverPos = _backCover.position; _objects = new GComponent[4] { obj1, obj2, null, null }; _objectIndice = new int[4] { -1, -1, -1, -1 }; _objectNewIndice = new int[4]; _turningTarget = -1; _currentPage = -1; _pageWidth = (int)obj1.width; _pageHeight = (int)obj1.height; _pageResource = obj1.resourceURL; _mask1 = new GGraph(); _mask1.displayObject.home = this.displayObject.cachedTransform; _mask1.SetSize(_pageWidth, _pageHeight); _mask2 = new GGraph(); _mask2.displayObject.home = this.displayObject.cachedTransform; _mask2.SetSize(_pageWidth, _pageHeight); SetupHotspot(GetChild("hotspot_tl"), Corner.TL); SetupHotspot(GetChild("hotspot_bl"), Corner.BL); SetupHotspot(GetChild("hotspot_tr"), Corner.TR); SetupHotspot(GetChild("hotspot_br"), Corner.BR); } public override void Dispose() { for (int i = 0; i < 4; i++) { if (_objects[i] != null) _objects[i].Dispose(); } _mask1.Dispose(); _mask2.Dispose(); if (_softShadow != null) _softShadow.Dispose(); base.Dispose(); } /// /// /// public EventListener onTurnComplete { get { return _onTurnComplete ?? (_onTurnComplete = new EventListener(this, "onTurnComplete")); } } /// /// /// /// public void SetSoftShadowResource(string res) { _softShadow = UIPackage.CreateObjectFromURL(res); _softShadow.height = Mathf.Sqrt(Mathf.Pow(_pageWidth, 2) + Mathf.Pow(_pageHeight, 2)) + 60; _softShadow.displayObject.home = this.displayObject.cachedTransform; _softShadow.sortingOrder = int.MaxValue; } /// /// /// public Paper pageSoftness { get { return _paper; } set { _paper = value; } } /// /// /// public int pageCount { get { return _pageCount; } set { if (_pageCount % 2 != 0) throw new System.Exception("Page count must be even!"); _pageCount = value; } } /// /// /// public int currentPage { get { return _currentPage; } set { if (value < 0 || value > _pageCount - 1) throw new Exception("Page index out of bounds: " + value); if (_currentPage != value) { GTween.Kill(this, true); _currentPage = value; _coverStatus = CoverStatus.Hidden; RenderPages(); } } } /// /// /// /// public void TurnTo(int pageIndex) { if (pageIndex < 0 || pageIndex > _pageCount - 1) throw new Exception("Page index out of bounds: " + pageIndex); GTween.Kill(this, true); if (_coverStatus == CoverStatus.ShowingFront) { _coverTurningOp = CoverTurningOp.HideFront; _draggingCorner = Corner.BR; } else if (_coverStatus == CoverStatus.ShowingBack) { _coverTurningOp = CoverTurningOp.HideBack; _draggingCorner = Corner.BL; } int tt1 = _currentPage; if (_currentPage % 2 == 0) tt1--; int tt2 = pageIndex; if (pageIndex % 2 == 0) tt2--; if (tt1 == tt2) { _currentPage = pageIndex; _turningTarget = -1; } else { _turningTarget = pageIndex; if (_turningTarget < _currentPage) _draggingCorner = Corner.BL; else _draggingCorner = Corner.BR; } if (_draggingCorner == Corner.INVALID) return; StartTween(); } /// /// /// public void TurnNext() { GTween.Kill(this, true); if (isCoverShowing(CoverType.Front)) TurnTo(0); else if (_currentPage == _pageCount - 1) ShowCover(CoverType.Back, true); else if (_currentPage % 2 == 0) TurnTo(_currentPage + 1); else TurnTo(_currentPage + 2); } /// /// /// public void TurnPrevious() { GTween.Kill(this, true); if (isCoverShowing(CoverType.Back)) TurnTo(_pageCount - 1); else if (_currentPage == 0) ShowCover(CoverType.Front, true); else if (_currentPage % 2 == 0) TurnTo(_currentPage - 2); else TurnTo(_currentPage - 1); } /// /// /// /// /// public void ShowCover(CoverType cover, bool turnEffect) { GTween.Kill(this, true); if (_frontCover == null) return; if (turnEffect) { if (cover == CoverType.Front) { if (_coverStatus == CoverStatus.ShowingFront) return; _coverTurningOp = CoverTurningOp.ShowFront; _draggingCorner = Corner.BL; _currentPage = 0; } else { if (_coverStatus == CoverStatus.ShowingBack) return; _coverTurningOp = CoverTurningOp.ShowBack; _draggingCorner = Corner.BR; _currentPage = _pageCount - 1; } StartTween(); } else { if (cover == CoverType.Front) { _currentPage = 0; _coverStatus = CoverStatus.ShowingFront; } else { _currentPage = _pageCount - 1; _coverStatus = CoverStatus.ShowingBack; } RenderPages(); } } /// /// /// /// /// public bool isCoverShowing(CoverType cover) { return cover == CoverType.Front ? (_coverStatus == CoverStatus.ShowingFront) : (_coverStatus == CoverStatus.ShowingBack); } void StartTween() { _turningAmount = 0; RenderPages(); Vector2 source = GetCornerPosition(_draggingCorner, _coverTurningOp != CoverTurningOp.None); Vector2 target; if (_draggingCorner == Corner.TL || _draggingCorner == Corner.BL) target = GetCornerPosition(_draggingCorner + 2, _coverTurningOp != CoverTurningOp.None); else target = GetCornerPosition(_draggingCorner - 2, _coverTurningOp != CoverTurningOp.None); if (_turningPath == null) _turningPath = new GPath(); Vector2 mid = new Vector2(source.x + (target.x - source.x) / 2, target.y - 50); _turningPath.Create(new GPathPoint(source), new GPathPoint(mid), new GPathPoint(target)); GTween.To(source, target, EffectDuration).SetUserData(true).SetTarget(this) .SetPath(_turningPath) .OnUpdate(OnTurnUpdate).OnComplete(OnTurnComplete); } void OnTurnUpdate(GTweener tweener) { _dragPoint = tweener.value.vec2; _turningAmount = _dragPoint.x / (_coverTurningOp != CoverTurningOp.None ? _frontCover.width * 2 : _pageWidth * 2); if (_draggingCorner == Corner.TR || _draggingCorner == Corner.BR) _turningAmount = 1 - _turningAmount; PlayTurnEffect(); } void OnTurnComplete(GTweener tweener) { bool suc = (bool)tweener.userData; _draggingCorner = Corner.INVALID; if (suc && _turningTarget != -1) _currentPage = _turningTarget; if (suc && _coverTurningOp != CoverTurningOp.None) { if (_coverTurningOp == CoverTurningOp.ShowFront) _coverStatus = CoverStatus.ShowingFront; else if (_coverTurningOp == CoverTurningOp.ShowBack) _coverStatus = CoverStatus.ShowingBack; else _coverStatus = CoverStatus.Hidden; } _coverTurningOp = CoverTurningOp.None; _turningTarget = -1; RenderPages(); DispatchEvent("onTurnComplete"); } void PlayTurnEffect() { if (_coverTurningOp != CoverTurningOp.None) PlayCoverEffect(); if (_turningTarget != -1) { if (_paper == Paper.Hard) PlayHardEffect(); else PlaySoftEffect(); } } void PlayCoverEffect() { float amount = Mathf.Clamp01(_turningAmount); float ratio; bool isLeft; GComponent turningObj = (_coverTurningOp == CoverTurningOp.ShowFront || _coverTurningOp == CoverTurningOp.HideFront) ? _frontCover : _backCover; PolygonMesh mesh = GetHardMesh(turningObj); if (amount < 0.5f) { ratio = 1 - amount * 2; isLeft = _coverTurningOp == CoverTurningOp.ShowFront || _coverTurningOp == CoverTurningOp.HideBack; } else { ratio = (amount - 0.5f) * 2; isLeft = _coverTurningOp == CoverTurningOp.HideFront || _coverTurningOp == CoverTurningOp.ShowBack; } if (turningObj == _frontCover) SetCoverStatus(turningObj, CoverType.Front, !isLeft); else SetCoverStatus(turningObj, CoverType.Back, isLeft); mesh.points.Clear(); mesh.texcoords.Clear(); if (isLeft) { float topOffset = 1f / 8 * (1 - ratio); float xOffset = 1 - ratio; mesh.Add(new Vector2(xOffset, 1 + topOffset)); mesh.Add(new Vector2(xOffset, -topOffset)); mesh.Add(new Vector2(1, 0)); mesh.Add(new Vector2(1, 1)); } else { float topOffset = 1f / 8 * (1 - ratio); mesh.Add(new Vector2(0, 1)); mesh.Add(new Vector2(0, 0)); mesh.Add(new Vector2(ratio, -topOffset)); mesh.Add(new Vector2(ratio, 1 + topOffset)); } mesh.texcoords.AddRange(VertexBuffer.NormalizedUV); } void PlayHardEffect() { float amount = Mathf.Clamp01(_turningAmount); float ratio; bool isLeft; GComponent turningObj; PolygonMesh mesh; if (amount < 0.5f) { ratio = 1 - amount * 2; isLeft = _turningTarget < _currentPage; turningObj = _objects[2]; mesh = GetHardMesh(turningObj); GetHardMesh(_objects[3]).points.Clear(); } else { ratio = (amount - 0.5f) * 2; isLeft = _turningTarget > _currentPage; turningObj = _objects[3]; mesh = GetHardMesh(turningObj); GetHardMesh(_objects[2]).points.Clear(); } mesh.points.Clear(); mesh.texcoords.Clear(); if (isLeft) { turningObj.x = 0; float topOffset = 1f / 8 * (1 - ratio); float xOffset = 1 - ratio; mesh.Add(new Vector2(xOffset, 1 + topOffset)); mesh.Add(new Vector2(xOffset, -topOffset)); mesh.Add(new Vector2(1, 0)); mesh.Add(new Vector2(1, 1)); } else { turningObj.x = _pageWidth; float topOffset = 1f / 8 * (1 - ratio); mesh.Add(new Vector2(0, 1)); mesh.Add(new Vector2(0, 0)); mesh.Add(new Vector2(ratio, -topOffset)); mesh.Add(new Vector2(ratio, 1 + topOffset)); } mesh.texcoords.AddRange(VertexBuffer.NormalizedUV); } void FlipPoint(ref Vector2 pt, float w, float h) { switch (_draggingCorner) { case Corner.TL: pt.x = w - pt.x; pt.y = h - pt.y; break; case Corner.BL: pt.x = w - pt.x; break; case Corner.TR: pt.y = h - pt.y; break; } } void PlaySoftEffect() { GComponent turningObj1 = _objects[2]; GComponent turningObj2 = _objects[3]; PolygonMesh mesh1 = GetSoftMesh(turningObj1); PolygonMesh mesh2 = GetSoftMesh(turningObj2); /** * a * / \ * f(0,0)------/ b--g(w,0) * | / / | * | / / | * | c / | * | \ / | * | \ / | * e(0,h)-----d--------h(w,h) */ Vector2 pa, pb, pc, pd, pe, pf, pg, ph; float k, angle; bool threePoints = false; pc = _dragPoint; pe = new Vector2(0, _pageHeight); pf = Vector2.zero; pg = new Vector2(_pageWidth, 0); ph = new Vector2(_pageWidth, _pageHeight); FlipPoint(ref pc, _pageWidth * 2, _pageHeight); pc.x -= _pageWidth; if (pc.x >= _pageWidth) return; k = (ph.y - pc.y) / (ph.x - pc.x); float k2 = 1 + Mathf.Pow(k, 2); float min; min = ph.x - _pageWidth * 2 / k2; if (pc.x < min) { pc.x = min; if (pc.x >= _pageWidth) return; pc.y = ph.y - k * (ph.x - pc.x); } min = ph.x - (_pageWidth + _pageHeight * k) * 2 / k2; if (pc.x < min) { pc.x = min; if (pc.x >= _pageWidth) return; pc.y = ph.y - k * (ph.x - pc.x); } angle = Mathf.Atan(k) * Mathf.Rad2Deg; pd = new Vector2(_pageWidth - k2 * (ph.x - pc.x) / 2, _pageHeight); pb = new Vector2(pd.x + _pageHeight * k, 0); pa = new Vector2(); if (pb.x > _pageWidth) { pb.x = _pageWidth; pa = new Vector2(_pageWidth, _pageHeight - (_pageWidth - pd.x) / k); threePoints = true; } FlipPoint(ref pa, _pageWidth, _pageHeight); FlipPoint(ref pb, _pageWidth, _pageHeight); FlipPoint(ref pd, _pageWidth, _pageHeight); FlipPoint(ref pc, _pageWidth, _pageHeight); if (_draggingCorner == Corner.BL || _draggingCorner == Corner.TL) angle = -angle; switch (_draggingCorner) { case Corner.BR: { turningObj1.SetPivot(0, 0, true); turningObj1.position = new Vector2(_pageWidth, 0); turningObj2.SetPivot(0, 1, true); turningObj2.position = new Vector2(_pageWidth + pc.x, pc.y); turningObj2.rotation = 2 * angle; if (_softShadow != null) { _softShadow.SetPivot(1, (_softShadow.height - 30) / _softShadow.height, true); _softShadow.position = new Vector2(Vector2.Distance(pc, pd), _pageHeight); _softShadow.rotation = -angle; if (_softShadow.x > _pageWidth - 20) _softShadow.alpha = (_pageWidth - _softShadow.x) / 20; else _softShadow.alpha = 1; } mesh1.points.Clear(); mesh1.Add(pe); mesh1.Add(pf); mesh1.Add(pb); if (threePoints) mesh1.Add(pa); mesh1.Add(pd); mesh2.points.Clear(); mesh2.Add(new Vector2(Vector2.Distance(pc, pd), _pageHeight)); mesh2.Add(new Vector2(0, _pageHeight)); if (threePoints) mesh2.Add(new Vector2(0, _pageHeight - Vector2.Distance(pc, pa))); else { mesh2.Add(new Vector2(0, 0)); mesh2.Add(new Vector2(Vector2.Distance(pg, pb), 0)); } break; } case Corner.TR: { turningObj1.SetPivot(0, 0, true); turningObj1.position = new Vector2(_pageWidth, 0); turningObj2.SetPivot(0, 0, true); turningObj2.position = new Vector2(_pageWidth + pc.x, pc.y); turningObj2.rotation = -2 * angle; if (_softShadow != null) { _softShadow.SetPivot(1, 30 / _softShadow.height, true); _softShadow.position = new Vector2(Vector2.Distance(pc, pd), 0); _softShadow.rotation = angle; if (_softShadow.x > _pageWidth - 20) _softShadow.alpha = (_pageWidth - _softShadow.x) / 20; else _softShadow.alpha = 1; } mesh1.points.Clear(); mesh1.Add(pe); mesh1.Add(pf); mesh1.Add(pd); if (threePoints) mesh1.Add(pa); mesh1.Add(pb); mesh2.points.Clear(); if (threePoints) mesh2.Add(new Vector2(0, Vector2.Distance(pc, pa))); else { mesh2.Add(new Vector2(Vector2.Distance(pb, ph), _pageHeight)); mesh2.Add(new Vector2(0, _pageHeight)); } mesh2.Add(new Vector2(0, 0)); mesh2.Add(new Vector2(Vector2.Distance(pc, pd), 0)); break; } case Corner.BL: { turningObj1.SetPivot(0, 0, true); turningObj1.position = Vector2.zero; turningObj2.SetPivot(1, 1, true); turningObj2.position = pc; turningObj2.rotation = 2 * angle; if (_softShadow != null) { _softShadow.SetPivot(1, 30 / _softShadow.height, true); _softShadow.position = new Vector2(_pageWidth - Vector2.Distance(pc, pd), _pageHeight); _softShadow.rotation = 180 - angle; if (_softShadow.x < 20) _softShadow.alpha = (_softShadow.x - 20) / 20; else _softShadow.alpha = 1; } mesh1.points.Clear(); mesh1.Add(pb); mesh1.Add(pg); mesh1.Add(ph); mesh1.Add(pd); if (threePoints) mesh1.Add(pa); mesh2.points.Clear(); if (!threePoints) { mesh2.Add(new Vector2(_pageWidth - Vector2.Distance(pf, pb), 0)); mesh2.Add(new Vector2(_pageWidth, 0)); } else mesh2.Add(new Vector2(_pageWidth, _pageHeight - Vector2.Distance(pc, pa))); mesh2.Add(new Vector2(_pageWidth, _pageHeight)); mesh2.Add(new Vector2(_pageWidth - Vector2.Distance(pc, pd), _pageHeight)); break; } case Corner.TL: { turningObj1.SetPivot(0, 0, true); turningObj1.position = Vector2.zero; turningObj2.SetPivot(1, 0, true); turningObj2.position = pc; turningObj2.rotation = -2 * angle; if (_softShadow != null) { _softShadow.SetPivot(1, (_softShadow.height - 30) / _softShadow.height, true); _softShadow.position = new Vector2(_pageWidth - Vector2.Distance(pc, pd), 0); _softShadow.rotation = 180 + angle; if (_softShadow.x < 20) _softShadow.alpha = (_softShadow.x - 20) / 20; else _softShadow.alpha = 1; } mesh1.points.Clear(); mesh1.Add(pd); mesh1.Add(pg); mesh1.Add(ph); mesh1.Add(pb); if (threePoints) mesh1.Add(pa); mesh2.points.Clear(); mesh2.Add(new Vector2(_pageWidth - Vector2.Distance(pc, pd), 0)); mesh2.Add(new Vector2(_pageWidth, 0)); if (threePoints) mesh2.Add(new Vector2(_pageWidth, Vector2.Distance(pc, pa))); else { mesh2.Add(new Vector2(_pageWidth, _pageHeight)); mesh2.Add(new Vector2(_pageWidth - Vector2.Distance(pe, pb), _pageHeight)); } break; } } } void RenderPages() { RenderCovers(); if (_softShadow != null) _softShadow.RemoveFromParent(); int curPage = _currentPage; if (curPage % 2 == 0) curPage--; int leftPage, rightPage, turningPageBack, turningPageFront; leftPage = curPage; rightPage = leftPage < _pageCount - 1 ? (leftPage + 1) : -1; if (_turningTarget != -1) { int tt = _turningTarget; if (tt % 2 == 0) tt = tt - 1; if (tt == curPage) { _currentPage = _turningTarget; turningPageBack = turningPageFront = -1; } else if (tt > leftPage) { turningPageFront = tt; turningPageBack = rightPage; rightPage = tt < _pageCount - 1 ? (tt + 1) : -1; } else { turningPageFront = tt > 0 ? (tt + 1) : 0; turningPageBack = leftPage; leftPage = tt > 0 ? tt : -1; } } else { turningPageBack = turningPageFront = -1; } _objectNewIndice[0] = leftPage; _objectNewIndice[1] = rightPage; _objectNewIndice[2] = turningPageBack; _objectNewIndice[3] = turningPageFront; for (int i = 0; i < 4; i++) { int pageIndex = _objectNewIndice[i]; if (pageIndex != -1) { for (int j = 0; j < 4; j++) { int pageIndex2 = _objectIndice[j]; if (pageIndex2 == pageIndex) { if (j != i) { _objectIndice[j] = _objectIndice[i]; _objectIndice[i] = pageIndex; GComponent tmp = _objects[j]; _objects[j] = _objects[i]; _objects[i] = tmp; } break; } } } } for (int i = 0; i < 4; i++) { GComponent obj = _objects[i]; int oldIndex = _objectIndice[i]; int index = _objectNewIndice[i]; _objectIndice[i] = index; if (index == -1) { if (obj != null) obj.RemoveFromParent(); } else if (oldIndex != index) { if (obj == null) { obj = UIPackage.CreateObjectFromURL(_pageResource).asCom; obj.displayObject.home = this.displayObject.cachedTransform; _objects[i] = obj; } _pagesContainer.AddChild(obj); pageRenderer(index, obj); } else { if (obj.parent == null) { _pagesContainer.AddChild(obj); pageRenderer(index, obj); } else _pagesContainer.AddChild(obj); } if (obj != null && obj.parent != null) { Controller c1 = obj.GetController("side"); if (c1 != null) { if (index == 0) c1.selectedPage = "first"; else if (index == _pageCount - 1) c1.selectedPage = "last"; else c1.selectedPage = (index % 2 == 0) ? "right" : "left"; } if (i == 0 || i == 1) SetPageNormal(obj, i == 0); else if (_paper == Paper.Soft) SetPageSoft(obj, i == 2); else SetPageHard(obj, i == 2); } } } void RenderCovers() { if (_frontCover != null) { if (_coverTurningOp == CoverTurningOp.ShowFront || _coverTurningOp == CoverTurningOp.HideFront) { SetPageHard(_frontCover, true); SetCoverStatus(_frontCover, CoverType.Front, _coverTurningOp == CoverTurningOp.HideFront); } else { if (_frontCover.displayObject.cacheAsBitmap) SetCoverNormal(_frontCover, CoverType.Front); SetCoverStatus(_frontCover, CoverType.Front, _coverStatus == CoverStatus.ShowingFront); } } if (_backCover != null) { if (_coverTurningOp == CoverTurningOp.ShowBack || _coverTurningOp == CoverTurningOp.HideBack) { SetPageHard(_backCover, true); SetCoverStatus(_backCover, CoverType.Back, _coverTurningOp == CoverTurningOp.HideBack); } else { if (_backCover.displayObject.cacheAsBitmap) SetCoverNormal(_backCover, CoverType.Back); SetCoverStatus(_backCover, CoverType.Back, _coverStatus == CoverStatus.ShowingBack); } } } void SetupHotspot(GObject obj, Corner corner) { if (obj == null) return; obj.data = corner; obj.onTouchBegin.Add(__touchBegin); obj.onTouchMove.Add(__touchMove); obj.onTouchEnd.Add(__touchEnd); } void SetPageHard(GComponent obj, bool front) { obj.touchable = false; obj.displayObject.cacheAsBitmap = true; if (obj.mask != null) { obj.mask.RemoveFromParent(); obj.mask = null; } PolygonMesh mesh = obj.displayObject.paintingGraphics.GetMeshFactory(); mesh.usePercentPositions = true; mesh.points.Clear(); mesh.texcoords.Clear(); obj.displayObject.paintingGraphics.SetMeshDirty(); if (front) { mesh.points.AddRange(VertexBuffer.NormalizedPosition); mesh.texcoords.AddRange(VertexBuffer.NormalizedUV); } } void SetPageSoft(GComponent obj, bool front) { obj.touchable = false; obj.displayObject.cacheAsBitmap = false; DisplayObject mask = front ? _mask1.displayObject : _mask2.displayObject; obj.mask = mask; PolygonMesh mesh = mask.graphics.GetMeshFactory(); mesh.usePercentPositions = false; mesh.points.Clear(); mesh.texcoords.Clear(); mask.graphics.SetMeshDirty(); if (front) { mesh.Add(new Vector2(0, _pageHeight)); mesh.Add(Vector2.zero); mesh.Add(new Vector2(_pageWidth, 0)); mesh.Add(new Vector2(_pageWidth, _pageHeight)); } else if (_softShadow != null) obj.AddChild(_softShadow); } void SetPageNormal(GComponent obj, bool left) { obj.displayObject.cacheAsBitmap = false; obj.touchable = true; obj.SetPivot(0, 0, true); if (left) obj.SetXY(0, 0); else obj.SetXY(_pageWidth, 0); obj.rotation = 0; if (obj.mask != null) { obj.mask.RemoveFromParent(); obj.mask = null; } } void SetCoverStatus(GComponent obj, CoverType coverType, bool show) { Controller c = obj.GetController("side"); if (show) { if (c.selectedIndex != 0) { obj.position = coverType == CoverType.Front ? _backCoverPos : _frontCoverPos; obj.parent.SetChildIndexBefore(obj, obj.parent.GetChildIndex(_pagesContainer) + 1); c.selectedIndex = 0; //front if (obj.displayObject.cacheAsBitmap) obj.displayObject.cacheAsBitmap = true; //refresh } } else { if (c.selectedIndex != 1) { obj.position = coverType == CoverType.Front ? _frontCoverPos : _backCoverPos; obj.parent.SetChildIndexBefore(obj, obj.parent.GetChildIndex(_pagesContainer)); c.selectedIndex = 1; //back if (obj.displayObject.cacheAsBitmap) obj.displayObject.cacheAsBitmap = true; //refresh } } } void SetCoverNormal(GComponent obj, CoverType coverType) { obj.position = coverType == CoverType.Front ? _frontCoverPos : _backCoverPos; obj.displayObject.cacheAsBitmap = false; obj.touchable = true; obj.parent.SetChildIndexBefore(obj, obj.parent.GetChildIndex(_pagesContainer)); obj.GetController("side").selectedIndex = 1; //back } PolygonMesh GetHardMesh(GComponent obj) { obj.displayObject.paintingGraphics.SetMeshDirty(); return obj.displayObject.paintingGraphics.GetMeshFactory(); } PolygonMesh GetSoftMesh(GComponent obj) { obj.mask.graphics.SetMeshDirty(); return obj.mask.graphics.GetMeshFactory(); } void UpdateDragPosition(Vector2 pos) { if (_coverTurningOp != CoverTurningOp.None) { _dragPoint = GlobalToLocal(pos) - _frontCoverPos; _turningAmount = _dragPoint.x / (2 * _frontCover.width); } else { _dragPoint = _pagesContainer.GlobalToLocal(pos); _turningAmount = _dragPoint.x / (2 * _pageWidth); } if (_draggingCorner == Corner.TR || _draggingCorner == Corner.BR) _turningAmount = 1 - _turningAmount; } Vector2 GetCornerPosition(Corner corner, bool isCover) { float w = isCover ? _frontCover.width : _pageWidth; float h = isCover ? _frontCover.height : _pageHeight; Vector2 pt; switch (corner) { case Corner.BL: pt = new Vector2(0, h); break; case Corner.TR: pt = new Vector2(w * 2, 0); break; case Corner.BR: pt = new Vector2(w * 2, h); break; default: pt = Vector2.zero; break; } return pt; } void __touchBegin(EventContext context) { GTween.Kill(this, true); _draggingCorner = (Corner)((GObject)context.sender).data; if (_draggingCorner == Corner.TL || _draggingCorner == Corner.BL) { if (_coverStatus == CoverStatus.ShowingBack) { _coverTurningOp = CoverTurningOp.HideBack; } else if (_objectNewIndice[0] == -1) { if (_frontCover != null && _coverStatus != CoverStatus.ShowingFront) _coverTurningOp = CoverTurningOp.ShowFront; else _draggingCorner = Corner.INVALID; } else { _turningTarget = _objectNewIndice[0] - 2; if (_turningTarget < 0) _turningTarget = 0; } } else { if (_coverStatus == CoverStatus.ShowingFront) { _coverTurningOp = CoverTurningOp.HideFront; } else if (_objectNewIndice[1] == -1) { if (_backCover != null && _coverStatus != CoverStatus.ShowingBack) _coverTurningOp = CoverTurningOp.ShowBack; else _draggingCorner = Corner.INVALID; } else { _turningTarget = _objectNewIndice[1] + 1; } } if (_draggingCorner != Corner.INVALID) { _touchDownTime = Time.unscaledTime; UpdateDragPosition(context.inputEvent.position); RenderPages(); PlayTurnEffect(); context.CaptureTouch(); } } void __touchMove(EventContext context) { if (_draggingCorner != Corner.INVALID) { UpdateDragPosition(context.inputEvent.position); PlayTurnEffect(); } } void __touchEnd(EventContext context) { if (_draggingCorner != Corner.INVALID) { bool suc = _turningAmount > 0.4f || (Time.unscaledTime - _touchDownTime < 0.35f); Vector2 target; if (suc) { if (_draggingCorner == Corner.TL || _draggingCorner == Corner.BL) target = GetCornerPosition(_draggingCorner + 2, _coverTurningOp != CoverTurningOp.None); else target = GetCornerPosition(_draggingCorner - 2, _coverTurningOp != CoverTurningOp.None); } else target = GetCornerPosition(_draggingCorner, _coverTurningOp != CoverTurningOp.None); float duration = Mathf.Max(EffectDuration * 0.5f, Mathf.Abs(target.x - _dragPoint.x) / (_pageWidth * 2) * EffectDuration); GTween.To(_dragPoint, target, duration).SetTarget(this).SetUserData(suc) .OnUpdate(OnTurnUpdate).OnComplete(OnTurnComplete); } } }