- xml - AJAX/Jquery XML 解析
- 具有多重继承的 XML 模式
- .net - 枚举序列化 Json 与 XML
- XML 简单类型、简单内容、复杂类型、复杂内容
我有一个名为 Rails Across Europe 的 Facebook 游戏。它是用 PHP/MySQL/Facebook Javascript 编写的。我的游戏中缺少的重要功能之一是交互式用户教程。我有一个截屏视频,但我认为它的帮助不够。我注意到大多数开始游戏的用户在放弃之前只玩了一两轮。这是一个复杂的游戏,如果有交互式教程,它会受益匪浅。
问题是我不知道如何创建这样的教程。该游戏由一张欧洲 map 组成,其中包含欧洲城市、铁路线(例如轨道)和城市提供的商品。玩家应该 build 连接城市的轨道,沿着轨道驾驶他的火车,在一个城市提货,并将它们运送到另一个有需求的城市,届时他将获得报酬。
该游戏包含许多不同的事件处理程序,例如 build 轨道、移动火车、在城市装卸 cargo 等。
我正在努力研究如何构建本教程以使其与用户的操作保持同步(反之亦然),以及如何确定用户是否采取了允许教程继续进行的正确操作下一步以及如何知道下一步是什么。
以下是我的前端js代码示例:
var openCargoHolds = 0;
var cargoHoldsUsed = 0;
var loadCargoDialog = null;
var isIE = false;
function setBrowserIsIE(value) {
isIE = value;
}
function moveTrainAuto() {
//debugger;
//consoleTime('moveTrainAuto');
consoleLog('moveTrainAuto');
var ajax = new Ajax();
ajax.responseType = Ajax.JSON;
//consoleTime('moveTrainAuto::move-trains-auto');
ajax.ondone = function(data) {
//consoleTimeEnd('moveTrainAuto::move-trains-auto');
//consoleTimeEnd('moveTrainAuto::get-track-data');
//debugger;
var trackColor = (data.route_owned) ? '#FF0' : '#888';
var trains = [];
trains[0] = data.train;
removeTrain(trains);
drawTrack(data.y1, data.x1, data.y2, data.x2, trackColor, trains);
//debugger;
if(data.code == 'UNLOAD_CARGO') {
consoleLog('moveTrainAuto::unloadCargo');
//unloadCargo();
//myEventMoveTrainManual(null); //continue moving train until final destination is reached
moveTrainManual();
} else if (data.code == 'MOVE_TRAIN_AUTO') { // || data.code == 'TURN_END') {
moveTrainAuto();
} else if (data.code == 'TURN_END') {
consoleLog('moveTrainAuto::turnEnd');
turnEnd();
} else {
/* handle error */
}
}
ajax.post(baseURL + '/turn/move-train-auto-track-data');
//consoleTimeEnd('moveTrainAuto');
}
function moveTrainAutoEvent(evt) {
//debugger;
//moveTrainAuto();
//myEventMoveTrainManual(null, false);
moveTrainManual();
}
function moveTrainManual() {
//consoleTime('moveTrainManual');
consoleLog('moveTrainManual');
//debugger;
state = MOVE_TRAIN_MANUAL;
var ajax = new Ajax();
ajax.responseType = Ajax.JSON;
if(!trainInTransit) {
var actionPrompt = document.getElementById('action-prompt');
actionPrompt.setInnerXHTML('<span><div id="action-text">'+
'Move Train: Select destination'+
'</div>'+
'<div id="action-end">'+
'<form method="POST">'+
'<input type="button" value="Replace Demands" id="replace-demands-btn" style="width: 130px;" />'+
'<input type="button" value="Upgrade Train" disabled="disabled" id="upgrade-train-btn" class="btn" />'+
'<input type="button" value="Build Track" id="build-track-btn" class="btn" />'+
'<input type="button" value="Manage Cargo" id="manage-cargo-btn" class="btn" />'+
'</form>'+
'</div></span>');
var actionButton = document.getElementById('build-track-btn');
actionButton.addEventListener('click', moveTrainEventHandler);
actionButton = document.getElementById('replace-demands-btn');
actionButton.addEventListener('click', moveTrainEventHandler);
actionButton = document.getElementById('upgrade-train-btn');
actionButton.addEventListener('click', moveTrainEventHandler);
var loadCargoButton = document.getElementById('manage-cargo-btn');
loadCargoButton.addEventListener('click', moveTrainEventHandler);
} else {
var actionPrompt = document.getElementById('action-prompt');
actionPrompt.setInnerXHTML('<span><div id="action-text">'+
'Train in-transit to final destination...</div></span>');
}
ajax.ondone = function(data) {
consoleLog('ajax.moveTrainManual');
if(data.code == 'TURN_END') {
consoleLog('moveTrainManual::turnEnd');
turnEnd();
} else {
//debugger;
//myEventMoveTrainManual(null);
}
}
ajax.post(baseURL + '/turn/move-train-manual');
//consoleTimeEnd('moveTrainManual');
}
function unloadCargo() {
//debugger;
consoleLog('unloadCargo');
var actionPrompt = document.getElementById('action-prompt');
actionPrompt.setTextValue('Unloading cargo...');
var ajax = new Ajax();
ajax.responseType = Ajax.JSON;
ajax.ondone = function(data) {
//debugger;
if(data.unloadableCargo.length == 0) {
consoleLog('unloadableCargo == 0');
moveTrainManual();
//loadCargo();
} else {
consoleLog('unloadable cargo='+dump(data.unloadableCargo));
var i = 0;
var j = 0;
var ucCount = data.unloadableCargo.length;
for(i = 0; i < ucCount; i++) {
var cargoDialog = new Dialog();
cargoDialog.showChoice('Unload Cargo', 'Unload ' + data.unloadableCargo[i].goods_name + ' at ' + data.unloadableCargo[i].city_name + ' for ' + data.unloadableCargo[i].payoff + 'M euros?');
cargoDialog.iVal = i;
cargoDialog.onconfirm = function() {
//consoleLog('iVal='+this.iVal);
//consoleLog('unloadable cargo onconfirm='+dump(data.unloadableCargo));
var ajax = new Ajax();
ajax.responseType = Ajax.JSON;
var param = {"city_id": data.unloadableCargo[this.iVal].city_id, "goods_id": data.unloadableCargo[this.iVal].goods_id, "payoff": data.unloadableCargo[this.iVal].payoff};
ajax.ondone = function(demandData) {
refreshDemands();
// update balance
setHtmlBalance(demandData.balance);
if(demandData.post_to_wall) {
Facebook.streamPublish('', demandData.attachment, demandData.action_links);
}
ajax.responseType = Ajax.JSON;
//debugger;
ajax.ondone = function(data) {
if(!data.already_won && data.funds >= data.winning_balance) {
var dialog = new Dialog().showMessage('Congratulations!', 'You have earned over '+data.winning_balance+'M euros. You have won! You may continue playing or start a new game.');
dialog.onconfirm = function() {
moveTrainManual();
}
}
moveTrainManual();
}
ajax.post(baseURL + '/turn/get-player-stats');
}
ajax.post(baseURL + "/turn/do-unload-cargo", param);
}
cargoDialog.oncancel = function() { moveTrainManual(); }
}
}
}
ajax.onerror = function() {
var dialog = new Dialog().showMessage('Request taking too long', 'The system is taking too long to process this request. Please try refreshing the page. If this does not work, please Contact Us with a description of your problem. We are sorry for the inconvenience.');
}
ajax.post(baseURL + '/turn/unload-cargo');
}
function loadCargo() {
//consoleLog('Entering loadCargo()');
var actionPrompt = document.getElementById('action-prompt');
actionPrompt.setTextValue('Loading cargo...');
var ajax = new Ajax();
ajax.responseType = Ajax.JSON;
ajax.ondone = function(data) {
//consoleLog('Entering ondone for load-cargo');
//debugger;
ajax.responseType = Ajax.FBML;
ajax.ondone = function(fbjsData) {
//consoleLog('Entering ondone for load-cargo-dialog-fbjs');
//debugger;
if(data.loadableCargo.length == 0) {
//consoleLog('Calling moveTrainManual()');
moveTrainManual();
} else {
//consoleLog('Instantiating loadCargoDialog');
if(loadCargoDialog == null) {
loadCargoDialog = new Dialog();
//if browser is IE, move dialog up 50px to compensate for bug that causes it to shift down the screen
if(isIE) {
//loadCargoDialog.setStyle('position', 'relative');
//loadCargoDialog.setStyle('top', '-50px');
}
loadCargoDialog.showChoice('Load Cargo', fbjsData, 'Minimize', 'Pass');
} else {
if(isIE) {
//loadCargoDialog.setStyle('position', 'relative');
//loadCargoDialog.setStyle('top', '-50px');
}
loadCargoDialog.showChoice('Load Cargo', fbjsData, 'Minimize', 'Pass');
}
var dlgPrefixString = document.getElementById('dlg-prefix-string').getValue();
//var dlgPrefixString = dlgPrefixElem.getValue();
//consoleLog('Setting dlgBtnNew');
var dlgBtnNew = document.getElementById(dlgPrefixString+'-load-new-submit');
dlgBtnNew.cityId = data.loadableCargo.city_id;
dlgBtnNew.trainId = data.loadableCargo.train_id;
dlgBtnNew.prefixString = dlgPrefixString;
dlgBtnNew.loadCargoDialog = loadCargoDialog;
dlgBtnNew.addEventListener('click', cargoEventHandler); //loadNewCargo);
//consoleLog('Setting dlgBtnDiscard');
var dlgBtnDiscard = document.getElementById(dlgPrefixString+'-discard-existing-submit');
dlgBtnDiscard.cityId = data.loadableCargo.city_id;
dlgBtnDiscard.trainId = data.loadableCargo.train_id;
dlgBtnDiscard.prefixString = dlgPrefixString;
dlgBtnDiscard.loadCargoDialog = loadCargoDialog;
dlgBtnDiscard.addEventListener('click', discardExistingCargo);
loadCargoDialog.onconfirm = function() {
//consoleLog('Entering loadCargoDialog.onconfirm');
// Submit the form if it exists, then hide the dialog.
loadCargoDialog.hide();
actionPrompt = document.getElementById('action-prompt');
actionPrompt.setInnerXHTML('<span><div id="action-text">'+
'The "Load cargo" dialog has been minimized'+
'</div>'+
'<div id="action-end">'+
'<form action="" method="POST">'+
'<input type="button" value="Maximize" id="next-phase" onclick="loadCargo();" />'+
'</form>'+
'</div></span>');
actionButton = document.getElementById('next-phase');
actionButton.setValue('Maximize');
actionButton.addEventListener('click', loadCargoEventHandler);
//consoleLog('Exiting loadCargoDialog.onconfirm');
};
loadCargoDialog.oncancel = function() {
//consoleLog('Entering loadCargoDialog.oncancel');
moveTrainManual();
//consoleLog('Exiting loadCargoDialog.oncancel');
}
}
//consoleLog('Exiting ondone for load-cargo-dialog-fbjs');
}
ajax.onerror = function() {
var dialog = new Dialog().showMessage('Request taking too long', 'The system is taking too long to process this request. Please try refreshing the page. If this does not work, please Contact Us with a description of your problem. We are sorry for the inconvenience.');
}
ajax.post(baseURL + '/turn/load-cargo-dialog-fbjs', data);
//consoleLog('Exiting ondone for load-cargo');
}
ajax.onerror = function() {
var dialog = new Dialog().showMessage('Request taking too long', 'The system is taking too long to process this request. Please try refreshing the page. If this does not work, please Contact Us with a description of your problem. We are sorry for the inconvenience.');
}
ajax.post(baseURL + '/turn/load-cargo');
//consoleLog('Exiting loadCargo');
}
function loadCargoEventHandler(evt) {
if(evt.type == 'click') {
loadCargo();
}
}
function trackEventHandler(evt) {
var x1 = evt.target.x1;
var x2 = evt.target.x2;
var y1 = evt.target.y1;
var y2 = evt.target.y2;
var cost = evt.target.cost;
var prefixString = evt.target.prefixString;
evt.target.payDialog.hide();
ajax = new Ajax();
ajax.responseType = Ajax.JSON;
switch(evt.target.getId()) {
case prefixString + '-confirm-pay-submit':
ajax.ondone = function() {
var empty = [];
drawTrack(parseInt(y1), parseInt(x1), parseInt(y2), parseInt(x2), '#FF0', empty);
//new Dialog().showMessage('test', 'balance='+balance);
balance = balance - parseInt(cost);
setHtmlBalance(balance);
saveCityStartElem.setSrc(publicURL + '/images/city_marker.gif');
saveCityStartElem = null;
var actionPrompt = document.getElementById('action-prompt');
var innerHtml = '<span><div id="action-text">Build Track: Select a city where track building should begin</div>'+
'<div id="action-end">'+
'<form action="">'+
'<input type="button" value="End Track Building" id="next-phase" onClick="moveTrainAuto()" />'+
'</form>'+
'</div></span>';
actionPrompt.setInnerXHTML(innerHtml);
var btn = document.getElementById('next-phase');
btn.addEventListener('click', moveTrainAutoEvent);
state = TRACK_CITY_START;
}
ajax.onerror = function() {
new Dialog().showMessage('Track Building Error', 'An error occured while building this track. Please try again.');
}
ajax.post(baseURL + '/turn/build-track-confirmed', {"europass_used": 0});
break;
case prefixString + '-cancel-pay-submit':
saveCityStartElem.setSrc(publicURL + '/images/city_marker.gif');
saveCityStartElem = null;
var actionPrompt = document.getElementById('action-prompt');
var innerHtml = '<span><div id="action-text">Build Track: Select a city where track building should begin</div>'+
'<div id="action-end">'+
'<form action="">'+
'<input type="button" value="End Track Building" id="next-phase" onClick="moveTrainAuto()" />'+
'</form>'+
'</div></span>';
actionPrompt.setInnerXHTML(innerHtml);
var btn = document.getElementById('next-phase');
btn.addEventListener('click', moveTrainAutoEvent);
state = TRACK_CITY_START;
ajax.post(baseURL + '/turn/build-track-resume');
break;
case prefixString + '-europass-pay-submit':
ajax.ondone = function() {
var empty = [];
drawTrack(parseInt(y1), parseInt(x1), parseInt(y2), parseInt(x2), '#FF0', empty);
//new Dialog().showMessage('test', 'balance='+balance);
saveCityStartElem.setSrc(publicURL + '/images/city_marker.gif');
saveCityStartElem = null;
var actionPrompt = document.getElementById('action-prompt');
var innerHtml = '<span><div id="action-text">Build Track: Select a city where track building should begin</div>'+
'<div id="action-end">'+
'<form action="">'+
'<input type="button" value="End Track Building" id="next-phase" onClick="moveTrainAuto()" />'+
'</form>'+
'</div></span>';
actionPrompt.setInnerXHTML(innerHtml);
var btn = document.getElementById('next-phase');
btn.addEventListener('click', moveTrainAutoEvent);
state = TRACK_CITY_START;
}
ajax.onerror = function() {
new Dialog().showMessage('Track Building Error', 'An error occured while building this track. Please try again.');
}
ajax.post(baseURL + '/turn/build-track-confirmed', {"europass_used": 1});
break;
}
}
function cargoEventHandler(evt) {
//new Dialog().showMessage('loadNewCargo', 'city id='+cityId+', train id='+trainId);
//debugger;
var cityId = evt.target.cityId;
var trainId = evt.target.trainId;
var prefixString = evt.target.prefixString;
evt.target.loadCargoDialog.hide();
switch(evt.target.getId()) {
case prefixString + '-load-new-submit':
//debugger;
ajax = new Ajax();
ajax.responseType = Ajax.JSON;
param = { 'load-cargo-submit': "Load new goods", 'city-id': cityId, 'train-id': trainId };
ajax.ondone = function(data) {
openCargoHolds = data.openCargoHolds;
cargoHoldsUsed = 0;
ajax.responseType = Ajax.FBML;
param = { 'openCargoHolds': data.openCargoHolds, 'cityGoods': data.cityGoods, 'trainId': data.trainId };
ajax.ondone = function(fbjsData) {
//debugger;
var dialog = new Dialog().showChoice('Load Cargo', fbjsData, 'Load cargo', 'Cancel');
var numGoods = data.cityGoods.length;
for(var i = 1; i <= numGoods; i++) {
var decrementGoodsArrow = document.getElementById('goods-decrement-' + i);
decrementGoodsArrow.addEventListener('click', goodsAdjustmentHandler);
var incrementGoodsArrow = document.getElementById('goods-increment-' + i);
incrementGoodsArrow.addEventListener('click', goodsAdjustmentHandler);
}
dialog.onconfirm = function() {
//debugger;
var goods = [];
var goodsIds = [];
numGoods = document.getElementById('goods-count').getValue();
for(var i = 0; i < numGoods; i++) {
j = i + 1;
goods[i] = document.getElementById('goods-' + j).getValue();
goodsIds[i] = document.getElementById('goods-id-' + j).getValue();
}
var trainId = document.getElementById('train-id').getValue();
param = { "goods": goods, "goods-id": goodsIds, "train-id": trainId };
ajax.responseType = Ajax.JSON;
ajax.ondone = function(data) {
loadCargo();
}
ajax.onerror = function() {
var dialog = new Dialog().showMessage('Request taking too long', 'The system is taking too long to process this request. Please try refreshing the page. If this does not work, please Contact Us with a description of your problem. We are sorry for the inconvenience.');
}
ajax.post(baseURL + '/turn/do-load-cargo-new', param);
//dialog.hide();
};
dialog.oncancel = function() {
loadCargo();
}
}
ajax.post(baseURL + '/turn/load-cargo-new-dialog-fbjs', param);
}
ajax.post(baseURL + '/turn/load-cargo-select', param);
break;
case prefixString + '-discard-existing-submit':
ajax = new Ajax();
ajax.responseType = Ajax.JSON;
param = { 'load-cargo-submit': "Discard existing goods", 'city-id': cityId, 'train-id': trainId };
ajax.ondone = function(data) {
ajax.responseType = Ajax.FBML;
param = { 'openCargoHolds': data.openCargoHolds, 'trainGoods': data.trainGoods, 'trainId': data.trainId };
ajax.ondone = function(fbjsData) {
var dialog = new Dialog().showChoice('Discard Cargo', fbjsData, 'Discard cargo', 'Cancel');
dialog.onconfirm = function() {
//debugger;
var goods = [];
var goodsIds = [];
numGoods = document.getElementById('goods-count').getValue();
for(var i = 0; i < numGoods; i++) {
j = i + 1;
goods[i] = document.getElementById('goods-' + j).getValue();
goodsIds[i] = document.getElementById('goods-id-' + j).getValue();
}
var trainId = document.getElementById('train-id').getValue();
param = { "goods": goods, "goods-id": goodsIds, "train-id": trainId };
ajax.responseType = Ajax.JSON;
ajax.ondone = function(data) {
loadCargo();
}
ajax.post(baseURL + '/turn/do-load-cargo-discard', param);
//dialog.hide();
};
dialog.oncancel = function() {
loadCargo();
}
}
ajax.post(baseURL + '/turn/load-cargo-discard-dialog-fbjs', param);
}
ajax.post(baseURL + '/turn/load-cargo-select', param);
break;
}
return true;
}
最佳答案
任何人都需要一段时间才能理解您的代码,因此我认为为您的具体情况提供准确的代码示例有点困难,但对于一些一般性想法...
例如,教程中的每个步骤都可以有一组要求。单击此按钮,执行此操作。因此,要知道用户何时做了某事,您需要在这些操作上添加事件监听器并让它们更改当前“步骤”的状态。
一旦您的步骤的要求得到满足,它就会被下一步简单地替换掉。此时,事件处理程序等将更新以跟踪新步骤的要求。
例如,假设您有一个步骤,用户必须在其中构建一条从 A 到 B 的轨道,然后让火车通过它。在这种情况下,您可能会要求火车必须开往 A,然后再开往 B。因此您的游戏应该在火车到达指定车站时发生某种事件,并且您会跟踪该事件。
希望这对您有所帮助。
关于javascript - 创建 Javascript 游戏教程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6405426/
我正在做一个关于代码学院的教程,我在这里收到一个错误,说“看起来你的函数没有返回‘唉,你没有资格获得信用卡。资本主义就是这样残酷。’”当收入参数为 75 时。”但是该字符串在控制台中返回(由于某种原因
我正在阅读 Go 的官方教程,但很难理解 Channel 和 Buffered Channels 之间的区别。教程的链接是 https://tour.golang.org/concurrency/2和
就目前而言,这个问题不适合我们的问答形式。我们希望答案得到事实、引用资料或专业知识的支持,但这个问题可能会引发辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visit the
关闭。这个问题是off-topic .它目前不接受答案。 想改进这个问题? Update the question所以它是on-topic对于堆栈溢出。 9年前关闭。 Improve this que
已关闭。此问题不符合Stack Overflow guidelines 。目前不接受答案。 要求我们推荐或查找工具、库或最喜欢的场外资源的问题对于 Stack Overflow 来说是偏离主题的,因为
作为 iOS 新手,有大量书籍可以满足学习基础知识的需求。现在,我想转向一些高级阅读,例如 OAuth 和 SQLite 以及动态 API 派生的 TableView 等。您可以推荐任何资源吗? 最佳
就目前而言,这个问题不适合我们的问答形式。我们希望答案得到事实、引用资料或专业知识的支持,但这个问题可能会引发辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visit the
关闭。这个问题是opinion-based .它目前不接受答案。 想要改进这个问题? 更新问题,以便 editing this post 可以用事实和引用来回答它. 关闭 8 年前。 Improve
关闭。这个问题不符合Stack Overflow guidelines .它目前不接受答案。 我们不允许提问寻求书籍、工具、软件库等的推荐。您可以编辑问题,以便用事实和引用来回答。 关闭 8 年前。
前言 很多同学都知道,我们常见的CTF赛事除了解题赛之外,还有一种赛制叫AWD赛制。在这种赛制下,我们战队会拿到一个或多个服务器。服务器的连接方式通常是SSH链接,并且可能一个战队可能会同时有
Memcached是一个自由开源的,高性能,分布式内存键值对缓存系统 Memcached 是一种基于内存的key-value存储,用来存储小块的任意数据(字符串、对象),这些数据可以是数据库调用、A
Perl 又名实用报表提取语言, 是 Practical Extraction and Report Language 的缩写 Perl 是由 拉里·沃尔(Larry Wall)于19
WSDL 是 Web Services Description Language 的缩写,翻译成中文就是网络服务描述语言 WSDL 是一门基于 XML 的语言,用于描述 Web Services 以
关闭。这个问题不满足Stack Overflow guidelines .它目前不接受答案。 想改善这个问题吗?更新问题,使其成为 on-topic对于堆栈溢出。 6年前关闭。 Improve thi
我正在寻找解释在 WPF 中创建自定义用户控件的教程。 我想要一个控件,它结合了一个文本 block 、一个文本框和一个启动通用文件打开对话框的按钮。我已经完成了布局,一切都连接好了。它有效,但它是三
就目前而言,这个问题不适合我们的问答形式。我们希望答案得到事实、引用资料或专业知识的支持,但这个问题可能会引发辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visit the
我接近 fourth page of the Django tutorial 的开始看着vote查看,最后是这样的: # Always return an HttpResponseRedirect a
就目前而言,这个问题不适合我们的问答形式。我们希望答案得到事实、引用资料或专业知识的支持,但这个问题可能会引发辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visit the
是否有任何好的 Qt QSS 教程,或者在某个地方我可以看到样式小部件的示例?如果某处可用,我想要一些完整的引用。除了有关如何设置按钮或某些选项卡样式的小教程外,我找不到任何其他内容。 最佳答案 Qt
就目前而言,这个问题不适合我们的问答形式。我们希望答案得到事实、引用或专业知识的支持,但这个问题可能会引起辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visit the he
我是一名优秀的程序员,十分优秀!