Alternative to movement.enabled = false;

I wasn’t a big fan of Rick’s method of disabling movement using “.enabled = false” because it ended up causing an annoying bug: if we’re currently thrusting when we crash the movement script is disabled but we never actually stop the thrusting audio so that keeps playing until the scene reloads.

I fixed this by instead adding a public method inside of the Movement class and using that to set a bool variable called PlayerHasControl. I could then use this variable to determine if we should be paying attention to the key(s) the player is pressing or if we should just turn off any audio.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Movement : MonoBehaviour {
	[Header("Rocket Control Speed")]
	[SerializeField] float MainThrust = 750f;
	[SerializeField] float RotationThrust = 100f;

	[Header("Sound Effects")]
	[SerializeField] AudioClip MainThruster = null;
	[SerializeField] AudioClip AuxiliaryThruster = null;

	bool PlayerHasControl = true;

	Rigidbody Rigidbody;
	RigidbodyConstraints RigidbodyConstraints;
	AudioSource AudioSourceMainThruster;
	AudioSource AudioSourceAuxiliaryThruster;

	// Start is called before the first frame update
	void Start() {
		Rigidbody = GetComponent<Rigidbody>();
		RigidbodyConstraints = Rigidbody.constraints;

		foreach (var audioSource in GetComponents<AudioSource>()) {
			if (AudioSourceMainThruster == null) {
				AudioSourceMainThruster = audioSource;
				AudioSourceMainThruster.clip = MainThruster;
			} else {
				AudioSourceAuxiliaryThruster = audioSource;
				AudioSourceAuxiliaryThruster.clip = AuxiliaryThruster;
			}
		}
	}

	// Update is called once per frame
	void Update() {
		if (PlayerHasControl) {
			ProcessInput();
		} else {
			if (AudioSourceMainThruster.isPlaying) {
				AudioSourceMainThruster.volume = 0f;
			}
			if (AudioSourceAuxiliaryThruster.isPlaying) {
				AudioSourceAuxiliaryThruster.volume = 0f;
			}
		}
	}

	void ProcessInput() {
		ProcessThrust();
		ProcessRotation();
	}

	private void ProcessThrust() {
		if (Input.GetKey(KeyCode.Space) || Input.GetKey(KeyCode.UpArrow) || Input.GetKey(KeyCode.W)) {
			Rigidbody.AddRelativeForce(Vector3.up * MainThrust * Time.deltaTime);
			AudioSourceMainThruster.volume = 1f;
			if (AudioSourceMainThruster.isPlaying == false) {
				AudioSourceMainThruster.Play();
			}
		} else {
			// Used instead of .Stop() to avoid clicking sound at the end
			AudioSourceMainThruster.volume = 0f;
		}
	}

	private void ProcessRotation() {
		if (Input.GetKey(KeyCode.A) || Input.GetKey(KeyCode.LeftArrow)) {
			ApplyRotation(RotationThrust);
			AudioSourceAuxiliaryThruster.volume = 1f;
			if (AudioSourceAuxiliaryThruster.isPlaying == false) {
				AudioSourceAuxiliaryThruster.Play();
			}
		} else if (Input.GetKey(KeyCode.D) || Input.GetKey(KeyCode.RightArrow)) {
			ApplyRotation(RotationThrust * -1);
			AudioSourceAuxiliaryThruster.volume = 1f;
			if (AudioSourceAuxiliaryThruster.isPlaying == false) {
				AudioSourceAuxiliaryThruster.Play();
			}
		} else {
			// Used instead of .Stop() to avoid clicking sound at the end
			AudioSourceAuxiliaryThruster.volume = 0f;
		}
	}

	private void ApplyRotation(float rotationThrust) {
		// Freeze physics based rotation
		Rigidbody.freezeRotation = true;
		transform.Rotate(Vector3.forward * rotationThrust * Time.deltaTime);
		// Re-enable physics based rotation
		Rigidbody.constraints = RigidbodyConstraints;
	}

	public void RemovePlayerControl() {
		PlayerHasControl = false;
	}
}

I’m really enjoying this class, moreso than the 2D one that I started multiple times and could never find the motivation to finish :sweat_smile: I know Rick always says we don’t have to do things exactly like him though, so I enjoy finding little things like this that can be tweaked easily enough without drastically changing the code (and therefore making it harder to follow along with future videos).

2 Likes

Good job. Instead of setting the audio volume to 0, you could just stop the audio altogether using
AudioSourceMainThruster.Stop() and AudioSourceAuxiliaryThruster.Stop()

2 Likes

I did that originally but it gave a weird clicking noise every time the audio was stopped and that annoyed me. Not sure if .Pause() would cause the same thing though, that could be something else to try.

Edit: Nope. Using .Pause() still adds a weird clicking noise to the end of the audio and I’m too easily annoyed to let that stand :slight_smile: Not sure if it’s an issue with my Unity, my audio files, or something else, but I don’t like it. Ideally I’d prefer to either use .Stop() or .Pause() because those would be much more useful in the future (say if someone was speaking and you wanted to pause the audio in the middle, play something else, and then continue that audio) but for now using .volume instead works okay.

1 Like

That pop is the audio clipping. Ideally, we’d have a bit of linear falloff to prevent that (and sound a bit more natural), but it sounds like you found a good workaround by just setting the volume to 0 directly, which is good to know!

And by linear falloff, I mean a function that would scale the current volume to 0 over a given time parameter–say, a quarter second. That’s a bit beyond this class, I think. It’s always surprised me Unity doesn’t have this method built-in, though.

Privacy & Terms