public class PipeSpawner : MonoBehaviour
{
public float maxTime = 1;
private float timer = 0;
public GameObject pipe;
public float height;
void Update()
{
if (timer > maxTime)
{
GameObject newpipe = Instantiate(pipe);
newpipe.transform.position = transform.position + new Vector3(0, Random.Range(-height, height), 0);
Destroy(newpipe, 15);
timer = 0;
}
}
}
Timer never passes max time, so the code in the update method never executes.
This is a neat way of doing "cooldowns" or "timers":
public class PipeSpawner : MonoBehaviour
{
public float futureTimestamp;
public GameObject pipe;
public float height;
void Start()
{
futureTimestamp = SetFutureTimestamp(5);
}
void Update()
{
if (Time.time > maxTime)
{
GameObject newpipe = Instantiate(pipe);
newpipe.transform.position = transform.position + new Vector3(0, Random.Range(-height, height), 0);
Destroy(newpipe, 15);
}
}
}
void SetFutureTimestamp(float seconds) {
futureTimestamp = Time.time + seconds;
}
Basically setting a timestamp in the future and checking if current time is larger than future time each update. Time.time > futureTimestamp
You could use class Timer and
Timer.Start();
create a global int variable
int tik = 0
and using the event Timer_Tik to count how many seconds passed (tik++).
To control the interval you should use Timer.Interval = 1000; witch is one second and final
if (tik > maxTime)
Related
I am trying to make a script that moves my GameObject for sometime and then stops it for 2 seconds.
But my code does make it run a while then stop but then it goes in an endless loop of not doing anything at all
Here is my code;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Threading;
public class Enemyai : MonoBehaviour
{
public Animator anim;
public int timer = 100000;
public int Abstimer = 100000;
public bool running = true;
public float speed = 5;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
if (timer==0)
{
timer = Abstimer;
anim.SetBool("isRunning", false);
running = false;
Invoke("attack", 2);
}
if (running == true)
{
anim.SetBool("isRunning", true);
this.transform.position += transform.right * -speed * Time.deltaTime;
timer--;
}
}
void attack()
{
running = true;
}
`
Well .. you know you currently make it wait for 100000 frames
=> with a normal frame rate of about 60 frames per second that makes about 1667 seconds - aka 27 Minutes - of waiting...
What you would rather do is
not use frame rate dependent code but seconds
use a reasonable amount of time ^^
Like e.g.
public class Enemyai : MonoBehaviour
{
public Animator anim;
// This would mean 3 seconds
public float Abstimer = 3f;
public float speed = 5;
void Update()
{
if (timer<=0)
{
timer = Abstimer;
anim.SetBool("isRunning", false);
running = false;
Invoke(nameof(attack), 2);
}
if (running)
{
this.transform.position -= transform.right * speed * Time.deltaTime;
timer-= Time.deltaTime:
}
}
void attack()
{
anim.SetBool("isRunning", true);
running = true;
}
}
Maybe easier to handle might be a Coroutine like e.g.
public class Enemyai : MonoBehaviour
{
public Animator anim;
// This would mean 3 seconds
public float Abstimer = 3f;
public float speed = 5;
private IEnumerator Start()
{
while(true)
{
yield return new WaitForSeconds(2);
anim.SetBool("isRunning", true);
for(var timer = 0f; timer < Abstimer; timer += Time.deltaTime)
{
transform.position -= transform.right * speed * Time.deltaTime;
yield return null;
}
anim.SetBool("isRunning", false);
}
}
}
Either way have in mind you still need to actually adjust the value of Abstimer in the Inspector not only in code
public class ProjectileFlightTimeUntilDecay : MonoBehaviour
{
public float PlayerProjectile;
public float timeUntilDecay = 5.0f;
void Start()
{
timeUntilDecay = timeUntilDecay * Time.deltaTime;
}
// Update is called once per frame
void Update()
{
if(timeUntilDecay <= 0)
{
// Destroy the projectile
}
}
}
I tried this, and doesn't work.
timeUntilDecay is never decreased from its initial value, so the check if (timeUntilDecay <= 0) will never be true.
Typically this is done by decrementing it in Update(), e.g.
timeUntilDecay -= Time.deltaTime;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ScrollingObject : MonoBehaviour
{
private Rigidbody2D rb2d;
// Start is called before the first frame update
void Start()
{
rb2d = GetComponent<Rigidbody2D>();
//if (GameControl.instance.score > 0)
// rb2d.velocity = new Vector2(GameControl.instance.scrollSpeed * GameControl.instance.score, 0);
//else
rb2d.velocity = new Vector2(GameControl.instance.scrollSpeed, 0);
}
// Update is called once per frame
void Update()
{
if (GameControl.instance.score > 5)
rb2d.velocity = new Vector2(GameControl.instance.scrollSpeed *3, 0);
if (GameControl.instance.score > 10)
rb2d.velocity = new Vector2(GameControl.instance.scrollSpeed*5, 0);
if (GameControl.instance.gameOver == true)
{
rb2d.velocity = Vector2.zero;
}
}
}
You already seem to have a central Singleton controller storing your values.
So instead of poll checking these values every frame I would rather implement it event based using properties and an event
public class GameControl : MonoBehaviour
{
// by default multiplier is 1
private float multiplier = 1;
// Configure here whatever your scrollSpeed is anyway
[SerializeField] private float _scrollSpeed = 20;
// A public read-only property which already has the multiplier applied
public float scrolSpeed => _scrollSpeed * multiplier;
// the actual score backing field
private int _score;
public int score
{
// when accessing the score property just return the internal _score value
get => _score;
// when assigning a new value to score
set
{
// update the backing field
_score = value;
// also update the multiplier
// use a base value of 1
// intentionally use an int division to increase multiplier by 2 for every 5 points
multiplier = 1 + 2 * score / 5;
// inform listeners that the score was changed
onScoreChanged?.Invoke();
}
}
// evnt whih is invoked everytime the score is changed
public event Action onScoreChanged;
...
}
and then you simply want to do
public class ScrollingObject : MonoBehaviour
{
[SerializeField] private Rigidbody2D rb2d;
private void Awake()
{
if(!rb2d) rb2d = GetComponent<Rigidbody2D>();
}
private void FixedUpdate()
{
rb2d.velocity = Vector2.right * GameControl.instance.scrollSpeed;
}
}
if you really need to constantly set the velocity for whatever reason.
Or even better do it all event based and only update the velocity once the score was actually changed:
public class ScrollingObject : MonoBehaviour
{
[SerializeField] private Rigidbody2D rb2d;
private void Awake()
{
if(!rb2d) rb2d = GetComponent<Rigidbody2D>();
// fetch the initial values once immediately
OnScoreChanged();
// attach a callback to the score changed event
GameControl.instance.onScoreChanged += OnScoreChanged;
}
private void OnDestroy()
{
// be sure to remove callbacks as soon as not needed anymore
GameControl.instance.onScoreChanged += OnScoreChanged;
}
// automatically called once every time the score was changed
private void OnScoreChanged()
{
// update the velocity
rb2d.velocity = Vector2.right * GameControl.instance.scrollSpeed;
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ColumnPool : MonoBehaviour
{
public int columnPoolSize = 5;
public GameObject columnPrefab;
public float spawnRate = 1f;
public float columnMin = -1.5f;
public float columnMax = 1.5f;
private GameObject[] columns;
private Vector2 objectPoolPosition = new Vector2(-15f, -25f);
private float timeSinceLastSpawned;
private float spawnXPosition = 10f;
private int currentColumn = 0;
// Start is called before the first frame update
void Start()
{
columns = new GameObject[columnPoolSize];
for (int i = 0; i < columnPoolSize; i++)
{
columns[i] = (GameObject)Instantiate(columnPrefab, objectPoolPosition, Quaternion.identity);
}
}
// Update is called once per frame
void Update()
{
// timeSinceLastSpawned += Time.deltaTime;
//if (GameControl.instance.score > 5)
//timeSinceLastSpawned += Time.deltaTime * GameControl.instance.score;
//// timeSinceLastSpawned += Time.deltaTime;
//if (GameControl.instance.score % 5 == 0)
if ((GameControl.instance.score > 1 && GameControl.instance.score % 5 == 0))
{
timeSinceLastSpawned += Time.deltaTime;
}
// timeSinceLastSpawned += Time.deltaTime *1.0f;
//if (GameControl.instance.score > 5)
// timeSinceLastSpawned += Time.deltaTime * 2;
if (GameControl.instance.gameOver == false && timeSinceLastSpawned >= spawnRate)
{
timeSinceLastSpawned = 0;
float spawnYPosition = Random.Range(columnMin, columnMax);
columns [currentColumn].transform.position = new Vector2(spawnXPosition, spawnYPosition);
currentColumn++;
if (currentColumn >= columnPoolSize)
{
currentColumn = 0;
}
}
}
}
I'm very new to scripting and to unity as well, In my scene, I would like the player from its current location to teleport to a certain location after the countdown timer hits zero, is there a way to do this? I research online however I could not find many tips about it thus I am asking here.
I did a basic code timer I found online
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class Timer : MonoBehaviour
{
public float timeRemaining = 150;
public bool timerIsRunning = false;
public Text timeText;
private void Start()
{
// Starts the timer automatically
timerIsRunning = true;
}
void Update()
{
if (timerIsRunning)
{
if (timeRemaining > 0)
{
timeRemaining -= Time.deltaTime;
DisplayTime(timeRemaining);
}
else
{
Debug.Log("Time has run out!");
timeRemaining = 0;
timerIsRunning = false;
}
}
}
void DisplayTime(float timeToDisplay)
{
timeToDisplay += 1;
float minutes = Mathf.FloorToInt(timeToDisplay / 60);
float seconds = Mathf.FloorToInt(timeToDisplay % 60);
timeText.text = string.Format("{0:00}:{1:00}", minutes, seconds);
}
}
You have many ways to do the "teleport", but it's basically change object transform position, so if you want that the object goes to the 3D space position (0,1,0), just assign it to it:
this.transform.position = new Vector3(0,1,0);
For the timer you can use Invoke or InvokeRepeating methods or a countdown like yours.
So in your code it will looke something like:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class Timer : MonoBehaviour
{
///
public GameObject objectToTeleport = null; //assign it from inspector or code
public Vector3 destination = new Vector3(0,0,0); //assign it from inspector or code
///
public float timeRemaining = 150;
public bool timerIsRunning = false;
public Text timeText;
private void Start()
{
// Starts the timer automatically
timerIsRunning = true;
}
void Update()
{
if (timerIsRunning)
{
if (timeRemaining > 0)
{
timeRemaining -= Time.deltaTime;
DisplayTime(timeRemaining);
}
else
{
Debug.Log("Time has run out!");
timeRemaining = 0;
timerIsRunning = false;
//Move object
objectToTeleport.transform.position = destination;
}
}
}
void DisplayTime(float timeToDisplay)
{
timeToDisplay += 1;
float minutes = Mathf.FloorToInt(timeToDisplay / 60);
float seconds = Mathf.FloorToInt(timeToDisplay % 60);
timeText.text = string.Format("{0:00}:{1:00}", minutes, seconds);
}
}
I have a timer.cs that has 30 sec and i want to add like 4 more sec whenever i get a point. The script that detects is ScoringSystem.cs
ScoringSystem.cs
public class ScoringSystem : MonoBehaviour {
public GameObject scoreText;
public static int theScore;
void Update()
{
scoreText.GetComponent<Text>().text = "Score: " + theScore;
}
}
Timer.cs
public class Timer : MonoBehaviour
{
public string LevelToLoad;
private static float timer = 30f;
private Text timerSeconds;
// Use this for initialization
void Start ()
{
timerSeconds = GetComponent<Text> ();
}
// Update is called once per frame
void Update ()
{
timer -= Time.deltaTime;
timerSeconds.text = timer.ToString("f0");
if (timer <= 0)
{
timer = 30f;
Application.LoadLevel (LevelToLoad);
}
}
}
There's the update on how the ScoringSystem works. https://prnt.sc/t7xk8l
Add this code under the if-statement in the CollectPoint.cs:
Timer.timer += 4;
And change the timer variable from private static float timer = 30f; to public static float timer = 30f;