How to avoid timer stacking - c

I'm sorry if his question has already been asked in some way.
I'm currently re-writing a vibration driver in a Linux kernel. The reason why I changed it was due to overly strong vibrations caused by gaining a specific velocity of the vibration motor. To work that around I've implemented a PWM like controller that simply stops the motor at a specific time before reaching it's max acceleration, finally it keeps repeating this action.
There is one big issue that is mainly noticeable when using the keyboard. If the vibrator gets toggled too often in a very short time, the timer tends to stack up times, causing lag and vibration delays. This flaw can be easily achieved when typing multiple keys at once.
To demonstrate you this event visually I created a small graph.
The red area indicates timer overlap. The overlap between vibration 1 and 2 causes a delay for the second vibration, moving it out of place.
My main idea to prevent this issue is to merge vibrations into one if the previous vibration hasn't finished yet. For instance vibration 2 would simply join vibration 1.
Another way would be to simply use a single vibration for stacked vibrations, for instance, vibration 2 could simply use the last remaining bit of vibration 1. Why would this work? Well because the vibration controller that I've implemented only applies to times under 100ms, meaning vibration time differences would not be noticeable if one was to spam to keystrokes at once, instead both keystrokes should form and share single vibration.
Finally to my question, how could I make a function check itself it it's being called again. Or at least add a time for the function to check if keystrokes are being spammed multiple times in a short period?

int foo ()
{
static foo_counter;
if(foo_counter)
{
// If function has been called again
}
return(0);
foo_counter++;
}

Related

Is there a way to render my Termbox game and handle keyboard events in the same loop?

I'm having issues with my termbox program rendering the screen and handling keyboard events. Recently, I've finished a C and C++ class at my university. I wanted to demonstrate my knowledge by creating a basic Snake game. The first steps, I wanted to get a simple render loop going and have a block of text simply move leftward and exit the game upon reaching the 0th x-coordinate. The issue arises when continuing to the next render frame, because the game is running single-threaded the next frame won't be rendered until a new keyboard event is accepted. Ordinarily, I would expect the game to continue rendering regardless of events, new events affecting the new frame.
As for potential solutions, I thought about using multiple threads to run the game loop and handle keyboard events. But, I think this would be overkill for such a small problem, there are likely easier alternatives than having to manage multiple threads for a simple snake game.
As for the code, it's as simple as:
while (1)
{
tb_clear();
draw(gameState);
tb_present();
struct tb_event event;
tb_poll_event(&event);
if (event.ch == 'q')
break;
}
After digging through the header file a bit more I found a method which doesn't wait forever.
/* Wait for an event up to 'timeout' milliseconds and fill the 'event'
* structure with it, when the event is available. Returns the type of the
* event (one of TB_EVENT_* constants) or -1 if there was an error or 0 in case
* there were no event during 'timeout' period.
*/
SO_IMPORT int tb_peek_event(struct tb_event *event, int timeout);

Timer to represent AI reaction times

I'm creating a card game in pygame for my college project, and a large aspect of the game is how the game's AI reacts to the current situation. I have a function to randomly generate a number within 2 parameters, and this is how long I want the program to wait.
All of the code on my ai is contained within an if statement, and once called I want the program to wait generated amount of time, and then make it's decision on what to do.
Originally I had:
pygame.time.delay(calcAISpeed(AIspeed))
This would work well, if it didn't pause the rest of the program whilst the AI is waiting, stopping the user from interacting with the program. This means I cannot use while loops to create my timer either.
What is the best way to work around this without going into multi-threading or other complex solutions? My project is due in soon and I don't want to make massive changes. I've tried using pygame.time.Clock functions to compare the current time to the generated one, but resetting the clock once the operation has been performed has proved troublesome.
Thanks for the help and I look forward to your input.
The easiest way around this would be to have a variable within your AI called something like "wait" and set it to a random number (of course it will have to be tweaked to your program speed... I'll explain in the code below.). Then in your update function have a conditional that waits to see if that wait number is zero or below, and if not subtract a certain amount of time from it. Below is a basic set of code to explain this...
class AI(object):
def __init__(self):
#put the stuff you want in your ai in here
self.currentwait = 100
#^^^ All you need is this variable defined somewhere
#If you want a static number as your wait time add this variable
self.wait = 100 #Your number here
def updateAI(self):
#If the wait number is less than zero then do stuff
if self.currentwait <= 0:
#Do your AI stuff here
else:
#Based on your game's tick speed and how long you want
#your AI to wait you can change the amount removed from
#your "current wait" variable
self.currentwait -= 100 #Your number here
To give you an idea of what is going on above, you have a variable called currentwait. This variable describes the time left the program has to wait. If this number is greater than 0, there is still time to wait, so nothing will get executed. However, time will be subtracted from this variable so every tick there is less time to wait. You can control this rate by using the clock tick rate. For example, if you clock rate is set to 60, then you can make the program wait 1 second by setting currentwait to 60 and taking 1 off every tick until the number reaches zero.
Like I said this is very basic so you will probably have to change it to fit your program slightly, but it should do the trick. Hope this helps you and good luck with your project :)
The other option is to create a timer event on the event queue and listen for it in the event loop: How can I detect if the user has double-clicked in pygame?

How do I reliably pause the state of a game?

So I have a couple instances where I want to be able to 'freeze' the state of my game. It's a top-down scroller, and I want to give the player the ability to pause the scrolling of the screen for a short time by using a powerup (if you fall to the bottom of the screen you die). I also want to pause the game as it is starting, and draw a 3, 2, 1, go! to give the player time to get ready, because right now as soon as you hit play, the screen starts scrolling.
I have been using Timer to accomplish this, however it doesn't work if I want to freeze the screen on consecutive occasions. Like if a player uses a freeze, the screen sucesssfully freezes, but if they quickly use another freeze, it doesn't work. There seems to be an unintended cool-down. I have a similar problem for the 'intro delay' I explained earlier. For some reason it only works on the first 2 levels. Here is how I am using Timer.
if(gameState != STATE.frozen) {
camera.translate(0, (float) scrollSpeed);
staminaBar.setPosition(staminaBar.getX(), (float) (staminaBar.getY()+scrollSpeed));
staminaMeter.setPosition(staminaMeter.getX(), (float) (staminaMeter.getY()+scrollSpeed));
healthBar.setPosition(healthBar.getX(), (float) (healthBar.getY()+scrollSpeed));
healthMeter.setPosition(healthBar.getX(), (float) (healthMeter.getY()+scrollSpeed));
boostBar.setPosition(boostBar.getX(), (float) (boostBar.getY()+scrollSpeed));
boostMeter.setPosition(boostMeter.getX(), (float) (boostMeter.getY()+scrollSpeed));
screenCeiling += (float) scrollSpeed;
screenFloor += (float) scrollSpeed;
}
else {
Timer.schedule(new Task() { //freeze the screen for 5 seconds
#Override
public void run() {
gameState = STATE.playing;
}
}, 5);
}
From what I understand, it waits 5 second before resuming the game to the 'playing' state. But like I said, this only works when activated between large intervals and I don't know why. Is there a better way I can be doing this?
As for the intro delay, this may be a question better asked seperate, but I use the same method, but it doesn't let me draw sprites over my tiledmap, so if anyone knows how to do that please include it in your response
Assuming the code you posted is in your render loop, then whenever you are not in the frozen state, you are creating a new timer task on every frame. So if you freeze for 5 seconds and your game is running at 60fps, you will create 300 timer tasks, each of which is going to force the game to go back to playing state. The last one won't fire until 5 seconds after the first one fires, so there will be a five second "cooldown" during which you cannot change the state to anything besides playing, because there will be another timer task firing on every frame during that time.
You need to ensure that you only create one timer task, only when you first enter frozen state.
I do have a suggestion...instead of using a state to freeze the game, use a variable that's multiplied by scrollSpeed. Change that variable from one to zero when the player uses the powerup. Then you can do fancy stuff like quickly interpolating from one to zero so the speed change isn't so abrupt. And it will probably make your code simpler since there would be one less state that must be handled differently in the algorithm.
Check your gameState variable in the render method and if the game is playing, then update the game as usual and draw it.
If the game is not playing then skip the game's update method and create a time delay from the current time:
endTime = TimeUtils.millis()+5000;
Then each time through the render method check to see if current time is greater than the end time. When the current time is past your delay time, set gameState back to playing and have the game go back to updating.
You'll have to have another boolean flag so you only set the endTime once (you don't want to keep resetting this each time through the render loop), or if "STATE" is an enum, then include an option for "justPaused" for the exact frame that you pause the game, set the end time, then set STATE to "notPlaying".
You can also use this to create an alternative "update" method where you can update your countdown sprites, but not update the game itself. When the game is playing this other update method will be skipped.

Implementing pacman in c, ghost movement

I am creating a pacman in c and currently I am usisng a single thread for each ghost and each ghost represents a '#' but when I run it all the screen gets full of ghosts and not all the ghosts move just one or two.
Im using this logic
create a struct of 5 ghost, each ghost contains the x,y position.
create an array of 5 threads and each thread implements one ghost
each ghost moves randomly on the screen, for each space that it moves I print
a space in the old position and then I print a '#' in the new position.
Could you provide me please an example of how to implement the movement of the ghost,
or the implementation Im doing is the correct way?
Thank you
One thread per agent is not a very common approach to building games. It quickly becomes unworkable for large scenes. The conventional solution is to define a state machine representing a ghost, with some kind of "advance" method that gives it a chance to adjust its internal state to the next time quantum. Create multiple instances of this state machine, and call all their "advance" methods on each iteration of the game loop. All of this can happen in a single thread.
There's quite a bit more to it than this, but it'll get you started.
Trying to update the screen simultaneously from several threads requires a mutex around the screen update code.

On creating expensive WPF objects and multithreading

The classic advice in multithreading programing is to do processor heavy work on a background thread and return the result to the UI thread for minor processing (update a label, etc). What if generating the WPF element itself is the operation which is expensive?
I'm working with a third party library which generates some intense elements, which can take around to 0.75s - 1.5s to render. Generating one isn't too bad, but when I need to create 5 of them to show at once it noticeably locks the UI (including progress spinners). Unfortunately, there isn't any other place to create them because WPF is thread affine.
I've already tried DispatcherPriority.Background but its not enough. What is the recommended way to deal with this problem?
If the objects being created derived from Freezable, then you can actually create them on a different thread than the UI thread - you just have to call Freeze on them while you're on the worker thread, and then you can transfer them over. However, that doesn't help you for items that don't derive from Freezable.
Have you tried creating them one at a time? The following example doesn't do any useful work but it does show how the basic structure for doing a lot of work in little bits:
int count = 100;
Action slow = null;
slow = delegate
{
Thread.Sleep(100);
count -= 1;
if (count > 0)
{
Dispatcher.BeginInvoke(slow, DispatcherPriority.Background);
}
};
Dispatcher.BeginInvoke(slow, DispatcherPriority.Background);
The 'work' here is to sleep for a tenth of a second. (So if you replace that with real work that takes about as long, you'll get the same behaviour.) This does that 100 times, so that's a total of 10 seconds of 'work'. The UI remains reasonably responsive for the whole time - things like dragging the window around become a bit less smooth, but it's perfectly usable. Change both those Background priorities to Normal, and the application locks up.
The key here is that we end up returning after doing each small bit of work having queued up the next bit - we end up calling Dispatcher.BeginInvoke 100 times in all instead of once. That gives the UI a chance to respond to input on a regular basis.

Resources