炉石传说 C# 开发笔记

 

最近在大连的同事强力推荐我玩 炉石传说,一个卡牌游戏。加上五一放一个很长很长的假期,为了磨练本身,决定尝试开发一个C#的炉石传说。node

这件事情有人已经干过了,开发了一个网页版的炉石,可是貌似不能玩。。。。git

http://cnodejs.org/topic/529c1366a6957a0809485f3dgithub

若是这位同志看到这篇文章,请必定和我联系!!编程

rudermail@qq.com或Q我377372779浏览器

第一天服务器

开始学习炉石传说的玩法,最好的方法是不停的玩游戏。网络

一个应用是否逻辑清晰,取决于你对于业务的了解程度,通常到开发后期发现有些逻辑内聚和耦合发生问题,每每都是前期对于业务的理解不够透彻。工具

不少开发都每每是随着业务逻辑的了解,进行不停的重构,固然,这个也是一个必然的过程,可是若是可以在前期就了解业务的话,则能够节约后期大量的时间。学习

因为长期作对日软件的缘故,式样书,设计书先行是根深蒂固的思想。全部设想都先以文字或者伪代码的形式写下来,进行一些假想的验证。测试

整个项目的平衡感,脉络,各个模块,层次结构都在这个时候定下来。这个时候是修改为本最低的阶段,等到后期这些模块再从新划分,风险就高了。

 经过第一天的学(you)习(xi),大概整理除了一个脉络:

(文字版本的不是很好看,下面的Excel版本,浏览器也看不到。。)

 

卡牌基础

  法术卡牌

    熟读各类法术牌,讲法术牌分类

  随从卡牌

    各类特性的整理,能够参考各类网络上的资料

  武器卡牌

    比较简单的类型

游戏环境

  英雄

    生命值

    基本技能

    武器

  牌堆

    套牌

  手牌

    手里的牌  

  战场

    7个位置的随从

  法力水晶

    因为某些卡牌会改变水晶,也为了细化系统,法力水晶升级为一个独立的类

 次日

  开始进行Coding。因为英语不是很好,有一些单词不知道,而后开始中英文夹杂编码。

  好久前,也讨论过中文编程的问题,其实不少变量,用中文仍是英语彻底没有限制。

  写代码只要能让本身和维护的人读得懂就能够了。毕竟即便你用英语变量,你的注释仍是中文的。。。

  固然,若是你想让代码可以国际化,特别是开源项目,能用标准的英语来写代码是极好的。

  NUnit用的不是很好,因此,本身写了一些GUI的界面来作一些简单的UT测试。

第三天

  代码的重构,设计书和代码的同步。

  不少项目,在一开始的时候还有设计书,而后在开发的时候,每每重构好代码后,设计书仍是重构以前的样子。

  IDE能够自动重构代码,可是不能自动重构设计书。。。。

  国内项目不注重文档,因此这种状况很常见。日系的开发,设计书则至关重要,一个是为了往后维护能有个依据,二是为了可以明确责任。

  这个地方为何要修改,对于总体项目有什么影响,都能从设计书的修改履历中看出端倪。

  代码和设计书同步的时候,也是一个反思的机会,看看现阶段写的代码,是否是很干净优雅,

    每每将代码转换为设计书的时候,能够看到代码的问题。特别是代码的一致性上,散落在不一样地方的代码,通过整理,用#region概括后,能够看到不少问题。

第四天

  炉石C#版本不是短期内能够完成的,在完成整个炉石以前,能够考虑用当前的代码,先制做一些小的工具。

  一来能够拉拢人气,隔一段时间有个小的能够检证的成果物,不至于半途而废;

  二来,小工具的制做也是为了炉石服务的,有些小工具的代码也能够反馈到炉石主体代码。

  我向来反对一开始就要作个了不得的东西,或者只开发了不得的东西,忘记了留下二次开发的接口或者周边产品的接口。

  魔法的定义

    魔法类型
        攻击
        回复
        召唤
        卡牌    奥术智慧
        变形    变羊术
        水晶    幸运币
        奥秘

    魔法关系
        或者    抉择系:例如:抉择: 对一个随从形成3点伤害;或者形成1点伤害并抽一张牌。
        而且    有反作用的魔法,例如:形成4点伤害,随机弃一张牌。

    目标选择模式
        随机
        全体
        指定

    目标选择方向
        本方
        对方
        无限制

    目标选择角色
        随从
        英雄
        全体

    标准效果点数
        伤害效果点数、治疗效果点数、抽牌数

    实际效果点数
        因为某些卡牌效果会影响效果点数

    效果回数
        例如:奥术飞弹是3次1点伤害

    附加信息
        难以用上面的规则的卡牌,特殊的附加信息

奥术智慧的定义:
  1.有一个效果:抽两张牌
  2.成本是1点
  3.对象时本方
        /// <summary>
        /// 初始化奥术智慧
        /// </summary>
        /// <returns></returns>
        public static Card.MagicCard Get奥术智慧()
        {
            Card.MagicCard 奥术智慧 = new Card.MagicCard();
            奥术智慧.SN = "M000002";
            奥术智慧.Name = "奥术智慧";
            奥术智慧.Description = "随机抽两张牌。";
            奥术智慧.Rare = Card.CardBasicInfo.稀有程度.绿色;
            //使用成本
            奥术智慧.ActualCostPoint = 1;
            奥术智慧.StandardCostPoint = 1;
            奥术智慧.JoinType = Card.MagicCard.EffectJoinType.None;

            //随机抽两张牌
            Card.MagicCardStockEffect cardStockEffect = new Card.MagicCardStockEffect();
            cardStockEffect.StandardEffectPoint = 2;
            cardStockEffect.EffectCount = 1;
            cardStockEffect.EffectTargetSelectDirect = Card.CardUtility.TargetSelectDirectEnum.本方;
            奥术智慧.FirstMagicDefine = cardStockEffect;
            return 奥术智慧;
        }

 

 

第五天

  我一直在考虑,AI是否是能代替人。

  炉石这样的游戏,有许多经常使用的套路,只要组好了套牌,而后可以将不少经常使用的卡牌组合,优先策略教授给AI,应该能够作到和人对战。

  和国际象棋,围棋比起来,炉石这样的游戏,胜利无非是:运气好,套牌组的合理,正确衡量场面上各类对方卡牌的威胁程度,熟练使用各类套路,有耐心,不犯低级错误。

  运气好,套牌组的合理,这个事情,前者人和AI都同样,套牌能够人组好后直接给AI使用。

  正确衡量场面上各类对方卡牌的威胁程度:这个也不难,其实卡牌的使用成本已是一个能够量化的威胁度指标了。

  熟练使用各类套路:对方出了一个 10/10 (合理的阀值)的家伙,若是有变羊术,就变掉;对手一大堆血量3,4的随从,就用清场的牌,这些套路也很直观

  有耐心,不犯低级错误:这个是AI的长处,AI绝对不会忘记还有魔法能够直接 打脸,还有可使用的随从去 打脸

  固然,对于顶级高手AI还不是能够简单的取胜,审时度势,及时调整战略的能力,人仍是有着无可比拟的优点。

 第六天

  看看客户端和服务器端分工如何:

  顺便提一句,平常文档的编写,WPS不比Office差,支持国货

 

  核心库 Card.DLL 还有客户端,服务器,之间要链接起来

客户端-服务器-核心库


    核心库:委托形式

            /// <summary>
            /// 抽牌委托
            /// </summary>
            /// <param name="IsFirst">前后手区分</param>
            /// <param name="magic">法术定义</param>
            public delegate List<CardBasicInfo> delegateDrawCard(Boolean IsFirst, int DrawCount);
            /// <summary>
            /// 抽牌魔法(服务器方法)
            /// </summary>
            public static delegateDrawCard DrawCard;


    客户端:实现委托

            /// <summary>
            /// 初始化
            /// </summary>
            public static void Init() {
                //抽牌的具体方法
                CardUtility.DrawCard += DrawCardAtServer;
            }

            /// <summary>
            /// 抽牌(服务器方法)
            /// </summary>
            /// <returns></returns>
            public static List<String> DrawCardAtServer(Boolean IsFirst, int Count)
            {
                //向服务器提出请求,得到牌
                return GameStatus.DrawCard(IsFirst,Count);
            }

    服务器端:实际操做牌堆

            /// <summary>
            /// 抽牌
            /// </summary>
            /// <param name="IsFirst"></param>
            /// <param name="Count"></param>
            /// <returns></returns>
            public static List<String> DrawCard(Boolean IsFirst, int Count)
            {
                var targetStock = IsFirst ? FirstCardStock : SecondCardStock;
                return targetStock.DrawCard(Count);
            }

    (调用Card核心库方法)

            /// <summary>
            /// 抽卡
            /// </summary>
            /// <param name="CardCount"></param>
            /// <returns></returns>
            public List<String> DrawCard(int CardCount)
            {
                List<String> newList = new List<String>();
                for (int i = 0; i < CardCount; i++)
                {
                    if (CardList.Count == 0) break;
                    newList.Add(CardList.Pop());
                }
                return newList;
            }

 

 第七天

 

考虑服务器和客户端的开发。

客户端-服务器通讯

    TCP协议,相似于网站那样的短链接。

        玩家A                    服务器消息区            玩家B
            回合开始                STARTTURN
            使用卡牌A,形成结果B                USE:A|EFFECT:B            每隔5秒从服务器端读一次A的行为,改变当前战场状态,知道读取到ENDTRUN消息
            使用卡牌C,形成结果D                USE:C|EFFECT:D
            回合结束                ENDTURN

                            STARTTURN            回合开始
            每隔5秒从服务器端读一次B的行为,改变当前战场状态,知道读取到ENDTRUN消息                USE:A|EFFECT:B            使用卡牌A,形成结果B
                            USE:C|EFFECT:D            使用卡牌C,形成结果D
                            ENDTURN            回合结束


    请求分类    (3位)

        游戏
            新建一个游戏        新建一个游戏
            加入一个游戏        加入一个游戏
            认输        认输,退出一个游戏
            等待游戏列表        获取等待加入者游戏的列表
            确认游戏启动状态        确认游戏是否处于启动状态
            是否为先手        是否为先手

        动做
            抽牌        抽牌
            回合结束        回合结束
            行动        改变战场的动做

 

 

下面这个连接是OneDriver上共享的设计书,有些图形对象没法在浏览器中显示,不知道能不能经过下载的方式保存到本地,而后打开。

点击这里查看 onlne Excel 版本的 设计书

代码在GitHub上面,不过为了帮MongoDB的项目拉人气,因此,将代码放到了MongoDB的解决方案里面了。

你们下载代码的时候,顺手点个赞吧 Star 一下

https://github.com/magicdict/MagicMongoDBTool

相关文章
相关标签/搜索