public void Init() { OnSelect += () => { //Debug.Log(name + " OnSelect , selectablePaths.Count = " + selectablePaths.Count); //MWB_SelectionQuery.Instance.CleanRegisteredPaths(); //MWB_SelectionQuery.Instance.RegisterPaths(selectablePaths); List <MWB_SelectablePath> previousSelectedPaths = MWB_SelectionQuery.Instance.SelectedPaths; // valid world List <MWB_DummyObjectList> previousSelectedWorlds = new List <MWB_DummyObjectList>(); foreach (MWB_SelectablePath previousSelectedPath in previousSelectedPaths) { MWB_Path t_previousSelectedPath = previousSelectedPath as MWB_Path; MWB_DummyObjectList t_world = t_previousSelectedPath.SourceDummyObject.correspondingDummyList; previousSelectedWorlds.Add(t_world); } List <MWB_SelectablePath> newSelectedPaths = new List <MWB_SelectablePath>(); foreach (MWB_SelectablePath selectablePath in selectablePaths) { MWB_Path t_selectablePath = selectablePath as MWB_Path; if (t_selectablePath.SourceDummyObject != null && previousSelectedWorlds.Contains(t_selectablePath.SourceDummyObject.correspondingDummyList)) { newSelectedPaths.Add(selectablePath); } } MWB_SelectionQuery.Instance.ChangeSelectablePathList(selectablePaths); // pre select some of the paths base on previously selected worlds MWB_SelectionQuery.Instance.SelectPaths(newSelectedPaths); }; OnDeselect += () => { //Debug.Log(name + " OnDeselect "); //MWB_SelectionQuery.Instance.CleanRegisteredPaths(); }; // MWB_PathFactory Factory = MWB_PathFactory.Instance; if (CurrentMainPath == null) { RootPath = CurrentMainPath = Factory.GetPath(); } else { var newPath = Factory.GetSubPath(CurrentMainPath); CurrentMainPath = newPath; } //selectablePaths.Add(RootPath); }
private MWB_DummyObjectList GenerateDummyObjects(MWB_ObjectList objectList, bool isInitializedAsAble) { MWB_DummyObjectList dummyObjectList = new MWB_DummyObjectList(); GameObject parent = new GameObject("initial dummy parent"); parent.transform.parent = dummyMasterParent.transform; // !!! IMPORTANT parent.transform.localPosition = transform.localPosition; parent.transform.localRotation = transform.localRotation; parent.transform.localScale = transform.localScale; // add parent to dummyParent list for clean up ! dummyParentList.Add(parent); // foreach (MWB_Object mwbObject in objectList.MWB_Objects) { GameObject forkedObject = Instantiate(mwbObject.gameObject, parent.transform); // Set layer forkedObject.layer = MWBWaitingLayer; forkedObject.SetActive(isInitializedAsAble); // turning MWB_Object to Dummy Object Destroy(forkedObject.GetComponent <MWB_Object>()); var dummy = forkedObject.AddComponent <MWB_DummyObject>(); dummy.Manager = this; // record object source dummy.objectSource = mwbObject; // record fork source ( initial object has null ) dummy.forkedSource = null; //record corresponding dummy list dummy.correspondingDummyList = dummyObjectList; // set pathIndex //dummy.pathIndex = 0; // record previous transform data segment (initial dummy object has null) dummy.transformDataSegment.previousSegment = null; // use main path to generate sub path dummy.SetSubPath(mwbObject.CurrentMainPath); // assign reference of dummy to path dummy.dummyMainPath.SourceDummyObject = dummy; // dummyObjectList.AddToDummyObjectList(dummy); } return(dummyObjectList); }
private void CleanUp() { m_collidingDummyObjects.Clear(); focusingDummyObjectList = null; forkedFrameNumber.Clear(); // destroy all dummys used for simulation by destroying their parent //foreach (GameObject dummyParent in dummyParentList) //{ // Destroy(dummyParent); //} Destroy(dummyMasterParent); dummyParentList.Clear(); MWB_SelectionQuery.Instance.CleanRegisteredPaths(); // clear all registered object's selectablePaths to empty foreach (MWB_Object mwb_Object in m_objectList.MWB_Objects) { mwb_Object.selectablePaths.Clear(); mwb_Object.InitializeRootPath(); } }
private MWB_DummyObjectList ForkDummyObjects(MWB_DummyObjectList dummyObjectList, bool isInitializedAsAble, int worldIndex = 0) { //Debug.Log("Forking"); GameObject parent = new GameObject("collide-forked dummy parent"); // this will also instantiate // !!! IMPORTANT : set the transform data of dummys' parent to the same as original objects' parent.transform.parent = dummyMasterParent.transform; // parent, which is the MWB_SYSTEM parent.transform.localPosition = transform.localPosition; parent.transform.localRotation = transform.localRotation; parent.transform.localScale = transform.localScale; // add parent to dummyParent list for clean up ! dummyParentList.Add(parent); MWB_DummyObjectList forkedDummyObjectList = new MWB_DummyObjectList(); foreach (MWB_DummyObject mwbDummyObject in dummyObjectList.MWB_DummyObjects) { GameObject forkedObject = Instantiate(mwbDummyObject.gameObject, parent.transform); // Set layer forkedObject.layer = MWBWaitingLayer; forkedObject.SetActive(isInitializedAsAble); // initilize as kinematic forkedObject.GetComponent <Rigidbody>().isKinematic = true; forkedObject.gameObject.GetComponent <Renderer>().enabled = false; // Destroy(forkedObject.GetComponent <MWB_Object>()); MWB_DummyObject forkedDummy = forkedObject.GetComponent <MWB_DummyObject>(); forkedDummy.Manager = this; // record object source forkedDummy.objectSource = mwbDummyObject.objectSource; // record fork source ( initial object has null ) forkedDummy.forkedSource = mwbDummyObject; // record corresponding dummy list forkedDummy.correspondingDummyList = forkedDummyObjectList; // record previous transform data segment (initial dummy object has null) TransformDataSegment parentSegment = mwbDummyObject.transformDataSegment; forkedDummy.transformDataSegment.previousSegment = parentSegment; mwbDummyObject.transformDataSegment = new TransformDataSegment(parentSegment); // use main path to generate two sub MWB_Path parentPath = mwbDummyObject.dummyMainPath; //mwbDummyObject.RecordPosition(); // !!! Record position to avoid broken line segment mwbDummyObject.SetSubPath(parentPath); //mwbDummyObject.RecordPosition(); // !!! Record position to avoid broken line segment forkedDummy.SetSubPath(parentPath); // assign reference of dummy to path mwbDummyObject.dummyMainPath.SourceDummyObject = mwbDummyObject; forkedDummy.dummyMainPath.SourceDummyObject = forkedDummy; // // set pathIndex //forkedDummy.pathIndex = mwbDummyObject.pathIndex; // Vector3 additionalImpulse; if (m_collidingDummyObjects.ContainsKey(mwbDummyObject)) { // TODO : add a logical additional pulse, rather than just random a force Collision collision = m_collidingDummyObjects[mwbDummyObject]; //additionalImpulse = Vector3.Cross(collision.impulse, Vector3.up) * collision.impulse.magnitude * 5f; //additionalImpulse = new Vector3(UnityEngine.Random.Range(-100, 100), 0, UnityEngine.Random.Range(-100, 100)); Vector3 origin = Vector3.zero; int counter = 0; foreach (var contactPoint in collision.contacts) { origin += contactPoint.point; counter++; } origin /= counter; List <Vector3> perturbation = SinDistributionUtility.CalculatePerturbation(origin, collision.impulse); if (perturbation.Count > worldIndex) { additionalImpulse = perturbation[worldIndex]; } else { additionalImpulse = perturbation[perturbation.Count - 1]; } } else { additionalImpulse = Vector3.zero; } // // maintain rigidbody info , otherwise it'll only copy variables info but not state info RigidbodyState rigidbodyState = new RigidbodyState(mwbDummyObject.GetComponent <Rigidbody>(), additionalImpulse); forkedDummy.rigidbodyState = rigidbodyState; forkedDummyObjectList.AddToDummyObjectList(forkedDummy); // } return(forkedDummyObjectList); }
// !!! IMPORTANT : If a collision already happens and you disactive object then active , OnCollisionEnter will trigger again public IEnumerator Run() { OnSystemBegin.Invoke(); dummyMasterParent = new GameObject("_TempDummyMasterParent"); // might need a lifetime for forked MWB_System forkedDummyObjectLists = new List <MWB_DummyObjectList> { GenerateDummyObjects(m_objectList, true) }; // set original object to disactive, and set to wait layer to avoid unnecessary collision foreach (MWB_Object mwbObject in m_objectList.MWB_Objects) { mwbObject.gameObject.SetActive(false); mwbObject.gameObject.layer = MWBWaitingLayer; } // for each forked dummyObjectList, check if the system needs to be forked for (int i = 0; i < forkedDummyObjectLists.Count; i++) { if (isForceStop) { break; } MWB_DummyObjectList dummyObjectList = forkedDummyObjectLists[i]; // Set focusing dummyObjectList focusingDummyObjectList = dummyObjectList; foreach (MWB_DummyObject dummyObject in dummyObjectList.MWB_DummyObjects) { dummyObject.gameObject.layer = MWBRunningLayer; // try to turn on dummys dummyObject.rigidbody.isKinematic = false; // regain maintained rigidbody state ( obtained when forked ) Rigidbody dummyRigidbody = dummyObject.GetComponent <Rigidbody>(); dummyObject.rigidbodyState.SetRigidbodyState(ref dummyRigidbody); // turn visible dummyObject.gameObject.GetComponent <Renderer>().enabled = true; } // simulation for (int currentFrame = 0; currentFrame < SimulateFrameCount; currentFrame++) { if (forkedFrameNumber.ContainsKey(dummyObjectList)) { currentFrame = forkedFrameNumber[dummyObjectList]; // !!! IMPORTANT !!! forkedFrameNumber.Remove(dummyObjectList); // continue; } // Record position to path ( when simulating ) foreach (MWB_DummyObject dummy in dummyObjectList.MWB_DummyObjects) { dummy.RecordPosition(); } // simulate Physics.Simulate(TimeStepPerFrame); // for each collided object , fork dummy objects (X) // if this system has a dummy collision, fork once. LoopCounter++; if (LoopCounter > MaxLoopPerFrame) { LoopCounter = 0; yield return(null); } if (m_collidingDummyObjects.Count > 0) { for (int k = 0; k < WorldForkedOnCollision; k++) { // fork every object in currentObjectList by their current status MWB_DummyObjectList forkedMWB_DummyObjectList = ForkDummyObjects(dummyObjectList, true, k); // add track to every objects that we just created forkedDummyObjectLists.Add(forkedMWB_DummyObjectList); // track frame forkedFrameNumber.Add(forkedMWB_DummyObjectList, currentFrame); } } m_collidingDummyObjects.Clear(); } // Set back to waiting for simulation foreach (MWB_DummyObject dummyObject in dummyObjectList.MWB_DummyObjects) { dummyObject.gameObject.layer = MWBWaitingLayer; // try to turn off dummys dummyObject.rigidbody.isKinematic = true; dummyObject.gameObject.GetComponent <Renderer>().enabled = false; // register to selectable // ?? //dummyObject.pathIndex = dummyObject.objectSource.selectablePaths.Count; // Debug.Log(dummyObject.pathIndex + " " + dummyObject.correspondingDummyList.worldIndex); // Do line set up at the end //dummyObject.objectSource.selectablePaths.Add(dummyObject.dummyMainPath); // //MWB_SelectionQuery.Instance.RegisterPath(dummyObject.dummyMainPath); registerPathCount++; } // update Progress += 1.0f / forkedDummyObjectLists.Count; } foreach (MWB_Object mwbObject in m_objectList.MWB_Objects) { mwbObject.gameObject.SetActive(true); mwbObject.gameObject.layer = MWBRunningLayer; // for updated line renderer!!! // Do line set up at the end //mwbObject.SetupLinedata(); } forkedFrameNumber.Clear(); m_collidingDummyObjects.Clear(); // TEST PURPOSE // AnimationClip clip = MWBDummyClipUtility.GenerateClipFromDummyList(forkedDummyObjectLists[3]); // ClipExportUtility.ExportAnimationClip(clip, @"Assets/test.anim"); // // output information Debug.Log("MWB_DummyObject.pathNumber = " + MWB_DummyObject.pathNumber); Debug.Log("MWB_DummyObject.dotNumber = " + MWB_DummyObject.dotNumber); Debug.Log("registerPathCount = " + registerPathCount); // if (isForceStop) { terminate(); isForceStop = false; } else { OnSystemComplete.Invoke(); } yield return(null); }
public static AnimationClip GenerateClipFromDummyList(MWB_DummyObjectList dummyList) { AnimationClip clip = new AnimationClip(); foreach (MWB_DummyObject dummy in dummyList.MWB_DummyObjects) { // stack from dummy itself to its root forked source, and reverse create clips Stack <TransformDataSegment> dataSegmentStack = new Stack <TransformDataSegment>(); TransformDataSegment currentDataSegment = dummy.transformDataSegment; while (currentDataSegment != null) { dataSegmentStack.Push(currentDataSegment); // travese upward in fork tree currentDataSegment = currentDataSegment.previousSegment; } // for each recorded Transform data, the time interval is Time.fixedDeltaTime float currentRelativeTime = 0f; // create curves base on the dummys in the stack AnimationCurve localPositionXCurve = new AnimationCurve(); AnimationCurve localPositionYCurve = new AnimationCurve(); AnimationCurve localPositionZCurve = new AnimationCurve(); AnimationCurve localRotationXCurve = new AnimationCurve(); AnimationCurve localRotationYCurve = new AnimationCurve(); AnimationCurve localRotationZCurve = new AnimationCurve(); AnimationCurve localRotationWCurve = new AnimationCurve(); AnimationCurve localScaleXCurve = new AnimationCurve(); AnimationCurve localScaleYCurve = new AnimationCurve(); AnimationCurve localScaleZCurve = new AnimationCurve(); while (dataSegmentStack.Count > 0) { currentDataSegment = dataSegmentStack.Pop(); if (currentDataSegment == null) { break; } for (int i = 0; i < currentDataSegment.transformData.Count; i++) { localPositionXCurve.AddKey(currentRelativeTime, currentDataSegment.transformData[i].localPosition.x); localPositionYCurve.AddKey(currentRelativeTime, currentDataSegment.transformData[i].localPosition.y); localPositionZCurve.AddKey(currentRelativeTime, currentDataSegment.transformData[i].localPosition.z); localRotationXCurve.AddKey(currentRelativeTime, currentDataSegment.transformData[i].localRotation.x); localRotationYCurve.AddKey(currentRelativeTime, currentDataSegment.transformData[i].localRotation.y); localRotationZCurve.AddKey(currentRelativeTime, currentDataSegment.transformData[i].localRotation.z); localRotationWCurve.AddKey(currentRelativeTime, currentDataSegment.transformData[i].localRotation.w); localScaleXCurve.AddKey(currentRelativeTime, currentDataSegment.transformData[i].localScale.x); localScaleYCurve.AddKey(currentRelativeTime, currentDataSegment.transformData[i].localScale.y); localScaleZCurve.AddKey(currentRelativeTime, currentDataSegment.transformData[i].localScale.z); currentRelativeTime += Time.fixedDeltaTime; } } // //Debug.Log("max frame = " + currentRelativeTime / Time.fixedDeltaTime); // set curve into the animation clip clip.SetCurve(dummy.objectSource.hierachyName, typeof(Transform), "localPosition.x", localPositionXCurve); clip.SetCurve(dummy.objectSource.hierachyName, typeof(Transform), "localPosition.y", localPositionYCurve); clip.SetCurve(dummy.objectSource.hierachyName, typeof(Transform), "localPosition.z", localPositionZCurve); clip.SetCurve(dummy.objectSource.hierachyName, typeof(Transform), "localRotation.x", localRotationXCurve); clip.SetCurve(dummy.objectSource.hierachyName, typeof(Transform), "localRotation.y", localRotationYCurve); clip.SetCurve(dummy.objectSource.hierachyName, typeof(Transform), "localRotation.z", localRotationZCurve); clip.SetCurve(dummy.objectSource.hierachyName, typeof(Transform), "localRotation.w", localRotationWCurve); clip.SetCurve(dummy.objectSource.hierachyName, typeof(Transform), "localScale.x", localScaleXCurve); clip.SetCurve(dummy.objectSource.hierachyName, typeof(Transform), "localScale.y", localScaleYCurve); clip.SetCurve(dummy.objectSource.hierachyName, typeof(Transform), "localScale.z", localScaleZCurve); } return(clip); }