Pause functionality in game works only once

Started by
19 comments, last by Khatharr 11 years, 2 months ago
The idea was making the gameLoop false to pause the game and unpause the game by making the gameLoop true again. It was able to pause and unpause once before the only way to close the game was to use Eclipse's terminate button instead of the x button in the top corner of the game window.
public class Game extends Canvas implements KeyListener{
private boolean isRunning;
public static void main(String[] args){
getInstance().run();
}
// Singleton pattern get instance
public static Game getInstance(){
if (instance == null){
instance = new Game();
}
return instance;
}
private Game(){
isRunning = true;
}
public void run(){
// basic game loop
while(isRunning){
// draws objects here
}
}
@Override
public void keyPressed(KeyEvent e) {
// TODO Auto-generated method stub
switch (e.getKeyCode())
{
// pause the game
case (KeyEvent.VK_P):
getInstance().setIsRunning(false);
break;
// unpause the game
case (KeyEvent.VK_U):
getInstance().setIsRunning(true);
run();
break;
}
}
}
Advertisement

why are you calling run after you setIsRunning(true)?(now your in a loop inside the input function)

if that's not the problem, idk because you barely posted any real code.

what we need to see is:

Initialization code

--Main game loop(is this controlled by "isRunning", because if so, setting it to false should break the loop.)

---Where you check for input(is this inside your main loop, which is controlled by the "isRunning" flag?)

Check out https://www.facebook.com/LiquidGames for some great games made by me on the Playstation Mobile market.

Paused and unpaused are typically considered game ''states''. Many represent these states as enumerations, but I would generally represent a game state as an object, I have a whole theory behind my own design for how a game state should be represented but it's a bit ''out of the box'' compared to what is generally considered a game state (from my experience). Throwing that out the window for now (it's still in the 'theory' phase that I'm testing in a home engine atm, maybe my theory is entirely bogus), you can typically represent a game state with two functions:


struct IGameState
{
    virtual void update( const UpdateArgs &updateArgs ) = 0;
    virtual void render( RenderArgs &renderArgs ) = 0;
};

If you consider your states as a stack, your normal game state would perform its rendering and update as normal. You could then 'push' a ''paused''' state onto the stack that forwarded the render state up the stack and simply consumed the update state. Which would give you a perfectly working paused state, you could extend this design further with a menu state etc. But the basics remain the same.

I'm not 100% sober atm sorry so please ignore any typo's or weird phrasing, but if there are any queries or questions on that let me know. My current design is much further evolved than this, but this seems like the most simplified to start with, without a huge posting smile.png

n!

why are you calling run after you setIsRunning(true)?(now your in a loop inside the input function)

if that's not the problem, idk because you barely posted any real code.

what we need to see is:

Initialization code

--Main game loop(is this controlled by "isRunning", because if so, setting it to false should break the loop.)

---Where you check for input(is this inside your main loop, which is controlled by the "isRunning" flag?)

because my approach was to pause the game. The only way to do it is to break out of the gameLoop. If I unpause the game, I need to call the run method which execute the game loop to keep things drawing again. the run method needs to be called by the programmer. the key events are in the keyPressed method of the Game class since the Game class will be responsible for controlling the pause/unpause nature of the game.

Are you sure you saw my code? blink.png

Paused and unpaused are typically considered game ''states''. Many represent these states as enumerations, but I would generally represent a game state as an object, I have a whole theory behind my own design for how a game state should be represented but it's a bit ''out of the box'' compared to what is generally considered a game state (from my experience). Throwing that out the window for now (it's still in the 'theory' phase that I'm testing in a home engine atm, maybe my theory is entirely bogus), you can typically represent a game state with two functions:


struct IGameState
{
    virtual void update( const UpdateArgs &updateArgs ) = 0;
    virtual void render( RenderArgs &renderArgs ) = 0;
};

If you consider your states as a stack, your normal game state would perform its rendering and update as normal. You could then 'push' a ''paused''' state onto the stack that forwarded the render state up the stack and simply consumed the update state. Which would give you a perfectly working paused state, you could extend this design further with a menu state etc. But the basics remain the same.

I'm not 100% sober atm sorry so please ignore any typo's or weird phrasing, but if there are any queries or questions on that let me know. My current design is much further evolved than this, but this seems like the most simplified to start with, without a huge posting smile.png

n!

I am coding my game in Java. I don't think C++ OOP will help me since I never touched much of C++ OOP


why are you calling run after you setIsRunning(true)?(now your in a loop inside the input function)

if that's not the problem, idk because you barely posted any real code.

what we need to see is:

Initialization code

--Main game loop(is this controlled by "isRunning", because if so, setting it to false should break the loop.)

---Where you check for input(is this inside your main loop, which is controlled by the "isRunning" flag?)

because my approach was to pause the game. The only way to do it is to break out of the gameLoop. If I unpause the game, I need to call the run method which execute the game loop to keep things drawing again. the run method needs to be called by the programmer. the key events are in the keyPressed method of the Game class since the Game class will be responsible for controlling the pause/unpause nature of the game.

Are you sure you saw my code? blink.png

think about what it means to start an infinite loop inside your input logic thread. and as far as i can see, that infinite loop does not check your input.

so yes, we need to see more code(unless my above assumption is correct, and that is why you can only pause/unpause once)

insead of doing:


void run(void){
  while(isRunning){
  }
}

try:


void run(void){
 while(!isDone){
  if(isRunning){
   //game logic here
  }
}
Check out https://www.facebook.com/LiquidGames for some great games made by me on the Playstation Mobile market.


why are you calling run after you setIsRunning(true)?(now your in a loop inside the input function)

if that's not the problem, idk because you barely posted any real code.

what we need to see is:

Initialization code

--Main game loop(is this controlled by "isRunning", because if so, setting it to false should break the loop.)

---Where you check for input(is this inside your main loop, which is controlled by the "isRunning" flag?)

because my approach was to pause the game. The only way to do it is to break out of the gameLoop. If I unpause the game, I need to call the run method which execute the game loop to keep things drawing again. the run method needs to be called by the programmer. the key events are in the keyPressed method of the Game class since the Game class will be responsible for controlling the pause/unpause nature of the game.

Are you sure you saw my code? blink.png

think about what it means to start an infinite loop inside your input logic thread. and as far as i can see, that infinite loop does not check your input.

so yes, we need to see more code(unless my above assumption is correct, and that is why you can only pause/unpause once)

insead of doing:


void run(void){
  while(isRunning){
  }
}

try:


void run(void){
 while(!isDone){
  if(isRunning){
   //game logic here
  }
}

why is void a parameter and is not given a data type? I posted my game loop below since I cannot longer edit my initial post. smile.png

public void run(){
// basic game loop
while(isRunning){
// calculate the time since the last loop
long milliseconds = System.currentTimeMillis() - lastTick;
lastTick = System.currentTimeMillis();
// set the focus to the panel
panel.requestFocus();
// get graphics context
Graphics2D g = (Graphics2D) strategy.getDrawGraphics();
clearBuffer(g);
// update all game items
for(GameComponent component : gameObjects){
component.update(milliseconds);
}
// handle the dynamic objects
addNewGameComponents();
removeOldGameComponents();
// draw all game items
for(GameComponent component: gameObjects){
component.draw(g);
}
/* do a bounding box collision of the laser with the
* oneEye monster's bounding box every game loop
* which is basically every time the game redraws
* itself.
* Collision test applies to ALL laser being drawn on screen!
*
* The easiest way is to check every instance of type Laser in the
* ArrayList and tell them to do monster collision detection
*/
// laser check for every OneEye monsters in the ArrayList
for(GameComponent component: gameObjects){
if(component instanceof Laser)
{
((Laser) component).checkMonsterCollision(gameObjects);
}
if(component instanceof OneEyeSlashSkill)
{
((OneEyeSlashSkill) component).checkShipCollision(gameObjects);
}
}
flipBuffer(g);
// pause for a bit so we don't consume 100% CPU
try { Thread.sleep(10); } catch (Exception e) {}
}
}

Feel free to correct me if I'm wrong (still learning C++, having learned Java, and some C#), but I believe this is what it is...

In C-based languages, void is simply nothingness, as I'm sure you know. Commonly (thought not seen in Java much - at least I don't to use it) void is an unnecessary parameter in functions if used as above. This is merely just a matter of taste from what I know.
Therefore, this:


void run (void){
  //Filler code
}

should compile the same as this:


void run (){
  //Filler code
}

Really the only thing that the extra void does is fill in the parameter parenthesis, and make it a bit clearer to the programmer that the function has no intent to take arguments. However, depending on your level of comments & documentation, it may be completely unnecessary. tldr: Don't worry about it.

There may be some subtleties between them, but nothing very significant.


EDIT: Looking at your loop, I'd recommend doing what slicer4ever suggested. That could very likely be the root of your problem. Granted I can't see all of your custom methods (eg: your update() and all that jazz), but looking at it, it doesn't seem like you're doing all too much with your milliseconds variable, rather than using it in one method. Instead of invoking Thread.sleep(), you might be better enclosing your drawing code within an if statement that checks the time.
To give you an idea, take this basic structure:


public void run(){
  //basic game loop
  while (isRunning){
    //calculate time since last loop
    long milliseconds = System.currentTimeMillis() - lastTick;
    
    //This would be the change here
    //replace (1000/framesPersecond) if you prefer ticks in ms
    if (framesPerSecond> 0 && milliseconds > (1000/framesPerSecond)){
      //GAME LOGIC & DRAWING

      lastTick = System.currentTimeMillis(); //moved into the if statement
    }
  }
}

I believe that a structure more like this would save yourself the time of your interpreter having to call a method outside of your class. It also should be a bit more accurate and constant for your game, as the sleep() and wait() methods can be a bit off at times, or have occasionally failed.
An article here could explain the inaccuracy a bit more than I could.


why are you calling run after you setIsRunning(true)?(now your in a loop inside the input function)

if that's not the problem, idk because you barely posted any real code.

what we need to see is:

Initialization code

--Main game loop(is this controlled by "isRunning", because if so, setting it to false should break the loop.)

---Where you check for input(is this inside your main loop, which is controlled by the "isRunning" flag?)

because my approach was to pause the game. The only way to do it is to break out of the gameLoop. If I unpause the game, I need to call the run method which execute the game loop to keep things drawing again. the run method needs to be called by the programmer. the key events are in the keyPressed method of the Game class since the Game class will be responsible for controlling the pause/unpause nature of the game.

Are you sure you saw my code? blink.png

think about what it means to start an infinite loop inside your input logic thread. and as far as i can see, that infinite loop does not check your input.

so yes, we need to see more code(unless my above assumption is correct, and that is why you can only pause/unpause once)

insead of doing:


void run(void){
  while(isRunning){
  }
}

try:


void run(void){
 while(!isDone){
  if(isRunning){
   //game logic here
  }
}

why is void a parameter and is not given a data type? I posted my game loop below since I cannot longer edit my initial post. smile.png

public void run(){
// basic game loop
while(isRunning){
// calculate the time since the last loop
long milliseconds = System.currentTimeMillis() - lastTick;
lastTick = System.currentTimeMillis();
// set the focus to the panel
panel.requestFocus();
// get graphics context
Graphics2D g = (Graphics2D) strategy.getDrawGraphics();
clearBuffer(g);
// update all game items
for(GameComponent component : gameObjects){
component.update(milliseconds);
}
// handle the dynamic objects
addNewGameComponents();
removeOldGameComponents();
// draw all game items
for(GameComponent component: gameObjects){
component.draw(g);
}
/* do a bounding box collision of the laser with the
* oneEye monster's bounding box every game loop
* which is basically every time the game redraws
* itself.
* Collision test applies to ALL laser being drawn on screen!
*
* The easiest way is to check every instance of type Laser in the
* ArrayList and tell them to do monster collision detection
*/
// laser check for every OneEye monsters in the ArrayList
for(GameComponent component: gameObjects){
if(component instanceof Laser)
{
((Laser) component).checkMonsterCollision(gameObjects);
}
if(component instanceof OneEyeSlashSkill)
{
((OneEyeSlashSkill) component).checkShipCollision(gameObjects);
}
}
flipBuffer(g);
// pause for a bit so we don't consume 100% CPU
try { Thread.sleep(10); } catch (Exception e) {}
}
}

ok, so i'm fairly certain(note: i've used little java, so i might be wrong in how java handle's things) the problem is as i described, you are calling run inside your input logic, this means that you essentially never get back to check input again.

the void inside the run is just indicating that their are no parameters to pass to the function(as epicpunnum said), so you can freely think of run() and run(void) as the same thing.

in short, don't break the loop inside run, just do a conditional check inside the loop that if(isRunning==true), and put your logic inside that.

alternatively, you coud do:

void run(){
  while(!isDone){
   if(!isRunning) continue; //goes back to the beginning of the loop.
   //your code here!
  }
};

basically, your core problem is that you call run() inside your input code, instead you need to re-think how you manage your main loop with pause/unpause.

Check out https://www.facebook.com/LiquidGames for some great games made by me on the Playstation Mobile market.

Feel free to correct me if I'm wrong (still learning C++, having learned Java, and some C#), but I believe this is what it is...

In C-based languages, void is simply nothingness, as I'm sure you know. Commonly (thought not seen in Java much - at least I don't to use it) void is an unnecessary parameter in functions if used as above. This is merely just a matter of taste from what I know.
Therefore, this:


void run (void){
  //Filler code
}

should compile the same as this:


void run (){
  //Filler code
}

Really the only thing that the extra void does is fill in the parameter parenthesis, and make it a bit clearer to the programmer that the function has no intent to take arguments. However, depending on your level of comments & documentation, it may be completely unnecessary. tldr: Don't worry about it.

There may be some subtleties between them, but nothing very significant.

Java does not allow void in the parameter. Maybe for other languages but not Java. I tested it just now

This topic is closed to new replies.

Advertisement