public void Update() { OnMouseMoved (); float dt = Time.deltaTime; scrollStateTime += dt; Vector2 assignScroll = scroll; bool updateScroll = false; switch(scrollState) { case PlanetScrollState.Decelerating: //update the horizontal deceleration if(((int)scrollDirection & (int)scrollLockDirection & (int)PlanetScrollDirection.Horizontal) != 0) { if(horizontalDecelerationState == PlanetScrollDeceleratingState.ReturningFromEdge) { //we're returning from being scrolled past the edge horizontalDecelerationTime += dt; assignScroll.x = easeOutCubic(animStartScroll.x, animEndScroll.x, horizontalDecelerationTime/kAnimationDuration); //are we done animating? if(horizontalDecelerationTime >= kAnimationDuration) { velocity.x = 0.0f; assignScroll.x = animEndScroll.x; horizontalDecelerationState = PlanetScrollDeceleratingState.Idle; } } else { //we were not scrolled past the edge, scroll normally if(horizontalDecelerationState == PlanetScrollDeceleratingState.Scrolling) { //we're scrolling, and have not yet hit the edge float deceleratingPercent = scrollStateTime/kScrollDuration; assignScroll.x = easeOutQuint(animStartScroll.x, animEndScroll.x, deceleratingPercent); velocity.x = easeOutQuint(animStartVelocity.x, 0.0f, deceleratingPercent); //check if we've hit the edge if(assignScroll.x > 0.0f || assignScroll.x < calcMinScrollX()) { if(bounces) { horizontalDecelerationState = PlanetScrollDeceleratingState.Bouncing; horizontalDecelerationTime = 0.0f; } else { velocity.x = 0.0f; if(assignScroll.x > 0.0f) assignScroll.x = 0.0f; else if(assignScroll.x < calcMinScrollX()) assignScroll.x = calcMinScrollX(); horizontalDecelerationState = PlanetScrollDeceleratingState.Idle; } } else if(scrollStateTime > kScrollDuration) { velocity.x = 0.0f; assignScroll.x = animEndScroll.x; horizontalDecelerationState = PlanetScrollDeceleratingState.Idle; } } if(horizontalDecelerationState == PlanetScrollDeceleratingState.Bouncing) { horizontalDecelerationTime += dt; //which edge are we bouncing from? float edge = bounceEdgeX(assignScroll.x); //are we done bouncing? if(horizontalDecelerationTime >= kEdgeBounceDuration) { assignScroll.x = edge; velocity.x = 0.0f; horizontalDecelerationState = PlanetScrollDeceleratingState.Idle; } else { //assign the bounce position float bounceDistPastEdge = edge + velocity.x*kBounceDistancePerVelocity; if(horizontalDecelerationTime < kEdgeBounceEaseTimePercent*kEdgeBounceDuration) { assignScroll.x = easeOutQuad(edge, bounceDistPastEdge, horizontalDecelerationTime / (kEdgeBounceEaseTimePercent*kEdgeBounceDuration)); } else { assignScroll.x = easeOutQuad(bounceDistPastEdge, edge, (horizontalDecelerationTime - kEdgeBounceEaseTimePercent*kEdgeBounceDuration) / ((1.0f-kEdgeBounceEaseTimePercent)*kEdgeBounceDuration)); } } } } } //update the vertical deceleration if(((int)scrollDirection & (int)scrollLockDirection & (int)PlanetScrollDirection.Vertical) != 0) { if(verticalDecelerationState == PlanetScrollDeceleratingState.ReturningFromEdge) { //we're returning from being scrolled past the edge verticalDecelerationTime += dt; assignScroll.y = easeOutCubic(animStartScroll.y, animEndScroll.y, verticalDecelerationTime/kAnimationDuration); //are we done animating? if(verticalDecelerationTime >= kAnimationDuration) { velocity.y = 0.0f; assignScroll.y = animEndScroll.y; verticalDecelerationState = PlanetScrollDeceleratingState.Idle; } } else { //we were not scrolled past the edge, scroll normally if(verticalDecelerationState == PlanetScrollDeceleratingState.Scrolling) { //we're scrolling, and have not yet hit the edge float deceleratingPercent = scrollStateTime/kScrollDuration; assignScroll.y = easeOutQuint(animStartScroll.y, animEndScroll.y, deceleratingPercent); velocity.y = easeOutQuint(animStartVelocity.y, 0.0f, deceleratingPercent); //check if we've hit the edge if(assignScroll.y < 0.0f || assignScroll.y > calcMaxScrollY()) { if(bounces) { verticalDecelerationState = PlanetScrollDeceleratingState.Bouncing; verticalDecelerationTime = 0.0f; } else { velocity.y = 0.0f; if(assignScroll.y < 0.0f) assignScroll.y = 0.0f; else if(assignScroll.y > calcMaxScrollY()) assignScroll.y = calcMaxScrollY(); verticalDecelerationState = PlanetScrollDeceleratingState.Idle; } } else if(scrollStateTime > kScrollDuration) { velocity.y = 0.0f; assignScroll.y = animEndScroll.y; verticalDecelerationState = PlanetScrollDeceleratingState.Idle; } } if(verticalDecelerationState == PlanetScrollDeceleratingState.Bouncing) { verticalDecelerationTime += dt; //which edge are we bouncing from? float edge = bounceEdgeY(assignScroll.y); //are we done bouncing? if(verticalDecelerationTime >= kEdgeBounceDuration) { assignScroll.y = edge; velocity.y = 0.0f; verticalDecelerationState = PlanetScrollDeceleratingState.Idle; } else { //assign the bounce position float bounceDistPastEdge = edge + velocity.y*kBounceDistancePerVelocity; if(verticalDecelerationTime < kEdgeBounceEaseTimePercent*kEdgeBounceDuration) { assignScroll.y = easeOutQuad(edge, bounceDistPastEdge, verticalDecelerationTime / (kEdgeBounceEaseTimePercent*kEdgeBounceDuration)); } else { assignScroll.y = easeOutQuad(bounceDistPastEdge, edge, (verticalDecelerationTime - kEdgeBounceEaseTimePercent*kEdgeBounceDuration) / ((1.0f-kEdgeBounceEaseTimePercent)*kEdgeBounceDuration)); } } } } } //check if we're done decelerating if(horizontalDecelerationState == PlanetScrollDeceleratingState.Idle && verticalDecelerationState == PlanetScrollDeceleratingState.Idle) { setScrollState(PlanetScrollState.Idle); } updateScroll = true; break; case PlanetScrollState.UserDragging: { //account for touch offset assignScroll.x += touchEdgeOffset.x; assignScroll.y += touchEdgeOffset.y; //do bungee effect horizontally if(assignScroll.x > 0) { if(bounces) assignScroll.x = bungee(assignScroll.x, entity.bounds.w); else { assignScroll.x = 0.0f; velocity.x = 0.0f; } } else { float minScroll = calcMinScrollX(); if(assignScroll.x < minScroll) { if(bounces) assignScroll.x = entity.bounds.w - bungee((minScroll - assignScroll.x), entity.bounds.w) - entity.contentSize.x; else { assignScroll.x = minScroll; velocity.x = 0.0f; } } } //do bungee effect vertically if(assignScroll.y < 0) { if (bounces) { assignScroll.y = bungee (assignScroll.y, -entity.bounds.h); } else { assignScroll.y = 0.0f; velocity.y = 0.0f; } } else { float minScroll = calcMaxScrollY(); if(assignScroll.y > minScroll) { if(bounces) assignScroll.y = bungee((assignScroll.y-minScroll), entity.bounds.h) + entity.contentSize.y - entity.bounds.h; else { assignScroll.y = minScroll; velocity.y = 0.0f; } } } } break; case PlanetScrollState.Animating: { //animate horizontally if(((int)scrollDirection & (int)scrollLockDirection & (int)PlanetScrollDirection.Horizontal) != 0) { //animate towards our desired scroll position assignScroll.x = easeOutCubic(animStartScroll.x, animEndScroll.x, scrollStateTime/kAnimationDuration); } //animate vertically if(((int)scrollDirection & (int)scrollLockDirection & (int)PlanetScrollDirection.Vertical) != 0) { //animate towards our desired scroll position assignScroll.y = easeOutCubic(animStartScroll.y, animEndScroll.y, scrollStateTime/kAnimationDuration); } //ready to switch states? if(scrollStateTime >= kAnimationDuration) { assignScroll = animEndScroll; velocity.x = velocity.y = 0.0f; setScrollState(PlanetScrollState.Idle); } //we want the position that we calculated to persist updateScroll = true; } break; default: break; } //update the scroll position internalScroll(assignScroll, updateScroll); }
void setScrollState(PlanetScrollState newState) { //ignore redundant changes if(scrollState != newState) { if(newState == PlanetScrollState.UserDragging) { // TODO: call scrollViewWillBeginDragging on delegate } else if(newState == PlanetScrollState.Decelerating) { // TODO: call scrollViewWillBeginDecelerating on delegate } else if(newState == PlanetScrollState.Animating) { // TODO: call scrollViewWillBeginAnimating on delegate } if(scrollState == PlanetScrollState.UserDragging) { // TODO: call scrollViewWillEndDragging on delegate } if(newState == PlanetScrollState.Animating || newState == PlanetScrollState.Decelerating) { animStartScroll = entity.gameObject.transform.localPosition; animStartVelocity = velocity; horizontalDecelerationState = PlanetScrollDeceleratingState.Scrolling; verticalDecelerationState = PlanetScrollDeceleratingState.Scrolling; } //this will reset directional lock when paging is enabled if(newState == PlanetScrollState.Idle && userTouching == false) directionalLockIsSet = false; PlanetScrollState oldState = scrollState; scrollState = newState; scrollStateTime = 0.0f; if(oldState == PlanetScrollState.UserDragging) { // TODO: call scrollViewDidEndDragging on delegate } else if(oldState == PlanetScrollState.Decelerating) { // TODO: call scrollViewDidEndDecelerating on delegate } else if(oldState == PlanetScrollState.Animating) { // TODO: call scrollViewDidEndAnimating on delegate } } }
public void OnMouseUp() { if (scrollEnabled == false) return; if (userTouching) { userTouching = false; //this will reset directional lock only when paging is not enabled if(!pagingEnabled) directionalLockIsSet = false; absScroll.x += Mathf.Abs (velocity.x); absScroll.y += Mathf.Abs (velocity.y); if (absScroll.x >= kMinCancelTouchesVelocity || absScroll.y >= kMinCancelTouchesVelocity) { shouldCancelTouches = true; } if (shouldCancelTouches) { NotificationCenter.postNotification (entity.scope (), "PlanetUnityCancelMouse"); } //check if we flicked the scroll view if(Mathf.Abs(velocity.x) < kMinCancelTouchesVelocity) velocity.x = 0; if(Mathf.Abs(velocity.y) < kMinCancelTouchesVelocity) velocity.y = 0; //we do some weird shifting around of the scroll position to correctly calculate the bungee effect //recover the value from the bungee effect here to avoid any position snapping scroll = entity.gameObject.transform.localPosition; if(pagingEnabled) { //we're paging, animate if we're not already correctly positioned calcPagingTarget(); //always switch states to ensure delegates get certain callbacks setScrollState(PlanetScrollState.Animating); //if we're already lined up, stop the animation state immediately if(!shouldBeAnimating()) { //set the position to to line up exactly with the current page scroll = animEndScroll; //entity.gameObject.transform.localPosition = scroll; setScrollState(PlanetScrollState.Idle); } } else { bool isPastHorizontalEdge = scroll.x > 0.0f || scroll.x < calcMinScrollX(); bool isPastVerticalEdge = scroll.y < 0.0f || scroll.y > calcMaxScrollY(); bool isMoving = Mathf.Abs(velocity.x) > kMinScrollSpeed || Mathf.Abs(velocity.y) > kMinScrollSpeed; if(isMoving || isPastHorizontalEdge || isPastVerticalEdge) { //switch to decelerating setScrollState(PlanetScrollState.Decelerating); //we should scroll, calculate where our scroll should end if(isPastHorizontalEdge) { //animate back to the edge instead of scrolling horizontalDecelerationTime = 0.0f; horizontalDecelerationState = PlanetScrollDeceleratingState.ReturningFromEdge; animEndScroll.x = bounceEdgeX(scroll.x); } else animEndScroll.x = scroll.x + kSwipeDistancePerVelocity*velocity.x; if(isPastVerticalEdge) { //animate back to the edge instead of scrolling verticalDecelerationTime = 0.0f; verticalDecelerationState = PlanetScrollDeceleratingState.ReturningFromEdge; animEndScroll.y = bounceEdgeY(scroll.y); } else animEndScroll.y = scroll.y + kSwipeDistancePerVelocity*velocity.y; } else { //we're not moving or past the edge of the scroll, just idle setScrollState(PlanetScrollState.Idle); } } } }