Question

I am currently working on a card battle game. In the main battle scene I am trying to show the cards actively battling one another with their health bars decreasing and eventually weapons moving around the scene as well.

At present, when it enters the battle loop, the display freezes, but I have been logging what is happening and the battle is still happening, just behind the scene. I have separated the battle loop into its own function at the top of the code and call that function with a tap event.

I verify that it is running by using the print statements within the while loop which prints out the current health of the card and the name of the card to the console. The current health of the cards are changing, it's just not changing scenes, but instead freezing on the old one, without actively displaying what is happening.

Here is the code for the entire scene:

function battleScene(playerCards, enemyCards, allCards, cardHealth)
  while not checkIfDead(playerCards) and not checkIfDead(enemyCards) do
    for i=1, 6 do
      if allCards[i]~=0 then
        allCards[i]:battle()
      end
      print( allCards[i]:getCurHealth().." "..allCards[i]:getName() )--The test to see current health of card
      cardHealth[i]:setHealth(allCards[i]:getCurHealth(),allCards[i]:getHealth())
      if checkIfDead(playerCards) or checkIfDead(enemyCards) then
        break
      end
      usleep(2000)
    end
  end
end
---------------------------------------------------------------------------------

-- "scene:show()"
function scene:show( event )

  local sceneGroup = self.view
  local phase = event.phase

  if ( phase == "will" ) then
     -- Called when the scene is still off screen (but is about to come on screen).
  elseif ( phase == "did" ) then
     --The current health of each card is set to max 
     --and then the card is rendered along with health bars

     local card1=test1:render()
     card1.x=display.contentCenterX-100
     card1.y=display.contentCenterY-100
     sceneGroup:insert(card1)

     local card1Health=HealthBar:new()
     card1Health.x=display.contentCenterX-100
     card1Health.y=display.contentCenterY-40
     card1Health:setHealth(test1:getCurHealth(), test1:getHealth())
     sceneGroup:insert(card1Health)

     playerCards={test4, test5, test6}

     enemyCards={test1, test2, test3}

     for i=1, 3 do
       if playerCards[i]:getClass()=="Tank" or playerCards[i]:getClass()=="Damage" then
         playerCards[i]:setBattleSet(enemyCards)
       else
         playerCards[i]:setBattleSet(playerCards)
       end
     end

    for i=1, 3 do
      if enemyCards[i]:getClass()=="Tank" or enemyCards[i]:getClass()=="Damage" then
        enemyCards[i]:setBattleSet(playerCards)
      else
        enemyCards[i]:setBattleSet(enemyCards)
      end
    end

    local allCards={test1, test2, test3, test4, test5, test6}

    bubbleSort(allCards)

    local cardHealth=     {card1Health,card2Health,card3Health,card4Health,card5Health,card6Health}

    local startBattleButton=display.newText( "Start Battle", 0, 0, globals.font.regular, 18 )
    startBattleButton.x = display.contentCenterX
    startBattleButton.y = display.contentCenterY

    local function onTap(event)
      startBattleButton.isVisible=false
      battleScene(playerCards, enemyCards, allCards, cardHealth)
    end

    startBattleButton:addEventListener( "tap", onTap )

    sceneGroup:insert(startBattleButton)

    if checkIfDead(playerCards) then
      win=false
    end
  end
end
Était-ce utile?

La solution

The problem is that your battle scene function is looping and modifying the scene, however the scene engine updates the scene only between event handling calls. I.e., if your tap function gets called and you modify it, you will see the changes only after the tap function returns and the scene engine has processed the new scene state.

So instead of doing this:

function battleScene(args)
  while condition do
     do stuff
  end
end

do instead

function battleScene(args)
  if condition then
     do stuff
     timer.performWithDelay(2, function() battleScene(args) end)
  end
end

This executes "do stuff" when the condition is true, and schedules a call to battleScene for later. The battleScene will return immediately after that, given the display engine the chance to update GUI, and 2 ms later, will call battleScene again, until eventually the condition is false and no re-call will be scheduled. Note that I had to create a temp anonymous function because battleScene takes arguments whereas performWithDelay does not pass any arguments to the scheduled function, but they can be given implicitly as upvalues via anonymous function. To be clear, if battleScene had taken no args, you could have just done this:

function battleScene()
  if condition then
     do stuff
     timer.performWithDelay(2, battleScene)
  end
end
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top