Silverlight 2.5D RPG游戏技巧与特效处理:(十二)魔法系统

    技术2022-05-19  50

    世界首款Silverlight MMORPG<<窝窝世界>>震撼登场!伴着与XNA合体后的Silverlight 5 强势发布,一波Silverlight网游研发海啸即将席卷全球!

    多磨的好事依旧让人激动,于是一不小心写下13款全新的魔法效果旨在祝贺。今天的教程不会让你失望,没错,又是一场超豪华魔法盛宴!接下来您将看到的是本教程ARPG Demo战斗实景,一切灵感均来源于近期即将内测的2.5D大作《倩女幽魂Online》。动态光路之连锁闪电!野蛮冲撞之幻象刺杀!自适配地形之雷电风行!完美冰冻之暴风狂雪!环形突击之圆月斩!随机多段连环突刺~毒化!自定义波浪发散之烈火轰炸!连续多段灼烧之陨石坠落!扇形范围之石化穿梭箭

    在线演示Demo地址:http://silverfuture.cn/

    那么回溯到本节的主题:魔法系统是如何创建的呢?首先,我们可以将魔法和技能看做同一系统;魔法的原理与AI系统类似,从简单切入主要划分为“规则”与“使用”两个部分。“规则”包括魔法的基础性质/属性(等级、施放条件、抵抗条件、威力、附加效果、特效、物理引擎、粒子系统等等),魔法的分类(以元素为基础,日系的如气、水、火、土、光明、黑暗;中式的金、木、水、火、土,相生相克。以作用为根据,BuffDeBuff、召唤、复制、魔幻等等),以及魔法的炼化(金钱/经验/使用次数升级;装备加成;组合拆分等等)。而“使用”则面向所有不同类型的魔法从触发开始到完成所有伤害这整个流程。

    规则这部分属于策划的范畴我们暂且放它一边,本节的重点是向大家讲解Silverlight MMORPG中魔法施放的整个流程。

    首先是触发,主角施法过程通常由玩家操作鼠标右键或通过键盘的快捷键触发:

    游戏中鼠标右键按下          ///   <summary>          ///  游戏中鼠标右键按下         ///   </summary>          void  LayoutRoot_MouseRightButtonDown( object  sender, MouseButtonEventArgs e) {            e.Handled  =   true ;            Point p  =  e.GetPosition(space);            leader.Target  =   null ;            leader.TurnTowardsTo(p);            leader.Casting( new  MagicArgs() {                Code  =  Convert.ToInt32(((ComboBoxItem)comboBox39.SelectedItem).Tag),                Level  =  Convert.ToInt32(((ComboBoxItem)comboBox38.SelectedItem).Tag),                SpaceLayer  =  leader.SpaceLayer,                Scale  =  leader.Scale,                Position  =  leader.Position,                Destination  =  p,            });        }

    而非控角色则通常由AI引导触发:

    角色行为执行          ///   <summary>          ///  角色行为执行         ///   </summary>          void  role_ActionDecide( object  sender, EventArgs e) {            RoleBase attacker  =  sender  as  RoleBase;            RoleBase target  =  attacker.Target;             if  (attacker.IsHostileTo(target)  &&  attacker.IsVisible) {                 // 怯懦行为简单表现为不主动追击,发现被攻击时立刻逃跑                  if  (target.ActionAI  ==  ActionAIs.Cowardice) {                    target.Target  =   null ;                    target.MoveTo( new  Point(ObjectBase.RandomSeed.Next(( int )(target.Position.X  -  target.SightRange), ( int )(target.Position.X  +  target.SightRange)), ObjectBase.RandomSeed.Next(( int )(target.Position.Y  -  target.SightRange), ( int )(target.Position.Y  +  target.SightRange))));                }                 if  (target.InCircle(attacker.Position, attacker.AttackRange)) {                    attacker.TurnTowardsTo(target.Position);                     #region  测试用,一定机会释放魔法/技能                      if  (attacker.Action  ==  Actions.Casting) {  return ; }                       if  (ObjectBase.RandomSeed.Next( 100 <  ( int )slider13.Value) {                         ......                         attacker.Casting( new  MagicArgs() {                             Code  =  code,                             Level  =  ObjectBase.RandomSeed.Next( 1 4 ),                             SpaceLayer  =  attacker.SpaceLayer,                             Scale  =  attacker.Scale,                             Position  =  attacker.Position,                             Destination  =  target.Position,                         });                     }  else  {                        attacker.Attack();                    }                     #endregion                      ......                 }  else   if  (target.InCircle(attacker.Position, attacker.SightRange)  ||  attacker.ActionAI  ==  ActionAIs.Persistent) {                     // 固执行为简单表现为抓住一个目标一直追击,直至自己或目标死亡为止                     attacker.MoveTo( new  Point(ObjectBase.RandomSeed.Next(( int )(target.Position.X  -  attacker.AttackRange), ( int )(target.Position.X  +  attacker.AttackRange)), ObjectBase.RandomSeed.Next(( int )(target.Position.Y  -  attacker.AttackRange), ( int )(target.Position.Y  +  attacker.AttackRange))));                }  else  {                    attacker.Target  =   null ;                    attacker.Stop();                }            }        }

    接下来是动作播放,角色控件内部播放施法动作,无论是2D还是3D模型,当播放到“放出”关键帧时解析魔法配置并触发DoCasting事件:

    施法关键帧              // 不同动作处理              switch  (Action) {                 case  Actions.Attack:                     if  (frame.Current  ==  frames.AttackEffect) {                         if  (DoAttack  !=   null ) { DoAttack( this , e); }                    }                     break ;                 case  Actions.Casting:                     if  (frame.Current  ==  frames.AttackEffect) {                         if  (DoCasting  !=   null ) {                             // 解析等级魔法具体参数                             XElement info  =  Infos[ " Magic " ].DescendantsAndSelf( " Magics " ).Elements().Single(X  =>  X.Attribute( " Code " ).Value  ==  magicArgs.Code.ToString());                            magicArgs.AnimationCode  =  ( int )(info.Attribute( " AnimationCode " ));                            magicArgs.MagicType  =  (MagicTypes)( int )info.Attribute( " MagicType " );                            magicArgs.MagicLayer  =  (MagicLayers)( int )info.Attribute( " MagicLayer " );                            magicArgs.MagicPosition  =  (MagicPositions)( int )info.Attribute( " MagicPosition " );                            magicArgs.AdditionalEffect  =  (AdditionalEffects)( int )info.Attribute( " AdditionalEffect " );                            magicArgs.SpecialEffect  =  (SpecialEffects)( int )info.Attribute( " SpecialEffect " );                            XElement levelInfo  =  info.Element( " Levels " ).Elements().Single(X  =>  X.Attribute( " ID " ).Value  ==  magicArgs.Level.ToString());                            magicArgs.DamageMin  =  ( int )(levelInfo.Attribute( " DamageMin " ));                            magicArgs.DamageMax  =  ( int )(levelInfo.Attribute( " DamageMax " ));                            magicArgs.Radius  =  ( int )(levelInfo.Attribute( " Radius " ));                            magicArgs.Number  =  ( int )(levelInfo.Attribute( " Number " ));                            DoCasting( this new  DoCastingEventArgs() { MagicArgs  =  magicArgs });                         }                    }                     break ;            }

    在角色所注册的DoCasting事件中通过反射来创建魔法实例并运行重写MagicBaseRun方法:

    角色开始技能/魔法攻击          // 角色开始技能/魔法攻击          void  role_DoCasting( object  sender, DoCastingEventArgs e) {            RoleBase caster  =  sender  as  RoleBase;             // 通过反射来加载并实例化各类型魔法             Assembly assembly  =  Assembly.Load( " Components,Version=1.0.0.0 " );            MagicBase magic  =  assembly.CreateInstance( string .Format( " Components.Magic.{0} " , e.MagicArgs.MagicType.ToString()))  as  MagicBase;            magic.Run(caster, space, e.MagicArgs);        }

    依据魔法参数中的魔法类型,选择相应的具体魔法类执行具体逻辑,比如魔法实体及子魔法实体的创建、移动、特效显示、伤害处理等等,以一个圆形范围的群攻魔法为例,其逻辑组成代码如下:

    圆形范围魔法(基础群攻) namespace  Components.Magic {     ///   <summary>      ///  圆形范围魔法     ///   </summary>      public   sealed   class  CircleMagic : MagicBase {         public   override   void  Run(RoleBase caster, Space space, MagicArgs args) {            args.Position  =  args.MagicPosition  ==  MagicPositions.Position  ?  args.Position : args.Destination;            Point p  =  space.Terrain.GetCoordinateFromPosition(args.Position);             if  (space.Terrain.InEffectiveRange(p)) {                 if  ((args.SpaceLayer  ==  SpaceLayers.Ground  &&  space.Terrain.Matrix[( int )p.X, ( int )p.Y]  !=   0 ||  args.SpaceLayer  ==  SpaceLayers.Sky) {                    AnimationBase magic  =   new  AnimationBase() { Code  =  args.AnimationCode, SpaceLayer  =  args.SpaceLayer, Position  =  args.Position, Z  =  args.MagicLayer  ==  MagicLayers.Ground  ?   - 1  : ( int )args.Position.Y };                    EventHandler handler  =   null ;                    magic.Disposed  +=  handler  =   delegate  {                        magic.Disposed  -=  handler;                         space.RemoveAnimation(magic);                    };                    space.AddAnimation(magic);                }            }             // space.Wave(args.Position);              for  ( int  i  =  space.AllRoles().Count  -   1 ; i  >=   0 ; i -- ) {                RoleBase target  =  space.AllRoles()[i];                 if  (caster.IsHostileTo(target)  &&  target.InCircle(args.Position, args.Radius  *  args.Scale)) {                    Targets.Add(target);                }            }             // 对精灵表中所有精灵进行魔法/技能伤害              foreach  (RoleBase role  in  Targets) {                caster.CastingToHurt(role, args);            }            Targets.Clear();        }    }}

        一款网游能够吸引玩家的几大模块不外乎魔法、装备与探索;随着个人电脑性能跨越式飙升,当下网游更青睐以画面取悦玩家;没错,确实是屡试不爽。而魔法又是网游画面与体验的形象代言。可见,在网游开发中如能把握住魔法工序的每道细节,比如魔法与障碍的碰撞检测、动态运动轨迹、自适应及随机性、分帧处理架构、修饰及特效的组合布局等等,那么你的团队打造出一款世界顶级的网游必定指日可待,还在垂涎魔兽世界而望其项背吗?你也能做到的!

     

     

    再返回本文的开头,或许你会说这样的画面哪能和倩女幽魂Online比呀?

    请记住了,我们只是Silverlight Game Engine Developer,你懂的。Silverlight 5 目前已完美集成了XNA3D API,我相信如果您拥有一只美工水准堪称媲美雷火工作室的美术团队,使用Silverlight 5绝对能够研发出与之一拼的极品网游,甚至超越。

    创新工厂给当下国内网游的定义是“太重。没错,轻量化的网游正需要像Silverlight这样高研发效率、高性能、完全动态布局的RIA来实现;Silverlight 2.5D/3D网游时代已扬帆起航,4月28日,《WOWO世界》出中国乃至世界的第一步!所有的一切都是从零开始,完全自主的知识产权,完全自主研发的核心引擎、辅助工具,高度可维护性与拓展性,零外部依赖;俗话说的好:拽在自己手中的东西才最踏实,而Silverlight让我们开发者从心记忆着每个工序流程,没错,一切都属于你。我们可以面朝世界昂首呐喊:Silverlight 网游,中国造!

    这才是我们国人的骄傲!

    兵法曰:兵贵神速。不需要“十年一剑”,一年足矣。缔造的神话只有伴着酸甜苦辣走来的我们深刻体会。今日,当3D页游领域依旧仿若白纸一张时,我相信谁都迫切渴望通过最短的时间攻占世界前沿技术之巅峰!

    Silverlight 5 正预言着这么一个奇迹:中国的网游将在世界重新崛起,变革便在今朝!

    本节源码请到目录中下载

    在线演示地址:http://silverfuture.cn

     


    最新回复(0)