/** * Take all cards from talon and put them back in the stock */ public void ReplinishStock(MoveTypes moveType = MoveTypes.NORMAL) { SnapManager talonSnapManager = talon.GetComponentInChildren <SnapManager>(); Card[] talonCards = talonSnapManager.GetCardSet(); if (DEBUG_MODE) { Debug.Log("Cards in talon:"); } // Need to iterate in reverse order so that the cards are drawn from the stock in the same order as before for (int i = talonCards.Length - 1; i >= 0; i--) { Card card = talonCards[i]; // Remove from talon card.transform.parent = null; // Move the card position from the talon to the stock card.transform.position = new Vector3( m_stockPile.position.x, m_stockPile.position.y, card.transform.position.z ); // Rotate the card to be face down again card.Flip(false); // Add the card to the stock card.transform.parent = m_stockPile; // Flip the first card from the stock pile over to the talon automatically if (i == 0) { // Don't track this move card.MoveTo(m_talonPile, null, MoveTypes.INCOGNITO); // Need to manually flip card because of not tracking if (card.IsFaceDown()) { card.Flip(); } } } // Track replinish event if (moveType.Equals(MoveTypes.NORMAL)) { Move move = new Move(); move.SetSpecial(true); Event ev = new Event(); ev.SetType(Event.EventType.REPLINISH); move.AddEvent(ev); AddMove(move, MoveTypes.NORMAL); } }
/** * Event invoked by animation event in animation editor. * This function will be called on the last frame of the events that call it. */ public void CardAnimationCompleteEvent() { if (GameManager.DEBUG_MODE) { Debug.Log("Card animation complete."); } if (!m_translating) { // Handle corner cases with flipping cards between stock and talon SnapManager originalSnap; if (m_originalParent != null) { originalSnap = m_originalParent.GetComponent <SnapManager>(); } else if (m_startParent != null) { originalSnap = m_startParent.GetComponent <SnapManager>(); } else { // Need to determine which snap the card is closest to originalSnap = Utils.GetNearestSnapManager(this); } // Set new original parent to ensure non-null value (which may be itself) m_originalParent = originalSnap.transform; // Handle corner cases if (m_moveType.Equals(Move.MoveTypes.UNDO) && originalSnap.BelongsTo(GameManager.Sections.TALON)) { m_originalParent = GameManager.Instance.GetStockPile(); } if (m_moveType.Equals(Move.MoveTypes.REDO) && originalSnap.BelongsTo(GameManager.Sections.STOCK)) { m_originalParent = GameManager.Instance.GetTalonPile(); } // Re-attach to parent now that the animation event has completed transform.SetParent(m_originalParent); // Tell the snap manager parent to stop waiting now if (m_originalParent != null) { SnapManager snapManager = m_originalParent.GetComponent <SnapManager>(); if (snapManager != null) { snapManager.SetWaiting(false); } } } m_flipping = false; }
/** * Get the nearest snap manager to a given card. This function assumes that * the given card is not translating and not flipping (e.g., not performing any * animations). This function uses a collision vector that works like a * laser pointer from the origin of the card snap about the y-axis and z-axis to determine * if there are any snap managers nearby vertically. This * function is intended to be used only if the card has been double clicked. * * @param card the card to use as reference in determining the nearest snap manager. * @return the nearest snap manager. Returns null if no nearest snap manager exists. */ public static SnapManager GetNearestSnapManager(Card card) { SnapManager nearestSnap = null; if (card != null) { Vector3 collisionVector = new Vector3(10.0f, 10.0f, 1000.0f); Collider[] hitColliders = Physics.OverlapBox(card.transform.position, collisionVector); // First pass will be to find the snap manager // Iterate backwards to start with the nearest collisions relative to the card for (int i = hitColliders.Length - 1; i >= 0; i--) { Collider hitCollider = hitColliders[i]; if (hitCollider.transform.CompareTag("Snap")) { // No need to continue once the snap has been found nearestSnap = hitCollider.transform.GetComponent <SnapManager>(); break; } } // If a snap couldn't be found then attempt to get the parent snap off of a collided card if (nearestSnap == null) { // Iterate backwards to start with the nearest collisions relative to the card for (int i = hitColliders.Length - 1; i >= 0; i--) { Collider hitCollider = hitColliders[i]; if (hitCollider.transform.CompareTag("Card")) { // Attempt to get snap from collided card Card collidedCard = hitCollider.transform.GetComponent <Card>(); nearestSnap = collidedCard.GetComponentInParent <SnapManager>(); // No need to continue once the snap has been found if (nearestSnap != null) { break; } } } } } return(nearestSnap); }
public Transform GetCurrentParent() { // Handle corner case when parent is null by returning the transform of the nearest snap // only if the card isn't currently translating or flipping SnapManager currentSnapManager = GetComponentInParent <SnapManager>(); Transform currentParent = null; //Transform currentParent = GetComponentInParent<SnapManager>().transform; if (currentSnapManager == null) { SnapManager nearestSnap = Utils.GetNearestSnapManager(this); if (nearestSnap != null) { currentParent = nearestSnap.transform; } } return(currentParent); }
/** * Used for reversing a replinishing event */ public void DeplinishStock(MoveTypes moveType = MoveTypes.NORMAL) { SnapManager stockSnapManager = stock.GetComponentInChildren <SnapManager>(); Card[] stockCards = stockSnapManager.GetCardSet(); for (int i = stockCards.Length - 1; i >= 0; i--) { Card card = stockCards[i]; // Remove from stock card.transform.parent = null; // Move the card position from the stock to the talon card.transform.position = new Vector3( m_talonPile.position.x, m_talonPile.position.y, card.transform.position.z ); // Rotate the card to be face up if (card.IsFaceDown()) { card.Flip(false); } // Add the card to the talon card.transform.parent = m_talonPile; } // Track deplinish event if (moveType.Equals(MoveTypes.NORMAL)) { Move move = new Move(); move.SetSpecial(true); Event ev = new Event(); ev.SetType(Event.EventType.DEPLINISH); move.AddEvent(ev); AddMove(move, MoveTypes.NORMAL); } }
/** * */ private void HandleTouchUp(Touch touch) { // Don't process if dragging isn't currently allowed if (!DraggingIsAllowed()) { Init(); return; } // Don't process if target card is performing an animation if (m_isDoingAnimation) { Init(); return; } if (m_isCard || (m_currentObject != null && m_currentObject.CompareTag("Snap"))) { m_screenPoint = Camera.main.ScreenToWorldPoint(new Vector3(touch.position.x, touch.position.y, 10)); //Vector3 curPosition = Camera.main.ScreenToWorldPoint(m_screenPoint) + m_offset; Vector3 curPosition = m_screenPoint; if (GameManager.DEBUG_MODE) { Debug.Log("Stopped dragging at: " + curPosition); Debug.Log("Starting point was: " + m_startPos); } // Mouse up will be determined as a click if the current position is the same as the start position if (IsClick(curPosition)) { if (m_currentObject.CompareTag("Snap")) { if (m_currentObject.transform.parent.CompareTag("Stock")) { // Only way to get to this point is if the stock was clicked and there are no cards on it // Transfer all cards attached to talon back to stock GameManager.Instance.SetBlocked(true); GameManager.Instance.ReplinishStock(); } } else { Card cardOfInterest = m_currentObject.GetComponent <Card>(); if (cardOfInterest.GetStartParent() != null) { string cardParentSetTag = cardOfInterest.GetStartParent().parent.tag; // Determine if double click float timeDiff = Time.timeSinceLevelLoad - m_timeSinceLastClick; if (GameManager.DEBUG_MODE) { Debug.Log("Time difference since last click: " + timeDiff); } bool doubleClick = (m_timeSinceLastClick >= 0) && timeDiff <= CLICK_DIFF_TIME_THRESHOLD; Transform nextMove = null; // Don't apply double-click logic to stock // Also don't permit click spamming for drawing cards (use game manager action/event block) if (cardParentSetTag.Equals("Stock") && !GameManager.Instance.IsBlocked()) { // Move the card to the talon pile once it has been clicked on the stock (draw card) GameManager.Instance.SetBlocked(true); // Place temporary lock to prevent concurrent actions/events cardOfInterest.MoveTo(GameManager.Instance.GetTalonPile()); } else if (doubleClick || SettingsManager.Instance.IsSingleTapAutoCompleteTrigger()) { // Determine the next valid move. Supply the dragged cards count so prevent the scenario in which // more than one card is dragged to a foundation in one event. nextMove = GameManager.Instance.GetNextAvailableMove(cardOfInterest, m_draggedCards.Length); if (GameManager.DEBUG_MODE) { Debug.Log("Next Move: " + nextMove); } // If double click and there is a valid next move // Then, automatically move the double clicked card to the most appropriate location. if (nextMove) { // Move all cards in set of dragged cards (can be 1) GameManager.Instance.SetBlocked(true); // Place temporary lock to prevent concurrent actions/events cardOfInterest.MoveTo(nextMove, m_draggedCards); } } // Handle cleanup case if (!cardParentSetTag.Equals("Stock") && !nextMove) { // Need to set the parent back to the original parent for card(s) in the set of dragged cards. foreach (Card card in m_draggedCards) { card.transform.parent = card.GetStartParent(); // Ensure all mesh colliders are re-enabled (corner case when double clicking a face down card) card.GetComponent <MeshCollider>().enabled = true; } // Unblock actions/events since invalid click GameManager.Instance.SetBlocked(false); } } } // Keep track of the time of last click m_timeSinceLastClick = Time.timeSinceLevelLoad; return; } // Don't allow dropping stock cards or face-down cards Card cardCheck = m_currentObject.GetComponent <Card>(); bool valid = !m_isStockCard && cardCheck != null && !cardCheck.IsFaceDown(); // Validate the dragged location to determine if the card should be snapped back to original location // or snapped to the respective target (e.g., attempted drag location) Vector3 collisionVector = new Vector3(10.0f, 10.0f, 1000.0f); bool collides = Physics.CheckBox(curPosition, collisionVector); if (collides && valid) { Collider[] hitColliders = Physics.OverlapBox(curPosition, collisionVector); int i = 0; while (i < hitColliders.Length) { Transform collidedTransform = hitColliders[i].GetComponent <Transform>(); if (GameManager.DEBUG_MODE) { Debug.Log("Would collide with object: " + collidedTransform); } // Snap to the snap location if there is one if (collidedTransform.CompareTag("Snap")) { // Don't allow dropping dragged cards in prohibited locations SnapManager snapManager = collidedTransform.GetComponent <SnapManager>(); if (GameManager.PROHIBITED_DROP_LOCATIONS.Contains(collidedTransform.parent.tag)) { if (GameManager.DEBUG_MODE) { Debug.Log("Can't manually drop card in " + collidedTransform.parent.tag); } valid = false; break; } // Make sure there isn't already a card attached to the snap (otherwise need to search for card) if (snapManager.HasCard()) { if (GameManager.DEBUG_MODE) { Debug.Log("Snap already has a card, skipping..."); } } else { if (GameManager.DEBUG_MODE) { Debug.Log("Placing card(s) in: " + collidedTransform.parent.tag); } // Set the new position relative to the snap, adjusting the z value appropriately Vector3 newPos = new Vector3( collidedTransform.position.x, collidedTransform.position.y, -1.0f // Set to a z value of -1 for initial card in stack ); // Need to iterate the set of dragged cards and adjust the position accordingly bool isFoundation = collidedTransform.parent.CompareTag("Foundations"); // Assert that there is only one card being placed if target is foundation if (isFoundation && m_draggedCards.Length > 1) { if (GameManager.DEBUG_MODE) { Debug.Log("Cannot move more than one card at once to a foundation."); } valid = false; break; } // General validation step to take card value and suit into consideration valid = snapManager.IsValidMove(m_draggedCards[0]); if (valid) { float yOffset = isFoundation ? 0.0f : GameManager.FOUNDATION_Y_OFFSET; int j = 0; foreach (Card card in m_draggedCards) { Vector3 cardPosition = card.transform.position; Vector3 newCardPos = new Vector3(newPos.x, newPos.y - (yOffset * j), newPos.z - j); card.transform.position = newCardPos; // Add the card to the stack card.transform.parent = collidedTransform; // Re-enable the mesh colliders on the cards card.GetComponent <MeshCollider>().enabled = true; j++; } } break; } } else if (collidedTransform.CompareTag("Card")) { // Determine if the card was the same one that is being dragged/dropped if (collidedTransform.Equals(m_currentObject.transform)) { if (GameManager.DEBUG_MODE) { Debug.Log("Collided object is self, skipping..."); } } else { // Get the card object to determine if the respective card is stackable Card targetCard = collidedTransform.GetComponent <Card>(); if (!targetCard.IsStackable()) { if (GameManager.DEBUG_MODE) { Debug.Log("Card is not stackable, skipping..."); } } else { // Reference the snap manager the card is attached to SnapManager snapManager = targetCard.GetComponentInParent <SnapManager>(); if (GameManager.DEBUG_MODE) { Debug.Log("Placing card(s) in: " + collidedTransform.parent.parent.tag); } bool isFoundation = collidedTransform.parent.parent.CompareTag("Foundations"); // Assert that there is only one card being placed if target is foundation if (isFoundation && m_draggedCards.Length > 1) { if (GameManager.DEBUG_MODE) { Debug.Log("Cannot move more than one card at once to a foundation."); } valid = false; break; } // General validation step to take card value and suit into consideration valid = snapManager.IsValidMove(m_draggedCards[0]); if (valid) { float yOffset = isFoundation ? 0.0f : GameManager.FOUNDATION_Y_OFFSET; // Offset y position by specified foundation y-offset // so that the card that is below is still shown Vector3 newPos = new Vector3( collidedTransform.position.x, collidedTransform.position.y - yOffset, collidedTransform.position.z - 1.0f ); // Need to iterate the set of dragged cards and adjust the position accordingly int j = 0; foreach (Card card in m_draggedCards) { Vector3 cardPosition = card.transform.position; Vector3 newCardPos = new Vector3(newPos.x, newPos.y - (yOffset * j), newPos.z - j); card.transform.position = newCardPos; // Add the card to the stack (note that the parent is not the collided transform) card.transform.parent = collidedTransform.parent; // Re-enable the mesh colliders on the cards card.GetComponent <MeshCollider>().enabled = true; j++; } } break; } } } else { // If collided with anything else other than a card or a snap then deemed as invalid valid = false; } i++; } } // Need to do one last check to determine if the cards were moved to the same location if (valid) { Card topCard = m_draggedCards[0]; Vector3 topCardStartPos = topCard.GetStartPos(); valid = !(topCard.transform.position.x == topCardStartPos.x && topCard.transform.position.y == topCardStartPos.y); } if (!valid) { if (GameManager.DEBUG_MODE) { Debug.Log("Invalid Move."); } // If the drag location is deemed invalid then we should snap back to starting position // Need to iterate the list of dragged cards and set each card back to their respective // starting position and starting parent if (m_draggedCards != null) { foreach (Card card in m_draggedCards) { // Hanle corner case for when origin was the stock pile if (m_originSnapManager.BelongsTo(GameManager.Sections.STOCK)) { Vector3 startPos = card.GetStartPos(); bool samePos = card.transform.position.x == startPos.x && card.transform.position.y == startPos.y; // Only handle this corner case if the card's curren position isn't the same // as it's starting position. if (!samePos) { Transform talonTransform = GameManager.Instance.GetTalonPile(); card.transform.position = talonTransform.position; card.transform.parent = talonTransform; } } else { card.transform.position = card.GetStartPos(); card.transform.parent = card.GetStartParent(); } // Re-enable the mesh colliders on the cards card.GetComponent <MeshCollider>().enabled = true; } } } else { // Register the manual move if it was valid Move move = new Move(); move.SetCards(m_draggedCards); move.SetPreviousParent(m_originSnapManager.transform); move.SetNextParent(m_draggedCards[0].transform.parent); GameManager.Instance.AddMove(move, Move.MoveTypes.NORMAL); // Play the card set sound one shot so that other clips can play at the same time AudioSource cardSetSound = SettingsManager.Instance.cardSetSound; cardSetSound.PlayOneShot(SettingsManager.Instance.cardSetSoundClip); // Track the total number of moves with stats manager StatsManager.Instance.TallyMove(); } // Remove temporary locks set during dragging if (m_dragged) { // Can stop waiting now that the move is complete // Evaluate only if origin snap manager isn't null if (m_originSnapManager != null) { m_originSnapManager.SetWaiting(false); } GameManager.Instance.SetBlocked(false); m_dragged = false; } } // Always initialize as a last step Init(); }
/** * */ private void HandleTouchDown(Touch touch) { // Don't process if dragging isn't currently allowed if (!DraggingIsAllowed()) { return; } Ray raycast = Camera.main.ScreenPointToRay(touch.position); if (Physics.Raycast(raycast, out RaycastHit raycastHit)) { m_screenPoint = Camera.main.ScreenToWorldPoint(new Vector3(touch.position.x, touch.position.y, 10)); m_startPos = m_screenPoint; m_currentObject = raycastHit.collider.gameObject; m_isCard = raycastHit.collider.CompareTag("Card"); if (m_isCard) { // Assert that the card isn't face down (permit if card is in stock pile) Card targetCard = m_currentObject.GetComponent <Card>(); SnapManager parentSnap = targetCard.GetComponentInParent <SnapManager>(); // Don't deem as card if the target card is face down and doesn't belong to the stock m_isCard = !(targetCard.IsFaceDown() && !parentSnap.BelongsTo(GameManager.Sections.STOCK)); } } // If card, we need to get a list of the cards that are to be dragged (through the use of the Snap Manager) if (m_isCard && m_currentObject.transform.parent != null) { Card targetCard = m_currentObject.GetComponent <Card>(); m_isDoingAnimation = targetCard.IsTranslating() || targetCard.IsFlipping(); if (m_isDoingAnimation) { if (GameManager.DEBUG_MODE) { Debug.Log("Card is doing an animation and cannot be dragged!"); } return; } // Initialize the dragged cards list by referencing the set of cards that are attached to the // respective snap that one or many cards are to be dragged from. m_draggedCards = m_currentObject.GetComponentInParent <SnapManager>().GetCardSet(targetCard); if (m_draggedCards != null && m_draggedCards.Length > 0) { // Check the first card to see if it's a stock card if (GameManager.DEBUG_MODE) { Debug.Log("Tag Clicked: " + m_draggedCards[0].transform.parent.parent.tag); } m_isStockCard = m_draggedCards[0].transform.parent.parent.CompareTag("Stock"); if (GameManager.DEBUG_MODE) { Debug.Log("Is Stock Card: " + m_isStockCard); } // Set each dragged card's start position and parent int i = 0; m_originSnapManager = m_draggedCards[0].GetComponentInParent <SnapManager>(); m_originSnapManager.SetWaiting(true); // Wait until cards are dropped and validated before flipping any cards in tableau foreach (Card card in m_draggedCards) { card.SetStartPos(card.transform.position); card.SetStartParent(card.transform.parent); // Temporarily disable the mesh collider for all cards except the first one in the set of dragged cards. if (i != 0) { card.GetComponent <MeshCollider>().enabled = false; } i++; } } } else { // Only initialize if not a snap if (!m_currentObject.CompareTag("Snap")) { Init(); } } }
/** * Perform the core function for running the auto complete process. * This coroutine will rapidly move cards from the tableau to the foundation * and automatically complete the game once a valid winning state has been * determined by the system. */ private IEnumerator AutoWinCoroutine() { SetDoingAutoWin(true); int attempts = 0; int maxAttempts = 5000; // Build min priority queue based on all cards in tableau (prioritize lower value cards) PriorityQueue <Card> cardQueue = new PriorityQueue <Card>(true); // Add max attempts in case there is some corner case that occurs and causes a fail while (attempts < maxAttempts) { yield return(new WaitForEndOfFrame()); // Break out of the loop if the win state has been met if (HasWon()) { break; } SnapManager[] tableauSnaps = tableau.GetComponentsInChildren <SnapManager>(); foreach (SnapManager tableauSnap in tableauSnaps) { // Get only the top card for now Card topCard = tableauSnap.GetTopCard(); if (topCard != null) { cardQueue.Enqueue(topCard.value, topCard); } } // Dequeue cards from priority queue and move each one to the foundation while (cardQueue.Count > 0) { Card priorityCard = cardQueue.Dequeue(); Transform nextMove = GetNextAvailableMove(priorityCard); // Only process move if one existed and if it is to a foundation if (nextMove) { SnapManager currentSnapManager = priorityCard.GetComponentInParent <SnapManager>(); SnapManager nextSnapManager = nextMove.GetComponent <SnapManager>(); bool validMove = nextSnapManager.belongingSection.Equals(Sections.FOUNDATIONS); if (validMove) { // Make note of the current amount of attached cards int currentCardCount = nextSnapManager.GetCardCount(); priorityCard.MoveTo(nextMove); // Wait until the card is finished translating, is attached to the snap, and the current // card count has incremented by one yield return(new WaitUntil(() => { return priorityCard.transform.parent != null && !priorityCard.IsTranslating() && nextSnapManager.GetCardCount() >= (currentCardCount + 1); })); // Add the current snap manager's top card to the priority queue Card nextTopCard = currentSnapManager.GetTopCard(); if (nextTopCard != null) { cardQueue.Enqueue(nextTopCard.value, nextTopCard); } } } } attempts++; } SetDoingAutoWin(false); m_autoWinComplete = true; }
private void HandleTranslation() { if (m_translating) { float zOffset = m_flipping ? GameManager.Z_OFFSET_DRAGGING / 2.0f : GameManager.Z_OFFSET_DRAGGING; if (m_draggedCards != null && m_draggedCards.Length > 1) { foreach (Card card in m_draggedCards) { // Ensure that the z-offset is applied to the target translation position to avoid clipping Vector3 modTargetPos = card.GetTargetTranslatePosition(); modTargetPos = new Vector3( modTargetPos.x, modTargetPos.y, -(Mathf.Abs(modTargetPos.z) + zOffset) ); // Use linear interpolation (lerp) to move from point a to point b within a specific amount of time card.transform.position = Vector3.Lerp( card.GetStartPos(), modTargetPos, m_totalTime ); // Stop translating once the total time has elapsed for linear interpolation m_translating = m_totalTime < 1.0f; } } else { // Ensure that the z-offset is applied to the target translation position to avoid clipping Vector3 modTargetPos = new Vector3( m_targetTranslatePos.x, m_targetTranslatePos.y, -(Mathf.Abs(m_targetTranslatePos.z) + zOffset) ); // Use linear interpolation (lerp) to move from point a to point b within a specific amount of time transform.position = Vector3.Lerp( GetStartPos(), modTargetPos, m_totalTime ); // Stop translating once the total time has elapsed for linear interpolation m_translating = m_totalTime < 1.0f; // Only flip card if it's face down and processing normal move if (currentState.Equals(CardState.FACE_DOWN) && m_moveType.Equals(Move.MoveTypes.NORMAL)) { SnapManager targetSnapManager = m_targetTranslateSnap.GetComponent <SnapManager>(); // Flip the card with an animation Flip(); // Stage the event Event evt = new Event(); evt.SetType(Event.EventType.FLIP); evt.SetCard(this); // Setting relative snap manager to this instance for locking when reversing event evt.SetRelativeSnapManager(targetSnapManager); GameManager.Instance.AddEventToLastMove(evt); } } // Accumulate total time with respect to the card translation speed m_totalTime += Time.deltaTime / GameManager.Instance.GetCardTranslationSpeed(); // Perform final steps after translation is complete if (!m_translating) { // Play the card set sound one shot so more than one clip can play at a time SettingsManager.Instance.cardSetSound.PlayOneShot(SettingsManager.Instance.cardSetSoundClip); SnapManager targetSnapManager = m_targetTranslateSnap.GetComponent <SnapManager>(); if (m_draggedCards != null && m_draggedCards.Length > 1) { // Don't need to check current state when dragging more than one card // since the only case when the card is face down is if it came from the // stock pile. foreach (Card card in m_draggedCards) { // Place the card in the respective snap parent (this ensures proper card order) card.transform.parent = m_targetTranslateSnap; // Re-enable the mesh colliders on the cards card.GetComponent <MeshCollider>().enabled = true; } } else { // Only reattach to parent here if this card is not presently flipping if (!m_flipping) { transform.parent = m_targetTranslateSnap; // Re-enable the mesh colliders on this card GetComponent <MeshCollider>().enabled = true; } } // Need to remove any locks and blocks on parent snap manager and game manager instance caused by events targetSnapManager.SetWaiting(false); GameManager.Instance.SetBlocked(false); // Also tell the original snap manager to stop waiting if it is if (m_startParent != null) { m_startParent.GetComponent <SnapManager>().SetWaiting(false); } // Reset the total time for correct linear interpolation (lerp) m_totalTime = 0.0f; } } }
public CardState Flip(bool animate = true) { m_flipping = true; m_flipped = !m_flipped; currentState = m_flipped ? CardState.FACE_UP : CardState.FACE_DOWN; // Keep track of original parent so that it can be restored after flipping m_originalParent = transform.parent; // Need to detatch from parent to avoid odd clipping behavior // Will re-attach once any animations complete transform.SetParent(null); // Need to temporarily disable mesh collider and remove from parent when doing rotation MeshCollider meshCollider = gameObject.GetComponent <MeshCollider>(); meshCollider.enabled = false; if (animate) { // Need to tell the snap manager parent to wait until animation is done if (m_originalParent != null) { SnapManager snapManager = m_originalParent.GetComponent <SnapManager>(); if (snapManager != null) { snapManager.SetWaiting(true); } } // Handle corner case when original parent is null and when card came from stock else { if (m_startParent != null) { SnapManager startSnapManager = m_startParent.GetComponent <SnapManager>(); // Need to set original parent to talon pile so the card doesn't snap back to stock if (startSnapManager.BelongsTo(GameManager.Sections.STOCK)) { m_originalParent = GameManager.Instance.GetTalonPile(); } } } transform.position = new Vector3( transform.position.x, transform.position.y, -(Mathf.Abs(transform.position.z) + Mathf.Abs(GameManager.Z_OFFSET_DRAGGING)) ); // Implement flip animation string trigger = m_flipped ? "FlipFaceUp" : "FlipFaceDown"; m_animator = GetComponent <Animator>(); m_animator.SetTrigger(trigger); AudioSource cardFlipSound = SettingsManager.Instance.cardFlipSound; cardFlipSound.PlayOneShot(SettingsManager.Instance.cardFlipSoundClip); } else { int degrees = m_flipped ? 180 : 0; // Flip the card 180 degrees about the y axis transform.rotation = Quaternion.Euler(0, degrees, 0); transform.SetParent(m_originalParent); m_flipping = false; } // Re-enable the mesh collider meshCollider.enabled = true; return(currentState); }
/** * Move this card instance and/or other cards in it's card set to the specified target snap transform * @param Transform snap the target snap transform to move this card to * @param Card[] cardSet the set of dragged cards to handle translation all at once * with respect to this card instance. Defaults to null if a card set is not provided. * If the card set has only one card in it then it's assumed that the one card is * this card instance and will be processed as such. * @param MoveTypes moveType the type of move that determines how the move should be tracked in the GameManager. */ public void MoveTo(Transform snap, Card[] cardSet = null, Move.MoveTypes moveType = Move.MoveTypes.NORMAL) { // Prepare the move object m_move = new Move(); m_moveType = moveType; // Set the target card based on value of card set // (if card set is null then create a new card set with this card as the only element) m_move.SetCards(cardSet ?? (new Card[] { this })); // We know that the card has/had a parent m_move.SetPreviousParent(m_startParent); // Need to get what the snap belongs to so that the card is placed in the correct location SnapManager snapManager = snap.GetComponent <SnapManager>(); bool faceDownTarget = snapManager.HasCard() && snapManager.GetTopCard().IsFaceDown(); GameManager.Sections targetSection = snapManager.belongingSection; // Set the next parent in the move m_move.SetNextParent(snapManager.transform); // Need to target the top card in the respective tableau pile and offset the y and z positions Transform tableauHasCardTarget = targetSection.Equals(GameManager.Sections.TABLEAU) && snapManager.HasCard() ? snapManager.GetTopCard().transform : snap; // Setting for reference to new parent snap m_targetTranslateSnap = snap; m_targetTranslatePos = m_targetTranslateSnap.position; // Defaults to target snap position // Keep track of the starting position m_startPos = transform.position; m_draggedCards = cardSet; // Tell the snap manager currently associated with the card(s) to wait until animations are complete SnapManager currentSnap = GetComponentInParent <SnapManager>(); if (currentSnap != null) { // Set the start parent here so that the current snap can be told to stop waiting later SetStartParent(currentSnap.transform); currentSnap.SetWaiting(true); } // Process a bit differently if a card set has been provided if (m_draggedCards != null && m_draggedCards.Length > 1) { // Do a first pass-through to remove parent and bring z-value of each of the dragged cards // to the z-offset dragging value for (int i = 0; i < m_draggedCards.Length; i++) { Card draggedCard = m_draggedCards[i]; draggedCard.transform.parent = null; // Keep track of each card's starting position draggedCard.SetStartPos(draggedCard.transform.position); float yOffset; // Apply y-offset when dragging multiple cards (start without y-offset if there isn't a card on the snap) // Handle case when action was an undo and the top card in the target snap is facedown // (only the first card in the the set of dragged cards should have the face down y-offset applied in this case). if (faceDownTarget && i == 0) { yOffset = GameManager.FACE_DOWN_Y_OFFSET; } else { if (faceDownTarget) { // Need to compensate for the fact that the first card applied face down y-offset yOffset = (GameManager.FOUNDATION_Y_OFFSET * i) + GameManager.FACE_DOWN_Y_OFFSET; } else { // Process normally (e.g., not undoing a flip event) yOffset = GameManager.FOUNDATION_Y_OFFSET * (snapManager.HasCard() ? i + 1 : i); } } Vector3 newTargetPos = new Vector3( tableauHasCardTarget.position.x, tableauHasCardTarget.position.y - yOffset, tableauHasCardTarget.position.z - (i + 1) ); // Set the new translate position for the dragged card draggedCard.SetTargetTranslatePosition(newTargetPos); // Set the z-value of the transform to move to be high enough to hover over all other cards draggedCard.transform.position = new Vector3( draggedCard.transform.position.x, draggedCard.transform.position.y, -(GameManager.Z_OFFSET_DRAGGING + i) ); } } else // Otherwise, process on one card { // transform position is a special case for the Tableau cards due to y-offset in addition to z-offset if (targetSection.Equals(GameManager.Sections.TABLEAU) && snapManager.HasCard()) { Vector3 newTargetPos = new Vector3( tableauHasCardTarget.position.x, tableauHasCardTarget.position.y - (faceDownTarget ? GameManager.FACE_DOWN_Y_OFFSET : GameManager.FOUNDATION_Y_OFFSET), tableauHasCardTarget.position.z - 1 ); m_targetTranslatePos = newTargetPos; } transform.parent = null; // Temporarily detatch from the parent SetStartPos(transform.position); // Keep track of this card instance start position // Set the z-value of the transform to move to be high enough to hover over all other cards transform.position = new Vector3( transform.position.x, transform.position.y, -GameManager.Z_OFFSET_DRAGGING ); } // Add the move to the game manager instance (only if normal move and not undone or redone) if (moveType == Move.MoveTypes.NORMAL) { GameManager.Instance.AddMove(m_move, moveType); } // Track the total number of moves with stats manager StatsManager.Instance.TallyMove(); // Begin the translating animation m_translating = true; }