// Magica Cloth.
// Copyright (c) MagicaSoft, 2020-2022.
// https://magicasoft.jp
using System.Collections.Generic;
using Unity.Mathematics;
using UnityEngine;
namespace MagicaCloth
{
///
/// パーティクルゲームオブジェクト基底クラス
/// オブジェクトは複数のチームから利用される可能性があり、その場合はチームごとにパーティクルを生成する
///
public abstract class ParticleComponent : BaseComponent, IDataHash
{
///
/// パーティクルID
/// チームごと(自身は0)
///
protected Dictionary particleDict = new Dictionary();
///
/// 実行状態
///
protected RuntimeStatus status = new RuntimeStatus();
public RuntimeStatus Status
{
get
{
return status;
}
}
//=========================================================================================
///
/// データを識別するハッシュコードを作成して返す
///
///
public abstract int GetDataHash();
//=========================================================================================
public int CenterParticleIndex
{
get
{
if (particleDict.ContainsKey(0))
return particleDict[0].startIndex;
return -1;
}
}
//=========================================================================================
protected virtual void Start()
{
Init();
}
public virtual void OnEnable()
{
status.SetEnable(true);
status.UpdateStatus();
}
public virtual void OnDisable()
{
status.SetEnable(false);
status.UpdateStatus();
}
protected virtual void OnDestroy()
{
OnDispose();
status.SetDispose();
}
// 基本的にVerifyData()は常にtrueなので更新の必要なし
//protected virtual void Update()
//{
// if (status.IsInitSuccess)
// {
// var error = !VerifyData();
// status.SetRuntimeError(error);
// UpdateStatus();
// if (status.IsActive)
// OnUpdate();
// }
//}
//=========================================================================================
///
/// 初期化
/// 通常はStart()で呼ぶ
///
///
void Init()
{
status.UpdateStatusAction = OnUpdateStatus;
status.OwnerFunc = () => this;
if (status.IsInitComplete || status.IsInitStart)
return;
status.SetInitStart();
if (VerifyData() == false)
{
status.SetInitError();
return;
}
OnInit();
if (status.IsInitError)
return;
status.SetInitComplete();
status.UpdateStatus();
}
// 実行状態の更新通知
protected void OnUpdateStatus()
{
if (status.IsActive)
{
// 実行状態に入った
OnActive();
}
else
{
// 実行状態から抜けた
OnInactive();
}
}
///
/// 現在のデータが正常(実行できる状態)か返す
///
///
public virtual bool VerifyData()
{
return true;
}
//=========================================================================================
///
/// 初期化
///
protected virtual void OnInit() { }
///
/// 破棄
///
protected virtual void OnDispose()
{
if (MagicaPhysicsManager.IsInstance() == false)
return;
// パーティクルを破棄する
RemoveParticle();
}
///
/// 更新
///
protected virtual void OnUpdate() { }
///
/// 実行状態に入った場合に呼ばれます
///
protected virtual void OnActive()
{
// パーティクル有効化
EnableParticle();
}
///
/// 実行状態から抜けた場合に呼ばれます
///
protected virtual void OnInactive()
{
// パーティクル無効化
DisableParticle();
}
//=========================================================================================
///
/// パーティクル有効化
///
protected void EnableParticle()
{
foreach (var teamId in particleDict.Keys)
{
EnableTeamParticle(teamId);
}
}
///
/// パーティクル無効化
///
protected void DisableParticle()
{
if (MagicaPhysicsManager.IsInstance())
{
foreach (var teamId in particleDict.Keys)
{
DisableTeamParticle(teamId);
}
}
}
///
/// チームパーティクル有効化
///
///
protected void EnableTeamParticle(int teamId)
{
var c = particleDict[teamId];
MagicaPhysicsManager.Instance.Particle.SetEnable(
c,
true,
UserTransform,
UserTransformLocalPosition,
UserTransformLocalRotation
);
}
///
/// チームパーティクル無効化
///
///
protected void DisableTeamParticle(int teamId)
{
var c = particleDict[teamId];
MagicaPhysicsManager.Instance.Particle.SetEnable(
c,
false,
UserTransform,
UserTransformLocalPosition,
UserTransformLocalRotation
);
}
///
/// パーティクルのデータ更新を予約する
///
protected void ReserveDataUpdate()
{
if (MagicaPhysicsManager.IsInstance())
MagicaPhysicsManager.Instance.Component.ReserveDataUpdateParticleComponent(this);
}
///
/// パーティクルのデータ更新処理
///
internal virtual void DataUpdate() { }
///
/// 状態の更新
///
internal void UpdateStatus()
{
status.UpdateStatus();
}
//=========================================================================================
///
/// 指定チームのパーティクルを1つ作成
///
///
///
///
///
///
///
///
///
protected ChunkData CreateParticle(
uint flag,
int teamId,
float depth,
float3 radius,
float3 localPos
)
{
// すでに登録済みならば無効(v1.9.3)
if (particleDict.ContainsKey(teamId))
{
return new ChunkData();
}
// 自動追加フラグ
if (MagicaPhysicsManager.Instance.Team.IsFlag(teamId, PhysicsManagerTeamData.Flag_UpdatePhysics))
flag |= PhysicsManagerParticleData.Flag_Transform_UnityPhysics;
var t = transform;
var c = MagicaPhysicsManager.Instance.Particle.CreateParticle(
flag,
teamId,
t.position,
t.rotation,
depth,
radius,
localPos
);
particleDict.Add(teamId, c);
// 初期状態はDisable
DisableTeamParticle(teamId);
return c;
}
///
/// 指定チームのパーティクルを削除
///
///
protected void RemoveTeamParticle(int teamId)
{
if (MagicaPhysicsManager.IsInstance())
{
// パーティクル無効化
DisableTeamParticle(teamId);
// パーティクル削除
var c = particleDict[teamId];
MagicaPhysicsManager.Instance.Particle.RemoveParticle(c);
particleDict.Remove(teamId);
}
}
///
/// パーティクル削除
///
protected void RemoveParticle()
{
if (MagicaPhysicsManager.IsInstance())
{
foreach (var teamId in particleDict.Keys)
{
RemoveTeamParticle(teamId);
}
}
particleDict.Clear();
}
///
/// 頂点ごとの連動トランスフォーム設定(不要な場合はnull)
///
///
///
protected Transform UserTransform(int vindex)
{
return transform;
}
///
/// 頂点ごとの連動トランスフォームのLocalPositionを返す(不要な場合は0)
///
///
///
protected float3 UserTransformLocalPosition(int vindex)
{
return transform.localPosition;
}
///
/// 頂点ごとの連動トランスフォームのLocalRotationを返す(不要な場合はquaternion.identity)
///
///
///
protected quaternion UserTransformLocalRotation(int vindex)
{
return transform.localRotation;
}
}
}