2010-07-26 149 views
1

我一直在爲我寫的Facebook遊戲開發一項新功能。遊戲允許玩家在歐洲城市之間旅行,並提供商品以獲取利潤。我添加的這個功能增加了對遊戲的尋路AI:它允許玩家選擇要前往的城市,然後遊戲會自動將玩家的火車沿着軌道從其起始城市移動到目的地城市。我使用AJAX和setTimeout()從後端獲取數據,並使火車沿着連接城市的軌道移動。請參考代碼,希望能夠更好地理解我正在嘗試做什麼。試圖同步AJAX請求

問題是setTimeout()會被頻繁調用。我放了一個名爲statusFinalDest的全局變量,它可能包含兩個值:ENROUTE和ARRIVED。當列車是ENROUTE時,JS列車運動函數使用setTimeout調用它自己,直到後端返回ARRIVED的statusFinalDest,此時列車運動超時循環(假定)終止。但是,不是每次調用myEventMoveTrainManual()都會轉回後端進程,而是更頻繁地調用它,就好像它不識別statusFinalDest的已更改狀態。我試圖在代碼中加入更多的限制結構來結束這種過度的行爲,但它們似乎並沒有工作。

下面是相關FBJS(Facebook的JS)代碼:

function myEventMoveTrainManual(evt) { 
     if(mutexMoveTrainManual == 'CONTINUE') { 
     //mutexMoveTrainManual = 'LOCKED'; 
     var ajax = new Ajax(); 
     var param = {}; 
     if(evt) { 
      var cityId = evt.target.getParentNode().getId(); 
      var param = { "city_id": cityId }; 
     } 
     ajax.responseType = Ajax.JSON; 
     ajax.ondone = function(data) { 
      statusFinalDest = data.status_final_dest; 
      if(data.code != 'ERROR_FINAL_DEST') { 

      // Draw train at new location 
      trackAjax = new Ajax(); 
      trackAjax.responseType = Ajax.JSON; 
      trackAjax.ondone = function(trackData) { 
       var trains = []; 
       trains[0] = trackData.train; 
       removeTrain(trains); 
       drawTrack(trackData.y1, trackData.x1, trackData.y2, trackData.x2, '#FF0', trains); 

       if(data.code == 'UNLOAD_CARGO') { 
       unloadCargo(); 
       } else if (data.code == 'MOVE_TRAIN_AUTO' || data.code == 'TURN_END') { 
       moveTrainAuto(); 
       } else { 
       /* handle error */ 
       } 
       mutexMoveTrainManual = 'CONTINUE'; 
      } 
      trackAjax.post(baseURL + '/turn/get-track-data'); 
      } 
     } 
     ajax.post(baseURL + '/turn/move-train-set-destination', param); 
     } 

     // If we still haven't ARRIVED at our final destination, we are ENROUTE so continue 
     // moving the train until final destination is reached 
     // statusFinalDest is a global var 
     if(statusFinalDest == 'ENROUTE') { 
     setTimeout(myEventMoveTrainManual, 1000); 
     } 
} 

這裏是後端PHP代碼:

public function moveTrainSetDestinationAction() { 
    require_once 'Train.php'; 
    $trainModel = new Train(); 

    $userNamespace = new Zend_Session_Namespace('User'); 
    $gameNamespace = new Zend_Session_Namespace('Game'); 

    $this->_helper->layout()->disableLayout(); 
    $this->_helper->viewRenderer->setNoRender(); 

    $trainRow = $trainModel->getTrain($userNamespace->gamePlayerId); 
    $statusFinalDest = $trainRow['status_final_dest']; 
    if($statusFinalDest == 'ARRIVED') { 
     $originCityId = $trainRow['dest_city_id']; 
     $destCityId = $this->getRequest()->getPost('city_id'); 
     if(empty($destCityId)) { 
     // If we arrived at final dest but user supplied no city then this method got called 
     // incorrectly so return an error 
     echo Zend_Json::encode(array('code' => 'ERROR_FINAL_DEST', 'status_final_dest' => $statusFinalDest)); 
     exit; 
     } 

     $gameNamespace->itinerary = $this->_helper->getTrainItinerary($originCityId, $destCityId); 
     array_shift($gameNamespace->itinerary); //shift-off the current train city location 
     $trainModel->setStatusFinalDest('ENROUTE', $userNamespace->gamePlayerId); 
     $statusFinalDest = 'ENROUTE'; 
    } 
    $cityId = $trainRow['dest_city_id']; 
    if($trainRow['status'] == 'ARRIVED') { 
     if(count($gameNamespace->itinerary) > 0) { 
     $cityId = array_shift($gameNamespace->itinerary); 
     } 
    } 
    $trainRow = $this->_helper->moveTrain($cityId); 
    if(count($trainRow) > 0) { 
     if($trainRow['status'] == 'ARRIVED') { 
     // If there are no further cities on the itinerary, we have arrived at our final destination 
     if(count($gameNamespace->itinerary) == 0) { 
      $trainModel->setStatusFinalDest('ARRIVED', $userNamespace->gamePlayerId); 
      $statusFinalDest = 'ARRIVED'; 
     } 
     echo Zend_Json::encode(array('code' => 'UNLOAD_CARGO', 'status_final_dest' => $statusFinalDest)); 
     exit; 
     // Pass id for last city user selected so we can return user to previous map scroll postion 
     } else if($trainRow['track_units_remaining'] > 0) { 
     echo Zend_Json::encode(array('code' => 'MOVE_TRAIN_AUTO', 'status_final_dest' => $statusFinalDest)); 
     exit; 
     } else { /* Turn has ended */ 
     echo Zend_Json::encode(array('code' => 'TURN_END', 'status_final_dest' => $statusFinalDest)); 
     exit; 
     } 
    } 
    echo Zend_Json::encode(array('code' => 'MOVE_TRAIN_AUTO_ERROR')); 
    } 
+0

爲了澄清一點可能的困惑:myEventMoveTrainManual()不是一個事件處理程序,但它是從事件處理程序調用的。 – 2010-07-26 01:56:45

回答

2

如果函數myEventMoveTrainManual正在從一個事件處理函數調用,你」每次事件發生時都會重新運行一次新的定時器。

一個簡單的黑客應該幫助是開始一個新的人之前先殺死計時器:

var timerId; 

//... 
clearTimeout(timerId); 
timerId = setTimeout(myEventMoveTrainManual, 1000); 
//... 

但我認爲你真正想做的是調用不同的功能,一個如果你的計時器循環,檢查已經在運行,如果沒有,請調用myEventMoveTrainManual。

+0

感謝您的及時響應。我在我的代碼中添加了clearTimeout()。它確實改進了一些東西,但它並沒有解決我的主要問題。現在我已經意識到我還有一個問題:所有這些過多的函數調用通過調用turnEnd()過於頻繁地誇大了我的計數。這是一個嚴重的問題。無論如何,謝謝你的幫助。 – 2010-07-26 07:06:55