You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

552 lines
13 KiB
C#

using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public enum Sui_FX_Rules{
none,isUnderWater,isAboveWater,isAtWaterSurface,speedIsGreater,speedIsLess,
waterDepthGreater,waterDepthLess
}
public enum Sui_FX_RuleModifiers{
and,or
}
public enum Sui_FX_System{
none,bubbles,rings,ringfoam,splash,splashdrops
}
//public enum Sui_FX_ActionType{
// repeat,once
// }
namespace Suimono.Core
{
[ExecuteInEditMode]
public class fx_EffectObject : MonoBehaviour {
//PUBLIC VARIABLES
public Suimono.Core.SuimonoModuleFX fxObject;
public Sui_FX_Rules[] effectRule;
public float[] effectData;
public Sui_FX_Rules[] resetRule;
public string[] effectSystemName;
public Sui_FX_System[] effectSystem;
//public Sui_FX_ActionType actionType = Sui_FX_ActionType.repeat;
public Vector2 effectDelay = new Vector2(1.0f,1.0f);
public Vector2 emitTime = new Vector2(1.0f,1.0f);
public Vector2 emitNum = new Vector2(1.0f,1.0f);
public Vector2 effectSize = new Vector2(1.0f,1.0f);
public float emitSpeed;
public float speedThreshold;
public float directionMultiplier;
public bool emitAtWaterLevel = false;
public float effectDistance = 100.0f;
//audio
public AudioClip audioObj;
public Vector2 audioVol = new Vector2(0.9f,1.0f);
public Vector2 audioPit = new Vector2(0.8f,1.2f);
public float audioSpeed;
//events
public bool enableEvents = false;
//color
public Color tintCol = new Color(1f,1f,1f,1f);
public bool clampRot = false;
// for custom editor
public int actionIndex = 1;
[System.NonSerialized]public List<string> actionOptions = new List<string>(){
"Once","Repeat","Specific"
};
public int actionNum = 5;
public float actionReset = 15f;
public int typeIndex = 0;
public int[] ruleIndex;
[System.NonSerialized]public List<string> ruleOptions = new List<string>(){
"None","Object Is Underwater","Object Is Above Water","Object Is At Surface",
"Object Speed Is Greater Than","Object Speed Is Less Than","Water Depth Is Greater Than",
"Water Depth Is Less Than"
};
public int systemIndex = 0;
public List<string> sysNames = new List<string>();
public float currentSpeed ;
//PRIVATE VARIABLES
private int actionCount = 0;
private float actionTimer = 0f;
private Vector3 savePos = new Vector3(0f,0f,0f);
private Suimono.Core.SuimonoModule moduleObject;
private float emitTimer;
private bool delayPass = true;
private bool actionPass = true;
private float useSpd;
private float useAudioSpd;
private float isOverWater;
private float currentWaterPos;
private Vector3 emitPos;
private bool rulepass = false;
private float timerAudio = 0.0f;
private float timerParticle = 0.0f;
private float currentCamDistance = 0.0f;
//collect for GC
private Vector3 gizPos;
private int sN;
private int s;
private bool[] ruleCheck;
private int ruleCKNum = 0;
private bool[] resetCheck;
private int rCK;
private int emitN;
private float emitS;
private Vector3 emitV;
private float emitR;
private float emitAR;
private bool rp;
private float ruleData;
private float depth;
private Sui_FX_Rules[] tempRules;
private int[] tempIndex;
private float[] tempData;
private int aR;
private int endLP;
private int setInt;
private float[] heightValues;
private Transform transf;
private int randSeed;
private Suimono.Core.Random fxRand;
// create a simple cheap "smear" effect on the InvokeRepeating processor load.
// by shifting the work into rough groups via a simple static int, that we loop over.
// our global counter
static int staggerOffset = 0;
// our loop, we chose groups of roughly 20
static int staggerModulus = 20;
// our actual stagger value
private float stagger;
private float _deltaTime;
void OnDrawGizmos (){
gizPos = transform.position;
gizPos.y += 0.03f;
Gizmos.DrawIcon(gizPos, "gui_icon_fxobj.psd", true);
}
void Start () {
// Object References
transf = this.transform;
if (GameObject.Find("SUIMONO_Module")){
moduleObject = (Suimono.Core.SuimonoModule) FindObjectOfType(typeof(Suimono.Core.SuimonoModule));
if (moduleObject != null) fxObject = moduleObject.suimonoModuleLibrary.fxObject;
}
//populate system names
if (fxObject != null){
sysNames = fxObject.sysNames;
}
//set random
randSeed = System.Environment.TickCount;
fxRand = new Suimono.Core.Random(randSeed);
//run update loop at set FPS interval
staggerOffset++;
stagger = (staggerOffset+0f) *0.05f ;
staggerOffset = staggerOffset % staggerModulus;
InvokeRepeating("SetUpdate",0.1f+stagger,(1.0f/30.0f));
}
void SetUpdate(){
if (moduleObject != null){
//Cache Time for performance
_deltaTime = Time.deltaTime;
//check for action timing
actionPass = false;
if (actionIndex == 0 && actionCount < 1) actionPass = true;
if (actionIndex == 2 && actionCount < actionNum) actionPass = true;
if (actionIndex == 1) actionPass = true;
if (actionCount > 0 && (actionIndex == 0 || actionIndex == 2)){
actionTimer += _deltaTime;
if (actionTimer > actionReset && actionReset > 0f){
actionCount = 0;
actionTimer = 0f;
}
}
//set Random
if (fxRand == null) fxRand = new Suimono.Core.Random(randSeed);
//get objects while in editor mode
#if UNITY_EDITOR
if (!Application.isPlaying){
if (moduleObject == null){
if (GameObject.Find("SUIMONO_Module")){
moduleObject = GameObject.Find("SUIMONO_Module").GetComponent<Suimono.Core.SuimonoModule>() as Suimono.Core.SuimonoModule;
fxObject = moduleObject.suimonoModuleLibrary.fxObject;
}
}
}
#endif
if (Application.isPlaying){
//calculate camera distance
if (moduleObject.setTrack != null){
currentCamDistance = Vector3.Distance(transf.position,moduleObject.setTrack.transform.position);
if (currentCamDistance <= effectDistance){
//track position / speed
if (savePos != transf.position){
currentSpeed = Vector3.Distance(savePos,new Vector3(transf.position.x,transf.position.y,transf.position.z))/_deltaTime;
}
savePos = transf.position;
// track timers and emit
timerParticle += _deltaTime;
timerAudio += _deltaTime;
EmitFX();
if (timerAudio > audioSpeed){
timerAudio = 0f;
EmitSoundFX();
}
}
}
//Event trigger function
if (enableEvents){
timerEvent += _deltaTime;
BroadcastEvent();
}
}
}
}
void EmitSoundFX(){
if (actionPass){
if (audioObj != null && moduleObject != null){
if (moduleObject.gameObject.activeInHierarchy){
if (rulepass){
moduleObject.AddSoundFX(audioObj,emitPos,new Vector3(0f,fxRand.Next(audioPit.x,audioPit.y),fxRand.Next(audioVol.x,audioVol.y)));
}
}
}
}
}
void EmitFX () {
if (moduleObject.enableInteraction){
if (Application.isPlaying && moduleObject != null && moduleObject.gameObject.activeInHierarchy){
if (actionPass){
//######################################
//## CALCULATE TIMING and DELAYS ##
//######################################
delayPass = false;
emitTimer += _deltaTime;
if (emitTimer >= emitSpeed){
emitTimer = 0f;
delayPass = true;
}
//####################################
//## CALCULATE WATER RELATION ##
//####################################
heightValues = moduleObject.SuimonoGetHeightAll(transf.position);
currentWaterPos = heightValues[3];
isOverWater = heightValues[4];
//##########################
//## CALCULATE RULES ##
//##########################
rulepass = false;
if (ruleCheck == null) ruleCheck = new bool[effectRule.Length];
ruleCKNum = 0;
if (resetCheck == null) resetCheck = new bool[resetRule.Length];
if (Application.isPlaying){
var rp = false;
for (rCK = 0; rCK < effectRule.Length; rCK++){
//CHECK ALL RULES
rp = false;
ruleData = speedThreshold;
//get depth
depth = currentWaterPos;
if (rCK < effectData.Length) ruleData = effectData[rCK];
//rules.none
if (ruleIndex[rCK] == 0){
rp = true;
}
//rules.ObjectIsUnderwater
if (ruleIndex[rCK] == 1 && isOverWater==1f){
if (depth > 0f) rp = true;
}
//rules.ObjectIsAbovewater
if (ruleIndex[rCK] == 2 && isOverWater==1f){
if (depth <= 0f) rp = true;
}
//rules.ObjectIsAtSurface
if (ruleIndex[rCK] == 3 && isOverWater==1f){
if (depth < 0.15f && depth > -0.15f) rp = true;
}
//rules.speedIsGreater
if (ruleIndex[rCK] == 4 && isOverWater==1f){
if (currentSpeed > ruleData) rp = true;
}
//rules.speedIsLess
if (ruleIndex[rCK] == 5 && isOverWater==1f){
if (currentSpeed < ruleData) rp = true;
}
//rules.WaterDepthGreater
if (ruleIndex[rCK] == 6 && isOverWater==1f){
if (depth > ruleData) rp = true;
}
//rules.WaterDepthIsLess
if (ruleIndex[rCK] == 7 && isOverWater==1f){
if (depth < ruleData) rp = true;
}
ruleCheck[rCK] = rp;
}
}
//determine if all rules are passed
for (rCK = 0; rCK < effectRule.Length; rCK++){
if (ruleCheck[rCK]) ruleCKNum += 1;
}
if (ruleCKNum == effectRule.Length) rulepass = true;
//no rules
if (effectRule.Length == 0){
rulepass = true;
}
//######################
//## INITIATE FX ##
//######################
if (delayPass && rulepass){
emitN = Mathf.FloorToInt(fxRand.Next(emitNum.x,emitNum.y));
emitS = fxRand.Next(effectSize.x,effectSize.y);
emitV = new Vector3(0f,0f,0f);
emitPos = transform.position;
emitR = transform.eulerAngles.y-180f;
if (!clampRot){
emitR = fxRand.Next(-30f,10f);
}
emitAR = fxRand.Next(-360f,360f);
//get water level
if (emitAtWaterLevel){
emitPos = new Vector3(emitPos.x, (transform.position.y + currentWaterPos)-0.35f, emitPos.z);
}
if (directionMultiplier > 0f){
emitV = transform.up * (directionMultiplier * Mathf.Clamp01((currentSpeed/speedThreshold)));
}
//EMIT PARTICLE SYSTEM
if (timerParticle > emitSpeed){
timerParticle = 0f;
if (systemIndex-1 >= 0){
emitPos.y += (emitS*0.4f);
emitPos.x += fxRand.Next(-0.2f,0.2f);
emitPos.z += fxRand.Next(-0.2f,0.2f);
moduleObject.AddFX(systemIndex-1, emitPos, emitN, fxRand.Next(0.5f,0.75f)*emitS, emitR, emitAR, emitV, tintCol);
}
actionCount++;
}
}
}
}
}
}
public void AddRule(){
tempRules = effectRule;
tempIndex = ruleIndex;
tempData = effectData;
effectRule = new Sui_FX_Rules[tempRules.Length+1];
ruleIndex = new int[tempRules.Length+1];
effectData = new float[tempRules.Length+1];
for (aR = 0; aR < tempRules.Length; aR++){
effectRule[aR] = tempRules[aR];
ruleIndex[aR] = tempIndex[aR];
effectData[aR] = tempData[aR];
}
effectRule[tempRules.Length] = Sui_FX_Rules.none;
ruleIndex[tempRules.Length] = 0;
effectData[tempRules.Length] = 0;
}
public void DeleteRule(int ruleNum){
tempRules = effectRule;
tempIndex = ruleIndex;
tempData = effectData;
endLP = tempRules.Length-1;
if (endLP <= 0){
endLP = 0;
effectRule = new Sui_FX_Rules[0];
ruleIndex = new int[0];
effectData = new float[0];
} else {
effectRule = new Sui_FX_Rules[endLP];
ruleIndex = new int[endLP];
effectData = new float[endLP];
setInt = -1;
for (aR = 0; aR <= endLP; aR++){
if (aR != ruleNum){
setInt += 1;
} else {
setInt += 2;
}
if (setInt <= endLP){
effectRule[aR] = tempRules[setInt];
ruleIndex[aR] = tempIndex[setInt];
effectData[aR] = tempData[setInt];
}
}
}
}
void OnDisable(){
CancelInvoke("SetUpdate");
}
void OnEnable(){
staggerOffset++;
stagger = (staggerOffset+0f) *0.05f ;
staggerOffset = staggerOffset % staggerModulus;
CancelInvoke("SetUpdate");
InvokeRepeating("SetUpdate",0.1f+stagger,(1f/10f));
}
/// Used to broadcast location info.
public delegate void TriggerHandler(Vector3 position, Quaternion rotatoin);
// Broadcast when Event Trigger fires.
public event TriggerHandler OnTrigger;
// Broadcast interval in second.
public float eventInterval = 1f;
// Should event returns water level position instead of fx_EffectObject position?
public bool eventAtSurface = false;
// simple timer
private float timerEvent;
void BroadcastEvent()
{
if (!moduleObject.isActiveAndEnabled || !rulepass || OnTrigger == null || timerEvent < eventInterval) return;
timerEvent = 0f;
//Position: if atSurface is true, then return water level position, otherwise return this.transform.position
OnTrigger.Invoke(eventAtSurface ? new Vector3(emitPos.x, (transf.position.y + currentWaterPos) - 0.35f, emitPos.z) : transf.position, transf.rotation);
}
}
}