These four scripts form the logic backbone behind the rhythm component of Masking The Murder
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System.Collections; | |
using System.Collections.Generic; | |
using UnityEngine; | |
public class AudioTest : MonoBehaviour { | |
public float bpm = 120; | |
//the current position of the song (in seconds) | |
[HideInInspector] public float songPosition; | |
//the current position of the song (in beats) | |
[HideInInspector] public float songPosInBeats; | |
//the duration of a beat | |
[HideInInspector] public float secPerBeat; | |
//how much time (in seconds) has passed since the song started | |
[HideInInspector] public float dsptimesong; | |
[HideInInspector] public float[] notes; | |
[HideInInspector] public KeyCode[] keyPresses; | |
[HideInInspector] public GameObject[] NoteDisplay; | |
[HideInInspector] public GameObject dancerToSpawnOver; | |
public float numBeatsToCross = 4; | |
public Sprite[] spritesToSpawn; | |
public AudioClip[] songs; | |
public GameObject measureNote; | |
//Initialization | |
void Start() { | |
//notes represents when the note's input should be measured | |
notes = new float[] { 4.0f, 5.0f, 6.0f, 7.0f }; | |
keyPresses = new KeyCode[] { KeyCode.Alpha1, KeyCode.Alpha2, KeyCode.Alpha3, KeyCode.Alpha4 }; | |
secPerBeat = 60f / bpm; | |
dsptimesong = (float)AudioSettings.dspTime; | |
//If a dancer has already been chosen, Update NoteDisplay with the objects that hold ButtonNotes | |
if (dancerToSpawnOver != null) { | |
NoteDisplay = new GameObject[dancerToSpawnOver.transform.childCount]; | |
for (int i = 0; i < NoteDisplay.Length; i++) { | |
NoteDisplay[i] = dancerToSpawnOver.transform.GetChild(i).gameObject; | |
} | |
//Create moves for it | |
SpawnNewMove(notes, keyPresses); | |
} | |
//Choose a random song and play it | |
GetComponent<AudioSource>().clip = songs[Random.Range(0, songs.Length)]; | |
GetComponent<AudioSource>().Play(); | |
} | |
// Update is called once per frame | |
void Update() { | |
//calculate the song position in seconds and beats | |
songPosition = (float)(AudioSettings.dspTime - dsptimesong); | |
songPosInBeats = songPosition / secPerBeat; | |
} | |
//Spawns the new dance moves | |
public void SpawnNewMove(float[] timeValues, KeyCode[] buttonPresses) { | |
if (timeValues.Length != buttonPresses.Length) { | |
throw new System.Exception("The length of timeValues and buttonPresses must be identical"); | |
} | |
notes = timeValues; | |
keyPresses = buttonPresses; | |
//Creates the correct sprites and updates the ButtonNote with needed information | |
for (int i = 0; i < NoteDisplay.Length; i++) { | |
if (i < notes.Length) { | |
switch (keyPresses[i]) { | |
case KeyCode.Alpha1: NoteDisplay[i].GetComponent<SpriteRenderer>().sprite = spritesToSpawn[0]; break; | |
case KeyCode.Alpha2: NoteDisplay[i].GetComponent<SpriteRenderer>().sprite = spritesToSpawn[1]; break; | |
case KeyCode.Alpha3: NoteDisplay[i].GetComponent<SpriteRenderer>().sprite = spritesToSpawn[2]; break; | |
case KeyCode.Alpha4: NoteDisplay[i].GetComponent<SpriteRenderer>().sprite = spritesToSpawn[3]; break; | |
default: throw new System.Exception("You have provided a KeyCode that is not 1, 2, 3, or 4."); | |
} | |
ButtonNote CurrentButton = NoteDisplay[i].GetComponent<ButtonNote>(); | |
CurrentButton.correctInput = keyPresses[i]; | |
CurrentButton.conductor = this; | |
CurrentButton.beatOfThisNote = timeValues[i]; | |
CurrentButton.ResetFade(); | |
} | |
} | |
} | |
//Updates the Dancer and establishes | |
public bool AssignNewBeatDisplay(GameObject newBeatDisplay) { | |
dancerToSpawnOver = newBeatDisplay; | |
//Catch state if newBeatDisplay hasn't been established and disables the current BeatNotes | |
if (newBeatDisplay == null) { | |
for (int i = 0; i < NoteDisplay.Length; i++) { | |
NoteDisplay[i].GetComponent<ButtonNote>().currentColor[3] = 0; | |
} | |
return false; | |
} | |
//Update NoteDisplay with the objects that hold ButtonNotes | |
NoteDisplay = new GameObject[dancerToSpawnOver.transform.childCount]; | |
for (int i = 0; i < NoteDisplay.Length; i++) { | |
NoteDisplay[i] = dancerToSpawnOver.transform.GetChild(i).gameObject; | |
} | |
SpawnNewMove(notes, keyPresses); | |
return true; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System.Collections; | |
using System.Collections.Generic; | |
using UnityEngine; | |
public class CircleNote : MonoBehaviour { | |
[HideInInspector] public PlayerDanceLogic danceLogic; | |
[HideInInspector] public AudioTest controller; | |
[HideInInspector] public float beatOfThisNote; | |
[HideInInspector] public float audioDelay; | |
[HideInInspector] public float sizeBeforeKill = 0; | |
[HideInInspector] public bool givenInput = false; | |
float numBeatsToDeath; | |
bool hasCrossed = false; | |
//Initialization | |
void Start() { | |
numBeatsToDeath = controller.numBeatsToCross * (sizeBeforeKill - 1) / (1 - 3); | |
gameObject.transform.localRotation = Quaternion.identity; | |
} | |
// Update is called once per frame | |
void Update() { | |
//Shrinks to the edge of the target | |
if (!hasCrossed) { | |
transform.localScale = Vector2.Lerp( | |
new Vector3(3, 3, 3), | |
new Vector3(1, 1, 1), | |
(controller.songPosInBeats - audioDelay - beatOfThisNote + controller.numBeatsToCross) / controller.numBeatsToCross); | |
//When it reaches the edge of the target, update hasCrossed to true | |
if ((controller.songPosInBeats - audioDelay - beatOfThisNote + controller.numBeatsToCross) / controller.numBeatsToCross >= 1) { | |
hasCrossed = true; | |
} | |
} | |
//Shrinks past the edge of the target | |
else { | |
transform.localScale = Vector2.Lerp( | |
new Vector3(1, 1, 1), | |
new Vector3(sizeBeforeKill, sizeBeforeKill, sizeBeforeKill), | |
(controller.songPosInBeats - audioDelay - beatOfThisNote) / numBeatsToDeath); | |
//When done, destroy this object and remove references to itself | |
if ((controller.songPosInBeats - audioDelay - beatOfThisNote) / numBeatsToDeath >= .5f) { | |
danceLogic.notesOnScreen.RemoveAt(0); | |
Destroy(gameObject); | |
} | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System.Collections; | |
using System.Collections.Generic; | |
using UnityEngine; | |
public class PlayerDanceLogic : MonoBehaviour { | |
[HideInInspector] public enum HitType { DEFAULT, PERFECT_HIT, OKAY_HIT, MISSED, SHOT_MISS } | |
[HideInInspector] public List<CircleNote> notesOnScreen = new List<CircleNote>(); | |
[HideInInspector] public AudioSource boop; | |
[HideInInspector] public HitType hitType; | |
[HideInInspector] public int numCirclesCrossed; | |
[HideInInspector] public int numSequencesCompleted; | |
[HideInInspector] public bool successfulHit; | |
[HideInInspector] public bool showLabel; | |
[HideInInspector] public KeyCode nextCorrectKeyPress; | |
public float audioDelay = 0.23f; | |
public float audioDelaySD = 0.1f; | |
public Sprite[] feedBackResults; | |
public Texture2D[] shotResults; | |
public GameObject noteToSpawn; | |
KeyCode[] possibleKeyInputs; | |
StealthMeter sneakyLevel; | |
AudioTest songInformation; | |
int nextIndex = 0; | |
//Initialization | |
void Start() { | |
possibleKeyInputs = new KeyCode[] { KeyCode.Alpha1, KeyCode.Alpha2, KeyCode.Alpha3, KeyCode.Alpha4 }; | |
songInformation = FindObjectOfType<AudioTest>(); | |
sneakyLevel = FindObjectOfType<StealthMeter>(); | |
boop = GetComponent<AudioSource>(); | |
hitType = HitType.DEFAULT; | |
successfulHit = false; | |
showLabel = false; | |
numCirclesCrossed = 0; | |
numSequencesCompleted = 0; | |
} | |
// Update is called once per frame | |
void Update() { | |
showLabel = false; | |
//Checks to see if a CircleNote Needs to be spawned | |
if (songInformation.dancerToSpawnOver != null && nextIndex < songInformation.NoteDisplay.Length && nextIndex < songInformation.notes.Length && | |
songInformation.notes[nextIndex] < songInformation.songPosInBeats + songInformation.numBeatsToCross) { | |
//instantiate the CircleNote | |
GameObject note = Instantiate(noteToSpawn, songInformation.NoteDisplay[nextIndex].transform.position, Quaternion.identity, songInformation.dancerToSpawnOver.transform); | |
//initializes the CircleNote fields | |
CircleNote noteAttributes = note.GetComponent<CircleNote>(); | |
noteAttributes.danceLogic = gameObject.GetComponent<PlayerDanceLogic>(); | |
noteAttributes.controller = songInformation; | |
noteAttributes.beatOfThisNote = songInformation.notes[nextIndex]; | |
noteAttributes.audioDelay = audioDelay; | |
notesOnScreen.Add(noteAttributes); | |
note.transform.localRotation = Quaternion.identity; | |
songInformation.NoteDisplay[nextIndex].GetComponent<ButtonNote>().tracker = noteAttributes; | |
nextIndex++; | |
} | |
//At the end of each measure, randomly create the next sequence of ButtonNotes for the player | |
if (songInformation.songPosInBeats > songInformation.notes[songInformation.notes.Length - 1] + 1f && songInformation.dancerToSpawnOver != null) { | |
CreateNewMoves(0); | |
numSequencesCompleted++; | |
} | |
//Reset SuccessfulHit and showLabel | |
successfulHit = false; | |
showLabel = true; | |
//Reset the value of numCirclesCrossed | |
if (numCirclesCrossed >= songInformation.keyPresses.Length) { | |
numCirclesCrossed -= songInformation.keyPresses.Length; | |
showLabel = false; | |
} | |
} | |
//Passes the information of the result to the stealth meter | |
public float SuccessfulHit(PlayerDanceLogic.HitType typeOfHit) { | |
return sneakyLevel.SuccessfulHit(typeOfHit); | |
} | |
//Create a new set of information to create correct ButtonNotes | |
public bool CreateNewMoves(double startingBeatOfNewSet) { | |
//Randomly choose the correct inputs | |
KeyCode[] newMove = new KeyCode[4]; | |
for (int i = 0; i < newMove.Length; i++) { | |
newMove[i] = possibleKeyInputs[Random.Range(0, possibleKeyInputs.Length)]; | |
} | |
//Select the correct beat to have the input on | |
float[] newPos = new float[4]; | |
for (int i = 0; i < newPos.Length; i++) { | |
//normalizes the input values to the next measure | |
newPos[i] = Mathf.Ceil(songInformation.songPosInBeats / 4) * 4 + i + 8; | |
} | |
//Create the Button Notes with these inputs and song positions | |
songInformation.SpawnNewMove(newPos, newMove); | |
nextIndex = 0; | |
//Clear any old extraneous data | |
for (int i = 0; i < notesOnScreen.Count; i++) { | |
if (notesOnScreen[i].gameObject != null) { | |
Destroy(notesOnScreen[i].gameObject); | |
} | |
} | |
notesOnScreen.Clear(); | |
return true; | |
} | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment