[转载]Android 资源的国际化

mikel阅读(906)

[转载]Android 资源的国际化 – 彬彬的博客 – 博客园.

但是在实际应用开发中,通常横屏(land)与竖屏(port)布局文件有所不同,这时候我们可以独自定义横屏与竖屏的布局文件( 文件名字要一样),默认情况是加载layout目录里的布局文件。同样应用还要支持不同的语言,如果我们应用里没有定义手机所用语言的资源时,会默认加载 values的值。

要使程序适应布局,则需要添加以下两个目录:layout-land 和 layout-port ,系统在进行改变的时候,将会根据这两个现在的屏幕的横竖分别读取这两种不同的布局方式,如果这当前的不存在,则会根据layout中的布局进行布局。

下面是我的的三个布局:

layout:

代码

<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent"> <TextView android:layout_width="fill_parent" android:id="@+id/text1" android:layout_height="wrap_content" android:text="@string/hello" /> <Button android:id="@+id/btn1" android:text="坚" android:layout_width="fill_parent" android:layout_height="wrap_content"> </Button> <Button android:id="@+id/btn2" android:text="横" android:layout_width="fill_parent" android:layout_height="wrap_content"> </Button> </LinearLayout>

layout-land:

代码

<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent"> <TextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="横屏显示" /> <TextView android:layout_width="fill_parent" android:id="@+id/text1" android:layout_height="wrap_content" android:text="@string/hello" /> <Button android:id="@+id/btn1" android:text="横" android:layout_width="fill_parent" android:layout_height="wrap_content"> </Button> <Button android:id="@+id/btn2" android:text="竖" android:layout_width="fill_parent" android:layout_height="wrap_content"> </Button> </LinearLayout>

显示效果:

layout-port:

代码

<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent"> <TextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="坚屏显示" /> <TextView android:layout_width="fill_parent" android:id="@+id/text1" android:layout_height="wrap_content" android:text="@string/hello" /> <Button android:id="@+id/btn1" android:text="横" android:layout_width="fill_parent" android:layout_height="wrap_content"> </Button> <Button android:id="@+id/btn2" android:text="竖" android:layout_width="fill_parent" android:layout_height="wrap_content"> </Button> </LinearLayout>

显示效果:

下面是对内容的显示进行的国际化:

需要添加以下目录:

values-zh-rCN 此下面放置的是显示中文内容的

values-zh-rTW 此下显示繁体中文

values-jp  显示日文

一般形式为:values-国家编号

这些显示将根据操作系统的语言进行读取,如果不存在相应的语言版本,将会直接获取values中的内容:

在此中,只对中文进行了设置

values中的内容如下:

<?xml version="1.0" encoding="utf-8"?> <resources> <string name="hello">Hello World, ShowTask!</string> <string name="app_name">ShowTask</string> </resources>

values-zh-rCN 中的内容如下:

<?xml version="1.0" encoding="utf-8"?> <resources> <string name="hello">此程序用于显示任务!</string> <string name="app_name">显示任务</string> </resources>

显示效果如下:

参考文章:

http://www.android123.com.cn/androidkaifa/206.html

[转载]新年快乐,介绍个简单的Excel理财工作的制作方法

mikel阅读(756)

[转载]新年快乐,介绍个简单的Excel理财工作的制作方法 – Killmyday – 博客园.

最近物价飞涨,得给钱找个保值的地方,朋友给我推荐了一个不错的楼盘投资保值,实 在不行自住也很舒服。这么一大笔的投资,为了验证一下保值的潜力,当然需要慎之又慎,小心的不能再小心。作决定前自然要估计一下收益如何,这种纷繁复杂的 计算,虽然每一步都是很简单的运算,但是很多步串起来,就有点顾此失彼了。因此就想到用Excel自己做一个分析工具,省去自己编程的麻烦,可能你也有类似的需求,就把制作方法介绍如下。

设计的目标:

1. 用户需要输入房子的单价、面积以及购买时间。

2. 用户需要输入首付和公积金贷款的总额,程序能够计算出每个月的还贷的压力。

3. 用户输入预计房子的出售时间以及出售时每平的单价,程序能够根据出售时间和单价的变化,计算出总利润和均摊到每个月的利润。

4. 最后,用户可以修改一些其他参数,例如商业贷款利率,公积金贷款利率,还款年限,出售房屋的手续费等。

自动计算利润的表格如下所示(可以通过修改第一列的每平售价和第一行的出售时间来分析盈亏):

制作步骤:

1. 分析每月还贷压力,表格截图如下:

其中C2D2分别是允许用户输入的购买单价和房屋面积,E2是购买时间—留着做出售时获利分析。

房屋的总价B2就是简单的:=C2 * D2

因为公积金贷款各地都有政策,而且都有贷款上限,所以我在D7这个单元格输入了公积金的贷款上限,逻辑是,能从公积金贷就从公积金贷,如果不能贷,就把D7这个值设置为0好了。

B7里,就是(房屋总价首付)和公积金贷款上限的最小值—如果公积金贷款能全部搞定,为什么要贷商业贷款呢?因此B7的公式就是:=MIN($D$7, $B$2-$B$5)

商业贷款B6的值就是剩下要贷款的总额了:=IF(B2-B5-B7>0, B2-B5-B7,0)

Excel自己带了等额本息还款方式的计算每月还贷的公式PMTPMT函数接受3个参数:

1) 第一个参数是月利率,比如说你的贷款年利率是5.22%的话,那月利率就是5.22%除以12

2) 第二个参数是还款周期,以月份计算,即如果你的贷款是20年的话,那就应该是240 = 20 * 12

3) 第三个参数是贷款的总额。

因此B10每个月商业贷款的还款是:=PMT($B$3/12, $B$8*12, $B$6)

B9每个月公积金贷款的汇款是:=IF($B$7=0, 0, PMT($B$4/12, $B$8*12, $B$7))

还款总额就是将每个月的固定的还款乘以还款周期,例如B13的商业贷款总额是:=$B$10 * $B$8*12

2. 根据指定的出售时间和价格,计算利润,表格截图如下:

根据最近出台的房屋出售营业税规定,如果是购买5年之内的住宅出售所得,需要交纳房价差额(卖价与买价的差额)的5.55%作为营业税,如果房子是5年以上的,则免交营业税。

第一步先计算出出售时间和购买时间的时差,Excel提供了一个函数,YEARFRAC就是用来计算两个时间间隔的年份的。因此D21的公式是:=YEARFRAC(E2, E19, 3)*12。即出售时间减去购买时间的年份乘以12—我使用月份来表示,是因为在按出售时间分析利润时,公式编写会方便一些。

出售房屋时,包括几个成本:当初的首付成本—B5,已还的贷款以及提前还贷需要还得本金。在等额本息还款方法里,前面月份还的钱大部分都是利息—不是本金,换句话说,已还贷款里大部分都是要交给银行的利息,所以提前还贷还不是简单的预计贷款还款总额减去已还的贷款。

Excel提供了一个函数,CUMPRINC可以用来计算在指定的还款次数后,总共还贷的本金额度,用法跟PMT类似。因此,实际缴纳商业贷款本金B23的公式是:=CUMPRINC(B3/12, B8*12, B6, 1,D21+1,1)

最后实际出售所得B26 实际成本B25就是我们的利润B27了。

3. 变动出售时间和价格,分析利润,表格截图如下:

设置B29的公式为:=B27,一定要指定公式,不要指定值,否则Excel无法从公式链表里,使用参数表个里面的值替换匹配公式的单元格。

C29E29(当然Z29也可以—如果你觉得有必要分析这么长的时间的话)这一行设置要分析的出售时间。

B30B42这一列设置要分析的出售单价。

选中B29E42这一个范围,点击菜单里的“数据”-> What-if分析”->“数据表”:

在弹出的对话框里:

l 设置行输入单元格(Row input cell)为E19,即我们在第二步计算中使用的出售时间。

l 设置列输入单元格(Column input cell)为C19,即我们在第二步计算中使用的出售单价。

最后就可以看到随着出售时间和单价的变化,总利润的变化了。

好啦,当前物价飞涨,跑不过刘翔,也要争取跑过CPI呀。新年快乐,恭喜发财,附送一个简单的小程序,示例文件下载:/Files/killmyday/Excel_Sample.zip

[转载]InfoQ: Silverlight 之轻

mikel阅读(949)

[转载]InfoQ: Silverlight 之轻.

【编者按】在企业应用的前端开发中,Ajax、Flash和Silverlight争奇斗艳,各有千秋。这次InfoQ中文站有幸邀请到来自中国人寿的Silverlight专家吴磊先生,为读者分享他的Silverlight在企业应用开发中的丰富经验。

就在笔者写下本文的当天,第二届Silverlight Firestarter 发布会在美国召开,微软企业副总裁 Scott Guthrie 发布了Silverlight 5 的一系列新特性,并宣布Silverlight 5 将注重丰富的媒体体验与企业应用开发两大方面的改进。其中针对媒体方面的改进包括GPU硬解码、H.264等5项功能,而针对企业应用方面的改进包括64 位操作系统支持、IE 9硬件加速、向量打印、文本清晰度、调用非托管代码等30多项功能,可以看出Silverlight已经逐渐将其未来重心转向企业级应用方面(一直以来, 笔者都认为Silverlight的强项应该是企业应用)。

Silverlight作为微软“三屏一云”战略中展现层的重要技术,越来越引起企业开发者的注意。新浪财经、腾讯、淘宝、口碑网等互联网企业已经 尝试使用Silverlight开发交互性较强的商业应用,而一贯谨慎保守的大型金融公司陆续开始使用Silverlight来提高企业应用的用户体验, 比如中国人寿(网上服务应用)、中国人保(商务智能应用)已经有相关应用,而像花旗银行、工商银行这样的大型银行也在尝试使用Silverlight来实 现未来网上银行一些功能。

为什么Silverlight在推出短短三年左右时间内就能触动企业开发者呢?原因很简单,Silverlight具有良好的后台语言框架支持,这就是基于.Net高级语言的精简运行环境。具体而言原因有三:

  1. Silverlight之轻,即较之WPF、Java Swing、Delphi等C\S架构有更加轻量的运行环境与零维护的特点:使用轻量的CLR Core运行时环境,不依赖于客户端环境(无须安装体积庞大的.Net Framework,这一点太棒了)。
  2. Silverlight之重,即较之Html+JavaScript等B/S架构有更优越的客户端弹性:使用C#高级语言代替 JavaScript来实现强大的客户端计算能力、支持多线程,继承了WPF丰富的样式、控件、特效与动画,更可控的浏览器适应性,更安全的沙箱模式,客 户端嵌入式数据库等。
  3. Silverlight之美,即较之传统应用有更友好的交互性,更酷的效果。支持完全面向用户体验的开发过程,其快速原型工具使需求与交付物更为明确,用户体验驱动开发,设计与编码分离。

在本文中,笔者要着重强调的是“Silverlight之轻!”, Silverlight是企业应用展现层的轻量级解决方案,从本文开始,笔者将采用连载的方式与大家一起探讨Silverlight在企业级应用解决方案与特性。

现在越来越多的企业已经开始考虑将原有“竖井状”的C/S与B/S架构通过SOA等理念进行重构与集成,譬如建立以客户、产品、合同为中心的主数据 管理平台(MDM),采用数据即服务的方式对逻辑层提供服务,使用企业服务总线(ESB)对这些服务进行消息路由、转换、监控及生命期管理,通过业务流程 管理平台(BPM)混编服务实现业务流程自动化,通过业务规则管理平台(BRM)实现对业务逻辑自动化,最后这些应用层服务形成了企业应用的服务器端处理 逻辑。而展现层就是企业应用中实现人机交互的最后一步,即信息的输入与展现。现在的企业应用解决方案中基于窗体的C/S与基于浏览器的B/S架构几乎构成 了企业应用的全部,但两者都有其优缺点,C/S架构在客户端的处理能力与交互性较强,但维护性极差;相反,B/S架构在客户端的维护性极高,但对信息的处 理能力、交互性、跨浏览器一致性方面都有不足。正是如此,相对C/S架构更为轻型的Silverlight技术就成为了未来高度集成化的企业应用中理想的 展现层的候选方案。传统的C/S架构,无论是VC++、Delphi、Java的Swing、还是.Net的WinForm、WPF都需要安装体积笨重的 运行时环境,即使客户端程序永远不会使用运行环境中的特殊组件,但使用者也只能被动接受这些组件占用计算机资源。而Silverlight有着更为轻便的 运行式环境(Silverlight3的运行时环境4.3M,Silverlight4为6M),在如此小的运行环境下面有着B/S无法比拟的高级语言支 持,也就是说Silverlight具有一颗.Net的心脏—CoreCLR。

CoreCLR简单来说就是CLR for Silverlight,是专门为Silverlight量身打造的轻型CLR,用来执行Silverlight代码。Silverlight基于C#高 级语言,使用同样的托管机制与MSIL中间语言,CoreCLR自备编译环境、内存管理器,不依赖于外部环境。打造这个轻型“心脏”的过程并不容易,对于 轻型的RIA框架来说Silverlight运行时环境要考虑两大问题:大小与兼容性。

大小就是运行时环境的大小,从用户的角度来看,下载必须非常小。这就要求将功能集减至最少,目前 Silverlight4运行时环境大小为6M,CoreCLR中的DLL文件在CLR和WPF的类库中几乎都能找到,只不过大大裁剪了尺寸。这其中就包 括对基类库(BCL)的消减,.Net BCL中的很多功能在 Web 客户端上都没有任何意义,例如:由于 Silverlight 不支持 CAS,因此大部分 System.Security 都不是必要的,System.Console 等许多桌面类在 Web 中也没有任何意义。因此,CoreCLR删减了大量服务器端类库(如ADO.NET),去除非泛型集合类(如ArrayList,完全可以通过泛型集合类 代替),同时将复杂的桌面类也一并去除(如PLINQ和一些动态类),但保留了.NET Compact Framework 和 Silverlight 间的兼容性。

对于兼容性而言,从编程人员的角度来看,针对 CLR 的编码应该始终相同。因此,Silverlight堆栈底部的各个组件使用了与桌面CLR相同的代码,执行引擎和虚拟机都必须相同,这部件包括类型系统、 元数据、垃圾回收器 (GC)、JIT 编译器、线程池以及运行时引擎的其他核心部件。但为了适应 Web 应用程序,CoreCLR进行了一些更改,如富 Internet 应用程序通常简单且运行时间短,JIT 编译器主要侧重于减少启动时间,而非执行更复杂的优化操作,同样,服务器垃圾回收模式可以对使用相似分配模式的多个工作线程进行优化,而对 Web 托管应用程序则行不通,因此,Silverlight 只包含针对交互式应用程序进行优化的标准工作站 GC。

现在的.NET Framework里有一万个类,十万个方法,但CoreCLR中减少到了46个命名空间下不超过一千个类。

C#之父(同时也是Turbo Pascal与Delphi之父)Anders Hejlsberg认为未来编程语言的发展趋势及未来方向应该朝着框架与工具发展。笔者认为未来的语言发展方向不是朝着大而全的运行时框架方向发展,而是 朝着“轻框架、重工具组件”的方向发展。当我们使用Visual Studio开发应用程序时,我们首先选择的是“语言”,然后是“运行时框架”,再引入我们需要的“工具组件”。而精干的“运行时框架”与丰富的可选“工 具组件”将为企业应用提供更大的弹性、减轻程序大小、优化响应性能。

事实上,目前很多金融企业的核心应用已经在朝着“去客户化”、“去产品化”的小核心方向发展,“小核心”+“大外围”使企业内部核心具有更加持久的 生命力、更加灵活的扩展性和更快的反应能力。而企业应用展现层也越来越青睐于使用小而灵活的运行时环境,开发者完全可以根据实际需求挑选合适的工具组件, 提供更富弹性的展现层应用。Silverlight的未来应该更加关注适用性,而不应该过度考虑基本功能的强大,否则将发展成为另一个WPF,而失去自己 的方向。Silverlight4将Silverlight3的身躯加大了1.7M,加入了一些诸如集合接口ISet<T>、延迟初始化类 Lazy<T>、元组对象工厂类Tuple等复杂类型,加重了Silverlight内核。因此,在Silverlight5的Wish List中,笔者强烈要求Silverlight5关注解决跨设备的问题,而不要过度考虑加重基础类库的强大功能,加重Silverlight的包袱,使 原本轻便的Silverlight CoreCLR变得更加臃肿,无法起飞。

“对于未来,希望Silverlight仍能轻舞飞扬!”

注:部分内容取材于笔者即将发布的新书《-企业级RIA应用与Silverlight开发全流程实战》,敬请关注。

关于作者

吴磊,中国人寿IT高级技术主管、高级工程师,拥有7年企业级应用开发经验,负责过多个业务系统的开发工作。曾获得系统分析师、 PMP等认证,2003年开始接触RIA技术,并不遗余力的在企业应用中推广RIA技术, 2008年带领团队成功研发了国内首个Silverlight企业级应用—中国人寿养老金咨询系统 (PACS),该项目先后在 Silverlight3 发布会、Teched09 技术大会、QCON2010全球企业开发大会上作为成功案例进行展示。

[转载]SilverLight搭建WCF聊天室详细过程

mikel阅读(1165)

[转载]SilverLight搭建WCF聊天室详细过程 – 邪之灵 – 博客园.

后话:写了几篇文章后根据大家提的意见,我以后会尽量少贴代码,多帖流程图,并且以后会加上文字讲解流程图,前几篇有时间我会添加上流程图讲解,以及思路,让初学者更好理解,谢谢大家的支持!

SilverLight 4正式版发布给开发人员带来了更多功能,并且4已经支持NET.TCP协议,配合WCF开发高效率的交互应用程序已经不再是难事,本系列文章主要针对已经 完成的SilverLight聊天室分几部分为大家演示WCF双工服务调用。

项目主要使用SilverLight 4和WCF,开发环境VS2010,使用NET.TCP协议,主要实现了以下功能,先前版本源代码下载可以进群45656086,已经放到群共享里了,如 果此文章对各位朋友有帮助,请劳烦点个推荐或者留言,你们的支持才是我更新下去的动力,谢谢大家,我是营长,有问题大家可以提问:

1.多窗口聊天,窗口可拖动

2.用户分组动态显示

3.仿windows任务栏显示当前聊天用户

4.文本消息发送

5.发送图片,并且可放大

6.大文件,多文件同时发送

7.视频,语音并且可以保存

本系列随笔列表:

1.SilverLight搭建WCF聊天室详细过程(一)配置IIS

2.SilverLight搭建WCF聊天室详细过程(二)注册和登录

3.SilverLight搭建WCF聊天室详细过程(三)好友列表之 Accordion滑动分组动态绑定

4.SilverLight搭建WCF聊天室详细过程(四)好友上线

5.SilverLight搭建WCF聊天室详细过程(五)好友下线

6.SilverLight搭建WCF聊天室详细过程(六)打开聊天窗口

7.SilverLight搭建WCF聊天室详细过程(七)打开窗口后添加到任务栏

8.SilverLight搭建WCF聊天室详细过程(八)发送文本消息

9.SilverLight搭建WCF聊天室详细过程(九)接收文本消息

10.SilverLight搭建WCF聊天室详细过程(十)接收离线消息

11.SilverLight搭建WCF聊天室详细过程(十一)发送图片

12.SilverLight搭建WCF聊天室详细过程(十二)接收图片

13.SilverLight搭建WCF聊天室详细过程(十三)发送文件邀请

14.SilverLight搭建WCF聊天室详细过程(十四)发送文件

15.SilverLight搭建WCF聊天室详细过程(十五)接收文件

16.SilverLight搭建WCF聊天室详细过程(十六)仿QQ消息提醒

17.SilverLight搭建WCF聊天室详细过程(十七)新用户注册并刷新所有在线好友列表

18.SilverLight搭建WCF聊天室详细过程(十八)视频

19.SilverLight搭建WCF聊天室详细过程(十九)WCF服务端变量以及对象设计思路

未完待续..

[转载]轻松建立Silverlight开发环境

mikel阅读(940)

创建Silverlight 4开发环境,微软提供最简单的方法是使用Web Platform Installer,进行“一键安装”,

下载安装后,Web Platform Installer会自动检测哪些软件你已经安装

silverlightchina.net

silverlightchina.net
silverlightchina.net
如果需要安装新的Developer Tools,只需要选中该项目,下面“Install”按钮会提示安装下一步。
通常来说,Silverlight 4 的开发环境需要包含以下几个开发工具:
1. Visual Studio 2010或者Visual Web Developer 2010 Express ,在安装过程中,.Net Framework 4会同时被安装,另外,也可以单独下载.Net Framework 4安装;
2. 安装完开发工具后,需要下载安装Silverlight 4 Tools for Visual Studio 2010开发包。下载链接:Silverlight 4 Tools for Visual Studio 2010; 安装完成后,在Visual Studio 2010中将会自动更新添加Silverlight 4项目开发模板,以及Silverlight 4 SDK和相关开发环境. 以下是该开发包中包含的内容:

  • Silverlight 4 developer runtime
  • Silverlight 4 SDK (software development kit)
  • Update for Visual Studio 2010 and Visual Web Developer Express 2010 (KB982218)
  • Silverlight 4 Tools for Visual Studio 2010
  • WCF RIA Services V1.0 for Silverlight 4
  • F# Runtime for Silverlight 4

3. 针对Silverlight美工开发人员,需要下载Expression Studio 4,因为只有Blend 4支持Silverlight 4项目开发,另外Blend 4和Visual Studio 2010是无缝结合,使用Blend 4可以很轻松的创建和修改自定义控件样式,开发专业的Silverlight项目界面。
4. 最后推荐安装Silverlight 4 Toolkit控件包,该控件是微软开发的Silverlight控件扩展包.其中包含数十种扩展控件,可以方便Silverlight项目开发,另外该项目是开源项目,开发人员可以轻松的修改控件,创建自定义控件效果。
安装完成以上工具,Silverlight 4的开发环境已经创建完毕,如果是使用Web Platform Installer,可以选择以上相关选项进行一键安装,就可以开发Silverlight 4项目了。
另外微软已经推出Silverlight 4简体中文正式版脱机帮助文档,该文档包含Silverlight 4所有的技术知识,是开发人员必备资料,推荐下载。
Microsoft Silverlight 4 脱机文档 (简体中文)
http://www.microsoft.com/downloads/details.aspx?displaylang=zh-cn&FamilyID=b6127b9b-968c-46c2-8cb6-d228e017ad74

Microsoft Silverlight 4 在线帮助文档(MSDN)(简体中文)
http://msdn.microsoft.com/zh-cn/library/cc838158(vs.95).aspx

以下是基于Visual Studio 2008的Silverlight 3开发环境创建.

建立Silverlight 3开发环境分以下四个步骤:

1. 首先需要安装开发工具,对于Silverlight 3项目开发,必须使用 Visual Studio 2008 SP1 或者 Visual Web Developer Express with SP1 作为开发工具。在安装过程中,.Net Framework 3.5 sp1同时被安装,如果没有安装.Net Framwork 3.5 sp1需要独立下载安装。

2. 安装开发工具后,需要下载安装Silverlight工具开发包. 点击下载: Silverlight 2 Tools for Visual Studio 2008 SP1 或者 Silverlight 3 Tools for Visual Studio 2008 SP1, 完成Silverlight开发包安装后,Visual Studio 2008中将自动更新添加Silverlight项目开发模板,以及Silverlight SDK和相关开发环境.

3. 针对Silverlight 3项目,用户界面设计人员来讲,还需要安装Microsoft Expression Blend 3 . Blend是Expression配套软件,可以让界面设计人员很轻松的开发出专业的Silverlight用户界面.

4. 最后,需要下载Silverlight Toolkit. 该控件是微软开发的Silverlight控件扩展包.

完成以上安装后,即可进行Silverlight开发了.

请注意,Silverlight开发环境对于语言环境要求比较严格,在中文开发环境中,不能安装英文版本的Silverlight开发包。

最新Silverlight 3 英文开发包下载:  http://silverlightchina.net/html/download/books/2009/0710/56.html

最新Silverlight 3 中文开发包下载: http://silverlightchina.net/html/download/2009/0730/132.html

[转载]Silverlight MMORPG网页游戏开发课程(Game Lesson):目录

mikel阅读(946)

[转载]Silverlight MMORPG网页游戏开发课程(Game Lesson):目录 – 深蓝色右手 – 博客园.

一 次全新的开始,一次全新的构建与诠释。渴望在时空长廊中寻觅传说中光的起源,我决定用这部课程编写一首血脉喷张之进行曲。一年前,我一个人在战斗,前行, 引导我绝不放弃的是那遥远而飘渺的微米月光,循着光的足迹至今天,为这股越发坚定的力量所吸附更多的光无惧黑暗的吞噬,穿越,直至大地!何以扶平我此刻宽 慰的心?交织着英雄与自由主义那勇往直前之无尚银光。

有朋友认为这次的课程毫无新意,其实不然。如果你选择仔细阅读每个角落,或许你收获的东西比我第一部教程给 得更多且更实用。依旧是一节接一节循序渐进的模式推进着整个章节,对于有Silverlight基础的朋友可以说不存在任何难点。不要被“游戏开发”这几 个大字所吓到,既然你选择来到这个世界上,就一定要比前人活得更坚强且更有价值!理想的实现与每每朝着理想的方向迈出那么一小步都将成为你毕生的骄傲!或 许真该畏惧的是我,发自心底的害怕那些无法坚持,浮躁,热衷一步登天之徒。

整系列课程将分成两部份讲解,第一期主要实现Silverlight MMORPG的客户端部分主体功能;第二期则主要讲述Silverlight MMORPG服务器模块(通信编程)。

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

另外,这是一份最初静态版的课程Demo源码同样提供给大家参考。

友情提示:本系列课程完全为本人原创,本人享有示例源码的所有权并与博客园共同享有该教程版权,请在本人许可的前提下进行相关使用,否则保留追究法律责任的权利。另外,课程中所有素材均来源于网络,切勿用作商业用途,否则后果自负

本系列课程目录如下:

[一 期]

Silverlight MMORPG网页游戏开发课程[一期] 序言

Silverlight MMORPG网页游戏开发课程[一期] 第一课:控制对象移动 [源码 1.1 1.2 1.3] [视频 1.1 1.2]

Silverlight MMORPG网页游戏开发课程[一期] 第二课:完美2D精灵 [源码 2.1 2.2]

Silverlight MMORPG网页游戏开发课程[一期] 第三课:封装游戏控件[源码 3.1 3.2]

Silverlight MMORPG网页游戏开发课程[一期] 第四课:资源布局之动静结合 [源码 4.1 4.2 4.3]

Silverlight MMORPG网页游戏开发课程[一期] 第五课:GPU硬件加速与OOB模式 [源码 5.1]

Silverlight MMORPG网页游戏开发课程[一期] 第六课:场景之地图与遮挡 [源码 6.1 6.2]

Silverlight MMORPG网页游戏开发课程[一期] 第七课:场景之地形与寻径 [源码 7.1 7.2 地图编辑器 场景编辑器]

Silverlight MMORPG网页游戏开发课程[一期] 第八课:场景之切换与动画效果 [源码 8.1]

Silverlight MMORPG网页游戏开发课程[一期] 第九课:HUD与背景音乐 [源码 9.1]

Silverlight MMORPG网页游戏开发课程[一期] 第十课:面向对象的重构 [源码 10.1]

Silverlight MMORPG网页游戏开发课程[一期] 第十一课:战斗系统之脚本与精灵捕获 [源码 11.1]

Silverlight MMORPG网页游戏开发课程[一期] 第十二课:战斗系统之普通攻击 [源码 12.1]

Silverlight MMORPG网页游戏开发课程[一期] 第十三课:战斗系统之技能/魔法攻击 [源码 13.1]

Silverlight MMORPG网页游戏开发课程[一期] 第十四课:完结篇 [源码 14.1]

[二 期]

放思绪先飞一会儿吧,敬请期待……

友情招聘:中游在线[北京]招聘Silverlight游戏开发者,盛情期待您的加入!

具体要求:

理解面向对象的编程思想、设计模式;

熟悉使用基于C#语言基础及常用库的开发;

熟练下述任一开发环境,Visual Studio,Microsoft Expression Studio;

对Silverlight开发非常有兴趣;

有责任心,学习、沟通和团队合作必不可少,能适应较强的工作压力;

简历附有作品或项目介绍,提供演示程序或截图;

待遇面议,用您的潜力见证您的价值!

联系方式:http://nxria.com/contact.html

[转载]ASP.NET MVC:创建 ModelBinder 自动 Trim 所有字符串

mikel阅读(992)

[转载]ASP.NET MVC:创建 ModelBinder 自动 Trim 所有字符串 – 鹤冲天 – 博客园.

用户输入的字符串前后的空格会对程序造成很大的危害,最常见的问题就是查询和统计错误。作为严谨的开发人员,我们应该主动进行处理。

逐个 Trim 相当麻烦

.NET 中为我们提供了三个字符串处理函数,相信大家一定都用过:Trim、TrimStart、TrimEnd。

但在实际应用中,逐个 Trim 是相当麻烦的。我们来分析下,请看如下 Controller 及其 Model:

public class PersonController : Controller
{
    public ActionResult Query(string name)
    {
        //...
    }
    //...
    [HttpPost]
    public ActionResult Create(Person person)
    {
        //...
    }
    [HttpPost]
    public ActionResult Create2(FormCollection collection) 
    { 
        Person person = new Person();
	UpdateModel(person, collection);
        //...
    }
    //...
}

public class Person
{
    public int ID { get; set; }
    public string Name { get; set; }
}

需要进行 Trim 的大致有以下三种:

  1. Action 中的字符串参数,如 Query 方法中的 name 参数。
  2. Action 中的复杂类型参数的字符串属性,如 Create 方法中的 person 的 Name 属性。
  3. Action 中显式绑定的复杂类型的字符串属性,如 Create2 方法中的 person 的 Name 属性。

如果 Model 更复杂:

public class Person
{
    public int ID { get; set; }
    public string Name { get; set; }
    public string[] Hobbies { get; set; }
    public Person Father { get; set; }
}

还需要对 Hobbies 和 Father.Name 进行处理…

但在 MVC 中可以通过 ModelBinder 来轻松解决。

使用 ModelBinder 来解决 Trim 问题

使用 ModelBinder 来解决 Trim 问题,有 N 多种方式,本文介绍最简单的一种,只需要以下两步:

1. 创建一个有 Trim 功能的 ModelBinder(仅用于 string 类型):

public class StringTrimModelBinder : DefaultModelBinder
{
    public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        var value = base.BindModel(controllerContext, bindingContext);
        if (value is string) return (value as string).Trim();
        return value;
    }
}

简单吧,就三行代码(其实还可以再精简)。

2. 在 Global.asax 中为 string 类型指定这个 ModelBinder:

public class MvcApplication : System.Web.HttpApplication
{
    protected void Application_Start()
    {
        ModelBinders.Binders.Add(typeof(string), new StringTrimModelBinder());
        //...
    }
    //...
}

根据 MVC 的绑定机制,所有的字符串绑定都将会使用 StringTrimModelBinder。

也就是说,我们前面应用场景中提到的各种类型字符串都可以自动 Trim 了,包括 person.Name、 person.Hobbies 和 person.Father.Name。

OK!简单吧,这完全得益于 MVC 优秀的设计和架构。

[转载]ASP.NET MVC中的扩展点(四)过滤器

mikel阅读(1006)

[转载]MVC中的扩展点(四)过滤器 – xfrog – 博客园.

过滤器是一组.NET特性,MVC在特定运行时点调用这些特性上的指定方法,以此实现功能注入。MVC包含四个基本的过滤器类型:授权 (Authorization)、活动(Action)、结果(Result)以及异常(Exception)。MVC为这四中过滤器提供了接口定 义:IAuzhorizationFilter、IActionFilter、IResultFilter、IExceptionFilter,所以 MVC在运行时知道如何调用过滤器上的方法。
MVC实现的默认过滤器如以下类图所示:

FiltersClass
注意上图中Controller实现了四个基本的过滤器接口,所以在我们的控制器中,可直接重写过滤器方法来实现过滤器功能,此种方式适用于过滤器功能特定于控制器的情景,如果过滤器功能会跨多个控制器使用,那么使用特性的方式可避免重复代码。

各种默认过滤器,都直接或间接的继承于FilterAttribute类,FilterAttribute有一个Order属性,用于过滤器的排序。另 外,MVC为Action过滤器和Result过滤器提供了一个抽象基类ActionFilterAttribute,它同时实现了 IActionFilter和IResultFilter接口。

过滤器的执行过程由控制器的ActionInvoker对象实现,他是一个实现了IActionInvoker接口的类,ActionInvoker是控 制器的一个公共属性,所以我们可以实现自己的IActionInvoker类,然后通过设定Controller的ActionInvoker属性来指定 自定义的Invoker。MVC中默认的ActionInvoker类为ControllerActionInvoker,其执行过滤器列表的过程如下图 所示:
Filters
上图表示的是过滤器在没有发生任何异常时的执行顺序:获取过滤器列表——>依次调用按Order排序的授权过滤器,如果某个授权过滤器设置了 AuthorizationContext参数的Result属性,则立即终止剩余授权过滤器的调用,直接执行Result,生成页面应答内容。如果所有 授权过滤器都通过,并且Result为空,则继续调用Action过滤器上的OnActionExecuting方法,如果全部通过,将执行控制器上相应 的Action方法获取ActionResult对象,随后再按相反顺序执行Action过滤器上的OnActionExecuted方法,之后转入到 Result过滤器列表中,同Action类似,先按Order顺序执行OnResutExecuting方法,注意在 OnResultExecuting方法上,过滤器可通过将ResultExecutingContext.Cancel属性设置为True来立即终止 Invoker的执行(即不会执行ActionResult及Result过滤器上的OnResultExecuted方法),如果所有的 OnResultExecuting方法都通过,则通过ActionResult.ExecuteResult方法生成应答内容,最后再按相反顺序调用 Result过滤器上的OnResultExecuted方法。

对于ControllerActionInvoker类在执行过程中产生的异常,会传给Exception过滤器(MVC默认的异常处理过滤器为 HandleErrorAttribute)来处理。在ControllerActionInvoker的各个节点产生的异常会影响到过滤器的执行过程, 下面分几种情况来详细了解:

我们假设某个Action上有A、B两个授权过滤器,有A、B、C三个Action过滤器和Result过滤器以及A、B两个异常过滤器,首先,在没有异常发生时得执行过程如下图:A、B两个异常过滤器未执行,其余所有过滤器都执行

NoneException

如果在B.OnAuthorization上发生异常,会直接转到异常过滤器上,其余Action过滤器、Result过滤器及Action方法都不会调用:

AuthorizeException

如果在B.OnActionExecuting上发生异常,则会跳转到Action过滤器列表的上一个过滤器(即A),执行A.OnActionExecuted,然后转到异常过滤器:

ActionExecutingException

如果在B.OnActionExecuting上发生异常,但是在A.OnActionExecuted中将ActionExecutedContext.ExceptionHandled设置为true,此时将会继续执行Result过滤器,并忽略异常过滤器:

ActionExecuted.ExceptionHandled

如果在执行控制器的Action方法时发生异常,将会继续执行ActionExecuted方法,随后转到异常过滤器:

ControllerActionException

如果在Action的OnActionExecuted方法上发生异常,将会继续执行完Action过滤器,然后转到异常过滤器:

ActionExecutedException

在Result过滤器上的OnResultExecuting方法和OnResultExecuted方法上发生异常,其处理方式与Action过滤器类似,此处不再详细说明。

如果在Result过滤器OnResultExecuting中将ResultExecutingContext的Cancel属性设置为true,将立即完成Action方法执行:

ResultExecuting.Cancel

另外需要注意,在异常过滤器中将ExceptionContext.ExceptionHandled设置为true并不会终止异常过滤器的执行,该属性 仅仅用于标记“异常已被处理”。所以我们可以通过异常过滤器来实现错误日志记录功能,无需担心漏掉”已被处理”的异常。

如果我们要实现自定义的权限验证功能,应该从AuthorizeAttribute类继承,原因在于AuthorizeAttribute已经优化了与OutputCacheAttribute缓存过滤器的协调,避免因缓存原因造成权限验证失效的情况。

[转载]A*寻路初探 GameDev.net

mikel阅读(1032)

[转载]A*寻路初探 GameDev.net – GameRes.com.

A*寻路初探 GameDev.net

译者序:很久以前就知道了A*算法,但是从未认真读过相关的文章,也没有看过代码,只是脑子里有个模糊的概念。这次决定从头开始,研究一下这个被人推崇备至的简单方法,作为学习人工智能的开始。
这 篇文章非常知名,国内应该有不少人翻译过它,我没有查找,觉得翻译本身也是对自身英文水平的锻炼。经过努力,终于完成了文档,也明白的A*算法的原理。毫 无疑问,作者用形象的描述,简洁诙谐的语言由浅入深的讲述了这一神奇的算法,相信每个读过的人都会对此有所认识(如果没有,那就是偶的翻译太差了 –b)。
原文链接:http://www.gamedev.net/reference/articles/article2003.asp
以下是翻译的正文。(由于本人使用ultraedit编辑,所以没有对原文中的各种链接加以处理(除了图表),也是为了避免未经许可链接的嫌疑,有兴趣的读者可以参考原文。

会者不难,A*(念作A星)算法对初学者来说的确有些难度。

这篇文章并不试图对这个话题作权威的陈述。取而代之的是,它只是描述算法的原理,使你可以在进一步的阅读中理解其他相关的资料。

最后,这篇文章没有程序细节。你尽可以用任意的计算机程序语言实现它。如你所愿,我在文章的末尾包含了一个指向例子程序的链接。 压缩包包括C++和Blitz Basic两个语言的版本,如果你只是想看看它的运行效果,里面还包含了可执行文件。

我们正在提高自己。让我们从头开始。。。

序:搜索区域

假设有人想从A点移动到一墙之隔的B点,如下图,绿色的是起点A,红色是终点B,蓝色方块是中间的墙。


[图1]

你 首先注意到,搜索区域被我们划分成了方形网格。像这样,简化搜索区域,是寻路的第一步。这一方法把搜索区域简化成了一个二维数组。数组的每一个元素是网格 的一个方块,方块被标记为可通过的和不可通过的。路径被描述为从A到B我们经过的方块的集合。一旦路径被找到,我们的人就从一个方格的中心走向另一个,直 到到达目的地。

这些中点被称为“节点”。当你阅读其他的寻路资料 时,你将经常会看到人们讨论节点。为什么不把他们描述为方格呢?因为有可能你的路径被分割成其他不是方格的结构。他们完全可以是矩形,六角形,或者其他任 意形状。节点能够被放置在形状的任意位置-可以在中心,或者沿着边界,或其他什么地方。我们使用这种系统,无论如何,因为它是最简单的。

开始搜索

正如我们处理上图网格的方法,一旦搜索区域被转化为容易处理的节点,下一步就是去引导一次找到最短路径的搜索。在A*寻路算法中,我们通过从点A开始,检查相邻方格的方式,向外扩展直到找到目标。

我们做如下操作开始搜索:


1,从点A开始,并且把它作为待处理点存入一个“开启列表”。开启列表就像一张购物清单。尽管现在列表里只有一个元素,但以后就会多起来。你的路径可能会通过它包含的方格,也可能不会。基本上,这是一个待检查方格的列表。
2,寻找起点周围所有可到达或者可通过的方格,跳过有墙,水,或其他无法通过地形的方格。也把他们加入开启列表。为所有这些方格保存点A作为“父方格”。当我们想描述路径的时候,父方格的资料是十分重要的。后面会解释它的具体用途。
3,从开启列表中删除点A,把它加入到一个“关闭列表”,列表中保存所有不需要再次检查的方格。

在这一点,你应该形成如图的结构。在图中,暗绿色方格是你起始方格的中心。它被用浅蓝色描边,以表示它被加入到关闭列表中了。所有的相邻格现在都在开启列表中,它们被用浅绿色描边。每个方格都有一个灰色指针反指他们的父方格,也就是开始的方格。


[图2]

接着,我们选择开启列表中的临近方格,大致重复前面的过程,如下。但是,哪个方格是我们要选择的呢?是那个F值最低的。

路径评分

选择路径中经过哪个方格的关键是下面这个等式:

F = G + H

这里:
* G = 从起点A,沿着产生的路径,移动到网格上指定方格的移动耗费。
* H = 从网格上那个方格移动到终点B的预估移动耗费。这经常被称为启发式的,可能会让你有点迷惑。这样叫的原因是因为它只是个猜测。我们没办法事先知道路径的长 度,因为路上可能存在各种障碍(墙,水,等等)。虽然本文只提供了一种计算H的方法,但是你可以在网上找到很多其他的方法。

我们的路径是通过反复遍历开启列表并且选择具有最低F值的方格来生成的。文章将对这个过程做更详细的描述。首先,我们更深入的看看如何计算这个方程。

正 如上面所说,G表示沿路径从起点到当前点的移动耗费。在这个例子里,我们令水平或者垂直移动的耗费为10,对角线方向耗费为14。我们取这些值是因为沿对 角线的距离是沿水平或垂直移动耗费的的根号2(别怕),或者约1.414倍。为了简化,我们用10和14近似。比例基本正确,同时我们避免了求根运算和小 数。这不是只因为我们怕麻烦或者不喜欢数学。使用这样的整数对计算机来说也更快捷。你不就就会发现,如果你不使用这些简化方法,寻路会变得很慢。

既然我们在计算沿特定路径通往某个方格的G值,求值的方法就是取它父节点的G值,然后依照它相对父节点是对角线方向或者直角方向(非对角线),分别增加14和10。例子中这个方法的需求会变得更多,因为我们从起点方格以外获取了不止一个方格。

H 值可以用不同的方法估算。我们这里使用的方法被称为曼哈顿方法,它计算从当前格到目的格之间水平和垂直的方格的数量总和,忽略对角线方向。然后把结果乘以 10。这被成为曼哈顿方法是因为它看起来像计算城市中从一个地方到另外一个地方的街区数,在那里你不能沿对角线方向穿过街区。很重要的一点,我们忽略了一 切障碍物。这是对剩余距离的一个估算,而非实际值,这也是这一方法被称为启发式的原因。想知道更多?你可以在这里找到方程和额外的注解。

F的值是G和H的和。第一步搜索的结果可以在下面的图表中看到。F,G和H的评分被写在每个方格里。正如在紧挨起始格右侧的方格所表示的,F被打印在左上角,G在左下角,H则在右下角。


[图3]

现在我们来看看这些方格。写字母的方格里,G = 10。这是因为它只在水平方向偏离起始格一个格距。紧邻起始格的上方,下方和左边的方格的G值都等于10。对角线方向的G值是14。

H 值通过求解到红色目标格的曼哈顿距离得到,其中只在水平和垂直方向移动,并且忽略中间的墙。用这种方法,起点右侧紧邻的方格离红色方格有3格距离,H值就 是30。这块方格上方的方格有4格距离(记住,只能在水平和垂直方向移动),H值是40。你大致应该知道如何计算其他方格的H值了~。

每个格子的F值,还是简单的由G和H相加得到

继续搜索

为了继续搜索,我们简单的从开启列表中选择F值最低的方格。然后,对选中的方格做如下处理:

4,把它从开启列表中删除,然后添加到关闭列表中。
5,检查所有相邻格子。跳过那些已经在关闭列表中的或者不可通过的(有墙,水的地形,或者其他无法通过的地形),把他们添加进开启列表,如果他们还不在里面的话。把选中的方格作为新的方格的父节点。
6,如果某个相邻格已经在开启列表里了,检查现在的这条路径是否更好。换句话说,检查如果我们用新的路径到达它的话,G值是否会更低一些。如果不是,那就什么都不做。
另一方面,如果新的G值更低,那就把相邻方格的父节点改为目前选中的方格(在上面的图表中,把箭头的方向改为指向这个方格)。最后,重新计算F和G的值。如果这看起来不够清晰,你可以看下面的图示。

好了,让我们看看它是怎么运作的。我们最初的9格方格中,在起点被切换到关闭列表中后,还剩8格留在开启列表中。这里面,F值最低的那个是起始格右侧紧邻的格子,它的F值是40。因此我们选择这一格作为下一个要处理的方格。在紧随的图中,它被用蓝色突出显示。


[图4]

首先,我们把它从开启列表中取出,放入关闭列表(这就是他被蓝色突出显示的原因)。然后我们检查相邻的格子。哦,右侧的格子是墙,所以我们略过。左侧的格子是起始格。它在关闭列表里,所以我们也跳过它。

其 他4格已经在开启列表里了,于是我们检查G值来判定,如果通过这一格到达那里,路径是否更好。我们来看选中格子下面的方格。它的G值是14。如果我们从当 前格移动到那里,G值就会等于20(到达当前格的G值是10,移动到上面的格子将使得G值增加10)。因为G值20大于14,所以这不是更好的路径。如果 你看图,就能理解。与其通过先水平移动一格,再垂直移动一格,还不如直接沿对角线方向移动一格来得简单。

当我们对已经存在于开启列表中的4个临近格重复这一过程的时候,我们发现没有一条路径可以通过使用当前格子得到改善,所以我们不做任何改变。既然我们已经检查过了所有邻近格,那么就可以移动到下一格了。

于 是我们检索开启列表,现在里面只有7格了,我们仍然选择其中F值最低的。有趣的是,这次,有两个格子的数值都是54。我们如何选择?这并不麻烦。从速度上 考虑,选择最后添加进列表的格子会更快捷。这种导致了寻路过程中,在靠近目标的时候,优先使用新找到的格子的偏好。但这无关紧要。(对相同数值的不同对 待,导致不同版本的A*算法找到等长的不同路径。)

那我们就选择起始格右下方的格子,如图。


[图5]

这 次,当我们检查相邻格的时候,发现右侧是墙,于是略过。上面一格也被略过。我们也略过了墙下面的格子。为什么呢?因为你不能在不穿越墙角的情况下直接到达 那个格子。你的确需要先往下走然后到达那一格,按部就班的走过那个拐角。(注解:穿越拐角的规则是可选的。它取决于你的节点是如何放置的。)

这 样一来,就剩下了其他5格。当前格下面的另外两个格子目前不在开启列表中,于是我们添加他们,并且把当前格指定为他们的父节点。其余3格,两个已经在开启 列表中(起始格,和当前格上方的格子,在表格中蓝色高亮显示),于是我们略过它们。最后一格,在当前格的左侧,将被检查通过这条路径,G值是否更低。不必 担心,我们已经准备好检查开启列表中的下一格了。

我们重复这个过程,知道目标格被添加进开启列表,就如在下面的图中所看到的。


[图6]

注 意,起始格下方格子的父节点已经和前面不同的。之前它的G值是28,并且指向右上方的格子。现在它的G值是20,指向它上方的格子。这在寻路过程中的某处 发生,当应用新路径时,G值经过检查变得低了-于是父节点被重新指定,G和F值被重新计算。尽管这一变化在这个例子中并不重要,在很多场合,这种变化会导 致寻路结果的巨大变化。

那么,我们怎么确定这条路径呢?很简单,从红色的目标格开始,按箭头的方向朝父节点移动。这最终会引导你回到起始格,这就是你的路径!看起来应该像图中那样。从起始格A移动到目标格B只是简单的从每个格子(节点)的中点沿路径移动到下一个,直到你到达目标点。就这么简单。


[图7]

A*方法总结

好,现在你已经看完了整个说明,让我们把每一步的操作写在一起:

1,把起始格添加到开启列表。
2,重复如下的工作:
a) 寻找开启列表中F值最低的格子。我们称它为当前格。
b) 把它切换到关闭列表。
c) 对相邻的8格中的每一个?
* 如果它不可通过或者已经在关闭列表中,略过它。反之如下。
* 如果它不在开启列表中,把它添加进去。把当前格作为这一格的父节点。记录这一格的F,G,和H值。
* 如果它已经在开启列表中,用G值为参考检查新的路径是否更好。更低的G值意味着更好的路径。如果是这样,就把这一格的父节点改成当前格,并且重新计算这一格的G和F值。如果你保持你的开启列表按F值排序,改变之后你可能需要重新对开启列表排序。

d) 停止,当你
* 把目标格添加进了开启列表,这时候路径被找到,或者
* 没有找到目标格,开启列表已经空了。这时候,路径不存在。
3.保存路径。从目标格开始,沿着每一格的父节点移动直到回到起始格。这就是你的路径。

题外话

离 题一下,见谅,值得一提的是,当你在网上或者相关论坛看到关于A*的不同的探讨,你有时会看到一些被当作A*算法的代码而实际上他们不是。要使用A*,你 必须包含上面讨论的所有元素--特定的开启和关闭列表,用F,G和H作路径评价。有很多其他的寻路算法,但他们并不是A*,A*被认为是他们当中最好的。 Bryan Stout在这篇文章后面的参考文档中论述了一部分,包括他们的一些优点和缺点。有时候特定的场合其他算法会更好,但你必须很明确你在作什么。好了,够多 的了。回到文章。

实现的注解

现在你已经明白了基本原理,写你的程序的时候还得考虑一些额外的东西。下面这些材料中的一些引用了我用C++和Blitz Basic写的程序,但对其他语言写的代码同样有效。

1, 维护开启列表:这是A*寻路算法最重要的组成部分。每次你访问开启列表,你都需要寻找F值最低的方格。有几种不同的方法实现这一点。你可以把路径元素随意 保存,当需要寻找F值最低的元素的时候,遍历开启列表。这很简单,但是太慢了,尤其是对长路径来说。这可以通过维护一格排好序的列表来改善,每次寻找F值 最低的方格只需要选取列表的首元素。当我自己实现的时候,这种方法是我的首选。

在 小地图。这种方法工作的很好,但它并不是最快的解决方案。更苛求速度的A*程序员使用叫做“binary heap”的方法,这也是我在代码中使用的方法。凭我的经验,这种方法在大多数场合会快2~3倍,并且在长路经上速度呈几何级数提升(10倍以上速度)。 如果你想了解更多关于binary heap的内容,查阅我的文章,Using Binary Heaps in A* Pathfinding。

2, 其他单位:如果你恰好看了我的例子代码,你会发现它完全忽略了其他单位。我的寻路者事实上可以相互穿越。取决于具体的游戏,这也许可以,也许不行。如果你 打算考虑其他单位,希望他们能互相绕过,我建议在寻路算法中忽略其他单位,写一些新的代码作碰撞检测。当碰撞发生,你可以生成一条新路径或者使用一些标准 的移动规则(比如总是向右,等等)直到路上没有了障碍,然后再生成新路径。为什么在最初的路径计算中不考虑其他单位呢?那是因为其他单位会移动,当你到达 他们原来的位置的时候,他们可能已经离开了。这有可能会导致奇怪的结果,一个单位突然转向,躲避一个已经不在那里的单位,并且会撞到计算完路径后,冲进它 的路径中的单位。

然而,在寻路算法中忽略其他对象,意味着你必须编写单独的碰撞检测代码。这因游戏而异,所以我把这个决定权留给你。参考文献列表中,Bryan Stout的文章值得研究,里面有一些可能的解决方案(像鲁棒追踪,等等)。

3, 一些速度方面的提示:当你开发你自己的A*程序,或者改写我的,你会发现寻路占据了大量的CPU时间,尤其是在大地图上有大量对象在寻路的时候。如果你阅 读过网上的其他材料,你会明白,即使是开发了星际争霸或帝国时代的专家,这也无可奈何。如果你觉得寻路太过缓慢,这里有一些建议也许有效:

* 使用更小的地图或者更少的寻路者。
* 不要同时给多个对象寻路。取而代之的是把他们加入一个队列,把寻路过程分散在几个游戏周期中。如果你的游戏以40周期每秒的速度运行,没人能察觉。但是他们会发觉游戏速度突然变慢,当大量寻路者计算自己路径的时候。
* 尽量使用更大的地图网格。这降低了寻路中搜索的总网格数。如果你有志气,你可以设计两个或者更多寻路系统以便使用在不同场合,取决于路径的长度。这也正是 专业人士的做法,用大的区域计算长的路径,然后在接近目标的时候切换到使用小格子/区域的精细寻路。如果你对这个观点感兴趣,查阅我的文章Two- Tiered A* Pathfinding。
* 使用路径点系统计算长路径,或者预先计算好路径并加入到游戏中。
* 预处理你的地图,表明地图中哪些区域是不可到达的。我把这些区域称作“孤岛”。事实上,他们可以是岛屿或其他被墙壁包围等无法到达的任意区域。A*的下限 是,当你告诉它要寻找通往那些区域的路径时,它会搜索整个地图,直到所有可到达的方格/节点都被通过开启列表和关闭列表的计算。这会浪费大量的CPU时 间。可以通过预先确定这些区域(比如通过flood-fill或类似的方法)来避免这种情况的发生,用某些种类的数组记录这些信息,在开始寻路前检查它。 在我Blitz版本的代码中,我建立了一个地图预处理器来作这个工作。它也标明了寻路算法可以忽略的死端,这进一步提高了寻路速度。

4, 不同的地形损耗:在这个教程和我附带的程序中,地形只有两种-可通过的和不可通过的。但是你可能会需要一些可通过的地形,但是移动耗费更高-沼泽,小山, 地牢的楼梯,等等。这些都是可通过但是比平坦的开阔地移动耗费更高的地形。类似的,道路应该比自然地形移动耗费更低。

这 个问题很容易解决,只要在计算任何地形的G值的时候增加地形损耗就可以了。简单的给它增加一些额外的损耗就可以了。由于A*算法已经按照寻找最低耗费的路 径来设计,所以很容易处理这种情况。在我提供的这个简单的例子里,地形只有可通过和不可通过两种,A*会找到最短,最直接的路径。但是在地形耗费不同的场 合,耗费最低的路径也许会包含很长的移动距离-就像沿着路绕过沼泽而不是直接穿过它。

一 种需额外考虑的情况是被专家称之为“influence mapping”的东西(暂译为影响映射图)。就像上面描述的不同地形耗费一样,你可以创建一格额外的分数系统,并把它应用到寻路的AI中。假设你有一张 有大批寻路者的地图,他们都要通过某个山区。每次电脑生成一条通过那个关口的路径,它就会变得更拥挤。如果你愿意,你可以创建一个影响映射图对有大量屠杀 事件的格子施以不利影响。这会让计算机更倾向安全些的路径,并且帮助它避免总是仅仅因为路径短(但可能更危险)而持续把队伍和寻路者送到某一特定路径。

5,处理未知区域:你是否玩过这样的PC游戏,电脑总是知道哪条路是正确的,即使它还没有侦察过地图?对于游戏,寻路太好会显得不真实。幸运的是,这是一格可以轻易解决的问题。

答 案就是为每个不同的玩家和电脑(每个玩家,而不是每个单位--那样的话会耗费大量的内存)创建一个独立的“knownWalkability”数组,每个 数组包含玩家已经探索过的区域,以及被当作可通过区域的其他区域,直到被证实。用这种方法,单位会在路的死端徘徊并且导致错误的选择直到他们在周围找到 路。一旦地图被探索了,寻路就像往常那样进行。

6,平滑路径:尽管A*提供了最短,最低代价的路径,它无法自动提供看起来平滑的路径。看一下我们的例子最终形成的路径(在图7)。最初的一步是起始格的右下方,如果这一步是直接往下的话,路径不是会更平滑一些吗?

有 几种方法来解决这个问题。当计算路径的时候可以对改变方向的格子施加不利影响,对G值增加额外的数值。也可以换种方法,你可以在路径计算完之后沿着它跑一 遍,找那些用相邻格替换会让路径看起来更平滑的地方。想知道完整的结果,查看Toward More Realistic Pathfinding,一篇(免费,但是需要注册)Marco Pinter发表在Gamasutra.com的文章

7, 非方形搜索区域:在我们的例子里,我们使用简单的2D方形图。你可以不使用这种方式。你可以使用不规则形状的区域。想想冒险棋的游戏,和游戏中那些国家。 你可以设计一个像那样的寻路关卡。为此,你可能需要建立一个国家相邻关系的表格,和从一个国家移动到另一个的G值。你也需要估算H值的方法。其他的事情就 和例子中完全一样了。当你需要向开启列表中添加新元素的时候,不需使用相邻的格子,取而代之的是从表格中寻找相邻的国家。

类 似的,你可以为一张确定的地形图创建路径点系统,路径点一般是路上,或者地牢通道的转折点。作为游戏设计者,你可以预设这些路径点。两个路径点被认为是相 邻的如果他们之间的直线上没有障碍的话。在冒险棋的例子里,你可以保存这些相邻信息在某个表格里,当需要在开启列表中添加元素的时候使用它。然后你就可以 记录关联的G值(可能使用两点间的直线距离),H值(可以使用到目标点的直线距离),其他都按原先的做就可以了。

另一个在非方形区域搜索RPG地图的例子,查看我的文章Two-Tiered A* Pathfinding。

进一步的阅读

好,现在你对一些进一步的观点有了初步认识。这时,我建议你研究我的源代码。包里面包含两个版本,一个是用C++写的,另一个用Blitz Basic。顺便说一句,两个版本都注释详尽,容易阅读,这里是链接。

* 例子代码:A* Pathfinder (2D) Version 1.71

如 果你既不用C++也不用Blitz Basic,在C++版本里有两个小的可执行文件。Blitz Basic可以在从Blitz Basic网站免费下载的litz Basic 3D(不是Blitz Plus)演示版上运行。Ben O’Neill提供一个联机演示可以在这里找到。

你也该看看以下的网页。读了这篇教程后,他们应该变得容易理解多了。

* Amit的 A* 页面:这是由Amit Patel制作,被广泛引用的页面,如果你没有事先读这篇文章,可能会有点难以理解。值得一看。尤其要看Amit关于这个问题的自己的看法。
* Smart Moves:智能寻路:Bryan Stout发表在Gamasutra.com的这篇文章需要注册才能阅读。注册是免费的而且比起这篇文章和网站的其他资源,是非常物有所值的。Bryan 用Delphi写的程序帮助我学习A*,也是我的A*代码的灵感之源。它还描述了A*的几种变化。
* 地形分析:这是一格高阶,但是有趣的话题,Dave Pottinge撰写,Ensemble Studios的专家。这家伙参与了帝国时代和君王时代的开发。别指望看懂这里所有的东西,但是这是篇有趣的文章也许会让你产生自己的想法。它包含一些对 mip-mapping,influence mapping以及其他一些高级AI/寻路观点。对”flood filling”的讨论使我有了我自己的“死端”和“孤岛”的代码的灵感,这些包含在我Blitz版本的代码中。

其他一些值得一看的网站:

* aiGuru: Pathfinding
* Game AI Resource: Pathfinding
* GameDev.net: Pathfinding

好了,这就是全部。如果你刚好写一个运用这些观点的程序,我想见识见识。你可以这样联系我:
现在,好运!


我翻译的文章,很长: