纸娃娃系统,或许大家听起来并不陌生。早在十几年前,当时不论是文字游戏“泥巴(Mud)”或是交友、社交网站,我们只能通过屏幕上的文字来传达与交互信息;随着技术不断进步,2D/3D图形技术高速崛起,通过在基础模型上由客户随意挑选、任意更换各种造型(素材),即可打造出真正属于“自我”独特风格的网络虚拟形象,QQ秀便是我们耳熟能详的代表,更贴近真实的如(RPG)游戏及虚拟现实中的换装/换肤系统同样亦得益于纸娃娃机制。

  本节,我将向大家讲解如何最好的实现Silverlight 2.5D网络游戏中的纸娃娃系统,以最大程度控制性能损失为前提,将游戏资源占用最小化,综合效果及用户体验最优化。

  以《Silverlight MMORPG网页游戏开发课程(Game Lesson)一期》的源码为基础,我将其再一次的进行了大规模重构。

  素材来源于网络,取《封神榜3》中的角色系统(纸娃娃系统)做示例,每个角色大致都包含上海徐汇企业网站设计与制作pan lang="EN-US">3个部件:铠甲(身体)、武器、骑乘(乘)等,而其中的骑乘道具又由2个部份组成,比如异人(弓手)的翅膀分为左右两支;甲士(战士)的坐骑分为前后两半;而方士(法师)的飞剑则仅为单独对象:

  2D/2.5D游戏中角色带翅膀飞行要考虑左右翼与身体的层次关系,骑马则需要考虑马头/马尾与身体间的层次问题。而且武器长短,角色朝向,行为姿势等也都可能影响到各部件的层次关系。因此,一些游戏为了简化设计,同时又不失华丽,便诞生了比如“踏云”,“御剑”,“乘鹤”,“踩蝶”等诸多天马行空的驾驭模式,这些乘具的共同点就是均被踩在脚上,自然而然处理起来更简单明了。当然,如果角色是3D模型的话则无需考虑这么多层叠关系。

  鉴于以上的参考分析,在Silverlight中构造装备纸娃娃系统框架便会轻松很多。暂时以带翅膀的弓手为例子,依葫芦画瓢,我们首先新建如下几个类:

  如图,EquipBase乃装备(纸娃娃)系统中的核心,所有的装备部件类比如铠甲(身体)Armor/武器Weapon/翅膀Wing/坐骑Ride均继承自该类:

/// <summary>/// 装备部件基类/// </summary> 上海闵行企业网站设计与制作>public abstract class EquipBase : ObjectBase {/// <summary>/// 加载完毕/// </summary> public event EventHandler Ready;/// <summary>/// 获取或设置部件名/// </summary> protected string partName { get; set; }long index = 0; //上海闵行企业网站制作e="color: #008000;"> 异步加载与换装同步协调 public override int Code {get { return base.Code; }set {
index
++;if (value == -1) { base.Code = value; return; }string key = string.Format("{0}{1}", partName, value);if (Res.ContainsKey(key)) {base.Code = value;
loadConfig(key);
}
else {
Downloader downloader
= new Downloader();
downloader.OpenReadCompleted
+= new OpenReadCompletedEventHandler(webClient_OpenReadCompleted);
downloader.OpenReadAsync(
string.Format("{0}{1}.xap", partName, value), string.Format("{0},{1}", index, value), 2000);
}
}
}
void webClient_OpenReadCompleted(object sender, OpenReadCompletedEventArgs e) {
Downloader downloader
= sender as Downloader;
downloader.OpenReadCompleted
-= webClient_OpenReadCompleted;string[] str = e.UserState.ToString().Split(',');if (Convert.ToInt64(str[0]) == index) {int code = Convert.ToInt32(str[1]);string key = string.Format("{0}{1}", partName, str[1]);if (!Res.ContainsKey(key)) { Res.Add(key, new StreamResourceInfo(e.Result as Stream, "application/binary")); }base.Code = code;
loadConfig(key);
}
}

Dictionary<string, Point> frameOffset = new Dictionary& lt;string, Point>(); //各帧偏移 /// <summary>/// 加载配置/// </summary> void loadConfig(string key) {
XElement info
= XElement.Load(Application.GetResourceStream(Res[key], new Uri("Info.xml", UriKind.Relative)).Stream).DescendantsAndSelf(partName).Single();
FullName
= info.Attribute("FullName").Value;// 解析各帧偏移 IEnumerable<XElement> iFrame = info.Element("Frames").Elements();
frameOffset.Clear();
foreach (XElement element in iFrame) {
frameOffset.Add(element.Attribute(
"ID").Value, new Point() {
X
= (double)element.Attribute("OffsetX"),
Y
= (double)element.Attribute("OffsetY"),
});
}
if (Ready != null) { Ready(this, null); }
}
bool _IsTurn;/// <summary>/// 获取或设置是否水平翻转/// </summary> public bool IsTurn {get { return _IsTurn; }set {if (_IsTurn != value) {
Transform
= (_IsTurn = value) ? scaleTransform : null;
}
}
}
bool _Flash;/// <summary>/// 获取或设置是否闪光/// </summary> public bool Flash {get { return _Flash; }set {if (_Flash != value) {//if (_Flash = value) {// dispatcherTimer.Start();//} else {// this.Opacity = 1;// dispatcherTimer.Stop();//} this.Opacity = (_Flash = value) ? 0.4 : 1;
}
}
}
bool order = false;
DispatcherTimer dispatcherTimer
= new DispatcherTimer() { Interval = TimeSpan.FromMilliseconds(100) }; // 换装时的闪光特效计时器 上海网站建设le="color: #0000ff;">public EquipBase() {
dispatcherTimer.Tick
+= new EventHandler(dispatcherTimer_Tick);
}
void dispatcherTimer_Tick(object sender, EventArgs e) {if (order) {this.Opacity = this.Opacity + 0.1;
上海企业网站制作
if (this.Opacity >= 1) { order = false; }
}
else {this.Opacity = this.Opacity - 0.1;if (this.Opacity <= 0.3) { order = true; }
}
}
static Dictionary<string, Stream> equipRes = new Dictionary<string, Stream>();

ScaleTransform scaleTransform = new ScaleTransform() { ScaleX = -1 };/// <summary>/// 呈现帧图/// </summary> public void Display(string key) {string resKey = string.Format("{0}{1}{2}", partName, Code, key);if (!equipRes.ContainsKey(resKey)) {
equipRes.Add(resKey, Application.GetResourceStream(Res[
string.Format("{0}{1}", partName, Code)], new Uri(string.Format("{0}.png", key), UriKind.Relative)).Stream);
}
this.StreamSource = equipRes[resKey];this.InternalOffset = frameOffset[key];if (IsTurn) { scaleTransform.CenterX = Center.X - frameOffset[key].X; }
}
public override void Dispose(object sender, EventArgs e) {
dispatcherTimer.Stop();
dispatcherTimer.Tick
-= dispatcherTimer_Tick;base.Dispose(sender, e);
}
}

  内容比较简明:当角色需要换装时,通过异步下载的方式获取该装备部件的XAP包,一旦下载完毕便将其缓存起来使用。当然,由于是异步,在整个Loading的过程中为了提高用户体验,我们可以在角色(Role)身上做些修饰以让玩家一看就明白该角色正处于换装Loading,比较有新意的做法是在角色中心添加一些描述性的文字,或使用一些旋转类的动画(Animation)

  另外,我还为其增加了一个名为Flash的方法,即当某个装备部件正处于Loading过程中时,该部件将执行时隐时现的Opacity动画,这种效果最完美了。不过,就目前的Silverlight 4 来说还无法对UIElementOpacity进行GPU硬件加速,暂时该方案的拓展与取舍/取代问题只能交由大家一同探讨。

  然后是关于换装系统中的素材资源的组织。对于像Silverlight这样基于动态加载的游戏开发技术来说,最大程度减少质量损失前提下的资源容量高度浓缩有利于网页游戏的动态加载,以及像Windows Phone这样磁盘空间相对较小的移动设备平台。以精致的2.5D网游中的角色为例,大都以8方向居多,当然我们也还是能够仅仅使用5个方向素材即达到减少资源开支的效果(比如对其中的东北、东、东南进行水平翻转)

  此方法以牺牲少量性能进行图像水平翻转为代价达到让资源总量减少近一半,且画质不打折扣的效果。唯一缺陷就是武器永远处于同一只手中,无论面朝何方;不过就整体而言,这不失为大多数网页游戏之首选。另外,对于Silverlight开发2.5D网页游戏来说,将图像资源PNG8化确实必要而关键。由于本节源码中的素材均来源于网络,所以效果很一般,如果是由3D美术原创的话,将逐帧图像导出并处理成颜色过渡均匀,边线条纹清晰流畅且无镂空的PNG8精美素材并非难事,最终还能再一次大幅降低游戏整体资源占用及内存开销:

  此时,大家应该有注意到本节中的资源命名规范与以往有了些变化,形如a-b-c-d.png的形式,对于铠甲(身体)和武器来说,a代表状态(打坐/步行/骑乘)b代表行为动作(停止/移动/攻击/受伤)c代表朝向;d代表帧号。而对于骑乘道具,比如翅膀和坐骑,a代表行为动作;b代表对象代号(比如翅膀1/翅膀2,坐骑前半部分/坐骑后半部分)cd则与前面一致。当然,这或许仅符合我个人的思维习惯,自认为如此配置更便于理解和使用,还是那句老话,只要能给程序的编写带来便利,依旧是仁者见仁,智者见智,并无定论。

  当装备类及相关资源设置完毕后,我们便可通过一个Role控件作为容器进行统一包装管理,此时我们创建一个名为RoleBase的角色基类,游戏中一切主体生命对象均由此衍生而来,比如英雄(Hero)/怪物(Monster)/非控对象(NPC)等等:

  大伙应该会留意到,与以前编写的结构有所不同,此时的Sprite的意义得到了更广泛的延伸,是一次新的诠释,它指代所有基于场景坐标系布局中的对象(映射到现实世界中即指一切活动着得对象),比方说角色(如英雄,怪物,宠物,动物,NPC,动画,魔法等),道具(如火焰,植物,飞箭等),特效(如云雾缭绕,打雷闪电,刮风下雨,花叶纷飞)等等,我们均可将其纳入“游戏精灵”的行列。外加上对角色的Coordinate(场景中的Point坐标属性)Position(游戏画布中的Point坐标属性)进行了更完美的协调,于是整个游戏控件项目(Controls)重构后层次关系更趋合理,耦合度降低,重用性更高,更利于后期功能的拓展。

  最后还是得特别强调下,Silverlight游戏中尽量使用小尺寸图片,因为图像的尺寸越大越消耗UI线程。作者曾经尝试过对英雄的4个部件均使用510*510尺寸的帧图像,即精灵每动上海企业网站设计与制作一下就会同时切换4510*510的图片;此时同屏仅共存10个该英雄便已让CPUFPS痛苦不堪;而如果将该4个部件的每张图像多余的透明部分裁剪掉,即每张帧图片均只有不到100的宽和高,然后通过TranslateTransform偏移到共同位置上,性能较之前几乎提升了几十个数量级,同屏1004件套精灵FPS照样不下30,开发者们切记了:

  本节源码下载地址:Demo1.rar

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

Silverlight 2.“.NET研究”5D RPG游戏技巧与特效处理:(二)纸娃娃系统相关推荐

  1. Silverlight“.NET技术” 2.5D RPG游戏技巧与特效处理:(十)空间分层战斗系统

    提到RPG中的空战系统,首先想到的当然是3D,这方面可是它的绝活.比如以之为核心噱头的<永恒之塔>:当然,在2.5D网游中也有着类似的实现,像<西游记Online>,不过该游戏 ...

  2. Silverlight 2.5D RPG游戏技巧与特效处理(Game Effects):目录

    以当下主流的2.5D RPG客户端品质游戏特效为借鉴,以最大程度控制性能损失为前提,将Silverlight游戏资源占用最小化,综合效果及用户体验最优化,即本系列作者想要向大家讲解的核心技术知识. 本 ...

  3. Silverlight 2.5D RPG游戏技巧与特效处理:(二十一)自定义路径动画

    一直在想应该用什么作为<Silverlight 2.5D RPG游戏技巧与特效处理系列教程>的终结,既要实用而不拖泥带水:又要通用而不哗众取宠.于是一不小心便成就了我一个未了心愿:一切基于 ...

  4. Silverlight 2.5D RPG游戏技巧与特效处理:自定义路径动画

    一直在想应该用什么作为<Silverlight 2.5D RPG游戏技巧与特效处理系列教程>的终结,既要实用而不拖泥带水:又要通用而不哗众取宠.于是一不小心便成就了我一个未了心愿:一切基于 ...

  5. Silverlight 2.5D RPG游戏技巧与特效处理:(十一)AI系统

    Silverlight 2.5D RPG游戏技巧与特效处理:(十一)AI系统 作者: 深蓝色右手  来源: 博客园  发布时间: 2011-04-19 11:18  阅读: 1282 次  推荐: 0 ...

  6. Silverlight 2.5D RPG游戏技巧与特效处理:(三)动态光影

    通常来说,只要谈到影子及影子制作,首先想到的不外乎3D.游戏中的影子设计大致可分为硬实现和软实现两种,比如像"游戏影子制作技术"这篇文章所谈到3D游戏影子制作方案Projectiv ...

  7. Silverlight“.NET研究” 2.5D RPG游戏技巧与特效处理:(十)空间分层战斗系统

    提到RPG中的空战系统,首先想到的当然是3D,这方面可是它的绝活.比如以之为核心噱头的<永恒之塔>:当然,在2.5D网游中也有着类似的实现,像<上海徐汇企业网站制作n lang=&q ...

  8. Silverlight 2.5D RPG游戏技巧与特效处理:(十一“.NET研究”)AI系统

    谈到人工智能(AI),这个话题就太大了:大学里有<人工智能教程>专门讲这方面的知识,什么大名鼎鼎的人工神经网络.遗传算法等等均可一窥究竟,这里如赘述似乎有些班门弄斧,我们暂且丢它一边去吧. ...

  9. Silverlight 2.5D RPG游戏技巧与特效处理:(五)HLSL渲染动画

    或许大家依旧对上一节中的"黑夜"及"梦回过去"记忆犹新,追问下去HLSL到底是何方神圣能实现如此炫酷之效果?HLSL(高级着色器语言)作为微软的独门兵器,仅供D ...

  10. Silverlight 2.5D RPG游戏技巧与特效处理:HLSL渲染动画

    或许大家依旧对上一节中的"黑夜"及"梦回过去"记忆犹新,追问下去HLSL到底是何方神圣能实现如此炫酷之效果?HLSL(高级着色器语言)作为微软的独门兵器,仅供D ...

最新文章

  1. iOS开发之Masonry框架源码解析
  2. 较复杂js的书写格式
  3. 禅道的安装与简单使用
  4. 数据结构之二叉树的定义和性质
  5. Vue3 组合式Api之customRef实现防抖功能
  6. STM32 中的CEC
  7. 对计算机病毒的防治也,对计算机病毒及防范对策研究.doc
  8. matlab非线性误差的计算(附代码)
  9. 制作自己的ChatGPT
  10. 英语 译林 2019 单词表
  11. postman导出,断言,批量执行
  12. 毕业设计-基于 MATLAB 的图像分割算法研究及实现
  13. Mind+实现自定义用户库——TM1637数码管
  14. 多帧点云数据拼接合并_基于单帧图像与稀疏点云融合的道路交通标线提取算法研究...
  15. 新书隆重推介:网络协议本质论(2011年8月面世,沤心沥血之作)
  16. java腾讯云人脸核身移动浮层H5接入
  17. 计算机科学与技术检修建筑学,2020年东南大学最好专业排名:43个专业上榜,建筑学居全国前5%!...
  18. SHELL编程之CASE语句+函数+正则
  19. MySQL支持的可执行注释功能
  20. OpenCV官方教程中文版——学习笔记(一)

热门文章

  1. python 排队论_建模算法(七)——排队论模型
  2. 关于redis HSCAN count参数不生效的问题
  3. 2013年上半年 系统分析师 论文 真题
  4. Qt实战开发-数字软键盘
  5. 计算机操作系统试题及答案(带解析),计算机操作系统练习题及答案
  6. Winrunner经验总结
  7. 【电子书制作软件哪个好】云展网教程 | 搜索功能:搜索杂志内文字可高亮
  8. 安川西格玛7驱动器手册_安川伺服驱动说明书7.pdf
  9. 因子分析在SPSS中的操作过程及结果解读
  10. 小米pro安装win10系统