Creating a timer in Monogame. Creating an event after 5 seconds - c#

I have some troubles with creating a timer for my c# monogame. I already red the other timer questions on stack overflow, but I didn't get it.
I want to collect gold in my mine. But the gold is limited, every 5 seconds there should be new gold.
I tried to do it like How to create a timer/counter in C# XNA
But it isn't working. I get a System.NullReferenceException. Is there a better way to do a timer? Or how can I fix the Exception?
Here is the most important part of my code:
private GameTime gameTime;
int counter = 1;
int limit = 50;
float countDuration = 10f; //every 2s.
float currentTime = 0f;
private void CollectGold(ObjectFactory.ObjectType type)
{
currentTime += (float)gameTime.ElapsedGameTime.TotalSeconds; //Time passed since last Update()
if (currentTime >= countDuration)
{
counter++;
currentTime -= countDuration;
// maxGold limits the Mine
if (mMaxGold > 0)
{
mGold += 5;
mMaxGold -= 10;
}
}
}

thank. I did it. Just assign the value of GameTime wrong. Didn't know that it have to be in an update function. Thanks.

Related

Deplete set value every X second in Update method

I'd like to deplete value of health from set value every 1 second in Update method. I wrote the code, but it seems like it depletes faster than 1 second.
In an Update method, I call:
if (Hunger <= 0.0f)
{
userHealth -= HealthDepletionValue * Time.deltaTime;
}
Which should deplete set value of HealthDepletionValue every second Time.deltaTime.
When I run the game, it depletes HealthDepletionValue every 0.1 second or something along those lines. But surely not every 1 second, like I want to.
Did I miss something?
As stated in this post, Update() runs once per frame. So if you're game is running 30 frames/second, then Update() will execute 30 times/second.
To specify a function to be executed every x seconds, you can use InvokeRepeating. To do this, put the logic you want executed every second into it's own method:
void DepleteHealth()
{
if (Hunger <= 0.0f)
{
userHealth -= HealthDepletionValue * Time.deltaTime;
}
}
And then in the Start() method, call InvokeRepeating, passing in your method name and the number of seconds between execution of said method:
void Start()
{
InvokeRepeating("DepleteHealth", 1.0f, 1.0f);
}
The post above also shows alternative ways to handle this. Including tracking a second counter within the Update() method, to ensure that you're logic is only executed if the counter has passed a full second.
Another option to InvokeRepeating would be to create your own timer.
float timer = 0;
Update()
{
if (Hunger <= 0.0f)
{
timer += time.deltaTime;
if (timer > 1f){
userHealth -= HealthDepletionValue;
timer = 0; //reset timer
}
}
}
Alternatively you could use a Coroutine and the WaitForSeconds class.
public void Start () {
StartCoroutine(DepleteHealth(TimeSpan.FromSeconds(1), 5));
}
public IEnumerator DepleteHealth (TimeSpan frequency, int loss) {
var wait = new WaitForSeconds((float)frequency.TotalSeconds());
while(true) {
userHealth -= loss;
yield return wait;
}
}
This can be stopped and started pretty easily.

Decrease variable over a specific amount of time

So when my character gets hit by the enemies fire breath, I want to create the feel of the character being set on fire. So while the character is on fire I want him to lose a specific amount of health for a specific amount of time.
For example; lets say he is on fire for 3 seconds and I want to make him lose 30 health for being on fire, how would I evenly distribute losing 30 health for 3 seconds? I dont want the 30 damage to be applied instantly to the health, I want it to slowly tick away at the players health so that at the 3 second mark 30 damage has been dealt.
The game is being made with c#.
Thanks.
This is just like moving Gameobject over time or doing something over time. The only difference is that you have to use Mathf.Lerp instead of Vector3.Lerp. You also need to calculate the end value by subtracting the value you want to lose over time from the current value of the player's life. You pass this into the b or second parameter of the Mathf.Lerp function.
bool isRunning = false;
IEnumerator loseLifeOvertime(float currentLife, float lifeToLose, float duration)
{
//Make sure there is only one instance of this function running
if (isRunning)
{
yield break; ///exit if this is still running
}
isRunning = true;
float counter = 0;
//Get the current life of the player
float startLife = currentLife;
//Calculate how much to lose
float endLife = currentLife - lifeToLose;
//Stores the new player life
float newPlayerLife = currentLife;
while (counter < duration)
{
counter += Time.deltaTime;
newPlayerLife = Mathf.Lerp(startLife, endLife, counter / duration);
Debug.Log("Current Life: " + newPlayerLife);
yield return null;
}
//The latest life is stored in newPlayerLife variable
//yourLife = newPlayerLife; //????
isRunning = false;
}
Usage:
Let's say that player's life is 50 and we want to remove 2 from it within 3 seconds. The new player's life should be 48 after 3 seconds.
StartCoroutine(loseLifeOvertime(50, 2, 3));
Note that the player's life is stored in the newPlayerLife variable. At the end of the coroutine function, you will have to manually assign your player's life with the value from the newPlayerLife variable.
I suppose, what you are looking for is a Coroutine. Check out here and here for the documentation. It will allow you to do your custom health reducing actions separately from update function. Using coroutines you can make something happening by ticks, and you can determine how much time the tick is.
You could use couroutines. Something like this:
void OnHitByFire()
{
StartCoroutine(DoFireDamage(5f, 4, 10f));
}
IEnumerator DoFireDamage(float damageDuration, int damageCount, float damageAmount)
{
int currentCount = 0;
while (currentCount < damageCount)
{
HP -= damageAmount;
yield return new WaitForSeconds(damageDuration);
currentCount++;
}
}
So this is what I ended up doing. It causes the character on fire to lose 30 health and you can see the health ticking down instead of it happening over intervals.
IEnumerator OnFire()
{
bool burning = true;
float timer = 0;
while (burning)
{
yield return new WaitForSeconds(0.1f);
hp -= 1;
timer += 0.1f;
if (timer >= 3)
{
burning = false;
}
}
}

Cooldown timer for an incremental game

I'm trying to make a game in unity (which uses c#) and what I am trying to accomplish is almost identical to what is done in the game Adventure capitalist. When you click on one of the companies, there is a "cooldown" timer. I put that in quotations because you don't get the money until after the timer has finished. I have looked at the other suggested questions and have managed to create the code below
public UnityEngine.UI.Text showCurrency;
public int money = 0;
public int moneyPerClick = 1;
public float timeToCollect = 3.0F;
private float timeStamp;
private bool buttonClicked;
void Start()
{
timeStamp = Time.time + timeToCollect;
}
void Update()
{
showCurrency.text = "Money: " + money;
if(buttonClicked && timeStamp > 0.0F)
{
timeStamp -= Time.time;
}
if (timeStamp == 0.0F)
{
money += moneyPerClick;
}
}
public bool Clicked()
{
buttonClicked = true;
return buttonClicked;
}
I currently get 1 error but that started happening after I added the showCurrency.text = "Money: " + money; part. So that needs to be fixed.
The code, as far as I can tell, it not working. I don't have the cooldown effect working with the image fill (which will be a problem for another day) So I can't actually see if the timer is counting down, but I guess I could have a Debug.Log and have a system.out line to test that. The other thing that isn't working is I'm not getting the new money amount to show up on screen.
This code is a beginners best guess at how it would be layed out and it is where I'm at. If it looks like I am using the methods wrong, that's probably because I am. Any further information to at least point me in the right direction would be greatly appreciated.
Unity's Update() method gets called every frame. So if you have the game set to 30 FPS, then Update() will get called 30 times every second.
Firstly, timeStamp -= Time.time subtracts the current time from your stored time every single frame (it gets to be a realllly small number really fast). As you have it, try changing your second if statement to an inequality check instead of checking for equality:
if (timeStamp <= 0.0F)
Alternatively, your Update() function could be simplified to something like this:
void Update()
showCurrency.text = "Money: " + getMoney();/*Make money into a property with a getter and setter, so that it will be easily changeable at run-time*/
if(buttonClicked && (Time.time >= timeStamp))
{
timeStamp = (Time.time + timeToCollect);
setMoney(getMoney() + moneyPerClick);
buttonClicked = false; /*Reset your button to be clickable again*/
/*You could also setup your setMoney() like setMoney(moneyPerClick), but that's not what you asked ;b*/
}
}

How To Create And Display A Timer In XNA Game Studio

I am creating a Board-Game style game in XNA Game Studio. One of the "mini-games" inside of it requires a timer. I have tried various methods but, I am stumped. If anyone can help, I would also like it to be activated by a button. This is the code I have currently:
if (orbStart)
{
int counter = 10;
int limit = 50;
float countDuration = 2f; //every 2s.
float currentTime = 0f;
currentTime += (float)gameTime.ElapsedGameTime.TotalSeconds;
if (currentTime >= countDuration)
{
counter++;
currentTime -= countDuration;
}
if (counter >= limit)
{
//Stuff
}
}
}
OrbStart being the boolean activated by the button. Any help will be great!
Okay, first create global variables, for example:
bool isTimerOn = false;
float counter = 10; // 10 seconds
Then you should change isTimerOn to true when user presses your button, hope you know how to do it. Next step- inside your update method, substract elapsed time from the last tick from counter's value and check whether the time is up:
if (isTimerOn)
{
counter -= gameTime.ElapsedGameTime.Seconds;
if (counter <= 0)
doSomething();
}
Oh, I've noticed you wanted help with your button too. So first of all, you should create a Recentagle inside which your button will be placed:
Rectangle button = new Rectangle(50, 60, 100, 30);
This code means your buttons upper left point is located at (50, 60), it's width is 100 and it's height is 30. You can really read how to drawsprite at this location everywhere, as it was discussed for a couple of times here.
To check whether user clicks our button, just read about how to handle gestures and check whether tap's position is inside our rectangle, here's the code:
while (TouchPanel.IsGestureAvailable)
{
GestureSample gs = TouchPanel.ReadGesture();
switch (gs.GestureType)
{
case GestureType.Tap:
if (button.Contains((int) gs.Position.X, (int) gs.Position.Y))
isTimerOn = true;
break;
}
}
To make it work there's just one more thing- you have to enable tap gesture. Inside LoadContent() method add:
TouchPanel.EnabledGestures = GestureType.Tap;

XNA Elapsed time doesn't update

I am trying to implement a simple counter in my XNA game. Thought this would be simple enough. I have the following code:
elapsed = gameTime.ElapsedGameTime.TotalMilliseconds;
timer -= (int)elapsed;
if (timer <= 0)
{
timer = 10; //Reset Timer
}
But elapsed never changes from 0.0. Am I missing something obvious here? I suspect I am. I have gameTime declared at the top and initialised as usual.
As asked, here is a bit more code:
public class Game1 : Microsoft.Xna.Framework.Game
{
private GameTime zombieTime;
public Game1()
{
zombieTime = new GameTime();
// Other (unrelated) stuff here
}
protected void AddZombie()
{
elapsed = zombieTime.ElapsedGameTime.TotalMilliseconds;
timer -= (int)elapsed;
if (timer <= 0)
{
timer = 10; //Reset Timer
Zombie zombie = new Zombie(ScreenWidth, ScreenHeight, random);
zombie.LoadContent(this.Content, "ZombieSprites/ZombieLeft1");
zombies.Insert(0, zombie);
}
}
protected void Update()
{
AddZombie();
// Other game update stuff here
}
}
I am sorry, I believed the original code snippet would have been enough. I read some pages online where people posted examples of a timer and used the method I have used above. I understand some of the comments made here about the update going fast enough so that elapsed time will always be 0.
You're not using the correct GameTime. zombieTime is never updated by anything so it will always be zero'd out. The GameTime you want to use is passed into the Update() function already for you.
The correct way to do it would be like this:
protected void AddZombie(GameTime gameTime)
{
float elapsed = gameTime.ElapsedGameTime.TotalMilliseconds;
timer -= (int)elapsed;
if (timer <= 0)
{
timer = 10; //Reset Timer
// Rest of stuff goes here
}
}
protected void Update(GameTime gameTime)
{
AddZombie(gameTime);
}
http://msdn.microsoft.com/en-us/library/microsoft.xna.framework.gametime_members.aspx
Elapsed game time is the time since the LAST update. TOTAL game time in the cumulative game time...
So, unless you're doing a lot of work you're not showing, you're gonna be taking no time at all to update, so a value of 0 is quite sensible
try shoving a sleep statement in there and see if elapsed time goes up.

Categories