-1

How would you find the time since a certain variable was changed? Take for example a boolean variable, how would you find the time since it was last changed? I want to use the boolean variable as a trigger (activating the trigger when it's true), but only after an exact, constant time (such as 0.5s) has passed since it was changed to true (it can only be changed from false to true).

Here is the code I have:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class hitRegistration : MonoBehaviour
{

    AudioSource hitSound;
    private bool hitState = false;
    // Use this for initialization
    void Start()
    {
        hitSound = gameObject.GetComponent<AudioSource>();
    }
    void OnMouseOver()
    {
        Debug.Log("Mouse is over game object.");
        if (Input.GetKey(KeyCode.X) && hitState == false)
        {
            hitSound.Play();
            hitState = true;
        }
    }
    private void OnMouseExit()
    {
        Debug.Log("Mouse is no longer over game object.");
        if (hitState == true)
        {
            // sound clip gets cut if the cursor leaves before its finished.
            Destroy(gameObject);
        }
    }

    // Update is called once per frame
    void Update()
    {

    }
}

"OnMouseOver()" Is simply a function that is called when the mouse is placed over the game object in question. I want to delay destroying the game object until a certain time has passed.

Anya
  • 395
  • 2
  • 13
  • 2
    Possible duplicate of [Detect variable change c#](https://stackoverflow.com/questions/37924612/detect-variable-change-c-sharp) – gunr2171 Oct 23 '18 at 17:28
  • That doesn't give any reference to finding the time since the variable was changed – Anya Oct 23 '18 at 17:30
  • @Anya in order to figure out the time since a variable was last changed, you need to be alerted when it does change. – gunr2171 Oct 23 '18 at 17:33
  • @grek40 No. I don't need to change the value with a defined delay; I need code to execute with a delay that is dependent on when the value changed. I don't need to delay the changing of the variable, but rather code that will run as a result of the variable changing – Anya Oct 23 '18 at 17:34
  • 1
    @gunr2171 theoretically, another approach would be to constantly (interval < accepted variance in delay) check the variable value. So being notified is not *the only* way if some variance is accepted - and without any variance there is not a single way in C# / typical OS environments – grek40 Oct 23 '18 at 17:36
  • @Anya can the *value* be a property? – grek40 Oct 23 '18 at 17:37
  • @grek40 good point. – gunr2171 Oct 23 '18 at 17:39
  • @grek40 Sorry, I'm not sure what a property is. The value is just a boolean variable. I've included the code so hopefully you can deduce whether or not it can be from there – Anya Oct 23 '18 at 17:40
  • I recommind you take a step back and take a beginners book or online tutorial for C#. It's difficult to explain complex coding when you still need to learn about the most basic language concepts and terms. Sorry, I know that's not the answer you are looking for. – grek40 Oct 23 '18 at 17:56
  • That's ok. Any pointers to get me started (other than properties)? – Anya Oct 23 '18 at 18:03
  • 1
    Nothing says "beginner programmer" like `if(x == true)`. `x` is already either true or false, you don't need to *compare* it to true. Just say `if(x)`. Similarly, don't say `if (x == false)`, say `if (!x)` -- if x is **not true**. – Eric Lippert Oct 23 '18 at 18:14
  • 1
    What you're doing here is asking what we call an XY question. You have a problem. You have a crazy idea about how to solve the problem. Now you are asking a question about the crazy idea. It sounds like the problem is "how do I schedule a game action to happen in the future after an event is processed?" but the question you're asking is "how do I know when a variable changed value?" **Ask the question that describes the problem you actually have**. – Eric Lippert Oct 23 '18 at 18:18
  • 1
    @EricLippert don't over-generalize... in case of `bool? x` the check for `if (x == true)` is a somewhat acceptable alternative to `if (x.GetValueOrDefault())`. But this is getting off topic... I like your remark about the XY problem more. – grek40 Oct 23 '18 at 18:22
  • @Anya: Before continuing on this project, I strongly recommend you research what a C# property is and how it differs from a C# field. While properties may or may not be the correct solution to your current problem, they're a core part of how C# works. I will note that properties are probably the simplest approach to the question as you've asked it. That doesn't mean it's right, but any attempt to refute it without a full understanding of why people are suggesting it will lead to more complicated solutions. – Brian Oct 23 '18 at 20:30

3 Answers3

10

First off, as noted in a comment, you are probably trying to solve this problem the wrong way and you are probably asking an "XY" question -- a question where you are asking a question about a proposed bad solution instead of asking a question about the actual problem you face.

To answer the question you actually asked, for better or worse: there is no way to associate behaviours with reading or writing a variable in C#, but you can associate behaviours with a property:

private bool hitState; // The "backing store".
private bool HitState 
{
  get 
  {
    return hitState;
  }
  set
  {
    hitState = value;
  }
}

You would then use HitState rather than hitState throughout the rest of your class.

Now you can add whatever logic you want that happens when the property is read or written:

private DateTime hitStateTime = default(DateTime);
private bool hitState; // The "backing store".
private bool HitState 
{
  get 
  {
    return hitState;
  }
  set
  {
    hitState = value;
    hitStateSet = DateTime.Now;
  }
}

Now you know when it was set. And so on.

Eric Lippert
  • 647,829
  • 179
  • 1,238
  • 2,067
  • This solution works during a current session, not for saving state such as in PlayerPrefs and reading back the values. But, I do like this, +1. – Chad Oct 23 '18 at 19:07
  • 2
    @Chad yes it does .. if you make the setter part execute required steps to store this persistent. And the getter to read it from there. This wasn't specified by the OP – derHugo Oct 23 '18 at 19:54
1

Unless you really need to keep track of how much time has passed on each single frame, one way to do what you are asking for is to use Unity Coroutines.

A coroutine is a method that runs in parallel with the main thread. To solve your question, you can first create a coroutine in the same script, that waits and then does the thing you want to have delayed. A couroutine in Unity is a method that takes up to one parameter and has an IEnumerator return type. You use yield return WaitForSeconds(t); inside the coroutine to have it delay for t seconds.

Then, once it's time to die, check if the mouse is currently hovering over the object with isHovered (set in your OnMouseOver/OnMouseExit methods). If it is, keep a note that it's time to die. If it isn't, then it can die immediately.

IEnumerator WaitToDie(float delaySeconds) 
{
    yield return new WaitForSeconds(delaySeconds);

    // If the mouse is on the object, let OnMouseExit know we're ready to die
    if (isHovered) 
    {
        readyToDie = true;
    } 
    // Otherwise, just die
    else 
    {
        Destroy(gameObject)
    }

}

And then inside your OnMouseOver code, run the coroutine after starting the sound

void OnMouseOver()
{
    isHovered = true;

    Debug.Log("Mouse is over game object.");
    if (Input.GetKey(KeyCode.X) && !hitState)
    {

        hitState = true;
        hitSound.Play();

        // we want to delay for half a second before processing the hit.
        float delaySeconds = 0.5; 
        IEnumerator coroutine = WaitToDie(delaySeconds);

        StartCoroutine(coroutine);
    }
}

And in your OnMouseExit, let everything know that you're done hovering and check if it's past time to die or not.

private void OnMouseExit()
{
    isHovered = false;
    Debug.Log("Mouse is no longer over game object.");

    if (readyToDie) {
        Destroy(gameObject);
    } 

}

Altogether this code will have the object die when both the mouse is off the object AND the time has elapsed.

As a sidenote, I think you might want to revisit how you are checking for a hit, unless your really want to trigger from the player holding X and then moving the mouse over the object. If you intend to trigger any time X is pressed down while the mouse is on top, you might want to put the check in Update and check Input.GetKey(KeyCode.X) && !hitState && isHovered

Ruzihm
  • 19,749
  • 5
  • 36
  • 48
0

keep a seperate variable(DateTime) and call it lastUpdate. then be sure to set it to DateTime.Now, each time the bool you're tracking is updated. then when you need to see how long its been you can just subtract:

DateTime lengthOfTime = DateTime.Now-lastUpdate;

from lengthOfTime you can now access how many days, hours, minutes, and/or seconds have passed.

im on my phone so take it easy on my pseudo-code.

good luck

Technivorous
  • 1,682
  • 2
  • 16
  • 22