Reputation: 13
I am trying to call the AddFuel method from a different script but I am getting no error but my fuel wont update, the UI for the fuel kind of updates except it displays full fuel(even if the fuel shouldn't be full) but as soon as I expend fuel the fuel reverts to what it was minus the fuel that I expended.
How can I Solve this Problem?
RefuelPickup Script
void Collect()
{
PlayerController playerController =gameObject.AddComponent<PlayerController>();
float addFuel = .5f;
playerController.AddFuel(addFuel);
}
PlayerController Script
public void AddFuel(float value)
{
fuel += value;
UIController.SetFuel(fuel);
}
UIController Script
using UnityEngine;
using System.Collections;
public class UIController : MonoBehaviour {
private static UIController Instance { get; set; }
public UIRemaining remaining;
public UIFuel fuel;
public UIGameOver gameOver;
public UITimer timer;
/// <summary>
/// Update the UI to show the new number of remaining goals.
/// </summary>
/// <param name="value">The number of goals remaining.</param>
public static void SetRemaining(int value)
{
Instance.remaining.SetValue(value);
}
/// <summary>
/// Set the current value of the fuel bar
/// </summary>
/// <param name="value">A normalised value between 0 and 1, with 0 being empty and 1 being full.</param>
public static void SetFuel(float value)
{
Instance.fuel.SetValue (value);
}
/// <summary>
/// Update the game timer to display a new value
/// </summary>
/// <param name="gameTime">The time, in seconds, to display in the UI</param>
public static void SetTime(float gameTime)
{
Instance.timer.SetTime(gameTime);
}
/// <summary>
/// Display the game over screen with a custom message. This will not show any time information.
/// </summary>
/// <param name="message">The message to display on the game over screen.</param>
public static void GameOver(string message)
{
Instance.gameOver.Show (message);
}
/// <summary>
/// Display the game over screen with a custom message and time information.
/// </summary>
/// <param name="message">The message to display on the game over screen.</param>
/// <param name="time">The last time, in seconds, played in this level</param>
/// <param name="bestTime">The best time, in seconds, played in this level</param>
/// <param name="isNewHighscore">True if the best time is a new highscore, otherwise false.</param>
public static void GameOver(string message, float time, float bestTime, bool isNewHighscore)
{
Instance.gameOver.Show (message, time, bestTime, isNewHighscore);
}
public static void LoadUI()
{
if (Instance == null) {
Application.LoadLevelAdditive("UI");
}
}
void Awake()
{
Instance = this;
}
void OnDestroy()
{
Instance = null;
}
// Use this for initialization
void Start () {
}
}
UIFuel Script
using UnityEngine;
using UnityEngine.UI;
using System.Collections;
public class UIFuel : MonoBehaviour {
public Slider slider;
public void SetValue (float value)
{
slider.value = value;
}
// Use this for initialization
void Start () {
}
}
Upvotes: 0
Views: 128
Reputation: 3316
The line
PlayerController playerController=gameObject.AddComponent<PlayerController>();
creates a new PlayerController and attaches it. So, if you collect 20 time, you will end up with 20 PlayerControllers attached to your gameObject. My guess is that you attached one PlayerController earlier, and you want to get a reference to it instead of creating a new one. This is particularly bad if all 20 would compete to set the value of a slider indicating how much fuel is left. If so, use this instead:
PlayerController playerController=gameObject.GetComponent<PlayerController>();
Whenever you use GetComponent, you might want to test whether the object returned is null, and deal with that. So, you might follow it up with
if (playerController == null)
{
playerController = gameObject.AddComponent<PlayerController>();
}
This is similar to Gabriel Coutinho's answer, but here I preserved your use of playerController as a local variable. In addition, I used GetComponent. Using GetComponent can carry a slight performance hit, so you don't want to call this a lot of times every update. (You can use a public or private field so that you use GetComponent only once.) However, if you have already attached one PlayerController, say in the editor where you also set the initial amount of fuel, you want to use that one, and not create a second just because you don't yet have a reference to it. You want to avoid having two PlayerControllers with different ideas of how much fuel is left competing to set the value of the fuel indicator.
Upvotes: 1
Reputation: 81
On your RefuelPickup script you instantiate a new PlayerController component every time the Collect() Method is called. When a new PlayerController is instantiated, what is the starting value of the fuel property?
By looking at your code my guess would be that the PlayerController starts with the fuel at its maximum value. This would explain why the UIFuel slider value is always set to full on a new fuel collect. Everytime you call Collect a new PlayerController instance is created and the UIFuel is updated to display a full fuel value.
If the method you use to expend fuel is also on the PlayerController script, then it could be possible that you are always calling the expend method of the same PlayerController instance, probably the first one instatiated, thus setting the UIFuel slider value to the value it was before any collects minus the expended value.
If this is whats happening, the way to go is to avoid creating a new PlayerController everytime the Collect() method is called. Instead, try something like this on your RefuelPickup script:
private PlayerController playerController;
void Collect()
{
if(playerController == null)
{
PlayerController playerController = gameObject.AddComponent<PlayerController>();
}
playerController.AddFuel(.5f);
}
I had to make a lot of guesses but I hope this helps :)
Upvotes: 0