|
最近使用这个开源程序的朋友越来越多了,给我提出了很多宝贵的意见,在这里我非常感谢,我在逐渐完善它,相信它会越来越好。
前一段时间,有一个朋友说,你能不能在这个框架下实现一个简单的游戏插件,我们好作为开发参考?我答应了。于是就有了以下的文字。我将会在0.85版本推出的时候,给出全部游戏插件样例的开发代码。
不过,在我看来,其实有比开源插件代码更重要的工作,我希望大家如果有兴趣的话,可以把这个PSS发挥到极致,不过要想好好发挥它的能量,就要有一定的开发模式与之匹配。我希望大家读完车篇文章,看到的不仅仅是代码,而是一种开发的思维模式,如何去创造优秀?并且保持激情。
那么来看看,如果我要做一个简单的游戏插件,我需要具备哪些解决问题的能力?(我开始想写这个游戏模块的时候,首先浮出我脑子里面的4个问题。)
(1)我如何组织我的数据?我要求就算在程序崩溃的最坏条件下,我的重要的信息数据如何才能得到最大的保全?
(2)我如何分层组织数据,在BUG出现的时候,怎样做能迅速查找到问题的点?
(3)诚然,随着逻辑的多样化和复杂性,我的代码会看上去越来越乱,那么,我怎么来让它具备可维护性?就算一个新手来看,他应该从何方向着手?
(4)如果上面三个问题解决了,我怎么做到更快速的开发?
从我的从业经验而言,游戏其实是一个很简单的工作,也是一个很复杂的工作。很多人认为游戏门槛很高,其实从服务器角度而言,并非如此,你往往不需要很高深的数据知识。但是你需要通过学习和使用了解一些游戏逻辑的基本处理手段。写代码其实并不难,难在组织,难在沟通,我经历过几个游戏团队,失败的游戏做过,成功的也做过,那么,在我们动手之前,来看看我们会面临什么样的问题。
其实,策划和程序,在处理不好的时候,往往会变成矛盾体。一方面,程序需要维护自己的代码的执行效率,另外,还要懂得策划想要得到的结果。在逻辑简单的时候还好,等到逻辑越变越多的时候,程序往往会变的顾此失彼。策划总是说:"你实现的完全就不是我要的。",或者,"你实现的BUG太多了!"。受罪的同时,还要挨骂。如此恶性循环,最后会把项目推到危险的境地。
那么,什么如何解决这个问题呢?我觉得,关键在于组织,逻辑部分,策划是最清楚的。那么,有些东西就可以让策划去做,程序不再过多参与?恩,让我们想想,既然策划能够写出策划文档,为什么我不再进一步,我给策划提供一种实现的容器,让策划在上面组织积木?当然,这个积木是由我们提供的,策划拿到这些积木去建立他们的大楼,这样做,既节省了反复沟通的成本,也降低了程序开发的复杂性。那么或许你会说,这样的容器哪里去找?其实,这几年,脚本语言和C++的整合越来越成为了一种趋势,那么,我就先选一个我手熟的脚本,Lua来作为这个容器吧。
好了,容器有了,那么我们开始制造积木吧!
想的很美好,在实际游戏开发中,其实这里也是有误区和风险的。程序想,既然要制造积木,自然越细越好,比如,提供给策划各种玩家修改,修改金钱,修改数值。想的很好,洋洋洒洒写了几十个甚至上百个积木。
结果呢?过了一个星期,或许你会发现策划一行脚本也没写出来。
程序:"啊,怎么会这样?"
策划:"大哥,你把我当程序使啊,我哪里会?光看着几十个积木我就头晕,更别说组织了。"
程序:"你妹啊,我已经给你想要的一切了,你写不出来可不是我的问题!"
策划:“你这哪里是协作?分明是推卸责任,什么都我写了要你干啥?”
呵呵,如果你遇到这样的对话,当你遇到这样的时候,你会怎么想呢?或者说,你会怎么回答呢?
说实在的,freeeyes就面对过这样的对话。而且,那个程序很可能就是freeeyes哦。不得不说,这让freeeyes有很大的挫败感,当然,问题还是要解决的。静下来想想。如果自己是一个很完美的建筑师,要建立一个很漂亮的大楼,图纸写好了,结果施工的工人给我了一堆沙子,石子,钢块,木头。就算再优秀的建筑师,也会无从做起,为啥?鬼才知道我要的混凝土配方是怎么做的,我也不会炼钢,更别说如何做钢架构模型了,我又不是木工,别指望我能切削到我图纸上的那些木质结构,我连木锉怎么用都不知道。我要的是可以拆卸的构架,因为我只知道这个地方,要一个小小的构件!
构件,构件!!构件!!!
对,问题就在这里,如果我们把策划想象成建筑师,越是优秀的策划,可能对构件的要求越清晰。
对,解决它的方法,就由我们程序,来提供这些构件吧,你不知道混凝土怎么做,那么我就给你提供混凝土,甚至是一堵可以拆卸的墙。你需要什么样的钢架,我直接提供你钢架。
没错,聪明的呢一定想到了,要做好一件事情,我们就需要符合事物成长的关键因素,我姑且管他叫做"粒度",说俗一点就是"粗细"。好的程序,其实是一个非常完美的组织者,你可以清楚的了解,策划需要什么构件,而不是细致入微的东西。这一定要谨记!也是我设计开发遵守的准则之一。
于是,让我们继续。
就拿最近比较流行的德克萨斯扑克来说吧。
对于策划,他会想要什么呢?
策划说:"我想要知道什么时候发牌,什么时候玩家出来,玩家什么时候坐下,玩家什么时候离开。"
好,非常好,如果策划能说出上述语句,说明你第一步已经成功了。也就是说,策划开始思考,我需要什么样的事件。
让我们来看看,lua脚本是如何写的。- --在房间中的逻辑
- --add by freeeyes
- ROOM_PLAYER_SIZE = 5 --房间内玩家参加的最大人数
- ROOM_PLAYER_VISITOR_SIZE = 5 --观察者玩家的最大个数
- ROOM_ERROR_NULL = 0 --正确的返回值
- --玩家进入房间,nRoomID:房间ID,nPlayerID:玩家ID
- function EnterRoom(nRoomID, nPlayerID)
- end
- --玩家坐下,nRoomID:房间ID,nPlayerID:玩家ID, nLocation是所在位置
- function SitRoom(nRoomID, nPlayerID, nLocation)
- end
- --玩家离开房间nRoomID:房间ID,nPlayerID:玩家ID
- function ExitRoom(nRoomID, nPlayerID)
- end
- --房间踢出玩家规则nRoomID:房间ID,nPlayerID:玩家ID,nOperationIDc操作者ID
- function OutRoom(nRoomID, nPlayerID, nOperationID)
- end
- --玩家变换房间,nSrcRoomID:原始房间ID,nDstRoomID:目标房间ID,nPlayerID:玩家ID
- function ChangeRoom(nSrcRoomID, nDstRoomID, nPlayerID)
- end
- --房间事件到达,定时更新调用。nEventID,事件ID,nPlayerID触发玩家ID,如果没有玩家触发则是-1
- function Update(nRoomID, nPlayerID, nEventID, nData)
- end
- --清理房间,全部退出
- function ClearRoom()
- end
- --初始化房间
- function InitRoom()
- end
- --玩家Player身上的定时器到达
- function PlayerTimer(nRoomID, nPlayerID, nEventID)
- end
- --房间的定时器到达
- function RoomTimer(nRoomID, nPlayerID, nEventID)
- end
复制代码 好了,freeeyes兴冲冲的拿着这个文件给策划看。(到此,程序总耗时10分钟)
策划说,大部分我看懂了,但是,你的最后两个PlayerTimer和RoomTimer是干什么的?freeeyes解释说,这是定时器,因为是一个棋牌引擎,为了通用,我把这个隔离出来,你可以在玩家身上设置一个标记,比如,等待这个玩家出牌。如果20秒到了,玩家没有出牌,由你策划来决定怎么处置。之所以分为两个,是因为一个房间可以有N个玩家,这两种不同的定时器,用于处理不同的事件。策划说,了解了。
好了,那么freeeyes接着说,你可以开发了吧,策划说,还不行。我虽然知道了事件的含义,但是我不知道怎么操作?
恩,那么就让freeeyes来帮你把。
程序:"咱们说的细一点,先说第一个事件,EnterRoom。"
策划:"好的,让我们看看我们能做什么?"
程序:"EnterRoom, 顾名思义,玩家进入一个房间,你可以想象一下啊,我有一个房间,有一个玩家进来了。他会做什么呢?"
策划:"恩,我想让他看看,身边有没有人。"
程序:"恩,然后呢?"
策划:"奥,对了,之前我还得知道房间是否允许进入,是否满员,满员就不让进来了,还有,玩家进来必须先站着,想坐下的时候,才是想在这个房间进行游戏的玩家。"
程序:"非常棒,我似乎看到了你的场景的样子,肯定很精彩。那么,你来把它写在里面如何,用中文?"
策划:"好,我来试试。"
于是策划给了程序一个这样的东东。- --玩家进入房间,nRoomID:房间ID,nPlayerID:玩家ID
- function EnterRoom(nRoomID, nPlayerID)
- --如果房间内座位已满,则提示,你不能进去了
- --如果房间内参观玩家已满,则提示,站着的人都满了,您就别凑这个房间的热闹了
- --如果以上你都没有被踢出,那么贺喜你,你可以进来看看了,进入房间
-
- --当然也不能白看,在这里看是有时间限制的,如果你10秒钟还不坐下,对不起,你得被请出去,你不玩还有人玩呢
- end
复制代码 OK,程序非常高兴,如果你的策划已经能写出这样的东西,说明你已经成功了大半。
在我程序看来,上面每一步就是一个完整的构件。一共需要几个构件呢?
于是,freeeyes写下了以下的实现。(到此,程序总耗时15分钟)- --玩家进入房间,nRoomID:房间ID,nPlayerID:玩家ID
- function EnterRoom(nRoomID, nPlayerID)
- --如果房间内座位已满,则提示
- if LuaFn_Room_API_GetPlayerCount(nRoomID) > ROOM_PLAYER_SIZE then
- LuaFn_Print("RoomID["..nRoomID.."],nPlayerID["..nPlayerID.."] Room Player is full.")
- return -1
- end
-
- --如果房间内参观玩家已满,则提示
- if LuaFn_Room_API_GetVisitorPlayerCount(nRoomID) > ROOM_PLAYER_SIZE then
- LuaFn_Print("RoomID["..nRoomID.."],nPlayerID["..nPlayerID.."] Room Player is full.")
- return -1
- end
-
- --进入房间
- nRet = LuaFn_Room_API_EnterRoom(nRoomID, nPlayerID, "freeeyes", 1000)
- if nRet ~= ROOM_ERROR_NULL then
- LuaFn_Print("RoomID["..nRoomID.."],nPlayerID["..nPlayerID.."] EnterRoom fail.[nRet="..nRet.."]")
- return -1
- else
- --LuaFn_Print("RoomID["..nRoomID.."],nPlayerID["..nPlayerID.."] EnterRoom success.")
-
- --这部分为测试代码,用于数据跟踪
- --nCount = LuaFn_Room_API_GetPlayerCount(nRoomID)
- --nVisitorCount = LuaFn_Room_API_GetVisitorPlayerCount(nRoomID)
- --LuaFn_Print("RoomID["..nRoomID.."],nPlayerID["..nPlayerID.."] EnterRoom [Count="..nCount.."][Visit Count="..nVisitorCount.."]")
- return 0
- end
- end
复制代码 然后给策划看,策划看了一下,于是说,"我看不懂!"
程序此时并不失望,继续说,这就是我给你提供的构件,对应你上面的需求,看一下,是不是你要的?
策划对照着上面自己写的文档,看了一会,说:"恩,大概意思我明白了。"
于是程序说,对,这就是我要给你的构件。首先,我会尝试与你沟通,希望引导你我产生一种共鸣,并建立最简单的构件,当你习惯看这样的构件组织方式,我们的效率就真正起来了。一开始,我会帮你组织一个例子,以后等你手熟了,这些构件你就能自己制造了,而对于我,我只需要按照你的需求填充每个构件内的实现。你看,你做到了,这就是你做到的!
呵呵,良好的端源于敢于沟通,并鼓励,激情,感染。
于策划沟通,程序必须有足够的感染力,互动力,这样,策划才会慢慢放下警惕与恐惧,融入到你的想法中去,这里有freeeyes的准则之一,你必须让你的伙伴,感到成就感。
策划看了一会,说:"让我们一起来,把其他部分填充一下。"
于是策划写出了如下的文字:- --在房间中的逻辑
- --add by freeeyes
- ROOM_PLAYER_SIZE = 5 --房间内玩家参加的最大人数
- ROOM_PLAYER_VISITOR_SIZE = 5 --观察者玩家的最大个数
- ROOM_ERROR_NULL = 0 --正确的返回值
- --玩家进入房间,nRoomID:房间ID,nPlayerID:玩家ID
- function EnterRoom(nRoomID, nPlayerID)
- --如果房间内座位已满,则提示
-
- --如果房间内参观玩家已满,则提示
-
- --进入房间
- end
- --玩家坐下,nRoomID:房间ID,nPlayerID:玩家ID, nLocation是所在位置
- function SitRoom(nRoomID, nPlayerID, nLocation)
- --尝试坐下
- --判断房间是否存在定时器
- --如果没有定时器,则按照规则做一个定时器
- --判断当前时间是否大于房间更新时间5秒
- --添加一个房间的定时器
- end
- --玩家离开房间nRoomID:房间ID,nPlayerID:玩家ID
- function ExitRoom(nRoomID, nPlayerID)
- --玩家离开房间,并做一些清理动作
- end
- --房间踢出玩家规则nRoomID:房间ID,nPlayerID:玩家ID,nOperationIDc操作者ID
- function OutRoom(nRoomID, nPlayerID, nOperationID)
- --踢出玩家
- end
- --玩家变换房间,nSrcRoomID:原始房间ID,nDstRoomID:目标房间ID,nPlayerID:玩家ID
- function ChangeRoom(nSrcRoomID, nDstRoomID, nPlayerID)
- end
- --房间事件到达,定时更新调用。nEventID,事件ID,nPlayerID触发玩家ID,如果没有玩家触发则是-1
- function Update(nRoomID, nPlayerID, nEventID, nData)
- --玩家下注
- --移动到下一个玩家
- --计算当前轮次是不是最后一轮
- --在这里进行牌局结算
- else
- --给下一个玩家身上装上定时器
- return 0
- end
- --清理房间,全部退出
- function ClearRoom()
- end
- --初始化房间
- function InitRoom()
- end
- --玩家Player身上的定时器到达
- function PlayerTimer(nRoomID, nPlayerID, nEventID)
- --到期玩家没有下注
-
- --在这里处理玩家移动的规则
- end
- --房间的定时器到达
- function RoomTimer(nRoomID, nPlayerID, nEventID)
- --如果是1001事件,那么就是到时发牌事件(在这个C++函数里面完成了发牌,下大盲注,小盲注以及标记房间状态的任务)
- --设置开始的玩家ID,以此为轮次计算的依据,如果GetRoomNextPlayerID到了这个玩家,则轮次计算+1
-
- --对下一个出牌的玩家添加定时器
- end
- end
- end
复制代码 好了,程序拿到这个。来看看。他怎么做的- --在房间中的逻辑
- --add by freeeyes
- ROOM_PLAYER_SIZE = 5 --房间内玩家参加的最大人数
- ROOM_PLAYER_VISITOR_SIZE = 5 --观察者玩家的最大个数
- ROOM_ERROR_NULL = 0 --正确的返回值
- --玩家进入房间,nRoomID:房间ID,nPlayerID:玩家ID
- function EnterRoom(nRoomID, nPlayerID)
- --如果房间内座位已满,则提示
- if LuaFn_Room_API_GetPlayerCount(nRoomID) > ROOM_PLAYER_SIZE then
- LuaFn_Print("RoomID["..nRoomID.."],nPlayerID["..nPlayerID.."] Room Player is full.")
- return -1
- end
-
- --如果房间内参观玩家已满,则提示
- if LuaFn_Room_API_GetVisitorPlayerCount(nRoomID) > ROOM_PLAYER_SIZE then
- LuaFn_Print("RoomID["..nRoomID.."],nPlayerID["..nPlayerID.."] Room Player is full.")
- return -1
- end
-
- --进入房间
- nRet = LuaFn_Room_API_EnterRoom(nRoomID, nPlayerID, "freeeyes", 1000)
- if nRet ~= ROOM_ERROR_NULL then
- LuaFn_Print("RoomID["..nRoomID.."],nPlayerID["..nPlayerID.."] EnterRoom fail.[nRet="..nRet.."]")
- return -1
- else
- --LuaFn_Print("RoomID["..nRoomID.."],nPlayerID["..nPlayerID.."] EnterRoom success.")
-
- --这部分为测试代码,用于数据跟踪
- --nCount = LuaFn_Room_API_GetPlayerCount(nRoomID)
- --nVisitorCount = LuaFn_Room_API_GetVisitorPlayerCount(nRoomID)
- --LuaFn_Print("RoomID["..nRoomID.."],nPlayerID["..nPlayerID.."] EnterRoom [Count="..nCount.."][Visit Count="..nVisitorCount.."]")
- return 0
- end
- end
- --玩家坐下,nRoomID:房间ID,nPlayerID:玩家ID, nLocation是所在位置
- function SitRoom(nRoomID, nPlayerID, nLocation)
- --尝试坐下
- nRet = LuaFn_Room_API_PlayerSit(nRoomID, nPlayerID, nLocation)
- if nRet ~= ROOM_ERROR_NULL then
- LuaFn_Print("RoomID["..nRoomID.."],nPlayerID["..nPlayerID.."] SitRoom fail.[nRet="..nRet.."]")
- return -1
- else
- --LuaFn_Print("RoomID["..nRoomID.."],nPlayerID["..nPlayerID.."] SitRoom success.")
-
- --判断房间是否存在定时器
- if LuaFn_RoomTimer_API_Check(nRoomID) == false then
- --如果没有定时器,则按照规则做一个定时器
- nCount = LuaFn_Room_API_GetPlayerCount(nRoomID)
- nVisitorCount = LuaFn_Room_API_GetVisitorPlayerCount(nRoomID)
- LuaFn_Print("RoomID["..nRoomID.."],nPlayerID["..nPlayerID.."] SitRoom [Count="..nCount.."][Visit Count="..nVisitorCount.."]")
- if nCount > 1 then
- --判断当前时间是否大于房间更新时间5秒
- if LuaFn_Room_API_CheckRoomUpdateTime(nRoomID, 5) == true then
- --添加一个房间的定时器
- nRet = LuaFn_RoomTimer_API_Add(2, nRoomID, nPlayerID, 1001)
- if nRet <= 0 then
- LuaFn_Print("RoomID["..nRoomID.."],nPlayerID["..nPlayerID.."] SitRoom timer fail.[nRet="..nRet.."]")
- else
- --LuaFn_Print("RoomID["..nRoomID.."],nPlayerID["..nPlayerID.."] SitRoom timer success.[nsecond=5]")
- end
- else
- --添加一个房间的定时器
- nRet = LuaFn_RoomTimer_API_Add(5, nRoomID, nPlayerID, 1001)
- if nRet <= 0 then
- LuaFn_Print("RoomID["..nRoomID.."],nPlayerID["..nPlayerID.."] SitRoom timer fail.[nRet="..nRet.."]")
- else
- --LuaFn_Print("RoomID["..nRoomID.."],nPlayerID["..nPlayerID.."] SitRoom timer success.[nsecond=2]")
- end
- end
- end
- end
- end
- return 0
- end
- --玩家离开房间nRoomID:房间ID,nPlayerID:玩家ID
- function ExitRoom(nRoomID, nPlayerID)
- --调试代码
- --nCount = LuaFn_Room_API_GetPlayerCount(nRoomID)
- --nVisitorCount = LuaFn_Room_API_GetVisitorPlayerCount(nRoomID)
- --LuaFn_Print("RoomID["..nRoomID.."],nPlayerID["..nPlayerID.."] ExitRoom [Count="..nCount.."][Visit Count="..nVisitorCount.."]")
-
- --获得下一个用户
- --nPlayerID1 = LuaFn_Room_API_GetRoomNextPlayerID(nRoomID)
- --nPlayerID2 = LuaFn_Room_API_GetRoomNextPlayerID(nRoomID)
- --LuaFn_Print("RoomID["..nRoomID.."],nPlayerID["..nPlayerID.."] ExitRoom [nPlayerID1="..nPlayerID1.."][nPlayerID2="..nPlayerID2.."]")
-
- nRet = LuaFn_Room_API_Exit(nRoomID, nPlayerID)
- if nRet ~= ROOM_ERROR_NULL then
- LuaFn_Print("RoomID["..nRoomID.."],nPlayerID["..nPlayerID.."] ExitRoom fail.[nRet="..nRet.."]")
- return -1
- else
- --LuaFn_Print("RoomID["..nRoomID.."],nPlayerID["..nPlayerID.."] ExitRoom success.")
-
- --调试代码
- --nCount = LuaFn_Room_API_GetPlayerCount(nRoomID)
- --nVisitorCount = LuaFn_Room_API_GetVisitorPlayerCount(nRoomID)
- --LuaFn_Print("RoomID["..nRoomID.."],nPlayerID["..nPlayerID.."] ExitRoom [Count="..nCount.."][Visit Count="..nVisitorCount.."]")
- return 0
- end
- end
- --房间踢出玩家规则nRoomID:房间ID,nPlayerID:玩家ID,nOperationIDc操作者ID
- function OutRoom(nRoomID, nPlayerID, nOperationID)
- end
- --玩家变换房间,nSrcRoomID:原始房间ID,nDstRoomID:目标房间ID,nPlayerID:玩家ID
- function ChangeRoom(nSrcRoomID, nDstRoomID, nPlayerID)
- end
- --房间事件到达,定时更新调用。nEventID,事件ID,nPlayerID触发玩家ID,如果没有玩家触发则是-1
- function Update(nRoomID, nPlayerID, nEventID, nData)
- --玩家下注
- if nEventID == 3001 then
- nRet = LuaFn_Room_API_SetPlayerBet(nRoomID, nPlayerID, nData)
- if nRet ~= ROOM_ERROR_NULL then
- LuaFn_Print("RoomID["..nRoomID.."],nPlayerID["..nPlayerID.."] Update SetPlayerBet.[nRet="..nRet.."]")
- return 0
- else
- --移动到下一个玩家
- nNextPlayer = LuaFn_Room_API_GetRoomNextPlayerID(nRoomID)
- if nNextPlayer > 0 then
- --计算当前轮次是不是最后一轮
- if LuaFn_Room_GameInfo_API_GetRoundCount(nRoomID) >= 4 then
- LuaFn_Print("RoomID["..nRoomID.."],nPlayerID["..nPlayerID.."] Update LuaFn_Room_GameInfo_API_GetRoundCount.[RoundCount=4]")
- --在这里进行牌局结算
- else
-
- --给下一个玩家身上装上定时器
- LuaFn_PlayerTimer_API_Add(5, nRoomID, nNextPlayer, 2001)
- end
- else
- LuaFn_Print("RoomID["..nRoomID.."],nPlayerID["..nPlayerID.."] Update GetRoomNextPlayerID.[nRet="..nRet.."]")
- end
- end
- end
-
- return 0
- end
- --清理房间,全部退出
- function ClearRoom()
- end
- --初始化房间
- function InitRoom()
- end
- --玩家Player身上的定时器到达
- function PlayerTimer(nRoomID, nPlayerID, nEventID)
- if nEventID == 2001 then
- --到期玩家没有下注
- LuaFn_Print("RoomID["..nRoomID.."],nPlayerID["..nPlayerID.."] PlayerTimer Begin")
-
- --在这里处理玩家移动的规则
- end
- end
- --房间的定时器到达
- function RoomTimer(nRoomID, nPlayerID, nEventID)
- LuaFn_Print("RoomID["..nRoomID.."],nPlayerID["..nPlayerID.."] RoomTimer Begin")
- if nEventID == 1001 then
- --如果是1001事件,那么就是到时发牌事件(在这个C++函数里面完成了发牌,下大盲注,小盲注以及标记房间状态的任务)
- nRet = LuaFn_Room_API_DealCode(nRoomID, 1000, -1, -1)
- if nRet ~= ROOM_ERROR_NULL then
- LuaFn_Print("RoomID["..nRoomID.."],nPlayerID["..nPlayerID.."] RoomTimer Begin DealCode.[nRet="..nRet.."]")
- return 0
- else
- nCurrPlayerID = LuaFn_Room_API_GetRoomCurrPlayerID(nRoomID)
-
- --设置开始的玩家ID,以此为轮次计算的依据,如果GetRoomNextPlayerID到了这个玩家,则轮次计算+1
- LuaFn_Room_API_SetBenginePlayerID(nCurrPlayerID)
-
- --对下一个出牌的玩家添加定时器
- LuaFn_PlayerTimer_API_Add(5, nRoomID, nPlayerID, 2001)
- end
- end
- end
复制代码 程序开始一行行的解释,给策划。应对它的每一个构件。一直到策划能够提出在哪里完善新的构件位置。(到此,程序总耗时30分钟)
这里,freeeyes开发准则之一,在开发的前期,伪代码永远会提升你对逻辑的吸收和理解,所以请不要吝惜这些看似没意义的东西。
好了,今天先写到这里,呵呵,这是一个系列文章,下一章,我将会讲到,如何在程序里面实现和lua对接的技巧和方法,我希望用我的文字,来告诉大家,我是如何开发一个游戏的。
期盼winston加精吧。
|
|