views:

241

answers:

2

So, i'm attempting simple card game. I have player "class" with draw function, and public members deck and hand, both are Arrays.

I need to draw a card from the deck, put it in hand and show it in player "hand" area. I'm concerned about the way I do "flip" and "play" buttons (through closures).

Here is the code:

littlegame.player.prototype.draw = function() {
 if (this.canDrawCard()) {
  var card = this.deck.draw(); // this.deck is Array

  //Create card element on the playfield

  var card_object = $('<div class="card"></div>').append($('<span class="attack">' + card.attack + '</span>')).append($('<span class="defence">' + card.defence + '</span>'));

  // Add controls to card
  if (this.playerid == 1) {
   var flipper = $('<span class="flip">Flip</span>');
   flipper.click(function(){
    card.flip();
   });

   var actuator = $('<span class="play">Play</span>');
   console.log('Loading actuator closure with id ' + this.playerid + ' and name ' + this.playername);
   var player = this;

   var old_hand = this.hand.slice(0); // Store a copy of old hand. Stupid trick, i know. It doesn't work

   actuator.click(function(){
    card.play(player.playerid);
    delete card;
    player.hand = old_hand;
   });

   card_object = card_object.append(flipper).append(actuator);
  }

  this.element.append(card_object);
  card.element = card_object;

  // Put card in hand
  this.hand.push(card);
 }
};

What i need is a way to call card.play() and card.flip() on corresponding button presses, with card.play knowing card position in hand, to remove the card. How can I do this?

A: 

I tried the following. I had to leave position of card in hand array in the closure along with links to player and the card itself. It goes like this:

littlegame.player.prototype.draw = function() {
 if (this.hand.length < this.agility) {
  var card = this.deck.draw();

  // Put card in hand
  this.hand.push(card);

  var card_in_hand = this.hand[this.hand.length - 1];
  var card_position = this.hand.length;

  //Create card element on the playfield
  var card_object = $('<div class="card"></div>').append($('<span class="attack">' + card.attack + '</span>')).append($('<span class="defence">' + card.defence + '</span>'));

  // Add controls to card
  if (this.playerid == 1) {
   var flipper = $('<span class="flip">Flip</span>');
   flipper.click(function(){
    card_in_hand.flip();
   });

   var actuator = $('<span class="play">Play</span>');
   console.log('Loading actuator closure with id ' + this.playerid + ' and name ' + this.playername);
   var player = this;

   actuator.click(function(){
    card_in_hand.play(player.playerid);
    player.hand.remove(card_position);
   });

   card_object = card_object.append(flipper).append(actuator);
  }


  this.element.append(card_object);
  card_in_hand.element = card_object;
 }
};

I also used Array.remove() function from John Resig.

Kuroki Kaze
Ooh, no luck. Cards sometimes just stay in hand :( Why, oh why JavaScript arrays is not like PHP arrays?
Kuroki Kaze
+1  A: 
littlegame.player.prototype.draw = function() {
        if (this.canDrawCard()) {
                var card = this.deck.draw(); // this.deck is Array

                //Create card element on the playfield

                var card_object = $('<div class="card"></div>').append($('<span class="attack">' + card.attack + '</span>')).append($('<span class="defence">' + card.defence + '</span>'));

                // Add controls to card
                if (this.playerid == 1) {
                        var flipper = $('<span class="flip">Flip</span>');
                        flipper.click(function(){
                                card.flip();
                        });

                        var actuator = $('<span class="play">Play</span>');
                        console.log('Loading actuator closure with id ' + this.playerid + ' and name ' + this.playername);
                        var player = this;

                        var old_hand = this.hand.slice(0); // Store a copy of old hand. Stupid trick, i know. It doesn't work

                        actuator.click(function(){
                                card.play(player.playerid);
                                delete card;
                                player.hand = old_hand;
                        });

                        card_object = card_object.append(flipper).append(actuator);
                }

                this.element.append(card_object);
                card.element = card_object;

                // Put card in hand
                this.hand.push(card);
                var hand = this.hand;
                card.remove = function () {
                     var i;
                     for(i=0;i<hand.length;i++) {
                       if(hand[i]===this) {
                           hand.splice(i,1);
                       }
                     }
                }
        }
};

The key here is to define the remove function in the scope that contains the variables you're interested in. Here, I define the variable hand, which makes it available inside the remove function that I define immediately after. You can then call the remove function whenever you like. If you know that the card will not change position within the hand, you can shortcut by making the index some variable (say, cardposition) and simply splice your array there, or whatever it is you want to do with your array.

Breton
Hmmm. If, let's say, I splice third card from hand, won't remaining cards shift by 1 to beginning?`card.delete` is cool, I'll try it now.
Kuroki Kaze
yes, but since I don't have your design document on hand, and I don't know what card game you're playing, I had to kind of guess at what you want.
Breton
Actually, I have no design document :) The issue was storing persistent links to objects in array so they doesn't stop working when array elements get deleted.Anyway, seems that your approach actually works well. Thanks :)
Kuroki Kaze