// Magica Cloth 2. // Copyright (c) 2023 MagicaSoft. // https://magicasoft.jp using System; using System.Collections.Generic; using UnityEngine; namespace MagicaCloth2 { public partial class MagicaCloth { /// /// シリアライズデータ2の取得 /// SerializeData2クラスはシステムが利用するパラメータクラスです。 /// そのためユーザーによる変更は推奨されていません。 /// /// Acquisition of SerializedData2. /// The SerializeData2 class is a parameter class used by the system. /// Therefore, user modification is not recommended. /// /// public ClothSerializeData2 GetSerializeData2() { return serializeData2; } /// /// クロスデータ構築完了後イベント /// Event after completion of cloth data construction. /// (true = Success, false = Failure) /// public Action OnBuildComplete; /// /// 初期化を実行します /// すでに初期化済みの場合は何もしません。 /// perform initialization. /// If already initialized, do nothing. /// public void Initialize() { if (Application.isPlaying == false) return; Process.Init(); } /// /// コンポーネントのStart()で実行される自動ビルドを無効にします /// Disable automatic builds that run on the component's Start(). /// public void DisableAutoBuild() { if (Application.isPlaying == false) return; Process.SetState(ClothProcess.State_DisableAutoBuild, true); } /// /// コンポーネントを構築し実行します /// すべてのデータをセットアップしたあとに呼び出す必要があります /// build and run the component. /// Must be called after setting up all data. /// /// true=start build. false=build failed. public bool BuildAndRun() { bool ret = false; bool buildComplate = true; try { if (Application.isPlaying == false) throw new MagicaClothProcessingException(); DisableAutoBuild(); if (Process.IsState(ClothProcess.State_Build)) { Develop.LogError($"Already built.:{this.name}"); throw new MagicaClothProcessingException(); } // initialize generated data. if (Process.GenerateInitialization() == false) throw new MagicaClothProcessingException(); // check Pre-Build bool usePreBuildData = serializeData2.preBuildData.UsePreBuild(); if (usePreBuildData == false) { // Runtime Build. // setting by type. switch (serializeData.clothType) { case ClothProcess.ClothType.BoneCloth: case ClothProcess.ClothType.BoneSpring: // BoneCloth用のセレクションデータの作成 // ただしセレクションデータが存在し、かつユーザー定義されている場合は作成しない var nowSelection = serializeData2.selectionData; if (nowSelection == null || nowSelection.IsValid() == false || nowSelection.IsUserEdit() == false) { if (Process.GenerateBoneClothSelection() == false) throw new MagicaClothProcessingException(); } break; } // build and run. ret = Process.StartRuntimeBuild(); if (ret) buildComplate = false; // OnBuildCompleteはランタイム構築後に呼ばれる } else { // pre-build ret = Process.PreBuildDataConstruction(); } } catch (MagicaClothProcessingException) { } catch (Exception exception) { Debug.LogException(exception); } finally { // ビルド完了イベント if (buildComplate) OnBuildComplete?.Invoke(ret); } return ret; } /// /// コンポーネントが保持するトランスフォームを置換します。 /// 置換先のトランスフォーム名をキーとした辞書を渡します。 /// Replaces a component's transform. /// Passes a dictionary keyed by the name of the transform to be replaced. /// /// Dictionary keyed by the name of the transform to be replaced. public void ReplaceTransform(Dictionary targetTransformDict) { // コンポーネントが利用しているすべてのTransformを取得します var useTransformSet = new HashSet(); Process.GetUsedTransform(useTransformSet); // 置換処理用の辞書を作成 // key:置換対象トランスフォームのインスタンスID // value:入れ替えるトランスフォーム var replaceDict = new Dictionary(); foreach (var t in useTransformSet) { if (targetTransformDict.ContainsKey(t.name)) { replaceDict.Add(t.GetInstanceID(), targetTransformDict[t.name]); } } // 置換する Process.ReplaceTransform(replaceDict); } /// /// パラメータの変更を通知 /// 実行中にパラメータを変更した場合はこの関数を呼ぶ必要があります /// You should call this function if you changed parameters during execution. /// public void SetParameterChange() { if (IsValid()) { Process.DataUpdate(); } } /// /// タイムスケールを変更します /// Change the time scale. /// /// 0.0-1.0 public void SetTimeScale(float timeScale) { if (IsValid()) { ref var tdata = ref MagicaManager.Team.GetTeamDataRef(Process.TeamId); tdata.timeScale = Mathf.Clamp01(timeScale); } } /// /// タイムスケールを取得します /// Get the time scale. /// /// public float GetTimeScale() { if (IsValid()) { ref var tdata = ref MagicaManager.Team.GetTeamDataRef(Process.TeamId); return tdata.timeScale; } else return 1.0f; } /// /// シミュレーションを初期状態にリセットします /// Reset the simulation to its initial state. /// /// If true, resume while maintaining posture. public void ResetCloth(bool keepPose = false) { if (IsValid()) { ref var tdata = ref MagicaManager.Team.GetTeamDataRef(Process.TeamId); if (keepPose) { // Keep tdata.flag.SetBits(TeamManager.Flag_KeepTeleport, true); } else { // Reset tdata.flag.SetBits(TeamManager.Flag_Reset, true); tdata.flag.SetBits(TeamManager.Flag_TimeReset, true); tdata.flag.SetBits(TeamManager.Flag_CullingKeep, false); Process.SetState(ClothProcess.State_CullingKeep, false); Process.UpdateRendererUse(); } } } /// /// 慣性の中心座標を取得します /// Get the center of inertia position. /// /// public Vector3 GetCenterPosition() { if (IsValid()) { ref var cdata = ref MagicaManager.Team.GetCenterDataRef(Process.TeamId); return ClothTransform.TransformPoint(cdata.frameLocalPosition); } else return Vector3.zero; } /// /// 外力を加えます /// Add external force. /// /// /// (m/s) /// public void AddForce(Vector3 forceDirection, float forceVelocity, ClothForceMode fmode = ClothForceMode.VelocityAdd) { if (IsValid() && forceDirection.magnitude > 0.0f && forceVelocity > 0.0f && fmode != ClothForceMode.None) { ref var tdata = ref MagicaManager.Team.GetTeamDataRef(Process.TeamId); tdata.forceMode = fmode; tdata.impactForce = forceDirection.normalized * forceVelocity; } } /// /// TransformおよびMeshへの書き込みを禁止または許可します /// この機能を使うことでストップモーションを実装することが可能です /// Prevent or allow writing to Transform and Mesh. /// By using this function, it is possible to implement stop motion. /// /// true=write disabled, false=write enabled public void SetSkipWriting(bool sw) { if (IsValid()) { Process.SetSkipWriting(sw); } } } }