如何听取其他物体的事件排放?

时间:2015-01-31 21:57:37

标签: javascript node.js

我正在尝试使用事件监听器和排放复制一个后院的捕获游戏。人A'投掷'并且 - 十分之九的人 - B'捕获'然后又回来了。两个人都不能抓住自己的投掷。我该怎么做呢?下面的示例/伪代码。

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');

如果我想扩展游戏以包括第三人(在这种情况下投掷的目标只能是两个可能的接收者之一),该怎么办?

1 个答案:

答案 0 :(得分:0)

我不确切知道你的游戏是如何运作的,所以我用不同的游戏逻辑编写了一个游戏。但您可以轻松地根据自己的需要进行调整。

游戏的工作原理如下:

每个玩家以交替的方式投掷两个骰子。第一个玩家1投掷骰子而不是玩家2,依此类推。 每个玩家可以随机捕捉其他玩家的骰子。捕获的骰子总和得分,得分最高的玩家赢得比赛。

现在到代码。起初,我没有看到你正在做一个nodeJs应用程序。但是我的前端应用程序应该可以在节点上运行并进行一些调整。

我已经使用SignalsJS进行活动。您可以找到示例here

以下引用来自here

  

信号类似于事件发射器/调度器或发布/订阅系统,主要区别在于每个事件类型都有自己的控制器,并且不依赖于字符串来广播/订阅事件

将signalJS视为发布者和订阅者系统是最好的理解它正在做什么。

订阅者/侦听者正在侦听来自发布者的事件。一旦发布者调度某些内容,就会调用订阅者的回调。

要管理事件,您需要在评论中提出某种中介,这样您就可以处理所有事情。在我的演示中,对象DiceGame充当调解器,因为它将玩家和抛出的骰子保存在数组中。

请在jsFiddle找到以下游戏的演示。

(如果有什么需要改进的地方,请在评论中告诉我。)

  //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>