Quetzhal:
In your Update of the Noises you start a coroutine. This means you start this coroutine every frame. not good.
cadw96:
After looking at what you are requesting, I believe the answer is a bit simpler, and corresponds to what I was suggesting before. Though not in the same manor.
Assuming that you have a separate up and down heartbeat, you will need a timer that will play them in rhythm. So in working our that rhythm, I started tapping my fingers on the desk, bump, bump… bump bump… And I there is actually a rhythm there: bump bump off bump bump off. So timing can then be figured out mathematically that there are 3 phases to each beat. up down off, up down off.
we can use a generic timer to handle this. BMP, or Beats Per Minute. This says that the up beat should always happen every bmp / 60 seconds. Now, all we then have to do is multiply that out to divide it by 3. So, bmp / 60 * 0.333 is the time between the up beat and down beat, and bmp / 60 * 0.667 is the time between the down beat and the next up beat, so total it is bmp / 60 beats.
Rather than focusing on enemy vs player, I went the route of just a heart beat controller. Every bmp, it beats up, down, off.
Now, your script simply controls the controller with simple variables: BMP, Volume and Pitch. (yes, I left pitch in there because you may need it.)
using UnityEngine;
using System.Collections;
[RequireComponent (typeof (AudioSource))]
public class HeartBeat : MonoBehaviour {
public float bpm = 60;
public float volume = 1;
private float pitch = 1;
public AudioClip upBeat;
public AudioClip downBeat;
private AudioSource upBeatSource;
private AudioSource downBeatSource;
private float nextBeat = 0;
private bool beatSwap = false;
void Start(){
GameObject go = new GameObject ();
go.transform.position = transform.position;
go.transform.parent = transform;
upBeatSource = go.AddComponent<AudioSource> ();
upBeatSource.clip = upBeat;
upBeatSource.loop = false;
go = new GameObject ();
go.transform.position = transform.position;
go.transform.parent = transform;
downBeatSource = go.AddComponent<AudioSource> ();
downBeatSource.clip = downBeat;
downBeatSource.loop = false;
}
void Update(){
volume = Mathf.Clamp01 ((bpm - 80) / 100) * 6;
//pitch = Mathf.Clamp((bpm - 60) / 160, 0.9f, 1.1f);
if (Time.time > nextBeat) {
if(beatSwap){
upBeatSource.volume = volume;
upBeatSource.pitch = pitch;
upBeatSource.Stop();
upBeatSource.Play();
nextBeat+= 60 / bpm * 0.333f;
}else{
downBeatSource.volume = volume;
downBeatSource.pitch = pitch;
downBeatSource.Stop();
downBeatSource.Play();
nextBeat+= 60 / bpm * 0.667f;
}
beatSwap = !beatSwap;
}
}
}
Now all you have to do is change the variables in the controller to get whatever you need.
So now, all you have to do is concentrate on how you want that danger level thing to work. At rest, a human’s heartbeat is between 60 and 100 bpm. When we run we get up to about 150 or so normally, when we run fast, we get up to about 192. So that is a good range to start with.
Now, lets add this to an existing charcter controller. (I made this for another thread.) all I should have to do is add a line of code.
using UnityEngine;
using System.Collections;
[RequireComponent (typeof (CharacterController))]
[RequireComponent (typeof (HeartBeat))]
public class PlayerCharacterHeartBeat : MonoBehaviour {
// HeartBeat controller
private float defaultBMP = 60;
private float defaultChangeRate = 0.5f;
private float bpm = 60;
private float changeRate = 0.5f;
public Transform enemy;
private HeartBeat heartbeat;
// mouselook player character.
private float speed = 6;
private float lookSpeed = 2f;
public bool invertY = false;
private Vector3 movement;
private CharacterController controller;
// Use this for initialization
void Start () {
heartbeat = gameObject.GetComponent<HeartBeat> ();
Screen.lockCursor = true;
Screen.showCursor = false;
controller = gameObject.GetComponent<CharacterController> ();
}
// Update is called once per frame
void Update () {
movement = controller.velocity;
UpdateSmoothLook ();
UpdateSmoothControls ();
UpdateGravity ();
UpdateHeartBeat ();
controller.Move (movement * Time.deltaTime);
}
void UpdateHeartBeat(){
float targetBPM = defaultBMP;
float targetChangeRate = defaultChangeRate;
if (enemy) {
float threat = 1 - Mathf.Clamp01 ((enemy.position - transform.position).magnitude * 0.01f);
// add up to 75 bmp depending on how close enemy is to us.
targetChangeRate += threat;
targetBPM += threat * 75;
}
// run here is the Left Shift key.
// add 75 bmp for running.
if (Input.GetKey (KeyCode.LeftShift)){
targetBPM += 75;
}
// lerp these two values so we don't have instant changes.
changeRate = Mathf.Lerp (changeRate, targetChangeRate, 4 * Time.deltaTime);
bpm = Mathf.Lerp (bpm, targetBPM, changeRate * Time.deltaTime);
// let the controller do the work.
heartbeat.bpm = bpm;
}
void UpdateSmoothLook(){
Transform cam = Camera.main.transform;
Vector3 look = Vector3.zero;
look.x = -Input.GetAxis ("Mouse Y") * lookSpeed;
if (invertY) look.x = -look.x;
cam.Rotate (look) ;
}
void UpdateSmoothControls(){
Vector3 look = Vector3.zero;
look.y = Input.GetAxis ("Mouse X") * lookSpeed;
transform.Rotate (look);
Vector3 input = new Vector3(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical"));
input = transform.TransformDirection(input);
float spd = speed;
if (Input.GetKey (KeyCode.LeftShift)) spd *= 2;
input *= spd;
if (!controller.isGrounded) {
input *= Time.deltaTime * 2;
movement += input;
} else {
input.y = movement.y;
movement = input;
}
float y = movement.y;
movement.y = 0;
if (movement.magnitude > spd) movement = movement.normalized * spd;
movement.y = y;
}
void UpdateGravity(){
movement += Physics.gravity * 2 * Time.deltaTime;
if (controller.isGrounded Input.GetButtonDown ("Jump"))
movement -= Physics.gravity;
}
}
As you can see, the whole player controller simply calls methods to do the movement stuff, this makes it easier to read what the Update is doing. All I did then is to add a method to update the bmp.