2026-06-20 뉴페어리

This commit is contained in:
2026-06-20 16:46:29 +09:00
parent 833dd50fa9
commit 295e284dd0
849 changed files with 116860 additions and 2 deletions

View File

@@ -0,0 +1,60 @@
// Magica Cloth 2.
// Copyright (c) 2023 MagicaSoft.
// https://magicasoft.jp
using UnityEngine;
namespace MagicaCloth2
{
public class AutoRotate : MonoBehaviour
{
public Vector3 eulers = new Vector3(0, 90, 0);
public Space space = Space.World;
public enum UpdateMode
{
Update,
FixedUpdate,
}
[SerializeField]
private UpdateMode updateMode = UpdateMode.Update;
[SerializeField]
[Range(0.1f, 5.0f)]
private float interval = 2.0f;
public bool useSin = true;
private float time = 0;
protected void FixedUpdate()
{
if (updateMode == UpdateMode.FixedUpdate)
UpdatePosition(Time.fixedDeltaTime);
}
protected void Update()
{
if (updateMode == UpdateMode.Update)
UpdatePosition(Time.deltaTime);
}
void UpdatePosition(float dtime)
{
if (useSin)
{
time += dtime;
float ang = (time % interval) / interval * Mathf.PI * 2.0f;
var t = Mathf.Sin(ang);
if (space == Space.World)
transform.eulerAngles = eulers * t;
else
transform.localEulerAngles = eulers * t;
}
else
{
transform.Rotate(eulers * dtime, space);
}
}
}
}

View File

@@ -0,0 +1,19 @@
fileFormatVersion: 2
guid: 4124c59241137374c9cae45d25683042
timeCreated: 1510336570
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 242307
packageName: Magica Cloth 2
packageVersion: 2.18.1
assetPath: Assets/MagicaCloth2/Example (Can be deleted)/Common/Scripts/AutoRotate.cs
uploadId: 893596

View File

@@ -0,0 +1,249 @@
// Magica Cloth 2.
// Copyright (c) 2023 MagicaSoft.
// https://magicasoft.jp
using UnityEngine;
namespace MagicaCloth2
{
/// <summary>
/// カメラ回転
/// </summary>
public class CameraOrbit : MonoBehaviour
{
[SerializeField]
private Transform cameraTransform;
[Header("Camera Target")]
public Transform cameraTarget;
public Vector3 cameraTargetPos;
public Vector3 cameraTargetOffset;
[Header("Now Position")]
[SerializeField]
private float cameraDist = 1.5f;
[SerializeField]
private float cameraPitch = 21.0f;
[SerializeField]
private float cameraYaw = 180.0f;
[Header("Parameter")]
[SerializeField]
private float cameraDistHokanTime = 0.1f;
[SerializeField]
private float cameraAngleHokanTime = 0.1f;
[SerializeField]
private float cameraDistSpeed = 0.02f;
[SerializeField]
private float cameraDistMax = 8.0f;
[SerializeField]
private float cameraDistMin = 0.1f;
[SerializeField]
private float cameraYawSpeed = 0.3f;
[SerializeField]
private float cameraPitchSpeed = 0.3f;
[SerializeField]
private float cameraMaxAngleSpeed = 100.0f;
[SerializeField]
private float cameraPitchMax = 89.0f;
[SerializeField]
private float cameraPitchMin = -89.0f;
// 中ボタンドラッグによる移動
public enum MoveMode
{
None,
UpDown,
Free,
}
[SerializeField]
private MoveMode moveMode = MoveMode.Free;
[SerializeField]
private float moveSpeed = 0.002f;
// 自動回転
[Header("Auto Rotation")]
[SerializeField]
private bool useAutoRotation = false;
[SerializeField]
private float autoRotationSpeed = 90.0f;
// 移動作業用
private float setCameraDist;
private float setCameraPitch;
private float setCameraYaw;
private float cameraDistVelocity;
private float cameraPitchVelocity;
private float cameraYawVelocity;
private float offsetYaw;
protected void Start()
{
if (cameraTransform == null)
{
var cam = GetComponent<Camera>();
if (cam)
cameraTransform = cam.transform;
}
if (cameraTransform == null)
enabled = false;
setCameraDist = cameraDist;
setCameraPitch = cameraPitch;
setCameraYaw = cameraYaw;
}
protected void OnEnable()
{
// 入力イベント登録
SimpleInputManager.OnTouchMove += OnTouchMove;
SimpleInputManager.OnDoubleTouchMove += OnDoubleTouchMove;
SimpleInputManager.OnTouchPinch += OnTouchPinch;
}
protected void OnDisable()
{
// 入力イベント解除
SimpleInputManager.OnTouchMove -= OnTouchMove;
SimpleInputManager.OnDoubleTouchMove -= OnDoubleTouchMove;
SimpleInputManager.OnTouchPinch -= OnTouchPinch;
}
protected void LateUpdate()
{
// カメラ更新
updateCamera();
}
// カメラ更新
private void updateCamera()
{
if (cameraTransform == null)
return;
// カメラターゲットポジション
cameraTargetPos = cameraTarget ? cameraTarget.position : transform.position;
// 補間
cameraDist = Mathf.SmoothDamp(cameraDist, setCameraDist, ref cameraDistVelocity, cameraDistHokanTime);
cameraPitch = Mathf.SmoothDampAngle(cameraPitch, setCameraPitch, ref cameraPitchVelocity, cameraAngleHokanTime);
cameraYaw = Mathf.SmoothDampAngle(cameraYaw, setCameraYaw, ref cameraYawVelocity, cameraAngleHokanTime);
// 自動回転
if (useAutoRotation)
{
offsetYaw += autoRotationSpeed * Time.deltaTime;
}
// 座標確定
Quaternion q = Quaternion.Euler(cameraPitch, cameraYaw + offsetYaw, 0);
q = transform.rotation * q; // コンポーネントの回転
Vector3 v = new Vector3(0, 0, -cameraDist);
Vector3 pos = q * v;
// ターゲットポジション
Vector3 tarpos = cameraTargetPos + transform.TransformVector(cameraTargetOffset);
Vector3 fixpos = tarpos + pos;
cameraTransform.position = fixpos;
// 回転確定
Vector3 relativePos = tarpos - cameraTransform.position;
Quaternion rot = Quaternion.LookRotation(relativePos, transform.up);
cameraTransform.rotation = rot;
}
// 回転操作
private void updatePitchYaw(Vector2 speed)
{
// Yaw
setCameraYaw += speed.x * cameraYawSpeed;
// Pitch
setCameraPitch += -speed.y * cameraPitchSpeed;
setCameraPitch = Mathf.Clamp(setCameraPitch, cameraPitchMin, cameraPitchMax);
}
// 移動操作
private void updateOffset(Vector2 speed)
{
if (cameraTransform == null)
{
return;
}
if (moveMode == MoveMode.UpDown)
{
cameraTargetOffset.y -= speed.y * moveSpeed;
}
else if (moveMode == MoveMode.Free)
{
Vector3 offset = moveSpeed * -speed.y * transform.InverseTransformDirection(cameraTransform.up);
offset += moveSpeed * -speed.x * transform.InverseTransformDirection(cameraTransform.right);
cameraTargetOffset += offset;
}
}
// ズーム操作
private void updateZoom(float speed)
{
float value = speed * cameraDistSpeed;
float scl = Mathf.InverseLerp(cameraDistMin, cameraDistMax, setCameraDist);
scl = Mathf.Clamp(scl, 0.1f, 1.0f);
setCameraDist -= value * scl;
setCameraDist = Mathf.Clamp(setCameraDist, cameraDistMin, cameraDistMax);
}
//=============================================================================================
/// <summary>
/// 入力通知:移動
/// </summary>
/// <param name="screenPos"></param>
/// <param name="screenVelocity"></param>
private void OnTouchMove(int fid, Vector2 screenPos, Vector2 screenVelocity, Vector2 cmVelocity)
{
screenVelocity *= SpeedAdjustment();
if (fid == 2)
{
// 中ドラッグ
updateOffset(screenVelocity);
}
else if (fid == 0)
{
// 左ドラッグ
// 最大速度
screenVelocity = Vector2.ClampMagnitude(screenVelocity, cameraMaxAngleSpeed);
updatePitchYaw(screenVelocity);
}
}
private void OnDoubleTouchMove(int fid, Vector2 screenPos, Vector2 screenVelocity, Vector2 cmVelocity)
{
screenVelocity *= SpeedAdjustment();
if (SimpleInputManager.Instance.GetTouchCount() >= 3)
updateOffset(screenVelocity);
}
/// <summary>
/// 入力通知:ピンチイン/アウト
/// </summary>
/// <param name="speedscr"></param>
/// <param name="speedcm"></param>
private void OnTouchPinch(float speedscr, float speedcm)
{
speedcm *= SpeedAdjustment();
if (SimpleInputManager.Instance.GetTouchCount() < 3)
updateZoom(speedcm);
}
private float SpeedAdjustment()
{
return Time.deltaTime * 60.0f;
}
}
}

View File

@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 1fd18111ed866534a92d0a2a59d1608d
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 242307
packageName: Magica Cloth 2
packageVersion: 2.18.1
assetPath: Assets/MagicaCloth2/Example (Can be deleted)/Common/Scripts/CameraOrbit.cs
uploadId: 893596

View File

@@ -0,0 +1,136 @@
// Magica Cloth 2.
// Copyright (c) 2023 MagicaSoft.
// https://magicasoft.jp
using UnityEngine;
namespace MagicaCloth2
{
/// <summary>
/// 基本的なシングルトンテンプレート
/// ・シーンに無い場合は作成する
/// ・自動初期化呼び出し機能
/// ・DontDestroyOnLoad設定
/// ・実行前でもInstanceアクセス可能
/// </summary>
/// <typeparam name="T"></typeparam>
public abstract class CreateSingleton<T> : MonoBehaviour where T : MonoBehaviour
{
private static T instance;
/// <summary>
/// 初期化フラグ
/// </summary>
private static T initInstance;
private static bool isDestroy;
/// <summary>
/// Reload Domain 対応
/// ※残念ながらジェネリッククラスでは[RuntimeInitializeOnLoadMethod]が利用できないため、
/// この初期化関数を派生元で[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
/// を使用して呼び出さなければならない
/// </summary>
protected static void InitMember()
{
instance = null;
initInstance = null;
isDestroy = false;
}
public static T Instance
{
get
{
if (instance == null)
{
// FindObjectOfTypeはそれなりに負荷がかかるので注意
// 非アクティブのオブジェクトは発見できないので注意!
#if UNITY_6000_4_OR_NEWER
instance = FindAnyObjectByType<T>();
#elif UNITY_2023_1_OR_NEWER
instance = FindFirstObjectByType<T>();
#else
instance = FindObjectOfType<T>();
#endif
if (instance == null && Application.isPlaying)
{
var obj = new GameObject(typeof(T).Name);
instance = obj.AddComponent<T>();
}
}
// 初期化
InitInstance();
return instance;
}
}
private static void InitInstance()
{
if (initInstance == null && instance != null && Application.isPlaying)
{
// シーン切り替えでもオブジェクトが消えないように設定
//DontDestroyOnLoad(instance.gameObject);
// 初期化呼び出し
var s = instance as CreateSingleton<T>;
s.InitSingleton();
initInstance = instance;
}
}
/// <summary>
/// インスタンスが存在する場合にTrueを返します
/// </summary>
/// <returns></returns>
public static bool IsInstance()
{
return instance != null && isDestroy == false;
}
/// <summary>
/// Awake()でのインスタンス設定
/// </summary>
protected virtual void Awake()
{
if (instance == null)
{
instance = this as T;
InitInstance();
}
else if (instance != this)
{
// 2つ目のコンポーネントを発見
var s = instance as CreateSingleton<T>;
s.DuplicateDetection(this as T);
// 2つ目のコンポーネントは破棄する
Destroy(this.gameObject);
}
}
protected virtual void OnDestroy()
{
// インスタンスクラスならば無効化フラグを立てる
if (instance == this)
{
isDestroy = true;
}
}
/// <summary>
/// 2つ目の破棄されるコンポーネントを通知
/// </summary>
/// <param name="duplicate"></param>
protected virtual void DuplicateDetection(T duplicate) { }
/// <summary>
/// 内部初期化
/// </summary>
protected abstract void InitSingleton();
}
}

View File

@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 0d1b801c369005647ae0e5a315e0bdaf
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 242307
packageName: Magica Cloth 2
packageVersion: 2.18.1
assetPath: Assets/MagicaCloth2/Example (Can be deleted)/Common/Scripts/CreateSingleton.cs
uploadId: 893596

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 776d5a1b173ef154c9bef26d30c53fcc
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 347fb6ccc378d9442a92b5316d0ff7c9
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,24 @@
{
"name": "MagicaCloth2UPMImporterShaderGraph",
"rootNamespace": "",
"references": [],
"includePlatforms": [
"Editor"
],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": true,
"defineConstraints": [
"!MC2_SHADERGRAPH"
],
"versionDefines": [
{
"name": "com.unity.shadergraph",
"expression": "12.0.0",
"define": "MC2_SHADERGRAPH"
}
],
"noEngineReferences": false
}

View File

@@ -0,0 +1,14 @@
fileFormatVersion: 2
guid: 34d2974f64e7a9f49a48b400abf046ff
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 242307
packageName: Magica Cloth 2
packageVersion: 2.18.1
assetPath: Assets/MagicaCloth2/Example (Can be deleted)/Common/Scripts/Editor/ShaderGraph/MagicaCloth2UPMImporterShaderGraph.asmdef
uploadId: 893596

View File

@@ -0,0 +1,30 @@
// Magica Cloth 2.
// Copyright (c) 2023 MagicaSoft.
// https://magicasoft.jp
using UnityEditor;
using UnityEditor.PackageManager;
using UnityEngine;
namespace MagicaCloth2UPMImporterCollections
{
/// <summary>
/// 必要なUnityPackageの自動インストール
/// </summary>
[InitializeOnLoad]
public static class UnityPackageImporter
{
static UnityPackageImporter()
{
Install("com.unity.shadergraph");
}
public static bool Install(string id)
{
Debug.Log($"Install...{id}");
var request = Client.Add(id);
while (!request.IsCompleted) { };
if (request.Error != null) Debug.LogError(request.Error.message);
return request.Error == null;
}
}
}

View File

@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: dd5d6386919360640adca6564193a8f5
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 242307
packageName: Magica Cloth 2
packageVersion: 2.18.1
assetPath: Assets/MagicaCloth2/Example (Can be deleted)/Common/Scripts/Editor/ShaderGraph/UnityPackageImporter.cs
uploadId: 893596

View File

@@ -0,0 +1,44 @@
// Magica Cloth 2.
// Copyright (c) 2023 MagicaSoft.
// https://magicasoft.jp
using System.Collections.Generic;
using UnityEngine;
namespace MagicaCloth2
{
public class GameObjectContainer : MonoBehaviour
{
[SerializeField]
private List<GameObject> gameObjectList = new List<GameObject>();
private Dictionary<string, GameObject> gameObjectDict = new Dictionary<string, GameObject>();
protected void Awake()
{
// create dictionary.
foreach (var obj in gameObjectList)
{
if (obj)
{
gameObjectDict.Add(obj.name, obj);
}
}
}
public bool Contains(string objName)
{
return gameObjectDict.ContainsKey(objName);
}
public GameObject GetGameObject(string objName)
{
if (gameObjectDict.ContainsKey(objName))
{
return gameObjectDict[objName];
}
else
return null;
}
}
}

View File

@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 4357444b3effcf149a7c0557d3c4ddc5
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 242307
packageName: Magica Cloth 2
packageVersion: 2.18.1
assetPath: Assets/MagicaCloth2/Example (Can be deleted)/Common/Scripts/GameObjectContainer.cs
uploadId: 893596

View File

@@ -0,0 +1,25 @@
{
"name": "MagicaCloth2Example",
"rootNamespace": "",
"references": [
"MagicaClothV2",
"Unity.InputSystem"
],
"includePlatforms": [],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": true,
"precompiledReferences": [],
"autoReferenced": false,
"defineConstraints": [
"MAGICACLOTH2"
],
"versionDefines": [
{
"name": "com.unity.inputsystem",
"expression": "1.0.0",
"define": "MC2_INPUTSYSTEM"
}
],
"noEngineReferences": false
}

View File

@@ -0,0 +1,14 @@
fileFormatVersion: 2
guid: 5bc0ea054e216f5498d1a84885db7ab1
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 242307
packageName: Magica Cloth 2
packageVersion: 2.18.1
assetPath: Assets/MagicaCloth2/Example (Can be deleted)/Common/Scripts/MagicaCloth2Example.asmdef
uploadId: 893596

View File

@@ -0,0 +1,82 @@
// Magica Cloth 2.
// Copyright (c) 2023 MagicaSoft.
// https://magicasoft.jp
using System.Collections.Generic;
using UnityEngine;
namespace MagicaCloth2
{
public class ModelController : MonoBehaviour
{
[SerializeField]
private List<GameObject> characterList = new List<GameObject>();
[SerializeField]
private float slowTime = 0.1f;
private bool slow;
protected void Start()
{
slow = false;
}
private void AnimatorAction(System.Action<Animator> act)
{
foreach (var chara in characterList)
{
if (chara && chara.activeInHierarchy)
{
var animator = chara.GetComponent<Animator>();
if (animator)
{
act(animator);
}
}
}
}
private void ClothAction(System.Action<MagicaCloth> act)
{
foreach (var chara in characterList)
{
if (chara && chara.activeInHierarchy)
{
var clothList = chara.GetComponentsInChildren<MagicaCloth>(true);
if (clothList != null)
{
foreach (var cloth in clothList)
{
act(cloth);
}
}
}
}
}
public void OnNextButton()
{
AnimatorAction((ani) => ani.SetTrigger("Next"));
}
public void OnBackButton()
{
AnimatorAction((ani) => ani.SetTrigger("Back"));
}
public void OnSlowButton()
{
slow = !slow;
float timeScale = slow ? slowTime : 1.0f;
AnimatorAction((ani) => ani.speed = timeScale);
ClothAction((cloth) => cloth.SetTimeScale(timeScale));
}
public void OnActiveButton()
{
ClothAction((cloth) => cloth.gameObject.SetActive(!cloth.gameObject.activeSelf));
}
}
}

View File

@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 49572a6b5327127438636ad59bdb9226
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 242307
packageName: Magica Cloth 2
packageVersion: 2.18.1
assetPath: Assets/MagicaCloth2/Example (Can be deleted)/Common/Scripts/ModelController.cs
uploadId: 893596

View File

@@ -0,0 +1,248 @@
// Magica Cloth 2.
// Copyright (c) 2023 MagicaSoft.
// https://magicasoft.jp
using UnityEngine;
namespace MagicaCloth2
{
/// <summary>
/// A sample that builds MagicaCloth at runtime.
/// </summary>
public class RuntimeBuildDemo : MonoBehaviour
{
[SerializeField]
private GameObject characterPrefab;
[SerializeField]
private MagicaCloth frontHairSource;
[SerializeField]
private string ribbonPresetName;
[SerializeField]
private string skirtName;
[SerializeField]
private Texture2D skirtPaintMap;
GameObject character;
GameObjectContainer gameObjectContainer;
protected void Start()
{
character = null;
gameObjectContainer = null;
}
public void OnCreateButton()
{
if (character)
return;
// Generate a character from a prefab.
GenerateCharacter();
// BoneCloth construction example (1).
SetupHairTail_BoneCloth();
// BoneCloth construction example (2).
SetupFrontHair_BoneCloth();
// BoneCloth construction example (3).
SetupRibbon_BoneCloth();
// MeshCloth construction example (1).
SetupSkirt_MeshCloth();
}
public void OnRemoveButton()
{
if (character)
{
Destroy(character);
character = null;
gameObjectContainer = null;
}
}
/// <summary>
/// Generate a character from a prefab.
/// A character already contains a<GameObjectContainer> to reference a GameObject.
/// This component is optional.
/// It's just there to help with data construction.
/// </summary>
void GenerateCharacter()
{
if (characterPrefab)
{
character = Instantiate(characterPrefab, transform);
gameObjectContainer = character.GetComponent<GameObjectContainer>();
}
}
/// <summary>
/// BoneCloth construction example (1).
/// Set all parameters from a script.
/// </summary>
void SetupHairTail_BoneCloth()
{
if (character == null)
return;
var obj = new GameObject("HairTail_BoneCloth");
obj.transform.SetParent(character.transform, false);
// add Magica Cloth
var cloth = obj.AddComponent<MagicaCloth>();
var sdata = cloth.SerializeData;
// bone cloth
sdata.clothType = ClothProcess.ClothType.BoneCloth;
sdata.rootBones.Add(gameObjectContainer.GetGameObject("J_L_HairTail_00_B").transform);
sdata.rootBones.Add(gameObjectContainer.GetGameObject("J_R_HairTail_00_B").transform);
// setup parameters
sdata.gravity = 3.0f;
sdata.damping.SetValue(0.05f);
sdata.angleRestorationConstraint.stiffness.SetValue(0.15f, 1.0f, 0.15f, true);
sdata.angleRestorationConstraint.velocityAttenuation = 0.6f;
sdata.tetherConstraint.distanceCompression = 0.5f;
sdata.inertiaConstraint.particleSpeedLimit.SetValue(true, 3.0f);
sdata.colliderCollisionConstraint.mode = ColliderCollisionConstraint.Mode.None;
// start build
cloth.BuildAndRun();
}
/// <summary>
/// BoneCloth construction example (2).
/// Copy parameters from an existing component.
/// </summary>
void SetupFrontHair_BoneCloth()
{
if (character == null || frontHairSource == null)
return;
var obj = new GameObject("HairFront_BoneCloth");
obj.transform.SetParent(character.transform, false);
// add Magica Cloth
var cloth = obj.AddComponent<MagicaCloth>();
var sdata = cloth.SerializeData;
// bone cloth
sdata.clothType = ClothProcess.ClothType.BoneCloth;
sdata.rootBones.Add(gameObjectContainer.GetGameObject("J_L_HairFront_00_B").transform);
sdata.rootBones.Add(gameObjectContainer.GetGameObject("J_L_HairSide2_00_B").transform);
sdata.rootBones.Add(gameObjectContainer.GetGameObject("J_L_HairSide_00_B").transform);
sdata.rootBones.Add(gameObjectContainer.GetGameObject("J_R_HairFront_00_B").transform);
sdata.rootBones.Add(gameObjectContainer.GetGameObject("J_R_HairSide2_00_B").transform);
sdata.rootBones.Add(gameObjectContainer.GetGameObject("J_R_HairSide_00_B").transform);
// Normal direction setting for backstop
sdata.normalAlignmentSetting.alignmentMode = NormalAlignmentSettings.AlignmentMode.Transform;
sdata.normalAlignmentSetting.adjustmentTransform = gameObjectContainer.GetGameObject("HeadCenter").transform;
// setup parameters
// Copy from source settings
sdata.Import(frontHairSource, false);
// start build
cloth.BuildAndRun();
}
/// <summary>
/// BoneCloth construction example (3).
/// Load parameters from saved presets.
/// </summary>
void SetupRibbon_BoneCloth()
{
if (character == null || string.IsNullOrEmpty(ribbonPresetName))
return;
var obj = new GameObject("Ribbon_BoneCloth");
obj.transform.SetParent(character.transform, false);
// add Magica Cloth
var cloth = obj.AddComponent<MagicaCloth>();
var sdata = cloth.SerializeData;
// bone cloth
sdata.clothType = ClothProcess.ClothType.BoneCloth;
sdata.rootBones.Add(gameObjectContainer.GetGameObject("J_L_HeadRibbon_00_B").transform);
sdata.rootBones.Add(gameObjectContainer.GetGameObject("J_R_HeadRibbon_00_B").transform);
// setup parameters
// Load presets from the Resource folder.
// Since presets are in TextAssets format, they can also be used as asset bundles.
var presetText = Resources.Load<TextAsset>(ribbonPresetName);
sdata.ImportJson(presetText.text);
// start build
cloth.BuildAndRun();
}
/// <summary>
/// MeshCloth construction example (1).
/// Reads vertex attributes from a paintmap.
/// </summary>
void SetupSkirt_MeshCloth()
{
if (character == null || skirtPaintMap == null)
return;
// skirt renderer
var sobj = gameObjectContainer.GetGameObject(skirtName);
if (sobj == null)
return;
if (!sobj.TryGetComponent<Renderer>(out var skirtRenderer))
return;
// add Magica Cloth
var obj = new GameObject("Skirt_MeshCloth");
obj.transform.SetParent(character.transform, false);
var cloth = obj.AddComponent<MagicaCloth>();
var sdata = cloth.SerializeData;
// mesh cloth
sdata.clothType = ClothProcess.ClothType.MeshCloth;
sdata.sourceRenderers.Add(skirtRenderer);
// reduction settings
sdata.reductionSetting.simpleDistance = 0.0212f;
sdata.reductionSetting.shapeDistance = 0.0244f;
// paint map settings
// *** Paintmaps must have Read/Write attributes enabled! ***
sdata.paintMode = ClothSerializeData.PaintMode.Texture_Fixed_Move;
sdata.paintMaps.Add(skirtPaintMap);
// setup parameters
sdata.gravity = 1.0f;
sdata.damping.SetValue(0.03f);
sdata.angleRestorationConstraint.stiffness.SetValue(0.05f, 1.0f, 0.5f, true);
sdata.angleRestorationConstraint.velocityAttenuation = 0.5f;
sdata.angleLimitConstraint.useAngleLimit = true;
sdata.angleLimitConstraint.limitAngle.SetValue(45.0f, 0.0f, 1.0f, true);
sdata.distanceConstraint.stiffness.SetValue(0.5f, 1.0f, 0.5f, true);
sdata.tetherConstraint.distanceCompression = 0.9f;
sdata.inertiaConstraint.depthInertia = 0.7f;
sdata.inertiaConstraint.movementSpeedLimit.SetValue(true, 3.0f);
sdata.inertiaConstraint.particleSpeedLimit.SetValue(true, 3.0f);
sdata.colliderCollisionConstraint.mode = ColliderCollisionConstraint.Mode.Point;
// setup collider
// UpperLeg L
var lobj = new GameObject("CapsuleCollider_L");
lobj.transform.SetParent(gameObjectContainer.GetGameObject("Character1_LeftUpLeg").transform);
lobj.transform.localPosition = new Vector3(0.0049f, 0.0f, -0.0832f);
lobj.transform.localEulerAngles = new Vector3(0.23f, 16.376f, -0.028f);
var colliderL = lobj.AddComponent<MagicaCapsuleCollider>();
colliderL.direction = MagicaCapsuleCollider.Direction.Z;
colliderL.SetSize(0.082f, 0.094f, 0.3f);
// UpperLeg R (Symmetry)
colliderL.symmetryMode = ColliderSymmetryMode.AutomaticHumanBody;
colliderL.UpdateParameters(); // Required when changing parameters.
sdata.colliderCollisionConstraint.colliderList.Add(colliderL);
// start build
cloth.BuildAndRun();
}
}
}

View File

@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: d0126e2925cecdf4a933c28a27f415ac
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 242307
packageName: Magica Cloth 2
packageVersion: 2.18.1
assetPath: Assets/MagicaCloth2/Example (Can be deleted)/Common/Scripts/RuntimeBuildDemo.cs
uploadId: 893596

View File

@@ -0,0 +1,210 @@
// Magica Cloth 2.
// Copyright (c) 2023 MagicaSoft.
// https://magicasoft.jp
using System.Collections.Generic;
using UnityEngine;
namespace MagicaCloth2
{
/// <summary>
/// Dress-up sample.
/// </summary>
public class RuntimeDressUpDemo : MonoBehaviour
{
/// <summary>
/// Avatar to change clothes.
/// </summary>
public GameObject targetAvatar;
/// <summary>
/// Hair prefab with MagicaCloth set in advance.
/// </summary>
public GameObject hariEqupPrefab;
/// <summary>
/// Clothes prefab with MagicaCloth set in advance.
/// </summary>
public GameObject bodyEquipPrefab;
//=========================================================================================
/// <summary>
/// Bones dictionary of avatars to dress up.
/// </summary>
Dictionary<string, Transform> targetAvatarBoneMap = new Dictionary<string, Transform>();
/// <summary>
/// Information class for canceling dress-up.
/// </summary>
class EquipInfo
{
public GameObject equipObject;
public List<ColliderComponent> colliderList;
public bool IsValid() => equipObject != null;
}
EquipInfo hairEquipInfo = new EquipInfo();
EquipInfo bodyEquipInfo = new EquipInfo();
//=========================================================================================
protected void Start()
{
Init();
}
//=========================================================================================
public void OnHairEquipButton()
{
if (hairEquipInfo.IsValid())
Remove(hairEquipInfo);
else
Equip(hariEqupPrefab, hairEquipInfo);
}
public void OnBodyEquipButton()
{
if (bodyEquipInfo.IsValid())
Remove(bodyEquipInfo);
else
Equip(bodyEquipPrefab, bodyEquipInfo);
}
//=========================================================================================
/// <summary>
/// Create an avatar bone dictionary in advance.
/// </summary>
void Init()
{
Debug.Assert(targetAvatar);
// Create all bone maps for the target avatar
foreach (Transform bone in targetAvatar.GetComponentsInChildren<Transform>())
{
if (targetAvatarBoneMap.ContainsKey(bone.name) == false)
{
targetAvatarBoneMap.Add(bone.name, bone);
}
else
{
Debug.Log($"Duplicate bone name :{bone.name}");
}
}
}
/// <summary>
/// Equip clothes.
/// </summary>
/// <param name="equipPrefab"></param>
/// <param name="einfo"></param>
void Equip(GameObject equipPrefab, EquipInfo einfo)
{
Debug.Assert(equipPrefab);
// Generate a prefab with cloth set up.
var gobj = Instantiate(equipPrefab, targetAvatar.transform);
// All cloth components included in the prefab.
var clothList = new List<MagicaCloth>(gobj.GetComponentsInChildren<MagicaCloth>());
// All collider components included in the prefab.
var colliderList = new List<ColliderComponent>(gobj.GetComponentsInChildren<ColliderComponent>());
// All renderers included in the prefab.
var skinList = new List<SkinnedMeshRenderer>(gobj.GetComponentsInChildren<SkinnedMeshRenderer>());
// First stop the automatic build that is executed with Start().
// And just in case, it does some initialization called Awake().
foreach (var cloth in clothList)
{
// Normally it is called with Awake(), but if the component is disabled, it will not be executed, so call it manually.
// Ignored if already run with Awake().
cloth.Initialize();
// Turn off auto-build on Start().
cloth.DisableAutoBuild();
}
// Swap the bones of the SkinnedMeshRenderer.
// This process is a general dress-up process for SkinnedMeshRenderer.
// Comment out this series of processes when performing this process with functions such as other assets.
foreach (var sren in skinList)
{
var bones = sren.bones;
Transform[] newBones = new Transform[bones.Length];
for (int i = 0; i < bones.Length; ++i)
{
Transform bone = bones[i];
if (!targetAvatarBoneMap.TryGetValue(bone.name, out newBones[i]))
{
// Is the bone the renderer itself?
if (bone.name == sren.name)
{
newBones[i] = sren.transform;
}
else
{
// bone not found
Debug.Log($"[SkinnedMeshRenderer({sren.name})] Unable to map bone [{bone.name}] to target skeleton.");
}
}
}
sren.bones = newBones;
// root bone
if (targetAvatarBoneMap.ContainsKey(sren.rootBone != null ? sren.rootBone.name : null))
{
sren.rootBone = targetAvatarBoneMap[sren.rootBone.name];
}
}
// Here, replace the bones used by the MagicaCloth component.
foreach (var cloth in clothList)
{
// Replaces a component's transform.
cloth.ReplaceTransform(targetAvatarBoneMap);
}
// Move all colliders to the new avatar.
foreach (var collider in colliderList)
{
Transform parent = collider.transform.parent;
if (parent && targetAvatarBoneMap.ContainsKey(parent.name))
{
Transform newParent = targetAvatarBoneMap[parent.name];
// After changing the parent, you need to write back the local posture and align it.
collider.transform.GetLocalPositionAndRotation(out var localPosition, out var localRotation);
collider.transform.SetParent(newParent);
collider.transform.SetLocalPositionAndRotation(localPosition, localRotation);
}
}
// Finally let's start building the cloth component.
foreach (var cloth in clothList)
{
// I disabled the automatic build, so I build it manually.
cloth.BuildAndRun();
}
// Record information for release.
einfo.equipObject = gobj;
einfo.colliderList = colliderList;
}
/// <summary>
/// Removes equipped clothing.
/// </summary>
/// <param name="einfo"></param>
void Remove(EquipInfo einfo)
{
Destroy(einfo.equipObject);
foreach (var c in einfo.colliderList)
{
Destroy(c.gameObject);
}
einfo.equipObject = null;
einfo.colliderList.Clear();
}
}
}

View File

@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: e72f8cfc2a22d184e86b4e1905cdf3ec
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 242307
packageName: Magica Cloth 2
packageVersion: 2.18.1
assetPath: Assets/MagicaCloth2/Example (Can be deleted)/Common/Scripts/RuntimeDressUpDemo.cs
uploadId: 893596

View File

@@ -0,0 +1,196 @@
// Magica Cloth 2.
// Copyright (c) 2025 MagicaSoft.
// https://magicasoft.jp
using UnityEngine;
#if MC2_INPUTSYSTEM
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.EnhancedTouch;
#endif
namespace MagicaCloth2
{
/// <summary>
/// InputManager/InputSystem入力切り替えラッパー
/// </summary>
public class SimpleInput
{
#if MC2_INPUTSYSTEM
// (New) Imput System
public static void Init()
{
EnhancedTouchSupport.Enable();
}
public static int touchCount
{
get
{
return UnityEngine.InputSystem.EnhancedTouch.Touch.activeTouches.Count;
}
}
public static UnityEngine.Touch GetTouch(int index)
{
var touchData = new UnityEngine.Touch();
int count = UnityEngine.InputSystem.EnhancedTouch.Touch.activeTouches.Count;
if (index < count)
{
var touch = UnityEngine.InputSystem.EnhancedTouch.Touch.activeTouches[index];
// convert
touchData.fingerId = touch.finger.index;
touchData.position = touch.screenPosition;
touchData.deltaPosition = touch.delta;
switch (touch.phase)
{
case UnityEngine.InputSystem.TouchPhase.Canceled:
touchData.phase = UnityEngine.TouchPhase.Canceled;
break;
case UnityEngine.InputSystem.TouchPhase.Ended:
touchData.phase = UnityEngine.TouchPhase.Ended;
break;
case UnityEngine.InputSystem.TouchPhase.Moved:
touchData.phase = UnityEngine.TouchPhase.Moved;
break;
case UnityEngine.InputSystem.TouchPhase.Began:
touchData.phase = UnityEngine.TouchPhase.Began;
break;
}
}
return touchData;
}
public static bool GetKey(KeyCode key)
{
switch (key)
{
case KeyCode.Escape:
return Keyboard.current.escapeKey.isPressed;
default:
return false;
}
}
public static bool GetKeyDown(KeyCode key)
{
switch (key)
{
case KeyCode.Backspace:
return Keyboard.current.backspaceKey.wasPressedThisFrame;
default:
return false;
}
}
public static bool GetMouseButtonDown(int button)
{
switch (button)
{
case 0:
return Mouse.current.leftButton.wasPressedThisFrame;
case 1:
return Mouse.current.rightButton.wasPressedThisFrame;
case 2:
return Mouse.current.middleButton.wasPressedThisFrame;
default:
return false;
}
}
public static bool GetMouseButtonUp(int button)
{
switch (button)
{
case 0:
return Mouse.current.leftButton.wasReleasedThisFrame;
case 1:
return Mouse.current.rightButton.wasReleasedThisFrame;
case 2:
return Mouse.current.middleButton.wasReleasedThisFrame;
default:
return false;
}
}
public static Vector3 mousePosition
{
get
{
return Mouse.current.position.ReadValue();
}
}
public static float GetMouseScrollWheel()
{
// 古いInputSystemに不具合あり
// ホイールデルタがデフォルトでx120されて返ってくる
// これはWindowsのみの挙動でMac/Linuxでは発生しない
// そしてUnity 2023.2以降は修正された
float value = Mouse.current.scroll.ReadValue().y * 0.12f; // base
#if UNITY_2023_2_OR_NEWER
return value;
#else
#if UNITY_STANDALONE_WIN || UNITY_EDITOR_WIN
return value / 120.0f; // ホイールデルタの不具合を吸収
#else
return value;
#endif
#endif
}
#else
// (Old) Imput Manager
public static void Init()
{
}
public static int touchCount
{
get
{
return Input.touchCount;
}
}
public static Touch GetTouch(int index)
{
return Input.GetTouch(index);
}
public static bool GetKey(KeyCode key)
{
return Input.GetKey(key);
}
public static bool GetKeyDown(KeyCode key)
{
return Input.GetKeyDown(key);
}
public static bool GetMouseButtonDown(int button)
{
return Input.GetMouseButtonDown(button);
}
public static bool GetMouseButtonUp(int button)
{
return Input.GetMouseButtonUp(button);
}
public static Vector3 mousePosition
{
get
{
return Input.mousePosition;
}
}
public static float GetMouseScrollWheel()
{
return Input.GetAxis("Mouse ScrollWheel");
}
#endif
}
}

View File

@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: ab72fcfec8965ae4181307a06400b57b
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 242307
packageName: Magica Cloth 2
packageVersion: 2.18.1
assetPath: Assets/MagicaCloth2/Example (Can be deleted)/Common/Scripts/SimpleInput.cs
uploadId: 893596

View File

@@ -0,0 +1,602 @@
// Magica Cloth 2.
// Copyright (c) 2023 MagicaSoft.
// https://magicasoft.jp
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.EventSystems;
namespace MagicaCloth2
{
/// <summary>
/// 入力マネージャ
/// ・簡単なタップやフリック判定
/// ・PCの場合はマウスによる自動エミュレーション
/// </summary>
public class SimpleInputManager : CreateSingleton<SimpleInputManager>
{
// 最大タッチ数
private const int MaxFinger = 3;
/// <summary>
/// タップ有効半径(cm)
/// </summary>
public float tapRadiusCm = 0.5f;
/// <summary>
/// フリック判定距離(cm)
/// </summary>
public float flickRangeCm = 0.01f;
/// <summary>
/// フリック判定速度(cm/s)
/// </summary>
public float flickCheckSpeed = 1.0f;
/// <summary>
/// マウスホイールのピンチイン・ピンチアウト速度係数
/// </summary>
public float mouseWheelSpeed = 5.0f;
// 入力情報管理
private int mainFingerId = -1;
private int subFingerId = -1;
private Vector2[] downPos; // 入力開始座標(スクリーン)
private Vector2[] lastPos;
private Vector2[] flickDownPos; // 入力開始座標(スクリーン)
private float[] flickDownTime;
private float lastTime = 0; // バックボタンの連続入力防止用
// モバイル情報管理
private bool mobilePlatform = false;
// マウスエミュレーション情報管理
private bool[] mouseDown;
private Vector2[] mouseOldMovePos;
// モニタ情報
private float screenDpi; // スクリーンDPI値
private float screenDpc; // スクリーンDots per cm値当たりのピクセル数
//------------------------------ モバイルタッチパネル/マウスエミュレーション ------------------
// タッチ開始通知
// タッチされた時に、フィンガーID、その位置スクリーンを通知します。
public static UnityAction<int, Vector2> OnTouchDown;
// 移動通知
// タッチされたまま移動された場合に、フィンガーID、その位置スクリーン、速度(スクリーン比率/s)、速度(cm/s)を通知します。
public static UnityAction<int, Vector2, Vector2, Vector2> OnTouchMove;
// ダブルタッチされたまま移動された場合に、フィンガーID、その位置スクリーン、速度(スクリーン比率/s)、速度(cm/s)を通知します。
public static UnityAction<int, Vector2, Vector2, Vector2> OnDoubleTouchMove;
// タッチ終了通知
// タッチが離されたフィンガーID、位置スクリーンを通知します。
public static UnityAction<int, Vector2> OnTouchUp;
// タッチキャンセル通知
// タッチ移動がキャンセル主に画面外に移動された場合に、フィンガーID、その最終位置スクリーンを通知します。
public static UnityAction<int, Vector2> OnTouchMoveCancel;
// タップ通知
// タップされた時に、フィンガーID、その位置スクリーンを通知します。
public static UnityAction<int, Vector2> OnTouchTap;
// フリック通知
// フリック判定された場合に、フィンガーID、その位置スクリーン、フリック速度(スクリーン比率/s)、速度(cm/s)を通知します。
public static UnityAction<int, Vector2, Vector2, Vector2> OnTouchFlick;
// ピンチイン/アウト通知
// ピンチイン/アウトの速度(スクリーン比率/s、速度(cm/s)を通知します。
public static UnityAction<float, float> OnTouchPinch;
// バックボタン通知Androiddeでは戻るボタン、PCでは BackSpace ボタン)
public static UnityAction OnBackButton;
//=========================================================================================
/// <summary>
/// Reload Domain 対策
/// </summary>
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
private static void Init()
{
InitMember();
}
//=========================================================================================
protected override void InitSingleton()
{
SimpleInput.Init();
// スクリーン情報
CalcScreenDpi();
// 情報初期化
downPos = new Vector2[MaxFinger];
lastPos = new Vector2[MaxFinger];
flickDownPos = new Vector2[MaxFinger];
flickDownTime = new float[MaxFinger];
// マウス用
mouseDown = new bool[3];
mouseOldMovePos = new Vector2[3];
AllResetTouchInfo();
// モバイルプラットフォーム判定
mobilePlatform = Application.isMobilePlatform;
}
protected void Update()
{
// 入力タイプ別更新処理
if (mobilePlatform)
{
// モバイル用タッチ入力
UpdateMobile();
}
else
{
// マウスエミュレーション
UpdateMouse();
}
}
//=========================================================================================
/// <summary>
/// スクリーンのDPI値(Dots per inchi)1インチ当たりのピクセル数を取得する
/// </summary>
public static float ScreenDpi
{
get
{
return Instance.screenDpi;
}
}
/// <summary>
/// スクリーンのDPC値(Dots per cm)1cm当たりのピクセル数を取得する
/// </summary>
public static float ScreenDpc
{
get
{
return Instance.screenDpc;
}
}
/// <summary>
/// スクリーンDpi/Dpcの再計算
/// </summary>
private void CalcScreenDpi()
{
screenDpi = Screen.dpi;
if (screenDpi == 0.0f)
{
screenDpi = 96; // ダミー
}
screenDpc = screenDpi / 2.54f; // インチをcmに変換
}
// タッチ入力情報リセット
private void AllResetTouchInfo()
{
mainFingerId = -1;
subFingerId = -1;
for (int i = 0; i < 3; i++)
{
mouseDown[i] = false;
}
}
public int GetTouchCount()
{
return SimpleInput.touchCount;
}
public bool IsUI()
{
if (EventSystem.current == null)
return false;
if (mobilePlatform)
{
// モバイル用タッチ入力
return EventSystem.current.IsPointerOverGameObject(SimpleInput.GetTouch(0).fingerId);
}
else
{
// マウスエミュレーション
return EventSystem.current.IsPointerOverGameObject();
}
}
//=========================================================================================
/// <summary>
/// モバイル用入力更新
/// </summary>
private void UpdateMobile()
{
int count = SimpleInput.touchCount;
if (count == 0)
{
AllResetTouchInfo();
// バックボタン
if (Application.platform == RuntimePlatform.Android)
{
if (SimpleInput.GetKey(KeyCode.Escape) && lastTime + 0.2f < Time.time)
{
lastTime = Time.time;
if (OnBackButton != null)
{
OnBackButton();
}
return;
}
}
}
else
{
// メイン
for (int i = 0; i < count; i++)
{
Touch touch = SimpleInput.GetTouch(i);
int fid = touch.fingerId;
// フィンガーIDが以外は無視する
if (fid >= 2)
{
continue;
}
if (touch.phase == TouchPhase.Began)
{
if (IsUI())
continue;
// down pos
downPos[fid] = touch.position;
lastPos[fid] = touch.position;
flickDownPos[fid] = touch.position;
if (fid == 0)
{
mainFingerId = fid;
}
else
{
subFingerId = fid;
}
// Downはメインフィンガーのみ
if (fid == 0)
{
flickDownTime[fid] = Time.time;
if (OnTouchDown != null)
{
OnTouchDown(fid, touch.position);
}
}
}
else if (touch.phase == TouchPhase.Moved)
{
// ピンチイン/アウト判定
if (mainFingerId >= 0 && subFingerId >= 0)
{
Vector2 t1pos = Vector2.zero;
Vector2 t2pos = Vector2.zero;
Vector2 t1delta = Vector2.zero;
Vector2 t2delta = Vector2.zero;
int setcnt = 0;
for (int j = 0; j < count; j++)
{
Touch t = SimpleInput.GetTouch(j);
if (mainFingerId == t.fingerId)
{
t1pos = t.position;
t1delta = t.deltaPosition;
setcnt++;
}
else if (subFingerId == t.fingerId)
{
t2pos = t.position;
t2delta = t.deltaPosition;
setcnt++;
}
}
if (setcnt == 2)
{
float nowdist = Vector2.Distance(t1pos, t2pos);
float olddist = Vector2.Distance(t1pos - t1delta, t2pos - t2delta);
float dist = nowdist - olddist;
// cm/sに変換
float distcm = dist / screenDpc; // 移動量(cm)
float speedcm = distcm / Time.deltaTime; // 速度(cm/s)
// スクリーン比率の速度
float speedscr = (dist / (Screen.width + Screen.height) * 0.5f) / Time.deltaTime;
// ピンチ通知(移動量(cm), 速度(cm/s))
if (OnTouchPinch != null)
{
OnTouchPinch(speedscr, speedcm);
}
}
if (fid == 0)
{
Vector2 distVec2 = touch.position - lastPos[fid];
Vector2 distcm = distVec2 / screenDpc; // 移動量(cm)
Vector2 speedcm = distcm / Time.deltaTime; // 速度(cm/s)
// 速度(スクリーン比率)
Vector2 speedscr = CalcScreenRatioVector(distVec2) / Time.deltaTime;
// 移動通知(現在スクリーン座標、速度(スクリーン比率), 速度(cm/s))
if (OnDoubleTouchMove != null)
{
OnDoubleTouchMove(fid, touch.position, speedscr, speedcm);
}
lastPos[fid] = touch.position;
}
}
else
{
// Moveはメインフィンガーのみ
if (fid == 0 && mainFingerId >= 0)
{
Vector2 distVec2 = touch.position - lastPos[fid];
Vector2 distcm = distVec2 / screenDpc; // 移動量(cm)
Vector2 speedcm = distcm / Time.deltaTime; // 速度(cm/s)
// 速度(スクリーン比率)
Vector2 speedscr = CalcScreenRatioVector(distVec2) / Time.deltaTime;
// 移動通知(現在スクリーン座標、速度(スクリーン比率), 速度(cm/s))
if (OnTouchMove != null)
{
OnTouchMove(fid, touch.position, speedscr, speedcm);
}
// フリックダウン位置更新
flickDownPos[fid] = (flickDownPos[fid] + touch.position) * 0.5f;
flickDownTime[fid] = Time.time;
}
lastPos[fid] = touch.position;
}
}
else if (touch.phase == TouchPhase.Ended)
{
// フィンガーIDのリリース
if (fid == 0)
{
mainFingerId = -1;
subFingerId = -1;
}
else
{
subFingerId = -1;
}
// End, Tap はメインフィンガーのみ
if (fid == 0)
{
// タップ判定
float dist = Vector2.Distance(downPos[fid], touch.position);
float distcm = dist / screenDpc;
if (distcm <= tapRadiusCm)
{
// タップ通知
if (OnTouchTap != null)
{
OnTouchTap(fid, touch.position);
}
}
// フリック判定
else
{
CheckFlic(fid, downPos[fid], touch.position, flickDownPos[fid], flickDownTime[fid]);
}
// タップアップ通知
if (OnTouchUp != null)
{
OnTouchUp(fid, touch.position);
}
}
}
else if (touch.phase == TouchPhase.Canceled)
{
// フィンガーIDのリリース
if (fid == 0)
{
mainFingerId = -1;
subFingerId = -1;
}
else
{
subFingerId = -1;
}
// Cancelはメインフィンガーのみ
if (fid == 0)
{
if (OnTouchMoveCancel != null)
{
OnTouchMoveCancel(fid, touch.position);
}
}
}
}
}
}
/// <summary>
/// スクリーン比率に変換したベクトルを求める
/// </summary>
/// <param name="vec"></param>
/// <returns></returns>
private Vector2 CalcScreenRatioVector(Vector2 vec)
{
return new Vector2(vec.x / Screen.width, vec.y / Screen.height);
}
/// <summary>
/// フリック判定
/// </summary>
/// <param name="oldpos"></param>
/// <param name="nowpos"></param>
/// <param name="downpos"></param>
/// <param name="flicktime"></param>
/// <returns></returns>
private bool CheckFlic(int fid, Vector2 oldpos, Vector2 nowpos, Vector2 downpos, float flicktime)
{
// フリック判定
float dist = Vector2.Distance(nowpos, downpos);
float distcm = dist / screenDpc;
if (distcm > flickRangeCm)
{
{
// 移動ピクセルをcm変換し、速度cm/sを割り出す
Vector2 distVec = (nowpos - downpos);
Vector2 distVec2 = distVec / screenDpc; // cmへ変換(移動量(cm))
float timeInterval = Time.time - flicktime;
float speedX = distVec2.x / timeInterval; // 速度(cm/s)
float speedY = distVec2.y / timeInterval; // 速度(cm/s)
//Develop.Log("distVec", distVec * 100);
//Develop.Log("sppedX:", speedX, " speedY:", speedY);
if (Mathf.Abs(speedX) >= flickCheckSpeed || Mathf.Abs(speedY) >= flickCheckSpeed)
{
// フリック通知(スクリーン位置,速度(スクリーン比率/s,速度(cm/s))
if (OnTouchFlick != null)
{
OnTouchFlick(fid, nowpos, CalcScreenRatioVector(distVec) / timeInterval, new Vector2(speedX, speedY));
}
return true;
}
}
}
return false;
}
//=========================================================================================
/// <summary>
/// 入力情報更新PC用
/// マウスエミュレーション
/// ・右クリックは使わない。
/// ・ピンチイン/アウトはマウスホイール。
/// </summary>
private void UpdateMouse()
{
// BackSpace を Android 端末のバックボタンに割り当てる
if (SimpleInput.GetKeyDown(KeyCode.Backspace))
{
if (OnBackButton != null)
OnBackButton();
return;
}
for (int i = 0; i < 3; i++)
{
// マウスボタンダウン
if (SimpleInput.GetMouseButtonDown(i))
{
if (IsUI())
continue;
if (mouseDown[i] == false && i == 0)
{
flickDownTime[i] = Time.time;
}
mouseDown[i] = true;
// 入力位置を記録
downPos[i] = SimpleInput.mousePosition;
mouseOldMovePos[i] = SimpleInput.mousePosition;
if (i == 0)
flickDownPos[i] = SimpleInput.mousePosition;
// タッチダウンイベント発行
if (OnTouchDown != null)
OnTouchDown(i, SimpleInput.mousePosition);
}
// マウスボタンアップ
if (SimpleInput.GetMouseButtonUp(i) && mouseDown[i])
{
mouseDown[i] = false;
// フリック判定
if (i == 0)
{
CheckFlic(i, mouseOldMovePos[i], SimpleInput.mousePosition, flickDownPos[i], flickDownTime[i]);
}
mouseOldMovePos[i] = Vector2.zero;
// タッチアップイベント
if (OnTouchUp != null)
OnTouchUp(i, SimpleInput.mousePosition);
// タップ判定
float distcm = Vector2.Distance(downPos[0], SimpleInput.mousePosition) / screenDpc;
if (distcm <= tapRadiusCm)
{
if (OnTouchTap != null)
OnTouchTap(i, SimpleInput.mousePosition);
}
}
// 移動
if (mouseDown[i])
{
Vector2 spos = new Vector2(SimpleInput.mousePosition.x, SimpleInput.mousePosition.y);
Vector2 delta = spos - mouseOldMovePos[i];
if (spos != mouseOldMovePos[i])
{
// 速度
Vector3 deltacm = delta / screenDpc; // 移動量(cm)
Vector2 speedcm = deltacm / Time.deltaTime; // 速度(cm/s)
// 移動通知(現在スクリーン座標、速度(スクリーン比率/s)、速度(cm/s))
if (OnTouchMove != null)
OnTouchMove(i, SimpleInput.mousePosition, CalcScreenRatioVector(delta) / Time.deltaTime, speedcm);
}
mouseOldMovePos[i] = SimpleInput.mousePosition;
// フリックダウン位置更新
flickDownPos[i] = (flickDownPos[i] + spos) * 0.5f;
flickDownTime[i] = Time.time;
}
}
// ピンチイン/アウト
float w = SimpleInput.GetMouseScrollWheel();
if (Mathf.Abs(w) > 0.01f)
{
// モバイル入力とスケール感を合わせるために係数を掛ける
w *= mouseWheelSpeed;
float speedcm = w / Time.deltaTime;
float speedscr = (w / (Screen.width + Screen.height) * 0.5f) / Time.deltaTime;
// 通知(速度(スクリーン比率/s)、速度(cm/s)
if (OnTouchPinch != null)
OnTouchPinch(speedscr, speedcm);
}
}
}
}

View File

@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 08208c43232950a4f8b6eae1f7919c13
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 242307
packageName: Magica Cloth 2
packageVersion: 2.18.1
assetPath: Assets/MagicaCloth2/Example (Can be deleted)/Common/Scripts/SimpleInputManager.cs
uploadId: 893596

View File

@@ -0,0 +1,46 @@
// Magica Cloth 2.
// Copyright (c) 2023 MagicaSoft.
// https://magicasoft.jp
using UnityEngine;
using UnityEngine.UI;
namespace MagicaCloth2
{
public class SliderText : MonoBehaviour
{
[SerializeField]
private Text text = null;
[SerializeField]
private string lable = "";
[SerializeField]
private string format = "0.00";
private string formatString;
protected void Start()
{
formatString = "{0} ({1:" + format + "})";
var slider = GetComponent<Slider>();
if (slider)
{
slider.onValueChanged.AddListener(OnChangeValue);
var val = slider.value;
slider.value = 0.001f;
slider.value = val;
}
}
private void OnChangeValue(float value)
{
if (text)
{
text.text = string.Format(formatString, lable, value);
}
}
}
}

View File

@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 37e7fecf2cf6fff42800da6e57c20d5d
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 242307
packageName: Magica Cloth 2
packageVersion: 2.18.1
assetPath: Assets/MagicaCloth2/Example (Can be deleted)/Common/Scripts/SliderText.cs
uploadId: 893596

View File

@@ -0,0 +1,19 @@
// Magica Cloth 2.
// Copyright (c) 2023 MagicaSoft.
// https://magicasoft.jp
using UnityEngine;
namespace MagicaCloth2
{
public class TargetFPS : MonoBehaviour
{
public int frameRate = 60;
#if !UNITY_EDITOR
protected void Start()
{
Application.targetFrameRate = frameRate;
}
#endif
}
}

View File

@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 70abefeafa131dd428880b40bd4c183c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 242307
packageName: Magica Cloth 2
packageVersion: 2.18.1
assetPath: Assets/MagicaCloth2/Example (Can be deleted)/Common/Scripts/TargetFPS.cs
uploadId: 893596

View File

@@ -0,0 +1,94 @@
// Magica Cloth 2.
// Copyright (c) 2023 MagicaSoft.
// https://magicasoft.jp
using System.Collections.Generic;
using UnityEngine;
namespace MagicaCloth2
{
public class WindDemo : MonoBehaviour
{
[SerializeField]
private MagicaWindZone magicaWindZone;
[SerializeField]
private WindZone unityWindZone;
[SerializeField]
private Renderer arrowRenderer = null;
[SerializeField]
private Gradient arrowGradient = new Gradient();
[SerializeField]
private List<Transform> rotationTransforms = new List<Transform>();
private float angleY = 0.0f;
private float angleX = 0.0f;
private float main = 0.0f;
private float turbulence = 0.0f;
public void OnDirectionY(float value)
{
angleY = value;
UpdateDirection();
}
public void OnDirectionX(float value)
{
angleX = value;
UpdateDirection();
}
public void OnMain(float value)
{
main = value;
UpdateMagicaWindZone();
UpdateUnityWindZone();
UpdateArrowColor();
}
public void OnTurbulence(float value)
{
turbulence = value;
UpdateMagicaWindZone();
}
//=========================================================================================
void UpdateArrowColor()
{
if (arrowRenderer)
{
// color
var t = Mathf.Clamp01(Mathf.InverseLerp(0.0f, 20.0f, main));
var col = arrowGradient.Evaluate(t);
arrowRenderer.material.color = col * 0.7f;
}
}
void UpdateDirection()
{
var lrot = Quaternion.Euler(angleX, angleY, 0.0f);
foreach (var t in rotationTransforms)
if (t)
t.localRotation = lrot;
UpdateMagicaWindZone();
}
void UpdateMagicaWindZone()
{
if (magicaWindZone)
{
magicaWindZone.main = main;
magicaWindZone.turbulence = turbulence;
magicaWindZone.directionAngleX = angleX;
magicaWindZone.directionAngleY = angleY;
}
}
void UpdateUnityWindZone()
{
if (unityWindZone)
{
unityWindZone.windMain = main;
}
}
}
}

View File

@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 13f11cb1bd01c684b9a48fd075e6a541
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 242307
packageName: Magica Cloth 2
packageVersion: 2.18.1
assetPath: Assets/MagicaCloth2/Example (Can be deleted)/Common/Scripts/WindDemo.cs
uploadId: 893596