Buzzer System

Hello Touchdesigner friends out there …
I am trying to create a simple “family fued style” buzzer system, very basic with 2 button and a simple lockout function for the other player when one person buzzes in. I have the basic network created and I am assuming I will use the count CHOP with some logic to do this.
I am stumbling on where to go next. How do I determine which buzzer (button) chimed in first?
Thank you for any and all help!
bUZZer.toe (5.27 KB)

You only really need one keyboard in for this.

Use a count CHOP to count both input channels, and then a CHOP execute DAT to announce the winner and lockout new entries by turning on the reset toggle for your count.

Your clear button can then be used to turn off your reset toggle, and empty our your winner message.
bUZZer_edits.toe (5.43 KB)

Ok, now I get it. Thank you!
I mucked things up with the second keyboard in and ran into a wall with where to plug that into the count CHOP.

So I added the color constants to the code, then added a bit to bypass the other constant so the wrong color couldn’t be displayed and noticed a strange anomaly. I can press the buttons at nearly the same time and get the correct text output but now both constants are bypassed.

I have to avoid the “pushed at the same time” scenario, which is why I went the bypass route. But that seems error prone too. Now I need an else statement to stop both if statements from running, right?
bUZZer_edits.toe (5.34 KB)

Close.

You don’t need to bypass your constant tops. The point of using a select is that you don’t have to think about doing this. The act of using a select will rout the correct color / message at the time of input.

By scripting the reset par on your count that effectively blocks new messages from reaching your CHOP execute. Which means you can’t fire the script until you’ve clicked your clear button.

It’s also worth noting that while you can script the select to point to an op, yo can also just use a path to the target TOP.

Instead of:

op('select1').par.top = op('constant1')

You could just use:

op('select1').par.top = 'constant1'

bUZZer_edits_nobypass.toe (5.32 KB)

One other note -

The CHOP execute for your second keyboard CHOP is set to fire on value change. This means that it will fire both when pressing down ‘c’ and when releasing ‘c’. When the value changes from 0 to 1 the script fires (pressing down the key) and it will fire again when releasing the key going from 1 to 0. I’d move your one liner here up to off to on or on to off (also make sure you flip the correct flag on the DAT to match where you’ve written your script). This will make sure that in controlling the reset you can specify exactly when you want this operation to happen rather than firing twice.

The edge case this protects against might look like:

Round 1 - Player Blue wins.
The operator presses down the c key to clear the board, and before they release the key player red has buzzed in for Round 2, as the operator releases the c key player red’s quick reaction time is erased, allowing player blue to buzz in.

I thought that was the case with the select top but I am still a little confused. This totally works unless I press the buttons at the same time. I still can’t seem to stop constant 2 from firing when player 1 wins.

Am I missing something?

I see.

One thing to consider is your tolerance for error. Assuming there’s a frame’s worth of potential time between responses, than the keyboard in CHOP is probably just fine. If you’re safeguarding against millisecond variance than you might be better off using the keyboard in DAT. Time for the keyboard in DAT is accurate to the millisecond, though you’ll need to do a little more python to get there.

One solution here would be to store the millisecond value in a CHOP channel - one for each player. You could then subtract the two times. Assuming that looks like:

Blue’s time - Red’s Time = difference

Then:

A difference value less than 0 would mean that blue buzzed in first.
A difference value greater than 0 would mean that red buzzed in first.
A difference value of 0 would mean that both buzzed in at the same time. (You probably need a third display state to represent a tie)

This will, however, only provide a solution if there’s at least one millisecond of difference between buzzer presses.

If you need microsecond accuracy, then you might import time, and use the python time library to get more fidelity.

Thank you again for the responses, this has been quite the learning experience.

I took your suggestion and tried the keyboardin DAT. I think I’m almost there, just missing something as I can’t seem to get the push to the select correct. In passing, I sent it to @Deadsound and he replied with yet another way to do it using the DAT and the same basic scripting as before. That’s awesome and thank you @Deadsound for more schooling! But I would love to know what I did wrong with your time method. Any thoughts?
bUZZer_v3.toe (6.45 KB)

Can you say a little more about what’s not behaving the way you expect?

Here’s what I’m seeing when testing:

I’ve bypassed the other examples to ensure that I’m not getting any other scripts firing.

Pressing 1 - constant1 (Red) is selected, and the message “Player 1 Wins” is displayed
Pressing 2 - constant2 (Blue) is selected, and the message “Player 2 Wins” is displayed

The ‘c’ key clears the board between pressing.

This seems like the right behavior. What am I missing?

Hmm … very interesting.

If I bypass all the other operators and use just the keyboardin2 chain, I can see channel values in the null change but that’s it. Are you saying the chopexec1 is firing the constant into the select for you?

Here I’ve isolated just method 3, and I think it’s working correctly.

Windows 10
Touch 099
2017.3340
base_method3.tox (2.72 KB)

My apologies, I have confused you.
Following your guidelines, I was trying to get method 2 to work. I was probably thinking too literal with method 2 and I guess that path will not work.

Method 3, which @Deadsound provided and which you just isolated, seems to be exactly what you were talking about in the first place. You both were saying the same thing, I just missed the boat with the way the toggle constant is used.

OHHHHH!

Sorry sorry, it wasn’t clear to me which method was which.

Here’s a look at just method 2 which is different and accounts for tie events.

The idea here is that all keyboard inputs are traced with the keyboard in DAT. You’ll notice that the callbacks for the DAT are used instead of converting to CHOPs. This lets us track specific key events. You’ll see in the callback that we start by testing state. State essentially gives us key up or down events. By testing first to see if state is true (i.e. the key is pressed down) we can ensure that we don’t fire our script twice. If we didn’t do this then we’d run our script both when we pressed the key down, and when we release the key. In python both these two logic tests are equivalent:

if state: some_script_action_here

and

if state == True: some_script_action_here

Having first isolated the key down events we can then further test to see which key is pressed. Key 1 and 2 will log their time events to constant3 in the value0 and value1 parameters respectively. Pressing the ‘c’ key will click your clear button - this removes the extra keyboard in CHOP whose only function was to click the clear button.

We can compare our two channels with a math CHOP, and then run a script with a CHOP execute based on the results. In the chopexec1 you’ll see that there are three possible conditions:

val > 0 → player 1 wins
val < 0 → player 2 wins
val == 0 → we have tie

Regardless of the results we also turn off the active flag for our execute after an event is logged - this ensures that no one else can buzz in after the fact.

Finally, when we clear the scene and prep for a new round we have to take a few precautions to ensure that we have consistent results.

First we make sure that the active flag for the chop execute is off, this ensures that as we’re resetting vals to prep for the next round we don’t inadvertently fire any scripts. Remember that with our CHOP Execute DAT set to fire on value change, the act of resetting our vals for the next round would likely trigger our script. This safety step ensures that we don’t have to worry about that circumstance.

Next we re-set our select TOP.

Then we reset our test vals. Here I’ve set the vals to be 1 and 0. This ensures that if there’s a tie in the next round we’ll correctly see that event. If we didn’t take this precaution a tie event wouldn’t register - our CHOP execute only fires if the values change, so if we reset our vals to 0 (0 - 0 = 0), and then during the round both players log their responses at the same time and time1 - time2 = 0, then our value won’t have changed and we won’t log a tie event.

Finally we re-activate our chop execute, but in doing so we wait 2 frames. This, again, is another safety precaution. This reset script is likely to happen all in the same frame - which would mean turning our active flag on and off simultaneously. The result of this would likely end up looking like our previous reset events didn’t happen correctly. This 2 frame delay ensures that all of the previous reset steps are complete before we’re ready to log the next event.

While this may seem rather cumbersome I think this satisfies the need to determine three possible response scenarios, as well as a clean re-set procedure between rounds.
buZZer_method2.1.tox (2.94 KB)

Sorry for the delay in my response, little kiddos on spring break …

Clear as mud, right?! Thank you, this is exactly what I was looking for!
I’m going to dive into this tonight to make sure I totally understand what’s going on. The way you explain it makes it seem so logical, and I really appreciate the responses.

Now time to add some other functionality. Time to control a watchout auxiliary timeline!

This first-one-to-hit-wins solution uses CHOPs only, thanks to TImer, Hold and Fan CHOPs.
FamilyFeud4.1.toe (4.92 KB)

Wow, nice!