You will see under the void start function the currentWave. I want it to increment by 1 every 20 seconds. but not sure where and how to go about doing so. Below you will see my declared variables. I have left out the other section of code as it is not necessary for what I need.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Spawner : MonoBehaviour
{
private int currentWave;
private float startTime;
private float currentTime;
Above is my declared variables, and below is my stary function with currentWave set to 1, which is the integer I want to change every 20 seconds.
void Start()
{
currentWave = 0;
startTime = Time.time;
StartCoroutine(SpawnEnemy(TimeFrame[currentWave]));
}
void Update()
{
currentTime = Time.time - startTime;
Debug.Log(currentTime);
}
}
I used my update function to get the current "running time" of the program.
Use a coroutine:
private IEnumerator waveIncrementer;
void Start()
{
currentWave = 0;
startTime = Time.time;
StartCoroutine(SpawnEnemy(TimeFrame[currentWave]));
waveIncrementer = IncrementWave();
StartCoroutine(waveIncrementer);
}
IEnumerator IncrementWave()
{
WaitForSeconds waiter = new WaitForSeconds(20f);
while (true)
{
yield return waiter;
currentWave++;
}
}
if you want it to increment immediately, put currentWave++ before yield return waiter;:
IEnumerator IncrementWave()
{
WaitForSeconds waiter = new WaitForSeconds(20f);
while (true)
{
currentWave++;
yield return waiter;
}
}
Then, you can stop it with StopCoroutine(waveIncrementer);
I think what you are looking for is InvokeRepeating
You don't need to update it every frame. Just compute it when you need it. Change the field to a property, and return a computed value.
public class Spawner : MonoBehaviour
{
private float startTime;
private float CurrentTime
{
get
{
return Time.time - startTime;
}
}
Related
This is my script, when I click the debounce works at first, but after the wait you can just spam click and shoot many bullets at once. How can I fix this? I am a beginner so any help will be nice :) I had to get rid of some because stack overflow wasn't happy
using Photon.Pun;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class SingleShotGun : Gun
{
[SerializeField] Camera cam;
PhotonView PV;
public bool debounce = false;
public float debounce2;
public AudioSource audioSource;
public AudioClip audioClip;
private float timeStarted;
private float audioTime;
private void Start()
{
if (PV.IsMine)
{
audioSource.clip = audioClip;
float timeStarted = (float)PhotonNetwork.Time;
audioTime = 0;
}
}
private void Update()
{
if (PV.IsMine)
{
float audioTime = (float)PhotonNetwork.Time - timeStarted;
}
else
{
audioSource.time = audioTime;
}
}
void Awake()
{
PV = GetComponent<PhotonView>();
}
public override void Use()
{
if (debounce)
{
StartCoroutine(Deb());
return;
}
if (PV.IsMine)
{
audioSource.clip = audioClip;
float timeStarted = (float)PhotonNetwork.Time;
}
debounce = true;
Shoot();
}
private IEnumerator Deb()
{
Debug.Log("Debouncing");
yield return new WaitForSeconds(debounce2);
debounce = false;
}
}
I Tried to make a debounce script for unity3d, but it didn't work?
As a first note: in
float audioTime = (float)PhotonNetwork.Time - timeStarted;
you are creating a new local variable => the class field audioTime is not assigned in that case
same also for all occurrences of
float timeStarted = (float)PhotonNetwork.Time;
you want to remove the float in all three places in order to rather assign your class fields instead of over shadowing them with same named local variables, otherwise they will always have the default value 0.
Then within Use you are starting multiple concurrent routines that will all finish eventually and reset your debounce in unexpected moments. You probably rather want to wrap it in order to start only a single routine like
if(!debounce)
{
debounce = true;
Shoot();
StartCoroutine(Deb()):
}
Also again in general I would expect the entire Use should be wrapped in / start with
if (!PV.IsMine) return;
as it looks and sounds like none of those things should happen at all if this is not your gun ;)
And after setting
audioSource.clip = audioClip;
you also need to
audioSource.Play();
I made a player in my game, such that it goes into slow-motion when you hold down the space bar. But I want the player to only be available to be in slow-motion for 5 seconds at a time. After 10 seconds the player will be available to go into slow-motion again.
Here is the code for the script
using UnityEngine;
public class SlowMotion : MonoBehaviour
{
public float slowMotionTimescale;
private float startTimescale;
private float startFixedDeltaTime;
void Start()
{
startTimescale = Time.timeScale;
startFixedDeltaTime = Time.fixedDeltaTime;
}
void Update()
{
if (Input.GetKeyDown(KeyCode.Space))
{
StartSlowMotion();
}
if (Input.GetKeyUp(KeyCode.Space))
{
StopSlowMotion();
}
}
private void StartSlowMotion()
{
Time.timeScale = slowMotionTimescale;
Time.fixedDeltaTime = startFixedDeltaTime * slowMotionTimescale;
}
private void StopSlowMotion()
{
Time.timeScale = startTimescale;
Time.fixedDeltaTime = startFixedDeltaTime;
}
}
You can use IEnumerator to run time-dependent methods. The method description is as follows:
public bool inTimer; // are slow motion is in timer?
public IEnumerator StartTimer()
{
inTimer = true;
StartSlowMotion();
yield return new WaitForSeconds(5f); // wait to end slow motion
StopSlowMotion();
yield return new WaitForSeconds(5f); // wait time to finish
inTimer = false;
}
In addition, you need to consider the condition not in timer.
if (Input.GetKeyDown(KeyCode.Space) && !inTimer)
{
StartCoroutine(StartTimer()); // how to run timer
}
any way i can make this code print "attacking" and than for 2 seconds then print it again and so on. this script just waits for 2 seconds the first time. and then keeps printing it with every frame
public class ZombieAI : MonoBehaviour
{
// Update is called once per frame
void Update()
{
StartCoroutine(time());
}
IEnumerator time()
{
yield return new WaitForSeconds(4);
Debug.Log("Attacking");
}
}
You can implement it by doing this
public class ZombieAI : MonoBehaviour
{
// Update is called once per frame
void Start()
{
StartCoroutine(time());
}
IEnumerator time()
{
Debug.Log("Attacking");
yield return new WaitForSeconds(2);
StartCoroutine(time());
}
}
You have to start the coroutine from inside the coroutine. However, if you want to implement this WITHOUT coroutines, do this:
public class ZombieAI : MonoBehaviour
{
float timer = 0;
public float attackTimer = 2;
// Update is called once per frame
void Update()
{
timer += Time.deltaTime;
if (timer >= attackTimer)
{
Debug.Log("Attacking!");
timer = 0;
}
}
}
Coroutines can cause headaches, but use whichever one you want :)
Firstly, do not put StartCoroutine() in Update(). That will begin a new coroutine every frame.
Apart from that, you just need to put the action inside a loop, e.g. a for loop. If you want it to keep looping indefinitely until you manually stop the coroutine, you can use:
public class ZombieAI : MonoBehaviour
{
void Start() // Or anywhere that will only be called once when you want to start the coroutine)
{
StartCoroutine(time());
}
IEnumerator time()
{
while( true ) {
yield return new WaitForSeconds(2);
Debug.Log("Attacking");
}
}
}
I created a function that will run until an images fillamount is at 0. However when I call this function from another class the unity editor completing freezes. I cant even stop pause play mode.
The class that calls the cooldown function.
Cooldown cooldown;
cooldown = gameObject.GetComponentInChildren<Cooldown>();//Sets cooldown to have the same values as the prefab.
public void gatherCooldown()
{
cooldown.resourceCooldown();
}
Cooldown Class
public class Cooldown : MonoBehaviour
{
public Image imageCooldown;
public float cooldown = 5;
public bool isCooldown
public void resourceCooldown()
{
while (imageCooldown.fillAmount >= 0)
{
imageCooldown.fillAmount -= 1 / cooldown * Time.deltaTime;
}
}
}
You are currently using a blocking method. To fix that you could use a Corountine instead to decreasing your images fillAmount.
Coroutine Example:
private IEnumerator DecreaseFillAmount() {
// Entered the Coroutine
isCooldown = true;
// Repeat until the fillAmount is smaller than or equal to 0
while (imageCooldown.fillAmount > 0) {
imageCooldown.fillAmount -= (1 / cooldown) * Time.deltaTime;
yield return null;
}
// Left the Coroutine
isCooldown = false;
}
You also need to make sure that you call your Coroutin the right way, you achieve this with StartCoroutine().
Calling the Coroutine:
public void resourceCooldown() {
// Call the DecreaseFillAmount Coroutine.
StartCoroutine(DecreaseFillAmount());
}
Your while is freezing the main thread.
This should probably rather be a Coroutine
public class Cooldown : MonoBehaviour
{
public Image imageCooldown;
public float cooldown = 5;
public bool isCooldown;
private IEnumerator CooldownRoutine()
{
isCooldown = true;
while (imageCooldown.fillAmount >= 0)
{
imageCooldown.fillAmount -= 1 / cooldown * Time.deltaTime;
// Tells Unity to "pause" this routine, render this frame
// And continue from here in the next frame
yield return null;
}
isCooldown = false;
}
public void resourceCooldown()
{
StartCoroutin(CooldownRoutine ());
}
}
So I put the object in the scene and then I made it "invisible" (deactivate if you will) from the inspector (the checkmark box next to the object's name) and after waiting 8 seconds it doesn't become visible. I am using Unity 2d and C#.
I have the game start paused for three seconds then plays after that which works. The first script is that one. The item is supposed to reappear after 8 seconds so after the game resumes, which doesn't work.
//delay before level starts script
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class countDown : MonoBehaviour
{
public GameObject CountDown;
private void Start()
{
StartCoroutine("StartDelay");
}
void Update()
{
}
IEnumerator StartDelay()
{
Time.timeScale = 0;
float pauseTime = Time.realtimeSinceStartup + 3f;
while (Time.realtimeSinceStartup < pauseTime)
yield return 0;
CountDown.gameObject.SetActive(false);
Time.timeScale = 1;
}
{
//script for the flower to appear
IEnumerator Start()
{
print(Time.time);
yield return new WaitForSeconds(8);
print(Time.time);
flowerInScene.gameObject.SetActive(true);
}
[SerializeField] Transform flowerInScene;
}
I still don't really get your two methods called Start
You can simply call a StartCoroutine at the end of another Coroutine so you can chain them together (though there are surely better ways to do what you want in general):
using System.Collections;
using UnityEngine;
public class CountDown : MonoBehaviour
{
public GameObject CountDownObject;
public GameObject flowerObject;
private void Start()
{
StartCoroutine(Delay());
}
private IEnumerator Delay()
{
yield return new WaitForSeconds(3);
HideCountdown();
StartCoroutine(FlowerDelay());
}
private void HideCountdown()
{
CountDownObject.SetActive(false);
}
private IEnumerator FlowerDelay()
{
yield return new WaitForSeconds(8);
ShowFlower();
}
private void ShowFlower()
{
flowerObject.SetActive(true);
}
}
I personaly don't like Coroutines .. they are not so easy to debug sometimes. I would prefer doing something like this with simple timers (though in the first moment it does look worse). Advantage is I can now directly watch the timer count down in the inspector:
using UnityEngine;
public class SimpleCountDown : MonoBehaviour
{
[Header("The Objects")]
public GameObject CountDownObject;
public GameObject FlowerObject;
[Header("Settings")]
// Here you can adjust the delay times
public float StartOffset = 3;
public float FlowerOffset = 8;
[Header("Debug")]
public float startTimer;
public float flowerTimer;
public bool isStartDelay;
public bool isFlowerDelay;
private void Start()
{
startTimer = StartOffset;
flowerTimer = FlowerOffset;
isStartDelay = true;
}
private void Update()
{
if (!isStartDelay && !isFlowerDelay) return;
if (isStartDelay)
{
startTimer -= Time.deltaTime;
if (startTimer <= 0)
{
HideCountdown();
isStartDelay = false;
isFlowerDelay = true;
}
}
if (isFlowerDelay)
{
flowerTimer -= Time.deltaTime;
if (flowerTimer <= 0)
{
ShowFlower();
isFlowerDelay = false;
this.enabled = false;
}
}
}
private void HideCountdown()
{
CountDownObject.SetActive(false);
}
private void ShowFlower()
{
FlowerObject.SetActive(true);
}
}