using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.Events; using UnityEngine.EventSystems; using UnityEngine.UI; using UltraCombos.Utility.Collections; namespace UltraCombos.Frozen { public class CharacterBehaviour : MonoBehaviour { public ReorderableAppearSataes appearSataes; [System.Serializable] public class ReorderableAppearSataes : ReorderableList { } public float videoStopTime = 1.5f; public float disappearTime = 5.0f; public Area area; public List appearAreas = new List(); Vector2 wallRoi; float origin_height = 0.0f; [SerializeField] List specificPositions = new List(); [SerializeField, Range(0, 1)] float roaming = 0.0f; float roaming_seed = 0.0f; [Header("DShow Player")] [SerializeField] bool isStandbyLoop = true; public DShowClip standbyClip; public List triggerClips = new List(); int trigger_clip_index = 0; public uint triggerFrame = 0; //[SerializeField] private DShowMoviePlayer[] players; [Header("Event")] [SerializeField] UnityEvent onTrigger = new UnityEvent(); enum Status { TRIGGER = 0, STANDBY = 1, SLEEP = 2 } Status status = Status.SLEEP; DShowMoviePlayer StatePlayer { get { return players[(int)status]; } } MeshRenderer StateRenderer { get { return renderers[(int)status]; } } MeshRenderer[] renderers; bool isTriggered = false; Coroutine flow = null; bool is_alive = false; const float alive_threshold = 0.5f / 255.0f; float alive_value = 0.0f; [SerializeField, Header("Debug")] bool mode = false; public string info; private void Awake() { renderers = GetComponentsInChildren(); if (renderers.Length != 2) Debug.LogWarningFormat("{0} renderer count is {1}", gameObject.name, renderers.Length); //m_meshRender = GetComponent(); //mat = new Material(Shader.Find("Unlit/ColorTransparent")); //m_meshRender.material = mat; origin_height = transform.position.y; InitialiseDSPlayer(); } void InitialiseDSPlayer() { CreateDSPlayer(triggerClips[0]); CreateDSPlayer(standbyClip); players = GetComponentsInChildren(); } void CreateDSPlayer(DShowClip clip) { GameObject triggerObj = new GameObject(clip.name); triggerObj.transform.parent = this.transform; var player = triggerObj.AddComponent(); player.VideoAsset = clip; player.Load(); } void InitialTouchButton() { EventSystemHandler test_touch = GetComponentInChildren(); if (test_touch != null) { test_touch.onPointerDown.AddListener((data) => Trigger()); test_touch.onPointerDrag.AddListener((data) => Trigger()); } } private void Start() { foreach (var rdr in renderers) { rdr.material.mainTextureScale = new Vector2(1, -1); rdr.material.mainTextureOffset = new Vector2(0, -1); } } private void OnEnable() { InitialTouchButton(); ResetFlow(); //standby = true; //isSleep = false; //StartCoroutine(PlayStandbyOnStart()); //StartCoroutine(RandomPosNoTriggerOther()); //color = new Color(1, 1, 1, 0); //StartCoroutine(Sleep()); EnableTouch(); } public bool Active { set { if (value) Activate(); else Deactivate(); } } public void Activate() { if (is_alive) return; is_alive = true; gameObject.SetActive(true); } public void Deactivate() { if (is_alive == false) return; is_alive = false; } void EnableTouch() { } void DisableTouch() { } private void ResetFlow() { if (flow != null) { StopCoroutine(flow); flow = null; } isTriggered = false; foreach (var rdr in renderers) { rdr.material.color = new Color(1, 1, 1, 0); rdr.material.SetColor("_TintColor", new Color(1, 1, 1, 0)); } foreach (var ply in players) { ply.Pause(); ply.Frame = 0; } if (is_alive) { flow = StartCoroutine(Flow()); } } IEnumerator Flow() { if (mode) info = "setup"; // setup { if (specificPositions.Count > 0) { SetSpecificPos(); } else { RandomAppearWall(); } roaming_seed = Random.value * 10.0f; trigger_clip_index = ++trigger_clip_index % triggerClips.Count; players[(int)Status.TRIGGER].VideoAsset = triggerClips[trigger_clip_index]; yield return null; } if (mode) info = "STANDBY"; // standby { EnableTouch(); status = Status.STANDBY; var player = StatePlayer; player.Loop = isStandbyLoop; player.Play(); while (isTriggered == false) { if (mode) info = "STANDBY is not triggered"; if (player.Loop == false) { if (player.IsPlaying == false) { //player.Pause(); //player.Frame = player.TotalNumFrames; if (mode) info = "STANDBY is not triggered and set frame"; } } yield return null; } } if (mode) info = "TRIGGER"; // trigger { DisableTouch(); onTrigger.Invoke(); status = Status.TRIGGER; var player = StatePlayer; player.Play(); player.Frame = triggerFrame; while (player.IsPlaying) { if (mode) info = "TRIGGER is playing"; yield return null; } player.Pause(); player.Frame = player.TotalNumFrames; if (mode) info = "TRIGGER is stopped"; yield return new WaitForSeconds(videoStopTime); } if (mode) info = "SLEEP"; // sleep { status = Status.SLEEP; yield return new WaitForSeconds(disappearTime); } while (renderers[(int)Status.TRIGGER].material.color.a > 0.5f / 255.0f) { yield return null; } flow = null; yield return null; } void Update() { alive_value = Mathf.Lerp(alive_value, is_alive ? 1.0f : 0.0f, Time.deltaTime); if (is_alive == false && alive_value < alive_threshold) { alive_value = 0.0f; gameObject.SetActive(false); } for (int i = 0; i < players.Length; i++) { if (players[i].IsPlaying) { renderers[i].material.mainTexture = players[i].Texture; } } // standby material { float smooth = Time.deltaTime * 2.0f; if (status != Status.STANDBY && isStandbyLoop == false) smooth = 1.0f; float alpha = System.Convert.ToInt32(status == Status.STANDBY); alpha = Mathf.Min(alpha, alive_value); var mat = renderers[(int)Status.STANDBY].material; var col = new Color(1, 1, 1, Mathf.Lerp(mat.color.a, alpha, smooth)); mat.color = col; mat.SetColor("_TintColor", col); } // trigger material { float smooth = Time.deltaTime * 2.0f; if (status == Status.TRIGGER) smooth = 1.0f; float alpha = System.Convert.ToInt32(status == Status.TRIGGER); alpha = Mathf.Min(alpha, alive_value); var mat = renderers[(int)Status.TRIGGER].material; var col = new Color(1, 1, 1, Mathf.Lerp(mat.color.a, alpha, smooth)); mat.color = col; mat.SetColor("_TintColor", col); } switch (status) { case Status.STANDBY: { if (roaming > 0.0f) { UpdateRoamingPosition(); UpdateWallRoiFromPosition(); } } break; case Status.TRIGGER: { } break; case Status.SLEEP: { } break; } if (mode) { if (Input.GetKeyDown(KeyCode.R)) { ResetFlow(); } } if (flow == null) ResetFlow(); } void UpdateRoamingPosition() { float noise = Mathf.PerlinNoise(Time.time * 0.4f + roaming_seed, roaming_seed) > 0.5f ? 1.0f : -1.0f; noise *= roaming * Time.deltaTime; //float padding = transform.localScale.x * 0.5f; float padding = renderers[(int)Status.TRIGGER].transform.localScale.x * 0.5f; Vector3 pos = transform.position; switch (area) { case Area.TopWall: { float minmax = Mathf.Abs(padding - FrozenScreenToWorldSpace.Instance.width * 0.5f); float shift = FrozenScreenToWorldSpace.Instance.Position.x; pos.x = pos.x + noise; pos.x = Mathf.Clamp(pos.x, -minmax + shift, minmax + shift); transform.position = pos; } break; case Area.LeftWall: case Area.RightWall: { float minmax = Mathf.Abs(padding - FrozenScreenToWorldSpace.Instance.depth * 0.5f); float shift = FrozenScreenToWorldSpace.Instance.Position.z; pos.z = pos.z + noise; pos.z = Mathf.Clamp(pos.z, -minmax + shift, minmax + shift); transform.position = pos; } break; } } void RandomAppearWall() { Vector3 newPos = Vector3.zero; area = appearAreas[Random.Range(0, appearAreas.Count)]; Quaternion q = new Quaternion(); if (area == Area.LeftWall) { newPos.x = -FrozenScreenToWorldSpace.Instance.width / 2; q.SetLookRotation(Vector3.left); } if (area == Area.RightWall) { newPos.x = FrozenScreenToWorldSpace.Instance.width / 2; q.SetLookRotation(Vector3.right); } if (area == Area.TopWall) { newPos.z = FrozenScreenToWorldSpace.Instance.depth / 2; q.SetLookRotation(Vector3.forward); } transform.rotation = q; transform.position = newPos;// + FrozenScreenToWorldSpace.Instance.Position; RandomPos(); } void RandomPos() { float minX = renderers[(int)Status.TRIGGER].transform.localScale.x / 2; switch (area) { case Area.TopWall: wallRoi.x = Random.Range(minX, FrozenScreenToWorldSpace.Instance.width - minX) / FrozenScreenToWorldSpace.Instance.width; break; case Area.LeftWall: case Area.RightWall: wallRoi.x = Random.Range(minX, FrozenScreenToWorldSpace.Instance.depth - minX) / FrozenScreenToWorldSpace.Instance.depth; break; } wallRoi.y = origin_height / FrozenScreenToWorldSpace.Instance.height; UpdatePos(); } void UpdatePos() { Vector3 n_pos = transform.position; switch (area) { case Area.TopWall: n_pos.x = Mathf.Lerp(-FrozenScreenToWorldSpace.Instance.width / 2, FrozenScreenToWorldSpace.Instance.width / 2, wallRoi.x); break; case Area.LeftWall: case Area.RightWall: n_pos.z = Mathf.Lerp(-FrozenScreenToWorldSpace.Instance.depth / 2, FrozenScreenToWorldSpace.Instance.depth / 2, wallRoi.x); break; } n_pos.y = Mathf.Lerp(0.0f, FrozenScreenToWorldSpace.Instance.height, wallRoi.y); transform.position = n_pos + FrozenScreenToWorldSpace.Instance.Position; //SetButtonPos(); } void SetSpecificPos() { int pos_index = Random.Range(0, specificPositions.Count); var dummy = specificPositions[pos_index]; area = dummy.area; transform.position = dummy.transform.position; transform.rotation = dummy.transform.rotation; UpdateWallRoiFromPosition(); } void UpdateWallRoiFromPosition() { wallRoi = FrozenScreenToWorldSpace.Instance.GetWallRoiFromPosition(area, transform.position); } private void Trigger() { if (status != Status.STANDBY) return; isTriggered = true; } } }