[SOLVED] UI bar based off of a public float? C#

I have a flashlight component on my player character, and when the flashlight is on, the batterypercentage decreases over time. The battery percentage is is a public float in the code that is a value of 0 - 100. What I am wanting to do is take that value and display a UI bar that fills as charge goes up, and depletes as charge goes down.

Here is the Flashlight script. This script is on two lights that are children of the player object. The script allows for the flashlight to toggle on/off with the F key, causes the batteryPercentage to drain when the flashlight is on, dims the light as the battery drains, and plays a sound when the flashlight is turned on/off.

using UnityEngine;
using System.Collections;


[RequireComponent(typeof(Light), typeof(AudioSource))]
public class Flashlight : MonoBehaviour {

     public AudioClip click;
     public float batteryLifeInSec = 300f;
     public float batteryPercentage = 100;  //this value decreses when the light is on and increases when a battery object is picked up; this is what I am wanting to convert to a UI bar.


     public Light lite;

     private bool on;
     private float timer;

     voidStart()
          {
          lite = GetComponent<Light>();
           }     

     void Update()  //this part basically controls the on/off for the flashlight and controls the battery drain based on whether the light is on or off.
          {
          timer += Time.deltaTime;

          if(Input.GetKeyDown(KeyCode.F) && timer >= 0.3f && batteryPercentage > 0) {
          on = !on;
          GetComponent<AudioSource>().PlayOneShot(click);
          timer = 0;
           }
      
     if(on) 
          {
          lite.enabled = true;
          batteryPercentage -= Time.deltaTime * (100 / batteryLifeInSec);
           }
     else 
          {
          lite.enabled = false;
          }

      batteryPercentage = Mathf.Clamp(batteryPercentage, 0, 100);
//the following 21 "if" statements are just adjusting the intensity of the light based off of the batteryPercentage value.  

if(batteryPercentage == 0) {
lite.intensity = Mathf.Lerp(lite.intensity, 0, Time.deltaTime * 2);
 }

if(batteryPercentage > 0 && batteryPercentage < 5) {
lite.intensity = Mathf.Lerp(lite.intensity, 0.15f, Time.deltaTime);
 }

if(batteryPercentage > 5 && batteryPercentage < 10) {
lite.intensity = Mathf.Lerp(lite.intensity, 0.30f, Time.deltaTime);
 }

if(batteryPercentage > 10 && batteryPercentage < 15) {
lite.intensity = Mathf.Lerp(lite.intensity, 0.45f, Time.deltaTime);
 }

if(batteryPercentage > 15 && batteryPercentage < 20) {
lite.intensity = Mathf.Lerp(lite.intensity, 0.6f, Time.deltaTime);
 }

if(batteryPercentage > 20 && batteryPercentage < 25) {
lite.intensity = Mathf.Lerp(lite.intensity, 0.75f, Time.deltaTime);
 }

if(batteryPercentage > 25 && batteryPercentage < 30) {
lite.intensity = Mathf.Lerp(lite.intensity, 0.9f, Time.deltaTime);
 }

if(batteryPercentage > 30 && batteryPercentage < 35) {
lite.intensity = Mathf.Lerp(lite.intensity, 1.05f, Time.deltaTime);
 }

if(batteryPercentage > 35 && batteryPercentage < 40) {
lite.intensity = Mathf.Lerp(lite.intensity, 1.2f, Time.deltaTime);
 }

if(batteryPercentage > 40 && batteryPercentage < 45) {
lite.intensity = Mathf.Lerp(lite.intensity, 1.35f, Time.deltaTime);
 }

if(batteryPercentage > 45 && batteryPercentage < 50) {
lite.intensity = Mathf.Lerp(lite.intensity, 1.5f, Time.deltaTime);
 }

if(batteryPercentage > 50 && batteryPercentage < 55) {
lite.intensity = Mathf.Lerp(lite.intensity, 1.65f, Time.deltaTime);
 }

if(batteryPercentage > 55 && batteryPercentage < 60) {
lite.intensity = Mathf.Lerp(lite.intensity, 1.8f, Time.deltaTime);
 }

if(batteryPercentage > 60 && batteryPercentage < 65) {
lite.intensity = Mathf.Lerp(lite.intensity, 1.95f, Time.deltaTime);
 }

if(batteryPercentage > 65 && batteryPercentage < 70) {
lite.intensity = Mathf.Lerp(lite.intensity, 2.1f, Time.deltaTime);
 }

if(batteryPercentage > 70 && batteryPercentage < 75) {
lite.intensity = Mathf.Lerp(lite.intensity, 2.25f, Time.deltaTime);
 }

if(batteryPercentage > 75 && batteryPercentage <= 80) {
lite.intensity = Mathf.Lerp(lite.intensity, 2.4f, Time.deltaTime);
 }

if(batteryPercentage > 80 && batteryPercentage <= 85) {
lite.intensity = Mathf.Lerp(lite.intensity, 2.55f, Time.deltaTime);
 }

if(batteryPercentage > 85 && batteryPercentage <= 90) {
lite.intensity = Mathf.Lerp(lite.intensity, 2.7f, Time.deltaTime);
 }

if(batteryPercentage > 90 && batteryPercentage <= 95) {
lite.intensity = Mathf.Lerp(lite.intensity, 2.85f, Time.deltaTime);
 }

if(batteryPercentage > 95 && batteryPercentage <= 100) {
lite.intensity = Mathf.Lerp(lite.intensity, 3, Time.deltaTime);
 }
 }
}

The other component which interacts with this and give recharge is a battery object which you pick up by walking over with the player character. Including this in case it is needed to address the question or if anyone is interested in using this code snippet for their own projects. Keep in mind that I am very new to this so while I have made changes to these code snippets for use with my game, credit goes to people on these forums for the base code. Thanks in advance for anyone who is willing to help me figure this out. Learning every day thanks to this awesome community! (the following code goes on the battery object)

using UnityEngine;
using System.Collections;


     public class Battery : MonoBehaviour {


     voidStart()  //automatically assigns a sphere collider with trigger to the object
      {
          this.GetComponent<SphereCollider>().isTrigger = true;
      }

     void OnTriggerEnter(Collider other)  //check to see if object it is colliding with is tagged "Player", then looks to see if children of the player have a component named "Flashlight> and restores 50 batteryPercentage to each light that is a child of the player that has a Flashlight component.
      {
          if(other.gameObject.tag == "Player")
           {
               foreach (varflashlightinother.GetComponentsInChildren<Flashlight>())
                {
                    flashlight.batteryPercentage += 50;
                }
           }
      }
}

I also have this snippet on my character movement script. I’m not sure if this should be in a different place, but all it does is destroys (actually just turns SetActive to false) pick up objects on collision and plays a sound for the pick up.

   void OnTriggerEnter(Collider other)
     {
          if (other.gameObject.CompareTag("Pick Up"))
          {
               GetComponent<AudioSource>().PlayOneShot(collect);
               other.gameObject.SetActive (false);
           }
 }

So what you want to do is use the Slider component you will need a UI script that has a reference to the torchlight and in its update method it sets the sliders value to the percentage.

Have a go a writing the code yourself first but if you have any problems please ask.

P.S - Just looking at your torch code - while this not a big problem you seem to be enabling your light every frame that it is on, even if the user hasnt pressed the button that frame. It might make sense to put that code inside the input checking if statement, the battery calculation still needs to be in the same place though.

1 Like

You can use UI.Slider as a filling bar. Check out: https://unity3d.com/learn/tutorials/modules/beginner/ui/ui-slider

1 Like

Thank You, Korno. I’ll have a look at that link and see what I am able to come up with. I’ll post what I can figure out in a while.

As for the enabling light every frame, I’d love some more detail about that after I get the first part figured out. Again, I have only been learning code for about a week so every task is a learning opportunity at this point.

You don’t need a slider component. You can use a filled Image component - change the image type to Filled, and you can set image.fillAmount to anything between 0 and 1. (In fact, the slider component bases its filled background bit on this value, as well.

4 Likes

Wow! Three replies in under 20 minutes! I’m going to see what I can figure out. You guys rock. I’ll post what I come up with and the inevitable bumps in the road I encounter. :slight_smile:

Before I dive too deep in either direction, is there an advantage of the filled image or slider in this case?

This is is actually a better idea. I forgot about filled image. Although, you cant use sliced images if I remember correctly? If you are just using a red/blue bar though is fine.

The script will still be the same though.

Make a script that:

  • References the image component and torch

  • in its update method, convert the torch percentage into a value between 0-1 (devide by 100 - but careful about devide by zero when the torch is empty)

  • set that value to be filled percentage of the filled image

The slider includes extra pieces that you may or may not need, and you have to remember to disable its interactivity or the player will be able to cause visual glitches by dragging it. It’s just sort of overkill.

1 Like

The same applies to a Slider. Slider uses a filled Image - look at the way the GameObject and its children are set up. It’s subject to all the same inabilities and limitations.

Still, if you really want to use a ninesliced sprite there’s a bit of trickery to be had.

Actually, the default Slider created using the GameObject/UI/Slider option creates a slider that uses a sliced sprite.

1 Like

Oh, hmm. That must have changed at some point during the 4.6 beta. I could swear it used to use a filled sprite.

In any case: you can do this with a sliced sprite by using a Mask.

ObjectA

  • ObjectB

On ObjectA, have an Image that is a filled image (it can be anything). Also, a Mask component, with “Show Mask Graphic” unchecked.
On ObjectB, put your sliced sprite. You’ll probably want to set its RectTransform to stretch in all directions.

1 Like

So being that I am a complete novice at this, I’ve been watching tutorials on the unity site and youtube all day. I cannot for the life of me even figure out how to change the image type to filled. On most of the tutorials I see, there is a drop down menu on the component for the UI image, but no such option exists when I create an image. How do I accomplish this in Unity 5? everything I am finding is Unity 4.6.

Thanks again.

Anyone willing to help make this a bit more understandable for someone new to this? Unfortunately all sample code I can find is in Java and all of the UI bar tutorials I am finding online seem to be out of date. I am using Unity 5 so any help with this is of course appreciated. Once I understand a bit better how to implement this, it will transfer into several UI features I plan on including in the project.

The Code

Ok - first the code using a Slider. I dont want to get into the sliced image vs filled image debate again. The reason I used a slider is that it provides two images - a background color and a filled color for the current amount and is very quick to get working.

using UnityEngine;
using System.Collections;

// use the unity UI
using UnityEngine.UI;

// dont worry about this, its from my project
using Koneko.Lights;

public class TorchBatteryDisplay : MonoBehaviour {


    public Slider BatterySlider;
    public Torch TheTorch;


    // Use this for initialization
    void Start () {

    }

    // Update is called once per frame
    void Update () {
        BatterySlider.value = TheTorch.CurrentPower;
}
}

This is all it took for my batter slider to display the battery value.

My Torch class exposes a property CurrentPower - which is a percentage value of the current power - if I remember correctly, the torch class you are using has the same. The update mode just sets the sliders value property to this. The MaxValue property of the slider needs to be set to 100 too.

Edit: I just noticed the max value property, I guess if you set this to 100 then you dont have to normalise the number. Ok Updated code and description.

This is very simple, in the editor I just assign the TheTorch property and the Slider property.

Setting up the slider

So I added a Canvas to my scene - set to screen space overlay. Then I added a slider to this, for my project I positioned it in the top left corner but where is up to you.By default the Slider is interactable (i.e. you can move it) so I disabled this in the editor.

Next, I wanted the current amount of power to be blue so if you look at the slider game object you will find a few child objects. There should be one called FillArea, and that has a child called Fill. If you look at this you will find an Image component, modify this components color property to change the current amount color.

I left the background at white, because it looked fine for me, but if you want to modify the background part use the Image component on the Background child object.

(By the way, you can also modify the sprite used by the slider by modifying those images source image property but for a basic bar the default is fine)

On the Slider script (on the parent object) I set the transition to none - as the user cant interact with the slider. Then I also set the Handle rect transform property to none - again as it cant be interacted. Finally I disabled the Handle child game object as we are using it. Now, you might need to just stretch the FillArea bar a tiny bit as it might not completely cover the background (it assumes there was a Handle there)

Done! You will have a health bar style bar, that displays the battery power. The same approach works for health bars and you can probably make it generic enough to work with any values.

If you want a prefab or something or have any questions or want to know how to do the same with a filled image pleas just ask.

Also, I am sorry for all the typos I have probably made in this…

1 Like

This script will allow you to toggle a flashlight, restore, drain and create a texture that represents the energy of intensity. Just attach it to whatever component has a Light component attached.

using UnityEngine;
using System.Collections;

public class Flashlight : MonoBehaviour {

    public Light flashLight; //This will be a holder for the light
    public Texture2D LightBar; //Create a texture to act as your bar and drop into this
    public bool isEnabled; //This is to check if the light is on or off
    public float Restore; //This is the amount to Restore the light by
    public float Drain; //This is how much to drain the light by

    void Start() {
        flashLight = GetComponent<Light> ();
    }

    void Update() {
        if (isEnabled && flashLight.intensity > 0f) //If the light is enabled and intensity is over 0, drain
            flashLight.intensity -= Drain;

        if (!isEnabled && flashLight.intensity < 1f) //If the light is enabled and intensity is under 1, restore
            flashLight.intensity += Restore;

        if (Input.GetKey (KeyCode.E)) //If E is pressed
            isEnabled = !isEnabled; //Set isEnabled to the opposite value

        flashLight.enabled = isEnabled; //Set the flashlight to whatever value isEnabled is
    }

    void OnGUI() {
        GUI.DrawTexture (new Rect (0, 0,flashLight.intensity * 100, 50), LightBar); //Draw a texture in the top left corner
        //because we are multiplying by 100 if the value was 0.2f then it is equal to 20, this way you can scale to 100 pixels and not 0.2 pixels
    }
}

He was using the new UI. I dont think going back to the old UI is the best of ideas these days, right?

1 Like

He didn’t mention in his original post that he wanted Legacy or the new UI, I saw you mentioned to use a Slider which IMO would be a bad idea for what he requires. If he just wants to show the percentage using a Legacy Texture or even a UI Image would do perfectly fine.

Korno, thank you for taking the time. Here is what I have done so far. I have set up the slider per your suggestions, and attached the following code to the flashlight component which is a child on the player.

using UnityEngine;
using System.Collections;
using UnityEngine.UI;

public class BatteryDisplay : MonoBehaviour
{
       public Slider BatSlider;
     public Light Flashlight;

     void Start ()
     {
     }

     void Update ()
     {
     BatSlider.value = Flashlight.batteryPercentage;
     }
}

I am not sure if I am assigning this to the correct object, but the console is kicking back this error;
Assets/Scripts/BatteryDisplay.cs(18,46): error CS1061: Type UnityEngine.Light' does not contain a definition for batteryPercentage’ and no extension method batteryPercentage' of type UnityEngine.Light’ could be found (are you missing a using directive or an assembly reference?)

I have a public float “BatteryDisplay” on the Flashlight, which is the field that displays the current charge. Am I not referencing this correctly or do I need to do something like GetComponentsinChildren? There is an array of the Flashlight Script; there are two lights that are children of the player object which both use the Flashlight script.

Thank you again for all of your help! progress!