Time Based Scoring Unity - unity3d

Hi I'm a beginner in unity and I want to be able to add 10 points to the score every 5 seconds since the game started, this is how i tried to implement it
private int score;
void Update () {
Timer = Time.time;
if (Timer > 5f) {
score += 5;
Timer -= 5f;
}
ScoreText.text = score.ToString ();
}
this is not working what happens is the score increases rapidly after 5f and then it crashes my game.

The math for calculating every 5 seconds is wrong. You should not be doing Timer = Time.time; every loop, that just throws away the old value of Timer. Use Time.deltaTime and add it to the timer instead.
//Be sure to assign this a value in the designer.
public Text ScoreText;
private int timer;
private int score;
void Update () {
timer += Time.deltaTime;
if (timer > 5f) {
score += 5;
//We only need to update the text if the score changed.
ScoreText.text = score.ToString();
//Reset the timer to 0.
timer = 0;
}
}

I know I am a bit late to answer, but the same can be done with Mathf.FloorToInt(Time.timeSinceLevelLoad)

Related

Unity - Decreasing float var with "Time.deltaTime" never going down

I'm try to create a function to stop player control, but when I pass the duration as a parameter in the function, the variable keeps ina huge number never really decreasing.
public void StopAllPlayerControl(float duration) {
stopPlayerDuration = duration;
stopPlayerDuration -= Time.deltaTime;
//stop here what you need.
playerInput.enableMovement = false;
if (stopPlayerDuration <= 0) {
//restore here to normal state
playerInput.enableMovement = true;
}
}
And Im calling this funct in a Update method like this
StopAllPlayerControl(3);
Image here to show that stopPlayerDuration getsm huge but stays in those big numbers never really decreasing. huge number
I used a combination of both answers, organized my logic better and, in this case, I used a coroutine.
This function starts the coroutine and I can call it and control it with a bool
public void startStopPlayerCo(float dur) {
//function to start stop player courutine from anywhere.
StartCoroutine(StopPlayerCo(dur));
}
This is the coroutine that works well now
public IEnumerator StopPlayerCo(float dur) {
while (startCO) {
GetComponent<PlayerMove>().enabled = false;
yield return new WaitForSeconds(dur);
//reset
GetComponent<PlayerMove>().enabled = true;
startCO = false;
}
}
And I call it in Update Method like this:
startStopPlayerCo(2) //2 seconds, or any var for desired time
Try this:
float startTime = 0;
float duration = 0;
public void StopAllPlayerControl(float duration)
{
this.duration = duration;
if(playerInput.enableMovement)
{
startTime = Time.time;
playerInput.enableMovement = false;
}
if(Time.time - startTime >= this.duration)
{
playerInput.enableMovement = true;
}
}
Explaination
Step 1
Firstly, we need to check if movement is already enabled. If it is, we mark the point that we started the timer, and disable movement. We also store our duration in a variable, and reference it locally with the `this` keyword.
if(playerInput.enableMovement)
{
startTime = Time.time;
playerInput.enableMovement = false;
}
Step 2
If the timer exceeds the duration then movement is enabled.
if(Time.time - startTime < duration)
{
playerInput.enableMovement = true;
}
It is also good practice to enclose this method in a boolean lock to prevent it from being called again while the timer is running, unless you want such a feature to be allowed.

Unity2D Disable player movement for X seconds

I am trying to disable a player movement for 1 second when it collides with a specific object. The object collides and it detects that just fine however currently the entire game freezes and does not return.
Ive implemented a 0 value (as found in other examples) to the X and Y movements with a timer. This freezes the game entirely and I have to kill process and reopen Unity.
public Boolean frozen = false;
float shipDisabledTimer = 1f;
// Start is called before the first frame update
void Start()
{
SetUpMoveBoundaries();
gameSession = FindObjectOfType<GameSession>();
}
// Update is called once per frame
void Update()
{
Move(frozen);
Fire();
if (SceneManager.GetActiveScene() == SceneManager.GetSceneByName("Game"))
{
if (Input.GetKey(KeyCode.Escape))
SceneManager.LoadScene("Game Over");
}
}
public void Move(Boolean Frozen)
{
UnityEngine.Debug.Log("Update1 - " + Frozen);
var deltaX = Input.GetAxis("Horizontal") * Time.deltaTime * moveSpeed;
var deltaY = Input.GetAxis("Vertical") * Time.deltaTime * moveSpeed;
var newXPos = Mathf.Clamp(transform.position.x + deltaX, xMin, xMax);
var newYPos = Mathf.Clamp(transform.position.y + deltaY, yMin, yMax);
transform.position = new Vector2(newXPos, newYPos);
if (frozen == true)
{
float timer = 0f;
timer += Time.deltaTime;
UnityEngine.Debug.Log(frozen);
while (timer < shipDisabledTimer)
{
newXPos = 0;
newYPos = 0;
}
disableship(frozen = false);
}
}
public Boolean disableship(Boolean frozen)
{
return frozen;
}
private void OnTriggerEnter2D(Collider2D other)
{
UnityEngine.Debug.Log(other.gameObject.name);
if (other.gameObject.name.Equals("Orb Shot(Clone)"))
{
UnityEngine.Debug.Log("Orb hit player");
//StartCoroutine(countdownTimer());
disableship(frozen = true);
}
}
The ship alone should freeze. No other game object should freeze. All scores, counters, enemies should continue onward. Only the player X,Y are disabled for 1 second.
This
while (timer < shipDisabledTimer)
{
newXPos = 0;
newYPos = 0;
}
entirely blocks your game's main thread since the timer nor shipDisabledTime are not changed within the loop so it will never end.
There are a few ways you could go here.
Invoke
Invoke allows you to call a method after a certain delay so you could easily do something like
public void Freeze()
{
frozen = true;
Invoke("Unfreeze"; shipDisabledTime);
}
private void Unfreeze()
{
frozen = false;
}
Coroutine
A Coroutine is like a temporary Update method. Simplest way in your case is using WaitForSeconds and do something like
public void Freeze()
{
StartCoroutine (FreezeRoutine());
}
private IEnumerator FreezeRoutine()
{
frozen = true;
yield return new WaitForSeconds(shipDisabledTime);
frozen = false;
}
simple timer
Or you could use a simple timer but in Update (not a while loop) like
private float timer = -1;
public void Freeze()
{
frozen = true;
timer = shipDisabledTime;
}
private void Update()
{
if(timer > 0)
{
timer -= Time.deltaTime;
if(timer <= 0)
{
timer = -1;
frozen = false;
}
}
...
}
And then either way you simply don't take any movement input in the meantime
public void Move()
{
if(frozen) return;
...
}
Except for the Invoke solution you can also extend them and decided whether you want to e.g. stack multiple freezes, ignore them while already frozen or simply start the timers over.
General note: In c# rather simply use bool it's basically the same but easier to read and write ;)
Also note that this call
disableship(frozen = false);
...
public Boolean disableship(Boolean frozen)
{
return frozen;
}
Is pretty strange ... first of all this method does absolutely nothing than just return the same value you pass in as parameter .. you are hiding the frozen field with a same named parameter so this does nothing!
Second your method returns a Boolean but you are not assigning it to anything.
If you want to change the value simply set it using frozen = XY but don't pass this in as parameter further.
Aaand avoid calling Debug.Log every frame .. it will slow down your app even in a build where you don't even see the log!

Move rigidbody from point a to b [duplicate]

I am learning Unity from a Swift SpriteKit background where moving a sprite's x Position is as straight forward as an running an action as below:
let moveLeft = SKAction.moveToX(self.frame.width/5, duration: 1.0)
let delayAction = SKAction.waitForDuration(1.0)
let handSequence = SKAction.sequence([delayAction, moveLeft])
sprite.runAction(handSequence)
I would like to know an equivalent or similar way of moving a sprite to a specific position for a specific duration (say, a second) with a delay that doesn't have to be called in the update function.
gjttt1's answer is close but is missing important functions and the use of WaitForSeconds() for moving GameObject is unacceptable. You should use combination of Lerp, Coroutine and Time.deltaTime. You must understand these stuff to be able to do animation from Script in Unity.
public GameObject objectectA;
public GameObject objectectB;
void Start()
{
StartCoroutine(moveToX(objectectA.transform, objectectB.transform.position, 1.0f));
}
bool isMoving = false;
IEnumerator moveToX(Transform fromPosition, Vector3 toPosition, float duration)
{
//Make sure there is only one instance of this function running
if (isMoving)
{
yield break; ///exit if this is still running
}
isMoving = true;
float counter = 0;
//Get the current position of the object to be moved
Vector3 startPos = fromPosition.position;
while (counter < duration)
{
counter += Time.deltaTime;
fromPosition.position = Vector3.Lerp(startPos, toPosition, counter / duration);
yield return null;
}
isMoving = false;
}
Similar Question: SKAction.scaleXTo
The answer of git1 is good but there is another solution if you do not want to use couritines.
You can use InvokeRepeating to repeatedly trigger a function.
float duration; //duration of movement
float durationTime; //this will be the value used to check if Time.time passed the current duration set
void Start()
{
StartMovement();
}
void StartMovement()
{
InvokeRepeating("MovementFunction", Time.deltaTime, Time.deltaTime); //Time.deltaTime is the time passed between two frames
durationTime = Time.time + duration; //This is how long the invoke will repeat
}
void MovementFunction()
{
if(durationTime > Time.time)
{
//Movement
}
else
{
CancelInvoke("MovementFunction"); //Stop the invoking of this function
return;
}
}
You can use co-routines to do this. To do this, create a function that returns type IEnumerator and include a loop to do what you want:
private IEnumerator foo()
{
while(yourCondition) //for example check if two seconds has passed
{
//move the player on a per frame basis.
yeild return null;
}
}
Then you can call it by using StartCoroutine(foo())
This calls the function every frame but it picks up where it left off last time. So in this example it stops at yield return null on one frame and then starts again on the next: thus it repeats the code in the while loop every frame.
If you want to pause for a certain amount of time then you can use yield return WaitForSeconds(3) to wait for 3 seconds. You can also yield return other co-routines! This means the current routine will pause and run a second coroutine and then pick up again once the second co-routine has finished.
I recommend checking the docs as they do a far superior job of explaining this than I could here

Can I do multiple countdown in unity?

Need help
Can i do this in void Update() ?
public float waitTime = 3f;
float timer;
void Update () {
// I will do anything here then,
timer += Time.deltaTime; // start counting
// If timer become 3 seconds
if (timer > waitTime) {
timer = 0f; // to reset timer back to 0 again
}
// I will do the next command here then,
timer += Time.deltaTime; // start counting again
// If timer become 3 seconds
if (timer > waitTime) {
timer = 0f; // to reset timer back to 0 again
}
// I will do the next command here then so on,
}
Or maybe there is another way? Need help again
No, that wouldn't work:
In Update, when you reach the first timer = 0f, for the rest of the function, you timer is 0 so the second event will never trigger. On the next frame, you will start over at the top and after 3 seconds, reach the first event again.
There are several solutions. To get a simple solution using your code, you can save the number of commands you already executed:
public float waitTime = 3f;
private float timer;
private int currentCommand = 0;
void Update ()
{
timer += Time.deltaTime;
if (timer > waitTime)
{
timer -= waitTime; // this is more exact than setting it to 0: timer might be a bit greater than waitTime
// The first time the timer reaches 3s, it will call ExecuteCommand with argument 0
// The second time, with argument 1, and so on
ExecuteCommand(currentCommand);
currentCommand++;
}
}
private void ExecuteCommand(int command)
{
switch(command)
{
case 0: //HERE Code for command 0
return;
case 1: //HERE Code for command 0
return;
// as many as you want
}
}
Another nice way would be to take advantages of coroutines. Coroutines are a bit tricky if you are a begginer. These are functions that can be stopped in the middle and resumed later. With a coroutine you could do something like
void Start ()
{
StartCoroutine("CommandRoutine");
}
private void IEnumerator CommandRoutine()
{
yield return new WaitForSeconds(waitTime);
// HER CODE FOR COMMAND 1
yield return new WaitForSeconds(waitTime);
// HER CODE FOR COMMAND 2
yield return new WaitForSeconds(waitTime);
// And so on
}
If you don't know coroutines, my first example will be simpler for you to understand, but it can be a nice occasion to try coroutine if you are interested.

unity c# countdown timer for dynamic times

I've worked out how to make a countdown timer. I would like to make a timer that counts minutes and seconds that I specify in the inspector. when I click an object the timer gets reduced by a few minutes and/or seconds. I will decide a little later. below is my code. Thanks!
using UnityEngine;
using System.Collections;
public class controllerScript : MonoBehaviour {
public GUIText timerText;
public float minutes;
void Start(){
timerText.text = "";
}
void Update(){
if (Input.GetMouseButtonDown(0)){
Debug.Log("pressed left click, casting ray");
CastRay();
}
minutes -= Time.deltaTime;
timerText.text = minutes.ToString("f0") + "";
}
void CastRay(){
Ray ray = Camera.main.ScreenPointToRay (Input.mousePosition);
RaycastHit2D hit = Physics2D.Raycast (ray.origin, ray.direction, Mathf.Infinity);
//start statements for what happens when Objects are clicked
if (hit.collider.gameObject.name == "target01"){
Debug.Log("you've click obj 1, good work.");
}
if (hit.collider.gameObject.name == "target02"){
Debug.Log("well that's obj 2, even better!");
}
}
}
Dont know, what exact is your question,
but you should realize, that Time.deltaTime is time in seconds and not in minutes.
So you should change the line
minutes -= Time.deltaTime;
to
minutes -= Time.deltaTime / 60.0;