using System; using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.Rendering; using HeavenStudio.Util; namespace HeavenStudio.Games.Scripts_PowerCalligraphy { public class Writing : MonoBehaviour { [Serializable] public struct PatternItem { public double beat; public SoundType soundType; public float soundVolume; public StrokeType stroke; public FudeType fudeAnim; } public enum SoundType { None = 0, brushTap, brush1, brush2, brush3, reShout, comma1, comma2, comma3, } public enum StrokeType { None = 0, TOME = 1, HANE, HARAI, } public enum FudeType { None = 0, Release, Tap, Prepare, } public double startBeat; public double ongoingBeat = Double.MinValue; public double nextBeat; [SerializeField] PatternItem[] AnimPattern; private Animator paperAnim; private SortingGroup paperSort; public Vector3 scrollSpeed; Vector3 scrollRate => scrollSpeed / (Conductor.instance.pitchedSecPerBeat * 2f); public bool onGoing = false; bool isFinish = false; int process_num; StrokeType stroke; public int Stroke { get { return (int)stroke; }} private PowerCalligraphy game; public void Init() { game = PowerCalligraphy.instance; paperAnim = GetComponent(); paperSort = GetComponent(); nextBeat = AnimPattern[^1].beat; } public void Play() { paperSort.sortingOrder++; var sounds = new List(); var actions = new List(); int anim_num = 0; foreach (var item in AnimPattern) { double itemBeat = startBeat + item.beat; string sound = item.soundType switch { SoundType.brushTap => "powerCalligraphy/brushTap", SoundType.brush1 => "powerCalligraphy/brush1", SoundType.brush2 => "powerCalligraphy/brush2", SoundType.brush3 => "powerCalligraphy/brush3", SoundType.reShout => "powerCalligraphy/reShout", SoundType.comma1 => "powerCalligraphy/comma1", SoundType.comma2 => "powerCalligraphy/comma2", SoundType.comma3 => "powerCalligraphy/comma3", _ => "" }; if (!string.IsNullOrEmpty(sound)) sounds.Add(new MultiSound.Sound(sound, itemBeat, volume:item.soundVolume)); int current_anim_num; switch (item.fudeAnim) { case FudeType.Release: anim_num++; current_anim_num = anim_num; actions.Add(new BeatAction.Action(itemBeat, delegate { Anim(current_anim_num); game.fudeAnim.DoScaledAnimationAsync("fude-none", 0.5f);})); break; case FudeType.Tap: anim_num++; current_anim_num = anim_num; actions.Add(new BeatAction.Action(itemBeat, delegate { Anim(current_anim_num); game.fudeAnim.DoScaledAnimationAsync("fude-tap", 0.5f);})); break; case FudeType.Prepare: actions.Add(new BeatAction.Action(itemBeat, delegate { game.fudeAnim.DoScaledAnimationAsync("fude-prepare", 0.5f);})); break; default: break; } int current_anim_num_1; switch(item.stroke) { case StrokeType.TOME: anim_num++; current_anim_num_1 = anim_num; actions.Add(new BeatAction.Action(itemBeat, delegate { Halt(); stroke = StrokeType.TOME; process_num = current_anim_num_1;})); actions.Add(new BeatAction.Action(itemBeat, delegate { onGoing = true; ongoingBeat = itemBeat;})); game.ScheduleInput(itemBeat, 1f, PowerCalligraphy.InputAction_BasicPress, writeSuccess, writeMiss, Empty, CanSuccess); break; case StrokeType.HANE: anim_num++; current_anim_num_1 = anim_num; actions.Add(new BeatAction.Action(itemBeat, delegate { Sweep(); stroke = StrokeType.HANE; process_num = current_anim_num_1;})); actions.Add(new BeatAction.Action(itemBeat+1, delegate { onGoing = true; ongoingBeat = itemBeat + 1;})); game.ScheduleInput(itemBeat, 2f, PowerCalligraphy.InputAction_FlickPress, writeSuccess, writeMiss, Empty, CanSuccess); break; case StrokeType.HARAI: anim_num++; current_anim_num_1 = anim_num; actions.Add(new BeatAction.Action(itemBeat, delegate { Sweep(); stroke = StrokeType.HARAI; process_num = current_anim_num_1;})); actions.Add(new BeatAction.Action(itemBeat+1, delegate { onGoing = true; ongoingBeat = itemBeat + 1;})); game.ScheduleInput(itemBeat, 2f, PowerCalligraphy.InputAction_FlickPress, writeSuccess, writeMiss, Empty, CanSuccess); break; default: break; } } actions.Add(new BeatAction.Action(startBeat + nextBeat, delegate { Finish();})); if (sounds.Count > 0) MultiSound.Play(sounds.ToArray()); if (actions.Count > 0) BeatAction.New(game, actions); } // TOME private void Halt() { game.fudeAnim.Play("fude-halt"); SoundByte.PlayOneShotGame("powerCalligraphy/releaseB1"); } // HANE HARAI private void Sweep() { game.fudeAnim.Play("fude-sweep"); SoundByte.PlayOneShotGame("powerCalligraphy/releaseA1", forcePlay: true); } private void Finish() { isFinish = true; paperSort.sortingOrder++; transform.SetParent(game.paperHolder.transform, true); game.fudeAnim.Play("fude-none"); paperAnim.enabled = false; } private void writeSuccess(PlayerActionEvent caller, float state) { if (state >= 1f) { ProcessInput("late"); game.ChouninMiss(); } else if (state <= -1f) { ProcessInput("fast"); game.ChouninMiss(); } else { ProcessInput("just"); } } private void writeMiss(PlayerActionEvent caller) { if (onGoing) Miss(); } private void Empty(PlayerActionEvent caller) { } bool CanSuccess() { return onGoing; } public void ProcessInput(string input) { onGoing = false; Anim(process_num, input); switch (input) { case "just": switch (stroke) { case StrokeType.TOME: game.fudeAnim.DoScaledAnimationAsync("fude-tap", 0.5f); SoundByte.PlayOneShotGame("powerCalligraphy/releaseB2"); break; case StrokeType.HANE: case StrokeType.HARAI: game.fudeAnim.DoScaledAnimationAsync("fude-none", 0.5f); SoundByte.PlayOneShotGame("powerCalligraphy/releaseA2"); break; } break; case "late": case "fast": game.fudeAnim.DoScaledAnimationAsync("fude-none", 0.5f); switch (stroke) { // WIP case StrokeType.TOME: SoundByte.PlayOneShotGame("powerCalligraphy/8"); break; case StrokeType.HANE: SoundByte.PlayOneShotGame("powerCalligraphy/6"); break; case StrokeType.HARAI: SoundByte.PlayOneShotGame("powerCalligraphy/9"); break; } break; default: break; } } public void Miss() { onGoing = false; SoundByte.PlayOneShotGame("powerCalligraphy/7"); // WIP Anim(process_num, "miss"); switch (stroke) { case StrokeType.TOME: game.fudeAnim.DoScaledAnimationAsync("fude-none", 0.5f); break; case StrokeType.HANE: case StrokeType.HARAI: game.fudeAnim.DoScaledAnimationAsync("fude-sweep-end", 0.5f); break; } } private void Anim(int num, string str = "") { string pattern = num.ToString() + str; game.fudePosAnim.DoScaledAnimationAsync(pattern, 0.5f); game.shiftAnim.DoScaledAnimationAsync(pattern, 0.5f); paperAnim.DoScaledAnimationAsync(pattern, 0.5f); } private void Update() { var cond = Conductor.instance; if (cond.isPlaying && !cond.isPaused) { if (ongoingBeat > 0) { float normalizedBeat = cond.GetPositionFromBeat(ongoingBeat, 1); float redRate = (normalizedBeat <= 0.5f) ? normalizedBeat/0.5f : (1.5f-normalizedBeat); if (game is not null) game.playerFude.redRate = redRate; } if (isFinish) { double beat = cond.songPositionInBeats; // Paper scroll. var paperPos = transform.localPosition; transform.localPosition = paperPos + (scrollRate * Time.deltaTime); if (beat >= startBeat + 24) Destroy(gameObject); } } } } }