3

I am trying to create a ping pong game and I need to say "If the user doesn't press space within 500 milliseconds, say 'You lost!' And if not, send the ball flying toward the other end."

The problem is that I can't use a function like Sleep() in if statements like:

if (Sleep(500)) {cout << "You lost!"}

Is there any time function that I could use in an if statement?

NathanielSantley
  • 299
  • 1
  • 16

2 Answers2

3

No.

You're programming at a lower level than a language with simple expressions to define rules like this.


Some ideas

Fundamentally, you're going to need to:

  1. Set up a timer for 500ms
  2. Set up a handler for keypresses
  3. Have your timer expiry handler say "You lost" if a boolean flag is set, or otherwise "send the ball flying into the net".
  4. Have your handler toggle that boolean flag if the keypress was Space

At a very basic level you could achieve this:

  • directly with two worker threads, or
  • crudely just by "waiting" for keypress activity (select, poll, epoll come to mind) with a timeout parameter (and ensure you don't reset the timeout if some other key were pressed instead), or
  • with help from your operating system, using e.g. a POSIX timer (though be cautious; this will send you into platform-specific, C-compatible land, which is probably not where you ultimately want to end up).

Usually, though, to do things "properly", we'd embed this logic into functionality provided by some engine implementing an "event loop" (particularly common in games, or in I/O-heavy applications).

Further information is going to take a book to explain adequately, and is thus not really appropriate in this medium. However, at least now you know which topics to explore in existing material.


Potentially interesting anecdote

I once wrote a little scripting language for my application, so that I could just define neat, high-level rules and the "compiler" would make use of my event loop to implement them. It made maintenance and expansion of my application really easy, which was important at the time because the rules became fairly complex and the application was broad in scope. It's not uncommon for computer game engines to embed scripting abilities of their own (say, using the "Lua" language), to achieve the same goal.

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
  • Nice entry into a very large subject. – NathanOliver May 02 '17 at 18:44
  • @NathanOliver: Thank you; I often find myself wishing there were a canonical Q&A for this kind of query. – Lightness Races in Orbit May 02 '17 at 18:47
  • That's a great answer, but I still have no clue on how to do a lot of that (I've only been doing C++ for a year). Can you explain to me how to do this? – NathanielSantley May 02 '17 at 18:47
  • @NathanielSantley: Then I think that you should work on something simpler first, and get to this kind of thing later in your studies (though, to be honest, after a year it's probably time to graduate!). As I already said, teaching you how to write event-driven programs in C++ is far too big a topic for this format. Good luck! – Lightness Races in Orbit May 02 '17 at 18:48
  • Hmmm.... I suppose this is a very advanced topic. I suppose I'll concentrate on something like this when I'm deeper into the language. Thank you so much for all your help though! :) – NathanielSantley May 02 '17 at 18:50
2

It's good to start thinking about your game design as a whole from the beginning as it helps solve problems like this in the design phase rather than further into development.

I'm not sure what library you're using but in sfml it would look something like this:

// Clock holds the current time.
// When we call Restart it returns the elapsed time since the last restart.
// With the current time and the start time we can find the elapsed time.    
sf::Clock clock;
sf::Time maxTime = sf::milliseconds(500);
while(window.isOpen())
{
    clock.Restart();
    while(window.PollEvents(sf::Event e))
    { 
        if(e.type == sf::Event::KeyPressed)
        {
            if(e.key.code == UP || e.key.code == DOWN || e.key.code == AnyOfOurOtherKeys)
            {
                maxTime = sf::milliseconds(500);
            }
            if(e.key.code == UP)
            {
                // Handle each individual key
            }
            if(e.key.code == DOWN)
            {
                // Handle each individual key
            }
            etc..
        }
        maxTime -= clock.Restart();
        if(maxTime < sf::milliseconds(0))
        {
            std::cout << "Game Over, no input detected for 500 ms" << std::endl;
        }
    }

Regardless of library you can always use std::chrono::high_resolution_clock, std::chrono::milliseconds and std::chrono::duration to achieve the same results.

When you do your game loop you want to get the startLoopTime and then at the end of the game loop you want your endLoopTime. You can then do:

totalLoopTime = endLoopTime - startLoopTime;
maxTime -= totalLoopTime;

When you handle input you want a system where if a key that has a function is used, you set the maxTime back to 500ms. You could alternatively set a bool to true when a key is pressed and then run a check on the bool to restart maxTime.

Omar Martinez
  • 708
  • 6
  • 19