//CKeyHook _oKeyHook_ThighSpread; //--------------------------------------------------------------------------- CREATE / DESTROY public override void OnStart_DefineLimb() { _nDrivePos = 0.5f * C_DrivePos; // Weaken the leg pin drive over default //=== Init Bones and Joints === CJointDriver oJointPelvis = _oBody._oActor_Pelvis._oJointExtremity; _aJoints.Add(_oJointThighBend = CJointDriver.Create(this, oJointPelvis, _sSidePrefixL+"ThighBend", 15, 3.0f, -115, 035, 000, 085, 1)); // X = Leg forward (-115) / back (35), Z = Thigh split (85) / together (20) ###BAD: Super-important thigh split needed same value for thigh together makes no sense! ###IMPROVE: 2nd joint? _aJoints.Add(_oJointThighTwist = CJointDriver.Create(this, _oJointThighBend, _sSidePrefixL+"ThighTwist", 20, 2.0f, -000, 000, 075, 000, 1)); // Y = Thigh twist -75 to 75 Ok _aJoints.Add(_oJointShin = CJointDriver.Create(this, _oJointThighTwist, _sSidePrefixL+"Shin", 10, 2.0f, -011, 155, 015, 005, 1)); // X = Knee bent (+155) or backward (-11), Y = Knee rotate -25 to 10 with compromise at 15, Z = Knee side-to-side -5 to 5 _aJoints.Add(_oJointFoot = CJointDriver.Create(this, _oJointShin, _sSidePrefixL+"Foot", 15, 1.0f, -025, 010, 020, 040, 1)); // X = Foot up (-40) and down (+75), inward -25 to +10, twist -35 to 15: ###IMPROVE: FootX not up/down!! ###IMPROVE: 2 joints? ###PROBLEM: Foot up down on Z with poor bending along down _aJoints.Add(_oJointMetatarsals = CJointDriver.Create(this, _oJointFoot, _sSidePrefixL+"Metatarsals", 20, 0.5f, -000, 000, 020, 012, 1)); // X = Metatarsals left/right = useless, Y = twist -20 to 20, Z = foot bend -12 to 12 _aJoints.Add(_oJointExtremity = CJointDriver.Create(this, _oJointMetatarsals, _sSidePrefixL+"Toe", 20, 3.0f, -000, 000, 020, 050, 1)); // X = Toes bend backward (-45) to forward (65), Y = Toe twist -20/20, Z = meaningless ###IMPROVE: Rotate axe? ###CHECK: Toe mass?? _oJointShin._oConfJoint.targetRotation = Quaternion.Euler(-160, 0, 0); //###WEAK: Set knee default position so it can easily bend (with very week drive) //###SOON: Proper bending of knee calculations from height //=== Init Hotspot === if (_eBodySide == 0) //###IMPROVE: Rediculously long path... switch to 'search for bone' (would not be as fast tho) _oHotSpot = CHotSpot.CreateHotspot(this, _oBody._oBodyBase.FindBone("chestUpper/chestLower/abdomenUpper/abdomenLower/hip/pelvis/lThighBend/lThighTwist/lShin/lFoot/lMetatarsals/lToe"), "Left Leg", true, new Vector3(0, 0, 0)); else _oHotSpot = CHotSpot.CreateHotspot(this, _oBody._oBodyBase.FindBone("chestUpper/chestLower/abdomenUpper/abdomenLower/hip/pelvis/rThighBend/rThighTwist/rShin/rFoot/rMetatarsals/rToe"), "Right Leg", true, new Vector3(0, 0, 0)); //=== Init CObject === _oObj = new CObject(this, _oBody._oBodyBase._nBodyID, typeof(EActorLeg), "Leg", "Leg" + _sSidePrefixU); _oObj.PropGroupBegin("", "", true); AddBaseActorProperties(); // The first properties of every CActor subclass are Pinned, pos & rot _oObj.PropAdd(EActorLeg.Thigh_Spread, "Thigh-Spread", 0, -100, 100, ""); _oObj.PropAdd(EActorLeg.Thigh_Rotate, "Thigh-Rotate", 0, -100, 100, ""); _oObj.FinishInitialization(); //_oKeyHook_ThighSpread = new CKeyHook(_oObj.PropFind(EActorLeg.Thigh_Spread), KeyCode.F, EKeyHookType.QuickMouseEdit, "Thigh Spread", -1); }
//--------------------------------------------------------------------------- CREATE / DESTROY public override void OnStart_DefineLimb() { //=== Init Bones and Joints === _aJoints.Add(_oJointExtremity = CJointDriver.Create(this, null, "chestUpper", 15, 8, -000, 000, 000, 000, 1)); //### The body's root bone... is kinematic and has no joint to a parent bone so all zeros _aJoints.Add(_oJointChestLower = CJointDriver.Create(this, _oJointExtremity, "chestLower", 15, 8, -015, 015, 010, 010, 1)); _aJoints.Add(_oJointAbdomenUpper = CJointDriver.Create(this, _oJointChestLower, "abdomenUpper", 15, 6, -035, 025, 012, 020, 1)); _aJoints.Add(_oJointAbdomenLower = CJointDriver.Create(this, _oJointAbdomenUpper, "abdomenLower", 15, 6, -040, 025, 024, 020, 1)); _aJoints.Add(_oJointHip = CJointDriver.Create(this, _oJointAbdomenLower, "hip", 15, 6, -035, 020, 015, 015, 1)); //###NOTE: Pelvis bone is in CActorPelvis for extra processing there. //###CHECK: Keep? _oJointExtremity._oRigidBody.isKinematic = (CGame.INSTANCE._GameMode == EGameModes.Configure); //###HACK ###TEMP ####REVA If play no anim just set everything to kinematic... for temp cloth exploration //###OBS? _oJointExtremity._oRigidBody.isKinematic = false; // We need to disable kinematic on bone as we're driving it with our pin! //=== Init Hotspot === _oHotSpot = CHotSpot.CreateHotspot(this, transform, "Chest", true, new Vector3(0, 0, 0), C_SizeHotSpot_BodyNodes); //_oHotSpot = CHotSpot.CreateHotspot(this, _oBody.FindBone("chestUpper"), "Chest", true, new Vector3(0, 0, 0), C_SizeHotSpot_TorsoNodes); //=== Init CObject === _oObj = new CObject(this, _oBody._oBodyBase._nBodyID, typeof(EActorChest), "Chest", "Chest"); _oObj.PropGroupBegin("", "", true); AddBaseActorProperties(); // The first properties of every CActor subclass are Pinned, pos & rot _oObj.PropAdd(EActorChest.Torso_LeftRight, "Torso_LeftRight", 0, -100, 100, ""); //###BUG: Have to recalibrate to make new abdoment-centric bones look good. _oObj.PropAdd(EActorChest.Torso_UpDown, "Torso_UpDown", 0, -100, 100, ""); //###NOW###: Forced to enter crappy name because of new CProp restrictions with naming! _oObj.PropAdd(EActorChest.Torso_Twist, "Torso_Twist", 0, -100, 100, ""); _oObj.FinishInitialization(); //###PROBLEM: Base actor adds 'pinned' but chest is always pinned? //###CHECK?? _oObj.PropSet(EActorChest.Pinned, 1); // Manually set pinned to 1 on torso so body doesn't float in space when no pose is loaded (Weak that we can't set in PropAdd() due to init-time problems) if (CGame.INSTANCE.EnableIdlePoseMovement) StartCoroutine(Coroutine_ChangeRandomPose()); //###CHECK: When destroyed OK?? }
public void OnStart() { _oHotSpot = CHotSpot.CreateHotspot(this, transform, "Pose Root", true, Vector3.zero, 2.0f); _oObj = new CObject(this, 0, typeof(EPoseRoot), "Pose Root"); _oObj.PropGroupBegin("", "", true); //###BROKEN: Need to flip load order, not 180!! _oObj.PropAdd(EPoseRoot.Flipped, "Flip Pose", 0, "", CProp.Local | CProp.AsCheckbox); //###IMPROVE: Add a separation member with key hook. A height too?? _oObj.FinishInitialization(); }
// CActorNode: Simple 'node based' actor without joints to enable user to move / rotate other real actors... Currently used for base and torso //###DESIGN: Really keep design based on CActor??? Just needs to move a simple node! public override void OnStart_DefineLimb() { //=== Init Bones and Joints === _oHotSpot = CHotSpot.CreateHotspot(this, transform, transform.name, true, Vector3.zero, C_SizeHotSpot_BodyNodes); //###DESIGN!!!!: How can user move actors apart that get too close?? //=== Init CObject === _oObj = new CObject(this, _oBody._oBodyBase._nBodyID, typeof(EActorNode), transform.name, transform.name); //###DESIGN: Keep??? _oObj.PropGroupBegin("", "", true); AddBaseActorProperties(); // The first properties of every CActor subclass are Pinned, pos & rot //###DESIGN? _oObj.PropAdd(EActorNode.Height, "Height", 0.5f, 0.5f, 1.2f, "", CProp.Local); //###DESIGN: Range tuned to standing height _oObj.FinishInitialization(); }
public CBody(CBodyBase oBodyBase) { //###NOW#11 _oBodyBase = oBodyBase; _oBodyBase._oBody = this; //###WEAK#13: Convenience early-set of our instance into owning parent. Needed as some of init code needs to access us from our parent! ###DESIGN! _oBodySkinnedMeshGO_HACK = new GameObject("RuntimeBody"); // Create the game object that will contain our important CBody component early (complex init tree needs it!) _oBodySkinnedMeshGO_HACK.transform.SetParent(_oBodyBase._oBodyRootGO.transform); _bEnabled = true; // Enabled at creation by defnition. //bool bForMorphingOnly = false; //###JUNK (CGame.INSTANCE._GameMode == EGameModes.MorphNew_TEMP); //####DEV!!!! Debug.Log(string.Format("+ Creating body #{0}", _oBodyBase._nBodyID)); _oObj = new CObject(this, _oBodyBase._nBodyID, typeof(EBodyDef), "Body"); _oObj.PropGroupBegin("", "", true); //_oObj.PropAdd(EBodyDef.Sex, "Sex", typeof(EBodySex), (int)EBodySex.Woman, ""); //_oObj.PropAdd(EBodyDef.ClothingTop, "Top Clothing", typeof(EBodyClothingTop_HACK), 0, ""); //###HACK!!!! //_oObj.PropAdd(EBodyDef.ClothingBottom, "Bottom Clothing", typeof(EBodyClothingBottom_HACK), 0, "" + CProp.Hide); //###BROKEN: Need to switch off v****a soft body!! //_oObj.PropAdd(EBodyDef.Hair, "Hair", typeof(EBodyHair), 0, ""); //_oObj.PropAdd(EBodyDef.BtnUpdateBody, "Update Body", 0, "", CProp.AsButton); _oObj.PropAdd(EBodyDef.BreastSize, "Breast Size BROKEN", 1.0f, 0.5f, 2.5f, ""); //###BROKEN#11 _oObj.FinishInitialization(); //=== Give some reasonable defaults to use when game loads === ###TODO: Load these from the user's last used body definitions! ####TEMP ####DESIGN: Load from user pref or file? NOT IN CODE!! // if (_oBodyBase._nBodyID == 0) { // _oObj.PropSet(EBodyDef.Sex, (int)EBodySex.Woman); // //_oObj.PropSet(EBodyDef.Sex, (int)EBodySex.Shemale); // _oObj.PropSet(EBodyDef.Hair, (int)EBodyHair.TiedUp); //// oObj.PropSet(EBodyDef.Hair, (int)EBodyHair.Messy); //// oObj.PropFind(EBodyDef.ClothingTop)._nPropFlags |= CProp.Hide; //###HACK!!!! //// oObj.PropFind(EBodyDef.BreastSize)._nPropFlags |= -CProp.Hide; //// oObj.PropFind(EBodyDef.Hair)._nPropFlags |= CProp.Hide; // } else { // //_oObj.PropSet(EBodyDef.Sex, (int)EBodySex.Man); ####REVB // _oObj.PropSet(EBodyDef.Sex, (int)EBodySex.Shemale); // //oObj.PropSet(EBodyDef.ClothingTop, (int)EBodyClothingTop_HACK.TiedTop); // _oObj.PropSet(EBodyDef.Hair, (int)EBodyHair.TiedUp); // //if (CGame.INSTANCE._bRunningInEditor) //###TEMP! :) // // oObj.PropSet(EBodyDef.BreastSize, 1.3f); // } //===== DETACHED SOFTBODY PARTS PROCESSING ===== if (_oBodyBase._eBodySex != EBodySex.Man) { //_aSoftBodies.Add(_oBreastL = (CBreastL)CSoftBody.Create(this, typeof(CBreastL), "chestUpper")); //###DEVNOW //_aSoftBodies.Add(_oBreastR = (CBreastR)CSoftBody.Create(this, typeof(CBreastR), "chestUpper")); } if (_oBodyBase._eBodySex == EBodySex.Woman) { //_aSoftBodies.Add(_oVagina = (CVagina)CSoftBody.Create(this, typeof(CVagina), "chest/abdomen/hip")); } else { //_aSoftBodies.Add(_oPenis = (CPenis)CSoftBody.Create(this, typeof(CPenis), "chest/abdomen/hip")); } ////####TEMP ####DESIGN ####TEMP ####MOVE //_aCloths.Add(CBCloth.Create(this, "MyShirt", "Shirt", "HACK-Cloth-TankTop", "_ClothSkinnedArea_ShoulderTop")); //_ClothSkinnedArea_Top ///_aCloths.Add(CBCloth.Create(this, "MyShirt", "Shirt", "BodySuit", "_ClothSkinnedArea_ShoulderTop")); //_ClothSkinnedArea_Top ////_aCloths.Add(CBCloth.Create(this, "Rough1-Holds")); ////_aCloths.Add(CBCloth.Create(this, "Rough2-Spreads")); ////_aCloths.Add(CBCloth.Create(this, "BodySuit-Top-Trimmed")); ////////////###DEV _aCloths.Add(CBCloth.Create(this, "FullShirt")); ////=== Create the various soft-body mesh parts that are dependant on the body sex === ////###IMPROVE!!!! Parse array of Blender-pushed softbody into our parts (instead of pulling like below?) //if (_bForMorphingOnly == false) { // if (_eBodySex == EBodySex.Woman || _eBodySex == EBodySex.Shemale) { // _aSoftBodies.Add(_oBreastL = (CBreastBase)CBMesh.Create(null, this, _sNameGameBody, "_Detach_Breasts", "Client", "Unity_GetMesh", "'SkinInfo'", typeof(CBreastBase))); //###WEAK: Create utility function like before??? // } // if (_eBodySex == EBodySex.Shemale || _eBodySex == EBodySex.Man) // _aSoftBodies.Add(_oPenis = (CPenis)CBMesh.Create(null, this, _sNameGameBody, "_Detach_Penis", "Client", "Unity_GetMesh", "'NoSkinInfo'", typeof(CPenis))); // if (_eBodySex == EBodySex.Woman) // _oVagina = new CVagina(this); // //=== Create the important body collider that will repel fluid in the scene === // _oBodyCol = (CBBodyCol)CBBodyCol.Create(null, this, _sNameGameBody); //} //=== Obtain the source mesh body for normal extraction === ///_oBodySource = CBMesh.Create(null, this, "oMeshSource", typeof(CBMesh)); ///_oBodySource.GetComponent<MeshRenderer>().enabled = false; // This mesh is to pull normals only. Not visible at runtime! //===== MAIN SKINNED BODY PROCESSING ===== //=== Get the main body skinned mesh (has to be done once all softbody parts have been detached) === _oBodySkinnedMesh = (CBSkin)CBMesh.Create(_oBodySkinnedMeshGO_HACK, _oBodyBase, ".oBody.oMeshBody", typeof(CBSkin)); //###IMPROVE#13: Create blender instance string for our CBody? _oBodySkinnedMesh.name = "GametimeBody"; //_oBodySkinnedMesh.GetComponent<SkinnedMeshRenderer>().enabled = false; //=== Create a hotspot at the character's head the user can use to invoke our (important) context menu === //###BROKENN // Transform oHeadT = FindBone("chest/neck/head"); // Our hotspot is located on the forehead of the character. //_oHotSpot = CHotSpot.CreateHotspot(this, oHeadT, this._sHumanCharacterName, false, new Vector3(0, 0.09f, 0.03f), 2.0f); //###IMPROVE: Get these offsets from pre-placed nodes on bone structure?? ////=== Create the head look controller to look at parts of the other body === //###BROKENN // _oHeadLook = _oBodyRootGO.gameObject.AddComponent<CHeadLook>(); //####DESIGN: Keep for morph mode?? //_oHeadLook.OnStart(this); //=== Instantiate the requested hair and pin as child of the head bone === //###BROKENN //EBodyHair eBodyHair = (EBodyHair)_oObj.PropGet(EBodyDef.Hair); //if (eBodyHair != EBodyHair.None) { // string sNameHair = "HairW-" + eBodyHair.ToString(); //###HACK!!! W extension! ###HACK!!!! Man support!! // GameObject oHairTemplateGO = Resources.Load("Models/Characters/Woman/Hair/" + sNameHair + "/" + sNameHair, typeof(GameObject)) as GameObject; // Hair has name of folder and filename the same. //###HACK: Path to hair, selection control, enumeration, etc // _oHairGO = GameObject.Instantiate(oHairTemplateGO) as GameObject; // Transform oBoneHead = FindBone("chest/neck/head"); // _oHairGO.transform.parent = oBoneHead; // _oHairGO.transform.localPosition = Vector3.zero; // _oHairGO.transform.localRotation = Quaternion.identity; // if (_eBodySex == EBodySex.Man) { //###HACK!!!!!! To reuse messy hair for man!! // _oHairGO.transform.localPosition = new Vector3(0, 0.0f, 0.0f); // _oHairGO.transform.localScale = new Vector3(1.07f, 1.07f, 1.08f); // } //} Body_InitActors(); ////=== Setup the keys to handle penis control on non-woman bodies === //if (_eBodySex != EBodySex.Woman) { //###MOVE? ###OBS ###F // bool bSelectedBodyOnly = (CGame.INSTANCE._nNumPenisInScene_BROKEN > 1); // Keys below are active if this body is the selected body ONLY if we have more than one man in the scene // if (_oPenis != null) { // _oKeyHook_PenisBaseUpDown = new CKeyHook(_oPenis._oObjDriver.PropFind(EPenis.BaseUpDown), KeyCode.Q, EKeyHookType.QuickMouseEdit, "Penis up/down", 1, bSelectedBodyOnly); // _oKeyHook_PenisShaftUpDown = new CKeyHook(_oPenis._oObjDriver.PropFind(EPenis.ShaftUpDown), KeyCode.E, EKeyHookType.QuickMouseEdit, "Penis bend up/down", 1, bSelectedBodyOnly); // _oKeyHook_PenisDriveStrengthMax = new CKeyHook(_oPenis._oObjDriver.PropFind(EPenis.DriveStrengthMax), KeyCode.G, EKeyHookType.QuickMouseEdit, "Penis erection", -1, bSelectedBodyOnly); // } //} _oKeyHook_ChestUpDown = new CKeyHook(_oActor_Chest._oObj.PropFind(EActorChest.Torso_UpDown), KeyCode.T, EKeyHookType.QuickMouseEdit, "Chest forward/back"); //=== Create the face and its associated morph channels === ///_oFace = (CFace)CBMesh.Create(null, this, "oMeshFace", typeof(CFace)); //=== Reparent our actor base to the pose root so that user can move / rotate all bodies at once === _oActor_Base.transform.SetParent(CGame.INSTANCE._oPoseRoot.transform); //###DESIGN#15! Causes problems with regular init/destory of CBody? Do we really want to keep reparenting for easy full pose movement??> _oActor_Base.gameObject.name = _oBodyBase._sBodyPrefix + "_Base"; //=== Copy references to our actors to our script-friendly CObject variables to provide friendlier access to our scriptable objects === Base = _oActor_Base._oObj; // CGamePlay passed us the reference to the right (empty) static object. We fill it here. Chest = _oActor_Chest._oObj; Torso = _oActor_Torso._oObj; Pelvis = _oActor_Pelvis._oObj; ArmL = _oActor_ArmL._oObj; ArmR = _oActor_ArmR._oObj; LegL = _oActor_LegL._oObj; LegR = _oActor_LegR._oObj; Face = null;/// _oFace._oObj; ///###BROKEN ###DEVO Penis = (_oPenis == null) ? null : _oPenis._oObjDriver; _oScriptPlay = CUtility.FindOrCreateComponent(_oBodyBase._oBodyRootGO.transform, typeof(CScriptPlay)) as CScriptPlay; _oScriptPlay.OnStart(this); //=== Rotate the 2nd body toward the first and separate slightly loading poses doesn't pile up one on another === ####MOVE? ####OBS? (Depend on pose?) //####PROBLEM: Set separation and don't do in all game modes if (_oBodyBase._nBodyID == 0) { _oActor_Base.transform.position = new Vector3(0, 0, -CGame.C_BodySeparationAtStart); //###DESIGN: Don't load base actor instead?? ###BUG Overwrites user setting of base!!!! } else { _oActor_Base.transform.position = new Vector3(0, 0, CGame.C_BodySeparationAtStart); _oActor_Base.transform.rotation = Quaternion.Euler(0, 180, 0); // Rotate the 2nd body 180 degrees } ///_oClothEdit_HACK = new CClothEdit(this, "Shirt"); ///CGame.gBL_SendCmd("CBody", "CBodyBase_GetBodyBase(" + _oBodyBase._nBodyID.ToString() + ").Breasts_ApplyMorph('RESIZE', 'Nipple', 'Center', 'Wide', (1.6, 1.6, 1.6, 0), None)"); //###F ###HACK!!! //=== Create the left and right canvases on each side of the body so that panels have a place to be pinned for close-to-body editing === _aUICanvas[0] = CUICanvas.Create(CUtility.FindChild(_oActor_Chest.transform, "_CanvasPin_Left")); //###HACK _aUICanvas[1] = CUICanvas.Create(CUtility.FindChild(_oActor_Chest.transform, "_CanvasPin_Right")); //###DESIGN: Which pin? Torso or chest? //=== Create the Flex collider in Blender and serialize it to Unity === CGame.gBL_SendCmd("CBody", _oBodyBase._sBlenderInstancePath_CBodyBase + ".oBody.CreateFlexCollider(" + CGame.INSTANCE.nDistFlexColliderShrinkMult + ")"); _oBodyFlexCollider = (CBSkin)CBMesh.Create(null, _oBodyBase, ".oBody.oMeshFlexCollider", typeof(CBSkin)); _oBodyFlexCollider.name = "FlexCollider"; _oBodyFlexCollider.transform.SetParent(_oBodySkinnedMesh.transform); //###IMPROVE#15: Put this common re-parenting and re-naming in Create! _oBodyFlexCollider.gameObject.AddComponent<CFlexSkinnedBody>(); _oBodyFlexCollider.GetComponent<SkinnedMeshRenderer>().enabled = false; //###IMPROVE: Move into CFlexSkinnedBody?? _oBodyFlexCollider.UpdateNormals(); //###NOW#15 }
//--------------------------------------------------------------------------- CREATE / DESTROY public override void OnStart_DefineLimb() { //###CHECK _aJoints.Add(_oJointExtremity = CJointDriver.Create(this, _oBody._oActor_Chest._oJointHip, "sex", 1.0f, 1.0f, -0f, 0, -0f, 0f, -0f, 0f)); _aJoints.Add(_oJointExtremity = CJointDriver.Create(this, _oBody._oActor_Chest._oJointHip, "pelvis", 15, 8, -025, 025, 010, 015, 1)); _oHotSpot = CHotSpot.CreateHotspot(this, transform, "Pelvis", true, new Vector3(0, 0, 0), C_SizeHotSpot_BodyNodes); _oObj = new CObject(this, _oBody._oBodyBase._nBodyID, typeof(EActorPelvis), "Pelvis", "Pelvis"); _oObj.PropGroupBegin("", "", true); AddBaseActorProperties(); // The first properties of every CActor subclass are Pinned, pos & rot _oObj.FinishInitialization(); _oObj.PropSet(EActorPelvis.Pinned, 1); // Manually set pinned to 1 on chest so body doesn't float in space when no pose is loaded (Weak that we can't set in PropAdd() due to init-time problems) }
public override void OnDeserializeFromBlender() { base.OnDeserializeFromBlender(); _sBlenderInstancePath_CCloth = CBCloth.s_sNameClothSrc_HACK; //=== Create the skinned-portion of the cloth. It will be responsible for driving Flex particles that heavily influence their corresponding particles in fully-simulated cloth mesh === _oBSkinBaked_SkinnedPortion = (CBSkinBaked)CBSkinBaked.Create(null, _oBodyBase, "." + _sBlenderInstancePath_CCloth + ".oMeshClothSkinned", typeof(CBSkinBaked)); //###WEAK#13!!! F*****g dot!! _oBSkinBaked_SkinnedPortion.transform.SetParent(transform); _oBSkinBaked_SkinnedPortion._oSkinMeshRendNow.enabled = false; // Skinned portion invisible to the user. Only used to guide simulated portion //=== Receive the aMapPinnedParticles array Blender created to map the skinned verts to their pertinent simulated ones === List<ushort> aMapPinnedParticles = CByteArray.GetArray_USHORT("'CBody'", _oBodyBase._sBlenderInstancePath_CBodyBase + "." + _sBlenderInstancePath_CCloth + ".aMapPinnedParticles.Unity_GetBytes()"); //=== Create the simulated part of the cloth === MeshFilter oMeshFilter = GetComponent<MeshFilter>(); MeshRenderer oMeshRend = GetComponent<MeshRenderer>(); //oMeshRend.sharedMaterial = Resources.Load("Materials/BasicColors/TransWhite25") as Material; //####SOON? Get mats! ###F oMeshRend.sharedMaterial = Resources.Load("Materials/Test-2Sided") as Material; //####SOON? Get mats! ###F _oBSkinBaked_SkinnedPortion._oSkinMeshRendNow.sharedMaterial = oMeshRend.sharedMaterial; // Skinned part has same material _oMeshNow = oMeshFilter.sharedMesh; _oMeshNow.MarkDynamic(); // Docs say "Call this before assigning vertices to get better performance when continually updating mesh" //=== Create the 'cloth at startup' mesh. It won't get simulated and is used to reset simulated cloth to its startup position === _oBMeshClothAtStartup = CBMesh.Create(null, _oBodyBase, "." + _sBlenderInstancePath_CCloth + ".oMeshClothSimulated", typeof(CBMesh)); _oBMeshClothAtStartup.transform.SetParent(_oBodyBase.FindBone("chestUpper")); // Reparent this 'backup' mesh to the chest bone so it rotates and moves with the body _oBMeshClothAtStartup.GetComponent<MeshRenderer>().enabled = false; //_oBMeshClothAtStartup.gameObject.SetActive(false); // De activate it so it takes no cycle. It merely exists for backup purposes //=== Create the Flex object for our simulated part === CFlex.CreateFlexObject(gameObject, _oMeshNow, _oMeshNow, uFlex.FlexBodyType.Cloth, uFlex.FlexInteractionType.None, CGame.INSTANCE.nMassCloth, Color.yellow); uFlex.FlexProcessor oFlexProc = CUtility.FindOrCreateComponent(gameObject, typeof(uFlex.FlexProcessor)) as uFlex.FlexProcessor; oFlexProc._oFlexProcessor = this; _oFlexParticles = GetComponent<uFlex.FlexParticles>(); _oFlexSprings = GetComponent<uFlex.FlexSprings>(); //=== Create the managing object and related hotspot === _oObj = new CObject(this, 0, typeof(EFlexCloth), "Cloth " + gameObject.name); //###IMPROVE: Name of soft body to GUI _oObj.PropGroupBegin("", "", true); _oObj.PropAdd(EFlexCloth.Tightness, "Tightness", 1.0f, 0.01f, 2.5f, ""); _oObj.PropAdd(EFlexCloth.Length, "Length", 1.0f, 0.50f, 1.10f, ""); _oObj.PropAdd(EFlexCloth.ClothMass, "Mass", 1.0f, 0.0001f, 1000.0f, ""); _oObj.FinishInitialization(); _oWatchBone = _oBodyBase.FindBone("chestUpper"); //####HACK ####DESIGN: Assumes this cloth is a top! _oHotSpot = CHotSpot.CreateHotspot(this, _oWatchBone, "Clothing", false, new Vector3(0, 0.22f, 0.04f)); //###IMPROVE!!! Position offset that makes sense for that piece of clothing (from center of its verts?) //=== Backup the startup cloth arrays so we can adjust in a non-destructive way === _aSpringRestLengthsBAK = new float[_oFlexSprings.m_springsCount]; System.Array.Copy(_oFlexSprings.m_springRestLengths, _aSpringRestLengthsBAK, _oFlexSprings.m_springsCount); //=== Create the Flex-to-skinned-mesh component responsible to guide selected Flex particles to skinned-mesh positions === _oPinnedParticles = CUtility.FindOrCreateComponent(gameObject, typeof(CPinnedParticles)) as CPinnedParticles; _oPinnedParticles.Initialize(ref aMapPinnedParticles, _oBSkinBaked_SkinnedPortion); }
//--------------------------------------------------------------------------- CREATE / DESTROY public override void OnStart_DefineLimb() { _nDrivePos = 0.1f * C_DrivePos; // Weaken the hand drive so hand doesn't fly from pin to pin //###TUNE //_memVecRayHitInfo = new CMemAlloc<Vector3>(2); //=== Init Bones and Joints === CJointDriver oJointChestUpper = _oBody._oActor_Chest._oJointExtremity; _aJoints.Add(_oJointCollar = CJointDriver.Create(this, oJointChestUpper, _sSidePrefixL+"Collar", 30, 2.5f, -010, 050, 030, 021, 1)); // X = Collar Up/Down OK, Z has 17 back and 25 forward (avg looks ok) _aJoints.Add(_oJointShoulderBend = CJointDriver.Create(this, _oJointCollar, _sSidePrefixL+"ShldrBend", 15, 2.0f, -085, 035, 000, 110, 1)); // X = Shoulder Up/Down OK, Z = Back goes to -40, Forward to 110!!! (###IMPROVE: Another joint?) _aJoints.Add(_oJointShoulderTwist = CJointDriver.Create(this, _oJointShoulderBend, _sSidePrefixL+"ShldrTwist", 20, 1.5f, -000, 000, 080, 000, 1)); // Y = Shoulder twist goes from -95 to 80 so max. ###PROBLEM: Shimmer in high rotation! _aJoints.Add(_oJointForearmBend = CJointDriver.Create(this, _oJointShoulderTwist, _sSidePrefixL+"ForearmBend", 10, 1.5f, -020, 135, 000, 000, 1)); // X = Elbow bend from -20 to 135. ok. _aJoints.Add(_oJointForearmTwist = CJointDriver.Create(this, _oJointForearmBend, _sSidePrefixL+"ForearmTwist", 20, 1.0f, -000, 000, 080, 000, 1)); // Y = Forearm twist from -90 to 80 so max. ###IMPROVE: Could rotate the axes on the twists so we use XL/XH _aJoints.Add(_oJointExtremity = CJointDriver.Create(this, _oJointForearmTwist, _sSidePrefixL+"Hand", 10, 0.5f, -070, 080, 010, 029, 1)); // X = Hand -down(-70) / +up (+80), Y = Hand twist +/-10, Z = Hand side-to-side -28 to +30 //ConfigFingerRoot(1, "Index"); // Thumb is handled below ###DESIGN!!! Fingers in Unity PhysX is just a no-go because of extremely poor latency... what to do????? //ConfigFingerRoot(2, "Mid"); //ConfigFingerRoot(3, "Ring"); //??? ###HACK!! Disabled man's carpal1&2 in 3dsMax so we can use same code as women's! //ConfigFingerRoot(4, "Pinky"); //CJointDriver oJointFingerBoneParent = _oJointExtremity; //oJointFingerBoneParent = ConfigFingerBone(oJointFingerBoneParent, 0, 0, "Thumb", 005f, -030f, 005f, 025f); //oJointFingerBoneParent = ConfigFingerBone(oJointFingerBoneParent, 0, 1, "Thumb", 010f, -015f, 000f, 000f); //oJointFingerBoneParent = ConfigFingerBone(oJointFingerBoneParent, 0, 2, "Thumb", 010f, -015f, 000f, 000f); //=== Init Hotspot === if (_eBodySide == 0) _oHotSpot = CHotSpot.CreateHotspot(this, _oBody._oBodyBase.FindBone("chestUpper/lCollar/lShldrBend/lShldrTwist/lForearmBend/lForearmTwist/lHand"), "Left Hand", true, new Vector3(0, 0, 0)); else _oHotSpot = CHotSpot.CreateHotspot(this, _oBody._oBodyBase.FindBone("chestUpper/rCollar/rShldrBend/rShldrTwist/rForearmBend/rForearmTwist/rHand"), "Right Hand", true, new Vector3(0, 0, 0)); //=== Init CObject === _oObj = new CObject(this, _oBody._oBodyBase._nBodyID, typeof(EActorArm), "Arm", "Arm" + _sSidePrefixU); _oObj.PropGroupBegin("", "", true); AddBaseActorProperties(); // The first properties of every CActor subclass are Pinned, pos & rot //_oObj.PropAdd(EActorArm.HandTarget, "HandTarget", typeof(EHandTargets), (int)EHandTargets.ManualPosition, ""); _oObj.PropAdd(EActorArm.Hand_UpDown, "Hand-UpDown", 0, -100, 100, ""); _oObj.PropAdd(EActorArm.Hand_LeftRight, "Hand-LeftRight", 0, -100, 100, ""); _oObj.PropAdd(EActorArm.Hand_Twist, "Hand-Twist", 0, -100, 100, ""); //_oObj.PropAdd(EActorArm.Fingers_Close, "Fingers-Close", 0, -100, 100, "", CProp.Hide); //###BROKEN //_oObj.PropAdd(EActorArm.Fingers_Spread, "Fingers-Spread", 0, -100, 100, "", CProp.Hide); //_oObj.PropAdd(EActorArm.Fingers_ThumbPose, "Fingers-ThumbPose", typeof(EThumbPose), (int)EThumbPose.AlongsideFingers, "", CProp.Hide); //_oObj.PropAdd(EActorArm.UserControl, "User Control", 0, 0, 1, ""); _oObj.FinishInitialization(); _oHandTarget_RaycastPin = CActorArm.FindHandTarget(_oBody, EHandTargets.RaycastPin, _eBodySide == EBodySide.Right); // Find the raycast pin hand target as we use it heavily and it is reparented }
//--------------------------------------------------------------------------- INIT public override void OnDeserializeFromBlender() { base.OnDeserializeFromBlender(); transform.SetParent(_oBodyBase._oBody._oBodySkinnedMeshGO_HACK.transform); // Parent to our body's main skinned mesh ###WEAK#14: Crappy circumvent way of obtaining node we need early in init! _sNameSoftBody = GetType().Name.Substring(1); // Obtain the name of our detached body part ('Breasts', 'Penis', 'V****a') from a substring of our class name. Must match Blender!! ###WEAK? _sBlenderInstancePath_CSoftBody = ".oBody.aSoftBodies['" + _sNameSoftBody + "']"; // Simplify access to Blender CSoftBody instance _sBlenderInstancePath_CSoftBody_FullyQualfied = _oBodyBase._sBlenderInstancePath_CBodyBase + _sBlenderInstancePath_CSoftBody; // Simplify access to fully-qualified Blender CSoftBody instance (from CBody instance) _oBoneAnchor = _oBodyBase._oBody._oBodyBase.FindBone(_sNameBoneAnchor_HACK); //=== Set bounds to infinite so our dynamically-created mesh never has to recalculate bounds === _oMeshNow.bounds = CGame._oBoundsInfinite; //####IMPROVE: This can hurt performance ####OPT!! _oMeshNow.MarkDynamic(); // Docs say "Call this before assigning vertices to get better performance when continually updating mesh" //=== Create the managing object and related hotspot === _oObj = new CObject(this, 0, typeof(EFlexSoftBody), "SoftBody " + gameObject.name); //###IMPROVE: Name of soft body to GUI _oObj.PropGroupBegin("", "", true); _oObj.PropAdd(EFlexSoftBody.Volume, "Volume", 1.0f, 0.6f, 1.6f, ""); _oObj.PropAdd(EFlexSoftBody.Stiffness, "Stiffness", 1.0f, 0.001f, 1.0f, ""); //###IMPROVE: Log scale! _oObj.PropAdd(EFlexSoftBody.SoftBodyMass, "Mass", 1.0f, 0.0001f, 1000.0f, ""); _oObj.FinishInitialization(); if (GetType() != typeof(CBreastR)) //###HACK!: Right breast doesn't get hotspot (left breast gets it and manually broadcasts to right one) _oHotSpot = CHotSpot.CreateHotspot(this, _oBoneAnchor, "SoftBody", false, new Vector3(0, 0.10f, 0.08f)); //###IMPROVE!!! Position offset that makes sense for that piece of clothing (from center of its verts?) }
public void Start() { // StartCoroutine(Coroutine_StartGame()); // Handled by a coroutine so that our 'OnGui' can run to update the 'Please wait' dialog //} //public IEnumerator Coroutine_StartGame() { //####OBS: IEnumerator?? //###NOTE: Game is started by iGUICode_Root once it has completely initialized (so as to present the 'Please Wait...' dialog Debug.Log("=== CGame.StartGame() ==="); INSTANCE = this; _nTimeAtStart = Time.time; //GameObject oGO_HACK = new GameObject("oGO_HACK", typeof(CSoftBody)); //###NOW### ////GameObject oGO_HACK = new GameObject("oGO_HACK", typeof(CSoftBodyBase)); //###NOW### ////GameObject oGO_HACK = new GameObject("oGO_HACK", typeof(CB)); //###NOW### ////GameObject oGO_HACK = new GameObject("oGO_HACK", typeof(CFuckOff)); ////GameObject oGO_HACK = new GameObject("oGO_HACK", typeof(CJointDriver)); //return; _oFlexSolver = FindObjectOfType<uFlex.FlexSolver>(); //###F GameObject oSceneGO = GameObject.Find("SCENE/SceneColliders"); //if (oSceneGO != null) // s_aColliders_Scene = oSceneGO.GetComponentsInChildren<CCollider_OBS>(); _bRunningInEditor = true; //###HACK ####REVA Application.isEditor _DemoVersion = (_bRunningInEditor == false); //###CHECK? If dev has Unity code they are non-demo _oCursor = CCursor.Cursor_Create(); //###DESIGN!!!!!: REVISIT! ###CLEANUP!!!!! Cursor.visible = Application.isEditor; // _bRunningInEditor; //=== Set rapid-access members to text widgets so we can rapidly update them === _oTextUL = GameObject.Find("/UI/CanvasScreen/UL/Text-UL").GetComponent<Text>(); _oTextUC = GameObject.Find("/UI/CanvasScreen/UC/Text-UC").GetComponent<Text>(); _oTextUR = GameObject.Find("/UI/CanvasScreen/UR/Text-UR").GetComponent<Text>(); //=== Create user-adjustable top-level game options === _oObj = new CObject(this, 0, typeof(EGamePlay), "Erotic9"); //###TEMP!!! Main game name in this low-importance GUI??? _oObj.PropGroupBegin("", "", true); //###CLEANUP //_oObj.PropAdd(EGamePlay.Pleasure, "Pleasure", 30, -100, 100, "Amount of pleasure experienced by game characters. Influences 'Arousal' (NOTE: Temporary game mechanism)"); //###BUG with first setting //_oObj.PropAdd(EGamePlay.Arousal, "Arousal", 0, 0, 100, "Current state of arousal from game characters. Currently influence penis size. (NOTE: Temporary game mechanism)"); //_oObj.PropAdd(EGamePlay.PoseRootPos, "Pose Root Position",typeof(EPoseRootPos), 0, "Base location of pose root. (e.g. on bed, by bedside, etc)"); //_oObj.PropAdd(EGamePlay.PenisSize, "Penis Size", 0, 0, 100, "", CProp.ReadOnly | CProp.Hide); //_oObj.PropAdd(EGamePlay.PenisErectionMax, "Erection", 0, 0, 100, "", CProp.ReadOnly | CProp.Hide); //_oObj.PropAdd(EGamePlay.FluidConfig, "Fluid Configuration", 0, "Display the properties of the Erotic9 fluid simulator. (Advanced)", CProp.AsButton); _oObj.FinishInitialization(); _oHotSpot = CHotSpot.CreateHotspot(this, transform, "Game Options", false, new Vector3(0, 0.0f, 0.0f), 1.0f); //if (_GameModeAtStartup == EGameModes.None) { // yield break; //} float nDelayForGuiCatchup = _bRunningInEditor ? 0.2f : 0.01f; //###HACK? ###TUNE: Adjustable delay to give iGUI time to update 'Game is Loading' message, with some extra time inserted to make Unity editor appear more responsive during game awake time ///yield return new WaitForSeconds(nDelayForGuiCatchup); //=== Send async call to authentication so it is ready by the time game has initialized === // WWW oWWW = null; // if (Application.genuine) { //###CHECK: Has any value against piracy??? // if (Application.internetReachability != NetworkReachability.NotReachable) { //###CHECK!!! // //####BROKEN?! Why store it if we don't use it? string sMachineID = PlayerPrefs.GetString(G.C_PlayerPref_MachineID); // string sMachineID = CGame.GetMachineID(); //###CHECK Can cause problems if switching adaptors frequently? // oWWW = new WWW("http://www.erotic9.net/cgi-bin/CheckUser.py?Action=Authenticate&MachineID=" + sMachineID); // } else { // Debug.LogError("Warning: Could not authenticate because of Internet unreacheability."); // } // } else { // Debug.LogError("Warning: Could not authenticate because of executable image corruption."); // } //=== Try to load our dll to extract helpful error message if it fails, then release it === //Debug.Log("INIT: Attempting to load ErosEngine.dll"); //###BROKEN! WTF No longer works loading 64 bit dll?? //int hLoadLibResult = LoadLibraryEx("ErosEngine.dll", 0, 2); //if (hLoadLibResult > 32) // FreeLibrary(hLoadLibResult); // Free our dll so Unity can load it its way. Based on code sample at http://support.microsoft.com/kb/142814 //else // CUtility.ThrowException("ERROR: Failure to load ErosEngine.dll. Error code = " + hLoadLibResult); // App unusable. Study return code to find out what is wrong. //Debug.Log("INIT: Succeeded in loading ErosEngine.dll"); //####OBS? GameObject oGuiGO = GameObject.Find("iGUI"); //###TODO!!! Update game load status... ###IMPROVE: Async load so OnGUI gets called??? (Big hassle for that!) Debug.Log("0. Game Awake"); ///yield return new WaitForSeconds(nDelayForGuiCatchup); int n123 = ErosEngine.Utility_Test_Return123_HACK(); // Dummy call just to see if DLL will load with Unity if (n123 != 123) CUtility.ThrowException("ERROR: Failure to get 123 from ErosEngine.dll call to Utility_Test_Return123_HACK."); Debug.Log("INIT: Succeeded in loading ErosEngine.dll"); //=== Initialize our gBlender direct-memory buffers === Debug.Log("1. Shared Memory Creation."); //###??? new WaitForSeconds(nDelayForGuiCatchup); if (ErosEngine.gBL_Init(CGame.GetFolderPathRuntime()) == false) CUtility.ThrowException("ERROR: Could not start gBlender library! Game unusable."); //=== Spawn Blender process === Debug.Log("2. Background Server Start."); //###??? new WaitForSeconds(nDelayForGuiCatchup); //###CHECK: Cannot wait long!! _hWnd_Unity = (IntPtr)GetActiveWindow(); // Just before we start Blender obtain the HWND of our Unity editor / player window. We will need this to re-activate our window. (Starting blender causes it to activate and would require user to alt-tab back to game!!) _oProcessBlender = CGame.LaunchProcessBlender("Erotic9.blend"); if (_oProcessBlender == null) CUtility.ThrowException("ERROR: Could not start Blender! Game unusable."); //_nWnd_Blender_HACK = (IntPtr)GetActiveWindow(); //=== Start Blender (and our gBlender scripts). Game cannot run without them === Debug.Log("3. Client / Server Handshake."); //###??? new WaitForSeconds(nDelayForGuiCatchup); if (ErosEngine.gBL_HandshakeBlender() == false) CUtility.ThrowException("ERROR: Could not handshake with Blender! Game unusable."); SetForegroundWindow(_hWnd_Unity); // Set our editor / player back into focus (away from just-spawned Blender) //=== Set Blender global variables === CGame.gBL_SendCmd("G", "CGlobals.SetFlexParticleSpacing(" + CGame.INSTANCE.particleSpacing.ToString() + ")"); //###TODO: Add others? //=== Start PhysX === // Debug.Log("4. PhysX3 Init."); //###??? new WaitForSeconds(nDelayForGuiCatchup); //ErosEngine.PhysX3_Create(); // *Must* occur before any call to physics library... So make sure this object is listed with high priority in Unity's "Script Execution Order" //Debug.Log("5. PhysX2 Init."); //###??? new WaitForSeconds(nDelayForGuiCatchup); //ErosEngine.PhysX2_Create(); //###IMPROVE!!! Return argument ###NOTROBUST //Debug.Log("6. OpenCL Init."); //###??? new WaitForSeconds(nDelayForGuiCatchup); // if (System.Environment.CommandLine.Contains("-DisableOpenCL") == false) //###TODO More / better command line processing? //###SOON ####BROKEN!!!!! OpenCL breaks cloth GPU! // ErosEngine.MCube_Init(); //###IMPROVE: Log message to user! SetForegroundWindow(_hWnd_Unity); //###WEAK: Can get rid of?? //=== Start misc stuff === Debug.Log("7. CGame globals."); //###??? new WaitForSeconds(nDelayForGuiCatchup); _oSceneMeshesGO = GameObject.Find("SceneMeshes"); // Remember our scene game object so we can hide/show _aGuiMessages = new string[(int)EGameGuiMsg.COUNT]; _ShowFPS = _ShowSysInfo = _bRunningInEditor; //###IMPROVE: Disabled until we need to save CPU cycles... Create upon user demand to record script! //_oScriptRecordUserActions = new CScriptRecord(GetPathScript("RecordedScript"), "Automatically-generated Erotic9 Scene Interation Script"); _oPoseRoot = GameObject.Find("CPoseRoot").GetComponent<CPoseRoot>(); _oPoseRoot.OnStart(); //_oFluid = gameObject.AddComponent<CFluid>(); //_oFluid.OnAwake(); Application.targetFrameRate = _TargetFrameRate; //###BUG!!! Why no effect???? _DefaultJointSpringOld = _DefaultJointSpring; //###OBS _DefaultJointDampingOld = _DefaultJointDamping; _oCamTarget = GameObject.Find("CCamTarget").GetComponent<CCamTarget>(); //###WEAK!!! _oCamTarget.OnStart(); Debug.Log("8. Body Assembly."); //###??? new WaitForSeconds(nDelayForGuiCatchup); //###WEAK!!! //_oFluid.OnStart(); //###CHECK: Keep interleave SetGameModeBasicInteractions(true); //=== Find the static scene colliders in 'SceneColliders' node and initialize them === //Debug.Log("CGame.StartGame() Registering Static Colliders: " + s_aColliders_Scene.Length); // if (s_aColliders_Scene != null) //foreach (CCollider_OBS oColStatic in s_aColliders_Scene) // Colliders that are marked as static registered themselves to us in their Awake() so we can start and destroy them // oColStatic.OnStart(); //StartCoroutine(Coroutine_Update100ms()); StartCoroutine(Coroutine_Update500ms()); _GameIsRunning = true; enabled = true; Debug.Log("+++ GameIsRunning ++"); Debug.Log("7. Scene settling time."); //###??? new WaitForSeconds(2.0f); //###DESIGN?? ###TUNE?? ///_oGui.ShowSceneBlanker(false); ///_oGui.ShowPanelGameLoad(false); //=== Check result of user authentication === /* if (oWWW != null) { yield return oWWW; string sResultAuth = oWWW.text; _DemoVersion = sResultAuth.Contains("Result=OK") == false; //###IMPROVE: Create parse routine and return server errors Debug.Log("Auth Results = " + sResultAuth); if (_DemoVersion == false) Debug.Log("Starting game in non-demo mode."); }*/ //_DemoVersion = false; //if (_DemoVersion) // Debug.Log("Starting game in demo mode."); //###TODO: Temp caption! /// if (_bRunningInEditor == false) /// CUtility.WndPopup_Create(EWndPopupType.LearnToPlay, null, "Online Help", 50, 50); // Show the help dialog at start... ###BUG: Does not change the combo box at top! SetForegroundWindow(_hWnd_Unity); //###WEAK: Can get rid of?? //if (CGame.INSTANCE._GameMode == EGameModes.None) //####TEMP // return; //=== Create the body publicly-editable body definitions that can construct and reconstruct CBody instances === //CGame.INSTANCE._nNumPenisInScene_BROKEN = 0; //###NOTE: For simplification in pose files we always have two bodies in the scene with man/shemale being body 0 and woman body 1 //CreateBody(0); // //CreateBody(1); _aBodyBases[0] = new CBodyBase(0, EBodySex.Woman); //###BROKEN _aBodyBases[0].SelectBody(); TemporarilyDisablePhysicsCollision(); ///SetPenisInVagina(false); // We initialize the penis in v****a state to false so v****a track colliders don't kick in at scene init if (CGame.INSTANCE._GameMode == EGameModes.Play) ScenePose_Load("Standing", false); // Load the default scene pose //###TODO ##NOW: Init GUI first!! //iGUISmartPrefab_WndPopup.WndPopup_Create(new CObject[] { oObj }, "Game Play", 0, 0); //###TEMP //Time.timeScale = 0.05f; //###REVA ###TEMP Gives more time for cloth to settle... but fix it some other way (with far stronger params??) ChangeGameMode(_GameModeAtStartup); // Set the initial game mode as statically requested Debug.LogFormat("Time at startup end: {0}", Time.time - _nTimeAtStart); //ScenePose_Load("Standing", false); // Load the default scene pose }