码迷,mamicode.com
首页 > 其他好文 > 详细

炉石传说 C# 开发笔记 (法术篇)

时间:2014-06-02 06:13:01      阅读:290      评论:0      收藏:0      [点我收藏+]

标签:des   android   c   style   class   blog   

炉石的设计,最核心的内容是法术效果。

法术卡牌,无疑是法术的集中体现,但是,法术效果除了在法术卡牌之外,也不除不在。

随从的战吼,亡语,奥秘的揭示等等都是法术效果的体现。

法术卡牌在炉石里面有很多种(200种),但是具体整理后,大约也只有10个种类,每个种类通过法术对象的指定方式,效果点数的不同排列组合,演化出了不同卡牌效果。

例如攻击类的卡牌,  通过攻击次数的不同(奥术飞弹是3次),攻击对象不同(有的是只能攻击随从,有的只能攻击英雄,有的两者都可以),

攻击方向不同(有的可以攻击对方,有的是本方,有的是双方),攻击模式不同(有的是随机对象,有的是全体,有的是指定),各种排列组合,获得不同的法术效果。

 综上所述,一个法术效果的定义看上去是这样的。

bubuko.com,布布扣
       /// <summary>
        /// 描述
        /// </summary>
        public String Description = String.Empty;
        /// <summary>
        /// 魔法效果
        /// </summary>
        public enum AbilityEffectEnum
        {
            /// <summary>
            /// 未定义
            /// </summary>
            未定义,
            /// <summary>
            /// 攻击类
            /// </summary>
            攻击,
            /// <summary>
            /// 治疗回复
            /// </summary>
            回复,
            /// <summary>
            /// 改变状态
            /// </summary>
            状态,
            /// <summary>
            /// 召唤
            /// </summary>
            召唤,
            /// <summary>
            /// 改变卡牌点数
            /// </summary>
            点数,
            /// <summary>
            /// 抽牌/弃牌
            /// </summary>
            卡牌,
            /// <summary>
            /// 变形
            /// 变羊,变青蛙
            /// </summary>
            变形,
            /// <summary>
            /// 获得水晶
            /// </summary>
            水晶,
            /// <summary>
            /// 奥秘
            /// </summary>
            奥秘,
        }
        /// <summary>
        /// 法术类型
        /// </summary>
        public AbilityEffectEnum AbilityEffectType;
        /// <summary>
        /// 法术对象选择模式
        /// </summary>
        public CardUtility.TargetSelectModeEnum EffictTargetSelectMode;
        /// <summary>
        /// 法术对象选择角色
        /// </summary>
        public CardUtility.TargetSelectRoleEnum EffectTargetSelectRole;
        /// <summary>
        /// 法术对象选择方向
        /// </summary>
        public CardUtility.TargetSelectDirectEnum EffectTargetSelectDirect;
        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public Boolean IsNeedSelectTarget()
        {
            return EffictTargetSelectMode == CardUtility.TargetSelectModeEnum.指定;
        }
        /// 攻击的时候:99表示消灭一个单位
        /// 治疗的时候:99表示完全回复一个单位
        /// 抽牌的时候:表示抽牌的数量
        /// <summary>
        /// 效果点数(标准)
        /// </summary>
        public int StandardEffectPoint;
        /// <summary>
        /// 效果点数(实际)
        /// </summary>
        public int ActualEffectPoint;
        /// <summary>
        /// 效果回数
        /// </summary>
        public int StandardEffectCount;
        /// <summary>
        /// 效果回数(实际)
        /// </summary>
        public int ActualEffectCount;
        /// <summary>
        /// 附加信息
        /// </summary>
        public String AddtionInfo;
bubuko.com,布布扣

 

同时,注意到每张法术卡牌中,可能包含两个法术效果,所以,设计的时候,每张法术卡牌可以包含两个效果,两个效果之间,可以是 AND 或者 OR。

(在抉择系卡牌的时候,两个法术效果用OR连接。)

这里还有一个概念,法术的原子效果:

例如奥术飞弹是进行3次打击效果。所以,一个原子法术效果就是一次打击。

每次打击后,整个战场进行清算,如果触发奥秘事件等等,都要实时计算。

对于攻击全体地方随从的操作,系统也会对于每次打击效果进行实时清算。

bubuko.com,布布扣
using System;
using System.Collections.Generic;

namespace Card.Effect
{
    [Serializable]
    public class Ability
    {
        /// <summary>
        /// 第一定义
        /// </summary>
        public EffectDefine FirstAbilityDefine = new EffectDefine();
        /// <summary>
        /// 第二定义
        /// </summary>
        public EffectDefine SecondAbilityDefine = new EffectDefine();
        /// <summary>
        /// 第一定义 和 第二定义 的连接方式
        /// </summary>
        public Card.CardUtility.EffectJoinType JoinType = Card.CardUtility.EffectJoinType.None;
        /// <summary>
        /// 是否需要抉择
        /// </summary>
        /// <returns></returns>
        public Boolean IsNeedSelect()
        {
            return JoinType == CardUtility.EffectJoinType.OR;
        }
        /// <summary>
        /// 分解获得效果列表
        /// </summary>
        /// <param name="IsFirstEffect">需要抉择的时候,是否选择第一项目</param>
        /// <returns>最小效果列表</returns>
        public List<Card.Effect.EffectDefine> GetSingleEffectList(Boolean IsFirstEffect)
        {
            //这里都转化为1次效果
            //例如:奥术飞弹的3次工具这里将转为3次效果
            //这样做的原因是,每次奥术飞弹攻击之后,必须要进行一次清算,是否有目标已经被摧毁
            //如果被摧毁的话,无法攻击这个目标了,
            //同时,如果出现亡语的话,亡语可能召唤出新的可攻击目标
            List<Card.Effect.EffectDefine> EffectLst = new List<Card.Effect.EffectDefine>();
            if (IsNeedSelect())
            {
                if (IsFirstEffect)
                {
                    for (int i = 0; i < FirstAbilityDefine.ActualEffectCount; i++)
                    {
                        EffectLst.Add(FirstAbilityDefine);
                    }
                }
                else
                {
                    for (int i = 0; i < SecondAbilityDefine.ActualEffectCount; i++)
                    {
                        EffectLst.Add(SecondAbilityDefine);
                    }
                }
            }
            else
            {
                for (int i = 0; i < FirstAbilityDefine.ActualEffectCount; i++)
                {
                    EffectLst.Add(FirstAbilityDefine);
                }
                if (SecondAbilityDefine.AbilityEffectType !=  EffectDefine.AbilityEffectEnum.未定义)
                {
                    for (int i = 0; i < SecondAbilityDefine.ActualEffectCount; i++)
                    {
                        EffectLst.Add(SecondAbilityDefine);
                    }
                }
            }
            return EffectLst;
        }
        /// <summary>
        /// 初始化
        /// </summary>
        public void Init()
        {
            if (FirstAbilityDefine != null) FirstAbilityDefine.Init();
            if (SecondAbilityDefine != null) SecondAbilityDefine.Init();            
        }
    }
}
bubuko.com,布布扣

法术的资料整理:

整个资料在整理的时候都保存为XLS文件,然后通过辅助程序,转化为XML。

程序运行的时候,将XML反序列化成对象。

A000XXX开始的都是实际的法术卡牌。可以作为玩家的手牌

A100XXX都是辅助卡牌,用户战吼和亡语等等。

A200XXX都是英雄技能。奥秘计算的时候,不算本方施法,不能享受法术效果加成和施法成本的减少。

bubuko.com,布布扣

施法逻辑:

第一段代码是施法的入口代码。

通过 game.UseAbility施法,获得施法的结果数组。这里包括了法术的各个动作。这些动作将作为对方客户端复原的法术的依据。

例如奥术飞弹的施法结果可能是这样的

ATTACK#YOU#2#1           //对方的2号位随从1点伤害

ATTACK#YOU#1#1          //对方的1号位随从1点伤害

ATTACK#YOU#2#1          //对方的2号位随从1点伤害

这些结果将发送到对方客户端,进行战场的同步操作。

然后触发 本方施法事件,

例如 法术浮龙会相应这个事件,攻击力 +1,有些奥秘会被揭示,产生效果

bubuko.com,布布扣
                    ActionCodeLst.Add(UseAbility(CardSn));
                    //初始化 Buff效果等等
                    Card.AbilityCard ablity = (Card.AbilityCard)CardUtility.GetCardInfoBySN(CardSn);
                    ablity.CardAbility.Init();
                    var ResultArg = game.UseAbility(ablity, ConvertPosDirect);
                    if (ResultArg.Count != 0)
                    {
                        ActionCodeLst.AddRange(ResultArg);
                        //英雄技能的时候,不算[本方施法] A900001 幸运币
                        if (CardSn.Substring(1, 1) != "2") ActionCodeLst.AddRange(game.MySelf.RoleInfo.BattleField.触发事件(MinionCard.事件类型列表.本方施法, game));
                    }
                    else
                    {
                        ActionCodeLst.Clear();
                    }
bubuko.com,布布扣

具体施法的代码比较冗长和复杂:

这里还是对于施法前的一些整理工作,

具体的施法动作,还是要交给各个  XXXXEffect处理。每个XXXXXEffect负责某种法术的施法工作。

这里有个有趣的话题:

法术强度本意是增加法术卡的总伤。以奥术飞弹为例,法术强度+1会令奥术飞弹多1发伤害,而非单发伤害+1。法术强度不影响治疗效果。
bubuko.com,布布扣
        /// <summary>
        /// 使用法术
        /// </summary>
        /// <param name="card"></param>
        /// <param name="ConvertPosDirect">对象方向转换</param>
        public List<String> UseAbility(Card.AbilityCard card, Boolean ConvertPosDirect)
        {
            List<String> Result = new List<string>();
            //法术伤害
            if (MySelf.RoleInfo.BattleField.AbilityEffect != 0)
            {
                //法术强度本意是增加法术卡的总伤。以奥术飞弹为例,法术强度+1会令奥术飞弹多1发伤害,而非单发伤害+1。法术强度不影响治疗效果。
                switch (card.CardAbility.FirstAbilityDefine.AbilityEffectType)
                {
                    case EffectDefine.AbilityEffectEnum.攻击:
                        if (card.CardAbility.FirstAbilityDefine.StandardEffectCount == 1)
                        {
                            card.CardAbility.FirstAbilityDefine.ActualEffectPoint = card.CardAbility.FirstAbilityDefine.StandardEffectPoint + MySelf.RoleInfo.BattleField.AbilityEffect;
                        }
                        else
                        {
                            card.CardAbility.FirstAbilityDefine.ActualEffectCount = card.CardAbility.FirstAbilityDefine.StandardEffectCount + MySelf.RoleInfo.BattleField.AbilityEffect;
                        }
                        break;
                    case EffectDefine.AbilityEffectEnum.回复:
                        card.CardAbility.FirstAbilityDefine.ActualEffectPoint = card.CardAbility.FirstAbilityDefine.StandardEffectPoint + MySelf.RoleInfo.BattleField.AbilityEffect;
                        break;
                }
                if (card.CardAbility.SecondAbilityDefine.AbilityEffectType != EffectDefine.AbilityEffectEnum.未定义)
                {
                    switch (card.CardAbility.SecondAbilityDefine.AbilityEffectType)
                    {
                        case EffectDefine.AbilityEffectEnum.攻击:
                            if (card.CardAbility.SecondAbilityDefine.StandardEffectCount == 1)
                            {
                                card.CardAbility.SecondAbilityDefine.ActualEffectPoint = card.CardAbility.SecondAbilityDefine.StandardEffectPoint + MySelf.RoleInfo.BattleField.AbilityEffect;
                            }
                            else
                            {
                                card.CardAbility.SecondAbilityDefine.ActualEffectCount = card.CardAbility.SecondAbilityDefine.StandardEffectCount + MySelf.RoleInfo.BattleField.AbilityEffect;
                            }
                            break;
                        case EffectDefine.AbilityEffectEnum.回复:
                            card.CardAbility.SecondAbilityDefine.ActualEffectPoint = card.CardAbility.SecondAbilityDefine.StandardEffectPoint + MySelf.RoleInfo.BattleField.AbilityEffect;
                            break;
                    }
                }
            }
            Card.CardUtility.PickEffect PickEffectResult = CardUtility.PickEffect.第一效果;
            if (card.CardAbility.IsNeedSelect())
            {
                PickEffectResult = PickEffect(card.CardAbility.FirstAbilityDefine.Description, card.CardAbility.SecondAbilityDefine.Description);
                if (PickEffectResult == CardUtility.PickEffect.取消) return new List<string>();
            }
            var SingleEffectList = card.CardAbility.GetSingleEffectList(PickEffectResult == CardUtility.PickEffect.第一效果);
            for (int i = 0; i < SingleEffectList.Count; i++)
            {
                Card.CardUtility.TargetPosition Pos = new CardUtility.TargetPosition();
                var singleEff = SingleEffectList[i];
                singleEff.StandardEffectCount = 1;
                if (singleEff.IsNeedSelectTarget())
                {
                    Pos = GetSelectTarget(singleEff.EffectTargetSelectDirect, singleEff.EffectTargetSelectRole, false);
                    //取消处理
                    if (Pos.Postion == -1) return new List<string>();
                }
                else
                {
                    if (ConvertPosDirect)
                    {
                        switch (singleEff.EffectTargetSelectDirect)
                        {
                            case CardUtility.TargetSelectDirectEnum.本方:
                                singleEff.EffectTargetSelectDirect = CardUtility.TargetSelectDirectEnum.对方;
                                break;
                            case CardUtility.TargetSelectDirectEnum.对方:
                                singleEff.EffectTargetSelectDirect = CardUtility.TargetSelectDirectEnum.本方;
                                break;
                            case CardUtility.TargetSelectDirectEnum.双方:
                                break;
                            default:
                                break;
                        }
                    }
                }
                Result.AddRange(EffectDefine.RunSingleEffect(singleEff, this, Pos, Seed));
                Seed++;
                //每次原子操作后进行一次清算
                //将亡语效果也发送给对方
                Result.AddRange(Settle());
            }
            return Result;
        }
        /// <summary>
bubuko.com,布布扣

 

源代码已经整理过了,去除了不需要的项目。

注意:以前文章中出现过的Git已经变更过了,请以前关注过,Fork过的朋友,重新Fork一下。

GitHub地址

从五月份到现在,都是一个人独自开发。得到了很多网友的支持和建议。

接下来,我想是不是有擅长界面和炉石的朋友来帮我开发Window Form的界面。

我的想法是,先做一个Windows/Ubutun 的版本,在这个版本成熟的基础上考虑 Android版本。

当然,如果你有想法,将魔兽主题的游戏改为 三国主题的游戏,可以发送游戏策划给我,这样能避免版权的问题。

游戏的玩法没有版权问题,但是使用的图片和文字描述,确实有版权问题。

如果你有兴趣,请留下电子邮件,以后我想通过电子邮件进行联系。IM可能有些浪费时间。

或者上海的朋友,真的有兴趣靠这个创业,可以留下联系方式,我们可以一起喝咖啡。聊聊计划。

(不是上海的朋友也欢迎,不过,有些事情当面聊天效果最好,电话联系也可以)

服务器数据库,我打算使用MongoDB,本人的MongoDB水平,应该在园子里面算好的了。

MongoDB的管理工具我也一直在开发着。

bubuko.com,布布扣

最新界面如下:

暂时没有职业区别,英雄技能是法师的技能。

bubuko.com,布布扣

 

博客园管理者:能否在网站分类中增加一个游戏开发的选项,谢谢。

炉石传说 C# 开发笔记 (法术篇),布布扣,bubuko.com

炉石传说 C# 开发笔记 (法术篇)

标签:des   android   c   style   class   blog   

原文地址:http://www.cnblogs.com/TextEditor/p/3763576.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!