Summary
My player lives is not reseting to the default value when they start the game over or enter the next level. When I die once and then complete the first level. The 2nd lvl loads and I start out with 2 lives. When I die 3xs it loads the main menu and when I click on start button it starts me off with 1 life.
LayOut:
Unity Hierarchy LayOut
Goal:
To have the player lives reset to 3 when re/starting the game/next Level.
Expected Results:
When the player completes a level with 2 lives left. The next level should load displaying that the player has 3 lives.
Actual Results:
When the player completes a level with 2 lives left. The next level displays that the player has 2 lives instead of 3.
Error Messages:
NONE
What I Tried
I am lost this is my first time creating a game. Where a player has multiple lives.
SpaceShip CODE:
public void completeSequence()
{
player = playerState.Transcending;
SFX.Stop();
SFX.PlayOneShot(completed);
death.Stop();
victory.Play();
Invoke("loadNextLevel", lvlLoadDelay);
}
public void resetLvl()
{
//print("Dead");
player = playerState.Dying;
SFX.Stop();
SFX.PlayOneShot(dead);
death.Play();
Invoke("loadCurrentSccene", lvlLoadDelay);
}
public void deadSequence()
{
//print("Dead");
player = playerState.Dying;
SFX.Stop();
SFX.PlayOneShot(dead);
death.Play();
Invoke("loadMainLevel", lvlLoadDelay);
}
public void loadCurrentSccene()
{
var currentScene = SceneManager.GetActiveScene().buildIndex;
SceneManager.LoadScene(currentScene);
}
public void loadMainLevel()
{
SceneManager.LoadScene(0);
}
public void loadNextLevel()
{
int currentScene = SceneManager.GetActiveScene().buildIndex;
//print(currentScene);
int nextScene = currentScene +1;
SceneManager.LoadScene(nextScene);
}
public void loadPreviousLevel()
{
int currentScene = SceneManager.GetActiveScene().buildIndex;
int nextScene = currentScene -1;
SceneManager.LoadScene(nextScene);
}
}
GameSession Code:
{
[SerializeField] int playerLives = 3;
[SerializeField] Text livesText;
private void Awake()
{
int numSessions = FindObjectsOfType<gameSession>().Length;
if (numSessions > 1)
{
Debug.Log("I am the NOT Original");
Destroy(gameObject);
}
else
{
Debug.Log("I am the Original");
DontDestroyOnLoad(gameObject);
}
}
// Start is called before the first frame update
void Start()
{
livesText.text = playerLives.ToString();
}
public void initiateDeath()
{
if (playerLives > 1)
{
reduceLives();
}
else
{
FindObjectOfType<spaceShip>().deadSequence();
}
}
public void reduceLives()
{
playerLives--;
FindObjectOfType<spaceShip>().resetLvl();
livesText.text = playerLives.ToString();
}
}
Currently, playerLives is being initialized to 3, and reduced by one whenever reduceLives() is called. None of your code sets playerLives back to 3, so when you enter a new level or call deadSequence() the lives stay at their previous value.
Adding a reset method to GameSession and calling this whenever you want to set the playerLives back to 3 (so presumably inside of both deadSequence() and completeSequence()) will fix this issue.
public void ResetLives()
{
playerLives = 3;
livesText.text = playerLives.ToString();
}
Related
I have an issue I'd appreciate help with. I'm trying to create game manager script that simply dictates if I have 5 objective game objects, the player is only allowed to complete them from the smallest (the smallest available objective will be indicated by the game manager) and it becomes a foul if he attempts the 2nd objective if the first is still there.
public class gameobjects : MonoBehaviour {
// Use this for initialization
int ballsLeft = 0;
bool PocketedAllBalls = false;
void Start () {
ballsLeft = 10; // or more;
}
// Update is called once per frame
void Update () {
GameObject[] balls = GameObject.FindGameObjectsWithTag("balls");
ballsLeft = balls.Length;
if(Input.GetKeyDown(KeyCode.A))
{
ballsLeft --;
}
if(ballsLeft == 0)
{
endGame();
}
}
void endGame()
{
PocketedAllBalls = true;
}
void OnGUI()
{
if(PocketedAllBalls)
{
GUI.Label(new Rect (0,0,200,20),"all gone");
}
else
{
GUI.Label(new Rect (0,0,200,20),"Balls Remaining : " + ballsLeft);
}
}
}
I have made 2 codes to manage my interstitial ads by making the ads show every 5 mins when the player losses but the problem is that I tried to reset them when the player passes the 5 mins and press the button when he losses but it didn't work so how to reset the timer when the player presses the button?
this is the 1st code :
public int LastShownIntTime = 300;
void Start()
{
#if UNITY_ANDROID
Advertisement.Initialize(androidID);
#endif
}
public void Update()
{
LastShownIntTime = PlayerPrefs.GetInt("LastShownIntTime");
}
public void showInterstitial()
{
if (LastShownIntTime <=0)
{
showInterstitialwith5mint();
}
}
public void showInterstitialwith5mint()
{
Advertisement.Show("video");
PlayerPrefs.SetInt("LastShownIntTime", 300);
}
and the 2nd one :
public float LastShownIntTimefloat;
public int LastShownIntTime = 300;
void Start()
{
LastShownIntTime = PlayerPrefs.GetInt("LastShownIntTime");
LastShownIntTimefloat = LastShownIntTime;
}
public void Update()
{
LastShownIntTimefloat -= Time.deltaTime;
LastShownIntTime = (int)LastShownIntTimefloat;
PlayerPrefs.SetInt("LastShownIntTime", LastShownIntTime);
}
}
The main issue here:
You would have to reset the LastShownIntTimefloat in your script2!
Otherwise you simply continue overwriting it with new values reducing the value more and write it back to PlayerPrefs
ā the next time your script1 polls the value it is not reset but already overwritten by script2!
In general: You should not use PlayerPrefs in order to make two components communicate!
In your case here I wouldn't even separate the logic and bother with implementing the communication between them but rather merge them into one single component.
Then it is not necessary to read and write PlayerPrefs every frame but rather only on certain checkpoints like
Read once in Start
Write once in OnApplicationQuit
Write once in OnDestroy (This is for the case you e.g. switch Scene but don't quit the app)
Write once ever time your user loses (showInterstitial is called)
Write once when resetting the value after showing the advertisement
I would also simply directly use a float and GetFloat and SetFloat instead of converting it from and to an int.
public class MergedClass : MonoBehaviour
{
// Rather sue a FLOAT for time!
public float LastShownTime = 300;
void Start()
{
#if UNITY_ANDROID
Advertisement.Initialize(androidID);
#endif
// use 300 as default value if no PlayerPrefs found
LastShownTime = PlayerPrefs.GetFloat("LastShownTime", 300f);
}
public void Update()
{
if(LastShownTime > 0f) LastShownTime -= Time.deltaTime;
}
public void showInterstitial()
{
PlayerPrefs.SetFloat("LastShownTime", LastShownTime);
PlayerPrefs.Save();
if (LastShownTime <= 0f)
{
showInterstitialwith5mint();
}
}
public void showInterstitialwith5mint()
{
#if UNITY_ANDROID
Advertisement.Show("video");
#else
LastShownTime = 300f;
PlayerPrefs.SetFloat("LastShownTime", LastShownTime);
PlayerPrefs.Save();
}
private void OnApplicationQuit()
{
PlayerPrefs.SetFloat("LastShownTime", LastShownTime);
PlayerPrefs.Save();
}
private void OnDestroy()
{
PlayerPrefs.SetFloat("LastShownTime", LastShownTime);
PlayerPrefs.Save();
}
}
I am working on 2D game.
When player collides with BOMBPrefab lose 1 heart (initial 3 heart), if collides 3 times = GameOver.
Thats is the code (works fine for BombPrefab):
using UnityEngine;
using System.Collections;
public class Heart : MonoBehaviour {
public Texture2D[] initialHeart;
private int heart;
private int many;
// Use this for initialization
void Start () {
GetComponent<GUITexture>().texture = initialHeart[0];
heart = initialHeart.Length;
}
// Update is called once per frame
void Update () {}
public bool TakeHeart()
{
if (heart < 0) {
return false;
}
if (many < (heart - 1)) {
many += 1;
GetComponent<GUITexture> ().texture = initialHeart [many];
return true;
} else {
return false;
}
}
}
I have a second HeartPrefab, I want to check when player collides... IF I have 3 hearts do nothing, IF have 1 or 2 hearts ADD extra heart.
BombPrefab Scrip:
using UnityEngine;
using System.Collections;
public class Bomb : MonoBehaviour
{
public AudioClip clipBomba;
private Heart heart;
private Gerenciador gerenciador;
void Awake ()
{
}
// Use this for initialization
void Start ()
{
gerenciador = FindObjectOfType (typeof(Gerenciador)) as Gerenciador;
}
// Update is called once per frame
void Update ()
{
}
void OnCollisionEnter2D (Collision2D colisor)
{
if (colisor.gameObject.tag == "floor") {
Destroy (gameObject, 2f);
} else {
if (colisor.gameObject.tag == "Bee") {
Som();
heart= GameObject.FindGameObjectWithTag ("Heart").GetComponent<Vidas> () as Vidas;
if (heart.TakeHeart ()) {
Destroy (gameObject);
} else {
gerenciador.GameOver ("GameOver");
}
}
}
}
void Som()
{
GetComponent<AudioSource> ().clip = clipBomb;
AudioSource.PlayClipAtPoint (clipBomb, transform.position);
}
}
First of all try not use GetComponent<>() in update and functions that are run often. It is better to cache components in Start() method. Using FindGameObjectWith...() is also not very efficient.
I would make it differently, each heart as a separate UI element (Toggle), with two states active and inactive. Then your player should have a list of those hearts and methods that allow to take damage and gain life.
int currentHeartsCount = 3;
int maxHeartsCount = 3;
List<Heart> hearts = new List<Heart>();
public void TakeDamage(int damage) {
ChangeHearts(-damage);
}
public void GainLife(int life) {
ChangeHearts(life);
}
private void ChangeHearts(int amount) {
currentHeartsCount += amount;
if(currentHeartsCount> maxHeartsCount)
currentHeartsCount = maxHeartsCount;
if(currentHeartsCount<=0) {
// call player dead code
}
int i = 1;
foreach(Heart heart in hearts) {
heart.SetHeartActive(i<=currentHeartsCount);
i++;
}
}
This is a simplified solution to give you an idea. It is more robust than yours because you can easily change start heart count, and make things like heart "overcharge". Just add base hearts, set max to desired value, and now you can create some special power ups which increase hearts over the initial limit.
What I've done so far is set a score to increase by each second in gameplay, get the score to show within the game scene and then set the highscore to be equal to the score if the score is greater than the highscore. This is my code so far:
bool gameOver;
public Text scoreText;
public Text highScoreText;
int score;
int highScore;
// Use this for initialization
void Start () {
score = 0;
highScore = 0;
InvokeRepeating ("scoreUpdate", 1.0f, 1.0f);
gameOver = false;
}
// Update is called once per frame
void Update () {
scoreText.text = "ā
" + score;
highScoreText.text = "ā
" + highScore;
}
public void gameOverActivated() {
gameOver = true;
if (score > highScore) {
highScore = score;
}
PlayerPrefs.SetInt("score", score);
PlayerPrefs.Save();
PlayerPrefs.SetInt("highScore", highScore);
PlayerPrefs.Save();
}
void scoreUpdate() {
if (!gameOver) {
score += 1;
}} }
"game over" is equal to true when this code happens:
void OnCollisionEnter2D (Collision2D col) {
if (col.gameObject.tag == "enemyPlanet") {
ui.gameOverActivated ();
Destroy (gameObject);
Application.LoadLevel ("gameOverScene2");
}
}
What I want is at this point (when the objects collide and game over is true) for the score to be saved, then the game over scene is loaded. How do I save the score at game over, then load it in the game over scene along with a saved highscore??
There are multiple ways you can do this, two of the most obvious ways to do it if you are only persisting the score for that session is to store it in a Static Class or a Singleton. These classes will persist for however long you need them to, regardless of scene loading, so be careful how you manage the information in them.
One example of a static class implementation would be:
public static class HighScoreManager
{
public static int HighScore { get; private set; }
public static void UpdateHighScore(int value)
{
HighScore = value;
}
}
If you are looking to persist the data for a longer amount of time you will need to look at this
I hope this helps!
Iām trying every possible solution, but have a look at this. The points are shown, and the high score too, but the high score is always the same as the score. When I restart the game, the score is not 0, but same the as the high score. If you got 6 points as a high score, the score is also 6 points. I hope you get it.
I took a screenshot. It just started and I didn't hit any enemy. the score should be 0, but is the same as the high score.
This is health script that is attached to the enemy:
using UnityEngine;
public class HealthScript : MonoBehaviour
{
public static HealthScript instance;
public int hp = 1;
private GUIText scoreReference;
private GUIText highscoreReference;
private static int _highscore = -1;
public int highscore {
get { if (_highscore == -1)
_highscore = PlayerPrefs.GetInt("Highscore", 0);
return _highscore;
}
set {
if (value > _highscore) {
_highscore = value;
highscoreReference.text = _highscore.ToString();
PlayerPrefs.SetInt("Highscore", _highscore);
}
}
}
public bool isEnemy = true;
private static int points;
public void Damage(int damageCount) {
hp -= damageCount;
if (hp <= 0)
{
// Dead!
Destroy(gameObject);
points++;
scoreReference.text = points.ToString();
}
}
public void gameEnd() {
points = highscore;
points = 0;
}
//update from previous code
void Start()
{
scoreReference = GameObject.Find("Score").guiText;
highscoreReference = GameObject.Find("HighScore").guiText;
scoreReference.text = points.ToString();
highscoreReference.text = highscore.ToString ();
instance = this;
}
and this is my player script where the gameover method in this class
void OnDestroy()
{
// Game Over.
// Add the script to the parent because the current game
// object is likely going to be destroyed immediately.
transform.parent.gameObject.AddComponent ();
HealthScript.instance.gameEnd ();
}
THE PROBLEM SOLVED. JUST CHANGE THIS "points = highscore;" TO "highscore = points;". I DON'T KNOW BUT DOES IT MATTER TO BE LIKE THAT? I HOPE SOMEONE CAN EXPLAIN THAT.
It looks like you have a duplicate here.
scoreReference = GameObject.Find("Score").guiText;
highscoreReference = GameObject.Find("HighScore").guiText;
scoreReference.text = points.ToString(); //KEEP THIS
highscoreReference.text = highscore.ToString();
scoreReference = GameObject.Find("Score").guiText;
scoreReference.text = highscore.ToString(); //REMOVE THIS - THIS IS A DUPLICATE