热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Silverlight游戏设计(GameDesign):(十)梦幻西游(Demo)之“天人合一”①

与当年盛大通过代理《传奇》一举成名,九城代理《奇迹》一夜发迹完全不同,金山、网易凭借他们自主的研发团队,数年时间倾力打造了《剑侠》及《西游》等系列非常优秀的纯国产网游,不仅开创了此领域的先河,且作为中

与当年盛大通过代理《传奇》一举成名,九城代理《奇迹》一夜发迹完全不同,金山、网易凭借他们自主的研发团队,数年时间倾力打造了《剑侠》及《西游》等系列非常优秀的纯国产网游,不仅开创了此领域的先河,且作为中国网游行业的榜样,让我时常感到崇敬与骄傲。西山居、烈火、大话西游等工作室这些如雷贯耳的称号已家喻户晓,所有成功的背后都有着一段源自对中国古风古韵故事的生动阐述,事实也证明了神化传说终是游戏设计中永不褪色的主题。

让经典重现是无比让人神往的体验。本节,我将以制作《梦幻西游》Demo为例,继续向大家讲解并演示如何通过Silverlight-2D场景编辑器搭建出结构更复杂的游戏场景。

与前两节不同,由于《梦幻西游》与《三国策》同属回合制RPG游戏类型,因此我们首先要做的是直接按照第七节的方法,但是使用基于第八节《三国策》Demo源码之上而直接修改出来新的Demo,并取名为MhxyDemo

精致的网络游戏中精灵应该具备多部件纸娃娃系统,梦幻西游中的角色也不例外。在此Demo中,我以原始素材为依据,同样将玩家角色精灵分成身体、武器、坐骑、影子等4个部分:

此时大家或许会有些疑惑,组合后的图似乎与这些分开的素材并不吻合?是的,上图中的武器、身体图片均为精灵在无坐骑状态时的素材;而当精灵由“步行”变换为“骑乘”状态后,武器、身体的素材又会更换成另一套,这里涉及到各部分素材该如何合理布局这样一个问题。寻找相应解决方案,我们得从游戏的整体设计出发。精灵是游戏中的主角,以精灵为本,在回合制RPG游戏中,精灵拥有3种不同的显示模式:步行模式、骑乘模式及战斗模式,在这3种模式下精灵的姿势及武器的位置等均不相同:

如上图,3张均为同一角色东朝向移动时的第二帧图片,显然是截然相同的。因此,为了逻辑代码上的便利,我们必须通过对这些素材进行类似如下布局方能轻松实现灵活的素材文件加载:

至于这些素材该怎样组合,方案也是多种多样的。最简单的方案就是通过直接叠加的方式,此方式不需耗费像素合成,工作量也小,然而缺点同样明显,素材尺寸一致将导致总体容量很大。传统游戏的做法是通过配置或表头文件为每张图片定义好它的偏移量,每次调用时进行相应偏移或定点截取即可:

唯一麻烦之处是需要前期大量的美工处理及布局调整。总体来说,多部件纸娃娃系统可以大幅提升游戏的趣味性,深度套劳玩家那颗对“角色Show”痴迷的心;当然,成功的背后一切都离不开良好的游戏结构设定与布局。

素材方面就讲到这。梦幻西游除了拥有优秀的角色设定外,在场景上同样也很卓越。在本节的Demo中,我以原形为基础搭建出了传说中的2.8D斜视角双背景层次结构:

    底层为云彩,包含于Window窗口容器中,可固定不动或朝主角相反的方向1/10左右速度相对移动;表层则是正常的地图背景,主位式镜头跟随主角相对移动。通过此方式对场景进行分层处理可以实现华丽的2.8D效果,玩家在游戏中将亲历置身于天空之城般神奇的体验。而若在此基础上,将双背景换成双场景,那么《梦幻诸仙》的飞空系统不同样可以轻易实现?嘿嘿,又一次的印证了基于场景的游戏架构定能让游戏开发更加简单。

同时,在本节的Demo中我还添加了第一部教程第三十七节中的讲到的地图切片及按需加载技术,此方案能大幅提升游戏的流畅性且降低服务器端负荷。这里还是想再次感谢goods,在他提供的9切片地图加载算法基础上,我将之再次升级为动态下载模式,核心代码如下:

        Point2D _sectionCenter;

        ///

        /// 获取或设置地图切片中心

        ///

        public Point2D sectionCenter {

            get { return _sectionCenter; }

            set {

                if (!_sectionCenter.Equals(value)) {

                    ChangeMapSection(_sectiOnCenter= value);

                }

            }

        }

 

        ///

        /// 更新呈现的地图切片

        ///

        /// 引导场景地图变换的精灵主角所处的窗口切片坐标

        private void ChangeMapSection(Point2D leaderSection) {

            int startSectionX, startSectionY, endSectionX, endSectionY;

            //根据主角当前位置来加载周边地图切片

            if (leaderSection.X == 0) {

                startSectiOnX= 0; endSectiOnX= 2;

            } else if (leaderSection.X == SectionXNum - 1) {

                startSectiOnX= leaderSection.X - 2; endSectiOnX= leaderSection.X;

            } else {

                startSectiOnX= leaderSection.X - 1; endSectiOnX= leaderSection.X + 1;

            }

            if (leaderSection.Y == 0) {

                startSectiOnY= 0; endSectiOnY= 2;

            } else if (leaderSection.Y == SectionYNum - 1) {

                startSectiOnY= leaderSection.Y - 2; endSectiOnY= leaderSection.Y;

            } else {

                startSectiOnY= leaderSection.Y - 1; endSectiOnY= leaderSection.Y + 1;

            }

            int index = 0;

            //取回已经超出主角周围9块范围的切片(x,y初始-1,第一次加载9)

            tempSection[] tempSectiOnList= sectionList.Where(c => c.x endSectionX || c.y endSectionY).ToArray();

            for (int x = startSectionX; x <= endSectionX; x++) {

                for (int y = startSectionY; y <= endSectionY; y++) {

                    //9点位中假如已经有该点位的切片在则检查下一个

                    if (sectionList.Where(c => c.x == x && c.y == y).Count() > 0) {

                        continue;

                    } else {

                        //将超出范围的切片填充到新的位置上,并重置它们的x,y点位坐标值

                        tempSectionList[index].x = x;

                        tempSectionList[index].y = y;

                        mapSection[tempSectionList[index].sectionNo].Source = GetProjectImage(string.Format("Images/MiniMap/{0}/Surface/{1}_{2}{3}", this.Code, x, y, FileType(MapFormat)));

                        //下载实际图片

                        Downloader downloader = new Downloader() {

                            Args = string.Format("{0},{1},{2}", index, x, y)

                        };

                        downloader.Completed += (s, e) => {

                            Downloader loader = s as Downloader;

                            string[] args = loader.Args.Split(',');

                            int tempIndex = Convert.ToInt32(args[0]), tempX = Convert.ToInt32(args[1]), tempY = Convert.ToInt32(args[2]);

                            if (tempSectionList[tempIndex].x == tempX && tempSectionList[tempIndex].y == tempY) {

                                mapSection[tempSectionList[tempIndex].sectionNo].Source = GetWebImage(string.Format("Images/Map/{0}/Surface/{1}_{2}{3}", this.Code, tempX, tempY, FileType(MapFormat)));

                            }

                        };

                        downloader.GetImage(WebPath(string.Format("Images/Map/{0}/Surface/{1}_{2}{3}", this.Code, x, y, FileType(MapFormat))));

                        Canvas.SetLeft(mapSection[tempSectionList[index].sectionNo], x * SectionWidth);

                        Canvas.SetTop(mapSection[tempSectionList[index].sectionNo], y * SectionHeight);

                        index++;

                    }

                }

            }

        }

另外,整张地图包含有3个景点,景点之间均是相互隔离的。在未修改任何上一节传送部分代码的基础上,我们只需配置xml文件中传送点传送到的坐标及ToScene等于当前场景代号,即可实现同场景不同位置间的传送(瞬移也是类似原理,封装好的传送代码为我们提供了相当大的便利):

    

    <Teleports>

      <Teleport ID="0" Code="0" X="2820" Y="2040" Z="184" ToScene="0" ToX="105" ToY="49" ToDirection="2" Tip="传送到:比武场"/>

      <Teleport ID="1" Code="0" X="2455" Y="1680" Z="164" ToScene="0" ToX="57" ToY="95" ToDirection="6" Tip="传送到:武门殿"/>

      <Teleport ID="2" Code="0" X="4270" Y="1530" Z="156" ToScene="0" ToX="99" ToY="83" ToDirection="2" Tip="传送到:空中亭阁"/>

      <Teleport ID="3" Code="0" X="835" Y="1510" Z="154" ToScene="0" ToX="88" ToY="79" ToDirection="0" Tip="传送到:空中亭阁"/>

    Teleports>

    再复杂的游戏设计也离不开最普通的游戏架构基础,光有强大的场景仍然无法支撑游戏的完美表述;因此,下一节我会在此Demo的基础上进一步丰富游戏,赋予游戏更多的生命与灵气。赶快加入到Silverlight游戏开发的行列中来吧,世界将因你而变得更精彩!

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

源码请到目录中下载

作者:深蓝色右手出处:http://blog.csdn.net/alamiye010/教程目录及源码下载:点击进入 本文版权归作者和CSDN共有,欢迎转载。但未经作者同意必须保留此段声明,且在文章页面显著位置给出原文连接,否则保留追究法律责任的权利。

 


推荐阅读
  • 尽管使用TensorFlow和PyTorch等成熟框架可以显著降低实现递归神经网络(RNN)的门槛,但对于初学者来说,理解其底层原理至关重要。本文将引导您使用NumPy从头构建一个用于自然语言处理(NLP)的RNN模型。 ... [详细]
  • 基因组浏览器中的Wig格式解析
    本文详细介绍了Wiggle(Wig)格式及其在基因组浏览器中的应用,涵盖variableStep和fixedStep两种主要格式的特点、适用场景及具体使用方法。同时,还提供了关于数据值和自定义参数的补充信息。 ... [详细]
  • 本文将介绍如何编写一些有趣的VBScript脚本,这些脚本可以在朋友之间进行无害的恶作剧。通过简单的代码示例,帮助您了解VBScript的基本语法和功能。 ... [详细]
  • Explore a common issue encountered when implementing an OAuth 1.0a API, specifically the inability to encode null objects and how to resolve it. ... [详细]
  • 计算机网络复习:第五章 网络层控制平面
    本文探讨了网络层的控制平面,包括转发和路由选择的基本原理。转发在数据平面上实现,通过配置路由器中的转发表完成;而路由选择则在控制平面上进行,涉及路由器中路由表的配置与更新。此外,文章还介绍了ICMP协议、两种控制平面的实现方法、路由选择算法及其分类等内容。 ... [详细]
  • 导航栏样式练习:项目实例解析
    本文详细介绍了如何创建一个具有动态效果的导航栏,包括HTML、CSS和JavaScript代码的实现,并附有详细的说明和效果图。 ... [详细]
  • 本文基于刘洪波老师的《英文词根词缀精讲》,深入探讨了多个重要词根词缀的起源及其相关词汇,帮助读者更好地理解和记忆英语单词。 ... [详细]
  • 数据管理权威指南:《DAMA-DMBOK2 数据管理知识体系》
    本书提供了全面的数据管理职能、术语和最佳实践方法的标准行业解释,构建了数据管理的总体框架,为数据管理的发展奠定了坚实的理论基础。适合各类数据管理专业人士和相关领域的从业人员。 ... [详细]
  • 前言--页数多了以后需要指定到某一页(只做了功能,样式没有细调)html ... [详细]
  • DNN Community 和 Professional 版本的主要差异
    本文详细解析了 DotNetNuke (DNN) 的两种主要版本:Community 和 Professional。通过对比两者的功能和附加组件,帮助用户选择最适合其需求的版本。 ... [详细]
  • 本章将深入探讨移动 UI 设计的核心原则,帮助开发者构建简洁、高效且用户友好的界面。通过学习设计规则和用户体验优化技巧,您将能够创建出既美观又实用的移动应用。 ... [详细]
  • 本文详细介绍了macOS系统的核心组件,包括如何管理其安全特性——系统完整性保护(SIP),并探讨了不同版本的更新亮点。对于使用macOS系统的用户来说,了解这些信息有助于更好地管理和优化系统性能。 ... [详细]
  • 本文详细记录了在银河麒麟操作系统和龙芯架构上使用 Qt 5.15.2 进行项目打包时遇到的问题及解决方案,特别关注于 linuxdeployqt 工具的应用。 ... [详细]
  • 本文详细介绍了中央电视台电影频道的节目预告,并通过专业工具分析了其加载方式,确保用户能够获取最准确的电视节目信息。 ... [详细]
  • 使用GDI的一些AIP函数我们可以轻易的绘制出简 ... [详细]
author-avatar
Aovte
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有