mirror of
https://github.com/RHeavenStudio/HeavenStudio.git
synced 2025-06-12 12:17:37 +02:00
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>
This commit is contained in:
174
Assets/Scripts/Games/CallAndResponseHandler.cs
Normal file
174
Assets/Scripts/Games/CallAndResponseHandler.cs
Normal file
@ -0,0 +1,174 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
11
Assets/Scripts/Games/CallAndResponseHandler.cs.meta
Normal file
11
Assets/Scripts/Games/CallAndResponseHandler.cs.meta
Normal file
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4af79422cc731bc489888dd72a37e11a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -15,20 +15,15 @@ namespace HeavenStudio.Games.Scripts_RhythmTweezers
|
||||
private Tweezers tweezers;
|
||||
private bool plucked;
|
||||
|
||||
PlayerActionEvent pluckEvent;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
game = RhythmTweezers.instance;
|
||||
tweezers = game.Tweezers;
|
||||
}
|
||||
|
||||
private void Start() {
|
||||
pluckEvent = game.ScheduleInput(createBeat, game.tweezerBeatOffset + game.beatInterval, InputType.STANDARD_DOWN | InputType.DIRECTION_DOWN, Just, Miss, Out);
|
||||
}
|
||||
|
||||
private void Update()
|
||||
public void StartInput(float beat, float length)
|
||||
{
|
||||
game.ScheduleInput(beat, length, InputType.STANDARD_DOWN | InputType.DIRECTION_DOWN, Just, Miss, Out);
|
||||
}
|
||||
|
||||
public void Ace()
|
||||
@ -60,11 +55,5 @@ namespace HeavenStudio.Games.Scripts_RhythmTweezers
|
||||
}
|
||||
|
||||
private void Out(PlayerActionEvent caller) {}
|
||||
|
||||
void OnDestroy()
|
||||
{
|
||||
if (pluckEvent != null)
|
||||
pluckEvent.Disable();
|
||||
}
|
||||
}
|
||||
}
|
@ -3,6 +3,7 @@ using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
using HeavenStudio.Util;
|
||||
using UnityEngine.UIElements;
|
||||
|
||||
namespace HeavenStudio.Games.Scripts_RhythmTweezers
|
||||
{
|
||||
@ -21,9 +22,9 @@ namespace HeavenStudio.Games.Scripts_RhythmTweezers
|
||||
|
||||
private Sound pullSound;
|
||||
|
||||
PlayerActionEvent pluckEvent;
|
||||
private float inputBeat;
|
||||
|
||||
PlayerActionEvent endEvent;
|
||||
InputType endInput;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
@ -32,34 +33,31 @@ namespace HeavenStudio.Games.Scripts_RhythmTweezers
|
||||
tweezers = game.Tweezers;
|
||||
}
|
||||
|
||||
private void Start() {
|
||||
game.ScheduleInput(createBeat, game.tweezerBeatOffset + game.beatInterval, InputType.STANDARD_DOWN | InputType.DIRECTION_DOWN, StartJust, StartMiss, Out);
|
||||
public void StartInput(float beat, float length)
|
||||
{
|
||||
inputBeat = beat + length;
|
||||
game.ScheduleInput(beat, length, InputType.STANDARD_DOWN | InputType.DIRECTION_DOWN, StartJust, StartMiss, Out);
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
if (pluckState == 1)
|
||||
{
|
||||
bool input = PlayerInput.PressedUp();
|
||||
if (endInput == InputType.DIRECTION_UP) input = PlayerInput.GetAnyDirectionUp();
|
||||
if (input && !game.IsExpectingInputNow(endInput))
|
||||
{
|
||||
endEvent.isEligible = false;
|
||||
EndEarly();
|
||||
return;
|
||||
}
|
||||
|
||||
Vector3 tst = tweezers.tweezerSpriteTrans.position;
|
||||
var hairDirection = new Vector3(tst.x + 0.173f, tst.y) - holder.transform.position;
|
||||
holder.transform.rotation = Quaternion.FromToRotation(Vector3.down, hairDirection);
|
||||
|
||||
float normalizedBeat = Conductor.instance.GetPositionFromBeat(createBeat + game.tweezerBeatOffset + game.beatInterval, 0.5f);
|
||||
float normalizedBeat = Conductor.instance.GetPositionFromBeat(inputBeat, 0.5f);
|
||||
anim.Play("LoopPull", 0, normalizedBeat);
|
||||
tweezers.anim.Play("Tweezers_LongPluck", 0, normalizedBeat);
|
||||
|
||||
if (!game.IsExpectingInputNow(InputType.STANDARD_UP | InputType.DIRECTION_DOWN_UP) && PlayerInput.PressedUp(true) && normalizedBeat < 1f)
|
||||
{
|
||||
EndEarly();
|
||||
endEvent.Disable();
|
||||
}
|
||||
// Auto-release if holding at release time.
|
||||
if (normalizedBeat >= 1f)
|
||||
endEvent.Hit(0f, 1f);
|
||||
if (normalizedBeat >= 1f && !game.IsExpectingInputNow(InputType.STANDARD_UP | InputType.DIRECTION_DOWN_UP))
|
||||
EndAce();
|
||||
}
|
||||
|
||||
loop.transform.localScale = Vector2.one / holder.transform.localScale;
|
||||
@ -67,6 +65,7 @@ namespace HeavenStudio.Games.Scripts_RhythmTweezers
|
||||
|
||||
public void EndAce()
|
||||
{
|
||||
if (pluckState != 1) return;
|
||||
tweezers.LongPluck(true, this);
|
||||
tweezers.hitOnFrame++;
|
||||
|
||||
@ -78,9 +77,9 @@ namespace HeavenStudio.Games.Scripts_RhythmTweezers
|
||||
|
||||
public void EndEarly()
|
||||
{
|
||||
var normalized = Conductor.instance.GetPositionFromBeat(createBeat + game.tweezerBeatOffset + game.beatInterval, 0.5f);
|
||||
var normalized = Conductor.instance.GetPositionFromBeat(inputBeat, 0.5f);
|
||||
anim.Play("LoopPullReverse", 0, normalized);
|
||||
tweezers.anim.Play("Idle", 0, 0);
|
||||
tweezers.anim.Play("Tweezers_Idle", 0, 0);
|
||||
|
||||
if (pullSound != null)
|
||||
pullSound.Stop();
|
||||
@ -95,17 +94,9 @@ namespace HeavenStudio.Games.Scripts_RhythmTweezers
|
||||
pluckState = -1;
|
||||
return;
|
||||
}
|
||||
if (PlayerInput.GetAnyDirectionDown())
|
||||
{
|
||||
endInput = InputType.DIRECTION_UP;
|
||||
}
|
||||
else
|
||||
{
|
||||
endInput = InputType.STANDARD_UP;
|
||||
}
|
||||
pullSound = Jukebox.PlayOneShotGame($"rhythmTweezers/longPull{UnityEngine.Random.Range(1, 5)}");
|
||||
pluckState = 1;
|
||||
endEvent = game.ScheduleInput(createBeat, game.tweezerBeatOffset + game.beatInterval + 0.5f, endInput, EndJust, Out, Out);
|
||||
endEvent = game.ScheduleInput(inputBeat, 0.5f, InputType.STANDARD_UP | InputType.DIRECTION_DOWN_UP, EndJust, Out, Out);
|
||||
}
|
||||
|
||||
private void StartMiss(PlayerActionEvent caller)
|
||||
@ -123,13 +114,5 @@ namespace HeavenStudio.Games.Scripts_RhythmTweezers
|
||||
}
|
||||
EndAce();
|
||||
}
|
||||
|
||||
void OnDestroy()
|
||||
{
|
||||
if (pluckEvent != null)
|
||||
pluckEvent.Disable();
|
||||
if (endEvent != null)
|
||||
endEvent.Disable();
|
||||
}
|
||||
}
|
||||
}
|
@ -20,73 +20,104 @@ namespace HeavenStudio.Games.Loaders
|
||||
function = delegate { RhythmTweezers.instance.SetIntervalStart(eventCaller.currentEntity.beat, eventCaller.currentEntity.length); },
|
||||
defaultLength = 4f,
|
||||
resizable = true,
|
||||
priority = 1
|
||||
priority = 1,
|
||||
inactiveFunction = delegate { RhythmTweezers.InactiveInterval(eventCaller.currentEntity.beat, eventCaller.currentEntity.length); }
|
||||
},
|
||||
new GameAction("short hair", "Short Hair")
|
||||
{
|
||||
|
||||
inactiveFunction = delegate { RhythmTweezers.SpawnHairInactive(eventCaller.currentEntity.beat); },
|
||||
function = delegate { RhythmTweezers.instance.SpawnHair(eventCaller.currentEntity.beat); },
|
||||
defaultLength = 0.5f
|
||||
},
|
||||
new GameAction("long hair", "Curly Hair")
|
||||
{
|
||||
inactiveFunction = delegate { RhythmTweezers.SpawnLongHairInactive(eventCaller.currentEntity.beat); },
|
||||
function = delegate { RhythmTweezers.instance.SpawnLongHair(eventCaller.currentEntity.beat); },
|
||||
defaultLength = 0.5f
|
||||
},
|
||||
new GameAction("passTurn", "Pass Turn")
|
||||
{
|
||||
function = delegate { var e = eventCaller.currentEntity; RhythmTweezers.instance.PassTurn(e.beat, e.length); },
|
||||
resizable = true,
|
||||
preFunction = delegate { var e = eventCaller.currentEntity; RhythmTweezers.PrePassTurn(e.beat, e.length); }
|
||||
},
|
||||
new GameAction("next vegetable", "Swap Vegetable")
|
||||
{
|
||||
function = delegate { var e = eventCaller.currentEntity; RhythmTweezers.instance.NextVegetable(e.beat, e["type"], e["colorA"], e["colorB"]); },
|
||||
function = delegate
|
||||
{
|
||||
var e = eventCaller.currentEntity;
|
||||
if (!e["instant"]) RhythmTweezers.instance.NextVegetable(e.beat, e["type"], e["colorA"], e["colorB"]);
|
||||
else RhythmTweezers.instance.ChangeVegetableImmediate(e["type"], e["colorA"], e["colorB"]);
|
||||
},
|
||||
defaultLength = 0.5f,
|
||||
parameters = new List<Param>()
|
||||
{
|
||||
new Param("type", RhythmTweezers.VegetableType.Onion, "Type", "The vegetable to switch to"),
|
||||
new Param("colorA", RhythmTweezers.defaultOnionColor, "Onion Color", "The color of the onion"),
|
||||
new Param("colorB", RhythmTweezers.defaultPotatoColor, "Potato Color", "The color of the potato"),
|
||||
new Param("instant", false, "Instant", "Instantly change vegetable?")
|
||||
},
|
||||
priority = 3
|
||||
},
|
||||
new GameAction("noPeek", "No Peeking Sign")
|
||||
{
|
||||
preFunction = delegate { var e = eventCaller.currentEntity; RhythmTweezers.PreNoPeeking(e.beat, e.length); },
|
||||
defaultLength = 4f,
|
||||
resizable = true
|
||||
},
|
||||
new GameAction("fade background color", "Background Fade")
|
||||
{
|
||||
function = delegate
|
||||
{
|
||||
var e = eventCaller.currentEntity;
|
||||
if (e["instant"])
|
||||
{
|
||||
RhythmTweezers.instance.ChangeBackgroundColor(e["colorA"], 0f);
|
||||
}
|
||||
else
|
||||
{
|
||||
RhythmTweezers.instance.FadeBackgroundColor(e["colorA"], e["colorB"], e.length);
|
||||
}
|
||||
},
|
||||
resizable = true,
|
||||
parameters = new List<Param>()
|
||||
{
|
||||
new Param("colorA", Color.white, "Start Color", "The starting color in the fade"),
|
||||
new Param("colorB", RhythmTweezers.defaultBgColor, "End Color", "The ending color in the fade"),
|
||||
new Param("instant", false, "Instant", "Instantly change color to start color?")
|
||||
}
|
||||
},
|
||||
new GameAction("altSmile", "Use Alt Smile")
|
||||
{
|
||||
function = delegate
|
||||
{
|
||||
RhythmTweezers.instance.VegetableAnimator.SetBool("UseAltSmile", !RhythmTweezers.instance.VegetableAnimator.GetBool("UseAltSmile"));
|
||||
},
|
||||
defaultLength = 0.5f
|
||||
},
|
||||
//backwards compatibility
|
||||
new GameAction("change vegetable", "Change Vegetable (Instant)")
|
||||
{
|
||||
function = delegate { var e = eventCaller.currentEntity; RhythmTweezers.instance.ChangeVegetableImmediate(e["type"], e["colorA"], e["colorB"]); },
|
||||
defaultLength = 0.5f,
|
||||
parameters = new List<Param>()
|
||||
{
|
||||
new Param("type", RhythmTweezers.VegetableType.Onion, "Type", "The vegetable to switch to"),
|
||||
new Param("colorA", RhythmTweezers.defaultOnionColor, "Onion Color", "The color of the onion"),
|
||||
new Param("colorB", RhythmTweezers.defaultPotatoColor, "Potato Color", "The color of the potato")
|
||||
},
|
||||
priority = 3
|
||||
},
|
||||
new GameAction("change vegetable", "Change Vegetable (Instant)")
|
||||
{
|
||||
function = delegate { var e = eventCaller.currentEntity; RhythmTweezers.instance.ChangeVegetableImmediate(e["type"], e["colorA"], e["colorB"]); },
|
||||
defaultLength = 0.5f,
|
||||
parameters = new List<Param>()
|
||||
{
|
||||
new Param("type", RhythmTweezers.VegetableType.Onion, "Type", "The vegetable to switch to"),
|
||||
new Param("colorA", RhythmTweezers.defaultOnionColor, "Onion Color", "The color of the onion"),
|
||||
new Param("colorB", RhythmTweezers.defaultPotatoColor, "Potato Color", "The color of the potato")
|
||||
}
|
||||
},
|
||||
new GameAction("set tweezer delay", "Offset Tweezer")
|
||||
{
|
||||
function = delegate { RhythmTweezers.instance.tweezerBeatOffset = eventCaller.currentEntity.length; },
|
||||
resizable = true,
|
||||
priority = 2
|
||||
},
|
||||
new GameAction("reset tweezer delay", "Reset Tweezer Offset")
|
||||
{
|
||||
function = delegate { RhythmTweezers.instance.tweezerBeatOffset = 0f; },
|
||||
defaultLength = 0.5f,
|
||||
priority = 2
|
||||
hidden = true,
|
||||
},
|
||||
new GameAction("set background color", "Background Colour")
|
||||
{
|
||||
function = delegate { var e = eventCaller.currentEntity; RhythmTweezers.instance.ChangeBackgroundColor(e["colorA"], 0f); },
|
||||
function = delegate { var e = eventCaller.currentEntity; RhythmTweezers.instance.ChangeBackgroundColor(e["colorA"], 0f); },
|
||||
defaultLength = 0.5f,
|
||||
parameters = new List<Param>()
|
||||
parameters = new List<Param>()
|
||||
{
|
||||
new Param("colorA", RhythmTweezers.defaultBgColor, "Background Color", "The background color to change to")
|
||||
}
|
||||
},
|
||||
hidden = true
|
||||
},
|
||||
new GameAction("fade background color", "Background Fade")
|
||||
{
|
||||
function = delegate { var e = eventCaller.currentEntity; RhythmTweezers.instance.FadeBackgroundColor(e["colorA"], e["colorB"], e.length); },
|
||||
resizable = true,
|
||||
parameters = new List<Param>()
|
||||
{
|
||||
new Param("colorA", Color.white, "Start Color", "The starting color in the fade"),
|
||||
new Param("colorB", RhythmTweezers.defaultBgColor, "End Color", "The ending color in the fade")
|
||||
}
|
||||
}
|
||||
},
|
||||
new List<string>() {"agb", "repeat"},
|
||||
"agbhair", "en",
|
||||
@ -108,6 +139,12 @@ namespace HeavenStudio.Games
|
||||
Potato
|
||||
}
|
||||
|
||||
private struct QueuedPeek
|
||||
{
|
||||
public float beat;
|
||||
public float length;
|
||||
}
|
||||
|
||||
[Header("References")]
|
||||
public Transform VegetableHolder;
|
||||
public SpriteRenderer Vegetable;
|
||||
@ -118,16 +155,16 @@ namespace HeavenStudio.Games
|
||||
public GameObject hairBase;
|
||||
public GameObject longHairBase;
|
||||
public GameObject pluckedHairBase;
|
||||
[SerializeField] private Animator noPeeking;
|
||||
|
||||
public GameObject HairsHolder;
|
||||
public GameObject DroppedHairsHolder;
|
||||
[NonSerialized] public int hairsLeft = 0;
|
||||
|
||||
[Header("Variables")]
|
||||
public float beatInterval = 4f;
|
||||
float intervalStartBeat;
|
||||
bool intervalStarted;
|
||||
public float tweezerBeatOffset = 0f;
|
||||
private float passTurnBeat;
|
||||
private float passTurnEndBeat = 2;
|
||||
private static List<QueuedPeek> queuedPeeks = new List<QueuedPeek>();
|
||||
|
||||
[Header("Sprites")]
|
||||
public Sprite pluckedHairSprite;
|
||||
@ -172,67 +209,172 @@ namespace HeavenStudio.Games
|
||||
}
|
||||
|
||||
public static RhythmTweezers instance { get; set; }
|
||||
private static CallAndResponseHandler crHandlerInstance;
|
||||
|
||||
private List<Hair> spawnedHairs = new List<Hair>();
|
||||
private List<LongHair> spawnedLongs = new List<LongHair>();
|
||||
|
||||
private static List<float> passedTurns = new List<float>();
|
||||
|
||||
private float peekBeat = -1;
|
||||
private bool peekRising;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
instance = this;
|
||||
if (crHandlerInstance == null)
|
||||
{
|
||||
crHandlerInstance = new CallAndResponseHandler(4);
|
||||
}
|
||||
if (crHandlerInstance.queuedEvents.Count > 0)
|
||||
{
|
||||
foreach (var crEvent in crHandlerInstance.queuedEvents)
|
||||
{
|
||||
if (crEvent.tag == "Hair")
|
||||
{
|
||||
Hair hair = Instantiate(hairBase, HairsHolder.transform).GetComponent<Hair>();
|
||||
spawnedHairs.Add(hair);
|
||||
hair.gameObject.SetActive(true);
|
||||
hair.GetComponent<Animator>().Play("SmallAppear", 0, 1);
|
||||
float rot = -58f + 116 * Mathp.Normalize(crEvent.relativeBeat, 0, crHandlerInstance.intervalLength - 1);
|
||||
hair.transform.eulerAngles = new Vector3(0, 0, rot);
|
||||
hair.createBeat = crEvent.beat;
|
||||
}
|
||||
else if (crEvent.tag == "Long")
|
||||
{
|
||||
LongHair hair = Instantiate(longHairBase, HairsHolder.transform).GetComponent<LongHair>();
|
||||
spawnedLongs.Add(hair);
|
||||
hair.gameObject.SetActive(true);
|
||||
hair.GetComponent<Animator>().Play("LongAppear", 0, 1);
|
||||
float rot = -58f + 116 * Mathp.Normalize(crEvent.relativeBeat, 0, crHandlerInstance.intervalLength - 1);
|
||||
hair.transform.eulerAngles = new Vector3(0, 0, rot);
|
||||
hair.createBeat = crEvent.beat;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void OnDestroy()
|
||||
{
|
||||
if (crHandlerInstance != null && !Conductor.instance.isPlaying)
|
||||
{
|
||||
crHandlerInstance = null;
|
||||
}
|
||||
}
|
||||
|
||||
public static void SpawnHairInactive(float beat)
|
||||
{
|
||||
if (crHandlerInstance == null)
|
||||
{
|
||||
crHandlerInstance = new CallAndResponseHandler(4);
|
||||
}
|
||||
if (crHandlerInstance.queuedEvents.Count > 0 && crHandlerInstance.queuedEvents.Find(x => x.beat == beat || (beat >= x.beat && beat <= x.beat + x.length)) != null) return;
|
||||
crHandlerInstance.AddEvent(beat, 0, "Hair");
|
||||
}
|
||||
|
||||
public static void SpawnLongHairInactive(float beat)
|
||||
{
|
||||
if (crHandlerInstance == null)
|
||||
{
|
||||
crHandlerInstance = new CallAndResponseHandler(4);
|
||||
}
|
||||
if (crHandlerInstance.queuedEvents.Count > 0 && crHandlerInstance.queuedEvents.Find(x => x.beat == beat || (beat >= x.beat && beat <= x.beat + x.length)) != null) return;
|
||||
crHandlerInstance.AddEvent(beat, 0.5f, "Long");
|
||||
}
|
||||
|
||||
public void SpawnHair(float beat)
|
||||
{
|
||||
if (crHandlerInstance.queuedEvents.Count > 0 && crHandlerInstance.queuedEvents.Find(x => x.beat == beat || (beat >= x.beat && beat <= x.beat + x.length)) != null) return;
|
||||
// End transition early if the next hair is a lil early.
|
||||
StopTransitionIfActive();
|
||||
|
||||
// If interval hasn't started, assume this is the first hair of the interval.
|
||||
if (!intervalStarted)
|
||||
{
|
||||
SetIntervalStart(beat, beatInterval);
|
||||
}
|
||||
crHandlerInstance.AddEvent(beat, 0, "Hair");
|
||||
|
||||
Jukebox.PlayOneShotGame("rhythmTweezers/shortAppear", beat);
|
||||
Hair hair = Instantiate(hairBase, HairsHolder.transform).GetComponent<Hair>();
|
||||
spawnedHairs.Add(hair);
|
||||
hair.gameObject.SetActive(true);
|
||||
hair.GetComponent<Animator>().Play("SmallAppear", 0, 0);
|
||||
|
||||
float rot = -58f + 116 * Mathp.Normalize(beat, intervalStartBeat, intervalStartBeat + beatInterval - 1f);
|
||||
float rot = -58f + 116 * crHandlerInstance.GetIntervalProgressFromBeat(beat, 1);
|
||||
hair.transform.eulerAngles = new Vector3(0, 0, rot);
|
||||
hair.createBeat = beat;
|
||||
hairsLeft++;
|
||||
}
|
||||
|
||||
public void SpawnLongHair(float beat)
|
||||
{
|
||||
if (crHandlerInstance.queuedEvents.Count > 0 && crHandlerInstance.queuedEvents.Find(x => x.beat == beat || (beat >= x.beat && beat <= x.beat + x.length)) != null) return;
|
||||
StopTransitionIfActive();
|
||||
|
||||
if (!intervalStarted)
|
||||
{
|
||||
SetIntervalStart(beat, beatInterval);
|
||||
}
|
||||
crHandlerInstance.AddEvent(beat, 0.5f, "Long");
|
||||
|
||||
Jukebox.PlayOneShotGame("rhythmTweezers/longAppear", beat);
|
||||
LongHair hair = Instantiate(longHairBase, HairsHolder.transform).GetComponent<LongHair>();
|
||||
spawnedLongs.Add(hair);
|
||||
hair.gameObject.SetActive(true);
|
||||
hair.GetComponent<Animator>().Play("LongAppear", 0, 0);
|
||||
|
||||
float rot = -58f + 116 * Mathp.Normalize(beat, intervalStartBeat, intervalStartBeat + beatInterval - 1f);
|
||||
float rot = -58f + 116 * crHandlerInstance.GetIntervalProgressFromBeat(beat, 1);
|
||||
hair.transform.eulerAngles = new Vector3(0, 0, rot);
|
||||
hair.createBeat = beat;
|
||||
hairsLeft++;
|
||||
}
|
||||
|
||||
public void SetIntervalStart(float beat, float interval = 4f)
|
||||
{
|
||||
// Don't do these things if the interval was already started.
|
||||
if (!intervalStarted)
|
||||
{
|
||||
// End transition early if the interval starts a lil early.
|
||||
StopTransitionIfActive();
|
||||
hairsLeft = 0;
|
||||
intervalStarted = true;
|
||||
}
|
||||
StopTransitionIfActive();
|
||||
hairsLeft = 0;
|
||||
eyeSize = 0;
|
||||
crHandlerInstance.StartInterval(beat, interval);
|
||||
}
|
||||
|
||||
intervalStartBeat = beat;
|
||||
beatInterval = interval;
|
||||
public static void InactiveInterval(float beat, float interval)
|
||||
{
|
||||
if (crHandlerInstance == null)
|
||||
{
|
||||
crHandlerInstance = new CallAndResponseHandler(4);
|
||||
}
|
||||
crHandlerInstance.StartInterval(beat, interval);
|
||||
}
|
||||
|
||||
public void PassTurn(float beat, float length)
|
||||
{
|
||||
if (crHandlerInstance.queuedEvents.Count > 0)
|
||||
{
|
||||
hairsLeft = crHandlerInstance.queuedEvents.Count;
|
||||
foreach (var crEvent in crHandlerInstance.queuedEvents)
|
||||
{
|
||||
if (crEvent.tag == "Hair")
|
||||
{
|
||||
Hair hairToInput = spawnedHairs.Find(x => x.createBeat == crEvent.beat);
|
||||
hairToInput.StartInput(beat + length, crEvent.relativeBeat);
|
||||
}
|
||||
else if (crEvent.tag == "Long")
|
||||
{
|
||||
LongHair hairToInput = spawnedLongs.Find(x => x.createBeat == crEvent.beat);
|
||||
hairToInput.StartInput(beat + length, crEvent.relativeBeat);
|
||||
}
|
||||
}
|
||||
crHandlerInstance.queuedEvents.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
public static void PrePassTurn(float beat, float length)
|
||||
{
|
||||
if (GameManager.instance.currentGame == "rhythmTweezers")
|
||||
{
|
||||
instance.SetPassTurnValues(beat + length);
|
||||
}
|
||||
else
|
||||
{
|
||||
passedTurns.Add(beat + length);
|
||||
}
|
||||
}
|
||||
|
||||
private void SetPassTurnValues(float startBeat)
|
||||
{
|
||||
if (crHandlerInstance.intervalLength <= 0) return;
|
||||
passTurnBeat = startBeat - 1f;
|
||||
passTurnEndBeat = startBeat + crHandlerInstance.intervalLength;
|
||||
}
|
||||
|
||||
const float vegDupeOffset = 16.7f;
|
||||
@ -261,7 +403,6 @@ namespace HeavenStudio.Games
|
||||
|
||||
ResetVegetable();
|
||||
transitioning = false;
|
||||
intervalStarted = false;
|
||||
|
||||
}).SetEase(Ease.InOutSine);
|
||||
}
|
||||
@ -302,13 +443,57 @@ namespace HeavenStudio.Games
|
||||
ChangeBackgroundColor(end, beats);
|
||||
}
|
||||
|
||||
public static void PreNoPeeking(float beat, float length)
|
||||
{
|
||||
if (GameManager.instance.currentGame == "rhythmTweezers")
|
||||
{
|
||||
instance.NoPeeking(beat, length);
|
||||
}
|
||||
else
|
||||
{
|
||||
queuedPeeks.Add(new QueuedPeek()
|
||||
{
|
||||
beat = beat,
|
||||
length = length
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public void NoPeeking(float beat, float length)
|
||||
{
|
||||
peekBeat = beat - 1f;
|
||||
peekRising = true;
|
||||
BeatAction.New(instance.gameObject, new List<BeatAction.Action>()
|
||||
{
|
||||
new BeatAction.Action(beat + length, delegate { peekBeat = beat + length; peekRising = false; })
|
||||
});
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
if (!Conductor.instance.isPlaying && !Conductor.instance.isPaused && intervalStarted)
|
||||
if (Conductor.instance.isPlaying && !Conductor.instance.isPaused)
|
||||
{
|
||||
StopTransitionIfActive();
|
||||
ResetVegetable();
|
||||
intervalStarted = false;
|
||||
if (passedTurns.Count > 0)
|
||||
{
|
||||
foreach (var turn in passedTurns)
|
||||
{
|
||||
SetPassTurnValues(turn);
|
||||
}
|
||||
passedTurns.Clear();
|
||||
}
|
||||
if (queuedPeeks.Count > 0)
|
||||
{
|
||||
foreach (var peek in queuedPeeks)
|
||||
{
|
||||
NoPeeking(peek.beat, peek.length);
|
||||
}
|
||||
queuedPeeks.Clear();
|
||||
}
|
||||
float normalizedBeat = Conductor.instance.GetPositionFromBeat(peekBeat, 1);
|
||||
if (normalizedBeat >= 0f && normalizedBeat <= 1f)
|
||||
{
|
||||
noPeeking.DoNormalizedAnimation(peekRising ? "NoPeekRise" : "NoPeekLower", normalizedBeat);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -317,12 +502,9 @@ namespace HeavenStudio.Games
|
||||
// Set tweezer angle.
|
||||
var tweezerAngle = -180f;
|
||||
|
||||
if (intervalStarted)
|
||||
{
|
||||
var tweezerTime = Conductor.instance.songPositionInBeats - beatInterval - tweezerBeatOffset;
|
||||
var unclampedAngle = -58f + 116 * Mathp.Normalize(tweezerTime, intervalStartBeat, intervalStartBeat + beatInterval - 1f);
|
||||
tweezerAngle = Mathf.Clamp(unclampedAngle, -180f, 180f);
|
||||
}
|
||||
var tweezerTime = Conductor.instance.songPositionInBeats;
|
||||
var unclampedAngle = -58f + 116 * Mathp.Normalize(tweezerTime, passTurnBeat + 1f, passTurnEndBeat - 1f);
|
||||
tweezerAngle = Mathf.Clamp(unclampedAngle, -180f, 180f);
|
||||
|
||||
Tweezers.transform.eulerAngles = new Vector3(0, 0, tweezerAngle);
|
||||
|
||||
|
8
Assets/Scripts/Games/Rockers.meta
Normal file
8
Assets/Scripts/Games/Rockers.meta
Normal file
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9946cfa50b9c13f4fa89f8d447238b13
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
46
Assets/Scripts/Games/Rockers/RockerBendInput.cs
Normal file
46
Assets/Scripts/Games/Rockers/RockerBendInput.cs
Normal file
@ -0,0 +1,46 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
|
||||
namespace HeavenStudio.Games.Scripts_Rockers
|
||||
{
|
||||
public class RockerBendInput : MonoBehaviour
|
||||
{
|
||||
private int pitch;
|
||||
|
||||
private Rockers game;
|
||||
|
||||
public void Init(int pitch, float beat, float length)
|
||||
{
|
||||
game = Rockers.instance;
|
||||
this.pitch = pitch;
|
||||
game.ScheduleInput(beat, length, InputType.DIRECTION_DOWN, Just, Miss, Empty);
|
||||
}
|
||||
|
||||
private void Just(PlayerActionEvent caller, float state)
|
||||
{
|
||||
if (state >= 1f || state <= -1f)
|
||||
{
|
||||
game.Soshi.BendUp(pitch);
|
||||
Destroy(gameObject);
|
||||
return;
|
||||
}
|
||||
game.Soshi.BendUp(pitch);
|
||||
Destroy(gameObject);
|
||||
}
|
||||
|
||||
private void Miss(PlayerActionEvent caller)
|
||||
{
|
||||
game.JJ.Miss();
|
||||
Destroy(gameObject);
|
||||
}
|
||||
|
||||
private void Empty(PlayerActionEvent caller)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
11
Assets/Scripts/Games/Rockers/RockerBendInput.cs.meta
Normal file
11
Assets/Scripts/Games/Rockers/RockerBendInput.cs.meta
Normal file
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 40bd44c5381eb69468a65caa371f3876
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
1014
Assets/Scripts/Games/Rockers/Rockers.cs
Normal file
1014
Assets/Scripts/Games/Rockers/Rockers.cs
Normal file
File diff suppressed because it is too large
Load Diff
11
Assets/Scripts/Games/Rockers/Rockers.cs.meta
Normal file
11
Assets/Scripts/Games/Rockers/Rockers.cs.meta
Normal file
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8fb47fde533de754e9d8fa37bcd9dd63
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
56
Assets/Scripts/Games/Rockers/RockersInput.cs
Normal file
56
Assets/Scripts/Games/Rockers/RockersInput.cs
Normal file
@ -0,0 +1,56 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
|
||||
namespace HeavenStudio.Games.Scripts_Rockers
|
||||
{
|
||||
public class RockersInput : MonoBehaviour
|
||||
{
|
||||
private List<int> pitches = new List<int>();
|
||||
|
||||
private bool gleeClub;
|
||||
|
||||
private Rockers.PremadeSamples sample;
|
||||
private int sampleTones;
|
||||
|
||||
private bool jump;
|
||||
|
||||
private Rockers game;
|
||||
|
||||
public void Init(bool gleeClub, int[] pitches, float beat, float length, Rockers.PremadeSamples sample, int sampleTones, bool jump = false)
|
||||
{
|
||||
game = Rockers.instance;
|
||||
this.gleeClub = gleeClub;
|
||||
this.pitches = pitches.ToList();
|
||||
this.sample = sample;
|
||||
this.sampleTones = sampleTones;
|
||||
this.jump = jump;
|
||||
game.ScheduleInput(beat, length, InputType.STANDARD_UP, Just, Miss, Empty);
|
||||
}
|
||||
|
||||
private void Just(PlayerActionEvent caller, float state)
|
||||
{
|
||||
if (state >= 1f || state <= -1f)
|
||||
{
|
||||
game.Soshi.StrumStrings(gleeClub, pitches.ToArray(), sample, sampleTones, false, jump, true);
|
||||
Destroy(gameObject);
|
||||
return;
|
||||
}
|
||||
game.Soshi.StrumStrings(gleeClub, pitches.ToArray(), sample, sampleTones, false, jump);
|
||||
Destroy(gameObject);
|
||||
}
|
||||
|
||||
private void Miss(PlayerActionEvent caller)
|
||||
{
|
||||
game.JJ.Miss();
|
||||
Destroy(gameObject);
|
||||
}
|
||||
|
||||
private void Empty(PlayerActionEvent caller)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
11
Assets/Scripts/Games/Rockers/RockersInput.cs.meta
Normal file
11
Assets/Scripts/Games/Rockers/RockersInput.cs.meta
Normal file
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 061139f39edbd4340814a1cc568dbb9b
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
291
Assets/Scripts/Games/Rockers/RockersRocker.cs
Normal file
291
Assets/Scripts/Games/Rockers/RockersRocker.cs
Normal file
@ -0,0 +1,291 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using HeavenStudio.Util;
|
||||
using System;
|
||||
|
||||
namespace HeavenStudio.Games.Scripts_Rockers
|
||||
{
|
||||
public class RockersRocker : MonoBehaviour
|
||||
{
|
||||
private Sound[] stringSounds = new Sound[6];
|
||||
private Sound chordSound;
|
||||
private Animator anim;
|
||||
public int[] lastPitches = new int[6];
|
||||
public int lastBendPitch;
|
||||
|
||||
[SerializeField] private GameObject strumEffect;
|
||||
|
||||
[SerializeField] private bool JJ;
|
||||
|
||||
[NonSerialized] public bool muted;
|
||||
private bool strumming;
|
||||
private bool bending;
|
||||
[NonSerialized] public bool together;
|
||||
|
||||
[SerializeField] List<Sprite> bluSprites = new List<Sprite>();
|
||||
[SerializeField] List<Sprite> yelSprites = new List<Sprite>();
|
||||
[SerializeField] List<Sprite> normalSprites = new List<Sprite>();
|
||||
|
||||
[SerializeField] List<SpriteRenderer> lightningLefts = new List<SpriteRenderer>();
|
||||
[SerializeField] List<SpriteRenderer> lightningRights = new List<SpriteRenderer>();
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
anim = GetComponent<Animator>();
|
||||
}
|
||||
|
||||
private void OnDestroy()
|
||||
{
|
||||
StopSounds();
|
||||
}
|
||||
|
||||
private void StopSounds()
|
||||
{
|
||||
foreach (var sound in stringSounds)
|
||||
{
|
||||
if (sound != null)
|
||||
{
|
||||
sound.KillLoop(0);
|
||||
}
|
||||
}
|
||||
if (chordSound != null)
|
||||
{
|
||||
chordSound.KillLoop(0);
|
||||
}
|
||||
}
|
||||
|
||||
public void PrepareTogether(bool forceMute = false)
|
||||
{
|
||||
together = true;
|
||||
if ((PlayerInput.Pressing() && !JJ) || forceMute)
|
||||
{
|
||||
DoScaledAnimationAsync("ComeOnPrepare", 0.5f);
|
||||
if (forceMute) Mute(true, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
DoScaledAnimationAsync("ComeOnPrepareNoMute", 0.5f);
|
||||
if (strumming) strumEffect.GetComponent<Animator>().Play("StrumRight", 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
public void Miss()
|
||||
{
|
||||
if (strumming) return;
|
||||
DoScaledAnimationAsync(together ? "Miss" : "MissComeOn", 0.5f);
|
||||
}
|
||||
|
||||
public void ReturnBack()
|
||||
{
|
||||
together = false;
|
||||
if (JJ)
|
||||
{
|
||||
muted = false;
|
||||
DoScaledAnimationAsync("Return", 0.5f);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (strumming) strumEffect.GetComponent<Animator>().Play("StrumIdle", 0, 0);
|
||||
if (PlayerInput.Pressing() || (GameManager.instance.autoplay && muted))
|
||||
{
|
||||
DoScaledAnimationAsync("Crouch", 0.5f);
|
||||
}
|
||||
else
|
||||
{
|
||||
muted = false;
|
||||
DoScaledAnimationAsync("Return", 0.5f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void StrumStrings(bool gleeClub, int[] pitches, Rockers.PremadeSamples sample, int sampleTones, bool disableStrumEffect = false, bool jump = false, bool barely = false)
|
||||
{
|
||||
muted = false;
|
||||
strumming = true;
|
||||
StopSounds();
|
||||
if (sample == Rockers.PremadeSamples.None)
|
||||
{
|
||||
lastPitches = pitches;
|
||||
for (int i = 0; i < pitches.Length; i++)
|
||||
{
|
||||
if (pitches[i] == -1) continue;
|
||||
float pitch = Jukebox.GetPitchFromSemiTones(pitches[i], true);
|
||||
float volume = GetVolumeBasedOnAmountOfStrings(pitches.Length);
|
||||
string soundName = "rockers/strings/" + (gleeClub ? "gleeClub/" : "normal/" + (i + 1));
|
||||
Debug.Log("Pitch: " + pitch + " Volume: " + volume + " Name: " + soundName);
|
||||
stringSounds[i] = Jukebox.PlayOneShotGame(soundName, -1, pitch, volume, true);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
float pitch = Jukebox.GetPitchFromSemiTones(sampleTones, true);
|
||||
string soundName = sample switch
|
||||
{
|
||||
Rockers.PremadeSamples.None => "",
|
||||
Rockers.PremadeSamples.BendG5 => "rockers/BendG5",
|
||||
Rockers.PremadeSamples.BendC6 => "rockers/BendC6",
|
||||
Rockers.PremadeSamples.ChordA => "rockers/rocker/ChordA",
|
||||
Rockers.PremadeSamples.ChordAsus4 => "rockers/rocker/ChordAsus4",
|
||||
Rockers.PremadeSamples.ChordBm => "rockers/rocker/ChordBm",
|
||||
Rockers.PremadeSamples.ChordCSharpm7 => "rockers/rocker/ChordC#m7",
|
||||
Rockers.PremadeSamples.ChordDmaj7 => "rockers/rocker/ChordDmaj7",
|
||||
Rockers.PremadeSamples.ChordDmaj9 => "rockers/rocker/ChordDmaj9",
|
||||
Rockers.PremadeSamples.ChordFSharp5 => "rockers/rocker/ChordF#5",
|
||||
Rockers.PremadeSamples.ChordG => "rockers/rocker/ChordG",
|
||||
Rockers.PremadeSamples.ChordG5 => "rockers/rocker/ChordG5",
|
||||
Rockers.PremadeSamples.ChordGdim7 => "rockers/rocker/ChordGdim7",
|
||||
Rockers.PremadeSamples.ChordGm => "rockers/rocker/ChordGm",
|
||||
Rockers.PremadeSamples.NoteASharp4 => "rockers/rocker/NoteA#4",
|
||||
Rockers.PremadeSamples.NoteA5 => "rockers/rocker/NoteA5",
|
||||
Rockers.PremadeSamples.PracticeChordD => "rockers/rocker/PracticeChordD",
|
||||
Rockers.PremadeSamples.Remix6ChordA => "rockers/rocker/Remix6ChordA",
|
||||
Rockers.PremadeSamples.Remix10ChordD => "rockers/rocker/Remix10ChordD",
|
||||
Rockers.PremadeSamples.Remix10ChordFSharpm => "rockers/rocker/Remix10ChordF#m",
|
||||
Rockers.PremadeSamples.DoremiChordA7 => "rockers/doremi/ChordA7",
|
||||
Rockers.PremadeSamples.DoremiChordAm7 => "rockers/doremi/ChordAm7",
|
||||
Rockers.PremadeSamples.DoremiChordC => "rockers/doremi/ChordC",
|
||||
Rockers.PremadeSamples.DoremiChordC7 => "rockers/doremi/ChordC7",
|
||||
Rockers.PremadeSamples.DoremiChordCadd9 => "rockers/doremi/ChordCadd9",
|
||||
Rockers.PremadeSamples.DoremiChordDm => "rockers/doremi/ChordDm",
|
||||
Rockers.PremadeSamples.DoremiChordDm7 => "rockers/doremi/ChordDm7",
|
||||
Rockers.PremadeSamples.DoremiChordEm => "rockers/doremi/ChordEm",
|
||||
Rockers.PremadeSamples.DoremiChordF => "rockers/doremi/ChordF",
|
||||
Rockers.PremadeSamples.DoremiChordFadd9 => "rockers/doremi/ChordFadd9",
|
||||
Rockers.PremadeSamples.DoremiChordFm => "rockers/doremi/ChordFm",
|
||||
Rockers.PremadeSamples.DoremiChordG => "rockers/doremi/ChordG",
|
||||
Rockers.PremadeSamples.DoremiChordG7 => "rockers/doremi/ChordG7",
|
||||
Rockers.PremadeSamples.DoremiChordGm => "rockers/doremi/ChordGm",
|
||||
Rockers.PremadeSamples.DoremiChordGsus4 => "rockers/doremi/ChordGsus4",
|
||||
Rockers.PremadeSamples.DoremiNoteA2 => "rockers/doremi/NoteA2",
|
||||
Rockers.PremadeSamples.DoremiNoteE2 => "rockers/doremi/NoteE2",
|
||||
_ => throw new System.NotImplementedException(),
|
||||
};
|
||||
chordSound = Jukebox.PlayOneShotGame(soundName, -1, pitch, 1, true);
|
||||
}
|
||||
|
||||
if (together)
|
||||
{
|
||||
DoScaledAnimationAsync(jump ? "Jump" : "ComeOnStrum", 0.5f);
|
||||
if (disableStrumEffect) return;
|
||||
strumEffect.SetActive(true);
|
||||
bool strumLeft = JJ && jump;
|
||||
strumEffect.GetComponent<Animator>().Play(strumLeft ? "StrumStartLeft" : "StrumStartRIght", 0, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
DoScaledAnimationAsync("Strum", 0.5f);
|
||||
if (disableStrumEffect) return;
|
||||
strumEffect.SetActive(true);
|
||||
strumEffect.GetComponent<Animator>().Play("StrumStart", 0, 0);
|
||||
}
|
||||
|
||||
if (!JJ)
|
||||
{
|
||||
if (barely)
|
||||
{
|
||||
bool useYel = UnityEngine.Random.Range(1, 3) == 1;
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
if (lightningRights[i].gameObject.activeSelf) lightningRights[i].sprite = useYel ? yelSprites[i] : bluSprites[i];
|
||||
if (lightningLefts[i].gameObject.activeSelf) lightningLefts[i].sprite = useYel ? yelSprites[i] : bluSprites[i];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
if (lightningRights[i].gameObject.activeSelf) lightningRights[i].sprite = normalSprites[i];
|
||||
if (lightningLefts[i].gameObject.activeSelf) lightningLefts[i].sprite = normalSprites[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void BendUp(int pitch)
|
||||
{
|
||||
if (bending || !strumming) return;
|
||||
bending = true;
|
||||
lastBendPitch = pitch;
|
||||
if (chordSound != null)
|
||||
{
|
||||
chordSound.BendUp(0.05f, Jukebox.GetPitchFromSemiTones(Jukebox.GetSemitonesFromPitch(chordSound.pitch) + pitch, true));
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < stringSounds.Length; i++)
|
||||
{
|
||||
if (stringSounds[i] != null)
|
||||
{
|
||||
stringSounds[i].BendUp(0.05f, Jukebox.GetPitchFromSemiTones(Jukebox.GetSemitonesFromPitch(stringSounds[i].pitch) + pitch, true));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Jukebox.PlayOneShotGame("rockers/bendUp");
|
||||
DoScaledAnimationAsync("Bend", 0.5f);
|
||||
}
|
||||
|
||||
|
||||
public void BendDown()
|
||||
{
|
||||
if (!bending) return;
|
||||
bending = false;
|
||||
foreach (var sound in stringSounds)
|
||||
{
|
||||
if (sound != null)
|
||||
{
|
||||
sound.BendDown(0.05f);
|
||||
}
|
||||
}
|
||||
if (chordSound != null)
|
||||
{
|
||||
chordSound.BendDown(0.05f);
|
||||
}
|
||||
Jukebox.PlayOneShotGame("rockers/bendDown");
|
||||
DoScaledAnimationAsync("Unbend", 0.5f);
|
||||
}
|
||||
|
||||
private float GetVolumeBasedOnAmountOfStrings(int stringAmount)
|
||||
{
|
||||
|
||||
switch (stringAmount)
|
||||
{
|
||||
default:
|
||||
return 1;
|
||||
case 3:
|
||||
return 0.893f;
|
||||
case 4:
|
||||
return 0.75f;
|
||||
case 5:
|
||||
return 0.686f;
|
||||
case 6:
|
||||
return 0.62f;
|
||||
}
|
||||
}
|
||||
|
||||
public void Mute(bool soundExists = true, bool noAnim = false)
|
||||
{
|
||||
strumming = false;
|
||||
strumEffect.SetActive(false);
|
||||
bending = false;
|
||||
StopSounds();
|
||||
if (soundExists) Jukebox.PlayOneShotGame("rockers/mute");
|
||||
if (!noAnim) DoScaledAnimationAsync(together ? "ComeOnMute" : "Crouch", 0.5f);
|
||||
muted = true;
|
||||
}
|
||||
|
||||
public void UnHold()
|
||||
{
|
||||
if (!muted) return;
|
||||
muted = false;
|
||||
if (!together) DoScaledAnimationAsync("UnCrouch", 0.5f);
|
||||
}
|
||||
|
||||
private void DoScaledAnimationAsync(string name, float time)
|
||||
{
|
||||
anim.DoScaledAnimationAsync((JJ ? "JJ" : "") + name, time);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
11
Assets/Scripts/Games/Rockers/RockersRocker.cs.meta
Normal file
11
Assets/Scripts/Games/Rockers/RockersRocker.cs.meta
Normal file
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e879fe35102c7154aaed4934ab31bed1
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -301,6 +301,14 @@ namespace HeavenStudio.Util
|
||||
return Mathf.Pow(2f, (1f / 12f) * semiTones);
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Returns the semitones from a pitch. Does not work with pitches pitched to music.
|
||||
/// </summary>
|
||||
/// <param name="pitch">The pitch of the sound.</param>
|
||||
public static int GetSemitonesFromPitch(float pitch)
|
||||
{
|
||||
return (int)(12f * Mathf.Log(pitch, 2));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a pitch multiplier from cents.
|
||||
|
@ -1,6 +1,7 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using Starpelly;
|
||||
|
||||
namespace HeavenStudio.Util
|
||||
{
|
||||
@ -8,6 +9,7 @@ namespace HeavenStudio.Util
|
||||
{
|
||||
public AudioClip clip;
|
||||
public float pitch = 1;
|
||||
public float bendedPitch = 1; //only used with rockers
|
||||
public float volume = 1;
|
||||
|
||||
// For use with PlayOneShotScheduled
|
||||
@ -136,12 +138,69 @@ namespace HeavenStudio.Util
|
||||
audioSource.Stop();
|
||||
}
|
||||
|
||||
public void Pause()
|
||||
{
|
||||
if (audioSource != null)
|
||||
audioSource.Pause();
|
||||
}
|
||||
|
||||
public void UnPause()
|
||||
{
|
||||
if (audioSource != null)
|
||||
audioSource.UnPause();
|
||||
}
|
||||
|
||||
public void Delete()
|
||||
{
|
||||
GameManager.instance.SoundObjects.Remove(gameObject);
|
||||
Destroy(gameObject);
|
||||
}
|
||||
|
||||
#region Bend
|
||||
// All of these should only be used with rockers.
|
||||
public void BendUp(float bendTime, float bendedPitch)
|
||||
{
|
||||
this.bendedPitch = bendedPitch;
|
||||
StartCoroutine(BendUpLoop(bendTime));
|
||||
}
|
||||
|
||||
public void BendDown(float bendTime)
|
||||
{
|
||||
StartCoroutine(BendDownLoop(bendTime));
|
||||
}
|
||||
|
||||
IEnumerator BendUpLoop(float bendTime)
|
||||
{
|
||||
float startingPitch = audioSource.pitch;
|
||||
float bendTimer = 0f;
|
||||
|
||||
while (bendTimer < bendTime)
|
||||
{
|
||||
bendTimer += Time.deltaTime;
|
||||
float normalizedProgress = Mathp.Normalize(bendTimer, 0, bendTime);
|
||||
float currentPitch = Mathf.Lerp(startingPitch, bendedPitch, normalizedProgress);
|
||||
audioSource.pitch = Mathf.Min(currentPitch, bendedPitch);
|
||||
yield return null;
|
||||
}
|
||||
}
|
||||
|
||||
IEnumerator BendDownLoop(float bendTime)
|
||||
{
|
||||
float bendTimer = 0f;
|
||||
float startingPitch = pitch;
|
||||
|
||||
while (bendTimer < bendTime)
|
||||
{
|
||||
bendTimer += Time.deltaTime;
|
||||
float normalizedProgress = Mathp.Normalize(bendTimer, 0, bendTime);
|
||||
float currentPitch = Mathf.Lerp(startingPitch, bendedPitch, 1 - normalizedProgress);
|
||||
audioSource.pitch = Mathf.Max(currentPitch, pitch);
|
||||
yield return null;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public void KillLoop(float fadeTime)
|
||||
{
|
||||
StartCoroutine(FadeLoop(fadeTime));
|
||||
|
Reference in New Issue
Block a user