2024-04-12 01:40:52 +00:00
|
|
|
using System.Linq;
|
|
|
|
using System.Collections.Generic;
|
|
|
|
using UnityEngine;
|
|
|
|
using NaughtyBezierCurves;
|
|
|
|
|
|
|
|
using HeavenStudio.Util;
|
|
|
|
using HeavenStudio.InputSystem;
|
|
|
|
|
|
|
|
namespace HeavenStudio.Games.Loaders
|
|
|
|
{
|
|
|
|
using static Minigames;
|
|
|
|
|
|
|
|
public static class AgbBouncyRoadLoader
|
|
|
|
{
|
|
|
|
public static Minigame AddGame(EventCaller eventCaller)
|
|
|
|
{
|
|
|
|
return new Minigame("bouncyRoad", "Bouncy Road", "0296FF", false, false, new List<GameAction>()
|
|
|
|
{
|
|
|
|
new GameAction("ball", "Ball")
|
|
|
|
{
|
|
|
|
defaultLength = 1f,
|
|
|
|
resizable = true,
|
|
|
|
parameters = new List<Param>()
|
|
|
|
{
|
|
|
|
new Param("goal", true, "Play Goal Sound"),
|
|
|
|
new Param("color", Color.white, "Color", "Choose the color of the ball."),
|
|
|
|
}
|
|
|
|
},
|
2024-04-16 03:57:14 +00:00
|
|
|
new GameAction("background appearance", "Background Appearance")
|
|
|
|
{
|
|
|
|
function = delegate {
|
|
|
|
var e = eventCaller.currentEntity;
|
|
|
|
BouncyRoad.instance.BackgroundColorSet(e.beat, e.length, e["colorBG1Start"], e["colorBG1End"], e["colorBG2Start"], e["colorBG2End"], e["ease"]);
|
|
|
|
},
|
|
|
|
defaultLength = 0.5f,
|
|
|
|
resizable = true,
|
|
|
|
parameters = new List<Param>()
|
|
|
|
{
|
|
|
|
new Param("colorBG1Start", new Color(0.004f, 0.596f, 0.996f), "Start BG Color", "Set top-most color of the background gradient at the start of the event."),
|
|
|
|
new Param("colorBG1End", new Color(0.004f, 0.596f, 0.996f), "End BG Color", "Set top-most color of the background gradient at the end of the event."),
|
|
|
|
new Param("colorBG2Start", Color.black, "Start BG Color", "Set bottom-most color of the background gradient at the start of the event."),
|
|
|
|
new Param("colorBG2End",Color.black, "End BG Color", "Set bottom-most color of the background gradient at the end of the event."),
|
|
|
|
new Param("ease", Util.EasingFunction.Ease.Instant, "Ease", "Set the easing of the action."),
|
|
|
|
}
|
|
|
|
},
|
|
|
|
// new GameAction("object appearance", "Object Appearance")
|
|
|
|
// {
|
|
|
|
// function = delegate {
|
|
|
|
// var e = eventCaller.currentEntity;
|
|
|
|
// BouncyRoad.instance.ObjectColorSet(e["color1"], e["color2"], e["color3"]);
|
|
|
|
// },
|
|
|
|
// defaultLength = 0.5f,
|
|
|
|
// parameters = new List<Param>()
|
|
|
|
// {
|
|
|
|
// new Param("color1", new Color(1, 1, 1), "Color 1"),
|
|
|
|
// new Param("color2", new Color(1, 1, 1), "Color 2"),
|
|
|
|
// new Param("color3", new Color(1, 1, 1), "Color 3"),
|
|
|
|
// }
|
|
|
|
// },
|
2024-04-12 01:40:52 +00:00
|
|
|
},
|
|
|
|
new List<string>() { "agb", "normal" },
|
|
|
|
"agbbouncy", "en",
|
|
|
|
new List<string>() { },
|
|
|
|
chronologicalSortKey: 24
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
namespace HeavenStudio.Games
|
|
|
|
{
|
|
|
|
using Scripts_BouncyRoad;
|
|
|
|
public class BouncyRoad : Minigame
|
|
|
|
{
|
|
|
|
[SerializeField] GameObject baseBall;
|
|
|
|
[SerializeField] GameObject baseBounceCurve;
|
|
|
|
[SerializeField] Transform CurveHolder;
|
|
|
|
|
|
|
|
[SerializeField] Transform ThingsTrans;
|
|
|
|
[System.NonSerialized] public Animator[] ThingsAnim;
|
|
|
|
[System.NonSerialized] public Dictionary<float, BezierCurve3D[]> CurveCache;
|
|
|
|
[SerializeField] BezierCurve3D PosCurve;
|
|
|
|
|
|
|
|
[SerializeField] float fallY;
|
|
|
|
|
2024-04-16 03:57:14 +00:00
|
|
|
[SerializeField] private SpriteRenderer BGGradient, BGHigh, BGLow;
|
|
|
|
private ColorEase[] colorEases = new ColorEase[2];
|
|
|
|
|
2024-04-12 01:40:52 +00:00
|
|
|
const double BALL_SEEK_TIME = 1.0;
|
|
|
|
private struct ScheduledBall
|
|
|
|
{
|
|
|
|
public double beat;
|
|
|
|
public double length;
|
|
|
|
public bool goal;
|
|
|
|
public Color color;
|
|
|
|
}
|
|
|
|
List<ScheduledBall> scheduledBalls = new();
|
|
|
|
int ballIndex;
|
|
|
|
|
|
|
|
public static BouncyRoad instance;
|
|
|
|
|
|
|
|
const int IALeft = 0;
|
|
|
|
const int IARight = 1;
|
|
|
|
|
|
|
|
protected static bool IA_PadLeft(out double dt)
|
|
|
|
{
|
|
|
|
return PlayerInput.GetPadDown(InputController.ActionsPad.Up, out dt)
|
|
|
|
|| PlayerInput.GetPadDown(InputController.ActionsPad.Down, out dt)
|
|
|
|
|| PlayerInput.GetPadDown(InputController.ActionsPad.Left, out dt)
|
|
|
|
|| PlayerInput.GetPadDown(InputController.ActionsPad.Right, out dt);
|
|
|
|
}
|
|
|
|
protected static bool IA_TouchLeft(out double dt)
|
|
|
|
{
|
|
|
|
return PlayerInput.GetTouchDown(InputController.ActionsTouch.Left, out dt);
|
|
|
|
}
|
|
|
|
|
|
|
|
protected static bool IA_PadRight(out double dt)
|
|
|
|
{
|
|
|
|
return PlayerInput.GetPadDown(InputController.ActionsPad.East, out dt);
|
|
|
|
}
|
|
|
|
protected static bool IA_TouchRight(out double dt)
|
|
|
|
{
|
|
|
|
return PlayerInput.GetTouchDown(InputController.ActionsTouch.Right, out dt);
|
|
|
|
}
|
|
|
|
|
|
|
|
public static PlayerInput.InputAction InputAction_Left =
|
|
|
|
new("AgbBouncyLeft", new int[] { IALeft, IALeft, IALeft },
|
|
|
|
IA_PadLeft, IA_TouchLeft, IA_BatonBasicPress);
|
|
|
|
|
|
|
|
public static PlayerInput.InputAction InputAction_Right =
|
|
|
|
new("AgbBouncyRight", new int[] { IARight, IARight, IAEmptyCat },
|
|
|
|
IA_PadRight, IA_TouchRight, IA_Empty);
|
|
|
|
|
|
|
|
void Awake()
|
|
|
|
{
|
|
|
|
instance = this;
|
2024-04-16 03:57:14 +00:00
|
|
|
|
|
|
|
colorEases = new ColorEase[] {
|
|
|
|
new(new Color(0.004f, 0.596f, 0.996f)),
|
|
|
|
new(Color.black),
|
|
|
|
};
|
2024-04-12 01:40:52 +00:00
|
|
|
|
|
|
|
ThingsAnim = new Animator[ThingsTrans.childCount];
|
|
|
|
int childIndex = 0;
|
|
|
|
foreach (Transform child in ThingsTrans)
|
|
|
|
{
|
|
|
|
// var prog = (float)childIndex/(ThingsTrans.childCount-1);
|
|
|
|
// child.transform.localPosition = PosCurve.GetPoint(prog);
|
|
|
|
ThingsAnim[childIndex++] = child.GetComponent<Animator>();
|
|
|
|
}
|
|
|
|
|
|
|
|
var newCurves = new BezierCurve3D[ThingsTrans.childCount + 3];
|
|
|
|
// for (var i = 0; i < ThingsAnim.Length + 1; ++i)
|
|
|
|
// {
|
|
|
|
// var prog1 = (float)(i-1)/(ThingsTrans.childCount-1);
|
|
|
|
// var prog2 = (float)(i)/(ThingsTrans.childCount-1);
|
|
|
|
// var pos1 = PosCurve.GetPoint(prog1);
|
|
|
|
// var pos2 = PosCurve.GetPoint(prog2);
|
|
|
|
|
|
|
|
// var newCurve = GenerateInitCurve(pos1, pos2);
|
|
|
|
|
|
|
|
// newCurves[i] = newCurve.GetComponent<BezierCurve3D>();
|
|
|
|
// }
|
|
|
|
{
|
|
|
|
Vector3 pos1, pos2;
|
|
|
|
pos1 = PosCurve.GetPoint((float)(-1)/(ThingsAnim.Length-1));
|
|
|
|
pos2 = PosCurve.GetPoint(0);
|
|
|
|
newCurves[0] = GenerateInitCurve(pos1, pos2).GetComponent<BezierCurve3D>();
|
|
|
|
|
|
|
|
for (var i = 0; i < ThingsAnim.Length-1; ++i)
|
|
|
|
{
|
|
|
|
pos1 = ThingsTrans.GetChild(i).transform.localPosition;
|
|
|
|
pos2 = ThingsTrans.GetChild(i+1).transform.localPosition;
|
|
|
|
|
|
|
|
var newCurve = GenerateInitCurve(pos1, pos2);
|
|
|
|
|
|
|
|
newCurves[1+i] = newCurve.GetComponent<BezierCurve3D>();
|
|
|
|
}
|
|
|
|
|
|
|
|
pos1 = PosCurve.GetPoint(1);
|
|
|
|
pos2 = PosCurve.GetPoint((float)(ThingsAnim.Length)/(ThingsAnim.Length-1));
|
|
|
|
newCurves[ThingsAnim.Length] = GenerateInitCurve(pos1, pos2).GetComponent<BezierCurve3D>();
|
|
|
|
}
|
|
|
|
newCurves[^2] = GenerateMissCurve(13).GetComponent<BezierCurve3D>();
|
|
|
|
newCurves[^1] = GenerateMissCurve(14).GetComponent<BezierCurve3D>();
|
|
|
|
|
|
|
|
CurveCache = new Dictionary<float, BezierCurve3D[]>();
|
|
|
|
CurveCache.Add(1, newCurves);
|
|
|
|
}
|
|
|
|
|
|
|
|
public override void OnGameSwitch(double beat)
|
|
|
|
{
|
2024-04-19 19:16:16 +00:00
|
|
|
|
|
|
|
PersistColor(beat);
|
|
|
|
|
2024-04-12 01:40:52 +00:00
|
|
|
double gameStartBeat = beat, gameEndBeat = double.MaxValue;
|
|
|
|
var firstEnd = EventCaller.GetAllInGameManagerList("gameManager", new string[] { "switchGame", "end" }).Find(x => x.beat > gameStartBeat);
|
|
|
|
gameEndBeat = firstEnd?.beat ?? gameEndBeat;
|
|
|
|
|
|
|
|
|
|
|
|
scheduledBalls.Clear();
|
|
|
|
ballIndex = 0;
|
|
|
|
var events = EventCaller.GetAllInGameManagerList("bouncyRoad", new string[] { "ball" }).FindAll(x => x.beat >= gameStartBeat && x.beat < gameEndBeat);
|
|
|
|
foreach (var e in events)
|
|
|
|
{
|
|
|
|
if (e.length == 0) continue;
|
|
|
|
var ball = new ScheduledBall
|
|
|
|
{
|
|
|
|
beat = e.beat,
|
|
|
|
length = e.length,
|
|
|
|
goal = e["goal"],
|
|
|
|
color = e["color"],
|
|
|
|
};
|
|
|
|
scheduledBalls.Add(ball);
|
|
|
|
}
|
|
|
|
scheduledBalls.Sort((x, y) => (x.beat - x.length).CompareTo(y.beat - y.length));
|
|
|
|
}
|
|
|
|
public override void OnPlay(double beat)
|
|
|
|
{
|
|
|
|
OnGameSwitch(beat);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Update()
|
|
|
|
{
|
|
|
|
var cond = Conductor.instance;
|
|
|
|
if (!cond.isPlaying || cond.isPaused) return;
|
|
|
|
|
|
|
|
if (PlayerInput.GetIsAction(InputAction_Right) && !IsExpectingInputNow(InputAction_Right))
|
|
|
|
{
|
|
|
|
ThingsAnim[12].Play("podium", 0, 0);
|
|
|
|
}
|
|
|
|
if (PlayerInput.GetIsAction(InputAction_Left) && !IsExpectingInputNow(InputAction_Left))
|
|
|
|
{
|
|
|
|
ThingsAnim[13].Play("podium", 0, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
UpdateBalls();
|
2024-04-16 03:57:14 +00:00
|
|
|
UpdateBackgroundColor();
|
2024-04-12 01:40:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void UpdateBalls()
|
|
|
|
{
|
|
|
|
double beat = conductor.songPositionInBeatsAsDouble;
|
|
|
|
while(ballIndex < scheduledBalls.Count)
|
|
|
|
{
|
|
|
|
var ball = scheduledBalls[ballIndex];
|
|
|
|
if (ball.beat - ball.length < beat + BALL_SEEK_TIME)
|
|
|
|
{
|
|
|
|
SpawnBall(ball.beat, ball.length, ball.goal, ball.color);
|
|
|
|
ballIndex++;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public void SpawnBall(double beat, double length, bool goal, Color color)
|
|
|
|
{
|
|
|
|
var newBall = Instantiate(baseBall, transform).GetComponent<Ball>();
|
|
|
|
|
|
|
|
newBall.startBeat = beat;
|
|
|
|
newBall.lengthBeat = length;
|
|
|
|
newBall.goal = goal;
|
|
|
|
newBall.color = color;
|
|
|
|
|
|
|
|
newBall.curve = GetHeightCurve((float)length);
|
|
|
|
|
|
|
|
BeatAction.New(instance, new List<BeatAction.Action>()
|
|
|
|
{
|
|
|
|
new BeatAction.Action(beat - length, delegate
|
|
|
|
{
|
|
|
|
newBall.Init();
|
|
|
|
newBall.gameObject.SetActive(true);
|
|
|
|
})
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
List<double> bounceBeats = new();
|
|
|
|
public void PlayBounceSound(double beat, double length)
|
|
|
|
{
|
|
|
|
var sounds = new List<MultiSound.Sound>();
|
|
|
|
for (int i = 0; i < 12 ; i++)
|
|
|
|
{
|
|
|
|
var bounceBeat = beat + i * length;
|
|
|
|
if (!bounceBeats.Contains(bounceBeat)) sounds.Add(new MultiSound.Sound("bouncyRoad/ballBounce", bounceBeat));
|
|
|
|
bounceBeats.Add(bounceBeat);
|
|
|
|
}
|
|
|
|
MultiSound.Play(sounds.ToArray());
|
|
|
|
}
|
|
|
|
|
|
|
|
private Transform GenerateInitCurve(Vector3 pos1, Vector3 pos2)
|
|
|
|
{
|
|
|
|
float dist = Vector3.Distance(pos1, pos2);
|
|
|
|
float angle = Mathf.Atan2(pos1.z - pos2.z, pos1.x - pos2.x) * Mathf.Rad2Deg;
|
|
|
|
|
|
|
|
var newCurve = Instantiate(baseBounceCurve, CurveHolder).transform;
|
|
|
|
|
|
|
|
var point0 = newCurve.GetChild(0);
|
|
|
|
var point1 = newCurve.GetChild(1);
|
|
|
|
|
|
|
|
point0.transform.localPosition = pos1;
|
|
|
|
point0.transform.localEulerAngles = new Vector3(0, -angle, 0);
|
|
|
|
point0.transform.localScale = new Vector3(dist, 1, 1);
|
|
|
|
point1.transform.localPosition = pos2;
|
|
|
|
point1.transform.localEulerAngles = new Vector3(0, -angle, 0);
|
|
|
|
point1.transform.localScale = new Vector3(dist, 1, 1);
|
|
|
|
|
|
|
|
return newCurve;
|
|
|
|
}
|
|
|
|
|
|
|
|
private Transform GenerateMissCurve(int number)
|
|
|
|
{
|
|
|
|
var curve = CurveHolder.GetChild(number);
|
|
|
|
|
|
|
|
var newCurve = Instantiate(curve, CurveHolder).transform;
|
|
|
|
|
|
|
|
var point0 = newCurve.GetChild(0);
|
|
|
|
var point1 = newCurve.GetChild(1);
|
|
|
|
|
|
|
|
Vector3 pos1 = point1.transform.localPosition;
|
|
|
|
point1.transform.localPosition = pos1 + new Vector3(0, fallY, 0);
|
|
|
|
|
|
|
|
return newCurve;
|
|
|
|
}
|
|
|
|
|
|
|
|
private BezierCurve3D[] GetHeightCurve(float length)
|
|
|
|
{
|
|
|
|
BezierCurve3D[] newCurves;
|
|
|
|
CurveCache.TryGetValue(length, out newCurves);
|
|
|
|
|
|
|
|
if (newCurves is null)
|
|
|
|
{
|
|
|
|
var newCurveHolder = Instantiate(CurveHolder, transform);
|
|
|
|
newCurveHolder.name = $"CurveHolder_{length}";
|
|
|
|
var newCurvesTrans = newCurveHolder.transform;
|
|
|
|
|
|
|
|
newCurves = new BezierCurve3D[newCurvesTrans.childCount];
|
|
|
|
int childIndex = 0;
|
|
|
|
foreach (Transform child in newCurvesTrans)
|
|
|
|
{
|
|
|
|
var point0 = child.GetChild(0);
|
|
|
|
var point1 = child.GetChild(1);
|
|
|
|
|
|
|
|
Vector3 scale = point0.transform.localScale;
|
|
|
|
point0.transform.localScale = new Vector3(scale.x, length * scale.y, scale.z);
|
|
|
|
point1.transform.localScale = new Vector3(scale.x, length * scale.y, scale.z);
|
|
|
|
newCurves[childIndex++] = child.GetComponent<BezierCurve3D>();
|
|
|
|
}
|
|
|
|
CurveCache.Add(length, newCurves);
|
|
|
|
}
|
|
|
|
|
|
|
|
return newCurves;
|
|
|
|
}
|
2024-04-16 03:57:14 +00:00
|
|
|
|
|
|
|
public void BackgroundColorSet(double beat, float length, Color BG1Start, Color BG1End, Color BG2Start, Color BG2End, int colorEaseSet)
|
|
|
|
{
|
|
|
|
colorEases = new ColorEase[] {
|
|
|
|
new(beat, length, BG1Start, BG1End, colorEaseSet),
|
|
|
|
new(beat, length, BG2Start, BG2End, colorEaseSet),
|
|
|
|
};
|
|
|
|
|
|
|
|
UpdateBackgroundColor();
|
|
|
|
}
|
|
|
|
public void ObjectColorSet(Color Color1, Color Color2, Color Color3)
|
|
|
|
{
|
|
|
|
|
|
|
|
}
|
|
|
|
private void UpdateBackgroundColor()
|
|
|
|
{
|
|
|
|
BGGradient.material.SetColor("_ColorAlpha", colorEases[0].GetColor());
|
|
|
|
BGGradient.material.SetColor("_ColorDelta", colorEases[1].GetColor());
|
|
|
|
BGHigh.color = colorEases[0].GetColor();
|
|
|
|
BGLow.color = colorEases[1].GetColor();
|
|
|
|
}
|
2024-04-19 19:16:16 +00:00
|
|
|
|
|
|
|
private void PersistColor(double beat)
|
|
|
|
{
|
|
|
|
var allEventsBeforeBeat = EventCaller.GetAllInGameManagerList("bouncyRoad", new string[] { "background appearance" }).FindAll(x => x.beat < beat);
|
|
|
|
if (allEventsBeforeBeat.Count > 0)
|
|
|
|
{
|
|
|
|
allEventsBeforeBeat.Sort((x, y) => x.beat.CompareTo(y.beat)); //just in case
|
|
|
|
var lastEvent = allEventsBeforeBeat[^1];
|
|
|
|
BackgroundColorSet(lastEvent.beat, lastEvent.length, lastEvent["colorBG1Start"], lastEvent["colorBG1End"], lastEvent["colorBG2Start"], lastEvent["colorBG2End"], lastEvent["ease"]);
|
|
|
|
}
|
|
|
|
}
|
2024-04-12 01:40:52 +00:00
|
|
|
}
|
|
|
|
}
|