我一直在爲我寫的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'));
}
爲了澄清一點可能的困惑:myEventMoveTrainManual()不是一個事件處理程序,但它是從事件處理程序調用的。 – 2010-07-26 01:56:45