Have you ever called a game a button masher? What did you mean? A button masher is game that you press the button over and over. Your score goes up. This is the perfect model for an Alexa game that uses the Echo Buttons.
The game I have in mind goes like this. Alexa announces the start of a round. Players press their button rapidly. Alexa announces the end of the round and reports the score. You can choose to continue with the next round. If you decide not to continue, Alexa saves the game and will offer to resume it next time you start the skill. Continuing with play, after three rounds you can end the game. If you end the game, Alexa declares a winner.
I have built a couple of skills before, but I've never worked with the Echo Buttons. The best way I've found to learn about a new, to me, Alexa feature is to look at the sample code they provide on github.
When working with Echo Buttons, it's important to implement a Roll Call. Roll call is the name given to the process of detecting the Echo Buttons to use with the skill. The Buttons Trivia sample code is a great source for a roll call. I used this as the starting point for the Button Masher Game skill.
Next, I removed all of the trivia related gameplay code and speech model. Then I focused on implementing an InputHandler to listen for button presses. The InputHandler from the sample skill stops listening after the first press. For the button masher game that won't do. We need to capture every button press. And then end the round after timeout. The below code creates a recognizer for any button down. And creates two events, one for every button press 'button_down_event', and the other 'time_out_event' for the end of the round.
ctx.directives.push(directives.GameEngine.startInputHandler({
'timeout': 10000,
'recognizers': {
'any_button_buzz_in': {
"type": "match",
"fuzzy": false,
"anchor": "start",
"gadgetIds": gadgetIds,
"pattern": [{
"action": "down"
}]
}
},
'events': {
'button_down_event': {
'meets': ['any_button_buzz_in'],
'reports': 'matches',
'shouldEndInputHandler': false
},
'time_out_event': {
'meets': ['timed out'],
'reports': 'history',
'shouldEndInputHandler': true
}
}
}));
This line of code makes sure that we don't miss a 'time_out_event' that arrives at the same time as a 'button_down_event'.
let gameEvent = gameEngineEvents.find((it) => it.name === 'time_out_event') || gameEngineEvents[0];
It can be found in right before the switch statement to handle the input handler events.
/**
* For format of the GameEngine.InputHandlerEvent see
* https://developer.amazon.com/docs/gadget-skills/receive-echo-button-events.html#receive
*/
let {
requestEnvelope,
attributesManager
} = handlerInput;
let ctx = attributesManager.getRequestAttributes();
let sessionAttributes = attributesManager.getSessionAttributes();
let gameEngineEvents = requestEnvelope.request.events;
logger.debug("GAME: handleGameInputEvent: " + JSON.stringify(gameEngineEvents));
let gameEvent = gameEngineEvents.find((it) => it.name === 'time_out_event') || gameEngineEvents[0];
switch (gameEvent.name) {
case 'button_down_event':
{
if (!sessionAttributes.roundOver) {
logger.debug('Game: handle game input event: button_down_event');
ctx.outputSpeech.push(settings.AUDIO.BUZZ_IN_AUDIO);
return;
}
return;
}
case 'time_out_event':
{
sessionAttributes.roundOver = true;
// Stop the input handler
Game.stopCurrentInputHandler(handlerInput);
// Shut off the button lights.
let gadgetIds = sessionAttributes.buttons.map((b, i) => b.buttonId);
Game.resetAnimations(handlerInput, gadgetIds);
// Call a helper to compose the score announcements.
logger.debug('Game: handle game input event: round over');
let outputSpeech = gameHelper.makeScoreAnnouncment(sessionAttributes,ctx);
ctx.outputSpeech.push(outputSpeech);
ctx.reprompt.push(outputSpeech);
sessionAttributes.round++
return;
}
default:
logger.error("UNHANDLED EVENT " + gameEngineEvents[0].name);
}
This video shows the game in action via the Alexa Simulator.
Overall working with Alexa Skills has been fun and straight forward.
Comments