您的位置:首页 > 编程语言 > C#

C#开发WPF/Silverlight动画及游戏系列教程(Game Tutorial):(三十二) 雷、混、冰、毒、火、风 - 幻化中的魔法魅力!

2009-09-09 18:06 633 查看
魔法的魅力不仅仅因为其华丽的外表,更深层次的,它们的额外附加属性效果使得游戏世界更加幻化多彩!无论是中式的金木水火土5行,还是欧式的水火风雷,异或是日式的风林火山等等,在目前的网游世界中无处不得到体现。更甚者,由此衍生出来的好比火影中的混合属性更推动了魔法属性概念的再一次升华。

本节,我将为大家演示如何为游戏中的魔法增加华丽的附加属性。

第一步,定义规则:

1)定义魔法附加属性分类:在本教程示例游戏中,我将魔法附加属性定义为6类:雷、混、冰、毒、火、风,为什么要以这样无规律的方式去命名?因为是教程,我们需要学习的是如何实现对应效果,此6类属性算是目前网游中最流行的六大魔法属性,如果大家都掌握了,无论是中国式5行还是诸如其他的风格设计,均能做到游刃有余。

2)定义魔法附加属性功能及效果:

雷 – 麻痹 – 精灵麻痹(被附加该属性精灵将无法动弹)

混 – 混乱 – 精灵混乱(被附加该属性精灵将乱跑)

冰 – 冰冻 – 精灵减速(被附加该属性精灵移动速度、物理攻击速度、施法速度均减慢)

毒 – 中毒 – 精灵中毒(被附加该属性精灵每秒持续减生命值)

火 – 燃烧 – 精灵灼伤(被附加该属性精灵所有防御类属性值降低)

风 – 虚弱 – 精灵弱化(被附加该属性精灵所有攻击类属性值降低)

对应枚举:

<ExtraItems>

<Item Value="0" Src="Interface/Icon/Extra0.png" Name="麻痹" Description="效果:无法动弹" />

<Item Value="1" Src="Interface/Icon/Extra1.png" Name="混乱" Description="效果:乱跑" />

<Item Value="2" Src="Interface/Icon/Extra2.png" Name="冰冻" Description="效果:速度减缓" />

<Item Value="3" Src="Interface/Icon/Extra3.png" Name="中毒" Description="效果:持续伤血" />

<Item Value="4" Src="Interface/Icon/Extra4.png" Name="燃烧" Description="效果:所有防御属性值降低" />

<Item Value="5" Src="Interface/Icon/Extra5.png" Name="虚弱" Description="效果:所有攻击属性值降低" />

</ExtraItems>

3)定义魔法附加属性视觉表现:[/u]

麻痹 – 雪白

混乱 – 黄色

冰冻 – 天蓝

中毒 – 绿色

燃烧 – 红色

虚弱 – 灰色

第二步,具体实现:

首先我们需要考虑的是如何实现精灵的变色,即如何改变精灵图片源的色相。在很多编程语言中都有现成的类库可以调用,但是在目前的WPF/Silverlight中,除了使用HLSL自定义渲染特效外,没有其他能够直接改变图片色相的方法了。但这并不意味着WPF/Silverlight就此束手无策了,WPF/Silverlight的强大图形表现能力让我想到了控件蒙版,既然直接的不行,那么我们就来间接的。

接下来我们为精灵控件QXSpirit的表现层xaml中添加如下一个矩形蒙版:

<Rectangle Name="BodyMask" Opacity="0.3" Visibility="Collapsed" Panel.ZIndex="1">

<Rectangle.OpacityMask>

<ImageBrush x:Name="BodyMaskSource"></ImageBrush>

</Rectangle.OpacityMask>

</Rectangle>

此精灵身体蒙版默认情况下是不可见的,它的透明度为0.3,并且ZIndex必须覆盖于精灵之上。只要我们在后台cs中将此蒙版宽高与精灵图片源宽高时刻保持联动一致,这样,当需要的时候通过设置BodyMaskSource.ImageSource = Body.Source;然后根据前文中相应的视觉表现赋予蒙版Fill颜色,并将之显示出来。即可以轻松的模仿实现精灵图片源的色相改变。

实现色相改变原来如此的简单,只是在性能上来说等于增加了多余的消耗,但这并不是长期的,仅仅当精灵被施与附加属性后才会短时间变色,在恢复正常后即将蒙版隐藏,Collapsed将不再占用界面资源。

完成了界面,剩下的就是实现逻辑。魔法附加属性不可能是永久的,就好比中毒有个中毒持续时间,麻痹有麻痹持续时间等等,除了那些即效魔法外,本文介绍的这6类魔法附加属性均为持续性的。因此,我通过为精灵控件添加一个ExtraTime属性来记录精灵被施与魔法附加属性的持续时间:

double[] _ExtraTime = new double[6];

/// <summary>

/// 获取或设置被附加属性对应持续时间,与枚举ExtraAttributes一一对应

/// </summary>

public double[] ExtraTime {

get { return _ExtraTime; }

set { _ExtraTime = value; }

}

该时间数组为double类型,分别与枚举ExtraAttributes一一对应。通过如此设置,我们可以轻松的借助主界面间隔为1秒的辅助线程AuxiliaryThread去同步更新它们(每秒-1),并实现例如中毒每秒伤血等相关业务逻辑,可谓水到渠成,无缝衔接。

由于此6种附加属性实现的相应功能相差较大,基本无统一的规律可寻,因此下面我将按类型分类进行讲解:

1)雷:

本示例教程中我将之定义为使精灵无法动弹,无法动弹一方面意味着它自身动作被锁定,另一方面表示它无法移动。代码实现即:

if (enemy.VLife > injure) {

enemy.BodyMaskColor = new SolidColorBrush(Colors.Snow);

enemy.BodyMaskSource.ImageSource = enemy.Body.Source;

enemy.TimerState = TimerStates.Stop;

Super.PauseSpiritStoryboard(enemy);

} else {

enemy.TimerState = TimerStates.Start;

}

同时需要为直线移动方法与A*移动方法开头添加一个判断: if (spirit.ExtraTime[0] > 0) { return; }

测试效果截图:



2)混

本示例教程中我将之定义为使精灵随机乱向跑动。此附加属性非常有趣,实现起来也很简单,我们只需将精灵的移动目标进行重新随机更改,即为直线移动方法与A*移动方法开头添加如下一个判断处理即可:

if (spirit.ExtraTime[1] > 0) {

p = new Point(p.X + (p.X > spirit.X ? -random.Next(200) : random.Next(200)),

p.Y + (p.Y > spirit.Y ? -random.Next(200) : random.Next(200)));

}

测试效果截图:



3)冰:

本示例教程中我将之定义为使精灵移动速度、攻击速度、施法速度减速。大家回忆一下第二十八节中关于精灵属性的设计,其中精灵的所有类型属性均由4个部分组成,以下为这3个速度属性的构造定义:

/// <summary>

/// 获取跑步速度(每移动一个单元格的花费时间,越小越快)

/// </summary>

public double VRunSpeed {

get { return ABase[5] + Equip[5] + Buff[5] - VAgile * Coefficient[5]; }

}

/// <summary>

/// 获取物攻速度(越小越快)

/// </summary>

public double VAttackSpeed {

get { return ABase[6] + Equip[6] + Buff[6] - VAgile * Coefficient[6]; }

}

/// <summary>

/// 获取施法速度(越小越快)

/// </summary>

public double VMagicSpeed {

get { return ABase[7] + Equip[7] + Buff[7] - VAgile * Coefficient[7]; }

}

其中的Buff即为附加属性影响的部分。了解了原理,将之转换成机器语言即为:

enemy.Buff[5] = enemy.ExtraEffect[magic.ExtraAttribute];

enemy.Buff[6] = enemy.ExtraEffect[magic.ExtraAttribute];

enemy.Buff[7] = enemy.ExtraEffect[magic.ExtraAttribute];

当判断冰冻持续时间减为0后,我们只需更新这3个Buff值归0即可。是不是很方便?嘿嘿,同时也证明了第二十八节我对精灵属性结构设计定义的正确性。

测试效果截图:



4)毒:

本示例教程中我将之定义为精灵每秒持续伤血。此效果实现起来更简单了,只需要在主界面间隔为1秒的辅助线程计时器中对中毒时间是否大于0进行判断,然后进行相应的伤害处理即可;并且其他的所有附加属性的时间减少均写在该方法内:

//同步激发精灵附加属性效果

for (int i = 0; i < Carrier.Children.Count; i++) {

if (Carrier.Children[i] is QXSpirit) {

QXSpirit spirit = Carrier.Children[i] as QXSpirit;

if (spirit.VLife != 0) {

for (int j = 0; j < spirit.ExtraTime.Count(); j++) {

if (spirit.ExtraTime[j] > 0) {

//中毒则每秒伤血

if (j == 3) {

Super.DoInjure(Find(spirit.ExtraSpirit), spirit, spirit.ExtraEffect[j]);

}

//持续时间减少

spirit.ExtraTime[j] = spirit.ExtraTime[j] - AuxiliaryThread.Interval.Seconds;

if (spirit.ExtraTime[j] <= 0) {

//移除附加属性效果

Super.RemoveExtraEffect(spirit, j);

}

}

}

}

}

}

测试效果截图:



5)火:

本示例教程中我将之定义为降低精灵所有防御类属性值。类似于冰的效果,处理时只需将物理防御力的Buff[9]、隔挡率的Buff[10]、魔法防御力的Buff[12]减少对应的火攻击值即可:

enemy.Buff[9] = -enemy.ExtraEffect[magic.ExtraAttribute];

enemy.Buff[10] = -enemy.ExtraEffect[magic.ExtraAttribute];

enemy.Buff[12] = -enemy.ExtraEffect[magic.ExtraAttribute];

解除时3者归0。

测试效果截图:



6)风:

本示例教程中我将之定义为降低精灵所有攻击类属性值

enemy.Buff[1] = -enemy.ExtraEffect[magic.ExtraAttribute];

enemy.Buff[2] = -enemy.ExtraEffect[magic.ExtraAttribute];

enemy.Buff[13] = -enemy.ExtraEffect[magic.ExtraAttribute];

enemy.Buff[14] = -enemy.ExtraEffect[magic.ExtraAttribute];

enemy.Buff[15] = -enemy.ExtraEffect[magic.ExtraAttribute];

解除时5者归0。

该类型魔法影响对象精灵的最小物理攻击的Buff[1]、最大物理攻击的Buff[2]、最小魔法攻击的Buff[13]、最大魔法攻击的Buff[14]、暴击率的Buff[15]等。

测试效果截图:



非常酷的6大魔法附加属性,基本上囊括了目前主流的魔法效果。好比麻痹,它又可以延伸出定身、眩晕、冻结等效果;冰冻同样也可以分解成减慢移动速度、减慢攻速、增加魔法咏唱时间等等。

魔法世界的幻化莫测时刻让我回味。教程至此已完美的诠释了我曾经制作的WPF-ARPG游戏引擎,更有过之而无不及~后期的教程我将更深入的对目前的引擎进行补充、完善、优化!敬请关注。



作者:深蓝色右手
出处:http://alamiye010.cnblogs.com/
教程目录及源码下载:点击进入(欢迎加入WPF/Silverlight小组 WPF/Silverlight博客团队)
本文版权归作者和博客园共有,欢迎转载。但未经作者同意必须保留此段声明,且在文章页面显著位置给出原文连接,否则保留追究法律责任的权利。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐