private void OnRingAskingToBeSelected(SelectableRing ring) { if (!isStarted) { //the exercise hasn't started yet return; } //Collision to the pin of the ring selected (to avoid innecesary animations) lastPinWithCollision = pins[ring.pin].GetInstanceID(); //Only the last ring can be selected if (pins[ring.pin].ringPeek().GetInstanceID() == ring.GetInstanceID()) { //Removing the ring from his current Pin so it can be moved pins[ring.pin].ringPop(); ring.SelectionAllowed(); aRingIsSelected = true; } #if UNITY_EDITOR else { aRingIsSelected = true; //For QA (have fun Roy!) QA_OnRingAskingToBeSelected(ring); } #endif }
/** * Add a ring to be used on the exercise **/ public void AddRingReference(SelectableRing ring) { rings.Add(ring); //Ring delegates ring.OnCanceled += OnRingSelectionCanceled; ring.AskSelectionPermit += OnRingAskingToBeSelected; ring.OnDropped += OnRingDropped; }
/** * Remove and return the last ring (Last In First Out) **/ public SelectableRing ringPop() { if (!isEmpty()) { SelectableRing result = ringsStack[ringsStack.Count - 1]; ringsStack.RemoveAt(ringsStack.Count - 1); return(result); } return(null); }
private IEnumerator DoSteps() { Vector3 pos; float duration; float moveDuration = intoPinAnimation.duration; //Lets make ir faster intoPinAnimation.duration = intoPinAnimation.duration * 0.85f; while (currentSolutionStep < solutionSteps.Count) { SelectableRing ring = solutionSteps[currentSolutionStep].ring.ringReference; Pin from = solutionSteps[currentSolutionStep].from.pinReference; Pin to = solutionSteps[currentSolutionStep].to.pinReference; //Logic status from.ringPop(); AddRingToPin(ring, to.index); movesCount++; //visual ststus ring.DoSelectionEffect(); //A little wait yield return(new WaitForSeconds(0.15f)); //Alittle move upward pos = ring.transform.position; pos.y += separationBetweenRings; duration = intoPinAnimation.duration; intoPinAnimation.duration = 0.1f; intoPinAnimation.target = ring.transform; intoPinAnimation.destination = pos; intoPinAnimation.Play(); yield return(new WaitForSeconds(0.11f)); intoPinAnimation.duration = duration; PositionateRingOnPin(ring, to.index, to.ringCount(), true); //We wait for the visuals again yield return(new WaitForSeconds(intoPinAnimation.duration * 0.85f)); ring.SortingOrderForSelection(false); currentSolutionStep++; } intoPinAnimation.duration = moveDuration; CheckIfExerciseIsCompleted(solutionSteps[solutionSteps.Count - 1].to.index); }
private void QA_OnRingAskingToBeSelected(SelectableRing ring) { if (!multipleSelectionAllowed) { return; } Pin pin = pins[ring.pin]; multipleRingSelection.Clear(); //Select the ring and everything above him int selectedIndex = -1; for (int i = 0; i < pin.ringsStack.Count; i++) { //Search for the selected ring if (selectedIndex < 0) { if (pin.ringsStack[i].GetInstanceID() == ring.GetInstanceID()) { selectedIndex = i; multipleRingSelection.Add(pin.ringsStack[i]); } } else { //Every ring after the selected should be added multipleRingSelection.Add(pin.ringsStack[i]); } } //Remove all the selected rings from the pin pin.ringsStack.RemoveRange(selectedIndex, multipleRingSelection.Count); //All the selected rings follow the movements of the one selected by the input StartCoroutine("MultipleSelectionVisualUpdate"); //Allow selection and visually select the extra rings ring.SelectionAllowed(); foreach (SelectableRing r in multipleRingSelection) { r.DoSelectionEffect(); } isMultipleSelectionActive = true; }
/** * Search among the ringNodes for the one that has a reference that matched with the one provided **/ private RingNode getRingNodeFromReference(SelectableRing reference) { foreach (RingNode ring in rings) { /* * WARNING: We found a bug using GetInstanceID in getPinContainingRing and change it for a size comparation * but since the size of this reference it is not guaranteed to be always the same we hope for the best */ if (ring.ringReference.GetInstanceID() == reference.GetInstanceID()) { return(ring); } } return(null); }
/** * Animation effect to move the ring over the pin **/ public void MoveRingOverPinEffect(SelectableRing ring, int pinIndex) { //Pin position Vector3 expectedPosition = pins[pinIndex].transform.position; //Y based on the pin height expectedPosition.y = pinHeightReference.position.y; //Coroutine params EffectParams effectParams = new EffectParams(); effectParams.ring = ring; effectParams.pin = pins[pinIndex]; effectParams.ringIndex = pins[pinIndex].ringCount(); overPinAnimation.destination = expectedPosition; overPinAnimation.target = ring.transform; overPinAnimation.Play(); StartCoroutine("WaitingForMoveRingOverEffectToFinish", effectParams); }
/** * Visual positionation of the ring on the indicated pin. * **/ public void PositionateRingOnPin(SelectableRing ring, Pin pin, int ringIndex, bool animate = false) { //Pin position Vector3 expectedPosition = pin.transform.position; //Ring sorting order (so the rings dont overlap) ring.setFrontSortingOrder(ringIndex); //Y position based on the ring index expectedPosition.y += (ringIndex - 1) * separationBetweenRings; if (animate) { intoPinAnimation.destination = expectedPosition; intoPinAnimation.target = ring.transform; intoPinAnimation.OnAnimationComplete += AfterDropAnimation; //some effects after the animation intoPinAnimation.Play(); } else { ring.transform.position = expectedPosition; } }
/** * When the selection was canceled by game external factors **/ private void OnRingSelectionCanceled(SelectableRing ring) { if (!isStarted) { //the exercise hasn't started yet return; } aRingIsSelected = false; //Return the ring to his previous position AddRingToPin(ring, ring.pin); //TODO Without animation? We have to review the possible causes for a touch cancel and then decide PositionateRingOnPin(ring, ring.pin, pins[ring.pin].ringCount(), false); //visual add //QA: If there is a multiple selection active then this should be managed #if UNITY_EDITOR if (isMultipleSelectionActive) { //Stop the visual updating StopCoroutine("MultipleSelectionVisualUpdate"); //Every ring back to his previous pin for (int i = 1; i < multipleRingSelection.Count; i++) { AddRingToPin(multipleRingSelection[i], ring.pin); //logical //TODO Without animation? We have to review the possible causes for a touch cancel and then decide PositionateRingOnPin(multipleRingSelection[i], ring.pin, pins[ring.pin].ringCount(), false); //visual } //Stop multiple selection isMultipleSelectionActive = false; } #endif }
/** * Add the ring to the indicated pin without validation. **/ public void AddRingToPin(SelectableRing ring, int pinIndex) { ring.pin = pinIndex; pins[pinIndex].ringPush(ring); }
/** * Visual positionation of the ring on the indicated pin. **/ public void PositionateRingOnPin(SelectableRing ring, int pinIndex, int ringIndex, bool animate = false) { PositionateRingOnPin(ring, pins[pinIndex], ringIndex, animate); }
private void OnRingDropped(SelectableRing ring) { if (!isStarted) { //the exercise hasn't started yet return; } aRingIsSelected = false; //check if the ring was dropped on a pin if (lastPinWithCollision != -1) { //The ring were dropen in the lastPinWithCollision ring for (int i = 0; i < pins.Count; i++) { if (pins[i].GetInstanceID() == lastPinWithCollision) { //Pin found /* * Lets see is this ring could be dropped here. * The ring can only be droopped on empty Pins or when the last ring on the pin * is smaller. */ if (pins[i].isEmpty() || pins[i].ringPeek().sizeIndicator >= ring.sizeIndicator) { //Allowed //we count the move only if the ring is dropped on another pin if (ring.pin != i) //the ring remember the previous pin until a new one is added { movesCount++; } AddRingToPin(ring, i); //loginc add PositionateRingOnPin(ring, i, pins[i].ringCount(), true); //visual add //QA: If there is a multiple selection active then we manage it #if UNITY_EDITOR if (isMultipleSelectionActive) { //The visual position should not be modified since every ring is folowing the selected one for (int j = 1; j < multipleRingSelection.Count; j++) { //Add the selected rings to the pin AddRingToPin(multipleRingSelection[j], i); //loginc add //Z sorting for all the extra selected rings(so the rings dont overlap) multipleRingSelection[j].setFrontSortingOrder(pins[i].ringCount()); multipleRingSelection[j].SortingOrderForSelection(false); } } #endif //if this isn't the starter pin then we check if the exercise is completed if (starterPin != i) { CheckIfExerciseIsCompleted(i); } break; } else { //Denied soundManager.PlayFX("denied"); //The ring is returned to his previous Pin AddRingToPin(ring, ring.pin); //loginc add MoveRingOverPinEffect(ring, ring.pin); //visual add //QA: If there is a multiple selection active then we manage it #if UNITY_EDITOR if (isMultipleSelectionActive) { //The visual position should not be modified since every ring is folowing the selected one for (int j = 1; j < multipleRingSelection.Count; j++) { //Add the selected rings to the pin AddRingToPin(multipleRingSelection[j], ring.pin); //loginc add //Z sorting for all the extra selected rings(so the rings dont overlap) multipleRingSelection[j].setFrontSortingOrder(pins[ring.pin].ringCount()); multipleRingSelection[j].SortingOrderForSelection(false); } } #endif } } } } else { //Pin dropped on the void //The ring is returned to his previous Pin AddRingToPin(ring, ring.pin); //loginc add MoveRingOverPinEffect(ring, ring.pin); //visual add //QA: If there is a multiple selection active then we manage it #if UNITY_EDITOR if (isMultipleSelectionActive) { //The visual position should not be modified since every ring is folowing the selected one for (int j = 1; j < multipleRingSelection.Count; j++) { //Add the selected rings to the pin AddRingToPin(multipleRingSelection[j], ring.pin); //loginc add //Z sorting for all the extra selected rings(so the rings dont overlap) multipleRingSelection[j].setFrontSortingOrder(pins[ring.pin].ringCount()); multipleRingSelection[j].SortingOrderForSelection(false); } } #endif } //QA #if UNITY_EDITOR if (isMultipleSelectionActive) { //Stop updating the selected rings when the effect finished intoPinAnimation.OnAnimationComplete += QA_OnDroppedAnimationComplete; } #endif }
public int index; //Index reference used in the ExerciseSolver public RingNode(SelectableRing reference, int ringSize) { ringReference = reference; pendingPaths = new List <ExercisePath>(); size = ringSize; }
private void AddRing(SelectableRing ring, int size) { rings.Add(new RingNode(ring, size)); rings[rings.Count - 1].index = rings.Count - 1; }
[HideInInspector] public int index; //Index in the exercise /** * Ring added to the stack */ public void ringPush(SelectableRing ring) { ringsStack.Add(ring); }
/** * Array partition for QuickSort. * * Partition selects a pivot and sort from start to end every value * so the values greater than pivote are to his right and the lesser ones are to his left. * * TODO: Support for reverse sorting order **/ private static int partition(List <SelectableRing> target, int start, int end) { //TODO pick a better pivot //pivot selection (last for simplicity) SelectableRing pivot = target[end - 1]; int left, right; left = start; right = end - 2; //We iterate until all the values greater than pivot are to his right and the lesser ones to his left while (left + 1 < right) { //find a left reference that is greater than pivot while (target[left].sizeIndicator <= pivot.sizeIndicator && left + 1 < right) { left++; } //find a right reference that is lesser than pivot while (target[right].sizeIndicator > pivot.sizeIndicator && right - 1 > left) { right--; } /* * Left is greater than pivot and right is less or equal so we swap. */ if (target[left].sizeIndicator > pivot.sizeIndicator && target[right].sizeIndicator <= pivot.sizeIndicator) { //swap //TODO some XOR optimization SelectableRing tmp = target[left]; target[left] = target[right]; target[right] = tmp; left++; } } //move the pivot to final position that is greater than him if (target[left].sizeIndicator > pivot.sizeIndicator) { //swap //TODO some XOR optimization SelectableRing tmp = target[left]; target[left] = target[end - 1]; target[end - 1] = tmp; //new pivot position return(left); } else if (target[right].sizeIndicator > pivot.sizeIndicator) { //swap //TODO some XOR optimization SelectableRing tmp = target[right]; target[right] = target[end - 1]; target[end - 1] = tmp; //new pivot position return(right); } //the pivote doesn't move return(end - 1); }