pausing one function to allow another to work properly

Ive run into a bit of a snag on a game that I'm making. I created a gui menu that should appear when a button is pressed that also uses a cursor bitmap that can be used to select menu items. the problem is that when I bring up the menu the controls for the player do not transfer to the new functions controls. this makes the player move while the menu does nothing.

player and cursor use different values and definitions from each other in separate functions. Each one pointing to the correct variables. But even after the menu is turned off he cursor still shows and remains on the screen.

I need a way to pause the player controls so the player moves but the cursor does and vice versa depending if the menu is on or off. I tried some else if state ments in the void loop that contains the calls to the two functions.

here are the menu controls

void Menu(){
if (ButtonA.fallingEdge()){
            menu_1 = menu_1 + 1;}


else if(menu_1 == 3){
 tft.writeRectNBPP(16,0,114,32,4,itemmenutop,palette);
  tft.writeRectNBPP(16,32,114,16,4,itemmenu2,palette);
   tft.writeRectNBPP(16,48,114,160,4,itemmenu3,palette);
   tft.writeRectNBPP(16,208,114,16,4,itemmenu4,palette);
}

else if(menu_1 >= 5){
          menu_1 = 1;}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
if (ButtonUp.fallingEdge()){
     tft.writeRectNBPP(cursor_x,cursor_y,16,16,4,cursordot2,palette);
     cursor_y -= 16;
//     if(checkcolision())
     {
      cursor_y += 16;} 
     }
     if(cursor_y <= 32){
        cursor_y = 32;}
          
//////////////////////////////////////////////////////////////////////////////
///////////////////////////////Down///////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
 if (ButtonDown.fallingEdge()){
   tft.writeRectNBPP(cursor_x, cursor_y,16,16,4,cursordot2,palette);
   cursor_y += 16;
//    if(checkcolision())
    {
    cursor_y -= 16;}
    }
    if(cursor_y >= 224){
       cursor_y = 224;}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
}

here is the plauer stuff

void drawplayer() {

// Clamp cameraX
if(cameraX < cameraXMin)
{
  cameraX = cameraXMin;
}
else if(cameraX > cameraXMax)
{
   cameraX = cameraXMax;
}

// Clamp cameraY
if(cameraY < cameraYMin)
{
  cameraY = cameraYMin;
}
else if(cameraY > cameraYMax)
{
   cameraY = cameraYMax;  
}

// Check if player is beyond X boundary
if(player_x < playerXMin)
{
  cameraX += cameraXSpeed;
  if(cameraX > cameraXMin && cameraX < cameraXMax)
  {
    player_x = playerXMin;
  }
}
else if(player_x > playerXMax)
{
  cameraX -= cameraXSpeed;
  if(cameraX > cameraXMin && cameraX < cameraXMax)
  {
    player_x = playerXMax;
  }
}

// Check if player is beyond Y boundary
if(player_y < playerYMin)
{
  cameraY += cameraYSpeed;
  if(cameraY > cameraYMin && cameraY < cameraYMax)
  {
    player_y = playerYMin;
  }
}
else if(player_y > playerYMax)
{
  cameraY -= cameraYSpeed;
  if(cameraY > cameraYMin && cameraY < cameraYMax)
  {
    player_y = playerYMax;
  }
}
 
///////////////////////////////////////////////////////////////////////////////
///////////////////////////Buttons Repeat//////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////  
       if (ButtonUp.update());
               if (ButtonDown.update());
                       if (ButtonLeft.update());
                             if (ButtonRight.update());
                                       if (ButtonA.update());
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
                                       ButtonUp.rebounce(10);
                               ButtonDown.rebounce(10);
                       ButtonLeft.rebounce(10);
            ButtonRight.rebounce(10);
 //    ButtonA.rebounce(10);
///////////////////////////////////////////////////////////////////////////////
////////////////////////////Up/////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
if (ButtonUp.fallingEdge()){
    tft.writeRectNBPP(player_x, player_y,16,16,4,paulrearwa,palette);
    tft.writeRectNBPP(player_x, player_y,16,16,4,paulrearwb,palette);
    player_direction = 1;
    player_y -= 4;
    if(checkcolision())
    {
        player_y += 4;} 
    }
     if(player_y <= 16){
        player_y = 16;}  

//////////////////////////////////////////////////////////////////////////////
///////////////////////////////Down///////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
if (ButtonDown.fallingEdge()){
    tft.writeRectNBPP(player_x, player_y,16,16,4,paulfrontwa,palette);
    tft.writeRectNBPP(player_x, player_y,16,16,4,paulfrontwb,palette);
    player_direction = 2;
    player_y += 4;
    if(checkcolision())
    {
       player_y -=4;}
    }
    if(player_y >= 224){
       player_y = 224;}
//////////////////////////////////////////////////////////////////////////////
//////////////////////////Left////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
if (ButtonLeft.fallingEdge()){
    tft.writeRectNBPP(player_x, player_y,16,16,4,paulleftw,palette);
    tft.writeRectNBPP(player_x, player_y,16,16,4,paulleft,palette);
    player_direction = 3;
    player_x -= 4;
    if(checkcolision())
   {
      player_x += 4;}  
   }
   if(player_x >= 304){
      player_x = 304;}    
/////////////////////////////////////////////////////////////////////////////
////////////////////////////Right////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
if (ButtonRight.fallingEdge()){
    tft.writeRectNBPP(player_x, player_y,16,16,4,paulrightw,palette);
    tft.writeRectNBPP(player_x, player_y,16,16,4,paulright,palette);
    player_direction = 4;
    player_x += 4;
  if(checkcolision())
  {
    player_x -= 4;}
  }
            if(player_x <= 16){
              player_x = 16;}
///////////////////////////////////////////////////////////////////////////////     
//////////////////////////////PLAYER DIRECTION/////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
if (player_direction == 1){
  tft.writeRectNBPP(player_x, player_y,16,16,4,paulrear,palette);
}
/////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////
else if (player_direction == 2){
   tft.writeRectNBPP(player_x, player_y,16,16,4,paulfront,palette);
}
/////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////
else if (player_direction == 3){
    tft.writeRectNBPP(player_x, player_y,16,16,4,paulleft,palette);
}
/////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////
else if (player_direction == 4){
     tft.writeRectNBPP(player_x, player_y,16,16,4,paulright,palette);
}
/////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////        
/////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////for use with movey blocks////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////
else if (player_direction == 5){
     tft.writeRectNBPP(player_x, player_y,16,16,4,paulrearwa,palette);
}     
else if (player_direction == 6){
     tft.writeRectNBPP(player_x, player_y,16,16,4,paulfrontwa,palette);
}     
else if (player_direction == 7){
     tft.writeRectNBPP(player_x, player_y,16,16,4,paulleftw,palette);
}          
else if (player_direction == 8){
     tft.writeRectNBPP(player_x, player_y,16,16,4,paulrightw,palette); 
}          
};

You should only check the button inputs in one place in the program. Then you can decide if the menu is active to move the menu or (if the menu is no up) then move the player.

void loop() {
  readInputs();
  doCalculations();
  setOutputs();
}

ok I've researched and tried everything I can think of and I still cant find an answer to switching the controls from one function to another. I've made if else loops both on the sets of controls and in my loop. I've also made two sets on button functions in their own void functions then tried to add them to their own state functions and all other kinds of stuff but so far ive made no progress.

My program is quite large so I'm posting the link to the GitHub page but I would be happy to post what ever you need upon request.

please help me. ive been running in circles with this for days

Hi,

Post your code as a attachment.

Please read the first post in any forum entitled how to use this forum.
http://forum.arduino.cc/index.php/topic,148850.0.html

What display are you using?
What model Arduino are you using?

Thanks.. Tom.. :slight_smile:

Duhjoker:
ok I've researched and tried everything I can think of and I still cant find an answer to switching the controls from one function to another.

Have a look at Planning and Implementing a Program. Note how each function runs very briefly and returns to loop() so the next one can be called. And there may be dozens of calls to a function before it is actually time for it to do anything.

The general style is like what @MorganS suggested.

...R

Ive been looking at a gaming rpg game called arduventure for the arduboy game system and has a lot of functions I should be able to translate to my library. it can be found here....

https://github.com/TEAMarg/ID-46-Arduventure

any way it sets the player movement like so in a structure type constant

const char playerMovement[][4] =
{
  {UP_BUTTON, DIR_UP, 0, -1},
  {DOWN_BUTTON, DIR_DOWN, 0, 1},
  {LEFT_BUTTON, DIR_LEFT, -1, 0},
  {RIGHT_BUTTON, DIR_RIGHT, 1, 0},
};

then it uses this function I think to get the current controls for what ever task its on....

//------------------------
// INPUT
//------------------------
bool getButtonDown(byte button)
{
  if(arduboy.pressed(button))
  {
    if(buttons & button) return false;
    else buttons |= button;
    return true;
  }
  else
  {
    if(buttons & button) buttons ^= button;
    return false;
  }
}

heres an example of whats being done

void doMenu()
{
  if(!menuIsSpecific)
  {
    // Draw
    arduboy.fillRect(84, 0, 64, 64, BLACK);

    for(byte i = 0; i < 3; i++)
    {
      drawText(menuLabels[i], 94, 2 + (i * 12), WHITE, ALIGN_LEFT);
    }
    
    arduboy.drawBitmap(88, 2 + (menuMainChoice * 12), font[43], 5, 5, WHITE);
  
    // Update
    if(textboxIsVisible) return;
    
    if(getButtonDown(UP_BUTTON)) menuMainChoice = max(menuMainChoice - 1, 0);
    if(getButtonDown(DOWN_BUTTON)) menuMainChoice = min(menuMainChoice + 1, 2);
    
    if(getButtonDown(A_BUTTON)) menuIsVisible = false;
    
    if(getButtonDown(B_BUTTON))

Am I correct on how getbuttondown works?

which chapter in morgans thread?

{I think you mean Robin's thread}

Without seeing the rest of the Arduboy program, I'm going to take a guess and say that "buttons" is actually a byte and it contains up to 8 button states. (Are there 8 buttons on a gameboy?)

It's the wrong approach. You need to remember inside your program if you're currently moving the menu or the player. For example:

void doCalculations() {
  //start with decoding the buttons we just read in the readInputs() function
  if(menuMode) {
    if(buttonUpBecamePressed) moveMenuUpOneLine();
    if(buttonDownBecamePressed) moveMenuDownOneLine();
    if(buttonMenuBecamePressed) menuMode = false; //exit the menu
  } else {
    //we're in the normal player-movement mode...
    if(buttonMenuBecamePressed) menuMode = true;
    ...
  }

}

Oops!! Sorry about that. Scratches head.. Is there an example of read inputs that I'm missing? Also can you explain the true and false on the menuMode? Are they supposed to reversed?

What does it mean to YOU if menuMode is true? Is the device currently showing the menu? You can define true and false to mean anything but usually a variable named isRunning is true when it's running and false when it's not running. That way statements like if(isRunning) read naturally.

No, you have to write the readInputs() function yourself. It should read all the buttons and other inputs. Since you probably have a lot of buttons and they all need debouncing, the debouncing and the first-became-pressed logic should probably be hidden away in that function.

ok so read inputs would look something like this?

void buttonInputs() = {
if (ButtonUp.update());
if (ButtonDown.update());
if (ButtonLeft.update());
if (ButtonRight.update());
if (ButtonA.update());

ButtonUp.rebounce(10);
ButtonDown.rebounce(10);
ButtonLeft.rebounce(10);
ButtonRight.rebounce(10);
ButtonA.rebounce(10);

if (ButtonUp.fallingEdge());
if (ButtonDown.fallingEdge());
if (ButtonLeft.fallingEdge());
if (ButtonRight.fallingEdge());
if (ButtonA.fallingEdge());
}

I haven't found away to write the button functions with out including the update and rebounce functions

I see a lot of if statements that don't have any use at all.

I'm still learning. Thank you! is there any thing else you see wrong? Also in MorganS example,

void doCalculations() {
  //start with decoding the buttons we just read in the readInputs() function
  if(menuMode) {
    if(buttonUpBecamePressed) moveMenuUpOneLine();
    if(buttonDownBecamePressed) moveMenuDownOneLine();
    if(buttonMenuBecamePressed) menuMode = false; //exit the menu
  } else {
    //we're in the normal player-movement mode...
    if(buttonMenuBecamePressed) menuMode = true;
    ...
  }

}

It looks like this does the calculations and can set the output.

ok so I'm already using a state change system to separate the game functions as in this example..

void loop(void) {

if(state == STATE_Menu){
 if (ButtonA.fallingEdge()){  
Menu();
controls();}
   state = STATE_Menu;
        nextState = STATE_Player;
}
else if(state == STATE_Player){
 World();
 controls();
     state = STATE_Player;
      nextState = STATE_Menu;   
 }

 if(nextState != state) state = nextState;
  

  tft.updateScreen();
 
 }

so I changed the example to this..

void buttonInputs[] = {
(ButtonUp.update());
(ButtonDown.update());
(ButtonLeft.update());
(ButtonRight.update());
(ButtonA.update());

ButtonUp.rebounce(10);
ButtonDown.rebounce(10);
ButtonLeft.rebounce(10);
ButtonRight.rebounce(10);
ButtonA.rebounce(10);

(ButtonUp.fallingEdge());
(ButtonDown.fallingEdge());
(ButtonLeft.fallingEdge());
(ButtonRight.fallingEdge());
(ButtonA.fallingEdge());
}

void doCalculations() {
  //start with decoding the buttons we just read in the readInputs() function
 if (state == STATE_Menu){
    if(ButtonUp.fallingEdge()) cursorUp();
    if(ButtonDown.fallingEdge()) cursorDown();
    if(ButtonA.fallingEdge()) state = STATE_Player;
  }
 else if (state == STATE_Player){
    //we're in the normal player-movement mode...
    if(ButtonUp.fallingEdge()) playerUp();
    if(ButtonDown.fallingEdge()) playerDown();
    if(ButtonLeft.fallingEdge()) playerLeft();
    if(ButtonRight.fallingEdge()) playerRight();
    if(ButtonA.fallingEdge()) state = STATE_Menu;
     }
}

example playerUp

void playerUp(){
    tft.writeRectNBPP(player.player_x, player.player_y,16,16,4,paulrearwa,palette);
    tft.writeRectNBPP(player.player_x, player.player_y,16,16,4,paulrearwb,palette);
    player.player_direction = 1;
    player.player_y -= 4;
    if(checkcolision())
    {
        player.player_y += 4;} 
    }
     if(player.player_y <= 16){
        player.player_y = 16;}

Now you're thinking in the right direction.

Yay!! I'm learning!! Happy Happy joy joy!

So now I should be able to drop void buttoniputs() and void buttonoutputs() in order inside each state like so?

void loop(void) {

if(state == STATE_Menu){
 buttonInputs();
 ButtonOutputs(); 
 Menu();
}
   state = STATE_Menu;
        nextState = STATE_Player;
}
else if(state == STATE_Player){
 buttonInputs();
 ButtonOutputs(); 
 World();

     state = STATE_Player;
      nextState = STATE_Menu;   
 }

 if(nextState != state) state = nextState;
  

  tft.updateScreen();
 
 }

Ok I'm having trouble with the reading the input part. This does nothing....

void buttonInputs() = {
(ButtonUp.update());
(ButtonDown.update());
(ButtonLeft.update());
(ButtonRight.update());
(ButtonA.update());

ButtonUp.rebounce(10);
ButtonDown.rebounce(10);
ButtonLeft.rebounce(10);
ButtonRight.rebounce(10);
ButtonA.rebounce(10);

(ButtonUp.fallingEdge());
(ButtonDown.fallingEdge());
(ButtonLeft.fallingEdge());
(ButtonRight.fallingEdge());
(ButtonA.fallingEdge());
}

Does the stuff above need to be outside a function or array? Do I need to do digital read?

Hi,

ButtonUp.update();
ButtonDown.update();

Like that, one too many pairs of ().

Tom.. :slight_smile:

Those structures ButtonUp.update() look like you're using a button-handling library. But at no point have you shown us enough of your sketch to include the #include lines or the declarations for those objects. Without that, we have no clue which library you might be using.

I suspect that the .update() method must be called regularly (hundreds of times per second) and then the other rising/falling functions will just return the most-recent result. I have no clue what .rebounce() might do.