Need help with implementing a delay for a minigame.

Hello everyone!

Me and my friend are trying to create a project at school, and we have run into an issue that we can't find a solution to on our own. We tried googling for a few hours trying to figure out how to do it, but that hasn't helped us unfortunately.

Basicly we are trying to make a game where two players compete against eachother, trying to react fastest.

We have two buttons installed, one for each player.

Both players have 3 LED's to represent their health.

When the LED in the middle flashes, the player who pushes his button first, turns off one of the opponent players LEDs.

The issue we're having makes it possible for the players to keep holding the button down. We are trying to implement a delay. (If you push the button and the LED in the middle is not flashing, you get a delay.).

We don't want to use the Delay() function, as it causes issues with the other parts of our program.

We use millis(); for randomly turning the LED in the middle on.

This is our code so far:

const int Pl1liv1 = 13; // player1 life
const int Pl1liv2 = 12; // player1 life
const int Pl1liv3 = 11; // player1 life
const int Pl2liv1 = 10; // player2 life
const int Pl2liv2 = 9; // player2 life
const int Pl2liv3 = 8; // player2 life
const int vinder = 6; // LED to represent a player winning.
const int delayPl1 = 5; // LED to represent delay for player1
const int delayPl2 = 4; // LED to represent delay for player2
const int lampe = 3; // the LED in the middle.
const int Pl1skyd = 2; // Player 1 button.
const int Pl2skyd = 7; // Player 2 button.
const int reset = 0;

int Pl1liv = 3;
int Pl2liv = 3;







unsigned long previousMillis = 0;
long interval = random(3000,6000);



int buttonState1 = 0;
int buttonState2 = 0;
int lampestate = LOW;


void setup() {
Serial.begin(9600);
pinMode(Pl1liv1, OUTPUT);
pinMode(Pl1liv2, OUTPUT);
pinMode(Pl1liv3, OUTPUT);
pinMode(Pl2liv1, OUTPUT);
pinMode(Pl2liv2, OUTPUT);
pinMode(Pl2liv3, OUTPUT);
pinMode(vinder, OUTPUT);
pinMode(delayPl1, OUTPUT);
pinMode(delayPl2, OUTPUT);
pinMode(lampe, OUTPUT);
pinMode(Pl1skyd, INPUT);
pinMode(Pl2skyd, INPUT);
pinMode(reset, INPUT);
randomSeed(analogRead(0));

}

void loop() {
  
 unsigned long currentMillis = millis();
 
 buttonState1 = digitalRead(Pl1skyd);
 buttonState2 = digitalRead(Pl2skyd);
 
 

 
 if (currentMillis - previousMillis >= interval){
  previousMillis = currentMillis;

    if (lampestate == LOW){
      lampestate = HIGH;
    } else {
      lampestate = LOW;
    }
    digitalWrite(lampe, lampestate);
 }

    
 
 

      
  if (Pl1liv == 3)
    {
      digitalWrite (Pl1liv1, HIGH);
      digitalWrite (Pl1liv2, HIGH);
      digitalWrite (Pl1liv3, HIGH);
    }
    else if (Pl1liv == 2)
      {
        digitalWrite (Pl1liv1, HIGH);
        digitalWrite (Pl1liv2, HIGH);
        digitalWrite (Pl1liv3, LOW);
      }
      else if (Pl1liv == 1)
      {
        digitalWrite (Pl1liv1, HIGH);
        digitalWrite (Pl1liv2, LOW);
        digitalWrite (Pl1liv3, LOW);
      }
        else if (Pl1liv == 0)
        {
          digitalWrite (Pl1liv1, LOW);
          digitalWrite (Pl1liv2, LOW);
          digitalWrite (Pl1liv3, LOW);
          digitalWrite (vinder, HIGH);
          digitalWrite (delayPl1, HIGH);
      }

       
   if (Pl2liv == 3)
    {
      digitalWrite (Pl2liv1, HIGH);
      digitalWrite (Pl2liv2, HIGH);
      digitalWrite (Pl2liv3, HIGH);
    }
    else if (Pl2liv == 2)
      {
        digitalWrite (Pl2liv1, HIGH);
        digitalWrite (Pl2liv2, HIGH);
        digitalWrite (Pl2liv3, LOW);
      }
      else if (Pl2liv == 1)
      {
        digitalWrite (Pl2liv1, HIGH);
        digitalWrite (Pl2liv2, LOW);
        digitalWrite (Pl2liv3, LOW);
      }
        else if (Pl2liv == 0)
        {
          digitalWrite (Pl2liv1, LOW);
          digitalWrite (Pl2liv2, LOW);
          digitalWrite (Pl2liv3, LOW);
          digitalWrite (vinder, HIGH);
          digitalWrite (delayPl2, HIGH);
      } 


 if (buttonState1 == HIGH && lampestate == HIGH)
  {
   Serial.println(Pl2liv); 
    Pl2liv--; 
   buttonState1 = LOW;
   lampestate = LOW;
   digitalWrite(lampe, LOW);
   Serial.println(buttonState1);
   Serial.println(lampestate);
  }

  
 if (buttonState2 == HIGH && lampestate == HIGH)
  {
   Serial.println(Pl1liv); 
    Pl1liv--; 
   buttonState2 = LOW;
   lampestate = LOW;
   digitalWrite(lampe, LOW);
   Serial.println(buttonState2);
   Serial.println(lampestate);
  }


  

      
     
  
 
  
}

Basicly we need help implementing a way to count. If player1 pushes the button when the LED (lampe) is not high. He needs to get a delay for 1 sec (perhaps a variable changing from 1 to 0 after a second)

Here is a picture of our board.
Thank you for taking your time to read through this post, hope that you can help :slight_smile:

Your thinking is wrong. Stop thinking about a delay. Think about, instead, ignoring input from a switch for a period of time, if an event occurs. The user presses the switch at the wrong time (the LED is not lit) is the event. That event sets a flag.

On every pass through loop(), you read the state of each switch if the flag to ignore that switch is not set.

On every pass through loop(), you determine if it is time to clear that flag, if it is set. Clearing happens if the time since the flag was set exceeds some threshold (one second for you, three for your opponent).

The issue we're having makes it possible for the players to keep holding the button down

Looks like you need to detect when the button becomes pressed rather than when it is preesed. Look at the StateChangeDetection example in the IDE. Combine that with the millis() timing technique, ie have the time the button is pressed then each time through loop() check whether the required period has elapsed since the event. If not then go round loop() again reading inputs etc. If the period has elapsed then take the required action such as allowing input again.

I suggest a small change to @PaulS' logic. Instead of

On every pass through loop(), you read the state of each switch if the flag to ignore that switch is not set.

I would have it like this

On every pass through loop(), you read the state of each switch and ignore the value for any switch if the flag to ignore that switch is not set.

This way you can have a simple function that reads all the switch values regardless of anything else.

...R

Hi guys thank you for your reply. We started programming this kind of stuff a few days ago, so our knowledge is very very limited.. I basicly have no clue what I'm reading atm..

We tried doing it something like this.. (using simple naming for our variables):

if (ThemiddleLamp == LOW && ButtonInputPlayer1 == HIGH){
Player1delay = HIGH;
}

if (Player1delay == HIGH){
<Code to make Player1delay = low after 1 second>
}

the <Code to make Player1delay = low after 1 second> is basicly what we're looking for.

I will use the delay(); function to demonstrate, since this does exactly what we want, except fucking up the rest of the program.

if (Player1delay == HIGH){

delay(1000);
Player1delay = LOW;
}

Hope it makes sense, and thank you for your inputs guys!

if (Player1delay == HIGH && (millis() - Player1_delayStart >= delayPeriod) )
  {
    Player1delay = LOW;
  }

Thanks for the reply UKHeliBob.

What should we initialise the variable Player1_delayStart and delayPeriod as?

unsigned long Player1_delayStart = 0; ??
unsigned long delayPeriod = 1000; ??

Hope you understand.

Set Player1_delayStart millis() when you detect that the player button has become pressed. Declare it as an unsigned long to match the return value from millis() and use subtraction to determine if the period has elapsed so that the millis() rollover will not affect timing if you leave the code running for more than 49 and a bit days. Probably not important here but get into the habit in case you write some long term embedded code at some time.

unsigned long delayPeriod = 1000;

Correct for a 1 second period. Adjust as necessary for different periods. You could even adjust it from within the program based on player performance. It does not strictly need to be unsigned but doing so keeps it consistent with millis().