I'm building a simple console game, there is the player who moves when key press down, and there are enemies which moves automatically, each type of enemy moves one time in X miliseconds.
As I understood I should using the timer, but I don't really know how to do that in the game loop (isn't built yet because I don't know how to do with the timer. but it should be while loop I think). the game ends when the enemy 'touch' the player (same x and y).
One important thing: I can't you in this exercise in Thread, but if you have other suggestions instead of using Timer you are welcome.
Thank you.
You normally don't use conventional timers in games. Games have a very different mechanism for handling their logic and the time that passed, they normally don't work with timers or not in the way you would expect:
Games normally have something called a game loop. Generally speaking it's three main functions that are called one after the other in a loop:
while(running)
{
HandleUserInput();
ChangeWorld();
Render();
}
You get user input, you change the game world accordingly and you draw it to the screen. Now, the faster your computer is, the faster this loop runs. That's good for the graphics (think FPS), but bad for the game. Imagine Tetris where every frame the blocks move. Now I would not want to buy a faster computer, the game would get more difficult that way.
So to keep the game speed constant independent of the power of the computer, the loop considers the time passed:
while(running)
{
var timePassedSinceLastLoop = CalculateTimeDelta();
HandleUserInput();
ChangeWorld(timePassedSinceLastLoop);
Render();
}
Now imagine a cooldown for something in game. The player pressed "a", some cool action happened and although he may press "a" again, nothing will happen for the next 5 seconds. But the game still runs and does all the other things that may happen ingame. This is not a conventional timer. It's a variable, lets call it ActionCooldown, and once the player triggers the action, it's set to 5 seconds. Every time the world changes, the timePassed is subtracted from that number until it's zero. All the time, the game is running and handling input and rendering. But only once ActionCooldown hits zero, another press of "a" will trigger that action again.
The ChangeWorld method includes all automatic changes to the world. Enemies, missiles, whatever moves without player interaction. And It moves based on time. If the enemy moves one square per second, You need to make his coordinate a float and add a fraction of a square every time the loop is run.
Lets say you have 30 fps so your loop runs 30 times a second. Your enemy now needs to move 1/30 of a square each loop. Then it will in the end have moved one full square per second.
The general premise behind the timer is to repeat some code every n.
To create the timer use this:
System.Timers.Timer aTimer = new System.Timers.Timer();
aTimer.Elapsed+=new ElapsedEventHandler(OnTimedEvent);
// Set the Interval to 1 millisecond. Note: Time is set in Milliseconds
aTimer.Interval=1;
aTimer.Enabled=true;
Then you implement this method:
private static void OnTimedEvent(object source, ElapsedEventArgs e)
{
//Whatever you need repeated
}
The full example can be found here:
http://msdn.microsoft.com/en-us/library/system.timers.timer(v=vs.71).aspx
Related
I am creating a rythm VR game for google cardboard, inspired by Beat Saber on PSVR and Oculus Rift.
The concept is that blocks with different directions come at you, following the rythm of the music, just like in Beat Saber.
For every music I have created a ScriptableObject called music, with every parameter it should contain like the difficulty of the song, the name, etc. but also an array of Vector3 called notes : the first float of the Vector corresponds to the time the note should be beaten in the rythm of the music starting from 0: ScriptableObject
Then in a script called SlashSpawnManagement, where every thing is based on WaitForSeconds(), I spawn the blocks to smash. It's realy hard for me to explain wih words the order I do it in, so here is an image : Explanation
In theory, what this script does, it waits for some time, spawns a block, waits for some time, spawn a block, etc. The logic seems okay, but here's the weird part. As you play the song the distance between each block gradually becomes bigger and bigger, meaning the blocks become more and more out of sync with the music. It starts very well, but at the end of the music there is at least a 5s gap.
I figured it has something to do with the frame rate drop, so I tried to set the frameRate to something low with :
QualitySettings.vSyncCount = 0; // VSync must be disabled
Application.targetFrameRate = 30;
But it doesn't solve the problem. I tried with WaitForSecondsRealtime instead of WaitForSeconds, but nothing changes. I have read somewhere that WaitForSeconds depends on the frame rate... Where I calculated the time, I tried sustractng h divided by a number to even out the gradual gap. This works for some blocks but not every block: Notes[j][0] - h / 500
So here's my question, how do I make the WaitForSeconds, or any other method consistent with the seconds provided ?
Thank you In advance,
PS : For more clarifications, please ask and please forgive my typos and my english :)
If you want something to happen in regular time intervals, it is important to make sure that errors don't accumulate.
Don't:
private IEnumerable DoInIntervals()
{
while (this)
{
yield return new WaitForSeconds(1f); // this will NOT wait exactly 1 second but a few ms more. This error accumulates over time
DoSomething();
}
}
Do:
private IEnumerable DoInIntervals()
{
const float interval = 1f;
float nextEventTime = Time.time + interval;
while (this)
{
if (Time.time >= nextEventTime)
{
nextEventTime += interval; // this ensures that nextEventTime is exactly (interval) seconds after the previous nextEventTime. Errors are not accumulated.
DoSomething();
}
yield return null;
}
}
This will make sure your events happen in regular intervals.
Note: Even though this will be regular, it does not guarantee that it will stay in sync with other systems like audio. That can only be achieved by having a shared time between systems, like spender mentioned in his comment on your question.
Trying to use WaitForSeconds the timing of audio and hope for the best is hoping a big hope.
Have a list of Vector3s prepared in advance. If you want to prepare the list using the rythm - it will work. Use AudioSource's time to check every Update whether the timing is right and spawn a block at that moment.
void Update () {
SpawnIfTimingIsRight();
}
void SpawnIfTimingIsRight() {
float nextTiming = timingsArray[nextIndex].x;
// Time For Block To Get To Position
float blockTime = this.blockDistanceToTravel / this.blockSpeed;
float timeToSpawnBlock = nextTiming - blockTime;
if (this.audioSource.time >= nextTiming && (this.audioSource.time - Time.deltaTime) < nextTiming) {
// Spawn block
}
}
I am creating an arena style battle game in Unity and I am having a problem with respawning players. Here's how it works right now.
When a player is killed it is put into a list of killed players to be respawned and it's player object is destroyed. The game then loops thru the list of killed players and selects a random available spawn point then respawns the player there. An available spawn point is any spawn point that is not triggered by a player being inside it's spawn area.
The problem comes when 2 players die at the same time, or at least extremely close to the same time and the randomly selected spawn point ends up to be the same because it didn't have enough time to process as triggered. When this happens all of unity crashes and I have to restart it completely.
I assume that in order to fix this, I need to keep Unity from spawning them at the same time, but I thought that would be fixed by looping thru the list. How should I actually go about spawning 2 players that die at the same time more safely?
This is the classic queue example the same thing happens in multi threaded applications. Two things you can do here:
Diversion of concern
Remove the conflict from beginning
In the first method you create an script outside of your player script for example in the arena it self and create a method there to select the next spawning point. This can be ordinal instead of random and each player upon death asks the script to select the next spawning point for it and no conflict over one point.
In the second method each player will have it's own spawning point for example an offset from the spawning points defined in the arena. For example player 1 will have offset zero and spawn right on spawning point then player two will have offset 1 which will spawn 1 unit off of the spawning point.
I prefer the first method if the number of players are limited. If you have many players then the queue might be a bother.
Hope it helps :)
I figured out my problem and I'm able to keep it with random spawn points. The problem didn't apparently have to do with 2 players dying at the same time so much as it had to do with a player dying while on a spawnpoint. When this happens it would not run the OnTriggerLeave() method and therefore would not count as an available spawnpoint even tho nothing was there.
I fixed it by having each spawnpoint hold a list of all the game objects that were triggering it which would change as players entered and exited the space. Then when a player was killed, it would check each spawnpoint's list to see if it contained the player's game object. If it found a match then I untrigger the spawnpoint and it appears as available.
A better approach to this which I am going to do instead is to check the list to see if there are any gameobjects in the spawnpoint's list and it should only be available if there are none. Because the current way doesn't account for other objects also triggering the point.
I'm a beginner programmer just starting out with MonoGame. I was implementing some code for running an animation and came to a problem I don't know how to solve. This is the code I used in my AnimationManager class:
public void Update(GameTime gameTime)
{
timeElapsed += (float)gameTime.ElapsedGameTime.TotalSeconds;
if (timeElapsed > timeToUpdate)
{
timeElapsed -= timeToUpdate;
//Tried to just reset timeElapsed to zero, still doesn't work
//timeElapsed = 0;
if (frameIndex < rectangles.Count -1)
{
frameIndex++;
}
else if (isLooping)
{
frameIndex = 0;
}
}
}
The problem is I animate at 24 frames per second and when the game runs at 60 or 30 fps and on each update code checks is it time to draw a new frame of animation, you get some remainder of frames, because you tried to draw 24 images per second, evenly, with 30 even game frames per second. So there's that remainder of 6 frames. The result of this is that approx 6 frames of animation gets drawn twice, some are skipped a whole animation gets about 25% longer. Is there a way to fix this? Can I maybe move this code to Draw call and then cap just the draw calls at 48 fps for 60 fps game, so each animation frame will be drawn at every second draw call. I don't know how would I go about doing this if it's a reasonable solution at all?
And how will VSync affect all of this at the end. Will it mess up animation frames, even if this problem is solved.
EDIT: forgot to say it's a 2d game, hand drawn animation.
Generally when you're doing this kind of stuff you don't need to worry about VSync or the fact that your game runs at 60 or 30 fps. That's all pretty much irrelevant.
The thing that matters is that you know the desired frames per second of your animation and how long it takes for a single game frame.
From that you can calculate the length of time in a single animation frame. For example, you'd end up with something like this:
var animationFrameTime = 1f / 24f; // 24 frames per second
So far so good.
The next thing you need to do is to start accumulating time somewhere. There's a few different ways to think about this. I like to think about it in terms of how much time is left until the next frame.
var gameFrameTime = (float)gameTime.ElapsedGameTime.TotalSeconds;
timeUntilNextFrame -= gameFrameTime;
Then you need to increment the frameIndex when you've run out of frame time.
if(timeUntilNextFrame <= 0)
{
frameIndex++;
timeUntilNextFrame += animationFrameTime;
}
Notice the important bit here. I've added the animationFrameTime to the timeUntilNextFrame. This way, if there's any left over time from the previous frame, it'll get added to the next frame, keeping the animation smooth.
There's really not much more to it than that. I've left out the rectangles.Count and isLooping bits, but it should be easy enough to add those back in. You might also want to initialize timeUntilNextFrame to animationFrameTime for the first frame.
Just a word of warning with this code, if the game is running slowly for some reason (or perhaps it's paused maybe) the gameFrameTime might end up having a very large value causing some strange behavior. I'm not entirely certain if that can ever happen in MonoGame / XNA but it's worth considering at least.
It turned out this is a well known problem. Basicaly its mathematicaly imposible to jam 24 animation fps in 30 game fps because they are not independent from each other. Interpolation is the only way to fix this problem. It's the same thing that's being done whenever you watch 24 fps movie on a 60 hz monitor.
https://en.wikipedia.org/wiki/Three-two_pull_down
i have the following issue in my code,
i have this loop running on timer (this is just a small part of the loops that running on the big timer),
inside that big timer (he tick every 1 second) i have 1 method that need to wait 5 second then continue with the the rest of the loop code, but i want that it wont stuck the code and the timer will continue to run every 1sec and wont wait for those 5sec.
what i did i add a new timer (timer_deva) that tick every 5sec and did all the checks inside it, and then timer stops.
so my issue is that i need to wait 5sec to retrieve a value to complete my code, but i need that my main timer will keep running simultaneously, and when he get his result for the other time he will need to complete the code he left behind.
thanks in advance,
else if (mobID.Equals(Convert.ToInt32(txtDeva)))
{
//START CHECK WITH TIMER
timer_deva.Start();
//Methods inside timer_deva update the winnerNation
//END CHECK TIMER - GET RESULT
winner(zoneId, winnerNation, humansKills, orcKills);
}
tl;dr
Conventional Timers are not used in games. Games have a very different mechanism for handling their logic and the time that passed.
Long Version:
I know this may not answer your question directly, but it's way to much text to cramp into a comment. Your timers sound very complicated and hierarchical. From your variable names I will assume you are programming a game. Games normally don't work with timers or not in the way you would expect. This different game-like behaviour would help you a lot in your timers problem and may even help you more with your design in general.
Games normally have something called a game loop. Generally speaking it's three main functions that are called one after the other in a loop:
while(running)
{
HandleUserInput();
ChangeWorld();
Render();
}
You get user input, you change the game world accordingly and you draw it to the screen. Now, the faster your computer is, the faster this loop runs. That's good for the graphics (think FPS), but bad for the game. Imagine Tetris where every frame the blocks move. Now I would not want to buy a faster computer, the game would get more difficult that way.
So to keep the game speed constant independent of the power of the computer, the loop considers the time passed:
while(running)
{
var timePassedSinceLastLoop = CalculateTimeDelta();
HandleUserInput();
ChangeWorld(timePassedSinceLastLoop);
Render();
}
Now imagine a cooldown for something in game. The player pressed "a", some cool action happened and although he may press "a" again, nothing will happen for the next 5 seconds. But the game still runs and does all the other things that may happen ingame. This is not a conventional timer. It's a variable, lets call it ActionCooldown, and once the player triggers the action, it's set to 5 seconds. Every time the world changes, the timePassed is subtracted from that number until it's zero. All the time, the game is running and handling input and rendering. But only once ActionCooldown hits zero, another press of "a" will trigger that action again.
A simple draw and move simulation uses the following:
A clock timer. Interval: 200ms.
A movement timer. Interval: 1ms.
Movement Constant. Value: 2.
Every time the movement timer ticks, a picture moves by addition by the movement constant. (i.e. picture.X = picture.X + movement constant)
The problem is fast forwarding. The user CAN fast-forward the simulation at any time.
How do I change theses three values (clock timer, movement timer, movement constant) to make the simulation speed faster without sacrificing integrity during a fast-forwarded run?
If integer multiples (1x, 2x, 3x, ...) for fast forwarding is enough, you could just run the simulation function several times during the timer handler function.
I'm not sure what you're doing with the clock timer though, but the same principle would apply to whatever it's doing.
You can have an "internal time" that's independant of the "real time". When the system runs at the base speed, these two increase in sync (every tick of the timer - that's set to 1 ms - adds 1ms to the internal time.
When you have a speedup multiplier of 2x, then add 2ms to the internal time for every timer tick.
Next you will have to calculate positions based on the internal time, with maybe a function like
newposition = startposition + speed * time
As Hans implied, there is a 'grain-size' in time and space in most simulations. Agents are then scheduled by skipping over time intervals ('ticks'). However, if you need more flexible and well-tested scheduling, you might want to borrow a scheduler from an ABM simulation package such as Mason (for Java) or Repast (Java or C++), or look at their open-source scheduler class codes and translate to another language.