Help with a game

Ok I am stumped - have tried 3 different ways but cant get it to work.

Basically I want the player to hold the button down for five seconds to do this

  case btnLEFT: { activePlayer = &red; ; break; }  // set player 1 active
    
    case btnRIGHT: { activePlayer = &blue; break; } // set player 2 active

I have tried so many ways - and none have worked. Any ideas?

Any ideas?

The usual - post your code.

// Domination using the LiquidCrystal library
#include <LiquidCrystal.h>

/*******************************************************   
Jamie Bull, February 2016
Modified chess clock, Legion 02/07/16
********************************************************/

// select the pins used on the LCD panel
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);
// define some values used by the panel and buttons
int lcdKey      = 0;
int adc_key_in  = 0;


enum Button 
{
    btnRIGHT,
    btnUP,
    btnDOWN,
    btnLEFT,
    btnSELECT,
    btnNONE
};

// read the buttons
int read_LCD_buttons()
{
    adc_key_in = analogRead(0);      // read the value from the sensor 
    // buttons when read are centered at these values: 0, 144, 329, 504, 741
    // we add approx 50 to those values and check to see if we are close
    
    // We make this the 1st option for speed reasons since it will be the most likely result
    if (adc_key_in > 1000) return btnNONE; 
    if (adc_key_in < 50)   return btnRIGHT;  
    if (adc_key_in < 250)  return btnUP; 
    if (adc_key_in < 450)  return btnDOWN; 
    if (adc_key_in < 650)  return btnLEFT; 
    if (adc_key_in < 850)  return btnSELECT;
    
    return btnNONE;  // when all others fail, return this...
}
//================================================================

// Initialise some global parameters
bool isUsingMenu = false;  // whether we are in the time-setting menu
bool isGameOver = false;

class Player 
{
    // Represents a player.
    public:
        int minutes;              // number of minutes allowed  
        String menuText;          // text for the time-setting menu
        String playIndicator;     // indicator for when active
        long secondsRun;          // seconds run while the player was active
    
        void IncrementMinutes() 
        {
            minutes = min(minutes + 1, 99);
            delay(250);        
        }
        void DecrementMinutes()
        {
            minutes = max(minutes - 1, 1);
            delay(250);        
        }
        int SecondsRemaining() 
        {
            // number of seconds remaining on the player's clock
            int minsAllowed = minutes;
            int secondsRunSoFar = secondsRun;
            return minsAllowed * 60 + secondsRunSoFar;
        }
        void UpdateCounter(Player p0, Player red, Player blue)
        {
            secondsRun += millis()/1000 - (p0.secondsRun + red.secondsRun + blue.secondsRun);
        }
};

// initialise the players
Player p0 = {0, "",               "  --  ", 0};  // dummy player, active when player clocks are not counting down
Player red = {0, "Red mins: ", "  <-  ", 0};
Player blue = {0, "Blue mins: ", "  ->  ", 0};

// set a pointer to the first player to be shown in the time-setting menu
Player* menuPlayer = &red;
// set the active player pointer to the player to start with
Player* activePlayer = &p0;

void setup()
{
    lcd.begin(16, 2);  
}

// Main loop
void loop()
{
    activePlayer->UpdateCounter(p0, red, blue);;  // do this every loop
    lcdKey = read_LCD_buttons();  
    if (isUsingMenu) 
    {
        updateMenuScreen();
    } else {
        updateTimerScreen();
    }
}

void resetGame()
// reset game to starting state
{
    p0.secondsRun += (red.secondsRun + blue.secondsRun);
    red.secondsRun = 0;
    blue.secondsRun = 0;
    activePlayer = &p0;
    isGameOver = false;
}

void updateTimerScreen()
{
    switch (lcdKey)               
    {
    case btnLEFT: { activePlayer = &red; ; break; }  // set player 1 active
    
    case btnRIGHT: { activePlayer = &blue; break; } // set player 2 active
    
    case btnUP: { activePlayer = &p0; break; }    // pause the timers
    
    case btnDOWN: { break; }                      // not used
    
    case btnSELECT: // to activate menu (or reset if game is over)
        {
        if (isGameOver)
        {
            resetGame();
        } else {
            // activate the menu
            isUsingMenu = true;   
            activePlayer = &p0;
        }
        delay(500);  // delay required otherwise the button fires repeatedly
        break;
        }
    case btnNONE:  // update timer if no button pressed
        {
        if (isGameOver) {
            // do nothing and wait for btnSELECT to reset the game
        } else {
            // check if either player is out of time
            int loser = getLoserNumber();
            
            lcd.setCursor(0,0);
            if (loser > 10) {
                lcd.print("   Game Over!   ");
                lcd.setCursor(0,1);
                lcd.print(" Team" + String(loser) + " Captured ");
                isGameOver = true;
            } else {
                // update timer display
                lcd.print("1 Red     2 Blue");
                lcd.setCursor(0,1);
                lcd.print(timeString(red.SecondsRemaining()));      
                lcd.setCursor(5,1);            
                lcd.print(activePlayer->playIndicator);        
                lcd.setCursor(11,1);
                lcd.print(timeString(blue.SecondsRemaining()));
            }
        }
        }
    }
}

void updateMenuScreen()
{
    switch (lcdKey)                
    {
    case btnUP: 
        { menuPlayer->IncrementMinutes(); break; } // increase minutes
    case btnDOWN:
        { menuPlayer->DecrementMinutes(); break; } // decrease minutes
    case btnLEFT:
        {
        // set pointer to player 1 as player to change time for
        menuPlayer = &red;
        break;
        }  
    case btnRIGHT:
        {
        // set pointer to player 2 as player to change time for
        menuPlayer = &blue;
        break;
        }  
    case btnSELECT:
        {
        // return to timer screen
        isUsingMenu = false;
        delay(500);  // delay required otherwise the button fires repeatedly
        break;       
        }  
    case btnNONE:
        {
        // update menu display
        lcd.setCursor(0,0);
        lcd.print("      MENU      ");
        lcd.setCursor(0,1);
        String playerMins;
        if (menuPlayer->minutes < 1) {
            playerMins = " " + String(menuPlayer->minutes);
        } else {
            playerMins = String(menuPlayer->minutes);
        }
        lcd.print(menuPlayer->menuText + playerMins);
        break;       
        }
    }
}
    
int getLoserNumber()
// return the number of the losing player, or 0 if both have time remaining
{
    if (red.SecondsRemaining() >= 1)
        {
        return 1;
    } else if (blue.SecondsRemaining() >= 1)
        {
        return 2;
    }
    return 0;
}


String timeString(long seconds)
// Convert seconds to an MM:SS display.
{
    int runMins = seconds / 60;
    int runSecs = seconds % 60;
  
    return pad(runMins) + ":" + pad(runSecs);
};

String pad(int toPad)
// Zero-pad to ensure two chars in the string for mins/secs
{
    if (toPad < 10) {
        return "0" + String(toPad);
    } else {
        return String(toPad);
    }
};

there are so many areas in your code that are hard to get through, poor formatting and over-commented.

Perhaps reduce an example sketch that manifests your problem/issue/question.

Are you looking to detect a long button press, make a sketch that does just that.

take a look at reply #2 of this thread for a nice way to capture button presses.

Yea - the code is a mess - but it was the only way I could get it to work - I did have this, which was much simpler - but the clocks started at the start and the button reset the clocks instead of clock at zero to start and starting each timer and ending the other with button push

#include <LiquidCrystal.h>
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);
int readkey;
void setup() {
  lcd.begin(16, 2);
  lcd.print("Trigger Happy");
  lcd.clear();
}
void loop() {

  // start time when buttons were pressed
  static unsigned long starttimeRed = 0;
  static unsigned long starttimeBlue = 0;

  // total time that buttons were pressed
  unsigned long totaltimeRed;
  unsigned long totaltimeBlue;
  lcd.setCursor(0, 0);
  lcd.print("Blue");
  lcd.setCursor(9, 0);
  lcd.print("Red");  

  readkey = analogRead(0);

  // if red pressed
  if (readkey < 50)
  {
   // if no starttime set, set it to current time (millis())
      starttimeRed = millis();
    }
  
  // if blue pressed
  else if (readkey < 790)
  {
    // if no starttime set, set it to current time (millis())
    if (starttimeBlue == 0)
    {
      starttimeBlue = millis();
    }
  }
  // nothing or anything else pressed
  else
  {
    // calculate total time
    totaltimeRed = millis() - starttimeRed;      
    totaltimeBlue = millis() - starttimeBlue;
     lcd.setCursor(0, 1);
    lcd.print(totaltimeRed / 1000);
     lcd.setCursor(9, 1);
    lcd.print(totaltimeBlue / 1000);

  }
}

Its basically a domination box for two teams to play

  // start time when buttons were pressed
  static unsigned long starttimeRed = 0;
  static unsigned long starttimeBlue = 0;

you did such a great job naming the variables, why do you feel that you need a comment?

  // nothing or anything else pressed
  else

followed by an if else, an else captures EVERYTHING else, so again, why the superfluous commenting?

here is your code properly formatted (You can use the TOOLS >> AUTOFORMAT) tool in your Arduino IDE:

#include <LiquidCrystal.h>

LiquidCrystal lcd(8, 9, 4, 5, 6, 7);
int readkey;

void setup() 
{
  lcd.begin(16, 2);
  lcd.print("Trigger Happy");
  lcd.clear();
}

void loop() 
{
  static unsigned long starttimeRed = 0;
  static unsigned long starttimeBlue = 0;
  unsigned long totaltimeRed;
  unsigned long totaltimeBlue;
  lcd.setCursor(0, 0);
  lcd.print("Blue");
  lcd.setCursor(9, 0);
  lcd.print("Red");

  readkey = analogRead(0);
  if (readkey < 50)
  {
    starttimeRed = millis();
  }
  else if (readkey < 790)
  {
    if (starttimeBlue == 0)
    {
      starttimeBlue = millis();
    }
  }
  else
  {
    totaltimeRed = millis() - starttimeRed;
    totaltimeBlue = millis() - starttimeBlue;
    lcd.setCursor(0, 1);
    lcd.print(totaltimeRed / 1000);
    lcd.setCursor(9, 1);
    lcd.print(totaltimeBlue / 1000);
  }
}

Also, it is easier to debug (and to get help) if your example code uses Serial output versus LCD. That way people don't have to hook up a device to see what you are seeing...

Sorry,yea I am a complete noob at this, basically learning on here and youtube. Did not even know about serial output... youtube here I come

Legioniw3:
Ok I am stumped - have tried 3 different ways but cant get it to work.

Basically I want the player to hold the button down for five seconds to do this

  case btnLEFT: { activePlayer = &red; ; break; }  // set player 1 active

case btnRIGHT: { activePlayer = &blue; break; } // set player 2 active




I have tried so many ways - and none have worked. Any ideas?

I don't see whether you have solved your problem meanwhile or not.

The code is for some kind of "LCD Keypad Shield" with some additional color buttons attached, isn't it?

Here is my suggested code for selecting Player RED or BLUE by pressing btnLEFT or btnRIGHT for 5 seconds.

#include <LiquidCrystal.h>

LiquidCrystal lcd(8, 9, 4, 5, 6, 7); 

enum {NONE, RED, BLUE};
enum Button
{
  btnRIGHT,
  btnUP,
  btnDOWN,
  btnLEFT,
  btnSELECT,
  btnNONE,
};

byte read_LCD_buttons()
{
  int adc_key_in = analogRead(0);      // read the value from the sensor
  // buttons when read are centered at these values: 0, 144, 329, 504, 741
  // we add approx 50 to those values and check to see if we are close

  // We make this the 1st option for speed reasons since it will be the most likely result
  if (adc_key_in > 1000) return btnNONE;
  if (adc_key_in < 50)   return btnRIGHT;  
 if (adc_key_in < 195)  return btnUP; 
 if (adc_key_in < 380)  return btnDOWN; 
 if (adc_key_in < 555)  return btnLEFT; 
 if (adc_key_in < 790)  return btnSELECT;   
   return btnNONE;  // when all others fail, return this...
}

byte userColor=NONE;
  

void setup() {
  Serial.begin(9600);
  lcd.begin(16, 2); delay(100);
  while(userColor==NONE) userColor=selectColor();
}

byte selectColor()
{
  static unsigned long timer;
  lcd.clear();lcd.print ("Select Color");delay(100);
  if (read_LCD_buttons()== btnLEFT)
  {
    timer=millis();
    while (read_LCD_buttons()== btnLEFT && millis()-timer<5000) ;
    if (millis()-timer>=5000) return RED; else return NONE;
  }
  else if (read_LCD_buttons()== btnRIGHT)
  {
    unsigned long timer=millis();
    while (read_LCD_buttons()== btnRIGHT && millis()-timer<5000) ;
    if (millis()-timer>=5000) return BLUE; else return NONE;
  }
  else return NONE;
}


void doPlayerMove()
{
  
}


void loop()
{
 lcd.setCursor(0,1);
 lcd.print("Your move - ");
 if (userColor==RED) lcd.print ("RED");
 if (userColor==BLUE) lcd.print ("BLUE");

doPlayerMove();
 ;
}

What do you think?
And what kind of game is it about?
A two player game human vs. human? Or a game human vs. Arduino?

Wow that works great. Basically I am trying to make a domination point, think call of duty. Two teams two buttons. Red team stops blue team timer and starts their own. And vice versa.

I run an indoor airsoft site, and at the minute I use flags (well colored pillowcases) on a little pully - but thought this would look great as boxes with screens.

I am still learning - I have got a bomb box working - with a code and keypad - but this is stumping me. I thought it would be so easy, two timers and two buttons - but am lost in a sea of code, that I only mildly know what it means.

Legioniw3:
Wow that works great.

Thanks for testing the example sketch and sending some friendly feedback!

Legioniw3:
Red team stops blue team timer and starts their own. And vice versa.

Sounds easy.
This is what I understand:
After BLUE ihas been selected initially, a BLUE timer starts running and it is RED to do the next step and press the red button. Then the BLUE timer stops and the RED timer starts.
Then BLUE must do the next step and press theblue buton.
Then the blue timer starts at the time when it was stopped and continues running while the red timer stops.
And so on and so on.

One problem when using the Arduino boards internal timing may be timing accuracy.

All boards with a "ceramic resonator for creating the boards 16 MHz clocking are only accurate to 0.8 %, wnich means 8 seconds of inaccuracy in 1000 seconds. Or even more . All of the "R3" design boards are such inaccurate,like "UNO R3" or "MEGA25650 R3". Is such inaccuracy suitable for your application? Which Arduino board are you planning to use? And is there any condidition for a gameover() function? Or is the game not limited in ime and runs forever (or until reset)?

Please let me know if you need additional assistance with some more lines of code.

Well the timing issue is not a problem - Before I was counting in my head which team had won.

I am using the Arduino Mega 2560, because if I try to solder a pcb board I will probably burn down the building.

The code I had at the start works - even though there are alot of contradictions in it. I used a chess timer and messed around with what little of the code I knew to get it working. But was unable to change using the lcd buttons to using external buttons into digitalout.

I could even live without the delay in the button push (but it is so nice).

I am just going to have this run - with no end time, as I will have three units, and just call the game when I see fit

Ok - so my two external buttons work - but not like the buttons on the lcd keypad. Is there a way to replace

  switch (lcdKey)               
    {
    case btnLEFT: { activePlayer = &red; ; break; } 
    
    case btnRIGHT: { activePlayer = &blue; break; }

with something like

  if (valRed == HIGH)          
    { activePlayer = &red;}