// To be called after dropping a fragment and snapping to other fragments // Check and handle victory condition bool CheckVictory() { // A fragment group should contain all fragments, otherwise we haven't won yet if (fragments.Count != fragments[0].fragmentGroup.fragments.Count) { return(false); } // Victory! MicrogameController.instance.setVictory(victory: true, final: true); // Save the starting values for the victory animation victoryStartTime = Time.time; victoryStartPosition = fragments[0].transform.position; victoryStartRotation = fragments[0].transform.eulerAngles; backgroundMask.position = victoryStartPosition; // Replace the mask fragments with the assembled model foreach (MaskPuzzleMaskFragment fragment in fragments) { fragment.gameObject.SetActive(false); } MaskPuzzleMaskFragment assembledMask = Instantiate( chosenMask.assembled, Vector2.zero, Quaternion.identity ).transform.GetChild(0).GetComponent <MaskPuzzleMaskFragment>(); assembledMask.fragmentsManager = this; assembledMask.gameObject.layer = FIRST_MASK_LAYER; assembledMask.VictoryAnimation(); return(true); }
public MaskPuzzleFragmentGroup(MaskPuzzleMaskFragment initialFragment) { fragments = new List <MaskPuzzleMaskFragment>(); fragments.Add(initialFragment); // Create a new camera for this group by cloning the main camera // A separate camera for each group is needed so they don't clip into each other // Drawing order is determined by the camera depth assignedCamera = Camera.Instantiate(Camera.main); assignedCamera.GetComponent <AudioListener>().enabled = false; assignedCamera.clearFlags = CameraClearFlags.Depth; assignedCamera.cullingMask = 1 << initialFragment.gameObject.layer; assignedCamera.depth = .1f; }
// To be called when dropping a mask // Checks whether any other fragments are near the drop position // If yes, snaps the fragments of this group to them by making their positions equal // and joins their groups public bool SnapToOtherFragments() { bool connected = false; for (int i = 0; i < fragments[0].fragmentsManager.fragments.Count; i++) { MaskPuzzleMaskFragment checkedFragment = fragments[0].fragmentsManager.fragments[i]; // Check if already connected if (fragments.Contains(checkedFragment)) { continue; } // Check distance if (Vector2.Distance(fragments[0].transform.position, checkedFragment.transform.position) > fragments[0].fragmentsManager.maxSnapDistance) { continue; } // Check if the grabbed fragment can be connected to the i-th fragment, // directly or through other already connected fragments Debug.Log("Checking connectability; grabbed group count: " + fragments.Count + "; checked group count: " + checkedFragment.fragmentGroup.fragments.Count); if (fragments[0].fragmentsManager.edges.areConnectable( this, checkedFragment.fragmentGroup)) { // Make positions equal and connect the groups foreach (MaskPuzzleMaskFragment fragment in fragments) { fragment.transform.position = checkedFragment.transform.position; Debug.Log("Snapped " + fragment.name + " to " + checkedFragment.name); } connectTo(checkedFragment.fragmentGroup); Debug.Log("Now the group contains " + fragments.Count + " fragments."); connected = true; } } return(connected); }
// Handle dragging and dropping the fragments void HandleDragging() { // Grabbing a fragment if (grabbedFragmentGroup == null && Input.GetMouseButtonDown(0)) { // Get an array of all the fragments under the cursor Ray mouseRay = Camera.main.ScreenPointToRay(Input.mousePosition); RaycastHit[] hits = Physics.RaycastAll(mouseRay, float.PositiveInfinity, 31 << 14); RaycastHit topHit = new RaycastHit(); MaskPuzzleMaskFragment fragmentHit, topHitFragment = null; float topHitDepth = -1f; float topHitDistance = 0f; // There might be multiple fragments under the cursor // We need to determine which one is on top - that one will be grabbed // We pick the one whose assigned camera has the highest depth // In case of equal depth we pick the fragment closest to the camera foreach (RaycastHit hit in hits) { fragmentHit = hit.collider.GetComponent <MaskPuzzleMaskFragment>(); if (fragmentHit.fragmentGroup.assignedCamera.depth <= topHitDepth) { continue; } if (fragmentHit.fragmentGroup.assignedCamera.depth == topHitDepth && hit.distance >= topHitDistance) { continue; } topHit = hit; topHitFragment = fragmentHit; topHitDepth = fragmentHit.fragmentGroup.assignedCamera.depth; topHitDistance = hit.distance; } if (topHitFragment) { grabbedFragmentGroup = topHitFragment.fragmentGroup; shiftGroupScale(grabbedFragmentGroup, grabScaleIncrease); // Grabbed fragment group should be on top grabbedFragmentGroup.assignedCamera.depth = (topDepth += .005f); // Save the grabbed point's coordinates needed for calculating position when dragging grabZ = topHit.point.z; grabOffset = topHitFragment.transform.position - CameraHelper.getCursorPosition(grabZ); print("Top hit=" + topHitFragment + "; depth=" + topHitDepth + "; dist=" + topHitDistance + "; z=" + topHit.point.z); MicrogameController.instance.playSFX( grabSound, volume: 1f, panStereo: AudioHelper.getAudioPan(topHitFragment.transform.position.x) ); } } // Dropping a fragment else if (grabbedFragmentGroup != null && !Input.GetMouseButton(0)) { shiftGroupScale(grabbedFragmentGroup, -grabScaleIncrease); MicrogameController.instance.playSFX( dropSound, volume: 1f, pitchMult: dropPitchMult, panStereo: AudioHelper.getAudioPan(grabbedFragmentGroup.fragments[0].transform.position.x) ); if (grabbedFragmentGroup.SnapToOtherFragments()) { MicrogameController.instance.playSFX( placeSound, volume: 1f, panStereo: AudioHelper.getAudioPan(grabbedFragmentGroup.fragments[0].transform.position.x) ); if (CheckVictory()) { MicrogameController.instance.playSFX( victorySound, volume: 1f, panStereo: 0f ); } } grabbedFragmentGroup = null; } // Dragging fragments else if (grabbedFragmentGroup != null) { Vector3 position = CameraHelper.getCursorPosition(grabZ); position += grabOffset; foreach (MaskPuzzleMaskFragment fragment in grabbedFragmentGroup.fragments) { fragment.transform.position = position; } } }