How to stop a looped instanced sound in c# - c#

Well im trying to make a system which decides which car sound to play when i accelerate, keep driving, slow down and idle.
Pretty much what happens is it ignores my .stop command for my looped sounds and then creates another instance and dosn't stop the other. I have tried many different ways of declaring my instanced sound but it just moans about any other way.
SoundEffectInstance CarIdleLooped = CarIdle.CreateInstance();
CarIdleLooped.IsLooped = true;
CarIdleLooped.Volume = 0.2f;
SoundEffectInstance CarFastlooped = CarFastloop.CreateInstance();
CarFastlooped.IsLooped = true;
CarFastlooped.Volume = 0.6f;
if (pad_p1.Triggers.Right == 0 && CarIdling == false && CarIsDriving == false)
{
CarIdling = true;
CarIdleLooped.Play();
}
if (pad_p1.Triggers.Right > 0 && CarIdling == true)
{
CarIdling = false;
CarIdleLooped.Stop();
CarAccelerate.Play();
}

Related

(Unity, 2D, C#) How can I make the player let go of a button before needing to press it again?

This is a weirdly phrased question...and I don't know how to explain it well. I'm making a ledge hang mechanic for my game I'm making, you press either of the directions to get onto the ledge, but you also press the directions to get off of the ledge. This means while you're trying to get on the ledge, he instantly falls off. Making a fixed wait time also doesn't feel good...I'm thinking that it would set the axis to 0 until the button is let go, but the problem is that if it's 0, the button is let go. It's a conundrum I can't solve.
Here is the code that detects movements pressed on the left or right arrow keys.
mx = Input.GetAxisRaw("Horizontal");
//Detects if the left or right arrow keys are pressed, and turns it into a number.
Here's some of the code that detects movement while you're hanging There's already a problem...there's an "if hanging" statement right before that's supposed to restrict movement until you let go or jump, but since moving is supposed to ALSO get you out of the hanging, it makes this point moot. I could really just use different buttons, like restricting it to just the jump button or down key (since that uses a different variable), but I want to see if a solution is possible.
if (IsGrabbing == true)
{
rb.velocity = new Vector2(0f, 0f);
rb.gravityScale = 0f;
// mx2 detects vertical movement. This is still a problem, if you're pressing down before you hang, it'll instantly hang instead of waiting for another press, but it's not as bad because you don't press down to hang on a ledge
if (mx != 0 || mx2 < 0)
{
//Just the code that makes you let go and unable to hang, this is reset when you land.
IsGrabbing = false;
anim.SetBool("IsHanging", false);
redXSize = 10f;
redYSize = 10f;
greenXSize = 0f;
greenYSize = 0f;
rb.gravityScale = 5f;
}
I've tried many things, a lot of "while" loops I've tried just crash the game. Does anyone know how to fix this issue? I'll provide all the code if needed.
Edit: With the help of the reply, I've found the solution! There needs to be a flag set like this, where by default it's false. However, it also only checks if it's false, and the else statement means it's true, not to mention the only way to set it to true bypasses that gate anyways. This gives the result needed! Also, while "while" loops seem to break it, adding a condition to every check to not do it while grabbing seemed to fix it. Thanks, everyone!
if (IsGrabbing == true)
{
if (mx != 0 && InitiateGrab == false)
{
InitiateGrab = false;
}
else
{
InitiateGrab = true;
}
rb.velocity = new Vector2(0f, 0f);
rb.gravityScale = 0f;
if (mx != 0 && InitiateGrab == true || mx2 < 0 && InitiateGrab == true)
{
IsGrabbing = false;
InitiateGrab = false;
anim.SetBool("IsHanging", false);
anim.SetBool("IsRising", false);
redXSize = 10f;
redYSize = 10f;
greenXSize = 0f;
greenYSize = 0f;
rb.gravityScale = 5f;
}
}
Since you don't have the code. I can't exactly help you out with the specifics, but I still understand what you're asking and can still help you out. Here is the "sample" code that I'd use in your case:
bool isHanging = false;
void Update()
{
if (Input.GetKeyDown("space") && !isHanging)
{
isHanging = true;
// Use ur code to hang onto the ledge.
} else if (Input.GetKeyDown("space") && !isHanging)
{
isHanging = false;
// Use ur code to get off the ledge.
}
}
bool CheckIfHanging()
{
if(isHanging) { return false; }
else return true;
}
Essentially, this causes a toggle effect where when you press the spacebar AND are close enough to the ledge, you set the bool to true, and you hang onto the ledge and went you want to get off it, you set the isHanging to false, and run your code to jump off the ledge. This does have the effect of making ur controls a toggle control however. If you're looking for a "press" control, where you hold onto a key to hold onto the ledge, and then let go when you press off, then maybe try this:
void Update()
{
if (Input.GetKeyDown("space"))
{
// Hang onto ledge
} else if (Input.GetKeyUp("space"))
{
// Let go of ledge.
}
}
Hope I could help!
(P.S. please put ur code in next time so that I can help you out more!)
Quick update on my answer since u posted ur code. Maybe try changing ur movement code to something like this
bool isHanging = false;
int speed; [SerializeField]
void MoveCharacter()
{
if (isHanging) return;
else mx = speed * Input.GetAxisRaw("Horizontal");
}
Essentially, this still allows you to move with your arrow keys, but will essentially stop your movement code if you're hanging. Also from ur previous comment, you said that you apparently can't use Input.GetKeyDown/Up for your left/right arrows? I'd recommend using KeyCode if that's the case, that should have the input for all btns in ur keyboard.
bool HangLedge()
{
if (!isHanging && Input.GetKeyDown(KeyCode.DownArrow)) return true;
else if (!isHanging && Input.GetKeyDown(KeyCode.DownArrow)) return false;
}
// Set ur ledge code and movement code to take this bool, and run the code when it's either false/true.
Hope I could clarify!

Snake Program stops running without exception

I am trying to program snake in console. After a random amount of steps the snake takes, a new GameObject spawns (e.g. an apple that makes the snake grow or a mushroom which makes the snake faster).
I create a random gameObject (on random (left, top) coordinates and then I need to check if that gameObject spawns on top of a snakeBodyPart or on top of another gameObject. If that is the case, I create a new gameObject and try the same again. Only if it doesn´t collide with another gameObject or the Snake, it will spawn.
snakeElemnts = a list, which has all the snake- body-parts;
gameObjects = a list with all existing gameObjects;
If the noCollisionAmount == the amount of snakeElements and GameObjects, there should be no collision and the new GameObject should spawn.
Unfortunately at one point (early on), the snake just stops moving and nothing happens (no exception or anything).
I can´t debug because I have a KeyboardWatcher running, which checks if a key gets pressed. Therefore when I press break, I can only examine the keyboardwatcher.
Setting a breakpoint is not useful, because I never break when the problem arises.
if (this.randomStepNumber == 0)
{
int noCollision = 0; // this variable counts the amount of times there was no collision
GameObject validGameObject;
while (true)
{
validGameObject = this.snakeGameObjectFactory.Generate();
foreach (SnakeElements element in snakeElements)
{
if (validGameObject.XPosition != element.XPosition || validGameObject.YPosition != element.YPosition)
{
noCollision++;
}
else
{
break;
}
}
foreach (GameObject gameObject in gameObjects)
{
if (noCollision == snakeElements.Count) // if there was no collision of the new gameobject with an element of the snake, the gameobjects will get checked
{
if (validGameObject.XPosition != gameObject.XPosition || validGameObject.YPosition != gameObject.YPosition)
{
noCollision++;
}
else
{
break;
}
}
else
{
break;
}
}
if (noCollision == snakeElements.Count + gameObjects.Count) // if there was no collision at all, the check is ended
{
break;
}
else
{
noCollision = 0;
}
}
this.gameObjects.Add(validGameObject);
this.randomStepNumber = this.random.Next(10, 30);
}
Based on your comments that removing this block of code causes the problem to cease, I thought maybe it would be good to clean up the code a little and remove that potential infinite loop with the continue statement. Making use of a little LINQ Enumerable.Any and a do-while loop, we can simplify the logic of the above code. There isn't really a need to be counting collisions, since the purpose of the code is to create a new object iff a collision is detected. That means if we detect a collision with the snake, then we want to generate a new object, or if we detect a collision with another existing object, then we want to generate a new object. So instead of counting, we use the Any statement to check if there is any collision with the snake or an existing object. If there is, then generate a new object. If not, then use that object and continue. Note: In order to use the Enumerable.Any you will need to add a using statement for the namespace System.Linq.
if (randomStepNumber == 0)
{
GameObject validGameObject;
do
{
validGameObject = snakeGameObjectFactory.Generate();
}
while(snakeElements.Any(s => validGameObject.XPosition == s.XPosition && validGameObject.YPosition == s.YPosition) ||
gameObjects.Any(o => validGameObject.XPosition == o.XPosition && validGameObject.YPosition == o.YPosition));
gameObjects.Add(validGameObject);
randomStepNumber = random.Next(10, 30);
}
As a side note. I removed the this keyword as it appeared you were not using it in all cases in your code, and if you do not have to use it, it makes the code a little more readable because it is less wordy. If it needs to be added back because of variable collisions, then I would suggest renaming the variables as having member and local variables with the same name can also be confusing when trying to debug something.
Secondary note - here is a version of the code not using LINQ, in case that is not allowed for your homework.
if (randomStepNumber == 0)
{
GameObject validGameObject = null;
while(validGameObject == null)
{
validGameObject = snakeGameObjectFactory.Generate();
foreach(var snake in snakeElements)
{
if (validGameObject.XPosition == snake.XPosition &&
validGameObject.YPosition == snake.YPosition)
{
validGameObject = null;
break;
}
}
if (validGameObject != null)
{
foreach(var gameObject in gameObjects)
{
if (validGameObject.XPosition == gameObject.XPosition &&
validGameObject.YPosition == gameObject.YPosition)
{
validGameObject = null;
break;
}
}
}
}
gameObjects.Add(validGameObject);
randomStepNumber = random.Next(10, 30);
}
I think you may not understand how "continue" works.
if (noCollision > snakeElements.Count + gameObjects.Count)
{
continue;
}
you have that at the beginning of a while loop. If it's found true you will be stuck in an infinite loop.
secondly, you have a While(true) in there that will never let you save a valid result since it's outside the loop. You should replace the while with a do while and check for a valid result at the end of it, then loop if there was a collision.

Disable a script when another script is active

So I have got two scene change scripts, both which are attached to two different game objects. But for some reason, one script affects both game objects. So I am trying to temporarily disable one of the scripts when the other script is active on the other game object. Here is what I have but this is returning the error, "BasketballSceneChange' is a type, which is not valid in the given context".
**GameObject.Find("pPrism1").GetComponent(BasketballSceneChange).enabled = false;**
{
if (Input.GetMouseButtonDown(0) && SceneManager.GetActiveScene().name == "MWalk")
{
SceneManager.LoadScene("BWalk");
}
if (Input.GetMouseButton(0) && SceneManager.GetActiveScene().name == "BWalk")
{
SceneManager.LoadScene("Basketball");
}
if (Input.GetMouseButton(0) && SceneManager.GetActiveScene().name == "Football")
{
SceneManager.LoadScene("SWalk");
}
if (Input.GetMouseButton(0) && SceneManager.GetActiveScene().name == "SWalk")
{
SceneManager.LoadScene("MWalk");
}
}
}
Change this:
GameObject.Find("pPrism1").GetComponent(BasketballSceneChange).enabled = false;
to
var myVariable = GetComponent(BasketballSceneChange) as myBaseClass;
myVariable.enabled = false;
change myBaseClass to class which shows your Scene.
You could avoid using GetComponent just declaring a public variable and assigning it from the inspector.
public AnotherScript theOtherScript;
void Update()
{
if(theOtherScript != null && theOtherScript.enabled)
{
theOtherScript.enabled = false;
}
}
Check this Tutorial
Other way is Finding the gameobject and geting the component as you did.
I've read your code again and I found the error that doesn't compile the line:
GameObject.Find("pPrism1").GetComponent(BasketballSceneChange).enabled = false;
should be
GameObject.Find("pPrism1").GetComponent<BasketballSceneChange>().enabled = false;

If-else statement for changing levels

I have a got a function for changing levels in my game. In the game, the first level changes to the second level correctly. But the second level changes to the first level too, then count = 4. How can I fix this? Here is my code:
public void CheckLevelCompletion() {
if ((count == 4) && (levelOneCompleted == false)) {
img.sprite = levelCompletedImage;
count = 0;
levelOneCompleted = true;
SceneManager.LoadScene("FifthGameSecondLevel");
}
else if ((count == 6) && (levelOneCompleted == true))
{
img.sprite = levelCompletedImage;
count = 0;
levelTwoCompleted = true;
SceneManager.LoadScene("FifthGameThirdLevel");
}
}
I don't know your code steps, but maybe it is this situation, I think.
If scene reloaded, your game object in previous scene is destroyed.
So levelOneCompleted is always false.
It is why SceneManager.LoadScene("FifthGameThirdLevel"); does not run.
If it is right, I recommend levelOneCompleted make public and set true in second level game object.

Activating and deactivating game objects in unity

So below you will find a short snippet of code. What this code does is it allows the player to hit the 'p' key to pause the game and when this happens a gui pops up and the players look and movement controls are disabled. My problem is with deactivating and reactivating the gui because it is a game object. It lets me deactivate it but when I try to activate it I get an error.
Code:
UnityEngine.Component walkScriptOld = GameObject.FindWithTag ("Player").GetComponent ("CharacterMotor");
UnityEngine.Behaviour walkScript = (UnityEngine.Behaviour)walkScriptOld;
UnityEngine.GameObject guiMenu = GameObject.FindWithTag ("Canvas");
if ((Input.GetKey ("p")) && (stoppedMovement == true)) {
stoppedMovement = false;
walkScript.enabled = true;
guiMenu.SetActive(true);
} else if ((Input.GetKey ("p")) && (stoppedMovement == false)) {
stoppedMovement = true;
walkScript.enabled = false;
guiMenu.SetActive(false);
}
Error:
NullReferenceException: Object reference not set to an instance of an object MouseLook.Update () (at Assets/Standard Assets/Character Controllers/Sources/Scripts/MouseLook.cs:44)
It seems that the code you've given here is in an Update. So the guiMenu object is being found and stored every frame.
What you want to do is cache the object in the Awake or Start function, and the rest of the code will work just fine. Also note that caching is always good practice.
//This is the Awake () function, part of the Monobehaviour class
//You can put this in Start () also
UnityEngine.GameObject guiMenu;
void Awake () {
guiMenu = GameObject.FindWithTag ("Canvas");
}
// Same as your code
void Update () {
if ((Input.GetKey ("p")) && (stoppedMovement == true)) {
stoppedMovement = false;
walkScript.enabled = true;
guiMenu.SetActive(true);
} else if ((Input.GetKey ("p")) && (stoppedMovement == false)) {
stoppedMovement = true;
walkScript.enabled = false;
guiMenu.SetActive(false);
}
}

Categories

Resources