[C#]项目管理实践【三】每日构建【Daily Build Using CruiseControl.

mikel阅读(738)

在上一篇项目管理实践教程二、源代码控制【Source Control Using VisualSVN Server and TortoiseSVN】中我们已经讲解了如何使用TortoiseSVN和VisualSVN Server来做简单的版本控制,这一篇我们将会讲解使用CruiseControl.NET和MSBuild来搭建每日构建系统。

在第一篇项目管理实践教程一、工欲善其事,必先利其器【Basic Tools】 中我们已经安装了CruiseControl.NET 1.4,因为我们还要用到MSBuild,所以如果你的系统没有安装Visual Studio,那么你需要首先安装Visual Studio 2005/2008,我们在这里使用的是Visual Studio 2008,准备好这些了吗?OK,我们正式开始今天的课程! 

首先,我们要配置CruiseControl.NET【下面简写为CCNET】,配置完成后,我们每次提交源代码到SVN服务器后,CCNET就可 以自动从SVN服务器上迁出源代码,并调用MSBuild自动进行编译。我们以昨天的教程中创建的StartKit项目为实例,先看看下面的配置文件:


  1 <cruisecontrol xmlns:cb="urn:ccnet.config.builder">
  2 <!–项目名称–>
  3 <name>StartKit</name>
  4 <!–标示类型,有多种类型。下面为默认标示,作为每次编译时生成的日志文件的名称–>
  5 <labeller type="defaultlabeller">
  6     <!–前缀–>
  7      <prefix>StartKit-1-</prefix>
  8     <!–编译失败时是否增加–>
  9      <incrementOnFailure>false</incrementOnFailure>
 10     <!–格式–>
 11      <labelFormat>00000</labelFormat>
 12 </labeller>
 13 <!–项目的WebDashboard地址,CruiseControl.NET包括二部分,一是Server用来配置项目和监视文件修改,二是WebDashboard,是一个显示项目信息及编译信息的Website–>
 14     <webURL>http://202.196.96.55:8080/server/local/project/StartKit/ViewProjectReport.aspx</webURL>
 15 <!–触发器,包含多种,有兴趣可以查看官方文档–>
 16 <triggers>
 17 <!–时间间隔触发器,下面是60秒触发一次–>
 18       <intervalTrigger seconds="60" />
 19 </triggers>
 20 <!–如果发现修改,延迟多久开始编译,下面是2秒–>
 21 <modificationDelaySeconds>2</modificationDelaySeconds>
 22 <!–源代码控制系统,支持多种,有兴趣可以查看官方文档,下面采用svn–>
 23 <sourcecontrol type="svn">
 24 <!–源代码在SVN服务器上的路径–>
 25       <trunkUrl>http://zt.net.henu.edu.cn/svn/StartKit/StartKit/</trunkUrl>
 26 <!–svn服务器所在路径,在这里就是VisualSVN Server安装目录中的bin目录下的svn.exe –>
 27       <executable>C:/Program Files/VisualSVN Server/bin/svn.exe</executable>
 28   <!–用来迁出源代码的用户名,svn服务器进行验证–>
 29 <username>starter</username>
 30 <!–用来迁出源代码的用户名对应的密码–>
 31       <password>123456</password>
 32     <!–web获取源代码的地址,类似于开源网站上浏览代码的那部分功能,这里的类型是trac–>
 33 <!–<webUrlBuilder type="trac">
 34     <!–trac中对应项目的地址¬–>
 35       <tracProjectUrl>http://svn.net.henu.edu.cn/pojects/StartKit/</tracProjectUrl>
 36       <!–trac中对应项目的源代码库地址,相对于上面的路径–>
 37       <tracRepositoryRoot>/StartKit</tracRepositoryRoot>
 38       </webUrlBuilder>–>
 39 </sourcecontrol>
 40 <!–该节点用来配置具体执行那些任务–>
 41 <tasks>
 42 <!–msbuild任务配置,用来编译项目–>
 43       <msbuild>
 44         <!–MSBuild.exe的路径–>
 45         <executable>C:\WINDOWS\Microsoft.NET\Framework\v3.5\MSBuild.exe</executable>
 46         <!–从SVN迁出的源代码的存放位置,可以不配置,下面的即为默认值 –>
 47         <!–我这里的CruiseControl.NET 安装在D盘,你们使用时候,改成自己的安装路径即可–>
 48         <workingDirectory>D:\Program Files\CruiseControl.NET\server\StartKit\WorkingDirectory</workingDirectory>
 49         <!–对这个项目的监控过程的日志记录目录,可以不配置,下面的即为默认值–>
 50         <!–我这里的CruiseControl.NET 安装在D盘,你们使用时候,改成自己的安装路径即可–>
 51          <artifactDirectory> D:\Program Files\CruiseControl.NET\server\StartKit\ Artifacts</artifactDirectory>
 52         <!–要编译的项目名称 –>
 53 <projectFile>StartKit.sln</projectFile>
 54 <!– MSBuild编译时的参数,具体参数信息可以查看MSDN上的说明–>
 55         <buildArgs>/p:configuration=Debug</buildArgs>
 56         <!–指定日志记录模块–>
 57         <!–我这里的CruiseControl.NET 安装在D盘,你们使用时候,改成自己的安装路径即可–>
 58         <logger>ThoughtWorks.CruiseControl.MsBuild.XmlLogger,D:\Program Files\CruiseControl.NET\server\ThoughtWorks.CruiseControl.MsBuild.dll</logger>
 59         <!–编译目标–>
 60 <targets />
 61       </msbuild>
 62         <!–在这里还可以添加其他的程序,比如运行测试、部署项目等等–>
 63 </tasks>
 64 <!–项目编译状态信息的保存位置–>
 65 <!–我这里的CruiseControl.NET 安装在D盘,你们使用时候,改成自己的安装路径即可–>
 66     <state type="state" directory="D:\Program Files\CruiseControl.NET\server\CCState" />
 67 <!–发布和部署配置–>
 68 <publishers>
 69   <!–如果编译成功,那么下面的配置,会将源代码复制到指定目录HistoryVersion下,名称为版本标识(自动增长,labeller配置)的子目录下–>
 70   <buildpublisher>
 71     <!–源代码路径–>
 72     <!–我这里的CruiseControl.NET 安装在D盘,你们使用时候,改成自己的安装路径即可–>
 73      <sourceDir> D:\Program Files\CruiseControl.NET\server\StartKit\WorkingDirectory </sourceDir>
 74      <!–编译成功后保存源代码到该目录下名称为版本标示labeller的目录中–>
 75     <!–我这里的CruiseControl.NET 安装在D盘,你们使用时候,改成自己的安装路径即可–>
 76 <publishDir> D:\Program Files\CruiseControl.NET\server\StartKit\HistoryVersion </publishDir>
 77   </buildpublisher> 
 78 <!–该节点用来配置合并多个文件,当时有外部插件时,要把他们分别产生的输出文件合并–> 
 79       <merge>
 80         <!–要合并的文件,合并后的信息可以显示在Web Dashboard和邮件通知里–>
 81         <files>
 82             <!–我这里的CruiseControl.NET 安装在D盘,你们使用时候,改成自己的安装路径即可–>
 83           <file>D:\Program Files\CruiseControl.NET\server\StartKit\WorkingDirectory\results.xml</file>
 84         </files>
 85       </merge>
 86         <!–源代码路径–>
 87       <xmllogger />
 88         <!–显示历史修改记录列表, 在Web Dashboard中可以查看–>
 89       <modificationHistory />
 90         <!–所有编译信息的统计, 在Web Dashboard中可以查看–>
 91       <statistics />
 92         <!–邮件通知配置,每次编译后,都会邮件通知下面配置中添加的用户–>
 93       <!– mailhost 是发送邮件的主机,mailport是邮件发送端口,mailhostUsername发送邮件的邮箱用户名,mailhostPassword发送邮件 的邮箱密码,from希望显示在发件人中的邮箱地址, includeDetails邮件内容是否包含详细的编译信息 –>
 94 <email mailhost="smtp.qq.com" mailport="25"
 95                  mailhostUsername="******" mailhostPassword="******" from="******@qq.com" includeDetails="true">
 96         <!–接收邮件通知的用户 –>
 97 <users>
 98   <!–name是SVN服务器上存在的用户名,group是SVN服务器上存在的组,address是该用户的邮箱地址 –>
 99           <user name="zt" group="StartKit" address="******1@qq.com" />
100           <user name="***" group="StartKit" address="******2@qq.com" />
101           <user name="***" group="StartKit" address="******3@qq.com" />
102         </users>
103         <!–接收邮件通知的组–>
104         <groups>
105         <!–name必须是SVN服务器上存在的组,notification是什么时候发送通知,可选有Always/Success/Change/Fixed/Failed –>
106           <group name="StartKit " notification="always" />
107         </groups>
108       </email>
109     </publishers>
110   </project>
111   <!–可以同时添加多个项目
112 <project >
113 <name>test</name>
114 ……
115 </project>
116 –>
117 </cruisecontrol>
118

好了,我们已经对CCNET的配置文件有了大致的了解,接下来,你打开CCNET的安装路径,找到子目录server下的ccnet.config文件, 把上面的配置信息Copy到ccnet.config文件中,记得把配置文件中的一些路径修改为自己的实际路径啊,修改好后,保存。这时候,检查 Windows服务CruiseControl.NET Server是否启动,如果没有则启动它,启动该服务后,打开浏览在地址栏输入上面配置文件中的webUrl地址:http://202.196.96.55:8080/server/local/project/StartKit/ViewProjectReport.aspx 也可以直接输入http://202.196.96.55:8080/server/ ,这里是演示地址,要根据自己的实际情况修改为正确的地址,OK,看到类似下图的效果,好了,搞定!如果你遇到了什么麻烦,请在下面留言,我一定会及时回复!

 点击StartKit,转入下图所示的页面:

OK,到这里,我们提交更新到SVN服务器后,CCNET就会根据我们配置自动编译项目,而且我们也可以通过Web Dashboard来查看具体的编译信息了,提示如果配置了邮件发送,那么我们还可以通过邮件收到详细的编译信息,怎么样?够方便吧!

其实,CCNET的功能是相当强大的,上面只是最常用的配置,其他还有很多非常好的功能。你想知道吗?那你可以在这里查看CCNET官方文档 ,实际上,你安装CCNET后,文档也已经安装到你的电脑了,在CCNET的安装目录下的webdashboard的子目录doc中就是。 

好了,我们今天的教程就到这里,本来我应该把如何使用CruiseControl.NET Tray来监视每次更新后的编译状态,但是今天真的太晚了,明天还要做项目,所以我明天补上,请大家见谅! 

如果大家有什么问题,欢迎和我交流! 


作者:ttzhangTechnology Life
出处:http://ttzhang.cnblogs.com/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

[Flex]Flash技术入住亚马逊

mikel阅读(717)

FLASH技术入住亚马逊,其试推多媒体购物网站

Windowshop.com

北京时间11月6日消息,据国外媒体报道,亚马逊9月中旬悄无声息地推出了一个新站点,通过多媒体方式展示某些商品,试图藉此改变在线购物通常无法给消费者带来“感官盛宴”的局面。

  亚马逊这一新站点名为Windowshop.com,该站点每周二都会陈列出最新、最热销和经过精挑细选的商品。亚马逊鼓励访客使用键盘上的方向键浏览Windowshop.com,该站特点是在矩形方框中以视频方式介绍某种商品,这些方框则呈棋盘状依次排列。

   目前,在Windowshop上陈列的商品有音乐、书籍、视频游戏和电影。访客在用鼠标点击或使用键盘方向键移动至某种商品时,该商品所在方框将会变 大,供访客观看或收听相关内容,如《功夫熊猫》的视频剪辑,或是某本书籍的音频预览等。如果想要购买某种商品,只需点击方框右下方的按钮跳转至亚马逊主站 即可。

  亚马逊负责零售客户体验的副总裁伊娃·马诺里斯(Eva Manolis)称,推出Windowshop旨在给消费者带来身临其境的感觉,这是在线购物中很难获得的体验,对亚马逊这样一个规模庞大的网站来说更是如此。她表示:“我们希望尝试不同于以往的新事物。”

  此外,亚马逊还将Windowshop.com网站的技术和美学理念用于主站的一个版块,展示广受欢迎的节日玩具和深得儿童喜爱的视频游戏及DVD等商品。马诺里斯称,鞋和服装等其他类型的产品也可采用Windowshop风格。

[Flex]Prana Framework力推ActionScript 3应用开发

mikel阅读(782)

Prana Framework力推ActionScript 3应用开发

作者 Moxie Zhang译者 张龙 发布于 2008年11月5日 下午3时59分

社区
Java
主题
RIA
标签
Flex

Prana是一个面向Adobe Flex及ActionScript 3的控制反转(Inversion of Control,即IoC)应用框架。InfoQ最近采访了Prana Framework的创建者Christophe Herreman和Damir Murat以深入了解该框架的使用。

InfoQ:您能否向InfoQ的读者说明一下当初为何在其他控制反转应用框架已经存在的前提下还要开发Prana呢?

Herreman:Prana诞生于我们开始重写之前用ActionScript 2和Flash开发的一个在线学习平台之际。我们使用的一个库是来自于as2lib的IoC容器,由于之前IoC对我们的工作提供了巨大的帮助,因此我们 想在自己的这个新平台上也添加同样的功能。那时还没有ActionScript 3的IoC容器,所以我打算自己开发一个。

我以一个自己的实现(基于Spring XML方言)开始,但很快我就决定尽可能地以Spring提供的代码作为基础。这样做更容易实现某些特性,因为可以参考Spring的源码;熟悉 Spring的开发者使用Prana时会很容易上手,当然我也借此机会更深入地学习Spring的内核。

InfoQ:您认为Prana framework最突出的特点是什么?

Herreman:它是一个通用、可扩展、功能强大的IoC容器。如果你了解Spring IoC容器,那么你就会清楚Prana能做些什么。

它有一个很棒的特性:你可以向其XML解析器中增加自定义的预处理器。预处理器用来转换已加载但尚未解析的XML。接下来,你可以增加新的元素和属性以方便地描述自定义对象,同时还可以让自定义的预处理器将元素转化为Prana解析器可以理解的形式。

除了IoC容器,Prana还有一个构建于describeType()之上的Reflection API。这样你就可以在运行时获得对象的信息,比如对象包含的属性和方法以及实现的接口等等。接下来,我们还为领域对象创建了一些基础类(这是从Eric Evans的Domain-Driven Design一书中得到的灵感)。这些基础类具有比较和克隆对象等逻辑。Prana还包含几个有用的帮助类。

Murat:Prana还提供了一些工具,这些工具可用来快速建立基于Prana的项目。其中一个主要特性就是 动态更新Flex编译器的配置信息以包含编译好的swf中的类,而这些类是无法通过代码访问的。这在IoC系统中很常见,因为IoC鼓励面向接口(而不是 类)编程。我们的工具与Eclipse/Flex Builder紧密集成,同时他们可以检测到Prana的配置信息何时发生了变化,如果需要的话,他们就会解析Prana的配置并相应地更新flex编译 器设置。当程序员必须显式声明无法通过代码访问的类以将其包含在最终编译好的swf中时,这种方式就无需再使用典型的flex“模式”了。我们的工具会自 动完成这些事情。

还有其他一些特性,如预定义的项目布局、定义好的Ant target,对subversion的支持等等。所有这些特性都是可配置的,并可通过几个步骤轻松搞定。开发者可以查看prana-tools项目(从svn或是分发包中都可以得到)以了解感兴趣的信息。

InfoQ: Prana集成了Cairngorm和PureMVC。您能否说明一下Prana为什么要与这两个框架集成,并且是如何实现集成的?

Herreman:我们为Cairngorm和PureMVC提供了一套扩展。因为我们使用了IoC,所以我们还想将该原理应用到我们正在使用的框架上,同时我们想用依赖注入(Dependency Injection,即DI)对应用的不同部分进行包装。

我们为Cairngorm提供了一个可配置在IoC容器中的服务定位器。你可以在外部定义远程对象、channelsets、consumers等, 并可以改变他们而无需重新编译应用。通过这种方式,你也无需编译services-config.xml文件并可以轻松地将其部署到不同的地方。它还使测 试变得更简单。典型的例子就是当你从开发机器迁移到测试或是产品服务器上时,你得改变端点(endpoints)。Prana使这一切变得简单,你无需重 新构建应用。

我们提供的frontcontroller是Cairngorm frontcontroller的一个子类,它接收定制的命令工厂。通过这种方式,你可以控制命令创建的方式,一旦命令创建好后,你就可以将额外的属性注入到命令中。除此以外,我们还支持链式的事件/命令,这样你就无需显式地从另一个命令中调用命令了。

Murat:与PureMVC的集成最初只是一种实验性的尝试,用来将IoC带到PureMVC应用中。后来发现这是可行的,于是我们就将这项工作公开了。

对于PureMVC用户来说,主要的好处是当遇到依赖时可以使用依赖注入。同时这也是最大的缺点,因为DI的使用不可避免地会改变一些原始的 PureMVC使用习惯,而这些习惯是基于服务定位器模式的。然而我们相信DI对任何应用都是很有帮助的,PureMVC也不例外。为了减轻移植到DI的 代价,我们尽可能简化Prana的PureMVC集成。例如,PureMVC开发者可以选择一个DI的应用范围。Prana只能用来管理非PureMVC 对象,或者说它只能用来管理部分PureMVC类,当然它可以管理应用中的PureMVC对象和非PureMVC对象。

InfoQ:能不能推荐一下使用Prana的最佳方式(或者是应用类型)?

Herreman:如果你需要在应用中保持一定程度的灵活性以便其可以运行在不同的上下文中,或者是你拥有大量的配置,想要集中管理他们,那么我极力推荐使用Prana。因为它基于Spring,很多开发者已经熟悉了其概念和XML方言。

就我们的情况来说,我们已经创建了一个在线学习平台,用户可以定制其自己的需求。因为我们自己管理该平台,所以需要有一种机制以允许所有这些定制。 如果没有IoC,我们就不得不对每个定制编译不同的软件版本,或者是我们必须编写一个基于XML或者是数据库的客户配置系统,而对其的维护绝对是一个噩 梦。与此相反,我们可以让每种定制都有一个应用上下文,当应用加载时就去装载该上下文,这取决于登录的用户。更酷的是我们可以从ASP页面(需要从数据库 中读取配置)中即时生成应用上下文。

InfoQ:Prana的长期计划是什么?

Herreman:最重要的事情就是IoC容器,我们期望1.0版会有一个稳定的容器。目前来看,容器本身很不错,但我们还可以改进一些东西,增加更多的Spring特性,如parent beans及自动装配等。我们还需要编写一些文档。

我们一直在与开发团队探讨将扩展(Cairngorm、PureMVC等)从主代码库中移除,然后将其作为独立的扩展库发布。这么做将有利于发布管理。

我还准备开发一个AOP(Aspect-Oriented Programming,面向方面的编程)框架,但遇到了一些麻烦,这些麻烦是由ActionScript 3的一些限制导致的。AOP背后的主要思想是基于动态代理机制创建新的对象类型,该对象会在运行时实现一些接口。问题在于这在ActionScript 3中是不可能的。我们已经在Adobe JIRA上发布了这个话题,如果有人愿意与我们分享一些见解的话我将感激不尽。该话题位于:http://bugs.adobe.com/jira/browse/ASC-3136

至于其他方面,我们还没有制订严格的路线图。当我们有新想法时就会引入一些新特性和进行一些改进,我们一直在倾听来自其他开发者的建议,同时还期待有更多的人能加入到我们的团队中。

查看英文原文:Prana Framework Helps on ActionScript 3 Application Development

[C#]BlogEngine.Net架构与源代码分析系列part4:Blog全局设置——BlogSe

mikel阅读(819)

     这 已经是本系列的第四篇了,以前我多数时间是看文章,自己写起来才感觉到当博主不容易啊,所以我们无论评论也好,阅读也好,都要尊重博主的劳动成果。闲话少 说,在这篇文章中我们将对BlogEngine.Net的全局配置进行一下分析与探讨。关于配置这一部分单独拿出来做一篇文章实在有些牵强,但是我总觉得 这个配置部分比较独立,而且BlogEngine.Net的设计和实现都有很多可以参考的地方。

在一个企业级应用系统中,对一些系统全局参数进行配置是必不可少的,那么我们是怎么处理这些配置的呢?

     一般都有以下三步:

1.在业务模块开发的过程中将一些可变的参量提取出来。

2.当所有业务模块开发完成时,将这些参量分类存储起来。

3.开发出相应的管理功能,允许用户对这些参量进行设置。

     相信大多数开发者都是直接操作数据库中的数据,可能有些比较完善的系统 会做出单独的页面来给用户管理使用,本质上也都是直接与数据库打交道,没有涉及太多的逻辑,比较直接。不过在BlogEngine.Net的架构模型上这 种操作就失效了,我们不可以在BlogEngine.Net的数据库中修改数据而希望在它的运行系统中体现出来(除非重启应用),因为 BlogEngine.Net的数据库只是完成数据存储功能,所有的业务逻辑都在BlogEngine.Core层由对象的状态维护来完成(可以参考我的第二篇文章)。有人可能会想可不可以进一步开发一种像ASP.NET中Cache那样对数据库表的依赖机制,我觉得这个问题要看需求,这种在BlogEngine.Net中似乎没有什么太多必要。

那么BlogEngine.Net的全局设置到底是怎么实现的呢?

     在安装 BlogEngine.Net以后进入后台管理中,我们会看到有很多分类的配置选项,包括主题,语言文化,时区等。这些配置的逻辑处理都是通过 BlogEngine.Core中的一个类完成的,那就是BlogSettings。BlogSettings只是完成BlogEngine.Net的全 局的配置处理,对于后文讲述的Widget的一些具体配置并不在这里完成,这主要是为了配置独立的目的,使得Widget可以独立开发。

     BlogSettings与外界交互图(这个图使用画图程序弄的,大家先凑合着看吧):

 

     

     在BlogSettings中除了各种配置项的对应属性以外,还有一个 静态的Changed事件用来通知外部全局配置已经发生了改变,这样就可以写出更多扩展来。BlogSettings使用单例模式来实现(一个设计模式的 很好的应用,全局配置具有系统唯一性)。

Code

 

从这里我们就可以知道为什么对于数据源的直接修改不能在BlogEngine.Net的运行系统中体现的原因了。

     BlogSettings在对象构造时执行了一个Load方法来加载所有数据存储中的配置信息,这个加载过程应用到了.Net反射技术,找到数据存储中与对象属性相同名称的配置项并将其值强制转换以后付给属性,当然这里的数据访问是通过我的第三篇文章中讲述的BlogService调用获得。同理修改配置是通过Save将数据保存回数据存储,也是使用反射完成。

Code

 

客户端的使用方法(注意:这里所说的客户端是指BlogSettings使用者或调用者)

Code

 

总结

     从BlogEngine.Net的全局配置部分我们可以学习到以下几点:
1.单例模式是如何应用在实际项目中的。
2.配置项的数据存取部分的实现有很好的参考价值,可以了解到.Net的反射给开发带来的方便。
3.对于静态事件的使用(BlogEngine.Net中有很多例子)使得我们可以在外部做一些扩展,例如开发一个监控配置修改的跟踪系统。

     好的设计要经过不断的重构才可以达到。

     上一篇:BlogEngine.Net架构与源代码分析系列part3:数据存储——基于Provider模式的实现

版权声明
作者:Thriving.country
出处:http://thriving-country.cnblogs.com/
本文版权归作者和博客园共同所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接.

[FireFox]FireFox3.1开始支持HTML5的视频和音频

mikel阅读(797)

Firefox 3.1现在包含对HTML 5 视频video音频audio 标签tags的支持了!直接可以在页面上控制音频和视频信息,Mozilla开发者网站发布一篇新的文章指导如何使用。Firefox 3.1目前支持Ogg format(一种新的崭露头角的音频文件格式),其他音乐格式还在讨论中,可能未来支持。
下面是范例使用方法:

Html代码 复制代码
  1. <video src="http://v2v.cc/~j/theora_testsuite/320×240.ogg" autoplay>   
  2. Your browser does not support the <code>video</code> element.   
  3. </video>  

是不是非常简单?你能为不同的格式提供不同的代码选项:

Html代码 复制代码
  1. <video autoplay>    
  2.    <source src="foo.ogg" type="video/ogg"></source>    
  3.    <source src="foo.mov"></source>    
  4.    Your browser does not support the <code>video</code> element.    
  5. </video>   

目前,所有源码元素还没有完全支持,媒体录音能通过JavaScript控制:

Js代码 复制代码
  1. var v = document.getElementsByTagName("video")[0];   
  2. v.play();  

你还可以通过不同的媒体事件来更新你的UI:

Js代码 复制代码
  1. var v = document.getElementsByTagName("video")[0];  
  2.   
  3. v.addEventListener("seeked"function() { document.getElementsByTagName("video")[0].play(); }, true);  
  4. v.currentTime = 10.0;   

真是挺强大的,希望其他浏览器对HTML 5的支持也能加强。

来自:ajaxian.com

[设计]30大优秀Logo设计详解

mikel阅读(953)

原文:30 Brilliant Vector Logo Designs, Deconstructed -Chris Spooner

编译:Vinwin (不倒猫

 

拥有一个抢眼的Logo对企业来乃一大幸事,毕竟Logo千千万,但真正让人过目不忘的作品可是屈指可数。好的Logo必须量体裁衣,迅速传递出企业的价值和理念。
但Logo不能只是金玉其外,还必须有思想、多功能。比如,可以用标准色在任何尺寸的纸张完美复制和再现。下面就晾出当前30个自认为很杰出的Logo,飨宴大家。

1.    Castle Print
一个打印机品牌,该Logo直截了当地体现了了企业的业务性质:利用减色模型,直指其打印行业背景,同时通过色彩的混合塑造出一个与其品牌相符的城堡(Castle)形象。


2.    Ryan-Biggs
负空间的运动使得这幅Logo有一种奇幻的效果,完全考验你的空间想象力!B和R两个字母代表了这个品牌,微微的倾斜让整个设计看起来更有深度和立体感。色彩搭配极为简单—红色,赋予了Logo更广的使用范围。

3.    One Leaf
One Leaf, 顾名思义,即一片树叶。以此为轴线,就呈现出了如此简洁巧妙的画面。

4.    Greener
设计师用粗细不同的灯芯体(San-serif)字体塑造出一种现代感。该Logo不但层次感强,更重要的是可以用单一色调复制重现(这也是评判Logo好坏的重要标准之一)。

5.    Talkmore
Talkmore字面意思是“多说点儿”。设计师采用象征的手法,用英文中的单引号分别代替字母“a”和“e”,从而在图形上给予品牌最鲜活的注解。


6.    Black Sparrow
看上去很简单的图标,但在细节处理上却达到了极致。从麻雀(即Black Sparrow的中文)的图案到字体,柔和的曲线与平滑的字体相得益彰,将完整的设计融入品牌表现。


7.    Swannie Lake
富有时代气息的Avenir字体配合平滑的图案,不但与该Logo完美贴合,而且增添了一许微妙的色彩。

8.    Elara Systems
先介绍一下,Elara Systems是一个动画和动态模型工作室,也必然要求2D和3D的结合。体现在Logo上,就是大家所看到的效果:柔软弯曲的字体配上3D的字母“e”(即首字母),很好的创意

9.    Onwine
完美的字体搭配独到的理念,Onwine Logo为我们展现出一个酿酒商的特质,无论是图案还是字体设计都无可挑剔。


10.    Popp
什么叫一气呵成?这幅Logo将基于同一字体的设计方法带上了全新的高度。每个字母都包含字母“O”,只是做了细微的改动就成了“P”,独具匠心。

11.    Therauz Fashions
能看出这个Logo的绝妙之处吗?该公司从事时装设计业务,所以针线活是少不了的。画面中央的长针,不仅反映了公司业务,而且将中间一串字母给“缝”了起来,成了必不可少的一部分,内涵之深可见一斑。

12.    Alatau
无论是字母还是彩色远点,共同的特点就是间距较大,这种手法带来的效果就是严肃而前卫。这样排列的好处还在于以中间两个字母中心,整个Logo看起来非常平衡。


13.    Spiffy Sparrow
作品采用复杂的形状、线条和色彩,为以后的调整打好了基础。另外,用负空间来塑造鸟的躯干也是令人叫绝的地方。


14.    About Thyme
干净利落的线条和形状,是Logo设计的固有套路。不过,本作品似乎摆脱了这样的条条框框:粗糙的手绘图案,给人以一种亲和力,也给体现了品牌所有者作为调味品公司的价值。

15.    Ta Jevi
一个娱乐网站。Logo的每一部分都闪烁着欢乐感。箭头组成的笑脸传递出了这样的信息—欢乐无止境。跳跃的色彩和超酷的手写字更突出了该网站的娱乐价值。


16.    Anti Particle
中文名—反粒子,是一家电影制作公司。这里有必要做个小小的科普,反粒子其实很简单,比如负电子的反粒子就是正电子,质子的反粒子就是反质子……好了,回 到Logo上,很明显,这又是一个用公司名做文章的范例。首先首字母“a”有无数颗粒组成,但里面恰恰有一颗蓝色颗粒,这就体现了“反粒子”的概念。


17. 69 Monos
不同于平面2D设计,有些Logo,就像69 Monos,通过3D效果给Logo增添深度和趣味。改变角度就能带来动感,何乐而不为?


18.    Green Dolphin
Logo使用海豚(Dolphin)的轮廓和绿色来传递品牌信息,同时也隐藏了次级画面—即大写字母G。

19.    Aramova
经典的莫比乌斯带(Mobius Strip http://hi.baidu.com/totogo/blog/item/629a233ff2239aec54e723ad.html)使用案例!柔软的质地+奇幻的色彩,整幅画面让人体会到永不停息的动感。


20.    Vize
并不是所有的Logo都需要附属图案,比如我们看到的这个。虽然只有字体,但由于在排版上做足了功夫,Logo同样可以表达品牌的理念。

21.    Friends in Places
交友网站,很明显。看似纷繁复杂的箭头构成了一幅世界地图,表现了互联网时代网络社交的全球性和广泛性,企业的品牌价值由此得到体现。


22.    Koloroo
一款色彩方案的软件产品。随机的颜色搭配勾勒出了一只袋鼠的形象,这也符合其产品形象。字体设计同样出众,因此可以说,该Logo两部分合起来是精品,拆开来也是优秀的图案和文字标识。


23.    Pangur
手工玻璃制造商。通常而言,透明的运用在Logo设计中是慎而又慎的,不过随着打印技术的改进,已经没有理由限制这种技法的使用了。设计师用不同色彩的玻璃碗进行简单堆砌,且呈现不规则倾斜,这恰恰抓住了玻璃手工艺的特点。Futura字体也给作品锦上添花。

24.    Tammy Lenski
美国一家争端解决公司(比如劳资纠纷等等)。现在,搭上千纸鹤,来一趟意境之旅吧。大多数Logo都直截了当地反映目标企业的各个方面,然而这个设计却通过千纸鹤的故事和寓意来展现企业形象(编者注:之所以这么说,是因为西方人并不了解千纸鹤的含义)。


25.    Eco Cafe
图案简洁又不是标识性,整幅作品看起来就像破土而出的生命。生态咖啡馆—该企业的名称—得到了最鲜明的宣示。而正因为标识本身的简洁,使得它贴在窗户上,也可以印在咖啡杯上。

26. Firefish
这又是一个运用流行技术—比如透明—塑造多层次标识的典范。火焰拼成的鱼(即Firefish,火鱼)搭配上经典的大写灯芯体(san-serif)字母,堪称一绝。

27. Boxbound
立体和透明同属当今Logo设计潮流,这幅作品同时运用了这两种技巧。生动的色彩加上浑圆可爱的字体,俨然一副基于网络的时代先锋形象。


28. AdMagik
看完这个Logo,你应该能学会用颜色区分信息。品红色部分突出了公司的名称“Magic”(魔术),而灰色字体暗示了该公司的身份,也是Logo的重点 所在,即“Ad”(广告)。最后,在字母J和I上做图,使之成为兔子的形象(编者注:兔子在西方是魔术的象征),再一次强调了企业点石成金的业务能力。


29. Jivespace
这个Logo用爆炸性的手法给人以强烈的视觉冲击,既有深度又充满活力,同时,全部小写字母的排版方式体现出其时代气息。

30. Core
和前面提到的“Popp”Logo类似,它也是基于一个形状延续下去,线条干净利落,颜色单一,该Logo的功能性可想而知有多么强大。

来自:blogbeta.com

[C#]BlogEngine.Net架构与源代码分析系列part3:数据存储——基于Provider

mikel阅读(848)

   上一篇文章中,我们主要分析了一下BlogEngine.Net的整体设计,在后半部分我们又对BusinessBase业务对象的状态维护做了一些比较深入的探讨。在这篇文章中我将引领大家完成对BlogEngine.Net中业务对象数据存储的设计思路与实现细节的分析。

BlogEngine.Net中的数据存储主要是应用Provider模式实现的,那么首先让我们认识一下Provider模式。

     Provider 模式应该是一种设计模式,是用来解决软件变化问题的。不过它关注的角度(或者维度)是功能声明跟功能实现的分离。一般来说,系统对某一功能的需求可能是相 对稳定的(比如每个系统都要求对登录用户进行验证,这个需要是相对稳定的),而这个功能的的具体实现却可以是多样的(比如,你可以去数据库里匹配用户进行 验证,也可以去一个XML文件里面去匹配)。Provider模式在.Net类库的设计中随处可见,如:MembershipProvider、 SiteMapProvider等,它的出现使我们的应用程序有了更大的扩展性,要注意Provider可以是一个数据工厂的提供者,也可以是一个逻辑处 理的提供者。在BlogEngine.Net中我们看到的都是数据工厂的提供者,对于逻辑处理的提供者,大家可以参考一下微软企业库 ApplicationBlock中的加密Block的实现。
     在.Net中要实现这种模式是相当的简单,因为它已经为我们实现了一部分,我们只需实现以下三步即可:
1、定义一个类,抽象出我们所需要的操作,它的基类为ProviderBase
2、实现一个Section,用来从配置文件中读取Provider的相关配置,该类继承于ConfigurationSection
3、在调用时去读取配置文件,并加载指定的Provider

对于BlogEngine.Net中的数据存储部分我是怎么看的呢(个人观点,不必在意)?

     BlogEngine.Net可以支持多种数据存储,在它目前的版本中 我们可以看到XML(默认采用,主要是为安装时即插即用考虑的)和数据库两种存储方式。BlogEngine.Net数据存储的Provider只是针对 数据如何存储部分(不涉及到一些逻辑处理与运算),所以对于数据库的要求非常的低,只要支持SQL语句并可以存储数据就行,实际上它在数据库中只有一些 表,从它的Provider的实现来看并没有使用数据库的主键级联删除等功能,而完全使用多条嵌入式SQL语句完成,这样做就可以使 BlogEngine.Net支持更多的数据库。对于数据库的存储BlogEngine.Net只使用了一个DbBlogProvider,而没有具体区 分到底采用何种数据库,我们只要在配置文件中根据链接字符串设定providerName就可以指定具体的数据库存储了。BlogEngine.Net的 这种对数据处理方式在业务逻辑很复杂的系统中我并不是很推荐。

那么再让我们看看在BlogEngine.Net中是怎样应用ProviderBase来完成数据存储问题的。

     先看一幅继承关系图:

从上图我们可以看出DbBlogProvider 和XmlBlogProvider都继承了抽象类BlogProvider(包含一些业务类或其它类等的操作声明),而BlogProvider直接继承 自ProviderBase,ProviderBase是微软的标准Provider框架,我们只要按照这种模型开发就行了,这个标准的Provider 框架已经解决很多问题,例如依赖注入问题等。为了利用.Net平台已有资源对于角色和成员BlogEngine.Net采用了.Net提供的 MembershipProvider和RoleProvider,BlogEngine.Net中 DbMembershipProvider,XmlMembershipProvider继承于 MembershipProvider,DbRoleProvider和XmlRoleProvider继承于RoleProvider,.Net的 MembershipProvider和RoleProvider同样也继承自ProviderBase。BlogProviderSection这个类 是为了解决配置问题的,也就是.Net中Provider模式实现中的第二步,这就很好的解决了依赖注入问题。BlogProvider定义了一些业务类 的标准的操作方法:

Code

子类只要重写这些方法就可以了。

     此外在BlogEngine.Net中还有一个比较推荐的处理,由于BlogProvider需要处理很多业务类型数据的操作,方法成员就会很多,所以在实现XmlBlogProvider时采用了partial class解决。

     DbBlogProvider重写了ProviderBase的 Initialize方法来达到链接字符串、表前缀、字段前缀等的获得,这么设计我觉得用处可能是由于BlogEngine.Net的数据库只有数据存储 功能,用户可能直接把它部署到了已有数据库中,为了和已有数据库中的其它表区分,我们可以指定一个表名前缀。对于DbRoleProvider和 DbMembershipProvider处理方式也是类似。在实现时BlogEngine.Net似乎也考虑了Mono,部分代码出现了对Mono运行 时的判断,但是我没有试过是否可以跨平台安装,感兴趣的朋友可以研究一下!

客户端是如何使用BlogProvider的呢?

     对于MembershipProvider和RoleProvider 的使用这里不再介绍,可以参照一下MSDN文档,BlogEngine.Net也是这么用的。这里主要讲一下BlogProvider的使用问 题,BlogEngine.Net中提供了一个BlogService的静态类,这个类提供给外界一个统一的数据访问接口,它内部的静态方法实现调用 BlogProvider来完成。在BlogService中有一个LoadProviders方法来根据配置文件动态加载BlogProvider:

BlogService

 

最后让我们看一下Web.config的相应配置

BlogProviderConfig

 

MembershipProviderConfig和RoleProviderConfig

 

总结

     BlogEngine.Net数据存储的实现应用了Provider模 式,这个在.Net平台下有很好的支持和案例,这种设计思想很值得借鉴,尤其是BlogService设计的很巧妙,也有一点面向服务的味道。不过在一些 业务逻辑非常复杂,尤其是一些应用到数据库逻辑处理的系统设计时,这种设计可能就无法满足需求了,还要坚持数据的处理离数据越近越好的原则。

     取其精华!

     上一篇:BlogEngine.Net架构与源代码分析系列part2:业务对象——共同的父类BusinessBase

版权声明
作者:Thriving.country
出处:http://thriving-country.cnblogs.com/
本文版权归作者和博客园共同所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接.

[C#]BlogEngine.net 学习笔记(一)

mikel阅读(627)

最近在园子溜达的时候发现了有人说BlogEngine.net 不错, 看了一下,
真的不错, 代码简洁, 功能不少, 真是麻雀虽小, 五脏俱全啊!!!
附上作者的主页:http://blog.madskristensen.dk/(注:他这个主页就是这个BlogEngine.net!!!!)
准备全程跟踪这个BlogEngine.net!!!!
下面写一些笔记:



[Flash]Flash与3D编程探秘(五)- 摄像机旋转和移动

mikel阅读(703)

点此下载程序源文件

 

上一篇我们讨论了关于旋转摄像机的一些知识,在这篇文章中我们将讲解如何定点旋转摄像机,以及把移动和旋转摄像机结合在一起。当我们只运用旋转摄像机时, 在屏幕上我们看到物体围绕着摄像机旋转,动画并不是那么的"3D",不过这个是我们的必经之路,等你完全的明白了旋转这个概念后,我们添加上摄像机在3D 空间移动,那样你就不会觉得乏味了。首先我们来看一个定点旋转摄像机的例子当作热身。

这个例子,我们还是使用我们的小P,不过是很多的小P,这样使我们的场景看起来更加的有层次感。运行我们的程序(效果如下),所有的物体都在围绕摄像机旋转,我想你会有摄像机在不停的旋转的错觉(或者没有…)。

 

定点旋转摄像机

动画制作步骤:

1. 一开始还是一些老步骤,设定原点,建立一个舞台,还有定义我们的摄像机,这些都是前几篇所讨论过的,就不再过多解释了。

// same as usual
var origin = new Object();
origin.x 
= stage.stageWidth/2;
origin.y 
= stage.stageHeight/2;
origin.z 
= 0;
var scene 
= new Sprite();
scene.x 
= origin.x;
scene.y 
= origin.y;
this.addChild(scene);
var camera 
= new Object();
camera.x 
= 0;
camera.y 
= 0;
camera.z 
= 0;
camera.panning 
= 0;
var focal_length 
= 300;

 

2. 下面定义一些常量,比如物体的总数量,PI和物体z间距。

// constants
var MAX_OBJ = 100;
var PI 
= 3.1415926535897932384626433832795;
var DISTANCE_Z 
= 20;                // the distance to your camera

 

3. 下面是初始化所有的物体,我们运用随机数产生小P所在的角度(对于摄像机),递增小P所在点到摄像机的距离(3D空间的),使用三角函数我们就可以得到小P的x和z,我们同样使用随机数产生它的y,最后把它添加到舞台上。

// now create lots of balls around your camera
for (var i = 0; i < MAX_OBJ; i++)
{
    var ball 
= new Sphere();
    ball.angle 
= Math.random()*(0PI*2+ PI*2;            // this is the rotate angle on the xz plane
    ball.dist_center = 140 + (MAX_OBJi)* DISTANCE;     // the distance to your camera
    ball.x_3d = Math.cos(ball.angle) * ball.dist_center;    // then we use trig to get x
    ball.z_3d = Math.sin(ball.angle) * ball.dist_center;     // and z
    ball.y_3d = Math.random()*(240240+ 240;          // now put the ball at random y
    scene.addChild(ball);                                            // add the ball to the collection
}

 

4. 对于每一个物体,我们在摄像机转动角度时刷新它的大小和位置。于是我们下一步写一个函数来达到目的,首先我们要确定小P相对于我们的摄像机的旋转角度。然 后我们根据这个角度和他们之间的垂直距离,算出它到摄像机的x,z和y的距离。最后,还是运用我们之前学过的算法,缩放和移动物体。

// update ball size and position
function update(obj)
{
    
// get the angle relative to your camera panning angle
    var angle = obj.angle  camera.panning;
    var x_pos 
= Math.cos(angle)*obj.dist_center  camera.x;        // use trig calculate the x
    var z_pos = Math.sin(angle)*obj.dist_center  camera.z;        // and z
    var y_pos = obj.y_3d  camera.y;                       // calculate the relative y
    
    
if (z_pos > 0)                                                  // if the ball isin front of the camera
    {
        
if (!obj.visible)                                
            obj.visible 
= true;                                    // make the ball visible anyway
            
        var scale 
= focal_length/(focal_length+z_pos);      // cal the scale of the ball
        obj.x = x_pos*scale;                              // calcualte the x position in a camera view 
        obj.y = y_pos*scale;                             // and y position
        obj.scaleX = obj.scaleY = scale;              // scale the ball to a proper state
    }
    
else
    {
        obj.visible 
= false;
    }
}

 

5. 写一个循环函数,在每一次执行时,递增摄像机的角度,并且刷新舞台上的所有的物体。

function run(e:Event)
{
    camera.panning 
+= 0.01;                           // increase the panning angle
    
    
if (camera.panning > 2*PI)
        camera.panning 
-= 2*PI;
    
if (camera.panning < 1*2*PI)
        camera.panning 
+= 2*PI;
    
    
for (var i = 0; i < scene.numChildren; i++)    // update all the balls on the screen
    {
        update(scene.getChildAt(i));
    }
}
// add loop event listener
this.addEventListener(Event.ENTER_FRAME, run);

注意:

这里我们提到的旋转,都是在保持y不变的情况下,横向旋转摄像机,换句话说,让我们的摄像机绕着y轴旋转,当然同理我们可以写出摄像机围绕着x轴旋转的操作。另外,同时进行上述两种旋转我将在后面的文章里进行介绍。

移动和旋转的组合

那 么现在你已经知道如何横向旋转摄像机,并且前几篇文章中也已经介绍了如何移动摄像机,如果我们把这两个操作结合在一起,那一定很棒。我想你应该觉得不会很 困难,因为我们前面已经把两个分开操作学会了,下面我们所要做的只是把这两种操作组合在一起。来看一个动画,其中发灰的摄像机是运动前的位置,另外一个是 向后(沿摄像机镜头的反方向)移动后位置(当摄像机镜头垂直向上看得时候移动得到),从动画中可以看到,对于摄像机镜头来说,景物的位置是不一样的。

移动加旋转摄像机

 

再来看一个图例,在这个图片中,摄像机沿BO方向向后移动,我们可以看出,摄像机的转角是不变的。那么我们就可以结合摄像机移动的位置和三角函数就可以算出它的x移动量(图中红色实线)和y移动量(图中蓝色实线),进而我们便可以算出对于移动后摄像机而言,小P的x和y。

 

移动和旋转角度的图解

需要注意的是,当你首先旋转摄像机,然后向后或者向前移动摄像机,那么摄像机是沿着摄像机旋转过后的角度运动的,至于移动量和物体到现在摄像机的距离,我们一样可以使用三角函数得到(三角函数!Nice!)。下面我们就看一个应用的例子:

 

定点旋转摄像机,WS前后移动摄像机,AD旋转

动画制作步骤

1. 重复前面的3步。

// constants
var MAX_OBJ = 100;
var PI 
= 3.1415926535897932384626433832795;
var DISTANCE_Z 
= 20;                                                 // the z distance to your camera
// same as usual
var origin = new Object();
origin.x 
= stage.stageWidth/2;
origin.y 
= stage.stageHeight/2;
origin.z 
= 0;
var scene 
= new Sprite();
scene.x 
= origin.x;
scene.y 
= origin.y;
this.addChild(scene);
var camera 
= new Object();
camera.x 
= 0;
camera.y 
= 0;
camera.z 
= 0;
camera.panning 
= 0;
var movement 
= 0;
var focal_length 
= 300;
var pan_left;
var pan_right;
var move_forward;
var move_backward;
// now create lots of balls around your camera
for (var i = 0; i < MAX_OBJ; i++)
{
    var ball 
= new Sphere();
    ball.angle 
= Math.random()*(0PI*2+ PI*2;                // this is the rotate angle on the xz plane
    ball.dist_center = (MAX_OBJi)* DISTANCE_Z;              // the z distance to your camera
    ball.x_3d = Math.cos(ball.angle) * ball.dist_center;        // then we use trig to get x
    ball.z_3d = Math.sin(ball.angle) * ball.dist_center;         // and z
    ball.y_3d = Math.random()*(300300+ 300;              // now put the ball at random y
    scene.addChild(ball);                                                // add the ball to the collection
}

 

2. 下面这个函数是和上面例子中不同的主要部分。首先我们要得到物体和摄像机的x,y和z距离,然后我们使用反三角函数就可以得出物体所在的角度,同时使用勾 股定理得到物体和摄像机的距离(注意y距离为0),同理使用三角函数我们便可以得到在摄像机移动之后物体的x和z。然后再根据物体的x和z对物体进行2D 空间的缩放和移动。

// update ball size and position
function display(obj)
{
    var x_pos 
= obj.x_3d  camera.x;            // calculate the x distance from obbject to the camera
    var y_pos = obj.y_3d  camera.y;            // and y distance
    var z_pos = obj.z_3d  camera.z;            // and z distance
    
    var angle 
= Math.atan2(z_pos, x_pos);                    // caculate the relative angle
    
// now get the actual object radius around camera
    var radius = Math.sqrt(z_pos*z_pos + x_pos*x_pos);
    
    x_pos 
= Math.cos(angle+camera.panning)*radius;    // get the x position after panning
    z_pos = Math.sin(angle+camera.panning)*radius;     // and y position
    
    
if (z_pos > 0)                                                    // if the ball isin front of the camera
    {
        
if (!obj.visible)                                
            obj.visible 
= true;                                      // make the ball visible anyway
            
        var scale 
= focal_length/(focal_length+z_pos);  // cal the scale of the ball
        obj.x = x_pos*scale;                                     // calcualte the x position in a camera view 
        obj.y = y_pos*scale;                                    // and y position
        obj.scaleX = obj.scaleY = scale;                     // scale the ball to a proper state
    }
    
else
    {
        obj.visible 
= false;
    }
    
    txt_z.text 
= int(camera.z)+"";
    txt_panning.text 
= Number(camera.panning*(180/Math.PI)).toFixed(1+ "";
}

 

3. 写一个循环函数,在每一次执行时刷新舞台上的所有的物体。

function run(e:Event)
{
    
if (camera.panning > 2*PI)
        camera.panning 
-= 2*PI;
    
if (camera.panning < 1*2*PI)
        camera.panning 
+= 2*PI;
    
    
for (var i = 0; i < scene.numChildren; i++)                    // update all the balls on the screen
    {
        display(scene.getChildAt(i));
    }
}

 

4. 下面设置一些键盘相应事件,使用WS我们可以使摄像机前进和后退,AD旋转我们的摄像机。键盘事件我们在前面提到过,就不多说了,如果有什么问题的话可以查看一下前面的例子。

function run(e:Event)
{
    
if (camera.panning > 2*PI)
        camera.panning 
-= 2*PI;
    
if (camera.panning < 1*2*PI)
        camera.panning 
+= 2*PI;
    
    
for (var i = 0; i < scene.numChildren; i++)             // update all the balls on the screen
    {
        display(scene.getChildAt(i));
    }
}
function key_down(e:KeyboardEvent):
void
{
    
if (e.keyCode == 65)
        pan_left 
= true;
    
if (e.keyCode == 68)
        pan_right 
= true;
    
if (e.keyCode == 87)
        move_forward 
= true;
    
if (e.keyCode == 83)
        move_backward 
= true;
}
function key_up(e:KeyboardEvent):
void
{
    
if (e.keyCode == 65)
        pan_left 
= false;
    
if (e.keyCode == 68)
        pan_right 
= false;
    
if (e.keyCode == 87)
        move_forward 
= false;
    
if (e.keyCode == 83)
        move_backward 
= false;
}
function key_response(e:Event):
void
{
    
if (pan_left)
        camera.panning 
+= 0.015;                    // increase the panning angle
    if (pan_right)
        camera.panning 
-= 0.015;                    // decrease the panning angle
    if (move_forward)
    {
        movement 
= 20;
    }
    
if (move_backward)
    {
        movement 
= 20;
    }
    
if (move_forward || move_backward)
    {
        camera.x 
+= Math.sin(camera.panning)*movement;
        camera.z 
+= Math.cos(camera.panning)*movement;
    }
}
// add loop event listener
this.addEventListener(Event.ENTER_FRAME, run);
this.addEventListener(Event.ENTER_FRAME, key_response);
stage.addEventListener(KeyboardEvent.KEY_DOWN, key_down);
stage.addEventListener(KeyboardEvent.KEY_UP, key_up);

 

注意:

我们在这两个例子里,并没有涉及到物体层次,当然如果你在开发的时候,最好加上一个层次排序。这个算法我们在第一篇文章里就已经实现,你可以试着把那个函数添加到这两个例子里。

建议:

在开发的时候,我建议你使用面向对象的书写方式,这样便于你的管理。我一直没有使用OO的写法,是因为我不想给读者的阅读造成不必要的困惑,你可以试着把 例子中的代码写成类,然后从.fla文件调用。例如你可以我们例子中的小P写成一个类,它具有x_3d,y_3d,z_3d和其他一些属性。

 

点此下载程序源文件


作者:Yang Zhou
出处:http://yangzhou1030.cnblogs.com
感谢:Yunqing
本文版权归作者和博客园共有,转载未经作者同意必须保留此段声明。请在文章页面明显位置给出原文连接,作者保留追究法律责任的权利。