有目标就出手啊,在这里矫情个什么劲儿!

据观测,我的学习生产效率最高的时段是坐在公司电脑前的时间段。
回到家就是上网玩游戏看新闻看博客查各种奇怪的知识和突发奇想,有lol就晃到3点多没lol就晃到2点多,然后睡觉。第二点早晨9点50起床急急忙忙赶电车上班。
最近开始有工作进来,在公司的无压力自学状态已经结束了。但懒散了一个多月两个月,已经习惯了早走(20点一过就走),丧失了后续的学习时间。
想回到以前和末班车同进退的生活吧,竟然有点怕,不敢了。
这种变化让我惊讶。
我才25,能耐得住每晚凌晨3点睡,正是拼命学习的好时候。现在受享乐情绪的控制,未免太早、太不是时候了吧。

肯吃苦,吃苦半辈子,怕吃苦,吃苦一辈子。

今天立贴为证,2014年2月(除影响到交通的极端恶劣天气外)的每一个工作日,我都要在23点30以后回家。

哪怕是赖在公司看新闻写博客,也不许回家

 

—- 02-17 —-

特别想回家,好痛苦。工作也不想做,设计自己的卡牌服务器端逻辑流程倒还是觉得挺有趣的,但这股消极情绪实在是很强烈。

上周五因为东京历史级的大雪而提前回家,今天又不能保证11点半,真是…

算了,自责是最不解决问题的。目前我的自信心问题比责任感问题严重得多。

这股低潮的理由我也许知道,不过无能为力。还是回家逛个超市,泡个澡,喝点小酒,看着漫画睡觉吧。《将太的寿司》,虽然给我看略显低龄了,不过还是挺有趣的

Comments

    1. 查了一下,全是最近一两天的报道。在github上公开估计也不超过3天吧,竟然已经1000+关注了,真牛。

    1. 我也很想见见笃志,跟你狠狠聊一聊呀~>_< 不过回国暂时是不太可能了。 互相监督互相支持的话,在网上也可以做到的。 讲讲我最近的进展吧。卡牌游戏服务器端的框架我已经悟到了,就是栈式流程管理。我想了一个叫做OperationNode的概念(简称Op),操作节点。一个操作节点可以管理一类具体的操作,操作节点堆叠成栈型,栈顶的操作结束以后自己弹出,控制权重新回到下层栈。 举例来说,卡牌游戏《暗影猎人》的操作栈可能是 1. 栈底->gameLogicOp。主逻辑Op压入玩家回合Op
      2. 栈底->gameLogicOp->PlayerTurnOp。 玩家回合Op先压入移动Op,让玩家确定移动方式
      3. 栈底->gameLogicOp->PlayerTurnOp->MoveOp。询问是移动向相邻格子还是随机移动 new AskYesNoOp( “是否随机移动?”, 5, cb )。然后根据玩家响应的结果作为参数传递给回调函数cb,中略,移动Op结束,出栈。PlayerTurnOp收到移动结束的callback通知之后,这次压入攻击Op
      4. 栈底->gameLogicOp->PlayerTurnOp->AttackOp。中略,攻击Op结束,PlayerTurnOp发现自己的使命结束了,调用自己的cb。顺便说一下,每个Op都必然会有一个cb成员,调用就可以弹出自己。这个是压入栈的时候就设置好的,由框架管理。即使新人程序员写错了逻辑,也不会影响到下层栈,因为从结构上来说每个Op都只能访问到自己直接或间接创建的Op,也就是自己的上层栈。这样问题的影响范围可以得到控制,大不了让一个逻辑正常的Op把自己之上的Op全部出栈,也就回复正常了。
      5. 栈底->gameLogicOp->PlayerTurnOp。 PlayerTurnOp看AttackOp也返回了,自己的使命也就结束了,于是调用自己的cb回到gameLogicOp,gameLogicOp根据各个玩家的作为次序,将下一个该行动的玩家的PlayerTurnOp压入栈。

      包括在同时有多个房间运行多场游戏时,怎么让指定房间的目标玩家响应某个特定的Op的某些特定的函数之类的管理也做到了。现在我只在一个房间里测试,但理论上是可以存在复数个房间,逻辑也互不影响的。
      不过现在有一个不良设计问题。我让指定玩家响应指定Op的这个管理类是一个单类,因为这样我就不需要额外参数,可以在Op基类里直接使用这些功能了。但是有时候,比如玩家死亡Op什么的,我想暂时屏蔽指定房间内的所有之前注册过的可响应函数,等死亡Op出栈以后再回复。实现这个,最理想的是每个房间有自己的管理器,但是这样的话,每次创建Op的时候都需要传入这个管理器参数。要把一个参数运往世界的每一个角落,这工作量太大了,代码结构也绝对好不了。另一个做法就是,单类还是单类,但是在注册的时候,因为必须指定可以响应的uid,而有了uid就等于有了roomId,我可以在那个单类里区分房间……对呀!这就是解决方案嘛!只是把情况写下来,就想到了答案,开心,哈哈~

      我目前挺满意自己这个Op模型的,很适合做回合制游戏。pomelo入门了,node.js现在也用习惯了,用回调函数写复杂的游戏有种新鲜的乐趣。加上Op模型把回调函数分出很多逻辑层来,一定程度上也解决了node.js的巢状代码问题。

      笃志能讲讲你现在的研究吗?(3D图形学除外,那个我连门都还没进去= =)

  1. …我还真是不擅长记录这些灵光一闪的解决方案,因为每当我有想法的时候就会很迅速的拿笔和纸记录一些大部分人看不懂的片段单词,然后就整理一下编码去了……原先还有记录的一些习惯,现在反而觉得有一定程度的浪费,为了把一些已知的信息表达给其他人明了,还要费力整理……
    嘛…系统的讲解更不是我现在所好,现在想获取知识信息是很简单的事情,专业出书的家伙常常做的很好,以至于我连条理整理的兴趣也丧失了……
    好吧,我们还是就事论事,说说你提到的这个问题和想法吧。
    首先,你的开始的op栈的方式,我在写编辑器时候最爱这么做。用户使用编辑器,进行一步一步操作(你可以理解是ps的操作过程),然后我们进行记录,以便进行恢复和撤销。一般这个功能我会考虑使用伪MVC方式。C是control也就是你的所谓的OP,然后每个op关联一份数据。(你可以这么理解,假设你要撤销返回上一步操作,你必须知道上一步操作所对应的值,例如你将地形拉高,那么原来的地形高度是多少这份数据必须被记录)。那么最终我记录的也是一个op栈,每个op对应一份数据(因数据结构类型不同,这里关联指针)。你所做的不同在我看来是将op增加了一个队列分类,即使用了桶结构(可以了解下hash桶),因为你的操作对象分为player,player2,computer,而地图编辑器仅需要记录一个player的操作就可以了。本身这样的存储方式是个比较稳妥也常规的做法,似乎我做不出什么特殊的评价……
    然后下面关于单件的做法,我依然不赞同op管理器唯一,并使用roomid为标示区别。原因很简单,我认为op栈你很可能设计到op管理器中并且唯一,这样的后果是,如果有大量房间大将玩家进行操作,那么这个op栈将相当庞大,无论你使用什么样的(hash索引也好,平衡二叉也好)都不会从本质上改变这个问题,你在查询指定op时候代价将过大。
    另外我一直有个疑问,你说这个是个栈,那么物理地址是连续的。那么你每个op内部的cb对自己的释放,是否会将其上面的op进行内存复制下来,如果是这样,代价将过于昂贵。而且你的栈一旦唯一,那么每次memcpy实在是……好恐怖。你可以保证不进行插入,但是如何保证不删除?
    所以,我依然推荐每个房间一个自己的op栈,当然,你的op管理类可以提供一些索引以及op操作常规方法,即(control被统一,但是data被分离)这样会比较好。这样的话,你的op data的确最适合使用堆栈保存在每个房间。
    我几乎不会因为函数参数的复杂度增加而做出某种修改调整,只会因为性能,扩展性这些对结构进行修改调整。
    但是最终我还是要说……如果我做卡牌的话。。。我不会这么设计,因为脑海里有一些更好的方式……特别是从大局上(这点你没有提及)需要有良好的设计,会更加有趣一些。
    好吧。。。满屏幕没赞扬的语句,我还是自我违规了。。

    1. 整理好也能加深印象,但是太复杂的东西就得想着怎么能让没有背景的人懂,耗费的经历就和加深理解、甚至和编程都没什么关系了,这部分确实是浪费。
      用cb控制是因为用的是node.js(pomelo是node.js框架),称其为栈只是为了便于理解,实际上实现的方法是类似链表的东西。我不太清楚node.js怎么分配大片连续的内存,不过既然用了脚本语言,那就不考虑极限挖掘内存使用效率的潜能了,还是侧重于开发效率吧。加上我是第一次尝试服务器端编程,完全没有经验,过早优化只会自取灭亡,无论是项目还是热情。
      Op栈和笃志的编辑器有很多结构相似的地方,但是用的场合还是不太一样的。
      Op栈是每个房间各持有一个的,不是全集中在单类中,不会太庞大。如果房间超级多,那hash倒是可能慢下来,但是我看国内最牛的卡牌游戏三国杀每个服务器的房间也就那么一点点,我也就没多想,直接roomId当Key用Map了。
      统一方法是有的,其实也就是Push,Pop,update,注册等待被玩家响应的函数等等。因为是链表,所以push和pop是Op自己就可以做,注册函数是要单类来负责。啊,这里就可能遇到笃志说的查询压力大的问题了。我所有Op都是向单类中注册函数的,如果某个瞬间,每个玩家都可以响应某个事件(比如三国杀的无懈可击),这样就要向单类注册一个监听……哦,对了,就算所有人都可以响应,也只注册一个就够了,这么算起来,每个游戏瞬间都不会有太多事件等待玩家回应(不超过5个吧),查找起来是5X房间数,感觉不是很严重。笃志会担心是因为笃志的编辑器栈是记录,所以会很长,但我的Op栈只是为了维护逻辑流程,用完就弹出,所以每个房间每个瞬间其实Op栈也没几层。现在是刚开始用,一般也就5、6层,找这个趋势,写成之后应该也会少于10层吧。当然,如果想把代码分更细,那就可以做更多Op出来,这样也不错,可以简单的分配任务给更多人同时去做,每个人只要嘱咐好构造函数里会进来什么数据,callback函数里应该返回什么东西就可以了。这个概念果然适合回合制游戏啊,如果是MMOARPG,就肯定不行了。回合制是每个瞬间玩家只有少数几种可以做出的选择,怎么处理都很轻松(怎么感觉用php+数据库都能搞定了……)。
      查了一下hash桶,发现这个概念我也是自己悟到的!我在大学的时候就做过随机分配,和冲突了用队列的解决方案。印象中后来也用过这种概念,反正脑子里一直有“这种事情可以这样解决”的印象。不过想想看,这其实也不是很难想到的数据结构,没什么可高兴的嘛。如果我能自己悟到那个N个男人和N个女人搞对象,没人都对N个异性有满意度排名的情况下,怎么组成总满意度最高的N对情侣这种问题,那才有点高兴的价值(这是我看的一本算法书上的第一个例子,六七页书看了我几十个小时,真是震住我了)。
      我是很讨厌参数列表过长或者结构诡异的。把一个参数传入世界的每一个角落让我有种很强烈的抵触情绪,但是pomelo框架其实就在这么做——它把app这个引用传入了每一个需要它的实例。按我的理解,app是个全局唯一的对象,那为什么不用require直接取得它的单类呢?也许是为了效率吧,毕竟是框架。node.js我是初学者,保持使用它的热情最重要。经验的、具体的优化方案什么的,暂时搁置才是上策。
      卡牌在大局上怎么设计我真是没有想好,笃志会有更好的设计,我特别信。Op这个概念是很泛用的概念,也许之后会遇到需要隔层相互调用的问题,如果我不能很优雅的解决,那我也许会放弃Op,改换其他解决方案。这个Op栈是我在写上层伪代码开发的时候,在一点点具体化伪代码时,察觉到的一个工具。用它可以很好的实现我的伪代码(我的设计方案),但伪代码毕竟还是代码,比较具体,并不是从很大局的高度去考虑卡牌游戏的,视野有局限,我也很担心这一点。我最担心的就是我没有开发一个完整网络游戏的经验,对网络环境的各种复杂状况的估计会不足。在我脑海里,还是以程序会安定运行为前提在设计的,错误对策什么的,暂时还只是/*TODO*/状态。
      我希望这个游戏能好好做,做到有开发者以外的人常玩,让我能运营它一段时间,给我一点这方面的经验。当然,如果能直接从笃志那里取到经验,那就最开心了^_^

  2. -。-写了好多……
    大致看完,只找问号的回复了就。
    1:为何app全局唯一的单件要慢慢传参,而不直接单件获取?
    Q:首先单件这个设计模式真的很双刃剑,线程的安全这个老大难问题不说,我最头疼的一直是其创建顺序和释放顺序。即使你无聊到显式的调用A::getSingleon();一句空语句以确保单件对象的构造位置,也无法避免下列的情况 — 假设A类是个单件全局唯一类,构造用到了B类一个对象的成员函数,结果B类也是个单件全局唯一类,而类构造里也使用了A::getSingleton()->initXXOO();这样的函数。那就怎么看都是崩溃了。而且析构顺序也会带来这些问题,让人很是讨厌。其实单件类在效率上到确实没有任何问题……另外建议你可以深入考虑一下,如果说那个框架,有两个app对象,会怎样?什么情况下可能使用两个app对象?这个真心建议你好好思考,不要被一个很常规的设定把思维限制住了。
    2:好吧,貌似你也没问题了- -那我继续扯淡。游戏的框架其实总是万变不离其宗,开始觉得架构神马的似乎很高大上的玩意儿,其实跟两三个项目,实实在在弄几个结构图(动态流程图,数据图,静态类结构图),你会发现总是一个模子出来的,或者说就如建筑,看起来千变万化,其实都是几个承重梁,几个围护结构组成的,实在也折腾不出什么诡异的花样来……(我当前能力也就只看到这步),于是有点兴趣索然。
    最后呢,你的游戏要是出来了介绍我玩一下,我现在重心一直不在程序技巧上了,甚至管理技巧的进步也相对缓慢,在产品本身的比较多,即使没有源代码,作为一个资深游戏玩家加个半吊子策划也能喷你几句,只要你内心强大不怕喷子就行,哈哈~

    1. node.js里两个单类构造函数内互相引用对方(两个文件互相require对方)的话,我也挺好奇会发生什么的。我编程最初的一两万行几乎都是java,所以互相引用问题、内存管理等等稍微底层一点的地方都很弱,程序写大了总是难逃内存泄漏的命运。当然,工作上的代码我是不敢让他内存泄漏的。
      还有底层通信我也有点怕,以前写过一个侦测内存创建和销毁的工具,被侦测的程序和监控器靠TCP通信。整个工程从最开始就特别不顺利。网络方面各种特殊情况,每个都卡我几小时十几小时,有人能指点一句就能简单解决的问题,可我也没人能问,时间都浪费在开发以外的地方,而且是只有一句话价值的地方,特别不值,搞得我那段时间非常挫败。加上我自己用C++写协议也乱七八糟的,发送和接受的逻辑改来改去,稍微没对上就要排查很久,不定期发生的C++通信bug太可怕了!本来进公司的时候还信心满满的跟他们说我对网络和AI部分比较感兴趣,那一役之后心理变化很大。
      幸好后来遇到了pomelo,node.js帮我弥补了很多弱项。现在我只要关注程序正确就好,不用在底层细节上耗费太多精力。像卡牌这种逻辑比较简单的游戏的服务器端,写起来已经是想到就能实现,指哪打哪,特别开心。
      3D和网络,不掌握这些有深度的技术的话,我会处在很容易被别人替代的不安全位置上。不过任何技术都不值得我以伤害自己对游戏编程的热情为代价去学习。我要以自己可以接受的节奏来学习。整个程序写好了,自然会对这个框架的实现方法产生兴趣,到时候从上向下学习,更符合我的节奏。

      笃志说的弄结构图,我真是挺感兴趣的。现在我觉得自己读代码的效率还是太低,也没有什么顺藤摸瓜理清一个复杂框架/游戏运转流程的能力。我也读过侯捷的《上窮碧落下黃泉- 源碼追蹤經驗談》什么的,感觉他那个时代仿佛连IDE都没有,介绍的很多东西在我拥有一个可以打开的sln文件时都是无用武之地的。我想知道的是更抽象,更上层的阅读技术,像是不要过早跳进去看细节啊,从main开始先看上层函数,推测它的作用啊什么的。但是这也只是在阅读的当时有效,我希望有可以积累阅读成果的方法,让我能一点一点把程序内的脉络都记录在纸上,也就是笃志说的各种图。开发的时候我偶尔会画UML图,确实对一次成型帮助非常大,基本上画图10小时,编写40分钟。如果直接写,可能总时间也差不多,但内部的清晰程度就完全没得比了。不过小东西我还是懒得画UML图的。阅读代码时,我用我仅知道的这种图做记录,后来发现为了写UML图的各个成员,我花了大量时间在纯书写上,而且太庞杂,感觉是比我硬读的理解效率都低,于是放弃了。我很喜欢一个叫ygopro的开源游戏王游戏,里面的每一块都特别迷人,我好几次跃跃欲试要攻克它,最后都只啃掉些边角,就进行不下去了。在阅读大项目的笔记、画图这方面,还想跟笃志请教一下。

      说来惭愧,我的游戏很少有能出来的。一般都是完成度5%的时候开发效率最高,最狂热,最投入。等到接近75%的时候,技术难题已经全部攻克,就差收尾精加工了,我就彻底没兴趣,搁置了。
      我还真是挺怕喷的,人比较敏感。不过在我自信足够强的领域,我就比较抗喷了。游戏编程我当然不算强,但已经可以读懂战斗力,能看到差距的具体数值了。就像画画,画得一般,但是有鉴赏力了,我知道哪幅比哪幅好,好在哪里,也就不会仅仅因外界的评价而伤心动摇了。

      强大的感觉真好(哈哈)。

  3. 通讯底层的设计,以及3D渲染的优化,这俩在我看来是程序方向最有技术一些的层面了,一个是磨练功底,通用设计,一个是磨练对内存显存优化,锁,线程的理解。这俩方面务必要搞懂吃掉。
    不过有一点咱俩不同,你喜欢从上向下,有个引擎先会用再看细节,这也是大部分人喜欢和建议的方式。但是我有点奇怪,不搞清楚底层就全身发痒的一种感觉,所以一个引擎到手,我一般不看demo,先看类结构,然后随便找个demo,从main开始查各个模块,不懂底层就难受的习惯导致我几乎完全不用商业引擎,例如U3D,现在火的要死,我也几乎完全提不起兴趣。当然也包括了as这样的奇怪的语言(引擎)?
    幸运的是,我一般不惧怕大规模的玩意儿,相反我比较喜欢大规模的玩意儿,然后自己开始拆,这里拆一块封装起来,那里拆一块封装起来,最后A的b零件和B的a零件组装一起,拥有我认为的一种奇特的优势……其实我自己的FKEngine就这么搞出来的。
    我推荐看一个代码,先把大的看小,知道有几个模块,模块之间大致怎么联系的。然后再小的看大,每个模块内部每个类甚至核心的几行函数作用。但是我也怕自己画图时候会花费太多时间在图像布局本身,所以依然习惯是看代码时候直接在代码上打注释- -最后有心情了整理了,没心情就放那了。。Orz
    做完整游戏的话,中后期确实无聊的很,我也没好办法,只能忍吧。
    总之,现在我对自己也信心不足了,于是主要考虑的是挖小坑,原来的一个一个巨大的天坑就丢那了,小坑小坑的慢慢组合为大坑,这样或许才容易坚持点。恩

  4. 程序猿的对话越来越看不懂了哈哈
    抱歉狠久没来。
    有目标就赶紧下手,立刻,马上,这才是纯爷们(不,妹子也应该这样做)
    以前俺也是想到啥就干啥的,进入大学之后开始優柔不断,最近努力改正中,与基拉君共勉哈哈

回复 基拉铃妖 取消回复

您的邮箱地址不会被公开。 必填项已用 * 标注