Unity. Function call after a certain period of time - c#

How can I make an object invisible (or just delete) after a certain period of time?
Use NGUI.
My example (for changes):
public class scriptFlashingPressStart : MonoBehaviour
{
public GameObject off_Logo;
public float dead_logo = 1.5f;
void OffLogo()
{
off_Logo.SetActive(false);
}
//function onclick button
//remove item after a certain time after pressing ???
void press_start()
{
InvokeRepeating("OffLogo", dead_logo , ...);
}
}

Use Invoke rather than InvokeRepeating.
check Invoke function here
public class scriptFlashingPressStart : MonoBehaviour
{
public GameObject off_Logo;
public float dead_logo = 1.5f;
bool pressed = false;
void OffLogo()
{
//do anything(delete or invisible)
off_Logo.SetActive(false);
pressed = false;
}
//use Invoke rather than InvokeRepeating
void press_start()
{
if(!pressed)
{
pressed = true;
Invoke("OffLogo", dead_logo);
}
else
{
Debug.Log("Button already pressed");
}
}
}

try
StartCoroutine(SomeFunctionAfterSomeTime);
IEnumerator SomeFunctionAfterSomeTime()
{
... //Your own logic
yield return new WaitForSeconds(SomeTime);
}

You can destroy an object in a given time by simply calling Destroy.
public static void Destroy(Object obj, float t = 0.0F);
Parameters
obj The object to destroy.
t The optional amount of time to delay
before destroying the object.
See http://docs.unity3d.com/Documentation/ScriptReference/Object.Destroy.html

Related

How can I create a instantiate my border around a "bronze" when it is the closest and destroy the border when no longer the closest?

I've been stuck at this for a while. What I want is for my outline object to be instantiated at the location of my bronze Base game object and for it to destroy when the bronze base is no longer the closest to the player.
I'm willing to completely restart my bronze script if it means I can make this easier.
Thanks in advance!
Find Closest Bronze Script
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using UnityEngine;
public class FindBronze : MonoBehaviour
{
void Update()
{
FindClosestBronze();
}
void FindClosestBronze()
{
float distanceToClosestBronze = Mathf.Infinity;
Bronze closestBronze = null;
Bronze[] allBronze = GameObject.FindObjectsOfType<Bronze>();
foreach (Bronze currentBronze in allBronze)
{
float distanceToBronze = (currentBronze.transform.position - this.transform.position).sqrMagnitude;
if (distanceToBronze < distanceToClosestBronze)
{
distanceToClosestBronze = distanceToBronze;
closestBronze = currentBronze;
}
if (distanceToBronze > distanceToClosestBronze)
{
closestBronze.GetComponent<Bronze>().notSelected();
}
closestBronze.GetComponent<Bronze>().Selected();
}
}
}
Bronze (includes outline) script
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Bronze : MonoBehaviour
{
public bool isSelected = false;
public Animator anim;
[SerializeField]
public GameObject selectedBox;
public GameObject bronzeBase;
private GameObject clone;
// Update is called once per frame
void Awake()
{
clone = (GameObject)Instantiate(selectedBox, bronzeBase.transform);
}
public void Selected()
{
if (!isSelected)
{
clone = (GameObject)Instantiate(selectedBox, bronzeBase.transform);
isSelected = true;
}
else
{
Destroy(clone);
isSelected = false;
}
}
public void notSelected()
{
Destroy(selectedBox);
}
}
In the Bronze in notSelected you are destroying the prefab selectBox!
You probably rather wanted to destroy the clone instance.
Anyway I would suggest a few things that I would do different
Instead of Instantiate and Destroy all the time rather only use SetActive
Instead of using FindObjectOfType in Update store them in a HashSet event driven: Each Bronze instance registers and unregisters itself
Depends on personal taste but I would use Linq to find the closest instance
This could look somewhat like
public class Bronze : MonoBehaviour
{
// Every instance of this component registers and unregisters itself here
public static readonly HashSet<Bronze> Instances = new HashSet<Bronze>();
[Header("References")]
public Animator anim;
[SerializeField] private GameObject selectedBox;
[SerializeField] private GameObject bronzeBase;
[Header("Debugging")]
[SerializeField] bool _isSelected = false;
private GameObject clone;
// Have a property for the selection
public bool IsSelected
{
// when something reads this property return _isSelected
get => _isSelected;
// This is executed everytime someone changes the value of IsSelected
set
{
if(_isSelected == value) return;
_isSelected = value;
clone.SetActive(_isSelected);
}
}
// Update is called once per frame
void Awake()
{
// Instantiate already returns the type of the given prefab
clone = Instantiate(selectedBox, bronzeBase.transform);
// Register yourself to the alive instances
Instances.Add(this);
}
private void OnDestroy ()
{
// Remove yourself from the Instances
Instances.Remove(this);
}
}
And then use it
using System.Linq;
public class FindBronze : MonoBehaviour
{
private Bronze currentSelected;
private void Update()
{
UpdateClosestBronze();
}
void UpdateClosestBronze()
{
if(Bronze.Instances.Count ==0) return;
// This takes the instances
// orders them by distance ascending using the sqrMagnitude
// of the vector between the Instance and you
// sqrMagnitude is more efficient than Vector3.Distance when you only need to compare instead of the actual distance
// then finally it takes the first item
var newClosest = Bronze.Instances.OrderBy(b => (b.transform.position - transform.position).sqrMagnitude).First();
// skip if the result is the same as last time
if(newClosest == currentSelected) return;
// otherwise first deselect the current selection if there is one
if(currentSelected)
{
currentSelected.IsSelected = false;
}
// Then set the new selection
currentSelected = newSelected;
currentSelected.IsSelected = true;
}
}

can't reset specfic playerprefs in unity3d

I have made 2 codes to manage my interstitial ads by making the ads show every 5 mins when the player losses but the problem is that I tried to reset them when the player passes the 5 mins and press the button when he losses but it didn't work so how to reset the timer when the player presses the button?
this is the 1st code :
public int LastShownIntTime = 300;
void Start()
{
#if UNITY_ANDROID
Advertisement.Initialize(androidID);
#endif
}
public void Update()
{
LastShownIntTime = PlayerPrefs.GetInt("LastShownIntTime");
}
public void showInterstitial()
{
if (LastShownIntTime <=0)
{
showInterstitialwith5mint();
}
}
public void showInterstitialwith5mint()
{
Advertisement.Show("video");
PlayerPrefs.SetInt("LastShownIntTime", 300);
}
and the 2nd one :
public float LastShownIntTimefloat;
public int LastShownIntTime = 300;
void Start()
{
LastShownIntTime = PlayerPrefs.GetInt("LastShownIntTime");
LastShownIntTimefloat = LastShownIntTime;
}
public void Update()
{
LastShownIntTimefloat -= Time.deltaTime;
LastShownIntTime = (int)LastShownIntTimefloat;
PlayerPrefs.SetInt("LastShownIntTime", LastShownIntTime);
}
}
The main issue here:
You would have to reset the LastShownIntTimefloat in your script2!
Otherwise you simply continue overwriting it with new values reducing the value more and write it back to PlayerPrefs
→ the next time your script1 polls the value it is not reset but already overwritten by script2!
In general: You should not use PlayerPrefs in order to make two components communicate!
In your case here I wouldn't even separate the logic and bother with implementing the communication between them but rather merge them into one single component.
Then it is not necessary to read and write PlayerPrefs every frame but rather only on certain checkpoints like
Read once in Start
Write once in OnApplicationQuit
Write once in OnDestroy (This is for the case you e.g. switch Scene but don't quit the app)
Write once ever time your user loses (showInterstitial is called)
Write once when resetting the value after showing the advertisement
I would also simply directly use a float and GetFloat and SetFloat instead of converting it from and to an int.
public class MergedClass : MonoBehaviour
{
// Rather sue a FLOAT for time!
public float LastShownTime = 300;
void Start()
{
#if UNITY_ANDROID
Advertisement.Initialize(androidID);
#endif
// use 300 as default value if no PlayerPrefs found
LastShownTime = PlayerPrefs.GetFloat("LastShownTime", 300f);
}
public void Update()
{
if(LastShownTime > 0f) LastShownTime -= Time.deltaTime;
}
public void showInterstitial()
{
PlayerPrefs.SetFloat("LastShownTime", LastShownTime);
PlayerPrefs.Save();
if (LastShownTime <= 0f)
{
showInterstitialwith5mint();
}
}
public void showInterstitialwith5mint()
{
#if UNITY_ANDROID
Advertisement.Show("video");
#else
LastShownTime = 300f;
PlayerPrefs.SetFloat("LastShownTime", LastShownTime);
PlayerPrefs.Save();
}
private void OnApplicationQuit()
{
PlayerPrefs.SetFloat("LastShownTime", LastShownTime);
PlayerPrefs.Save();
}
private void OnDestroy()
{
PlayerPrefs.SetFloat("LastShownTime", LastShownTime);
PlayerPrefs.Save();
}
}

Save bools from a scene to another in Unity

I've trying to make an adventure game which saves different bools in order to get to the next scene. The problem is that one bool is in another scene with makes it null. Is there any advice?
public class Farmer : MonoBehaviour
{
public bool NextLevel = false;
public Cow1 cow1;
public Cow2 cow2;
public Cow3 cow3;
public Dialogue dialogue;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
if (GetComponent<Cow1>().getIsDisplayed() && GetComponent<Cow2>().getIsDisplayed() && GetComponent<Cow3>().getIsDisplayed())
{
NextLevel = true;
}
if (NextLevel == true)
{
FindObjectOfType<DialogueManager>().startDialogue(dialogue);
}
}
}
Yes, there is quite an easy way to do this, simply give a game object the DontDestroyOnLoad property
{
public bool NextLevel = false;
public Cow1 cow1;
public Cow2 cow2;
public Cow3 cow3;
public Dialogue dialogue;
// Start is called before the first frame update
void Start()
{
DontDestroyOnLoad(this.gameObject);
}
// Update is called once per frame
void Update()
{
if (GetComponent<Cow1>().getIsDisplayed() && GetComponent<Cow2>().getIsDisplayed() && GetComponent<Cow3>().getIsDisplayed())
{
NextLevel = true;
}
if (NextLevel == true)
{
FindObjectOfType<DialogueManager>().startDialogue(dialogue);
}
}
}
This will make your game object persistent through scene changes
You can make use of multi-scene editing so you have some values and variables carry on between your scenes. You can learn more about this here.

How can I detect an object that I see on screen using Raycasting?

So, I want to check if I see an object on screen. Using Raycasting of course.
Code:
private void SeeObject(){
ISeeObj = false;
if (Vector3.Dot(cam.transform.forward, (cam.transform.position - obj.transform.position).normalized) < -0.65f){
RaycastHit hit;
if (Physics.Raycast(cam.transform.position, (obj.transform.position - cam.transform.position).normalized, out hit, range, layerMask)){
if (hit.transform.name == obj.name){
ISeeObj = true;
Debug.Log("I see an Object");
}
}
}
}
Also I've tried using
if (Vector3.Dot(cam.transform.forward,
(cam.transform.position - obj.transform.position).normalized) > 0 )
but it doesn't work.
I would recommend to not use a Raycast for this.
MonoBehaviour already implements the two methods OnBecameVisible
OnBecameVisible is called when the renderer became visible by any camera.
This message is sent to all scripts attached to the renderer.
and
OnBecameInvisible
OnBecameInvisible is called when the renderer is no longer visible by any camera.
This message is sent to all scripts attached to the renderer.
(Both can also be Coroutines)
So if you need to constantly check if an object is currently visible attach a component like
public class VisibilityChecker : MonoBehaviour
{
// E.g. using a read-only auto-property
public bool IsVisible{ get; private set; }
// If you rather like to be able to also see the value in the Inspector for debugging use
//public bool IsVisible { get { return _isVisible;}}
//[SerializeField] private bool _isVisible;
private void OnBecameVisible()
{
IsVisible = true;
//or
//_isVisible = true;
}
private void OnBecameInvisible()
{
IsVisible = false;
//or
//_isVisible = false;
}
}
And in another script e.g. check it in Update like
private VisibilityChecker objVisibilityChecker;
private void Awake()
{
objVisibilityChecker = obj.GetComponent<VisibilityChecker>();
}
private void Update()
{
if(objVisibilityChecker.IsVisible)
{
// Do something
}
else
{
// Do another thing
}
}

calling a child class method in OnMouseDown() of sprite in unity

Good Day all, I am trying to make a simple 2D game and here is how it works. Assume there is a sprite "tent", and whenever i clicked the tent, the console will print out a message. Sounds straightforward is it? However I'm like stuck in the middle of it and I know I am gonna facepalmed myself so hard after this. What I did in my script is:
public abstract class Player : MonoBehaviour {
protected string _name;
// Use this for initialization
public Player(string name)
{
_name = name;
}
public string Name
{
get { return _name; }
set { _name = value; }
}
void Start () {
}
// Update is called once per frame
void Update () {
}}
Next I have a child class called Civilian
public class Civilian : Player {
// Use this for initialization
public Civilian(string name):base(name)
{
}
void Start () {
}
// Update is called once per frame
void Update () {
}
}
Then in my script "Tentclicked", i want to called the function of sleep when the sprite is clicked.
public class tentclicked : MonoBehaviour {
void OnMouseDown()
{
// c.Sleep();
}
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
}
}
And you are wondering what is c and what it is point to? I instantiated a new class in another script called testing1.
public class testing1 : MonoBehaviour
{
public Text p1name;
public void Awake()
{
//p1name.text = "Hello";
//Civilian C = Scriptss.AddComponent<Civilian>();
//GameObject theCivilian = GameObject.Find("Scriptss");
// Civilian c = theCivilian.GetComponent<Civilian>();
//c.Name = Testingsavename.playernames.username;
//c.Name = "Hello";
}
// Use this for initialization
void Start()
{
if (Choosechar.choice.choicecount == 1)
{
Civilian c = new Civilian(Testingsavename.playernames.username);
p1name = GetComponent<Text>();
p1name.text = c.Name;
}
I have already add a circle collider to my sprite. The error is that in tentclicked, c does not exist in context. So i suspect it may be that unity does not know what c is. I am thinking of making civilian class a static one, and just called Civilian.civilian.Sleep() in tentclicked script....
"c" does not exist in this context because your tentclicked class has no reference to it. Find "c" with GameObject.Find(string name) and assign the gameobject value to a variable in tentclicked
You could raycast from the current mouse position towards the object (just make sure that the object has a collider.
void OnMouseDown()
{
RaycastHit hit;
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
if ( Physics.Raycast (ray,out hit,100.0f))
{
Civilian c = hit.collider.gameObject.GetComponent<Civilian>();
c.Sleep();
}
}

Categories

Resources