Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

charging flashlight

Discussion in 'Scripting' started by ghastlygibus, Aug 14, 2019.

  1. ghastlygibus

    ghastlygibus

    Joined:
    Aug 14, 2019
    Posts:
    8
    I've just installed unity editor a day ago and am messing around with a concept for a flashlight-based-puzzle-thingy, but I don't know c#. (I've picked up a bit of js but I don't remember most of it now lol)

    I'm trying to make a flashlight that turns off when you press LMB and turns back on when you release it which shouldn't be too hard to copy and edit from a youtube tutorial or something, but the main thing I'm trying to to do is have a function where if you hold RMB while holding LMB it will gradually increase the light's FOV, intensity and range capping at some specific number (making a point light on top of the flashlight blink upon reaching the cap, if at all possible) and releasing RMB makes the light turn on, lowering the values to normal after about 0.1 seconds.

    I have no idea how I would go about doing this, but I imagine something along the lines of "while buttonClick LMB+RMB, var "charge" +1"? eh, idk.
     
  2. LiterallyJeff

    LiterallyJeff

    Joined:
    Jan 21, 2015
    Posts:
    2,807
    ghastlygibus likes this.
  3. ghastlygibus

    ghastlygibus

    Joined:
    Aug 14, 2019
    Posts:
    8
  4. ghastlygibus

    ghastlygibus

    Joined:
    Aug 14, 2019
    Posts:
    8
    i have the GetKey programming set but how do i control the lights with it
     
  5. LiterallyJeff

    LiterallyJeff

    Joined:
    Jan 21, 2015
    Posts:
    2,807
    You use your "charge" variable to drive some properties on a light object each frame when it changes.

    Assuming you're using the "Light" component as a flashlight, you'll need to have a "Light" variable to hold a reference to the light you want to affect. You can define a public variable like
    public Light flashlight;
    which will show up in the inspector in Unity. Then you can assign it by dragging the light object from the scene hierarchy into the script's new flashlight field. Then your code can access properties like "Intensity", "Range", "Spot Angle" on that light.

    https://docs.unity3d.com/Manual/class-Light.html

    You'll probably want to define some variables which represent the min/max values for those light properties, as well as for "charge" variable. Then as charge goes from its min/max you can change the light properties from their min/max as well. For that, you can use linear interpolation or Lerp.

    Since this is getting into the weeds a little bit, I'm going to give you a little bit of example code here. If anything in here doesn't make sense to you, please ask. This probably doesn't do exactly what you want, but this should be a good start for you to learn from and built on top of:
    Code (CSharp):
    1. public class Example : MonoBehaviour
    2. {
    3.     [Header("Charging")]
    4.     public float chargeIncreasePerSecond = 1;
    5.     public float chargeDecreasePerSecond = 1;
    6.     public float maxCharge;
    7.  
    8.     [Header("Flashlight")]
    9.     public Light flashlight;
    10.     public float minFlashlightIntensity;
    11.     public float maxFlashlightIntensity;
    12.  
    13.     private float currentCharge;
    14.  
    15.     private void Update()
    16.     {
    17.         bool holdingLMB = Input.GetMouseButton(0);
    18.         bool holdingRMB = Input.GetMouseButton(1);
    19.  
    20.         // enable/disable flashlight based on LMB
    21.         flashlight.enabled = holdingLMB;
    22.  
    23.         // if the RMB is held
    24.         if(holdingRMB)
    25.         {
    26.             // add to the charge variable a little bit
    27.             currentCharge += chargeIncreasePerSecond * Time.deltaTime;
    28.         }
    29.         else
    30.         {
    31.             // subtract from the charge variable a little bit
    32.             currentCharge -= chargeDecreasePerSecond * Time.deltaTime;
    33.         }
    34.  
    35.         // keep charge between 0 and maxCharge
    36.         currentCharge = Mathf.Clamp(currentCharge, 0, maxCharge);
    37.  
    38.         UpdateFlashlight(currentCharge);
    39.     }
    40.  
    41.     private void UpdateFlashlight(float currentCharge)
    42.     {
    43.         // get a number between 0 and 1 which represents how much charge we have built up
    44.         // Clamp keeps the number from going outside 0 or 1 here
    45.         float chargePercentage = Mathf.Clamp01(currentCharge / maxCharge);
    46.  
    47.         // 0 to 1 is a very useful range, and is exactly what the Lerp function needs
    48.  
    49.         // this will choose a value between min/max intensity based on chargePercentage
    50.         // if chargePercentage is 0, min will be used
    51.         // if chargePercentage is 1, max will be used
    52.         // if chargePercentage is 0.5, halfway between min/max will be used
    53.         flashlight.intensity = Mathf.Lerp(minFlashlightIntensity, maxFlashlightIntensity, chargePercentage);
    54.     }
    55. }
     
  6. ghastlygibus

    ghastlygibus

    Joined:
    Aug 14, 2019
    Posts:
    8
    just fixed the "on LMB held, turn off light" thing in my project with that info. will work on the charge thing in a sec. thanks bro
     
  7. ghastlygibus

    ghastlygibus

    Joined:
    Aug 14, 2019
    Posts:
    8
    if I can bother you with one more thing, is there a way I can trigger some code by aiming at an object and using the charged flashlight on it, like a flash-triggered door lock or something?
     
  8. LiterallyJeff

    LiterallyJeff

    Joined:
    Jan 21, 2015
    Posts:
    2,807
    You'll probably need to add a collider as a trigger to the light object and detect overlaps with the door. The collider may need to be resized along with the light if the light is changing size and shape. Could possibly be a composite of multiple colliders, like a series of spheres increasing in size.

    See this answer: https://gamedev.stackexchange.com/a/63140

    Another solution would be to use math to detect the distance and angle to a nearby door relative to the flashlight, creating a virtual "field of view" and detect things that way, but a mesh collider shape as a trigger is probably simpler.
     
    Last edited: Aug 14, 2019
    ghastlygibus likes this.
  9. ghastlygibus

    ghastlygibus

    Joined:
    Aug 14, 2019
    Posts:
    8
    I got the system fully working.

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class NewBehaviourScript : MonoBehaviour
    6. {
    7.     public float minIntense;
    8.     public float maxIntense;
    9.     public float minRange;
    10.     public float maxRange;
    11.     public float minAngle;
    12.     public float maxAngle;
    13.     public float chargeInc = 2;
    14.     public float chargeDec = 10;
    15.     public float maxCharge;
    16.     public Light flashlight;
    17.     public bool lmbStatus;
    18.     public bool rmbStatus;
    19.     private float currentCharge;
    20.     // Start is called before the first frame update
    21.     void Start()
    22.     {
    23.        
    24.     }
    25.  
    26.     // Update is called once per frame
    27.    private void Update()
    28.     {
    29.         { if (Input.GetKey(KeyCode.Mouse0)) // on LMB held, make true
    30.                 lmbStatus = true;
    31.             else
    32.                 lmbStatus = false;
    33.  
    34.  
    35.             if (Input.GetKey(KeyCode.Mouse1))  // on RMB held, make true
    36.                 rmbStatus = true;
    37.             else
    38.                 rmbStatus = false;
    39.  
    40.             // the hard stuff :)
    41.  
    42.             if (lmbStatus == true) // turns the flashlight's bulb off if LMB is held
    43.                 flashlight.enabled = false;
    44.             else
    45.                 flashlight.enabled = true;
    46.  
    47.  
    48.             if (lmbStatus == true && rmbStatus == true) //when both buttons are held, the charge level is raised
    49.                 currentCharge += chargeInc * Time.deltaTime;
    50.             else                                             // otherwise, it is decreased
    51.                 currentCharge -= chargeDec * Time.deltaTime;
    52.         }
    53.  
    54.         currentCharge = Mathf.Clamp(currentCharge, 0, maxCharge); // keeps charge between 0 and the set max
    55.  
    56.         UpdateFlashlight(currentCharge);
    57.        
    58.     }
    59.  
    60.     private void UpdateFlashlight(float currentCharge)
    61.     {
    62.  
    63.         float chargePercent = Mathf.Clamp01(currentCharge / maxCharge);
    64.  
    65.         flashlight.intensity = Mathf.Lerp(minIntense, maxIntense, chargePercent);
    66.         flashlight.range = Mathf.Lerp(minRange, maxRange, chargePercent);
    67.         flashlight.spotAngle = Mathf.Lerp(minAngle, maxAngle, chargePercent);
    68.     }
    69. }
     
    LiterallyJeff likes this.
  10. ghastlygibus

    ghastlygibus

    Joined:
    Aug 14, 2019
    Posts:
    8
    im trying to make a separate light on top of the flashlight model blink 10 times per second when its fully charged but dunno how wait works
     
  11. LiterallyJeff

    LiterallyJeff

    Joined:
    Jan 21, 2015
    Posts:
    2,807
    You can use a Coroutine function to wait by yielding the function's execution until some condition is met. Unity has some really useful built-in yield instructions, like WaitForSeconds.

    There's an example here:
    https://docs.unity3d.com/Manual/Coroutines.html

    You can put your wait inside a loop that runs while "currentCharge == maxCharge" and enable/disable the light.
     
  12. ghastlygibus

    ghastlygibus

    Joined:
    Aug 14, 2019
    Posts:
    8
    when its triggered it loops the first while statement

    Code (CSharp):
    1. IEnumerator blink()
    2.         {
    3.  
    4.                 while (currentCharge == maxCharge)
    5.                 {
    6.                     yield return new WaitForSeconds(0.25f);
    7.                     blinker.enabled = true;
    8.                     yield return new WaitForSeconds(0.25f);
    9.                     blinker.enabled = false;
    10.                 while (currentCharge != maxCharge)
    11.                 {
    12.                     yield return null;
    13.                 }
    14.             }
    15.  
    16.             yield return null;
    17.  
    18.         }
    19.             StartCoroutine(blink());