Files
crtr/Assets/Cryville/Crtr/NoteHandler.cs

222 lines
6.7 KiB
C#

using Cryville.Common;
using Cryville.Common.Math;
using Cryville.Crtr.Components;
using Cryville.Crtr.Event;
using System;
using System.Collections.Generic;
using UnityEngine;
namespace Cryville.Crtr {
public class NoteHandler : ContainerHandler {
readonly GroupHandler gh;
public readonly Chart.Note Event;
public NoteHandler(Chart.Note ev, GroupHandler gh) : base() {
Event = ev;
this.gh = gh;
}
public override string TypeName {
get {
return "note";
}
}
SectionalGameObject[] sgos;
readonly Dictionary<Chart.Judge, JudgeState> judges = new Dictionary<Chart.Judge, JudgeState>();
readonly Dictionary<int, DynamicJudgeAnchorPair> dynJudgeAnchors = new Dictionary<int, DynamicJudgeAnchorPair>();
class JudgeState {
static readonly int _var_judge_result = IdentifierManager.SharedInstance.Request("judge_result");
public Anchor StaticAnchor { get; private set; }
public DynamicJudgeAnchorPair DynamicAnchors { get; private set; }
public bool Judged { get; private set; }
public float AbsoluteTime { get; private set; }
public float RelativeTime { get; private set; }
int _result = 0;
PropSrc _resultPropSrc;
public JudgeState(NoteHandler handler, int name) {
StaticAnchor = handler.RegisterAnchor(handler.judge.judgeMap[name], true);
DynamicAnchors = handler.GetDynamicJudgeAnchorPair(name);
}
public void MarkJudged(float abs, float rel, int result) {
Judged = true;
AbsoluteTime = abs;
RelativeTime = rel;
_result = result;
_resultPropSrc.Invalidate();
}
public void InitPropSrcs() {
StaticAnchor.PropSrcs.Add(_var_judge_result, _resultPropSrc = new PropSrc.Identifier(() => _result));
}
}
class DynamicJudgeAnchorPair {
public Anchor Absolute { get; private set; }
public Anchor Relative { get; private set; }
public DynamicJudgeAnchorPair(Anchor absolute, Anchor relative) {
Absolute = absolute;
Relative = relative;
}
}
DynamicJudgeAnchorPair GetDynamicJudgeAnchorPair(int name) {
DynamicJudgeAnchorPair result;
if (!dynJudgeAnchors.TryGetValue(name, out result)) {
dynJudgeAnchors.Add(name, result = new DynamicJudgeAnchorPair(
RegisterAnchor(judge.jtabsMap[name]),
RegisterAnchor(judge.jtrelMap[name])
));
}
return result;
}
public override void PreInit() {
base.PreInit();
foreach (var j in Event.judges) {
judges.Add(j, new JudgeState(this, j.Id.Key));
}
}
public override void Init() {
base.Init();
sgos = gogroup.GetComponentsInChildren<SectionalGameObject>();
foreach (var judge in judges.Values) judge.InitPropSrcs();
}
protected override void PreAwake(ContainerState s) {
base.PreAwake(s);
#if UNITY_5_6_OR_NEWER
a_head.Transform.SetPositionAndRotation(Position = GetFramePoint(s.Parent, s.Track), Rotation = GetFrameRotation(s.Parent, s.Track));
#else
a_head.Transform.position = Position = GetFramePoint(s.Parent, s.Track);
a_head.Transform.rotation = Rotation = GetFrameRotation(s.Parent, s.Track);
#endif
}
protected override void Awake(ContainerState s) {
base.Awake(s);
if (s.CloneType == 2) {
if (!gogroup) return;
if (Event.IsLong) {
foreach (var i in sgos) {
i.Reset();
i.AppendPoint(Position, Rotation);
}
}
else {
#if UNITY_5_6_OR_NEWER
gogroup.SetPositionAndRotation(Position, Rotation);
#else
gogroup.position = Position;
gogroup.rotation = Rotation;
#endif
}
}
}
public override void Update(ContainerState s, StampedEvent ev) {
base.Update(s, ev);
if (s.CloneType <= 2) {
Position = GetFramePoint(s.Parent, s.Track);
Rotation = GetFrameRotation(s.Parent, s.Track);
}
if (s.CloneType == 2) {
if (!gogroup) return;
Chart.Note tev = Event;
if (tev.IsLong) {
foreach (var i in sgos)
i.AppendPoint(Position, Rotation);
}
}
else if (s.CloneType == 16) {
if (ev == null) { }
else if (ev.Unstamped == null) { }
else if (ev.Unstamped is Chart.Judge) {
ChartPlayer.etor.ContextEvent = ev.Unstamped;
ChartPlayer.etor.ContextState = s;
judge.Prepare(ev, this);
ChartPlayer.etor.ContextState = null;
ChartPlayer.etor.ContextEvent = null;
}
}
}
public override void Anchor() {
base.Anchor();
foreach (var j in judges.Values) {
if (!j.Judged) continue;
PushAnchorEvent(j.AbsoluteTime, j.DynamicAnchors.Absolute);
PushAnchorEvent(j.RelativeTime + cs.Time, j.DynamicAnchors.Relative);
}
}
public override void EndUpdate(ContainerState s) {
if (s.CloneType == 2 && gogroup) {
foreach (var i in sgos) i.Seal();
#if UNITY_5_6_OR_NEWER
a_tail.Transform.SetPositionAndRotation(GetFramePoint(ts.Parent, ts.Track), Quaternion.Euler(ts.Direction));
#else
a_tail.Transform.position = GetFramePoint(ts.Parent, ts.Track);
a_tail.Transform.rotation = Quaternion.Euler(ts.Direction);
#endif
}
base.EndUpdate(s);
}
Vector3 GetFramePoint(ContainerState state, float track) {
return GetFrame(state, track, th => ((TrackHandler)th.Handler).GetCurrentWorldPoint());
}
Quaternion GetFrameRotation(ContainerState state, float track) {
var r = GetFrame(state, track, th => Quaternion.Euler(th.Direction) * Vector3.forward);
return Quaternion.LookRotation(r, state.Normal);
}
readonly List<Vector3> ctrl = new List<Vector3>(2);
Vector3 GetFrame(ContainerState state, float track, Func<ContainerState, Vector3> func) {
// TODO
int id = Mathf.FloorToInt(track);
var ts0 = state.GetChild(id, typeof(Chart.Track));
var p1 = func(ts0);
if (track == id)
return p1;
var ts1 = state.GetChild(id + 1, typeof(Chart.Track));
var p2 = func(ts1);
bool c0 = ts0.Corner;
bool c1 = ts1.Corner;
float t = track - id;
float deltaz = p2.z - p1.z;
float nt = 1 - t;
if (c0 && c1)
return (1 - t) * p1 + t * p2;
else {
ctrl.Clear();
if (!c0) {
var tp = ts0.GetControlPoint(true, deltaz);
if (tp != Vector3.zero) ctrl.Add(tp);
}
if (!c1) {
var tp = ts1.GetControlPoint(false, -deltaz);
if (tp != Vector3.zero) ctrl.Add(tp);
}
if (ctrl.Count == 0) {
var frame = gh.GetCurrentFrame(func);
return frame.Dot(
ColumnVector<float>.WithPolynomialCoefficients(
frame.Size, track
),
Vector3Operator.Instance
);
}
else if (ctrl.Count == 1) {
return nt * (nt * p1 + t * (ctrl[0] + p1)) + t * t * p2;
}
else {
var t2 = t * t;
return nt * (nt * (nt * p1 + t * (ctrl[0] + p1)) + t2 * (ctrl[1] + p1)) + t2 * t * p2;
}
}
}
public void ReportJudge(Judge.JudgeEvent ev, float time, Identifier result) {
JudgeState state;
if (!judges.TryGetValue(ev.BaseEvent, out state)) return;
state.MarkJudged(time, (float)(ev.StartTime - time), result.Key);
}
}
}