Quick question about restarting levels on fail - c#

I got a quick question for you. I have already everything prepared. I am making a simple launching game, where you need to kill all enemies (not time-based) to pass to the next level. I have 2 methods GoToNextLevel() and AllMonsterDied(); .
Need to make something like player have 3 attempts (3 launchings whenever he wants not based on time).
Then every launch checks if any monster left. If does just show 1 attemps less. After 3 times just restart scene.
Thanks a lot since I am new to both c# and unity that would mean the world to me.
public class LevelController: MonoBehaviour
{
[SerializeField] string _nextLevelName;
Monster[] _monsters;
void OnEnable()
{
_monsters = FindObjectsOfType<Monster>();
}
void Update()
{
int currentLevel = SceneManager.GetActiveScene().buildIndex;
if (currentLevel >= PlayerPrefs.GetInt("levelsUnlocked"))
{
PlayerPrefs.SetInt("levelsUnlocked", currentLevel + 1);
}
if (MonsterAreAllDead() )
{
GoToNextLevel();
}
Debug.Log("Level" + PlayerPrefs.GetInt("levelsUnlocked") + "UNLOCKED");
}
void GoToNextLevel()
{
Debug.Log("Go to next level" + _nextLevelName);
SceneManager.LoadScene(_nextLevelName);
}
bool MonsterAreAllDead()
{
foreach (var monster in _monsters)
{
if (monster.gameObject.activeSelf)
return false;
}
return true;
}
}
Line from Monster.cs
private void OnCollisionEnter2D(Collision2D collision)
{
if (SouldDieFromCollision(collision))
{
tickSource.Play();
StartCoroutine(Die());
}
}
IEnumerator Die()
{
_hasDied =true;
GetComponent<SpriteRenderer>().sprite=_deadsprite;
_particleSystem.Play();
yield return new WaitForSeconds(1);
gameObject.SetActive(false);
}

Let's say you want the next level launch attempt happen when the player hits N key on the keyboard.
When the player hits the key, check if all monsters are dead. If so, call GoToNextLeve(), otherwise take off 1 attempt from the attempts available and restart the current scene.
int attempts;
void OnEnable()
{
attempts = 3;
}
void Update()
{
if (Input.GetKeyUp(KeyCode.H)
{
TryGoToNextLevel();
}
}
void TryGoToNextLevel()
{
if (MonsterAreAllDead() )
{
GoToNextLevel();
}
else
{
attempts--;
}
if (attempts <= 0)
{
SceneManager.LoadScene(
SceneManager.GetActiveScene().name);
}
}

Related

Unity- Load - Unlock levels and check if there are next levels existing

I am working on small game similar to angry birds since I am new to both unity
and C#. I want to make load and unlock next level if all enemies are dead and check if new level exist
(if not) return back to Level selection scene.
This is what I tried:
LevelScript
using UnityEngine;
using UnityEngine.SceneManagement;
public class LevelScript : MonoBehaviour
{
[SerializeField] string _nextLevelName;
Monster[] _monsters;
void OnEnable()
{
_monsters = FindObjectsOfType<Monster>();
}
private void Update()
{
int currentLevel = SceneManager.GetActiveScene().buildIndex ;
if (currentLevel >= PlayerPrefs.GetInt("levelsUnlocked"))
{
PlayerPrefs.SetInt("levelsUnlocked", currentLevel );
}
if (MonsterAreAllDead())
{
GoToNextLevel();
}
Debug.Log("Level" + PlayerPrefs.GetInt("levelsUnlocked") + "UNLOCKED");
}
public void Pass()
{
int currentLevel = SceneManager.GetActiveScene().buildIndex;
if (currentLevel >= PlayerPrefs.GetInt("levelsUnlocked") )
{
PlayerPrefs.SetInt("levelsUnlocked", currentLevel + 1);
};
}
bool MonsterAreAllDead()
{
foreach (var monster in _monsters)
{
if (monster.gameObject.activeSelf)
return false;
}
return true;
}
void GoToNextLevel()
{
Debug.Log("Go to next level" + _nextLevelName);
SceneManager.LoadScene(_nextLevelName);
}
}
and Level Manager
public class LevelManager : MonoBehaviour
{
int levelsUnlocked;
public Button[] buttons;
void Start()
{
levelsUnlocked = PlayerPrefs.GetInt("levelsUnlocked", 1);
for (int i = 0; i < buttons.Length; i++)
{
buttons[i].interactable = false;
}
for (int i = 0; i < levelsUnlocked; i++)
{
buttons[i].interactable = true;
}
}
public void LoadLevel(int levelIndex)
{
SceneManager.LoadScene(levelIndex);
}
I got these 2 scripts and I attached both canvas and my buttons and Level script to my levels.
Problem is that every level gets unlocked at begin and after completeing levels automatically
it want to go to next level whic is not exist yet.
Pls help me. Sorry if my question is stupid and for bad english.
You should make an array of scene in your LevelManager that know all your levels (in order)
and for getting next level you can get the position of your actual scene in the array and check the next one.
somethink like
pseudocode :
[Serialized]
Scene[] AllScenes
void GoToNextLevel()
{
int currentLevelPos = AllScenes.IndexOf(currentScene);
if (AllScenes[currentLevelPos + 1] != null)
Load Next Level
else
Go To Level Menu
}

How do I increase a score and print it in the console?

I'm still trying to finish off my very simple game but I've ran into another problem.
I want the Console to print ("Player's score") everytime the ball touches the sidewalls. So i created a new script and called it ScoreManager that should take care of this function. But the only thing the console does is print (0). this is the code.
void Update()
{
//boundaries
if (Ball.transform.position.x < -5.61f)
{
RightScore++;
print(RightScore);
}
if (Ball.transform.position.x > 5.5f)
{
LeftScore++;
print(LeftScore);
}
}
RightScore and LeftScore are not defined. If you define them, it should work:
private int RightScore = 0;
private int LeftScore = 0;
void Update()
{
//boundaries
if (Ball.transform.position.x < -5.61f)
{
RightScore++;
print(RightScore);
}
if (Ball.transform.position.x > 5.5f)
{
LeftScore++;
print(LeftScore);
}
}

Score reset on Reload

I know that there are many similar questions but none of them seem to be quite the same as mine. I have a score that increments by one every time an object is destroyed and that works fine but I want to reset it to 0 when I reload the scene... For some reason it won't reset, everything else works fine.
variables:
public Text Score;
public static int counter;
public Transform obstacle;
public GameObject Obstacle;
code to increment when the object is destroyed:
void Update()
{
if (Obstacle.transform.position.z <= -5)
{
DestroyObstacle(Obstacle);
}
Score.text = (counter / 3).ToString();
}
void DestroyObstacle(GameObject Obstacle)
{
Destroy(Obstacle);
counter++;
}
}
The following code stops everything and brings up a button. When that button is clicked, it reloads the level as you can see, yet the score does not reset:
public void OnCollisionEnter(Collision collision)
{
if (collision.collider.tag == "Obstacle")
{
movement.enabled = false;
Spawner.enabled = false;
PlayButton.enabled = true;
PlayText.enabled = true;
PlayButton.onClick.AddListener(TaskOnClick);
}
}
void TaskOnClick()
{
Score.text = 0.ToString();
SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex);
}
I know that it is probably something simple but I would really appreciate the help.
Also! For some reason, if my counter is not a static int, the score will not increase? That's why it is static.
Because counter is static, it won't reset.
It won't increment if it is not because the object with the incremented value is destroyed.
You need another script that will have the counter variable and will increment it when an object is destroyed.
Replace the line
counter++;
by
Camera.main.GetComponent<ScoreCounter>().Increase();
And do another class (something like that) and add the script on your camera :
public class ScoreCounter : MonoBehaviour
{
public int counter;
public Text Score;
public void Increase()
{
counter++;
Score.text = (counter / 3).ToString();
}
}
It's because counter is static, and as such it belongs to the class and not the object. It won't reset unless there's a hard restart. Adding counter = 0 as the first line in your TaskOnClick would do it, or changing counter to not be static and be a member of the object.

Dialogue keeps being stuck at last sentence

I made a dialogue script so that I can display sentences on different NPC's.
I also have added a continue button so it goes from sentence to sentence.
The problem is that for some reason the last dialog gets stuck and keeps replaying if I interact after all sentences have played.
What I want is to replay all sentences that I added onto the NPC.
I also wanted to ask if there was a way to NOT use the continue button? And let the text type itself out after a certain amount of time. Like a real conversation.
As you can see I added the lines on the right
The first line printed
The second line printed
The third line printed
Starts placing the last line back to back every time I interact UNLESS I click the Button, because then it clears. But it still replays the last sentence every time instead of reverting back to the 1st.
Dialogue Script
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
[System.Serializable]
public class Dialogue2 : MonoBehaviour
{
public GameObject dialogBox; // Attach ui image to this
public Text npcname; // Attach UI text gameObject
public Text dialogText; // Attach UI text gameObject
public string NPC; // What is he/she called?
public string[] sentences;
public bool playerInRange; // Is the Player in range?
public float typingSpeed;
private int index;
public GameObject continueButton;
public AudioSource SignUpSfx;
public AudioSource SignDownSfx;
void Update()
{
if(dialogText.text == sentences[index]){
continueButton.SetActive(true);
}
// Player in range and E is hit
if(Input.GetKeyDown(KeyCode.E) && playerInRange)
{
if(dialogBox.activeInHierarchy)
{
dialogBox.SetActive(false);
SignDownSfx.Play();
}
else
{
dialogBox.SetActive(true);
StopAllCoroutines();
StartCoroutine(Type());
npcname.text = NPC;
SignUpSfx.Play();
}
}
}
private void OnTriggerEnter2D(Collider2D other)
{
if(other.CompareTag("Entity"))
{
playerInRange = true;
}
}
private void OnTriggerExit2D(Collider2D other)
{
if(other.CompareTag("Entity") && dialogBox.activeInHierarchy == true)
{
SignDownSfx.Play();
}
if(other.CompareTag("Entity"))
{
playerInRange = false;
dialogBox.SetActive(false);
}
}
IEnumerator Type(){
foreach(char letter in sentences[index].ToCharArray()){
dialogText.text += letter;
yield return new WaitForSeconds(typingSpeed);
}
}
public void NextSentence(){
continueButton.SetActive(false);
if(index < sentences.Length - 1){
index++;
dialogText.text = "";
StartCoroutine(Type());
} else {
dialogText.text = "";
continueButton.SetActive(false);
}
}
}
Couldn't you just change:
if(index < sentences.Length - 1){
index++;
dialogText.text = "";
StartCoroutine(Type());
} else {
dialogText.text = "";
continueButton.SetActive(false);
}
To this?
if(index < sentences.Length - 1){
index++;
dialogText.text = "";
StartCoroutine(Type());
} else {
dialogText.text = "";
continueButton.SetActive(false);
index = 0;
}

Unable to get coroutine to start and stop when button is down

I am working on the walking sounds for my game, I am wanting it to play a sound and then wait and play the next. As it is walking I only want it to do this when w is pressed. I have been trying to use an Enumerator to do so but I am having issues where it will not start the function.
private IEnumerator audioPlayCoroutine;
public AudioSource[] steps;
public AudioSource[] cabinSteps;
private bool running;
void Start()
{
running = false;
audioPlayCoroutine = AudioPlay();
}
void Update()
{
if (Input.GetKey("w"))
{
if (running == false)
{
running = true;
}
}
if (running == true)
{
StartCoroutine(audioPlayCoroutine);
}
else if (running == false)
{
StopCoroutine(audioPlayCoroutine);
}
}
IEnumerator AudioPlay()
{
int ran = Random.Range(0, 4);
steps[ran].Play();
yield return new WaitForSeconds(2);
}
Okay, there are multiple reasons why it doesn't work:
For one running is never set to false. Once your player pressed w once, it will stay true.
Instead write
if (Input.GetKey("w"))
running = true;
else
running = false;
Additionally you start and stop your Coroutine multiple times.
Instead you should either check, whether the running status either changed or you should just check running in your coroutine.
It could then look like this:
void Start() {
running = false;
audioPlayCoroutine = AudioPlay();
StartCoroutine(audioPlayCoroutine);
}
void Update() {
if (Input.GetKey("w"))
running = true;
else
running = false;
}
IEnumerator AudioPlay()
{
while (true) {
if(!running)
yield return new WaitForSeconds(0);
int ran = Random.Range(0, 4);
steps[ran].Play();
// if you want it to play continuously, you can use the clip length for
// the sleep. This way it will start playing the next clip right after
// this one is done. If you don't want that, go with your code
yield return new WaitForSeconds(steps[ran].clip.length);
}
}
If your clip is actually 2 seconds long, you might also want to interrupt it from playing once your user stops pressing the button.

Categories

Resources