Power Calligraphy fixed #Feature Complete (#794)

* Power Calligraphy (WIP)

* modified:   Assets/Scripts/Games/PowerCalligraphy/Writing.cs

* comma

* onore

* sweep

* sun

* kokoro

* Power Calligraphy (WIP)

* Changed object to prefab

* Force Prepare

* Changed so that the next paper is set correctly.

* updated controllers

* Red hand

* Paper shift

* Chounin (WIP)

* Power Calligraphy #Feature Complete

* Fixed Animations to 30fps
This commit is contained in:
フマジメ
2024-03-18 11:40:24 +09:00
committed by GitHub
parent 2fab37113d
commit faaf3854db
340 changed files with 25593 additions and 5560 deletions

View File

@ -0,0 +1,94 @@
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Rendering;
using HeavenStudio.Util;
namespace HeavenStudio.Games.Scripts_PowerCalligraphy
{
public class Fude : MonoBehaviour
{
[Header("References")]
[SerializeField] SpriteRenderer handRenderer;
[SerializeField] SpriteRenderer thumbRenderer;
[SerializeField] SpriteRenderer stickRenderer;
[SerializeField] SpriteRenderer tipRenderer;
[SerializeField] SpriteRenderer ballRenderer;
[Header("Variables")]
[SerializeField] float REDRATE_1;
[SerializeField] float REDRATE_2;
public float redRate = 0;
private int red
{
get
{
if (redRate >= REDRATE_2)
{
return 2;
}
else if (redRate >= REDRATE_1)
{
return 1;
}
else
{
return 0;
}
}
}
public static Sprite GetSprite(string spriteName) {
Sprite[] sprites = Resources.LoadAll<Sprite>("Sprites/Games/PowerCalligraphy/fude");
return System.Array.Find<Sprite>(sprites, (sprite) => sprite.name.Equals(spriteName));
}
public void HaltTurnRed(int frame)
{
int stick = 0, tip = 0;
if (frame==0)
{
stick = 1;
}
else
{
stick = frame + 2;
}
tip = frame + 7;
TurnRed(stick, tip, red);
}
public void SweepTurnRed(int frame)
{
int stick = 0, tip = 0;
if (frame<=5)
{
tip = frame + 1;
}
else
{
stick = 2;
tip = frame%2 + 5;
}
TurnRed(stick, tip, red);
}
public void TurnRed(int stick, int tip, int red)
{
handRenderer.sprite = GetSprite($"hand_{red}");
thumbRenderer.sprite = GetSprite($"thumb_{red}");
stickRenderer.sprite = GetSprite($"fude_stick_{stick}_{red}");
tipRenderer.sprite = GetSprite($"fude_tip_{tip}_{red}");
ballRenderer.sprite = GetSprite($"fude_ball_{red}");
}
public void Tap()
{
TurnRed(0, 12, red);
}
public void Idle()
{
TurnRed(0, 0, red);
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 73db3026877efe94896eff1fcc86ab8a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -18,46 +18,48 @@ namespace HeavenStudio.Games.Loaders
{
return new Minigame("powerCalligraphy", "Power Calligraphy", "ffffff", false, false, new List<GameAction>()
{
new GameAction("bop", "Bop")
{
function = delegate {var e = eventCaller.currentEntity; PowerCalligraphy.instance.ToggleBop(e.beat, e.length, e["bop"], e["bopAuto"]); },
resizable = true,
parameters = new List<Param>()
{
new Param("bop", true, "Bop", "Toggle if the paddlers should bop for the duration of this event."),
new Param("bopAuto", false, "Bop (Auto)", "Toggle if the paddlers should automatically bop until another Bop event is reached.")
}
},
new GameAction("re", "Re (レ)")
{
preFunction = delegate {var e = eventCaller.currentEntity; PowerCalligraphy.instance.QueuePaper(e.beat, (int)PowerCalligraphy.CharacterType.re); },
function = delegate {var e = eventCaller.currentEntity; PowerCalligraphy.instance.Write(e.beat, (int)PowerCalligraphy.CharacterType.re); },
defaultLength = 8f,
},
new GameAction("comma", "Comma (、)")
{
preFunction = delegate {var e = eventCaller.currentEntity; PowerCalligraphy.instance.QueuePaper(e.beat, (int)PowerCalligraphy.CharacterType.comma); },
function = delegate {var e = eventCaller.currentEntity; PowerCalligraphy.instance.Write(e.beat, (int)PowerCalligraphy.CharacterType.comma); },
defaultLength = 8f,
},
new GameAction("chikara", "Chikara (力)")
{
preFunction = delegate {var e = eventCaller.currentEntity; PowerCalligraphy.instance.QueuePaper(e.beat, (int)PowerCalligraphy.CharacterType.chikara); },
function = delegate {var e = eventCaller.currentEntity; PowerCalligraphy.instance.Write(e.beat, (int)PowerCalligraphy.CharacterType.chikara); },
defaultLength = 8f,
},
new GameAction("onore", "Onore (己)")
{
preFunction = delegate {var e = eventCaller.currentEntity; PowerCalligraphy.instance.QueuePaper(e.beat, (int)PowerCalligraphy.CharacterType.onore); },
function = delegate {var e = eventCaller.currentEntity; PowerCalligraphy.instance.Write(e.beat, (int)PowerCalligraphy.CharacterType.onore); },
defaultLength = 8f,
},
new GameAction("sun", "Sun (寸)")
{
preFunction = delegate {var e = eventCaller.currentEntity; PowerCalligraphy.instance.QueuePaper(e.beat, (int)PowerCalligraphy.CharacterType.sun); },
function = delegate {var e = eventCaller.currentEntity; PowerCalligraphy.instance.Write(e.beat, (int)PowerCalligraphy.CharacterType.sun); },
defaultLength = 8f,
},
new GameAction("kokoro", "Kokoro (心)")
{
preFunction = delegate {var e = eventCaller.currentEntity; PowerCalligraphy.instance.QueuePaper(e.beat, (int)PowerCalligraphy.CharacterType.kokoro); },
function = delegate {var e = eventCaller.currentEntity; PowerCalligraphy.instance.Write(e.beat, (int)PowerCalligraphy.CharacterType.kokoro); },
defaultLength = 8f,
},
new GameAction("face", "Face (つるニハ○○ムし)")
{
preFunction = delegate {var e = eventCaller.currentEntity; PowerCalligraphy.instance.QueuePaper(e.beat,
e["korean"] ? (int)PowerCalligraphy.CharacterType.face_kr : (int)PowerCalligraphy.CharacterType.face); },
function = delegate {var e = eventCaller.currentEntity; PowerCalligraphy.instance.Write(e.beat,
e["korean"] ? (int)PowerCalligraphy.CharacterType.face_kr : (int)PowerCalligraphy.CharacterType.face); },
parameters = new List<Param>()
@ -77,6 +79,15 @@ namespace HeavenStudio.Games.Loaders
},
defaultLength = 0.5f,
},
new GameAction("chounin events", "Chounin Animations")
{
function = delegate { var e = eventCaller.currentEntity; PowerCalligraphy.instance.PlayChouninAnimation(e["type"], e["pos"]); },
parameters = new List<Param>()
{
new Param("type", PowerCalligraphy.ChouninType.Dance, "Animation", "Set the animation for Chounin to perform."),
new Param("pos", new EntityTypes.Float(0, 14, 0), "Position", "Set the position of Chounin."),
}
},
new GameAction("end", "The End")
{
function = delegate {PowerCalligraphy.instance.TheEnd();},
@ -97,16 +108,21 @@ namespace HeavenStudio.Games
[Header("References")]
[SerializeField] List<GameObject> basePapers = new List<GameObject>();
[SerializeField] List<RuntimeAnimatorController> fudePosCntls = new List<RuntimeAnimatorController>();
[SerializeField] List<RuntimeAnimatorController> shiftCntls = new List<RuntimeAnimatorController>();
public Transform shiftHolder;
public Transform paperHolder;
public Animator endPaper;
public GameObject[] Chounin;
public Animator fudePosAnim;
public Animator fudeAnim;
public static int queuedType;
public Animator shiftAnim;
public Fude playerFude;
[Header("Variables")]
public Vector3 scrollSpeed = new Vector3();
public float chouninSpeed;
float chouninRate => chouninSpeed / (Conductor.instance.pitchedSecPerBeat * 2f);
public enum CharacterType
{
@ -128,6 +144,7 @@ namespace HeavenStudio.Games
void Awake()
{
instance = this;
SetupBopRegion("powerCalligraphy", "bop", "bopAuto");
}
public override void OnGameSwitch(double beat)
{
@ -144,23 +161,14 @@ namespace HeavenStudio.Games
void Update()
{
var cond = Conductor.instance;
if (!cond.isPlaying || cond.isPaused)
{
if (!cond.isPaused) queuedType = (int)CharacterType.NONE;
return;
}
if (queuedType != (int)CharacterType.NONE)
{
Prepare(queuedType);
queuedType = (int)CharacterType.NONE;
}
if (!cond.isPlaying || cond.isPaused) return;
if (PlayerInput.GetIsAction(InputAction_BasicPress) && !IsExpectingInputNow(InputAction_BasicPress))
{
if (nowPaper.onGoing && nowPaper.Stroke == 1)
{
nowPaper.ProcessInput("fast");
ChouninMiss();
ScoreMiss();
}
}
@ -169,51 +177,46 @@ namespace HeavenStudio.Games
if (nowPaper.onGoing && nowPaper.Stroke != 1)
{
nowPaper.ProcessInput("fast");
ChouninMiss();
ScoreMiss();
}
}
if (isChouninMove) UpdateChouninPos(chouninRate * Time.deltaTime);
}
private void SpawnPaper(int type)
{
if (nowPaper is not null) nowPaper.transform.SetParent(paperHolder.transform, true);
nowPaper = Instantiate(basePapers[type], paperHolder).GetComponent<Writing>();
nowPaper.scrollSpeed = scrollSpeed;
nowPaper.gameObject.SetActive(true);
nowPaper.Init();
fudePosAnim.runtimeAnimatorController = fudePosCntls[type];
fudePosAnim.Play("0", 0, 0);
shiftAnim.runtimeAnimatorController = shiftCntls[type];
shiftHolder.transform.position = new Vector3(0, 0, 0);
}
public void Write(double beat, int type)
{
Prepare(type);
nowPaper.transform.SetParent(shiftHolder.transform, true);
nowPaper.startBeat = beat;
nowPaper.Play();
isPrepare=false;
double nextBeat = beat + nowPaper.nextBeat;
BeatAction.New(instance, new List<BeatAction.Action>(){
new BeatAction.Action(nextBeat, delegate{ NextPrepare(nextBeat);})
new BeatAction.Action(beat, delegate{isPrepare = false;}),
new BeatAction.Action(nextBeat, delegate{NextPrepare(nextBeat);}),
});
}
public void QueuePaper(double beat, int type)
{
if (GameManager.instance.currentGame != "powerCalligraphy")
{
queuedType = type;
}
else if(Conductor.instance.songPositionInBeats < beat)
{
BeatAction.New(instance, new List<BeatAction.Action>(){
new BeatAction.Action(beat-1, delegate{ Prepare(type);})
});
}
}
public void Prepare(int type)
{
if (!isPrepare)
{
SpawnPaper(type);
isPrepare = true;
SpawnPaper(type);
}
}
public void NextPrepare(double beat) // Prepare next paper
@ -258,5 +261,115 @@ namespace HeavenStudio.Games
fudePosAnim.Play("fudePos-end");
endPaper.Play("paper-end");
}
public override void OnBeatPulse(double beat)
{
if (BeatIsInBopRegion(beat)) Bop();
}
public void ToggleBop(double beat, float length, bool bopOrNah, bool autoBop)
{
if (bopOrNah)
{
for (int i = 0; i < length; i++)
{
BeatAction.New(instance, new() {new BeatAction.Action(beat + i, delegate {Bop();}) });
}
}
}
public void Bop()
{
if (chouninType != (int)ChouninType.Dance) return;
isChouninMove = true;
double beat = Conductor.instance.songPositionInBeats;
for (int i=0; i<2; i++) {
int j = 0;
foreach (Transform child in Chounin[i].transform) {
var animator = child.GetComponent<Animator>();
if (animator != null) {
if ((int)(beat%2) == j%2) {
animator.DoScaledAnimationAsync("dance1", 0.5f);
} else {
animator.DoScaledAnimationAsync("dance0", 0.5f);
}
}
j++;
}
}
}
public enum ChouninType {
Dance,
Bow,
Idle,
}
bool isChouninMove = false;
int chouninType = -1;
public void PlayChouninAnimation(int type, float pos)
{
isChouninMove = false;
chouninType = type;
switch (type)
{
case (int)ChouninType.Dance:
isChouninMove = true;
Bop();
break;
case (int)ChouninType.Bow:
ChouninAnim("bow");
break;
default:
ChouninAnim("idle");
break;
}
if (pos>0) UpdateChouninPos(pos);
}
public void ChouninAnim(string type)
{
for (int i=0; i<2; i++) {
foreach (Transform child in Chounin[i].transform) {
var animator = child.GetComponent<Animator>();
if (animator != null) {
if (i%2 == 1) {
animator.DoScaledAnimationAsync($"{type}1", 0.5f);
} else {
animator.DoScaledAnimationAsync($"{type}0", 0.5f);
}
}
}
}
}
public void ChouninMiss()
{
isChouninMove = false;
double beat = Conductor.instance.songPositionInBeats;
var currentChouninType = chouninType;
BeatAction.New(instance, new() {new BeatAction.Action(beat + 1.5f, delegate {
if (chouninType == -1) chouninType = currentChouninType;
})});
chouninType = -1;
ChouninAnim("fall");
}
private void UpdateChouninPos(float pos)
{
foreach (Transform child in Chounin[0].transform) {
var childPos = child.localPosition;
var newChildY = childPos.y - pos;
newChildY = newChildY < -6 ? newChildY + 12 : newChildY;
child.localPosition = new Vector3(childPos.x, newChildY, childPos.z);
}
foreach (Transform child in Chounin[1].transform) {
var childPos = child.localPosition;
var newChildY = childPos.y + pos;
newChildY = newChildY > 6 ? newChildY - 12 : newChildY;
child.localPosition = new Vector3(childPos.x, newChildY, childPos.z);
}
}
}
}

View File

@ -47,6 +47,7 @@ namespace HeavenStudio.Games.Scripts_PowerCalligraphy
}
public double startBeat;
public double ongoingBeat = Double.MinValue;
public double nextBeat;
[SerializeField] PatternItem[] AnimPattern;
@ -75,7 +76,6 @@ namespace HeavenStudio.Games.Scripts_PowerCalligraphy
public void Play()
{
paperSort.sortingOrder++;
var sounds = new List<MultiSound.Sound>();
var actions = new List<BeatAction.Action>();
@ -124,7 +124,7 @@ namespace HeavenStudio.Games.Scripts_PowerCalligraphy
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;}));
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:
@ -132,7 +132,7 @@ namespace HeavenStudio.Games.Scripts_PowerCalligraphy
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;}));
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:
@ -140,7 +140,7 @@ namespace HeavenStudio.Games.Scripts_PowerCalligraphy
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;}));
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:
@ -168,24 +168,29 @@ namespace HeavenStudio.Games.Scripts_PowerCalligraphy
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)
if (state >= 1f) {
ProcessInput("late");
else if (state <= -1f)
game.ChouninMiss();
} else if (state <= -1f) {
ProcessInput("fast");
else
game.ChouninMiss();
} else {
ProcessInput("just");
}
}
private void writeMiss(PlayerActionEvent caller)
{
if (onGoing)
Miss();
if (onGoing) Miss();
}
private void Empty(PlayerActionEvent caller) { }
@ -219,17 +224,15 @@ namespace HeavenStudio.Games.Scripts_PowerCalligraphy
case "late":
case "fast":
game.fudeAnim.DoScaledAnimationAsync("fude-none", 0.5f);
switch (stroke) { // WIP
case StrokeType.TOME:
game.fudeAnim.DoScaledAnimationAsync("fude-none", 0.5f);
SoundByte.PlayOneShotGame("powerCalligraphy/8");
break;
case StrokeType.HANE:
game.fudeAnim.DoScaledAnimationAsync("fude-none", 0.5f);
SoundByte.PlayOneShotGame("powerCalligraphy/6");
break;
case StrokeType.HARAI:
game.fudeAnim.DoScaledAnimationAsync("fude-none", 0.5f);
SoundByte.PlayOneShotGame("powerCalligraphy/9");
break;
}
@ -262,6 +265,7 @@ namespace HeavenStudio.Games.Scripts_PowerCalligraphy
string pattern = num.ToString() + str;
game.fudePosAnim.DoScaledAnimationAsync(pattern, 0.5f);
game.shiftAnim.DoScaledAnimationAsync(pattern, 0.5f);
paperAnim.DoScaledAnimationAsync(pattern, 0.5f);
}
@ -271,6 +275,12 @@ namespace HeavenStudio.Games.Scripts_PowerCalligraphy
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;