If I test my game in Unity and I respawn I get my 3 lifes back.
But when I build the game, and I respawn I only get 2 lifes back.
Here is my code (not the full code) that I used for the respawning:
public int StarterLives; // 3
public GameObject plr; // My Player
public float maxVoidDist; // -10
public Object respawnLevel; // Level01 (My first and only asset)
public Text LivesHolder; // The text object (UI)
private Vector3 respawnPoint; // This gets updated in Start() and becomes the first position of the player
private string deadLevel; // This gets updated in Start() and becomes the name of my respawnlevel
private int lives; // This gets updated in Start() and becomes StarterLives (3)
private bool delay1 = false;
void Update () {
if ((plr.transform.position.y <= maxVoidDist) && (delay1.Equals(false)))
{
delay1 = true;
if((lives - 1) <= 0)
{
Application.LoadLevel(deadLevel);
lives = StarterLives + 1;
} else
{
plr.transform.position = respawnPoint;
}
lives = lives - 1;
updateLives();
delay1 = false;
}
}
void updateLives()
{
LivesHolder.text = "Lives: " + lives;
}
Full code:
using UnityEngine;
using System.Collections;
using UnityEngine.UI;
public class GameController : MonoBehaviour {
public int StarterLives;
public GameObject plr;
public float maxVoidDist;
public Object respawnLevel;
public Text LivesHolder;
private Vector3 respawnPoint;
private string deadLevel;
private int lives;
private bool delay1 = false;
void Awake()
{
QualitySettings.vSyncCount = 1;
}
// Use this for initialization
void Start () {
respawnPoint = plr.transform.position;
deadLevel = respawnLevel.name;
lives = StarterLives;
updateLives();
}
// Update is called once per frame
void Update () {
if ((plr.transform.position.y <= maxVoidDist) && (delay1.Equals(false)))
{
delay1 = true;
if((lives - 1) <= 0)
{
Application.LoadLevel(deadLevel);
lives = StarterLives + 1;
} else
{
plr.transform.position = respawnPoint;
}
lives = lives - 1;
updateLives();
delay1 = false;
}
}
void updateLives()
{
LivesHolder.text = "Lives: " + lives;
}
}
I see some strange things, in your code, I hope they can represent the issue:
1)
if((lives - 1) <= 0)
With this test, if you have 1 life remaining, you would restart the level. Is it what you want?
2)
Application.LoadLevel(deadLevel);
lives = StarterLives + 1;
In this snippet, the second line is useless because, as soon as you invoke LoadLevel(), the new scene is loaded and the rest of your code is not executed. So, lives = StarterLives + 1; is dead code.
3) Regarding the second point, let's suppose that the order of those lines is inverted (so, they are in the "right" order). It seems that you're trying to update some values in order to have them as the level restarts. But I can't see a DontDestroyOnLoad in your code, so values' preservation is useless.
Hope this helps!
Related
hi im trying to make a system where a variable controls the position of an object so that if the variable goes up then the Y position of the object will go up and if the variable goes down then the Y position of the object will go down.
I am trying to control the variable from a separate script but the value of the variable is not changing.
the variable script:
public class Money : MonoBehaviour {
public static float Flow;
public static float FlowPos;
// Use this for initialization
void Start () {
Flow = 50;
}
// Update is called once per frame
void Update () {
FlowPos = Flow/100;
print(Flow);
transform.position = new Vector3(10.56f,12 + FlowPos,1);
}
the script trying to change the variable:
using UnityEngine;
using System.Collections;
public class Barista01 : MonoBehaviour {
bool dragging = false;
bool CardActive = true;
void Start(){
}
void Update(){
if (transform.position.x > 11.5f && dragging == false){
GameControllerScript.Active = false;
this.Destroy(gameObject);
}
else if (transform.position.x < 4.5f && dragging == false){
GameControllerScript.Active = false;
Worker.Morale += 20;
Money.Flow -= 15;
this.Destroy(gameObject);
}
if (GameControllerScript.CardCall == 2 && CardActive == true){
CardActive = false;
Worker.Morale -= 20;
transform.position = new Vector3(8f, 6.89f, 9f);
}
}
void OnMouseDown(){
{
dragging = true;
}
}
void OnMouseUp(){
{
dragging = false;
}
}
}
edit: I put the plus, minus and eaquals symbols in the correct positions however the variables still do not change
You should correct these two lines:
Worker.Morale =+ 20;
Money.Flow =- 15;
to
Worker.Morale += 20;
Money.Flow -= 15;
I have a SceneController that's supposed to initialize a set of empty GameObject spawners, each working together at the same rhythm. The RockSpawners receive an array of time delays and wait the X seconds between spawning another rock.
I set the _nextSpawn = float.maxValue when the spawners start and plan to overwrite this after "Initializing" them (my own method), however even though my debug logs say I've overwritten my _nextSpawn value while initializing, the update loop is still reporting float.maxValue and nothing ends up spawning because _timeSinceLastSpawn hasn't exceeded float.maxValue seconds.
Is there something I'm missing with the scope of my _nextSpawn variables? It doesn't seem to be a "this" vs "local" issue, at least at first glance.
Debug output: 0 0 3 3. 0's stay the same, 3's will vary based on rng.
SceneController.cs:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class SceneController : MonoBehaviour {
[SerializeField] private GameObject _rockSpawnerPrefab;
public int numRocks = 6;
public int minSpawnDelaySec = 1;
public int maxSpawnDelaySec = 3;
private bool spawnersInitialized = false;
void Start () {
InitializeSpawners();
}
void Update () {
}
void InitializeSpawners() {
float[] pattern = new float[numRocks];
for (int i = 0; i < numRocks; i++) {
// Generate delays at half second increments within bounds
float delay = Mathf.Floor(Random.value * ((float)(maxSpawnDelaySec + 0.5f - minSpawnDelaySec) / 0.5f));
delay = delay * 0.5f + minSpawnDelaySec;
pattern[i] = delay;
}
GameObject spawner = Instantiate(_rockSpawnerPrefab) as GameObject;
spawner.transform.position = new Vector3(0, 4, 0);
RockSpawner rockSpawnerScript = spawner.GetComponent<RockSpawner>();
rockSpawnerScript.Initialize(pattern);
}
}
RockSpawner.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class RockSpawner : MonoBehaviour {
[SerializeField] private GameObject _rockPrefab;
public float minSpawnDelay = 3f;
public float maxSpawnDelay = 6f;
private float[] _pattern;
private int _currentPattern;
private float _timeSinceLastSpawn;
private float _nextSpawn;
void Start () {
_currentPattern = -1;
_nextSpawn = float.MaxValue;
}
void Update () {
if (_pattern == null) return;
_timeSinceLastSpawn += Time.deltaTime;
if (_timeSinceLastSpawn > _nextSpawn) {
GameObject rock = Instantiate(_rockPrefab) as GameObject;
rock.transform.position = transform.position;
NextTimer();
}
}
public void Initialize(float[] pattern) {
_pattern = pattern;
NextTimer();
}
private void NextTimer() {
_timeSinceLastSpawn = 0;
_currentPattern += 1;
Debug.Log(_nextSpawn);
Debug.Log(this._nextSpawn);
this._nextSpawn = _pattern[_currentPattern];
Debug.Log(_nextSpawn);
Debug.Log(this._nextSpawn);
}
}
It's not about scoping, it's about call order. When you create a GameObject its Start method is called on the frame it's enabled, not when the object is created. So your code will call Initialize first, then Start which overwrites the values.
Remove the code in Start and handle everything in Initialize and it should work as you want.
I am trying to set a Slider value through C# code.
I have a Main.scene which includes a slider called Slider.
The main camera has a game manager script attached to it.
The slider is not Interactable (so I can display the value but the user can't change it).
I defined a variable:
[SerializeField] private Slider sliderObj;
and put my slider in the inspector in this field
I have a float s variable that I want to reflect in the slider:
s = player1Time / (player1Time + player2Time) * 100.0f;
but when I write:
sliderObj.value = s;
I see this error:
'Slider' does not contain a definition for 'value' and no extension method 'value' accepting a first argument of type 'Slider' could be found (are you missing a using directive or an assembly reference?) [Assembly-CSharp]
any ideas?
Here is the entire script:
using UnityEngine;
using System.Collections;
using UnityEngine.UI;
public class GameManager : MonoBehaviour
{
public static GameManager instance = null; //this is to create a singleton => only one instance of this script running in memory
//so we only have one Game Manager running on memory
private int activePlayer = 1; //1 = down position 2 = up position
[SerializeField]
private GameObject playerObj;
[SerializeField]
private Text timer1Text; //player1 timer text
[SerializeField]
private Text timer2Text; //player2 timer text
[SerializeField]
private GameObject startBtn;
[SerializeField]
private Texture stopTexture;
[SerializeField]
private Slider sliderObj;
private Slider sli;
public float sli_val;
private RawImage img;
private float startTime;
private bool player1Active = true;
private static float player1Time;
private static float lastP1Time;
private static float player2Time;
private static float lastP2Time;
private bool gameOver = false;
private bool gameStarted = false;
private bool gameFinished = false;
void Awake()
{
if (instance == null)
{ //check if an instance of Game Manager is created
instance = this; //if not create one
}
else if (instance != this)
{
Destroy(gameObject); //if already exists destroy the new one trying to be created
}
DontDestroyOnLoad(gameObject); //Unity function allows a game object to persist between scenes
}
public bool GameStarted
{
get { return gameStarted; }
}
public bool GameOver
{
get { return gameOver; }
}
public void StartGame()
{
if (!gameStarted)
{
gameStarted = true;
//startTime = Time.time;
//player1Time = startTime;
player1Active = true;
//select start button
img = (RawImage)startBtn.GetComponent<RawImage>();
//replace it with stop button
img.texture = (Texture)stopTexture;
}
else
{
gameStarted = false;
gameOver = true;
}
Debug.Log("StartGame");
}
public void ChangePlayer()
{
float ty = 0f;
int smileyRotate = 180;
int sliderRotate = 180;
Quaternion smileyRotation = playerObj.transform.localRotation;
ty = playerObj.transform.position.y * -1;
if (activePlayer == 1)
{
player1Active = false;
activePlayer = 2;
smileyRotate = 180;
}
else
{
player1Active = true;
activePlayer = 1;
smileyRotate = 0;
}
playerObj.transform.position = new Vector2(playerObj.transform.position.x, ty);
smileyRotation.x = smileyRotate;
playerObj.transform.localRotation = smileyRotation;
}
// Use this for initialization
void Start()
{
}
// Update is called once per frame
private string FormatTime(float pt)
{
string hours, minutes, seconds, shaon;
hours = ((int)pt / 3600).ToString("00");
minutes = ((int)pt / 60).ToString("00");
seconds = (pt % 60).ToString("00");
if ((pt / 3600) > 1)
{
shaon = string.Format("{0:D1}:{1:D2}:{2:D2}", hours, minutes, seconds);
}
else
{
shaon = string.Format("{0:D2}:{1:D2}", minutes, seconds);
}
return shaon;
}
void Update()
{
float s;
GameObject sl1 = GameObject.Find("Slider");
if (GameStarted)
{
string zman;
if (player1Active)
{
player1Time += Time.deltaTime; //if player 1 active update his time
zman = FormatTime(player1Time);
timer1Text.text = zman;
//Debug.Log("player2Time: : "+ player2Time);
}
else
{
player2Time += Time.deltaTime; //if player 2 active update his time
zman = FormatTime(player2Time);
timer2Text.text = zman;
Debug.Log("player1Time: : " + player1Time);
}
s = player1Time / (player1Time + player2Time) * 100.0f;
//sliderObj.GetComponent<Slider>;
//sliderObj.=0.5f;
sli = GameObject.Find("Slider").GetComponent<Slider>();
sli.value = s;
sliderObj.value = s;
}
}
}
First of all, thanks for all your help.
Specially to bpgeck that chat with me and help me a lot.
Also Programmer was correct.
The main problem I had was the fatal error of calling the script attached to my slider Slider (I am still a noob, but learning)
I deleted that script and created a new one called Slider Percentage, in it I use the update function to change the value of the slider:
GameObject temp;
// Use this for initialization
void Start () {
temp = GameObject.Find("Slider");
}
// Update is called once per frame
void Update () {
temp.GetComponent<Slider>().value = GameManager.instance.GetPercentage;
}
The percentage value is still being calculated in the GameManager, but it is displayed using this script.
Now all works!! Thanks again for all your help :-)
Right now I have the script set to switch scenes when the players health gets low. I want is the die animation to play first than scene load after twenty-eight seconds . I am going to trigger the die animation . The die animation clip is 26.0 . The load scene the going to be gameover scene . The gameover scene needs to load 28.0 or 29.0 . Somewhere around their . Here is my code :
using UnityEngine;
using System.Collections;
using UnityEngine.UI;
using UnityEngine.SceneManagement;
[System.Serializable]
[RequireComponent(typeof(SpriteDatabase))]
public class Healthbar : MonoBehaviour {
public int fontSize;
public static int playersHealth;
public int health;
int healthNormalized;
GameObject player;
Image frame;
Image bar;
public int displayCritical;
public int displayRedBar;
public int displayYellowBar;
public string healthMessage;
public string criticalMessage = "Critical";
public string playerTag;
Text Message;
Text Critical;
public bool showHealthValue;
public bool showCritical;
public string sceneToLoad = "T";
SpriteDatabase sd;
public Theme chosenTheme;
public FontNames chosenFont;
int myTheme;
int myFontTheme;
public enum Positioning {
TopLeft,
TopRight,
BottomLeft,
BottomRight
}
[HideInInspector]
public bool alive = true;
//For demo purposes, store player's initial transform (so later it can be respawned there)
Vector3 startPos;
//used to choose between left or right alignment
public Positioning positioning;
//On Start, assign SpriteDatabse class to 'sd'. (Note: That class can never be missing due to the dependency system)
//It then runs Debugger() (find it below.) It checks whether the required sprites are assigned in the inspector, etc.
//Then, it builds hierarchy for GUI (find below)
void Start(){
sd = GetComponent<SpriteDatabase>();
fontSize = Mathf.Clamp(fontSize, 5, 30);
Debugger();
BuildHierarchy();
startPos = player.transform.position;
}
//Converts health integer to float value and updates it every frame.
//Keeps the GUI bar (image) fill amount value synchronized with the health value.
//Note: healthNormalized cuts the number so that it's on a 100 scale like in every game (it's basically the percentage)
void FixedUpdate(){
if (player) {
if (alive) {
/*
if (healthNormalized <= 0) {
alive = false;
die();
}
*/
healthNormalized = health/10;
//Converts health value to a float (range 0-1) so it can be used for image.fillamount
float healthValue = health * 0.001f;
healthValue = Mathf.Clamp(healthValue, 0, 1);
//Checks if it's time to turn the bar color to red or yellow (replace the sprite basically)
CheckForBarColor();
bar.fillAmount = healthValue;
}
DisplayText();
}
else
player = GameObject.FindGameObjectWithTag("Player");
}
void DisplayText(){
if (showHealthValue)
Message.text = healthMessage + ": " + healthNormalized.ToString();
if (healthNormalized <= displayCritical && alive && showCritical) {
Critical.enabled = true;
}
else
Critical.enabled = false;
}
//Called by every object affecting player's health.
//Class that calls it: ApplyDamage
//See that for more info on how to use it!
public void ModifyHealth(int amount) {
if (alive)
health = health - amount;
if (health <= 0) {
Debug.Log("1: sceneToLoad = " + sceneToLoad);
if ((sceneToLoad != "") && (SceneManager.GetSceneByName(sceneToLoad) != null)) {
Debug.Log("2: sceneToLoad = " + sceneToLoad);
SceneManager.LoadScene(sceneToLoad);
}
}
else {
health = Mathf.Clamp(health, 0, 1000);
}
}
}
Put SceneManager.LoadScene(sceneToLoad); in another function then call that function with Invoke("myfunction",25);. It will wait 25 seconds then call myfunction which will then load your scene by calling SceneManager.LoadScene(sceneToLoad);.
You can also start a coroutine and wait with yield return new WaitForSeconds(25f); then execute SceneManager.LoadScene.
As for your code, replace the ModifyHealth function with the function below:
public void ModifyHealth(int amount)
{
if (alive)
health = health - amount;
if (health <= 0)
{
Debug.Log("1: sceneToLoad = " + sceneToLoad);
if ((sceneToLoad != "") && (SceneManager.GetSceneByName(sceneToLoad) != null))
{
Debug.Log("2: sceneToLoad = " + sceneToLoad);
//Play your animation
//Call loadNewScene after 25 seconds
Invoke("loadNewScene",25);
}
}
else
{
health = Mathf.Clamp(health, 0, 1000);
}
}
void loadNewScene()
{
SceneManager.LoadScene(sceneToLoad);
}
I have and script below that does the following:
The player starts with 3 hearts [0] if it suffers damage loses one heart and changes the texture to 2 hearts 1, if he wins one extra heart back to the texture [0] .. If you're having only one heart [ 2] and suffers an injury, the game ends.
This code works perfectly, but I would like to convert it to UI Canvas Image. How do I do this?
using UnityEngine;
using System.Collections;
public class Hearts : MonoBehaviour {
public Texture2D[]initialHeart;
private int hearts;
private int currentHearts;
// Use this for initialization
void Start () {
GetComponent<GUITexture>().texture = initialHeart[0];
hearts = initialHeart.Length;
}
// Update is called once per frame
void Update () {
}
public bool TakeHeart()
{
if (hearts < 0) {
return false;
}
if (currentHearts < (hearts - 1)) {
currentHearts += 1;
GetComponent<GUITexture> ().texture = initialHeart [currentHearts];
return true;
} else {
return false;
}
}
public bool AddHeart() {
if (currentHearts > 0) {
currentHearts -= 1;
GetComponent<GUITexture> ().texture = initialHeart [currentHearts];
return true;
} else {
return false;
}
}
}
Edit:
Look what is happening:
In the object inspector, HealthBar I put 3 hearts as image (first imagem attached). But when I go into the script and try to select the images to be changed according to the user's progress, is not allowed to use image, objects only (second imagem attached).
1.Change Texture2D to Sprite.
2.Then change GetComponent<GUITexture>().texture = initialHeart[0]; to GetComponent<Image>().sprite = initialHeart[0];
3.And the two GetComponent<GUITexture> ().texture = initialHeart [currentHearts]; to GetComponent<Image>().sprite = initialHeart[currentHearts];
Note: Doing GetComponent<GUITexture> ().texture and GetComponent<Image>().sprite is not good. If you need to access any component multiple times, you need to cache it. That means you do GetComponent<Image>() once and save it to variable. That variable you can now use many other times. I noticed this in your other questions/codes too and decided it's time to tell you that. Take a look at the code below to understand it more. Code not tested but it compiles.
using UnityEngine;
using System.Collections;
using UnityEngine.UI;
public class Hearts : MonoBehaviour
{
public Sprite[] initialHeart;
private int hearts;
private int currentHearts;
// Use this for initialization
//Used for chaching Image so that you won't be doing GetComponent<Image>(); each time
Image heartImage;
void Start()
{
//Cache the Image once so that you won't be doing GetComponent<Image>(); each time
heartImage = GetComponent<Image>();
heartImage.sprite = initialHeart[0];
hearts = initialHeart.Length;
}
// Update is called once per frame
void Update()
{
}
public bool TakeHeart()
{
if (hearts < 0)
{
return false;
}
if (currentHearts < (hearts - 1))
{
currentHearts += 1;
heartImage.sprite = initialHeart[currentHearts];
return true;
}
else
{
return false;
}
}
public bool AddHeart()
{
if (currentHearts > 0)
{
currentHearts -= 1;
heartImage.sprite = initialHeart[currentHearts];
return true;
}
else
{
return false;
}
}
}
EDIT: I change changed the initialHeart from Image to Sprite so that you can put Sprite directly. Don't forget to remove GUITexture from the GameObject this script will be attached to. Also make sure that the GameObject you are attaching this script to has an Image attached to it. If you don't, GetComponent<Image>(); will fail.