b1fab52ad9
* add Jukebox library todo: - saving / loading of new format - inferrence of unknown data like past versions - move the temporary float casts to proper use of double - make sound related functions take double for timing - inform people that the Jukebox sound player was renamed to SoundByte lol * make sound, input scheduling, and super curve use double precision * successfully load charts * editor works again v1 riqs can be saved and loaded * first tempo and volume markers are unmovable fix loading of charts' easing values * use gsync / freesync * update Jukebox refs to SoundByte * game events use double part 1 Air Rally - Glee Club converted * don't load song if chart load fails * finish conversion of all minigames * remove editor waveform toggle * timeline now respects added song offset length clear cache files on app close prepped notes for dsp sync * update timeline length when offset changed * update to latest Jukebox * make error panel object in global game manager * improve conductor music scheduling * added error message box fix first game events sometimes not playing
207 lines
7.4 KiB
C#
207 lines
7.4 KiB
C#
using System;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using UnityEngine;
|
|
|
|
namespace HeavenStudio
|
|
{
|
|
public class SuperCurveObject : MonoBehaviour
|
|
{
|
|
[SerializeField] protected Vector3 offset;
|
|
protected Vector3 lastRealPos;
|
|
protected PathPos currentPathPos;
|
|
|
|
[Serializable]
|
|
public struct PathPos
|
|
{
|
|
[SerializeField] public string tag;
|
|
[SerializeField] public Vector3 pos;
|
|
[SerializeField] public Transform target;
|
|
[SerializeField] public float height;
|
|
[SerializeField] public float duration;
|
|
[SerializeField] public bool useLastRealPos;
|
|
[SerializeField] public PathValue[] values;
|
|
}
|
|
|
|
[Serializable]
|
|
public struct Path
|
|
{
|
|
[SerializeField] public string name;
|
|
[SerializeField] public bool preview;
|
|
[SerializeField] public GameObject anchor;
|
|
[SerializeField] public PathPos[] positions;
|
|
}
|
|
|
|
[Serializable]
|
|
public struct PathValue
|
|
{
|
|
[SerializeField] public string key;
|
|
[SerializeField] public float value;
|
|
}
|
|
|
|
public static PathPos GetPathPosByTag(Path path, string tag)
|
|
{
|
|
foreach (PathPos pos in path.positions)
|
|
{
|
|
if (pos.tag == tag)
|
|
return pos;
|
|
}
|
|
return default(PathPos);
|
|
}
|
|
|
|
public static PathPos GetPathPosByTime(Path path, double currentTime, out double posTime, out PathPos nextPos, out PathPos prevPos, out bool pastCurve)
|
|
{
|
|
pastCurve = false;
|
|
PathPos currentPos = path.positions[0];
|
|
prevPos = path.positions[0];
|
|
nextPos = path.positions[1];
|
|
float currentPosTime = 0f;
|
|
for (int i = 0; i < path.positions.Length - 1; i++)
|
|
{
|
|
prevPos = currentPos;
|
|
currentPos = path.positions[i];
|
|
nextPos = path.positions[i + 1];
|
|
if (currentTime >= currentPosTime && currentTime < currentPosTime + currentPos.duration)
|
|
{
|
|
posTime = currentPosTime;
|
|
return currentPos;
|
|
}
|
|
if (i + 1 < path.positions.Length - 1)
|
|
currentPosTime += currentPos.duration;
|
|
else
|
|
{
|
|
pastCurve = true;
|
|
posTime = currentPosTime;
|
|
return currentPos;
|
|
}
|
|
}
|
|
nextPos = default(PathPos);
|
|
prevPos = default(PathPos);
|
|
posTime = 0f;
|
|
return default(PathPos);
|
|
}
|
|
|
|
public static PathPos GetPathPosByTime(Path path, double currentTime)
|
|
{
|
|
return GetPathPosByTime(path, currentTime, out _, out _, out _, out _);
|
|
}
|
|
|
|
public static float GetPointTimeByTag(Path path, string tag)
|
|
{
|
|
float currentTime = 0f;
|
|
foreach (PathPos pos in path.positions)
|
|
{
|
|
if (pos.tag == tag)
|
|
return currentTime;
|
|
currentTime += pos.duration;
|
|
}
|
|
return 0f;
|
|
}
|
|
|
|
protected virtual void UpdateLastRealPos()
|
|
{
|
|
lastRealPos = transform.position;
|
|
}
|
|
|
|
protected virtual float GetPathValue(string key)
|
|
{
|
|
if (currentPathPos.values == null)
|
|
return 0f;
|
|
foreach (PathValue value in currentPathPos.values)
|
|
{
|
|
if (value.key == key)
|
|
{
|
|
return value.value;
|
|
}
|
|
}
|
|
return 0f;
|
|
}
|
|
|
|
protected virtual Vector3 GetPathPositionFromBeat(Path path, double currentTime, out double heightOffset, double startTime = 0f)
|
|
{
|
|
heightOffset = 0f;
|
|
Vector3 anchorPos = Vector3.zero;
|
|
if (path.anchor != null)
|
|
anchorPos = path.anchor.transform.position;
|
|
if (path.positions.Length < 2)
|
|
return transform.position;
|
|
|
|
PathPos nextPos = path.positions[0];
|
|
double currentPosTime = 0;
|
|
PathPos currentPos = GetPathPosByTime(path, currentTime - startTime, out currentPosTime, out nextPos, out _, out _);
|
|
currentPathPos = currentPos;
|
|
if (currentPos.pos == null || nextPos.pos == null)
|
|
return transform.position;
|
|
|
|
Vector3 startPos = currentPos.pos;
|
|
if (currentPos.useLastRealPos)
|
|
startPos = lastRealPos;
|
|
else if (currentPos.target != null)
|
|
startPos = currentPos.target.position;
|
|
Vector3 endPos = nextPos.pos;
|
|
if (nextPos.target != null)
|
|
endPos = nextPos.target.position;
|
|
|
|
double time = (currentTime - startTime - currentPosTime) / currentPos.duration;
|
|
Vector3 pos = Vector3.LerpUnclamped(startPos, endPos, (float) time);
|
|
double yMul = time * 2f - 1f;
|
|
double yWeight = -(yMul * yMul) + 1f;
|
|
heightOffset = yWeight * currentPos.height;
|
|
pos.y += (float) heightOffset;
|
|
return pos + offset + anchorPos;
|
|
}
|
|
|
|
protected virtual Vector3 GetPathPositionFromBeat(Path path, double currentTime, double startTime = 0f)
|
|
{
|
|
return GetPathPositionFromBeat(path, currentTime, out _, startTime);
|
|
}
|
|
|
|
// Editor gizmo to draw trajectories
|
|
const float TRAJECTORY_STEP = 0.1f;
|
|
public virtual void DrawEditorGizmo(Path path)
|
|
{
|
|
if (path.positions.Length > 1)
|
|
{
|
|
Vector3 anchorPos = Vector3.zero;
|
|
if (path.anchor != null)
|
|
anchorPos = path.anchor.transform.position;
|
|
for (int i = 0; i < path.positions.Length - 1; i++)
|
|
{
|
|
PathPos pos = path.positions[i];
|
|
PathPos nextPos = path.positions[i + 1];
|
|
if (pos.pos == null || nextPos.pos == null)
|
|
return;
|
|
|
|
Vector3 startPos = pos.pos;
|
|
if (pos.target != null)
|
|
startPos = pos.target.position;
|
|
Vector3 endPos = nextPos.pos;
|
|
if (nextPos.target != null)
|
|
endPos = nextPos.target.position;
|
|
|
|
// draw a curve between the two points using the path height
|
|
List<Vector3> points = new List<Vector3>();
|
|
for (float t = 0; t < 1; t += TRAJECTORY_STEP)
|
|
{
|
|
float yMul = t * 2f - 1f;
|
|
float yWeight = -(yMul * yMul) + 1f;
|
|
Vector3 p = Vector3.LerpUnclamped(startPos, endPos, t);
|
|
p.y += yWeight * pos.height;
|
|
points.Add(p + anchorPos);
|
|
}
|
|
|
|
points.Add(endPos + anchorPos);
|
|
|
|
for (int j = 0; j < points.Count - 1; j++)
|
|
{
|
|
Gizmos.color = Color.blue;
|
|
Gizmos.DrawLine(points[j], points[j + 1]);
|
|
}
|
|
|
|
Gizmos.DrawSphere(startPos, 0.1f);
|
|
Gizmos.DrawSphere(endPos, 0.1f);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} |