- Home /
Stopping Penelope's CountDown Timer
Hello everybody,
So I am using Penelope Unity Scripts for my game as I am not a programmer. The timer in the ScoreKeeper Script works fine but would like it to stop and win/end(and play character animation) the game when all the collectibles have been collected and deposited in the DepositArea(An on trigger cube without mesh renderer). Else, I have to wait for timer to finish to end the game which is not ideal. Hope someone can help.
Many thanks
var carrying : int;
var carryLimit : int;
var deposited : int;
var winScore : int; // How many orbs must be deposited to win
var gameLength : int; // Length in seconds
var guiMessage : GameObject; // Prefab for one-shot messages
// GUIText objects that must be assigned in editor
var carryingGui : GUIText;
var depositedGui : GUIText;
var timerGui : GUIText;
// Sound fx and voices for different events
var collectSounds : AudioClip[];
var winSound : AudioClip;
var loseSound : AudioClip;
var pickupSound : AudioClip;
var depositSound : AudioClip;
private var timeSinceLastPlay : float; // Last time we played a voice for pickup
private var timeLeft : float;
public function Start()
{
timeLeft = gameLength;
timeSinceLastPlay = Time.time;
UpdateCarryingGui();
UpdateDepositedGui();
CheckTime();
}
function UpdateCarryingGui()
{
carryingGui.text = " X " + carrying + " of " + carryLimit;
}
function UpdateDepositedGui()
{
depositedGui.text = " : " + deposited + " of " + winScore;
}
function UpdateTimerGui()
{
timerGui.text = " " + TimeRemaining();
}
private function CheckTime()
{
// Rather than using Update(), use a co-routine that controls the timer.
// We only need to check the timer once every second, not multiple times
// per second.
while ( timeLeft > 0 )
{
UpdateTimerGui();
yield WaitForSeconds(1);
timeLeft -= 1;
}
UpdateTimerGui();
EndGame();
}
// This is a utility function to a play one shot audio at a specific position
// and at a specific volume
function PlayAudioClip( clip : AudioClip, position : Vector3, volume : float )
{
var go = new GameObject( "One shot audio" );
go.transform.position = position;
var source : AudioSource = go.AddComponent( AudioSource );
source.rolloffMode = AudioRolloffMode.Logarithmic;
source.clip = clip;
source.volume = volume;
source.Play();
Destroy( go, clip.length );
return source;
}
private function EndGame()
{
var animationController : AnimationController = GetComponent( AnimationController );
var prefab : GameObject = Instantiate(guiMessage);
var endMessage : GUIText = prefab.GetComponent( GUIText );
if(deposited >= winScore)
{
//Player wins
endMessage.text = "You win!";
PlayAudioClip( winSound, Vector3.zero, 1.0 );
animationController.animationTarget.Play( "WIN" );
}
else
{
//Player loses
endMessage.text = "Ran out of time!";
PlayAudioClip( loseSound, Vector3.zero, 1.0 );
animationController.animationTarget.Play( "LOSE" );
}
// Alert other components on this GameObject that the game has ended
SendMessage( "OnEndGame" );
while( true )
{
// Wait for a touch before reloading the intro level
yield WaitForFixedUpdate();
if ( Input.touchCount > 0 && Input.GetTouch( 0 ).phase == TouchPhase.Began )
break;
}
Application.LoadLevel( 0 );
}
public function Pickup( pickup : ParticlePickup )
{
if ( carrying < carryLimit )
{
carrying++;
UpdateCarryingGui();
// We don't want a voice played for every pickup as this would be annoying.
// Only allow a voice to play with a random percentage of chance and only
// after a minimum time has passed.
var minTimeBetweenPlays = 5;
if ( Random.value < 0.1 && Time.time > ( minTimeBetweenPlays + timeSinceLastPlay ) )
{
PlayAudioClip( collectSounds[ Random.Range( 0, collectSounds.length ) ], Vector3.zero, 0.25 );
timeSinceLastPlay = Time.time;
}
pickup.Collected();
PlayAudioClip( pickupSound, pickup.transform.position, 1.0 );
}
else
{
var warning : GameObject = Instantiate( guiMessage );
warning.guiText.text = "You can't carry any more";
Destroy(warning, 2);
}
// Show the player where to deposit the orbs
if ( carrying >= carryLimit )
pickup.emitter.SendMessage( "ActivateDepository" );
}
public function Deposit()
{
deposited += carrying;
carrying = 0;
UpdateCarryingGui();
UpdateDepositedGui();
PlayAudioClip( depositSound, transform.position, 1.0 );
}
public function TimeRemaining() : String
{
var remaining : int = timeLeft;
var val : String;
if(remaining > 59) // Insert # of minutes
val+= remaining / 60 + ".";
if(remaining >= 0) // Add # of seconds
{
var seconds : String = (remaining % 60).ToString();
if(seconds.length < 2)
val += "0" + seconds; // insert leading 0
else
val += seconds;
}
return val;
}
Right now, looking at the script, it should do what you are asking for. Look at the EndGame() function. If a certain amount of stuff is deposited, it says you win and an animation plays out. What is the issue?
Hi, thank you for the prompt response. Yes it works fine but I would like the timer to stop when the WinScore(the required number of items collected) has been achieved.
Currently what happens is that: I collect all the items then have to wait for timer(here denoted by gamelength or timeLeft) to finish to win the game.
I would like to modify the script to end the timer or make the timer = 0 when all the items have been collected and deposited in the Deposit Area.
Do you see the section on line 88?
Underneath, simply set timeleft to be 0if (deposited >= winScore)
if(deposited >= winScore) { timeleft=0; }
Thanks! $$anonymous$$eep getting this error: Assets/Scripts/Score$$anonymous$$eeper.js(109,9): BCE0044: expecting EOF, found 'else'. Do you think an Ontrigger script with the deposit area collider would work ins$$anonymous$$d?
Answer by StrikeMasterz · Jan 07, 2015 at 12:31 AM
Your issue here is that there is nothing in your code that checks if you are picking up the game objects and increasing your score. Here is a way to fix that:
Step Zero: Notes
I need to sleep right now, and as such I won't be able to proofread this answer. There could be spelling mistakes, which you need to be mindful of, ESPECIALLY if they are in codeI use C# more than Javascript, so if there is any syntax wrong, please point it out :)
If there are still any errors/issues, please tell EXACTLY what is going wrong, AS WELL AS any errors that come from the unity engine
Step One: Editor
Add two game object cubes, one named DepositArea and one named ScoreBlock. Put them a fair distance apart. Set the tag for the DepositArea to be Deposit, while the tag for the score block to be ScoreBlock.
Check online if you are not sure how to tag objects
Then, set both of their colliders to be OnTrigger. Again, check if the internet if unsure how.
Step One.Five: Setting up some variables
In the beginning of the script, we assigned some variables, but never gave them a value. It would be best if we did. This is to just remove any possible errors
//This is how many you are carrying. In beginning, you are carrying none, so set this to 0
var carrying : int = 0;
// This is how many you can carry at one time. Set this to what you like (here, 10)
var carryLimit : int = 10;
//This is how many you have deposited.In beginning, you have deposited none, so set this to 0
var deposited : int = 0;
// This is how many you need to win. Set this to what you like (here, 5)
var winScore : int = 5;
Step Two: Increase Carrying Score by Code
Now we need to actually track the amount of blocks you are carrying. Put a new function inside the script, and set it to public: public function OnTriggerEnter (objectCollided: Collider)
{
// Something;
}
This function will execute everytime you hit an object that is marked OnTrigger. Now, check if that object has the tag ScoreBlock, so we know we are hitting a Score Block
public function OnTriggerEnter (objectCollided: Collider)
{
if (objectCollided.transform.tag == "ScoreBlock")
{
// Something;
}
}
Now, we are checking if the object we are collided is a Score Block, by checking if it has the tag Score Block. If it does, let us increase how many you are carrying.
public function OnTriggerEnter (objectCollided: Collider)
{
if (objectCollided.transform.tag == "ScoreBlock")
{
carrying++;
}
}
This will simply take how many you are carrying (In this case, 0) and add a 1 to it. Now, lets work on the Deposit Area!
Step Three: Increase Score when deposited by Code
Now, what we want to do is to do the exact same thing as before, but instead of looking if we hit a ScoreBlock, lets check if we are hitting a DepositBlock. We do both in an if
statement inside the function OnTriggerEnter
public function OnTriggerEnter (objectCollided: Collider)
{
if (objectCollided.transform.tag == "ScoreBlock")
{
carrying++;
}
if (objectCollided.transform.tag == "Deposit")
{
// Something;
}
}
Now, instead of increasing the carrying number, lets increase how many we have deposited by how many carrying we have
public function OnTriggerEnter (objectCollided: Collider)
{
if (objectCollided.transform.tag == "ScoreBlock")
{
carrying++;
}
if (objectCollided.transform.tag == "Deposit")
{
deposited += carrying;
}
}
What did does is increase deposited by our current carrying score. It is the same thing as writing deposited = deposited + carrying
, its just more concise. Now, we also need to reset the carrying score, so we can't just cheat and keep tapping the Deposit area with how much we previously carried
public function OnTriggerEnter (objectCollided: Collider)
{
if (objectCollided.transform.tag == "ScoreBlock")
{
carrying++;
}
if (objectCollided.transform.tag == "Deposit")
{
deposited += carrying;
carrying = 0;
}
}
Step Four: Done!
That is all we should need to do. Everytime you hit an object with the tag ScoreBlock, it will increase carrying by one. Whenever you hit the Deposit object, it will increase the deposit score with ScoreBlock, AS well as reset it to 0.
If there are any more problems, just say so :)
Step Five: Edited Code
MAKE SURE TO READ THE TEXT BEFOREHAND, INCREDIBLY IMPORTANT var carrying : int; = 0
var carryLimit : int; = 10
var deposited : int; = 0
var winScore : int; = 5 // How many orbs must be deposited to win
var gameLength : int; // Length in seconds
var guiMessage : GameObject; // Prefab for one-shot messages
// GUIText objects that must be assigned in editor
var carryingGui : GUIText;
var depositedGui : GUIText;
var timerGui : GUIText;
// Sound fx and voices for different events
var collectSounds : AudioClip[];
var winSound : AudioClip;
var loseSound : AudioClip;
var pickupSound : AudioClip;
var depositSound : AudioClip;
private var timeSinceLastPlay : float; // Last time we played a voice for pickup
private var timeLeft : float;
public function Start()
{
timeLeft = gameLength;
timeSinceLastPlay = Time.time;
UpdateCarryingGui();
UpdateDepositedGui();
CheckTime();
}
function UpdateCarryingGui()
{
carryingGui.text = " X " + carrying + " of " + carryLimit;
}
function UpdateDepositedGui()
{
depositedGui.text = " : " + deposited + " of " + winScore;
}
function UpdateTimerGui()
{
timerGui.text = " " + TimeRemaining();
}
private function CheckTime()
{
// Rather than using Update(), use a co-routine that controls the timer.
// We only need to check the timer once every second, not multiple times
// per second.
while ( timeLeft > 0 )
{
UpdateTimerGui();
yield WaitForSeconds(1);
timeLeft -= 1;
}
UpdateTimerGui();
EndGame();
}
// This is a utility function to a play one shot audio at a specific position
// and at a specific volume
function PlayAudioClip( clip : AudioClip, position : Vector3, volume : float )
{
var go = new GameObject( "One shot audio" );
go.transform.position = position;
var source : AudioSource = go.AddComponent( AudioSource );
source.rolloffMode = AudioRolloffMode.Logarithmic;
source.clip = clip;
source.volume = volume;
source.Play();
Destroy( go, clip.length );
return source;
}
private function EndGame()
{
var animationController : AnimationController = GetComponent( AnimationController );
var prefab : GameObject = Instantiate(guiMessage);
var endMessage : GUIText = prefab.GetComponent( GUIText );
if(deposited >= winScore)
{
//Player wins
timeleft=0;
endMessage.text = "You win!";
PlayAudioClip( winSound, Vector3.zero, 1.0 );
animationController.animationTarget.Play( "WIN" );
}
else
{
//Player loses
endMessage.text = "Ran out of time!";
PlayAudioClip( loseSound, Vector3.zero, 1.0 );
animationController.animationTarget.Play( "LOSE" );
}
// Alert other components on this GameObject that the game has ended
SendMessage( "OnEndGame" );
while( true )
{
// Wait for a touch before reloading the intro level
yield WaitForFixedUpdate();
if ( Input.touchCount > 0 && Input.GetTouch( 0 ).phase == TouchPhase.Began )
break;
}
Application.LoadLevel( 0 );
}
public function Pickup( pickup : ParticlePickup )
{
if ( carrying < carryLimit )
{
carrying++;
UpdateCarryingGui();
// We don't want a voice played for every pickup as this would be annoying.
// Only allow a voice to play with a random percentage of chance and only
// after a minimum time has passed.
var minTimeBetweenPlays = 5;
if ( Random.value < 0.1 && Time.time > ( minTimeBetweenPlays + timeSinceLastPlay ) )
{
PlayAudioClip( collectSounds[ Random.Range( 0, collectSounds.length ) ], Vector3.zero, 0.25 );
timeSinceLastPlay = Time.time;
}
pickup.Collected();
PlayAudioClip( pickupSound, pickup.transform.position, 1.0 );
}
else
{
var warning : GameObject = Instantiate( guiMessage );
warning.guiText.text = "You can't carry any more";
Destroy(warning, 2);
}
// Show the player where to deposit the orbs
if ( carrying >= carryLimit )
pickup.emitter.SendMessage( "ActivateDepository" );
}
public function Deposit()
{
deposited += carrying;
carrying = 0;
UpdateCarryingGui();
UpdateDepositedGui();
PlayAudioClip( depositSound, transform.position, 1.0 );
}
public function TimeRemaining() : String
{
var remaining : int = timeLeft;
var val : String;
if(remaining > 59) // Insert # of minutes
val+= remaining / 60 + ".";
if(remaining >= 0) // Add # of seconds
{
var seconds : String = (remaining % 60).ToString();
if(seconds.length < 2)
val += "0" + seconds; // insert leading 0
else
val += seconds;
}
return val;
}
public function OnTriggerEnter (objectCollided: Collider)
{
if (objectCollided.transform.tag == "ScoreBlock")
{
carrying++;
}
if (objectCollided.transform.tag == "Deposit")
{
deposited += carrying;
carrying = 0;
}
}
Thanks! The game plays but the timer keeps going and doesn't stop when all the coins have been collected :(
I have added this too but still doesn't work:
if(deposited >= winScore && timeLeft >= 0)
{
//Player wins
timeLeft=0;
Nope, it goes to zero and i win/lose the game fine but I am not able to win the game by collecting the required items before the timer finishes the countdown, even with your codes :( $$anonymous$$ight have to find a way around somehow...
Ah, I see. The problem is that you can't actually win the game right? From collecting the items?
Yes, i can't win the game from collecting the items. I have to wait for the timer to finish to win. I would ideally like to win the game upon depositing the collected items in the deposit area before the timer reaches zero. I am all ears though, please let me know what's best to do. Thank you so much for your help!
Answer by Graham-Dunnett · Jan 06, 2015 at 12:57 PM
Add after line 114:
if (deposited >= winScore)
timeleft = 0;
Now, when orbs are deposit and Deposit()
gets called you'll artificially change the time. The function CheckTime()
checks the time every second, so next time it runs it'll think the time has ended, so it'll call EndGame()
. The first thing EndGame()
does is to check the number of deposited orbs, so the player will see they have won.
Hello! Thank you so much for your reply, but it doesn't seem to be working. Do you think an OnTrigger script with the DepositArea collider would work better? Just don't know how to write it down.
Your answer
Follow this Question
Related Questions
Countdown Timer 1 Answer
Get the device IP address from Unity 3 Answers
iOS and Android native share dialog 3 Answers
windows to ios? 1 Answer