Coffeescript Callbacks和;功能

时间:2014-02-28 00:34:04

标签: javascript while-loop coffeescript

我有这个功能,我正在尝试使用两个由较小的和一个while循环组成的大型函数。一个是玩家转弯的时候,一个是对手的转弯,一个是玩家赢了的时候。当我在浏览器中运行它时,按钮不会执行任何操作。有什么问题?

$attackButtonClick = (opponent) ->
    if playersTurn and not player.Win
        player.attack(opponent)
        if opponent.currentHealth <= 0
            player.Win = true;
            allOff()
            postBattle(opponent)
        else 
            playersTurn = false;
            opponentTurn(opponent)

$defendButtonClick = (opponent) ->
    if playersTurn and not player.Win
        player.defend()
        appendToBattleOutputBox "<p>Your defense has been doubled for one turn.</p>"
        if opponent.currentHealth <= 0
            player.Win = true;
            allOff()
            return postBattle(opponent)
        else 
            playersTurn = false;
            opponentTurn(opponent)

$useItemButtonClick = (opponent) ->
    if playersTurn and not player.Win
        if $useItemSelection.html().length > 15
            itemBeingUsed = $("select[name='useItemSelection'] option:selected").text()
            switch itemBeingUsed
                when "Book of Spells"
                    player.Items.bookOfSpells.use()
                    if player.Items.bookOfSpells.effect is "burn" or player.Items.bookOfSpells.effect is "poison"
                        appendToBattleOutputBox "<p>You have #{player.Items.bookOfSpells.effect}ed #{opponent.Name}.</p>"
                        if player.Items.bookOfSpells.effect is "burn"
                            opponent.Burned = true;
                        else
                            opponent.Poisoned = true;
                    else
                        appendToBattleOutputBox "<p>You have frozen #{opponent.Name}.</p>"
                        opponent.Frozen = true;
                    player.Items.bookOfSpells.used = true;
                when "Shield Charm"
                    if (player.Items.shieldCharm.used is false)
                        player.Items.shieldCharm.use()
                        appendToBattleOutputBox "<p>You will block the next attack with you shield charm.</p>"
                        player.Items.shieldCharm.used = true;
                when "Normal Potion"
                    player.Items.normalPotion.use()
            if opponent.currentHealth <= 0
                player.Win = true;
                allOff()
                postBattle(opponent)
            else 
                playersTurn = false;
                opponentTurn(opponent)
        else 
            noUsableItemP = $("<p id='noUsableItemP'>You have no usable items. Select another command.</p>")
            $battleCommandPromptDiv.empty()
            $battleCommandPromptDiv.append(noUsableItemP)

battle = (opponent) ->
    console.log(p)
    appendToBattleOutputBox "<p>You make the first move!</p>"
    battleInProgress = yes;
    playersTurn = true;
    playerTurn = (opponent) ->
        $attackButton.click -> $attackButtonClick(opponent)

        $defendButton.click -> $defendButtonClick(opponent)

        $useItemButton.click -> $useItemButtonClick(opponent)

        status.Poison("opponent", opponent) if opponent.Poisoned
        status.Burn("opponent", opponent) if opponent.Burned
        status.Freeze("opponent", opponent) if opponent.Frozen
        opponent.undefend() if opponent.defenseDoubled or opponent.defenseTripled
        refresh(opponent)

    opponentTurn = (opponent) ->
        if not playersTurn and not player.Win
            if rndmNumber(10) > 5
                thisTurnAttack = opponent.attack(opponent.Attack, opponent.Luck)
                player.currentHealth -= thisTurnAttack
                refresh(opponent)
                if thisTurnAttack is 0 then appendToBattleOutputBox "<p class='right'>You have blocked the attack.</p>" else appendToBattleOutputBox "<p class='right'>#{thisTurnAttack} damage has been inflicted upon you.</p>"
            else 
                opponent.defend()
                appendToBattleOutputBox "<p class='right'>#{opponent.Name} has doubled his defense for one turn.</p>"
            player.undefend() if player.defenseDoubled or player.defenseTripled
            player.Poisoned = true if (opponent.Type is "Snake" and rndmNumber(10) > 7)
            player.Burned = true if (opponent.Name is "Salamander" and rndmNumber(10) > 3) or opponent.Name is "Fire Dragon"
            player.Frozen = true if (opponent.Name is "Penguin" and rndmNumber(10) > 5) or (opponent.Name is "Wolf" and rndmNumber(10) > 6) or (opponent.Name is "Polar Bear" and rndmNumber(10) > 4)
            status.Poison("player") if player.Poisoned
            status.Burn("player") if player.Burned
            status.Freeze("player") if player.Frozen
            if player.currentHealth <= 0 then postBattle(opponent) else playerTurn(opponent)
            playersTurn = true;

    playerTurn(opponent)

    while (player.Win is true)
        player.Win is false;
        postBattle(opponent)

P.S。在真假之后无视分号。我知道他们不应该在那里。


更新

现在我的问题是,当我尝试调用opponentTurn时,它没有被定义。我试过想办法在Coffeescript中提升一个函数,但什么都没发现。有没有办法提升功能或只是另一种方式来订购代码?

$attackButtonClick = (opponent) ->
    console.log(playersTurn)
    if playersTurn and not player.Win
        player.attack(opponent)
        if opponent.currentHealth <= 0
            player.Win = true;
            allOff()
            postBattle(opponent)
        else 
            playersTurn = false;
            opponentTurn(opponent)

$defendButtonClick = (opponent) ->
    if playersTurn and not player.Win
        player.defend()
        appendToBattleOutputBox "<p>Your defense has been doubled for one turn.</p>"
        if opponent.currentHealth <= 0
            player.Win = true;
            allOff()
            return postBattle(opponent)
        else 
            playersTurn = false;
            opponentTurn(opponent)

$useItemButtonClick = (opponent) ->
    if playersTurn and not player.Win
        if $useItemSelection.html().length > 15
            itemBeingUsed = $("select[name='useItemSelection'] option:selected").text()
            switch itemBeingUsed
                when "Book of Spells"
                    player.Items.bookOfSpells.use()
                    if player.Items.bookOfSpells.effect is "burn" or player.Items.bookOfSpells.effect is "poison"
                        appendToBattleOutputBox "<p>You have #{player.Items.bookOfSpells.effect}ed #{opponent.Name}.</p>"
                        if player.Items.bookOfSpells.effect is "burn"
                            opponent.Burned = true;
                        else
                            opponent.Poisoned = true;
                    else
                        appendToBattleOutputBox "<p>You have frozen #{opponent.Name}.</p>"
                        opponent.Frozen = true;
                    player.Items.bookOfSpells.used = true;
                when "Shield Charm"
                    if (player.Items.shieldCharm.used is false)
                        player.Items.shieldCharm.use()
                        appendToBattleOutputBox "<p>You will block the next attack with you shield charm.</p>"
                        player.Items.shieldCharm.used = true;
                when "Normal Potion"
                    player.Items.normalPotion.use()
            if opponent.currentHealth <= 0
                player.Win = true;
                allOff()
                postBattle(opponent)
            else 
                playersTurn = false;
                opponentTurn(opponent)
        else 
            noUsableItemP = $("<p id='noUsableItemP'>You have no usable items. Select another command.</p>")
            $battleCommandPromptDiv.empty()
            $battleCommandPromptDiv.append(noUsableItemP)

battle = (opponent) ->
    appendToBattleOutputBox "<p>You make the first move!</p>"
    battleInProgress = yes;
    playerTurn = (opponent) ->
        $attackButton.click -> $attackButtonClick(opponent)

        $defendButton.click -> $defendButtonClick(opponent)

        $useItemButton.click -> $useItemButtonClick(opponent)

        status.Poison("opponent", opponent) if opponent.Poisoned
        status.Burn("opponent", opponent) if opponent.Burned
        status.Freeze("opponent", opponent) if opponent.Frozen
        opponent.undefend() if opponent.defenseDoubled or opponent.defenseTripled
        refresh(opponent)

    opponentTurn = (opponent) ->
        if not playersTurn and not player.Win
            if rndmNumber(10) > 5
                thisTurnAttack = opponent.attack(opponent.Attack, opponent.Luck)
                player.currentHealth -= thisTurnAttack
                refresh(opponent)
                if thisTurnAttack is 0 then appendToBattleOutputBox "<p class='right'>You have blocked the attack.</p>" else appendToBattleOutputBox "<p class='right'>#{thisTurnAttack} damage has been inflicted upon you.</p>"
            else 
                opponent.defend()
                appendToBattleOutputBox "<p class='right'>#{opponent.Name} has doubled his defense for one turn.</p>"
            player.undefend() if player.defenseDoubled or player.defenseTripled
            player.Poisoned = true if (opponent.Type is "Snake" and rndmNumber(10) > 7)
            player.Burned = true if (opponent.Name is "Salamander" and rndmNumber(10) > 3) or opponent.Name is "Fire Dragon"
            player.Frozen = true if (opponent.Name is "Penguin" and rndmNumber(10) > 5) or (opponent.Name is "Wolf" and rndmNumber(10) > 6) or (opponent.Name is "Polar Bear" and rndmNumber(10) > 4)
            status.Poison("player") if player.Poisoned
            status.Burn("player") if player.Burned
            status.Freeze("player") if player.Frozen
            if player.currentHealth <= 0 then postBattle(opponent) else playerTurn(opponent)
            playersTurn = true;

    playerTurn(opponent)

    while (player.Win is true)
        player.Win is false;
        postBattle(opponent)

P.S。在真假之后无视分号。我知道他们不应该在那里。

1 个答案:

答案 0 :(得分:4)

没有简单的方法可以解释这一点。你从根本上误解了Javascript(以及扩展名Coffeescript)是如何工作的。

Javascript是一种异步语言,不会阻止io。当你做这样的事情时

while (playerTurn is true and player.Win is false)
    $attackButton.click ->
        player.attack(opponent)
        ...

您正在进入一个循环,该循环为单击事件注册回调,然后再次运行循环。由于你的while循环的性质,这种情况正在发生,数百甚至数千次。这就是你的浏览器崩溃的原因。

检查这种事情的好方法是使用console.log调试语句,这样你就可以通过查看打印输出的数量来查看输入代码的不同部分的频率在你的控制台中。

你需要重新构建游戏的逻辑,这样才能进行循环并等待阻塞条件发生;你有一组在事件发生时互相调用的函数。

我建议的是这样的:

attack = ->
  # conditions go here instead
  if playerTurn and not player.Win
    player.attack(opponent)
    if opponent.currentHealth <= 0
      player.Win = true
      allOff()
      # return statements aren't needed inside callback functions
      postBattle(opponent)
    else 
      playerTurn = false;

# not inside a while loop
$attackButton.click attack

您可以将此模型用于游戏中的任何“活动”,例如点击按钮或更改条件等。


更新

Coffeescript不支持功能提升,所以你在这里只有两个选择。尝试解开你的代码,以便你可以用不需要使用尚未定义的函数,的方式编写代码,使用Livescript

Livescript与Coffeescript有很多兼容性,它为表格提供了许多有用的功能,语法相似。其中一个功能是功能提升。你提升的函数将被声明为:

function opponentTurn (opponent)
  ...
# rather than
opponentTurn = (opponent) ->
  ... 

将分别编译为

function opponentTurn(opponent){
  ...
}

var opponentTurn;
opponentTurn = function(opponent){
  ...
};

我不能推荐Livescript作为Coffeescript的替代品。

http://livescript.net/blog/ten-reasons-to-switch-from-coffeescript.html