This is within the Update function. Excuse the brakeTorque stuff, that's just a bandaid for now. This is a drag racing game, and Staged means ready to go. Once both cars are staged, and the race hasn't started yet, then there should be a delay of 5 seconds then the words "GO 1" should appear (I added stupidCounter as a debugging tool). Then it sets the start time. Then it sets Racing to true in order to keep it from jumping back into this if statement again.
The issue is that it keeps jumping back in the if statement every frame; printing: GO1 GO2 GO3 etc.
The word "GO" is not mentioned anywhere else in any other script.
The "Racing" boolean is not mentioned anywhere else in any script.
Here's my code:
if(Staged && OtherCarStaged() && !Racing)
{
RearRightWheel.brakeTorque = 10000;
RearLeftWheel.brakeTorque = 10000;
FrontRightWheel.brakeTorque = 10000;
FrontLeftWheel.brakeTorque = 10000;
yield WaitForSeconds(5);
stupidCounter += 1;
Debug.Log("GO " + stupidCounter);
mainTimerStart = Time.realtimeSinceStartup;
Racing = true;
}
I'm assuming your function is a coroutine. The issue in your code is probably because you are calling the coroutine in every update frame. You either need to add a check to call the coroutine only once, or use your own timer to handle this instead of a coroutine.
Based on your mentioned requirement I think your code should go like this
var timeLeft : float = 5;
function Update()
{
StartCountdown();
}
function StartCountdown()
{
if(Staged && OtherCarStaged() && !Racing)
{
// your stuff
timeLeft -= Time.deltaTime;
if(timeLeft <= 0)
{
Debug.Log("GO");
mainTimerStart = Time.realtimeSinceStartup;
Racing = true;
}
}
}
Or, if you want to go with Coroutines, it would go like this
function Update()
{
if(!countdownStarted && Staged && OtherCarStaged())
StartCoroutine(StartCountdown(5));
}
var countdownStarted : bool = false;
function StartCountdown(float time)
{
countdownStarted = true;
yield WaitForSeconds(time);
Debug.Log("GO ");
mainTimerStart = Time.realtimeSinceStartup;
Racing = true;
}
Related
This is just a portion of my code, and I hope will be easy enough to understand. I found a way to "fix" it, but I still don't understand this:
I set my float countDownTime to 2f. In DisplayTime(), i thought the do-while loop would count from 2 down to 0, but instead starts counting down from 0 to negative numbers. I thought that it would count down and stop when countDownTime reaches 0, as assigned in the while(countDownTime >= 0) but it continues beyond that. Thanks for any feedback or assistance.
// Update is called once per frame
void Update()
{
if (Input.GetKeyDown(KeyCode.Space) && !hasStarted)
{
hasStarted = true;
StartGame();
}
DisplayTime();
}
void DisplayTime()
{
if (timerStart)
{
do
{
countDownTime -= Time.deltaTime;
} while (countDownTime >= 0);
timer2.text = Math.Round(countDownTime, 2).ToString();
}
}
I made changes to it, which is my fix:
// Update is called once per frame
void Update()
{
if (Input.GetKeyDown(KeyCode.Space) && !hasStarted)
{
hasStarted = true;
StartGame();
}
DisplayTime();
}
void DisplayTime()
{
if (timerStart && countDownTime >= 0)
{
do
{
countDownTime -= Time.deltaTime;
} while (countDownTime >= 2);
timer2.text = Math.Round(countDownTime, 2).ToString();
}
}
First off, I don't see where you're initially setting countDownTime to 2.
Second, countDownTime will more likely than not stop on a negative number rather than zero. This is because deltaTime is a measure of the ms that have passed since the last update, and varies quite a bit. So you should round it back up 0 if you don't want to be shown as negative.
Finally, I think you want to execute this code as a Coroutine, otherwise the entire loop will execute in a single frame, which is most likely not what you want.
IEnumerator DisplayTime() {
countDownTime = 2;
while (countDownTime > 0) {
countDownTime -= Time.deltaTime;
timer2.text = Math.Round(countDownTime, 2).ToString();
yield return new WaitForEndOfFrame();
}
}
void Start() {
// start coroutine
StartCoroutine(DisplayTime);
}
If you did not want a coroutine, and wanted to called it each frame from your Update method, you can simply drop the while loop.
void DisplayTime() {
if (timerStart) {
if (countDownTime > 0) {
countDownTime -= Time.deltaTime;
}
}
timer2.text = Math.Round(countDownTime, 2).ToString();
}
The benefit of the Coroutine method is it usually easier to manage. Rather than calling a method every time from Update, you can call it once and just let it run. Since the looping is confined to the method itself you can use DisplayTime to set the initial value of countDownTime to 2.
You need to consider 2 factors.
Update() Method is called on every frame. You are executing do-while loop in DisplayTime() which is called from Update() so do while loop will execute many time (once per frame).
do-while loop works differently from normal while loop. do-while loop first executes code inside do{} and only after checks condition and breaks loop if condition is false. so (even if condition is false) code inside do{} will run at least once once. In case of normal while if condition is false code inside loop will not run.
So in your case on first frame countDownTime is subscribed until it will become be less than 0. (So on screen you immediately see 0 instead of 2, because after first frame its
already 0).
after 1st frame on each frame when do-while is executed code inside do is executed only once and than loop immediately breaks because condition countDownTime >= is already false. So after 1st frame countDownTime -= Time.deltaTime;this code gets executed once per frame (without looping multiple times in do-while), that is why it works "correctly" afterwards.
I have a character that a Boolean flag which determines whether or not he is jumping (if he is jumping, he cannot jump again). When he jumps, the jump flag is set to true, and when he collides with something it is set back to false (so he can jump again).
However, he only jumps once, and jump stays true even when it's supposed to reset to false. Why is this so? My definition for OnCollisionEnter() is supposed to reset the flag.
var trump;
var jump = false;
function Start() {
// Assigns the Rigidbody to a variable
trump = GetComponent(Rigidbody2D);
// Variable Switches:
}
function OnCollisionEnter() {
jump = false;
trump.velocity.y = 0;
trump.velocity.x = 0;
}
function FixedUpdate() {
trump.velocity.x = Input.GetAxis("Horizontal") * 10;
if ((Input.GetKeyDown(KeyCode.UpArrow)) && (jump == false)) {
trump.AddForce(Vector2(0, 10), ForceMode2D.Impulse);
jump = true;
}
}
EDIT: Based on an answer given I tried adding the Collision parameter to OnCollisionEnter(), but it still doesn't look like the function is being called after I added a Debug.Log() inside of it to check. Is there something else wrong?
function OnCollisionEnter(collision: Collision) {
jump = false;
Debug.log("He Hit The Wall");
trump.velocity.y = 0;
trump.velocity.x = 0;
}
Your function signature for OnCollisionEnter() is incorrect. When defining these MonoBehaviour-specific functions, it is imperative that the name and parameters of the function match that shown in the documentation. Otherwise, the MonoBehaviour won't recognize them and the function won't be called when expected.
In this case, OnCollisionEnter() requires a Collision parameter:
function OnCollisionEnter(collision: Collision) {
jump = false;
trump.velocity.y = 0;
trump.velocity.x = 0;
}
Note: The above was written before the question was edited to implement the suggestion - before, OnCollisionEnter() was being defined without a parameter.
However, in your case that isn't the only problem - you're using Unity's 2D physics, which means you should actually be using the 2D variant of the function: OnCollisionEnter2D, which also takes a slightly different parameter of a Collision2D.
So you would need:
function OnCollisionEnter2D(collision: Collision2D) {
jump = false;
trump.velocity.y = 0;
trump.velocity.x = 0;
}
Hope this helps! Let me know if you have any questions.
I'm making and game which has digging as it's feature so I need timer which will count exact float (in seconds) and then destroy gameObject. This is what I tried now but it's freezing unity:
function Update()
{
if (Input.GetMouseButtonDown(0))
{
digTime = 1.5; // in secounds
}
while (!Input.GetMouseButtonUp(0)) // why is this infinite loop?
{
digtime -= Time.deltaTime;
if (digtime <= 0)
{
Destroy(hit.collider.gameObject);
}
}
Here is a basic example how you can check if player has clicked for a certain time period.
#pragma strict
// This can be set in the editor
var DiggingTime = 1.5;
// Time when last digging started
private var diggingStarted = 0.0f;
function Update () {
// On every update were the button is not pressed reset the timer
if (!Input.GetMouseButton(0))
{
diggingStarted = Time.timeSinceLevelLoad;
}
// Check if the DiggingTime has passed from last setting of the timer
if (diggingStarted + DiggingTime < Time.timeSinceLevelLoad)
{
// Do the digging things here
Debug.Log("Digging time passed");
// Reset the timer
diggingStarted = Time.timeSinceLevelLoad;
}
}
It is firing every DiggingTime of seconds even the player is holding the button down. If you want that the player needs to release the button and press again one solution is to add Boolean telling if the timer is on or not. It can be set true on GetMouseButtonDown and false on GetMouseButtonUp.
Update function is called every frame. If you add a while loop inside this function waiting for the mouseButtonUp, you'll freeze Unity for sure.
You don't need the while loop. Just check GetMouseButtonUp without while loop.
EDIT
This is the Update function:
void Update ()
{
if ( Input.GetMouseButtonDown( 0 ) )
{
digTime = 1.5f;
}
else if ( Input.GetMouseButton( 0 ) )
{
if ( digTime <= 0 )
{
Destroy( hit.collider.gameObject );
}
else
{
digTime -= Time.deltaTime;
}
}
}
Minor controls should be added to avoid destroying gameObject several times, but this is the idea to proceed
this will be my first question so go on easy on me please ;)
I'm building my first game in Unity using my limited knowledge, tutorials and troubleshooting on google but i can't seem to fix this issue
i have a script that counts score(with a GUIText) and another one to pause the game(using timescale) and you probably guessed it already but when i pause the game it doesn't pause the score.
Script for Pausing:
var isPaused : boolean = false;
function Update()
{
if(Input.GetKeyDown("p"))
{
Pause();
}
}
function Pause()
{
if (isPaused == true)
{
Time.timeScale = 1;
isPaused = false;
}
else
{
Time.timeScale = 0;
isPaused = true;
}
}
Script for Score:
var Counter : int = 100000;
var Substractor : int = 0;
var Score : int = Counter - Substractor;
function Update (
) {
Score--;
guiText.text = "Score: "+Score;
}
the score script is attached to a gameobject with a gui text and the script for pausing the game is attached to the player
another issue is that when i'm moving(using the arrow keys) then press pause and then unpause the player moves faster and unpredictable for a splitsecond but this is only when i press pause while pressing the arrow buttons when i only press pause there is no issue, this is a small bugg that i'l try to fix myself, just thought i'd add it here for those that have an easy answer to this issue aswell
I only know this problem from other game frameworks and I've got no experiance with unity. But it should work the same way for unity as it does in other frameworks. You have two options:
Update is called after every rendering frame! So your timescale doesn'T influence how often update is called. Instead you have to find some dt or deltaT (don't know how it is called in unity and how to get it, but I mean the time, since unities the last call to update, please tell me in the comments, so I can edit this answer).
Then don't calculate your score like:
Score--;
but use something like:
Score -= 1 * dt
or
Score -= 1 * dt * Time.timeScale
(depending how exactly unity works)
alternatively you can sourround your update-block with some if-statement:
in Score:
function Update (
) {
if (! isPaused()) { // not sure how this function / property is called in unity
Score--;
guiText.text = "Score: "+Score;
}
}
I am trying to make a game in where you can stab an enemy, the enemy struggles for about a second and drops dead. (ragdoll);
i think its best to just show my script and you know what I mean:
In an on trigger enter script:
if(other.tag == "enemy"){
other.transform.parent.gameObject.name = ("enemy" + currentEnemy);
print(other.name);
gameObject.Find("enemy" + currentEnemy).GetComponent("RagdollOrNot").MakeKinematicFalse();
BloodParticle.emit = true;
Stabbed = true;
Character.GetComponent("MouseLook").enabled = false;
Character.GetComponent("CharacterMotor").enabled = false;
}
and in the update function:
if(Stabbed == true){
StopBleeding ++;
}
if(StopBleeding > 50){
Stabbed = false;
StopBleeding = 0;
currentEnemy ++;
Character.GetComponent("MouseLook").enabled = true;
Character.GetComponent("CharacterMotor").enabled = true;
BloodParticle.emit = false;
}
Now when my knife enters the collision of the enemy the enemy imediatly drops to the floor.
I tried putting the:
gameObject.Find("enemy" + currentEnemy).GetComponent("RagdollOrNot").MakeKinematicFalse();
in the update function in if(StopBleeding > 50).
if I do that I get an error of Null reverance exception becaus the script cand find the enemy. While it can I its in the trigger enter.
Basicly my question is: Is there any way to fix this error to give it a 50 frame delay (all the rest in StopBleeding works)?
Or is there any way I can put a simple delay in before the Ragdoll gets activated?
Thanks in advance
You can use StartCoroutine("DelayDeath"); where DelayDeath is the name of a method. See below.
if(other.tag == "enemy"){
other.transform.parent.gameObject.name = ("enemy" + currentEnemy);
print(other.name);
StartCoroutine("DelayDeath");
BloodParticle.emit = true;
Stabbed = true;
Character.GetComponent("MouseLook").enabled = false;
Character.GetComponent("CharacterMotor").enabled = false;
}
private IEnumerator DelayDeath()
{
//this will return...and one second later re-enter and finish the method
yield return new WaitForSeconds(1.0f);
gameObject.Find("enemy" + currentEnemy).GetComponent("RagdollOrNot").MakeKinematicFalse();
}
Since you're asking specifically about Unity JS and not C#, you'll use the yield keyword.
print("foo");
yield WaitForSeconds (5.0); // waits for 5 seconds before executing the rest of the code
print("bar");
On stabbing you could look up the enemy object but save it away in a variable instead of issuing the enemies dead. After the bleeding finishes you don't have to look up the enemy and can trigger the death on the saved one.
Another hint: Don't count frames as frames might be of different length. Add up time from Time.deltaTime until you reach let's say 2 seconds and then trigger the death.
Hope that helps.