仅以此文献给曾经的旷世经典 大法师(T4C 又名第四次审判)

从红白机到PS3,从286到奔腾N核;曾记否孩时的回忆?与玩伴并肩闯关。往日的经典已化为过眼烟云,那些神话般的游戏角色是否仍徘徊于你的梦里?UO开创了网络游戏新时代,虚拟世界敞开了魔幻华丽的心扉;于是我坚定了信念,用自己的双手去开启这道华丽的轮回!

在传统的MMORPG游戏中,魔法种类大致分为:单攻魔法、群攻魔法、辅助魔法、地图魔法等,其中单攻魔法又可以细分为带过程的(如飞箭),不带过程的(如闪电),多段单体等等;群攻魔法就更多了,以圆形区域群攻为主流,还有多边形区域群攻,穿梭群攻,多段群攻等等;辅助魔法主要就是BUFF加成与减持,如加血、加防、加攻、加防护罩等等;地图魔法则以陷阱为主要代表,还有其他的例如瞬移等等。

本节我将为大家讲解最华丽且又是最易于实现的圆形范围群攻魔法的实现。

魔法控件是实现魔法的前提,因此我们首先建立一个名为QXMagic的魔法控件,并为之赋予一些属性(具体内容看源码)。这些属性都有注释这里就不详讲了;其中比较关键的是每个魔法同样拥有一个生命线程,用于播放及触发攻击效果,因为魔法从产生到结束是由一系列帧组成的:

有了魔法控件,接着就是考虑该如何实现功能。在通常的MMORPG中,我们主动施放魔法有两个途径:鼠标右键或键盘快捷键,过程其实大同小异,那么本节就以鼠标右键施放魔法为例进行讲解。

首先我们需要为游戏窗体注册鼠标右键事件,然后在里面这样写:

        private void Window_MouseRightButtonDown(object sender, MouseButtonEventArgs e) {

            if (Leader.Action == Actions.Death) { return; }

            ……

            Leader.MagicTarget = p;

            //假如点击的地方太远则先跑到施法范围再施法,否则直接施法

            if (Super.InCircle(Leader.X, Leader.Y, p.X, p.Y, Leader.MagicRange)) {

                ChangeDirection(Leader, p);

                DoMagic(Leader);

            } else {

                Leader.IsMagicMove = true;

                double n = Math.Sqrt(Math.Pow(p.Y - Leader.Y, 2) + Math.Pow(p.X - Leader.X, 2));

                double x = p.X - (p.X - Leader.X) * Leader.MagicRange / n;

                double y = p.Y - (p.Y - Leader.Y) * Leader.MagicRange / n;

                MoveTo(Leader, new Point(x, y));

            }

        }

当我们在地图上点击鼠标右键时,首先判断主角与施放点之间的距离是否在施法距离内,如果是则放出魔法,否则我们计算出能该方向上与释放点距离刚好为主角施法距离的点,然后主角向该点跑去,到达后再施法:

同时,我将法术的参数定义在xml参数文件中:

    <Magics>

      <Magic Code="0" HasDirection="false" FrameNum="19" EffectiveFrame="4" SingleWidth="320" SingleHeight="344" Radius="140" CenterX="154" CenterY="214">

        <Level Value="1" ATK="120" Consumption="10"/>

        <Level Value="2" ATK="160" Consumption="15"/>

        <Level Value="3" ATK="200" Consumption="20"/>

        <Level Value="4" ATK="240" Consumption="25"/>

        <Level Value="5" ATK="280" Consumption="30"/>

        <Level Value="6" ATK="320" Consumption="35"/>

        <Level Value="7" ATK="380" Consumption="40"/>

        <Level Value="8" ATK="500" Consumption="50"/>

        <Level Value="9" ATK="700" Consumption="60"/>

      </Magic>

    ……

<Magics>

大家可以看到,每个法术都拥有一个法术代号用于法术标识(上面的法术代号为Code="0")并且分列出法术各等级的附加攻击力(ATK)与消耗的魔法值(Consumption),然后在施放魔法之前首先判断施法者的魔法值与该魔法的魔法消耗值之间的大小关系以判断施法者当前魔法值是否足够支持施法者施法:

……

if (VSpell < consumption) {

        Super.ShowText(this, true, true, "NotEnough", "魔法值不足", 22, Colors.Green, 0.5);

}

……

这样施法前的步骤就完成了,下面就是伤害计算与结果处理。

伤害计算与前面章节中的物理攻击伤害计算很类似,只是由于本例魔法为群攻魔法,所以需要循环遍历所有在魔法攻击范围内(以魔法有效距离Radius为半径的圆内)的所有敌对精灵,然后进行攻防计算最终产生伤害并输出显示出来:

并且,主角在杀死怪物后会获得怪物的经验值,同样的需要显示输出:

额外的,主角自身的经验值属性也同时增加,并且当达到下一级所需的升级经验时即会触发升级效果,每一级所需的经验值我一并放在xml系统参数文件中:

    <LevelUp>

      <Experience Level="0" Value="0" />

      <Experience Level="1" Value="0" />

      <Experience Level="2" Value="400" />

      <Experience Level="3" Value="1280" />

      <Experience Level="4" Value="2720" />

      <Experience Level="5" Value="4800" />

      <Experience Level="6" Value="7600" />

      <Experience Level="7" Value="11200" />

      <Experience Level="8" Value="15680" />

      <Experience Level="9" Value="21120" />

      <Experience Level="10" Value="27600" />

      <Experience Level="11" Value="35200" />

      <Experience Level="12" Value="44000" />

      <Experience Level="13" Value="54080" />

      <Experience Level="14" Value="65520" />

      <Experience Level="15" Value="78400" />

      <Experience Level="16" Value="92800" />

      <Experience Level="17" Value="108800" />

      <Experience Level="18" Value="126480" />

      <Experience Level="19" Value="145920" />

      <Experience Level="20" Value="167200" />

      <Experience Level="21" Value="190400" />

      <Experience Level="22" Value="215600" />

      <Experience Level="23" Value="242880" />

      <Experience Level="24" Value="272320" />

      <Experience Level="25" Value="304000" />

      ……

</LevelUp>

该经验值表是参考魔兽世界的,暂时添加了25级。在游戏初始化时即加载进内存的public static int[] LevelUpExperienceList数组中。关于获取经验值并升级的相关逻辑我们可以这样写:

        /// <summary>

        /// 增加经验值

        /// </summary>

        /// <param name="spirit">对象精灵</param>

        /// <param name="value">增加值</param>

        public static void EarnExperience(QXSpirit spirit, int value) {

            //如果OL版还需要加入判断杀对方的人是否为玩家

            if (spirit.VExperience + value >= LevelUpExperienceList[spirit.VLevel + 1]) {

                //等级+1

                spirit.VLevel += 1;

                //多出来的经验

                value = spirit.VExperience + value - LevelUpExperienceList[spirit.VLevel];

                //当前经验归0

                spirit.VExperience = 0;

                //再重复检验一次,防止经验超过几级

                EarnExperience(spirit, value);

            } else {

                spirit.VExperience += value;

            }

        }

这样就完成了所有从准备施法->施法前判断->伤害处理->经验值获取这一系列完美施法流程。在本节中由于引入了群攻魔法,因此我增加了几个按钮用于调试:

至于其他的如单体魔法、辅助魔法等如果时间充裕的话我会在后续章节中进行补充。

这就是梦想,一个狂热的游戏爱好对曾经辉煌的直着。

夜已深,思绪再次回到了过去,无数经典缕上心头。与往昔素未谋面的战友们并肩战斗,畅快淋漓。如今的网游已索然无谓,抄袭到了一定的深度与骷髅骨架毫无区别。缅怀之余仍有一丝丝的期待 只因梦依旧。

WPF/Silverlight
作者:深蓝色右手
出处:http://alamiye010.cnblogs.com/
教程目录及源码下载:点击进入(欢迎加入WPF/Silverlight小组 WPF/Silverlight博客团队)
本文版权归作者和博客园共有,欢迎转载。但未经作者同意必须保留此段声明,且在文章页面显著位置给出原文连接,否则保留追究法律责任的权利。
posted on 2009-08-06 19:34  深蓝色右手  阅读(9397)  评论(43编辑  收藏  举报