HeavenStudioPlus/Assets/Scripts/Games/CallAndResponseHandler.cs
ev 4d2bb8c782
Rockers + Rhythm Tweezers Call and Response API (#444)
* rock hers

* Rockers is a real game and also color maps have been added

* little more set up

* anims and mor sprites

* First version of CallAndResponseHandler added

* You can mute now wow

* Got some stuff working

* anim city

* Fixed Inputs

* Visual goodies

* Changed how some events work

* Rockers is now stack proof

* Fixed a bug

* Bend early stages

* bendbendbendbendbendover

* bend fully implemented

* Removed "noise"

* pain

* Many animation

* Bend anims implemented

* strum effect implemented

* Made bends work way better

* dfgdfsgsdffsd

* Implemented strumstart and countin

* hi

* Made strumstart transition into strumidle

* Implemented samples

* All of the btsds samples are in now too

* many anim2

* A buggy version of the custom together system has been implemented

* Ok now it's unbuggified

* fixed a small thing

* lightning eff

* anim fixes

* oops

* you can now mute voiceline and also put in a standalone voiceline block

* Tweaks to dropdowns

* more tiny anim thing

* more animation stuff

* Bug fixes

* implemented mute and gotomiddle sliders for custom together event

* Default cmon and last one added

* You can chain last ones and cmons now

* Applause sounds added

* Fixed some bugs

* Made it so you can disable camera movement

* fixed an inconsistency

* Rhythm tweezers is actually kinda playable now, not finished though, i need to make beat offset work with this

* Rhythm tweezers now works between game switches

* Beat offset eradication

* Made eye size work properly

* Camera quad ease rather than quint

* Inactive intervals added

* Rockers works inactively too now

* Bug fix

* No peeking! No way!

* Alt smile added for tweezers

* early and late riff

* jj miss anim

* icon and miss

* Long hair works properly now

* Miss anims implemented for rockers

---------

Co-authored-by: Rapandrasmus <78219215+Rapandrasmus@users.noreply.github.com>
Co-authored-by: minenice55 <star.elementa@gmail.com>
2023-05-29 20:09:34 +00:00

174 lines
6.3 KiB
C#

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Starpelly;
namespace HeavenStudio.Games
{
public class CallAndResponseHandler
{
public struct CallAndResponseEventParam
{
public string propertyName;
public dynamic value;
public CallAndResponseEventParam(string propertyName, dynamic value)
{
this.propertyName = propertyName;
this.value = value;
}
}
public class CallAndResponseEvent
{
public float beat;
public float length;
public float relativeBeat; // this beat is relative to the intervalStartBeat
public Dictionary<string, dynamic> DynamicData; //if you need more properties for your queued event
public string tag;
public CallAndResponseEvent(float beat, float relativeBeat, string tag, float length = 0)
{
this.beat = beat;
this.length = length;
this.relativeBeat = relativeBeat;
DynamicData = new Dictionary<string, dynamic>();
this.tag = tag;
this.length = length;
}
public void CreateProperty(string name, dynamic defaultValue)
{
if (!DynamicData.ContainsKey(name))
{
DynamicData.Add(name, defaultValue);
}
}
public dynamic this[string propertyName]
{
get
{
if (DynamicData.ContainsKey(propertyName))
{
return DynamicData[propertyName];
}
else
{
Debug.LogWarning("This property does not exist on this callAndResponse event.");
return null;
}
}
set
{
if (DynamicData.ContainsKey(propertyName))
{
DynamicData[propertyName] = value;
}
else
{
Debug.LogError($"This callAndRespone event does not have a property named {propertyName}! Attempted to insert value of type {value.GetType()}");
}
}
}
}
public float intervalStartBeat = -1; // the first beat of the interval
public float intervalLength = -1; // the duration of the interval in beats
public float defaultIntervalLength; // when an event is queued and the interval has not started yet, it will use this as the interval length.
public CallAndResponseHandler(float defaultIntervalLength)
{
this.defaultIntervalLength = defaultIntervalLength;
}
public List<CallAndResponseEvent> queuedEvents = new List<CallAndResponseEvent>();
/// <summary>
/// Returns the normalized progress of the interval
/// </summary>
public float GetIntervalProgress(float lengthOffset = 0)
{
return Conductor.instance.GetPositionFromBeat(intervalStartBeat, intervalLength - lengthOffset);
}
public float GetIntervalProgressFromBeat(float beat, float lengthOffset = 0)
{
return Mathp.Normalize(beat, intervalStartBeat, intervalStartBeat + intervalLength - lengthOffset);
}
/// <summary>
/// Is the interval currently on-going?
/// </summary>
public bool IntervalIsActive()
{
float progress = GetIntervalProgress();
return progress >= 0 && progress <= 1;
}
/// <summary>
/// Starts the interval.
/// </summary>
/// <param name="beat">The interval start beat.</param>
/// <param name="length">The length of the interval.</param>
public void StartInterval(float beat, float length)
{
intervalStartBeat = beat;
intervalLength = length;
defaultIntervalLength = length;
}
/// <summary>
/// Adds an event to the queued events list.
/// </summary>
/// <param name="beat">The current beat.</param>
/// <param name="crParams">Extra properties to add to the event.</param>
/// <param name="ignoreInterval">If true, this function will not start a new interval if the interval isn't active.</param>
/// <param name="overrideInterval">If true, overrides the current interval.</param>
public void AddEvent(float beat, float length = 0, string tag = "", List<CallAndResponseEventParam> crParams = null, bool ignoreInterval = false, bool overrideInterval = false)
{
if ((!IntervalIsActive() && !ignoreInterval) || overrideInterval)
{
StartInterval(beat, defaultIntervalLength);
}
CallAndResponseEvent addedEvent = new CallAndResponseEvent(beat, beat - intervalStartBeat, tag, length);
if (crParams != null && crParams.Count > 0)
{
foreach (var param in crParams)
{
addedEvent.CreateProperty(param.propertyName, param.value);
}
}
queuedEvents.Add(addedEvent);
}
/// <summary>
/// Check if an event exists at beat.
/// </summary>
/// <param name="beat">The beat to check.</param>
public bool EventExistsAtBeat(float beat)
{
if (queuedEvents.Count == 0)
{
return false;
}
CallAndResponseEvent foundEvent = queuedEvents.Find(x => x.beat == beat);
return foundEvent != null;
}
/// <summary>
/// Check if an event exists at relativeBeat.
/// </summary>
/// <param name="beat">The beat to check.</param>
public bool EventExistsAtRelativetBeat(float relativeBeat)
{
if (queuedEvents.Count == 0)
{
return false;
}
CallAndResponseEvent foundEvent = queuedEvents.Find(x => x.relativeBeat == relativeBeat);
return foundEvent != null;
}
}
}