简体   繁体   中英

How to listen to another object's event emissions?

I am trying to replicate a backyard game of catch using event listeners and emissions. Person A 'throws' and - nine times out of ten - person B 'catches' and then throws back. Neither person can catch their own throws. How can I go about doing this? Example/psuedo code below.

var events = require('events'),
    EventEmitter = require('events').EventEmitter;

var a = new EventEmitter(),
    b = new EventEmitter();

a.on('start', function() {
  this.emit('throw', b);
})

a.on('catch', function() {
  console.log('a caught b\'s throw');
  this.emit('throw', b);
});

b.on('catch', function() {
  console.log('b caught a\'s throw');
  this.emit('throw', a);
});

a.emit('start');

What if I wanted to extend the game to include a third person (in which case the target of the throw can only be one of the two possible recipients)

I don't know exactly how your game works, so I have coded a game with a different game logic. But you can adjust it to your needs easily.

The game works like this:

Each player throws two dices in alternating manner. First player 1 throws the dice than player2 and so on. Each player can catch the dice of the other players randomly. The catched dice is summed to the score and the player with the highest score wins the game.

Now to the code. At first, I didn't see that you're doing a nodeJs app. But my front-end app should be runnable on node with some tweaks.

I have used SignalsJS for the eventing. You can find examples here .

The following quote is from here :

A Signal is similar to an Event Emitter/Dispatcher or a Pub/Sub system, the main difference is that each event type has its own controller and doesn't rely on strings to broadcast/subscribe to events

To think of signalJS as publisher and subscriber system is the best to understand what it is doing.

The subscriber/listener is listening for events from the publisher. Once the publisher dispatches something the callback of the subscriber(s) will be called.

And to manage the events you need some kind of mediator as proposed in the comments, so you can handle everything. In my demo the object DiceGame acts as a mediator because it holds the players and the thrown dices in arrays.

Please find the demo of the game below and here at jsFiddle .

(If there is something to improve, please let me know in the comments.)

  //store local reference for brevity var Signal = signals.Signal; /* // simple signals demo code here as an example //custom object that dispatch signals var dice = { threw: new Signal(), //past tense is the recommended signal naming convention carched: new Signal() }; function onThrew(param1, param2) { console.log(param1 + param2); } dice.threw.add(onThrew); //add listener dice.threw.dispatch('user1', ' - dice no. = 6'); //dispatch signal passing custom parameters dice.threw.remove(onThrew); //remove a single listener */ var DiceGame = function(settings) { this.settings = $.extend(DiceGame.defaultSettings, settings); var activePlayer = {}; this.addPlayer = function() { var index = this.players.push({ name: 'player' + (this.players.length + 1), //custom object that dispatch signals dice: { threw: new Signal(), //past tense is the recommended signal naming convention catched: new Signal() }, score: 0, dicesThrown: 0 }); activePlayer = this.players[index-1]; activePlayer.index = index-1; this.setActivePlayer(activePlayer); // add display listener activePlayer.dice.threw.add(this.onDiceThrew, this); activePlayer.dice.catched.add(this.onDiceCatched, this); //console.log(this.players, index, this.$activePlayerInfo, activePlayer); }; this.getActivePlayer = function() { return activePlayer; }; this.setActivePlayer = function(player, index){ if ( typeof index != 'undefined' ) { console.log(index, this.players[index]); activePlayer = this.players[index]; } else { activePlayer = player; } this.updatePlayerInfo(activePlayer.name); this.$activePlayerScore.html(activePlayer.score); }; this.initGame = function() { this.$activePlayerInfo = $(this.settings.elActivePlayer); this.$activePlayerScore = $(this.settings.elActivePlayerScore); this.$gameInfo = $(this.settings.elGameInfo); this.$playField = $(this.settings.elPlayField); // add click handlers (bind to DiceGame obj. with this) $('#newGame').click(this.reset.bind(this)); $('#addPlayer').click(this.addPlayer.bind(this)); $('#changePlayer').click(this.nextPlayer.bind(this)); $('#throw').click(this.throwDice.bind(this)); $('#catch').click(this.catchDice.bind(this)); // add two players _.each(new Array(this.settings.defaultPlayerCount), function(){ this.addPlayer(); }, this); this.setActivePlayer(null, 0); // can change current player by index } this.initGame(); }; DiceGame.defaultSettings = { elActivePlayer: '#activePlayer', elActivePlayerScore: '#activePlayerScore', elGameInfo: '#gameInfo', elPlayField: '#playField', defaultPlayerCount: 2, maxThrownCount: 2 }; DiceGame.prototype = { players: [], diceList: [], updatePlayerInfo: function(text) { this.$activePlayerInfo.html(text); }, reset: function() { this.diceList = []; $.each(this.players, function(index, item) { console.log(item); item.score = 0; item.dicesThrown = 0; }); this.setActivePlayer(null, 0); // can change current player by index this.refreshPlayField(); //this.showGameInfo(''); this.hideGameInfo(); }, nextPlayer: function() { var index = this.getActivePlayer().index; index++; if (index >= this.players.length ) { //'roll over' required! index = 0; } //var playerCopy = this.players.slice(0); this.setActivePlayer(this.players[index]); // next player }, onDiceThrew: function(diceNo) { console.log('threw dice', diceNo); var newDice = {player: this.getActivePlayer(), diceValue: diceNo}; if ( newDice.player.dicesThrown < this.settings.maxThrownCount ) { this.diceList.push(newDice); this.$playField.append($('<p/>').text(newDice.player.name + ' - threw dice: ' +newDice.diceValue)); //console.log('threw', this.diceList); newDice.player.dicesThrown++; } else { //alert(newDice.player.dicesThrown+ ' dices thrown. None left.'); //show message that all dices are thrown this.showGameInfo(newDice.player.dicesThrown+ ' dices thrown. None left.'); return; } console.log(newDice); this.nextPlayer(); // change to next player }, checkGameOver: function() { // all thrown and nothing to catch --> game is over var winner = _.max(this.players, function(player) { console.log(player); return player.score; }); console.log("winner", winner, this.players); var otherPlayers = _.omit(this.players, function(value) { console.log('value', value, value===winner); return value === winner;}); var scoresStr = ''; _.each(otherPlayers, function(player) { scoresStr += player.name + ': ' + player.score + '<br/>'; }); // check if we have a draw. //this.players[0].score = 5; // needed for testing //this.players[1].score = 5; var draw = _.every(this.players, function(player) { return player.score === winner.score; }); console.log(draw); if (draw) { this.showGameInfo('Game over!<br/>Draw with score ' + winner.score, true); } else { // call showGameInfo with true --> keeps message displayed this.showGameInfo('Game over!<br/>' + winner.name + ' wins the game with score ' + winner.score + '!<br/>Other scores:<br/>' + scoresStr, true); } }, onDiceCatched: function() { // catch one dice of other player var player = this.getActivePlayer(); var diceList = this.diceList.slice(0); // copy dice list var allowedDice = _.filter(diceList, function(dice) { return dice.player.name !== player.name; }); var catched = allowedDice[Math.floor(Math.random()*allowedDice.length)]; // console.log('catched dice = ', catched); // add score to active player if ( catched ) { player.score += catched.diceValue; this.$activePlayerScore.html(player.score); // update play field var newDiceList = this.removeItem(diceList, catched); this.diceList = newDiceList.slice(0); // copy new list to the dice list this.refreshPlayField(); var allDone = _.every(this.players.dicesThrown, function(element) { return element == this.settings.maxThrownCount; }); if ( this.diceList.length == 0 && allDone ){ this.checkGameOver(); } } else { // nothing catched // check if game is over? if yes, who is the winner? if ( player.dicesThrown >= this.settings.maxThrownCount ) { this.checkGameOver(); return; } } this.nextPlayer(); // change to next player }, removeItem: function(array, id) { // remove dice from list return _.reject(array, function(item) { //console.log(item, id, item===id); return item === id; // or some complex logic }); }, refreshPlayField: function() { var $field = this.$playField, $row = $('<p/>'); $field.empty(); $.each(this.diceList, function(index, item) { console.log(index, item); $row.text(item.player.name + ' - threw dice: ' +item.diceValue) $field.append($row.clone()); }); }, showGameInfo: function(message, keep) { var $info = this.$gameInfo; $info.html(message); // show info with jQuery animation $info .stop() .animate({opacity:1}, 'fast'); if ( !keep ) { // don't auto hidde --> required for game over $info .delay(2000) // display time of message .animate({opacity:0},'fast'); } }, hideGameInfo: function() { // required to hide gameover message this.$gameInfo.stop() .animate({opacity:0}, 'fast'); // also stop every animation if any is active }, throwDice: function() { var player = this.getActivePlayer(); player.dice.threw.dispatch(Math.floor(Math.random()*6+1)); }, catchDice: function() { console.log('catch dice method'); var player = this.getActivePlayer(); player.dice.catched.dispatch(); } } $(function() { // start game after DOM ready var game = new DiceGame(); }); 
 .playerInfo { position: absolute; top: 0px; right: 10px; border: 1px solid black; width: 200px; } #gameInfo { opacity: 0; margin: 0 auto; color: red; text-align: center; width: 300px; height: 100px; /* center div horizontally and vertically */ position:absolute; left:50%; top:50%; margin:-50px 0 0 -150px; border: 0px solid black; background-color: #FAFFBF; } 
 <script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.7.0/underscore.js"></script> <script src="https://cdn.rawgit.com/millermedeiros/js-signals/master/dist/signals.js"></script> <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <button id="newGame">New Game</button> <button id="addPlayer">New Player</button> <!-- <button id="changePlayer">Change player</button> --> <button id="throw">Throw dice</button> <button id="catch">Catch dice</button> <div class="playerInfo"> Active player: <span id="activePlayer"></span><br/> Score: <span id="activePlayerScore"></span> </div> <div id="gameInfo"></div> <div id="playField"></div> 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM