- Home /
Only make a timer work while an object has velocity
I'm rather new to unity and all, so please be gentle. I've remade pong from a tutorial, added my own score system and timer. But I want the timer to only count while the "ball" is actually moving. Since every time it resets, it waits a second to move again, while the timer already counted a second. I know I have to use some sort of while loop, but I can't seem to do it with While(GetComponent<Rigidbody2D>().velocity >= -15 || GetComponent<Rigidbody2D>().velocity <= 15)
as it has to be a vector2 but I don't know how to simulate that in here. Here's the code.
using UnityEngine;
using UnityEngine.UI;
using System.Collections;
public class Ball : MonoBehaviour
{
public float speed = 5;
public Text scoreLeft;
public Text scoreRight;
public int ScoreLeft = 0;
public int ScoreRight = 0;
public Text timer;
float minutes = 0;
float seconds = 0;
float miliseconds = 0;
void Start()
{
System.Random rng = new System.Random();
int randomNumber = rng.Next(0, 10);
if (randomNumber <= 5)
{
GetComponent<Rigidbody2D>().velocity = Vector2.left * speed;
}
if (randomNumber >= 5)
{
GetComponent<Rigidbody2D>().velocity = Vector2.right * speed;
}
}
void OnCollisionEnter2D(Collision2D col)
{
if (col.gameObject.name == "Player 1")
{
float y = hitFactor(transform.position, col.transform.position, col.collider.bounds.size.y);
Vector2 dir = new Vector2(1, y).normalized;
GetComponent<Rigidbody2D>().velocity = dir * speed;
}
if (col.gameObject.name == "Player 3")
{
float y = hitFactor(transform.position, col.transform.position, col.collider.bounds.size.y);
Vector2 dir = new Vector2(-1, y).normalized;
GetComponent<Rigidbody2D>().velocity = dir * speed;
}
if (col.gameObject.name == "Player 2")
{
float y = hitFactor(transform.position, col.transform.position, col.collider.bounds.size.y);
Vector2 dir = new Vector2(1, y).normalized;
GetComponent<Rigidbody2D>().velocity = dir * speed;
}
if (col.gameObject.name == "Player 4")
{
float y = hitFactor(transform.position, col.transform.position, col.collider.bounds.size.y);
Vector2 dir = new Vector2(-1, y).normalized;
GetComponent<Rigidbody2D>().velocity = dir * speed;
}
if (col.gameObject.name == "Wall2")
{
ScoreRight++;
if (ScoreRight >= 10)
{
KillGame();
}
else
{
scoreRight.text = ScoreRight.ToString();
RestartGame();
}
}
if (col.gameObject.name == "Wall3")
{
ScoreLeft++;
if (ScoreLeft >= 10)
{
KillGame();
}
else
{
scoreLeft.text = ScoreLeft.ToString();
RestartGame();
}
}
}
float hitFactor(Vector2 ballPos, Vector2 racketPos, float racketHeight)
{
return (ballPos.y - racketPos.y) / racketHeight;
}
void Reset()
{
GetComponent<Rigidbody2D>().velocity = Vector2.zero;
transform.position = Vector2.zero;
}
void RestartGame()
{
miliseconds = 0;
seconds = 0;
minutes = 0;
Reset();
Invoke("Start", 1);
}
void KillGame()
{
ScoreLeft = 0;
scoreLeft.text = ScoreLeft.ToString();
ScoreRight = 0;
scoreRight.text = ScoreRight.ToString();
RestartGame();
}
void Update()
{
miliseconds += Time.deltaTime * 100;
if (miliseconds >= 100)
{
miliseconds = 0;
seconds++;
if (seconds >= 60)
{
seconds = 0;
minutes++;
}
}
//Debug.Log(string.Format("{0}:{1},{2}", minutes, seconds, (int)miliseconds));
timer.text = string.Format("{0}:{1},{2}", minutes, seconds, (int)miliseconds);
}
}
Answer by metalted · Jun 18, 2019 at 08:07 PM
At first I wasn't really understanding the problem but after reading the script I think it is as this: When you restart the game you reset the timer in RestartGame, then Invoke "start" after 1 second. This is the second you don't want it to run. So there are some options for you now.
You want the timer to start when the game restarts, which means when the start function gets called. The easiest way would be to put the milliseconds = 0, seconds = 0, etc... into the Start function so that it will be reset the same time the game starts.
You want a break in between the ending and the resetting. So the game ends, timer stops, game resets with a one second delay, then start the game with a new timer. In this way, you can't have the timer directly in the Update function. You need to add more control for your timer, so you decide when it's going to run or not. Create some functions for your timer. A ResetTimer() for instance, where you put the milliseconds = 0, sec... etc into. You can add a lot of control by just adding a bool for your timer. You could encapsulate your timer code into an if statement. When the bool is true it will run the timer, when it is false, it won't. Then you can put a timer = true in you start() function and a timer = false in your restart() function. If you can't get it to work feel free to ask more.
I also have some tips for you and things to look out for, because you said you are new to unity and reading your code gives me the idea you are new to coding as well:
In line 26 you check if randomNumber is smaller or equal to 5, in line 30 you check if randomNumber is greater or equal to five. There is an overlap in the if statements. This means that if the randomNumber == 5, both if statements will evaluate to true. This might be something you don't want. There are some ways you could rewrite this:
//Original:
if (randomNumber <= 5)
{
GetComponent<Rigidbody2D>().velocity = Vector2.left * speed;
}
if (randomNumber >= 5)
{
GetComponent<Rigidbody2D>().velocity = Vector2.right * speed;
}
//New (if-else) This will evaluate the first OR the second
if (randomNumber <= 5)
{
GetComponent<Rigidbody2D>().velocity = Vector2.left * speed;
}
else
{
GetComponent<Rigidbody2D>().velocity = Vector2.right * speed;
}
//New (Ternary operator) a bit more advanced but also works
GetComponent<Rigidbody2D>().velocity = randomNumber <= 5 ? Vector2.left * speed : Vector2.right * speed;
"GetComponent()" doesn't have to be used every time. So to save you some typing you could save a reference to a variable in the start function and use that variable to access it:
public class Ball : MonoBehaviour
{
//...
private Rigidbody2D rb;
//...
void Start()
{
rb = GetComponent<Rigidbody2D>();
//...
//Instead of using GetComponent<Rigidbody2D>().velocity = Vector2.left * speed:
rb.velocity = Vector2.left * speed;
}
//...
}
The last thing is when you are copy pasting code, like for instance in the OnCollisionEnter2D() function, there is always a function in there. The code for player 1,2,3 and 4 is almost identical. If you turned this into a function it will save you a lot of lines. AND if you need to change a thing in the code, you only have to change it once instead of 4 times. This might not work for you in this case though. Also explaining how to create function is not really in the scope of your question.
Your answer
Follow this Question
Related Questions
Object jitters when the scene starts 0 Answers
Character won't move (Fixed) 1 Answer
Moving a RigidBody2D for a certain period of time? 0 Answers
Unity 2D addforce problem 1 Answer
How do I make a character Lunge? 2 Answers