diff --git a/examples/keyboardControls.ts b/examples/keyboardControls.ts new file mode 100644 index 0000000..8dddf50 --- /dev/null +++ b/examples/keyboardControls.ts @@ -0,0 +1,123 @@ +/* tslint:disable:no-console */ +import * as WebSocket from 'ws'; + +import { + GameClient, + IButton, + IButtonData, + IGridPlacement, + setWebSocket, +} from '../lib'; + +if (process.argv.length < 3) { + console.log('Usage: node keyboardControls.js '); + process.exit(); +} + +// We need to tell the interactive client what type of websocket we are using. +setWebSocket(WebSocket); + +// As we're on the Streamer's side we need a "GameClient" instance +const client = new GameClient(); + +// Log when we're connected to interactive +client.on('open', () => console.log('Connected to interactive')); + +// This makes grid placement objects dynamically, to be used for our controls below. +function getGridPlacement(x: number, y: number): IGridPlacement[] { + const size = 10; + return [ + { + size: 'large', + width: size, + height: size, + x: x * size, + y: y * size, + }, + { + size: 'medium', + width: size, + height: size, + x: x * size, + y: y * size, + }, + { + size: 'small', + width: size, + height: size, + x: x * size, + y: y * size, + }, + ]; +} + +/** + * These are our controls. The "keyCode" property is the JavaScript key code associated + * with the key that participants will press on their keyboard to trigger the button. + */ +const controls: IButtonData[] = [ + { + controlID: 'up', + kind: 'button', + text: 'W', + keyCode: 87, + position: getGridPlacement(1, 0), + }, + { + controlID: 'left', + kind: 'button', + text: 'A', + keyCode: 65, + position: getGridPlacement(0, 1), + }, + { + controlID: 'down', + kind: 'button', + text: 'S', + keyCode: 83, + position: getGridPlacement(1, 1), + }, + { + controlID: 'right', + kind: 'button', + text: 'D', + keyCode: 68, + position: getGridPlacement(2, 1), + }, +]; + +// Opens the connection by passing in our authentication details and a versionId. +client.open({ + authToken: process.argv[2], + versionId: parseInt(process.argv[3], 10), +}) +.then(() => { + // Creates the controls on the default scene, "default". + return client.createControls({ + sceneID: 'default', + controls, + }); +}) +.then(buttons => { + // Now that our controls are created, we can add some event listeners to each. + buttons.forEach((control: IButton) => { + control.on('keydown', (inputEvent, participant) => { + console.log(`${participant.username} pressed ${inputEvent.input.controlID} with their keyboard.`); + }); + + control.on('keyup', (inputEvent, participant) => { + console.log(`${participant.username} released ${inputEvent.input.controlID} with their keyboard.`); + }); + + control.on('mousedown', (inputEvent, participant) => { + console.log(`${participant.username} pressed ${inputEvent.input.controlID} with their mouse.`); + }); + + control.on('mouseup', (inputEvent, participant) => { + console.log(`${participant.username} released ${inputEvent.input.controlID} with their mouse.`); + }); + }); + + // Controls don't appear unless we tell Interactive that we are ready! + client.ready(true); +}); diff --git a/src/state/interfaces/controls/IButton.ts b/src/state/interfaces/controls/IButton.ts index 4afe082..44b0bc3 100644 --- a/src/state/interfaces/controls/IButton.ts +++ b/src/state/interfaces/controls/IButton.ts @@ -1,6 +1,6 @@ import { IParticipant } from '../'; import { IControl, IControlData, IControlUpdate } from './IControl'; -import { IButtonInput, IInputEvent } from './IInput'; +import { IButtonKeyboardInput, IButtonMouseInput, IInputEvent } from './IInput'; /** * Extends the regular control data with additional properties for Buttons @@ -69,22 +69,42 @@ export interface IButton extends IControl, IButtonData { update(changedData: IButtonUpdate): Promise; /** - * Fired when a participant presses this button. + * Fired when a participant presses this button with their mouse. */ on( event: 'mousedown', listener: ( - inputEvent: IInputEvent, + inputEvent: IInputEvent, participant: IParticipant, ) => void, ): this; /** - * Fired when a participant releases this button. + * Fired when a participant releases this button with their mouse. */ on( event: 'mouseup', listener: ( - inputEvent: IInputEvent, + inputEvent: IInputEvent, + participant: IParticipant, + ) => void, + ): this; + /** + * Fired when a participant presses the key associated with this button. + */ + on( + event: 'keydown', + listener: ( + inputEvent: IInputEvent, + participant: IParticipant, + ) => void, + ): this; + /** + * Fired when a participant releases the key associated with this button. + */ + on( + event: 'keyup', + listener: ( + inputEvent: IInputEvent, participant: IParticipant, ) => void, ): this; diff --git a/src/state/interfaces/controls/IInput.ts b/src/state/interfaces/controls/IInput.ts index 9344f6b..3643baa 100644 --- a/src/state/interfaces/controls/IInput.ts +++ b/src/state/interfaces/controls/IInput.ts @@ -15,7 +15,7 @@ export interface IInput { /** * Extends the base input to include button specific data. */ -export interface IButtonInput extends IInput { +export interface IButtonMouseInput extends IInput { /** * Buttons can emit the mousedown(depressed) or mouseup(released) event. */ @@ -29,6 +29,18 @@ export interface IButtonInput extends IInput { button: number; } +/** + * Extends the base input to include button specific data. + */ +export interface IButtonKeyboardInput extends IInput { + /** + * Buttons can emit the keydown(depressed) or keyup(released) event. + */ + event: 'keydown' | 'keyup'; +} + +export type IButtonInput = IButtonMouseInput | IButtonKeyboardInput; + /** * Extends the base input to include joystick specific data. */