策略类webgame游戏开发

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

策略类webgame游戏开发
目录
前言
1、简单的webgame程序框架
2、一个详细的例子
3、总结
一、WebGame架构篇
二、WebGame事件
三、多线程下数据库并发更新的处理
四、一个可以承载万人在线的架构
五、数据库表设计
六、缓存概述
一、简单的webgame程序框架。

webgame程序构成:三大部分。

第一是数据流程。

第二是程序。

第三是美术。

其中,数据流程包括了功能。

也只有在功能中才能体现数据流程。

数据流程相当的麻烦,后面再讨论。

比如最简单的卖买产品。

要实现这个功能。

那么需要有产品基础表、产品详细表、商店表、背包表。

如果扩展性更强,相应的双表是少不不了的。

表的问题都简单了。

关键是这个物品有什么用。

这样物品的来源,一大堆数据,物品的走向,又是一大堆数据。

最后,这些数据得绕成一个圈。

绕圈是一件困难的事情。

特别是功能和道具多了起来的时候。

难度是2的n次方。

在绕圈之前,如果你比较熟练设计模式。

那么这个过程可以简化。

难度由2的n次方变为1。

只需要有控制器、事件工厂、抽象道具工厂这三个虚类;再加上定时器,任务编辑器,这两个通用类。

即可以构建一个健壮、高扩展的webgame。

在webgame里控制器几乎可以等同于页面。

随便采用一种模板技术即能很方便的处理。

事件工厂是一个抽象类,所有的事件,如打工、战斗、移动等都由事件工厂的生产。

并且接口相同,方便控制器控制。

工厂模式。

抽象道具工厂是一个抽象类,所有的道具,如城市、地图、装备等,都由抽象道具工厂生产。

并且接口相同。

工厂模式。

事件与道具的结合又是一个桥接模式。

美术:
UI。

简洁漂亮的界面总会有好处。

小图标。

道具,地图,装备。

一类至少10个吧?大体上百把个是需要的。

程序分5个部分:
服务器定时器。

(C语言或自己设定服务器)定时循环执行某一段代码。

而这段代码主要是根据数据库的数据进行更新。

这个可以找个C语言程序员来做。

对于C语言程序员来讲,这个功能是相当的简单。

当然,具体的处理数据的判断和操作数据库,需要你自己写。

让C 语言程序员给你段标准代码就行了。

完全支持sql语句的。

php的话,可以配置corn实现。

但是不管是什么操作系统,配置的时间最低是1分钟。

所以,如果你要处理1秒钟刷新一次的情况。

你还需要专门的定时器程序来处理,或者被定时执行的php需要包含sleep().
当然,即使有即时交互,可以不管服务器端。

只处理交互的双方的客户端。

js和ajax实现。

功能页面、功能函数。

主要就是数据存取,判断,数据走向。

用上抽象类,会比较轻松。

不过子类的爆炸是少不了的了。

ajax函数。

(可选)某些需要伪即时的功能要用到。

为了让游戏看起来酷一点。

用吧。

javascript函数。

(可选)模拟客户端的数据计算。

也就是webgame的与时间相关的数据。

分为两部分。

一部分是真实数据,是由服务器端的定时器计算的。

另一部分是只有初始值,客户端显示用的。

不需要即时同步,仅仅需要模拟同步就行。

这里还包括一些漂亮的UI特效。

毕竟是游戏。

数据库。

一大堆基础数据表和详细数据表。

基础数据表:比如等级1到等级100的用户的属性初始值。

详细数据表:每个用户的具体属性。

数据库上,尽量优化。

结构上能用1字节的就别用2字节。

二、一个详细的例子。

单纯的讨论数据流程是件痛苦的事情。

讨论程序而不给代码也是比较痛苦。

这里用的是php+mysql的。

同时,这个例子没有用到类。

如果时间充足的话,今年年底,我会提供一个带即时交互的简单webgame代码和核心类来说明使用了设计模式的好处。

那就按一个超简单的webgame的方式来讨论。

配上适当的代码。

应该有所帮助。

不足的地方也请大家指出,对我个人也是帮助。

我们不去考虑游戏的可玩性,数值平衡等等问题。

我们先只考虑一个简单例子的实现。

那么一个webgame的基本内容需要些什么呢?
数据库:玩家、地图、城市、建筑、武器、士兵。

功能:登陆、升级、个人战斗、士兵之间的战斗、与城市的战斗、修建建筑、打造武器、买卖道具。

(注意:每一个功能,必然对应1个或多个数据表。

上面数据库中所列的只是基础中的基础。


首先是地图、城市、建筑。

这里认为,地图可以有多张,城市在地图上,建筑在城市内。

地图表
Map :Map_ID ,X坐标, Y坐标,City_ID(城市ID),描述。

其中Map_ID是指地图的id。

不是自动编号。

一张地图就是一个Map_ID,可以重复。

城市表
City:City_ID,城市名字,城市所有人,城市等级,城市资源,描述。

建筑表
Build:ID,City_ID,建筑名称,建筑等级,建筑功能。

其中,地图表确定城市的位置,城市表确定城市的相关数据以及所有人,建筑表内的多条信息属于某一个城市。

建表后,显示出来。

一个for循环。

把地图表整个取出来就ok。

跟普通网站的新闻列表没太大区别。

不同的是,你需要取得X坐标和Y坐标定位。

可以用tabel也可以用div。

class Map//地图类
{
var $Map_ID;
function Map_bg_css($Map_ID) {
$this->Map_ID = $Map_ID;
mysql_select_db($db_name,$link);
$sql="select * from map where Map_ID='".$this->Map_ID."' limit 1";
$result=mysql_query($sql,$link);
echo "<style type="."text"."/"."css>";
$rs=mysql_fetch_array($result);
echo "#map{";
echo "position:absolute;";
echo "width:".$rs[X坐标]."px;";
echo "height:".$rs[Y坐标]."px;";
echo "z-index:0;";
echo "left:0px;top:0px;}";
}
function Map_bg($Map_ID){
$this->Map_ID = $Map_ID;
$sql="select * from map where Map_ID='".$this->Map_ID."'";
$result=mysql_query($sql,$link);
while($rs=mysql_fetch_array($result))
{
echo "<div id=Layer_bg_".$rs[X坐标]."_".$rs[Y坐标].">";
echo "<img src=".$rs[Map_bg]." border=0 title=".$rs[ID]."></div>";
}
}
}
上面是一个很简单的地图类。

代码可能不太正确,意思是正确的。

就是根据map表中的坐标,生成了一组div层,以及这一组层的css。

你可以改为table的。

你可以也把坐标放到一个字段里,用数组的形式取。

使用的时候,用
new map;
map(N);
其中N是map表里的地图Map_ID.
城市内的建筑也类似。

如果要显示出来的话。

关于地图,现在我采用的方式更为简单。

通过坐标来判断需要哪些图,然后直接显示出来。

当然没有碰撞什么的,因为暂时不需要。

至于人物走动什么的,不在本文讨论范围。

有了地图和城市后。

涉及到的问题就是城市里资源的产生。

这时候,City表里需要有可供判断的时间和数量的字段。

比如:产生资金量Money,产生资金花费的时间Action_Time,上次产生资金时间Money_time。

这两个字段的数值应该在City_base表里出现。

(即城市基础表,不同等级,不同类型城市的对应数值。

这是给策划填数据用的,建好表后就等策划去头痛吧。

如果你身兼数职。


如何自动产生资源呢?
我们可以在城市所有人改变的时候,写入一个时间。

或者在城市初始化的时候写入一个时间。

$Now_Time=date('Y-m-d H:i:s');
(说明:$开头是变量的意思。

php里特有的。

如果是asp的话可以写成。

Now_Time=Now() )
把$Now_Time写入到Money_time里。

update("UPDATE City SET Money_time='$Now_Time WHERE City_ID='$City_ID' LIMIT 1;");
$City_ID是你自己定义的。

指某一个城市。

如:$City_ID=1;
我们假定当前城市产生资金量为100。

即$Money=100;(具体的数值,应该是由City_base 表里取出的。


假设间隔时间为$Action_Time,我们再假定是每小时执行一次。

即$Action_Time=3600;(具体的数值,是根据你的初始化表里取得的。

也可以根据城市等级或者用户等级取得。

反正随便你自己怎么设定。


这时候,有基础时间了。

有基础资金产量了。

有间隔时间了。

让它循环执行起来就行了。

上面说过,服务端用C语言定时器。

客户端用javascript。

服务端,资源定时器设定为5分钟执行一次。

那么我们的误差就是5分钟。

对网页游戏来说,可以接受。

(战斗的定时器得1分钟吧。

当然服务器够牛的话,几秒钟都可以。


当然,可以完全php写,然后配置php的corn。

现在我在做的程序就是直接用php写了。

包括任意长时间的定时器类,专门控制抽象事件用的。

C的定时器暂时没用。

每次执行什么代码呢?
首先得新建一个定时器任务的表。

目的就是让定时器知道需要执行哪些程序和数据的更新。

表内容比如:城市资源更新。

当然,这个表可要可不要。

建立的好处是方便处理类似保护状态不产生资源之类的问题。

服务端程序:
获得当前服务器时间。

获得当前需要更新城市。

判断服务器时间与$Money_time的时间差。

(时间戳,具体的时间戳网上资料满多的。


判断时间差是否大于$Action_Time。

大于,则更新资源。

同时更新$Money_time。

小于,则无操作。

客户端程序:
获得当前服务器时间。

获得当前城市的$Money,$Money_time,$Action_Time。

使用javascript显示剩余时间的倒计时,以及增加的资源量。

客户端特殊情况触发:
因为客户端显示的资源情况是伪同步,所以当客户端使用该资源的时候。

需要服务端将当前的实际资源更新,属于定时器处理的时间也需要更新。

即,当客户端触发涉及资源的情况时,立即更新当前资源。

同时更新定时器中会用到的$Money_time。

这样才不会造成,看的资源用不到,或者定时器重复产生资源。

总体来说。

这部分程序都很简单。

难点在C语言定时器的制作,以及前台javascipt倒计时的写法上。

C语言定时器,找个C语言程序员,超简单;前台的javascipt,网上有很多倒计时的代码,找个来改改就能用。

<SCRIPT LANGUAGE="JavaScript">
var maxtime = 这里是你的时间差///一个小时,按秒计算,自己调整!
function CountDown(){
if(maxtime>=0){
minutes = Math.floor(maxtime/60);
seconds = Math.floor(maxtime%60);
msg = "你的文字说明"+minutes+"分"+seconds+"秒";//动态显示剩余时间。

document.all["timer"].innerHTML=msg;
//if(maxtime == 3) document.all["timer"].innerHTML='只剩3秒!';
--maxtime;
}
else{
clearInterval(timer);
document.all["timer"].innerHTML='时间到';
}
}
timer = setInterval("CountDown()",1000);
</SCRIPT>
<div id=timer></div>
这个是网上找的代码。

稍微修改就可以用的。

这里只是显示了倒计时。

也可以改为显示资源的增加情况。

C语言里操作mysql数据库。

// TODO: Add your control notification handler code here
bool bRes = m_dbConn.Connect("数据库ip地址", 3306 , "用户名", "密码", "数据库名");
if(!bRes)
{
AfxMessageBox("connect fail");
return;
}
string strSql = "select * from city limit 1";//所有显示或取值类的都用这段。

中间的sql语句可以自己构造。

ResultSet* rs = m_dbConn.ExecuteQuery(strSql);
while(rs->Next())
{
string str = rs->GetString("username");
AfxMessageBox(str.c_str());
}
/*
strSql = "update city set money=money +100 where City_ID='xxx'";//所有的增加、删除、更新都用这段,中间的sql语句可以自己构造。

bRes = m_dbConn.ExecuteUpdate(strSql);
if(!bRes)
{
AfxMessageBox("ExecuteUpdate fail");
}
*/
m_dbConn.Close();
定时器的主函数。

void CBeiLiDlg::Go()
{
while(true)
{
// AfxMessageBox("go");
Sleep(5*1000);//毫秒。

定时器刷新时间。

}
}
当然。

这里的C的代码不能直接用。

只是一部分。

新的方法是,通过php定时器类负责前台、时间到后,调用ajax执行完成。

后台通过定时执行php定时器类的专用处理函数,处理前台掉线,前台未正常执行等情况。

如果我们的新游戏今年年底能正常上线的话。

我可以公开这个类,没技术含量,但是很巧妙。

地图、城市、基本上算是有了。

接下来是城市里的建筑。

上面讲的资源增加,其实定位在建筑上更准确。

不过建筑的分类和数值会复杂很多。

那是策划考虑的问题。

建筑上,只讲一个前台的修建效果。

当然,这个效果是可有可无。

你可以直接给个类似新闻列表的显示,再加个倒计时就行。

显示的效果就是,点修建后。

不刷新页面,调入一张动画图片。

并在时间到后自动转换为其他图片。

<script language='javascript'>
function xiujian()
{
top.abc.document.getElementById('前台建筑位置所在图片的id').src='修建后建筑的图片地址';
//显示修建后的建筑图片。

可以加上后台时间判断。

其中abc,是建筑所在层的id,}
function xiujian1()
{
setTimeout('xiujian()',5000);//动画时间5秒。

这里也可以加入时间判断。

当时间不到的完成的时候,继续调用动画。

}
function donghua()
{
top.abc.document.getElementById('前台建筑位置所在图片的id').src='建筑动画所在的地址';//显示修建动画。

}
donghua();
xiujian1();
</script>
附带讲一下。

如果要考虑多浏览器兼容,那么用prototype.js。

如果只需要ff和ie。

那么用而jqury.js
或尽量自己写。

因为120k的prototype.js不算小。

后台部分,把时间到,增加资源的代码,改为时间到,增加或更新建筑就行了。

又是增加N 个表。

新的方法是,增加事件子类。

建筑基础表:产出,类型,图片等等。

建筑详细表:属于哪个城市,可以在城市表里关联。

关联的方式不同会对程序有很大的影响。

各种关联方式都行,但是一旦关联方式确定后,最好别改动。

现在建筑也有了。

用类似的定时方式,打工,征兵等等都可以实现。

战斗,
兵的参数:兵种,数量,攻击,防御等等。

战斗的临时表:谁的兵,打谁,出发时间,战斗时间,战斗结果。

这里的几个字到是简单。

实际的表会复杂一些。

webgame中,战斗的过程分两种,
一种是给出双方参数,时间到,就根据公式计算结果。

一种是半即时或者即时的战斗,可以边打边喝药边用技能的那种。

第一种流程。

点出兵。

这时候,兵的参数,出发时间,到达时间,都记录进战斗临时表。

定时器中,处理战斗的部分,判断时间是否到开打的时候。

到开打的时间了,则取得被攻击方的兵的参数。

然后通过几个公式计算结果。

处理结果,比如谁的兵挂了多少,战场掉落了多少钱,城市被谁抢到了。

一大堆判断以及updata。

(这里的定时器处理和获得资源的定时器处理是很类似的。


最后把结果分别发给双方。

(又涉及到一个短信息系统。


第二种流程。

点攻击。

马上就处理数据。

打打npc好做。

玩家之间对战,也可以把被攻击的玩家当成npc 来处理。

两个人或两人以上即时战斗。

需要用到ajax了。

目前在技术上和理论上是没问题的,还没实际写代码,所以不好讲。

现在,技术上已经确定可以很好的实现了。

很简单的公式,两种战斗都可以用到:
intval(sqrt($User_B_AP)-sqrt($User_A_DP));
根号下攻击-根号下防御=伤害。

具体写的时候,公式肯定会复杂不少,不过这头痛的事,还是交给策划去做吧。

战斗的具体参数,其实已经不是程序考虑的了。

程序只需要考虑从数据表A取得数据,存入临时表B。

然后当时间到了后(通过定时器实现),再从数据表C取得数据,通过公式计算,最后删除临时表B或者把临时表B存到另外一个地方备份。

这里的思路其实就是定时器类。

数据是哪些?找策划要。

有几个表?找策划要。

战斗公式?找策划要。

有地图、城市、建筑、士兵、战斗后,道具的出现就有必要了。

为什么呢?
有了城市能做什么?产生资源,产生钱,产生兵。

有了士兵做什么?可以抢资源,抢钱。

资源和钱做什么?买道具。

买道具做什么?更好的抢资源和抢钱。

(同时,抢资源,抢钱的时候,资源会被消耗)
这是一个很简单的循环。

就是绕成了一个圈,虽然这个圈很小。

有部分策划想得非常好,就是绕不成圈,那样没任何意义。

首先,需要一个道具的基础表。

自动ID,道具类型,道具属性,说明。

在道具的处理上,可以在玩家表里增加更多字段,道具跟随玩家。

也可以单独建一个道具的详细表。

用类似背包的方式实现。

背包的方式有两种,一是用数组存储,二是用横向表存储。

都挺麻烦的。

不过从道具流通和买卖上考虑。

用背包的方式是值得的。

接下来的功能。

商店。

拍卖行。

基本上跟一般的网站应用很类似。

只不过产品变为了游戏里的道具。

货币是游戏币。

三、总结
上面的小例子,思路上是基本完善,没问题的。

程序代码上只给了一小部分,能真正理解这一小部分。

其他部分的程序应该不是问题。

webgame重要的还是数据流的绕成圈,以及可玩性。

现在讲为:程序的健壮和数据流的清晰。

上面的功能,真的做出来,是不够玩的。

就是没什么可玩性,做出来都没意义。

但是,仅仅是做出来,仍然是一件困难的事情。

游戏里涉及的东西太多。

即使是很简单的游戏,即使webgame看上去很简单,甚至实际也很简单;做出来,非常困难。

没有过开发webgame经验的人,来策划webgame或者说开发webgame。

会觉得很简单。

大功能其实就那么几个。

思路上也容易绕成圈。

实际情况是,一个非常简单的功能,当它需要绕圈的时候;当它需要交互的时候。

这个功能就不再简单,而是复杂,相当的复杂。

这是当你不太明白设计模式的时候,如果你精通设计模式,那么功能就会简单起来。

特别是你想制作一款有足够的可玩性,能面向市场的产品,即使是初期思路非常简单,功能也很单纯。

但你实际策划的时候,实际编程的时候。

大量的数据、数值需要你去处理,大量的交互需要你去处理。

这时候,开始的简单,已经变得复杂了。

虽然从程序的角度讲,技术含量不高。

更准确的讲,是繁琐,非常繁琐。

优秀的策划是可以把数据表列出来,把数据走向清晰的列出来,放在你面前。

这样的策划不多的。

当然,他不一定列得很准确,但是程序员能比较准确的理解他的意思。

web策略类游戏开发(一) WebGame架构篇
1 体系结构
1.1 传统的网站的架构
传统的网站一般都是以N层结构一般N为3,就是我们常说的三层架构。

3层架构分为数据层、业务逻辑层、页面显示层。

1.2 WebGame的架构
WebGame可以看作是网站和游戏的结合体,因此它具备了这两类系统的特性。

我们不但可以把WebGame看作是一个网站,也可以把它看作是一个网络游戏。

的网站是B/S结构,网络游戏则是C/S结构,WebGame则是这两者的结合我们暂且称之为B/C/S结构。

既在用户眼里,它是一个通过浏览器范围的网站。

在服务器系统里,它又是一个传统的C/S结构的网络游戏。

从上图分析,用户通过浏览器访问服务器的时候,首先是访问网页服务器,如windows平台下的IIS,linux下的Apache。

在通过网页服务器,以某种特殊的方式(分布式访问,如.net 下的remoting)去访问游戏服务器,通知游戏逻辑服务器执行玩家操作,并从游戏逻辑服务器里获得游戏相关的信息,或者直接通过访问数据库而获得游戏数据。

1.2.1 为什么要将服务器分为游戏服务器和网页服务器
网页服务器的特点是触发执行,及当有用户访问网页的时候,才会执行该网页的程序代码。

而我们常见的WebGame(Ogame,Travian)这些游戏实际上是需要24小时不间断执行的,因此网页服务器的执行方式并不适合与游戏。

因此我们另外需要一个应用程序来执行这些24小时不间断要做的事情。

这也就是我们需要增加一个游戏服务器的原因。

1.3 Web三国的架构
因为目前Web三国是非商业开发,因此如果照搬上面的WebGame架构来设计,会导致开发周期过长,开发效率低下的问题。

实际上在开发初期,Web三国是按照上面的架构去开发,碰上了上述问题,才换了另外一种结构。

实际性现在Web三国的结构和WebGame架构差不多,只不过将游戏服务器集成到网页服务器里,项目里按照传统的网站架构,将游戏分为:数据层、游戏逻辑层、页面层。

至于如何实现24小时不间断处理,者是通过在游戏启动时,创建一个线程去处理。

这个是里的一个功能,我不清楚php里是否也有这样的功能。

web策略类游戏开发(二) WebGame事件
1 事件系统
事件系统是整个WebGame系统里一个核心的组成部分,我们用它来控制的进程,让游戏世界里能够24小时运转。

1.1 事件的概念
事件是指游戏里玩家的某个(系列)活动,它可以分为瞬时活动和非瞬时活动。

瞬时活动顾名思义就是在玩家发出指令的瞬间就能完成的活动。

像RPG游戏里,玩家从NPC 里购买一瓶药水,在玩家发出这个指令后,玩家的金钱减少,并获得药水,这一切都在玩家发出指令后瞬间完成(当然实际逻辑上处理还需要几个ms处理时间)。

而非瞬时活动则是在玩家发出某个指令后一段事件才会被执行。

例如RPG里玩家鼠标点击地图上某个地方,游戏角色则会自动行走到刚才点击处。

这个移动过程就是一个非瞬时过程,它有了一个移动的过程,这个过程需要消耗一定的时间(玩家能感知的事件)
非瞬时系列活动是指一位或者多位玩家通过一系列的瞬时\非瞬时活动完成一个动作(功能)。

例如wow里面的拍卖场,有1位玩家提供道具,同服务器里的其他玩家对该道具进行竞拍。

在WebGame里,玩家的很多操作其实是非瞬时部分事件是村庄资源减少(前提投资),非瞬时事件是建筑物建设,这个动作(同能)的结果是建筑物等级上升。

又比如《Travian》里的攻击,瞬时事件是当前村庄的士兵减少(派出部队),非瞬时事件是减少的士兵移动到需要攻击的村庄(行军过程),动作结束是,两个村庄的部队开打了(战斗)。

1.2 触发器(事件队列)
前面说了瞬时事件和非瞬时事件的概念,当WebGame在24小时运转的时候,系统会产生大量的非瞬时事件,这些非瞬时事件不会在玩家点击页面时执行,而是需要等一段时间后才会执行,因此在游戏里把这些非瞬时事件拿出来,按事件的执行时间进行排序,组成一个事件队列。

再通过一个触发器,在事件设定的执行时间到达的那时执行相对应的事件。

这里面就涉及到两个内容:
•非瞬时的事件队列
•事件触发器
1.2.1 事件队列
数据库除了用于存储外,其查询功能也非常强大,直接拿来做事件队列很合适。

事件队列里通常保存事件涉及的对象(村庄),结束时间、事件类型以及事件相关参数等。

下表为我们系统里使用的事件表:
ID int
VillageCode int
TargetVillageCode int
Type int
EndTime DateTime
EventObject ntext
保存时将这些对象做xml序列化保存到EventObject字段里。

当然如果为了效率还可以存储二进制序列化后的对象,这样在序列化以及反序列化时能节省大部分时间。

1.2.2 触发器
的处理在触发器上的处理就比较简单了。

在服务器程序启动的时候,就执行一个线程,定时(1s)从数据库里取结束时间<当前事件的事件进行处理。

1 /**//// <summary>
2 /// 事件处理线程
3 /// 每间隔1s处理一次到时间了的事件
4 /// </summary>
5 static void EventThread()
6 {
7 DateTime lastTime = DateTime.Now;
8 while (Run)
9 {
10 try
11 {
12 Event.SystemEvent.DoEvent(lastTime);
13 }
14 catch (Exception ex)
15 {
16 Common.Logging.Error(ex.ToString());
17 }
18
19 long def = DateTime.Now.Ticks - lastTime.Ticks;
20 lastTime = DateTime.Now;
21
22 if (def < 10000000)
23 {
24 // 线程休息,并等待下一次时间间隔
25 int ms = (int)(10000000 - def) / 10000;
26 if (ms > 0)
27 System.Threading.Thread.Sleep(ms);
28 }
29 }
30 }
31
1 /**//// <summary>
2 /// 系统事件
3 /// 主要作用是执行处理事件的过程
4 /// </summary>
5 public class SystemEvent
6 {
7 public static void DoEvent(DateTime time)
8 {
9 List<Event> evs = Event.GetEvents(time);
10 foreach (Event e in evs)
11 {
12 try
13 {
14 IEvent ie = e.Object;
15 if (ie != null)
16 {
17 ie.Parent = e;
18 ie.DoEvent();
19 }
20 }
21 catch (Exception ex)
22 {
23 Common.Logging.Error(ex.ToString(), e.EventObject);
24 }
25 try
26 {
27 e.Delete(); // 从数据库里删除信息
28 }
29 catch (Exception ex)
30 {
31 Common.Logging.Error(ex.ToString());
32 }
33 }
34 }
35 }
36
php
PHP没用过,不过好像不能在PHP页面里无法创建线程,用纯PHP服务端来实现触发器估计有点难度。

但是可以做成一个PHP的应用程序,由应用程序来实现触发器。

1.3 游戏资源的24小时自动增长
游戏资源的24小时自动增长,这是一个有趣的话题,很多刚开始设计WebGame的朋友都会在这个问题上卡一下。

每个人对于如何实现这个功能都有自己的独到见解,我在这里就不能给出一个唯一的答案,这里给的解决方案只是自己正在做的WebGame用到的方案。

首先,我们否定了每个时间间隔(10分钟)就执行更新村庄资源的设计,这即不准确,同
时也很消耗服务器资源。

所以,我们的系统就只有在用户执行事件(瞬时的和非瞬时)的时候才将新的资源信息写入数据库。

平时显示资源的时候用
(当前时间- 上一次更新事件)*资源每小时产量+上一次更新产量
公式计算出当前资源并显示在页面上。

也就是说,每次页面更新时重新计算资源,但只只要用户没有做任何修改资源的动作(事件),就不会把重新计算后的资源写回数据库。

《Travian》在前台界面上看到资源不断的上涨其实是利用JavaScript实现的小效果。

web策略类游戏开发(三) 多线程下数据库并发更新的处理
1 多线程下数据库并发更新的处理
1.1 背景
不知道大家在玩《Travian》时有没有做过这样的事情:
同时打开多个集结点,并设定好要出发的士兵及数量,在快到压秒的时候,快速切换页面,不断的点确定,以确保游戏不会通讯问题导致压秒失败。

再看一个教科书里经常提到的数据库脏数据的案例:
A操作从表里获得数据D=10,在计算的时候,线程刚好进行切换,切换到B,B也需要操作D,并从数据库里取道值为10,在进行简单操作(D=D- 2)后将D=8的值写回数据库。

B操作处理结束后,线程再切换回A操作,这时A在做自己的操作时,仍然采用先前取到D(10)的值,在进行一个简单操作(D=D-1)后,仍然写回数据库。

这时,数据库里的值变为9,而实际上D的值应该是7(D=10-2-1).。

造成这个问题主要是因为CPU在执行A、B操作时没有按照顺序来执行,而是让B抢先在A执行完之前执行,导致它们在计算D的时候,因为数据没有同步而发生写入脏数(A的数据覆盖了B的数据)据的问题。

A操作伪代码:
{
D=GetDB()
D=D-1
SetDB(D)
}
B操作伪代码:
{
D=GetDB()
D=D-2
SetDB(D)
}
一个简单的图表表示它们的操作:。

相关文档
最新文档