Once upon a time(一个web游戏的实现方法+源代码)

Once upon a time

 

 

Once upon a time是前几天项目小组成员发过来,类似杀人游戏但比杀人游戏更好玩的多人游戏。这两天有空,用vs2005将游戏写成一个web游戏练练手,不过小组里相应平平,估计是在web上面玩的时候速度太慢(俺们的测试都在不停的催促“打字快点,打字快点”)。因此在网上玩了几次就搁浅了,准备周末到茶室大战几轮。现在在这里把游戏的实现过程以及源代码发布以下,有兴趣的网友可以找几个朋友周末聚聚玩玩这个游戏。

 

1.游戏的玩法:

 

游戏的名字叫做:Once upon a time,简称OUAT

OUAT首先需要的是至少一百张要素卡和五十张结局卡。要素卡上写的故事所必需或者不必需的一些要素:比如“国王”、“公主”、“魔法解除”、“意外的转折”等等。而结局卡上则写着各中各样的结局:比如“从此他们幸福地生活在一起”、“他回到了家里,和父母团聚”、“他们就一直那样跳舞,一直到现在都没结束”等等。

OUAT理论上需要2-无穷大的玩家数量,不过按照标准配置,是5名玩家。

 

1 首先所有玩家各自抽取一张结局卡和五张要素卡,抓在自己手里。

 

2 决定中断优先权顺位,通常是以讲叙者的右手边为最优先,然后逆时针排序。

 

3 上一轮的胜利者(如果是第一轮则通过骰子来决定)开始讲故事。

 

4 讲叙者需要以“很久很久以前”为第一句,任意发挥,讲一段故事。故事的长度不限,不过通常需要起码三段话。这段故事中,必须包含讲叙者手里一张牌上的要素。当讲完故事以后,讲叙者把用到的要素牌亮出来,放出牌堆,表明这张牌已经消耗掉了。

 

5 讲叙者讲完以后,其他玩家则观察自己手里的牌。如果讲叙者刚才的故事里出现了自己牌中的要素,那么就可以申请中断。然后所有中断者按照优先顺位依次亮牌。如果大家公认这张要素牌可以中断,那么讲叙者自己抓一张牌,中断者把中断用的要素牌丢入牌堆,继续(必须)接着讲叙者的故事讲;如果大家工人这张要素牌不能终端,那么中断者把这张牌丢入牌堆,另外抓两张牌;如果没有任何人表示中断或者中断全部失败,讲叙者可以继续讲故事。

 

6 每一段故事,只允许消耗一张要素牌。相应的,每一段故事,其他玩家也只有一次机会进行中断。

范例:

 

  比如玩家A手里抓了“牧羊女”、“剑”、“受伤”、“失而复得”与“变形”

     玩家B手里抓了“狼”、“谷仓”、“愤怒”、“朋友加入”和“死亡”。

 

     A首先讲:“在很久很久以前,有一位【牧羊女】生活在一个幽静的小村庄,她很漂亮,大家都叫她弥塞娅。她的父母双亡,从小就是个孤儿,可是她一直很快乐地生活着,大家都喜欢她。”

 

     然后A宣布这一段故事结束,并亮出自己的【牧羊女】牌,表明这张要素牌消耗掉了。

     这时候,B宣布“中断”,然后亮出了【死亡】,宣称A的故事里出现了死亡的要素。

     中断通过,因为A叙述里出现了“她父母双亡”。

     A抓一张牌【决斗】,B则接着A的故事往下说(注:中断卡也被视做消耗掉了,不纳入故事情节)

     B接着讲:她每天的工作就是放牧,可是,一直有一个困难困扰着她,因为森林里住着一只【狼】,经常潜入村子里来偷吃羊羔。

     然后B宣布这一段故事结束,并亮出自己的【狼】,表明这张要素牌被消耗掉了。

     A宣布中断,并亮出了【受伤】,并解释说狼偷吃羊,这应该有受伤的情况发生。

     大部分玩家表示不同意,因为【受伤】并没有在B的故事里得到体现,有些牵强。于是驳回。A把【受伤】丢入牌堆,另外抓了两张。

  

    (注:中断的合理性界定非常重要。一般来说,只能中断故事里明确提及到的要素,如未提及,即使可能有隐含的逻辑联系,也不能进行中断。比如A讲“他们结婚以后,六十年里他们一直幸福地生活在一起”B试图用【交配】来中断。尽管这六十年里他们可能H过,但是也可能没H过,A文没有提及,所以B驳回。而C用【夫妻】来断,【结婚】和【夫妻】有必然联系,因此中断成功)

 

7 当其中一位玩家把自己所有的要素卡都消耗光以后,就开始进入结局阶段。他必须承接先前的故事讲三段情节,每一段都停下来看别人是否要中断。如果这三段都无人中断,那么他亮出自己的结局卡,念出来作为结局。

 

       (注:结局三段情节不需要出示卡片,但是讲叙者必须要把结局和前面的故事联系起来,构成一个完整的故事,符合逻辑。如果太过生硬,将会遭到全体玩家的反对,要罚两张卡)

 

8 游戏的目的就是尽快消耗掉自己的要素卡,尽量不被别人中断,首先讲完结局的人获得胜利。

以下是游戏中的经典事例:

A 这一次的故事,一开头就被转到了李世民和少林武僧,而大家手抓到的全是童话牌。轮到玩家甲讲,甲百般无奈,只好硬着头皮讲“李世民正打的兴起,却惊动了地下沉睡的上古巨人夸父,夸父一脚下去,把李世民踩成了肉酱。”然后亮出了自己的要素卡“巨人”。玩家乙随即宣布中断,并亮出了自己的要素卡【变形】。

 

   “哪里有什么变形啊?”大家问。

 

   “李世民变成了肉酱。”

 

    “………………”于是全体通过。

B 这一次的故事讲到主角被巫师追杀,获得了一把神兵。玩家甲顺利地进入了结局阶段。他的第一段故事是:“主角不停地打不停地打不停地打,轰下了邪恶的巫师”。无人中断,狡猾的他一看这段话里的要素没人能中断,就采取邪恶的规避手段,故伎重演:“主角主角不停地打不停地打不停地打,轰下了其他所有邪恶的巫师”。这时候,玩家乙宣布中断。

 

   所有的人都在猜想:“第一段和第二段的要素完全一样,什么卡能够中断第一却不能中断第二呢?”

 

   这时候玩家乙从容亮出了自己的要素卡:【兄弟姐妹】

C 玩家丁抽到了一张【堂会】,这是我增补进去的。不幸的是,第一个讲故事的玩家选择了星战背景,于是在整个故事里,玩家丁就不停地在哀求别人。

 

   “于是温度大师获得了自己的紫色光剑。”

 

   “杰迪们得开个堂会庆祝一下吧……”

 

    “别傻了!”(玩家丁灰溜溜地缩会角落里哭泣)

 

    “西斯大帝轰下了所有的杰迪。”

 

    “西斯们总得开个堂会庆祝一下吧……”

 

    “别傻了!”(玩家丁灰溜溜地缩会角落里哭泣)

 

    “you kill my father! No, I am your father!"

 

    “父子相认,得开个堂会庆祝一下吧……”

 

     “别傻了!”(玩家丁灰溜溜地缩会角落里哭泣)

   

     一直持续到游戏结束,堂会还是没开成.

 

 

 

2开发思路

 

 

游戏采用B\S架构。后台使用asp.net 2.0 c# ,前台用 asp.net ajax

 

游戏基本流程:

游戏是多位玩家轮流说故事片段组成。第一位玩家先开始说一段故事,下一位玩家可以以手中的要素牌中断故事(要素牌与玩家说的故事剧情有关),或者放弃中断。

1.     如果所有玩家都放弃中断,则一开始说故事的那位玩家继续说故事。

2.     如果有玩家中断,则其他玩家需要判断中断的要素牌是否合适,

a)     如果合适则中断成功,中断玩家接着上面继续说故事,

b)    如果不合适则中断失败,中断玩家要受到惩罚,剩下的玩家接上面的故事判断是否中断还是放弃。

通过以上过程,一个故事片段就算完成了。在进行多次说故事片段后,哪位玩家手中的要素牌先用完,该玩家就获得游戏胜利。

游戏的流程流程图:

 

 

对象(类)设计:

 

 

 

整个游戏运行的逻辑都放在“游戏”类里,当玩家说故事、中断、故事判断、中断判断等操作的逻辑处理都放在该类里。

“玩家”类则存放玩家的信息,包括名字,要素牌等信息

“玩家队列”类继承自“循环队列”。循环队列的作用是把一个线性的队列首尾相连,形成一个环形队列。

“游戏状态”、“说故事状态”、“中断状态”则是根据游戏规则抽象出来的类。

a)        玩家列表里的玩家与“游戏”类里玩家队列里的玩家顺序一样,但是队列里的第一个元素则是发起该状态的玩家。

b)        玩家状态列表里保存当前状态里玩家的状态

I)         空:表示还没有轮到

II)       等待输入故事:这时玩家可以进行输入故事

III)    等待输入中断\故事是否合理:前面的玩家输入故事后,玩家可以进行中断,或者放弃中断

IV)    等待输入中断是否合理:前面的玩家进行中断后,玩家可以判断中断是否合理

V)      同意:表示故事里没有出现自己的要素牌无法中断\中断理由合适

VI)    反对:表示第一位玩家说的故事不合理,需要重新再说过\中断理由不合适

VII) 完成:该状态里第一位玩家(说故事的人\中断者)已经完成操作

 

 

前台设计:

 

界面设计:

 

因为游戏只是一个简单的Demo,所以,只是用Table简单的划分了一个田字区域:

 

游戏状态区域

游戏信息区域

玩家状态区域

玩家操作区域

 

1)      游戏状态区域:游戏里有多少玩家,每位玩家手上有多少张要素牌,以及当前轮到那位玩家进行游戏

2)      游戏信息区域:玩家说的故事、中断时候的理由、同意\反对故事(中断)的信息、玩家之间的聊天信息

3)      玩家状态区域:玩家当前手里拥有的要素牌

4)      玩家操作区域:轮到玩家进行时输入故事、中断、判断等操作界面

 

 

Ajax的使用:

 

整个游戏采用B\S架构,不像C\S架构那样客户端能够与服务器端一直保持连接,所以在取得游戏最新状态的时候就需要用到Ajax技术。因为是第一次开发Ajax的网站,所以用了Asp.net ajax的两种技术。

1)      使用客户端访问Web Service方法获得游戏状态以及游戏运行信息

     客户端范围Web Service 的方法很简单,就是在<ScriptManager>里把Web Service的地址加进去,然后就想使用一个类一样直接调用Web Service 的方法就可以了。不过使用该方法的时候,在后台代码里无法获得Session 信息,因此如果需要从Web Service里获得针对某个玩家的信息,则还需要再传递一个自定义的SessionID 来帮助Web Service 判断当前访问是那个玩家发出的。当然因为这是第一次用Ajax,所以不确定是否还有其它能够知道当前范围Web Service的是那位用户,如果那位知道请告知一二。

2)      使用UpdatePanel + Timer获得玩家状态以及控制玩家的操作状态

     UpdatePanel 里使用Timer控件,和在客户端调用Web Service方法很类似,都是定时的出发服务器端里某个时间。不同的是,客户端调用Web Service的时候,返回的是一个Xml(字符串),而Timer控件里就强大得多了,它不但能够获得用户的Session信息,还能够操作UpdatePanel里的控件。在游戏里玩家状态区域里会根据玩家当前的状态显示不同的操作Panel的功能,就是在Timer触发的事件里进行。3个不同的Panel的处理过程则和一般的Web页面事件处理过程一样

 

 /Files/yahle/Story.zip

posted on 2007-03-26 22:52  yahle  阅读(8206)  评论(7编辑  收藏  举报