一、選擇開發語言
後台:java .net php
前台:flex javascript ajax
數據庫:mysql mssql
用哪種組合,真的不重要。重要的是時間和成本。復雜的地方在數據的交互和完善,而不在技術或效果的實現。往往遇到一些問題。比如地圖如何編?人物移動如何實現?其實這些問題從技術上實現都比較容易。難在實現後,數據如何交互。沒有解決數據交互的問題,實現這些技術點的意義不大。我用的是php+javascript+mysql。
原因:簡單,上手快。可以比較快速的出產品。
二、程序簡單應用。
、模板
為了方便UI的修改。所以用模板。smart template還算方便。很簡單。代碼也可以嵌套在模板裡。唯一的問題是如果美術不會程序,修改模板還得程序來。不科學啊。
smart template的教程網上有。只說一點。可以在模板(.html的文件)裡用<?php ?>嵌套任何代碼。獲得傳值。用$_obj[‘xxx']或者用$_stack[0][‘']可以和{xxx}寫法的代碼嵌套。跟.php的文件一樣,沒任何區別。
、地圖
因為游戲類型不是ogame模式的,所以地圖並不是自動生成。而是全從數據庫裡調用。思路很簡單。地圖是一整張大圖。切成多個小圖塊。數據庫裡記錄下每個小圖塊對應大圖的絕對坐標。顯示的時候,調用相應坐標區域的小圖塊。
代碼類似:
$sql="select * from map where mapx between $xxx and $xxx and mapy between $ yyy and $yyy ";
意思就是從地圖表裡,獲得橫坐標xx到xx。縱坐標xx到xx的所有小圖塊。比如20個。假設我們寫個函數showMap(x,y),把獲得的數據全顯示出來。地圖可以有很多層。
每個小圖塊都是一個div。具體的控制就用css就行了。小圖塊可以當作div的背景。也可以用作div裡的圖片。控制好div的left和top就行了。(left和top就是小圖塊相對於大圖塊的絕對坐標)showMap(x,y)就放在下面兩個層的裡面。
一個層處理地圖大小:
<div style=\"position:relative;width:".$mapwidth."px;height:".$mapheight."px;overflow:hidden\" >
一個層處理拖動:
復制代碼 代碼如下:
<div style=\"position:absolute;z-index:10;left:2px;top:2px;width:".$mapwidth."px;height:".$mapheight."px;\" onmousedown=\"fDragging(this, event,false);\">
//處理拖動的js代碼。(網上抄的。。感謝這位大大。)
<script>
function fDragging(obj, e, limit){
if(!e) e=window.event;
var x=parseInt(obj.style.left);
var y=parseInt(obj.style.top);
var x_=e.clientX-x;
var y_=e.clientY-y;
if(document.addEventListener){
document.addEventListener('mousemove', inFmove, true);
document.addEventListener('mouseup', inFup, true);
document.body.style.cursor="move";
} else if(document.attachEvent){
document.attachEvent('onmousemove', inFmove);
document.attachEvent('onmouseup', inFup);
document.body.style.cursor="move";
}
inFstop(e);
inFabort(e)
function inFmove(e){
var evt;
if(!e)e=window.event;
if(limit){
var op=obj.parentNode;
var opX=parseInt(op.style.left);
var opY=parseInt(op.style.top);
if((e.clientX-x_)<0) return false;
else if((e.clientX-x_+obj.offsetWidth+opX)>(opX+op.offsetWidth)) return false;
if(e.clientY-y_<0) return false;
else if((e.clientY-y_+obj.offsetHeight+opY)>(opY+op.offsetHeight)) return false;
//status=e.clientY-y_;
}
obj.style.left=e.clientX-x_+'px';
obj.style.top=e.clientY-y_+'px';
inFstop(e);
} // shawl.qiu script
function inFup(e){
var evt;
if(!e)e=window.event;
if(document.removeEventListener){
document.removeEventListener('mousemove', inFmove, true);
document.removeEventListener('mouseup', inFup, true);
} else if(document.detachEvent){
document.detachEvent('onmousemove', inFmove);
document.detachEvent('onmouseup', inFup);
}
inFstop(e);
document.body.style.cursor="auto";
//實現類似google地圖的拖動效果。
ajaxRead('map.php?mapx='+(e.clientX-x_)+'&mapy='+(e.clientY-y_)+'','2');
} // shawl.qiu script
function inFstop(e){
if(e.stopPropagation) return e.stopPropagation();
else return e.cancelBubble=true;
} // shawl.qiu script
function inFabort(e){
if(e.preventDefault) return e.preventDefault();
else return e.returnValue=false;
} // shawl.qiu script
}
//]]>
</script>
注意下面這段代碼:
ajaxRead('map.php?mapx='+(e.clientX-x_)+'&mapy='+(e.clientY-y_)+'','2');
這句代碼的位置,是在拖動層後,釋放鼠標的時候觸發的。你可以用alert(“地圖拖動到了這裡”); 替換。測試下效果。這句代碼的意思是,根據當前地圖被拖動的坐標。調用一個ajax。也就是重新從數據庫裡獲得地圖信息。AjaxRead()是一個ajax的調用函數。你可以全部自己寫。也可以用如prototype.js之類的框架寫。
//處理ajax的代碼。(還是網上抄的,有輕微的改動。。。唉,怎麼老抄呢。。主要是為了節約開發時間。。還有一點就是我的JavaScript很垃圾的(*^__^*) 嘻嘻)
復制代碼 代碼如下:
function ajaxRead(file,action)
{
var xmlObj = null;
if(window.XMLHttpRequest)
{
xmlObj = new XMLHttpRequest();
}
else if(window.ActiveXObject)
{
xmlObj = new ActiveXObject("Microsoft.XMLHTTP");
}
else
{
return;
}
function ajaxDo(action)
{
switch(action)
{
case "2":
document.getElementById('display').innerHTML = xmlObj.responseText;//這裡的display是你在頁面上層的id。上面的地圖代碼都需要放到這個層裡。如<div id=display name=display></div>寫id和name,是為了方便firefox和ie的兼容。
break;
}
}
xmlObj.onreadystatechange = function()
{
/*
if(xmlObj.readyState == 1 )//loading狀態。
{
document.getElementById('xianshi2').innerHTML = "正在載入";
}
*/
if(xmlObj.readyState == 4)//完成狀態時。
{
ajaxDo(action);
}
}
xmlObj.open ('GET', file, true);
//xmlObj.reload('GET', file, true);
xmlObj.send (null);
//xmlObj.abort ('');
}
整個代碼的意思就是:
當拖動地圖釋放鼠標後,顯示層重新獲得數據。並無刷新的顯示出來。地圖裡的圖片都用的png32的透明圖。Ie7和ff3都沒問題。遇到ie6的話。。用gif的替代吧。map.php的功能。根據獲得的x,y顯示相應的一謝謝小圖塊。這個功能其實就是上面說的showMap(x,y),這個很像google地圖的拖動。不過簡單了很多。簡單,效果還不錯。2、角2、角色屬性
因為設定的要求。角色需要有裝備加成,有狀態加成(buff,debuff)。這時候,把所有需要的加成,都放到角色類裡。是一個很好的方法。
大概像這樣:
復制代碼 代碼如下:
class role
{
//獲得角色數據。
getRloe()
{
從數據庫裡獲得角色信息。
}
//獲得裝備加成。
getEquip()
{
獲得裝備加成信息。
}
//獲得狀態加成
getState()
{
獲得狀態加成信息。
}
//把上面獲得的信息相加或者相減,或者調整。
//返回角色數據。
Return xxx
}
專門把這條提出來說。是因為沒把加成放到角色對象裡時。每次要戰斗或者要干點什麼的時候。獲得角色數據後,還要加一大堆代碼處理加成。重復太多。一讓代碼前置,世界就清靜了。。。
、道具
道具比較特殊。因為種類繁多,使用方式多,可能有多個存放地點,可能有唯一道具。有天看了web魔獸的代碼。發現他的道具只有一個表。有一個字段,來處理道具位置,如(1,拍賣行,2,背包,3,倉庫,4,商店)這個辦法挺好的。不過,如果道具的復雜度上去了。比如不同的倉庫,不同的拍賣行,需要合成等等。還是只有分表。
基礎道具表:
id
itemname 名稱
itemprice 價格
itemimage 圖片
itemtype 類型
uptype 增加類型
uppoint 增加點數
addtype 增加類型(永久)
addpoint 增加點數(永久)
cleardebuff 清除debuff
addbuff 增加buff
從uptype開始。都可以寫成xx|yy|zz的形式。最好一一對應。分割符號可以自己選。
調用和處理數據的時候,可以用類似下面的方式:
復制代碼 代碼如下:
$uptype = explode("|", $iteminfo['uptype']);
$uppoint = explode("|", $iteminfo['uppoint']);
for ($j=0;$j<count($uptype);$j++)
{
echo $uptype[$j];
echo $uppoint[$j];
}
倉庫,拍賣行,商店,背包等等。承載道具的地方。只要有個id字段來存道具id就可以。至於是橫表或者是縱表,根據實際需要選擇。目前為止,道具看上去處理得還不錯。這時候,策劃說。道具需要有唯一的,需要能附魔。ok,那麼你把所有組合都填到道具表裡吧。合成也就是a+b=c而已。。一計算。比如40個可能附魔的東西。200個可以附魔的道具。40*200=8000。顯然,策劃不會同意的。那麼頭痛的就是程序了。怎麼處理呢。加表吧。
唯一道具表:
id 唯一道具id(與普通道具id不能重復。方便背包等等調用)
temp_id 臨時id(默認0。合成道具的時候可能會用到。)
itemid 原始道具id(獲得道具的初始值)
fumo_id 附魔id。(默認0,即無附魔)
附魔表:(即增加的屬性)
id
uptype 增加類型
uppoint 增加點數
cleardebuff 清除debuff
addbuff 增加buff
現在看功能修改
首先是道具類:
class Item
{
getItem()
{
//以前是直接根據id獲得道具信息就ok了。
//現在增加了附魔
//首先判斷道具id是否屬於唯一道具。(比如普通道具1-10000。唯一道具id的從10001開始。如果覺得這樣不好,那麼基礎道具表裡,加個字段。判斷道具是否唯一)
if (道具唯一)
{
//從唯一道具表獲得原始道具id和附魔id
//根據原始道具id,或者道具基礎信息。
//根據附魔id,獲得附魔加成信息。
//兩邊值相加。
Return 道具信息。
}
else
{
直接獲得道具信息。
}
}
}
附魔功能:
道具A。(基礎道具)+道具B。(基礎道具) =道具C。(唯一道具)
也就是唯一道具是在附魔功能執行的時候生成。以背包舉例。沒附魔前。
背包內道具A。id為1。
背包內道具B。id為2。
當執行附魔功能後。道具A,道具B的id都置0(橫表),或者刪除了(縱表)。生成一個唯一數。temp_id。(md5生成就行了。)生成一個唯一道具。這時候,根據temp_id,讓A的背包再次獲得唯一道具的id。道具,比較完善的解決了。
以下部分均涉及到一些商業問題,所以只能給思路,及很少的代碼。
--------------------------------------------------------------------------------
、記時器
處理等待xx時間後,執行xx的問題。php自帶一個sleep()函數。等待時間也可以控制。
但是顯然,不管從運用還是效率上講。都不足以支持游戲計時的。思路很簡單。將需要倒計時的事件的所有參數,以及開始時間、結束時間。都存儲到一個表裡。前台用javascript倒計時,時間到後,通過ajax調用時間到後的處理程序。後台每隔一定時間,自動執行一次調用時間到後的處理程序。
至少需要三個php頁面。
一個用來寫存取定時的內容。
一個處理前台時間到時,結束操作。
一個處理後台定時刷新,判斷時間到了就執行結束,時間未到不作處理。
miracle:計時器是不同的計時器對應不同的事件,還是可以多個事件都調用同一個計時器,如果一個玩家他調用了一個計時器計時一個建築建設多長時間,在之中又調用了這個計時器用來計時另一個建築建設多長時間,這樣行不行的?會不會有沖突?
鍵盤上的煙灰:
多個事件對應1個計時器。
你可以在timer裡增加一個字段。比如叫做actiontype(事件類型)
每個用戶可以同時處理多件事。只是每個事情都有固定編號。
比如你的用戶允許同時做5件事情。那麼actiontype裡直接編號為1-5。調用計時器的時候,根據不同的編號,你就知道這是用戶的第某個“線程”。
miracle
如果是不同的用戶,調用同一個計時器是不會發生沖突的吧
鍵盤上的煙灰:
當然不會。你看。userid可以用來確定某一個用戶。actiontype可以用來確定是第幾個線程。
、事件控制
結合記時器,處理開始(),過程(),結束()
復制代碼 代碼如下:
interface Action
{
function doAction();
function beginAction();
function processAction();
function endAction();
}
//簡單事件工廠
class ActionFactory
{
public function getAction($what)
{
$ActionName = $what;
return new $ActionName;
}
}
//比如移動
class Move implements Action
{
function doAction()
{
具體執行函數
什麼時候該這行哪一個過程。都在這裡判斷。
}
function beginAction()
{
事件開始時候執行。
這裡可以把數據存到記時器裡。以後就從記時器裡取數據了。
}
function processAction()
{
從記時器裡取數據。
事件執行的過程。比如用戶刷新頁面的時候。如果仍然在倒計時。那麼就是調用這裡了。
}
function endAction()
{
從記時器裡取數據。
事件結束的過程。
記時到後,完成事件。
}
}
//第一次調用的時候。
$Action = new ActionFactory();
$InstanceAction = $Action->getAction("Move");
$InstanceAction->set ($parameter);
$InstanceAction->doAction();
//以後調用的時候。
$Action = new ActionFactory();
$InstanceAction = $Action->getAction("Move");
//這時候,事件的參數或數據都從記時器裡取得。
$InstanceAction->doAction();
、戰斗
即時和半即時的回合戰斗(兩人或多人即時回合制戰斗)比較繁瑣。
至少包含:
前台:
自動接收邀請信息。Ajax
顯示戰斗過程。Ajax
回合倒計時間。javascript
後台:
發送邀請,接受,拒絕,超時。一個表。戰斗數據。一個表。保存雙方或多方的數據,包括回合時間,第幾回合等。
戰斗控制。一系列函數。處理玩家的操作,將操作存到戰斗數據表裡。時間到後執行操作。
出兵後,直接返回戰報。
寫在事件裡就行了。
function endAction()
{
從記時器裡取數據。
生成回合,生成戰報。
}
注:由於本人工作原因,此系列可能要暫停一段時間才更新,望大家見諒。。。