月度归档:2011年03月

游戏开发中常用的设计模式

游戏开发中常用的设计模式
2009-02-23 01:43

使用设计模式来提高程序库的重复利用性是大型程序项目开发必须的。但是在“四人帮”的设计模式概述中提到了23种标准设计模式,伍但难以记住,而且有些设计模式更多的适用于应用程序开发,对游戏项目引擎设计并没有很多的利用价值。根据经验,精挑细选后,笃志在这里记录一些自认为有利用价值的设计模式,以便之后自己设计时使用。

一:观察者Observer

观察者的设计意图和作用是: 它将对象与对象之间创建一种依赖关系,当其中一个对象发生变化时,它会将这个变化通知给与其创建关系的对象中,实现自动化的通知更新。

游戏中观察者的适用环境有:

1:UI控件管理类。当我们的GUI控件都使用观察者模式后,那么用户的任何界面相关操作和改变都将会通知其关联对象-----我们的UI事件机。

2:动画管理器。很多时候我们在播放一个动画桢的时候,对其Frame有很大兴趣,此时我们设置一个FrameLister对象对其进行监视,获得我们关心的事件进行处理是必须的。

观察者伪代码:

//-------------------------------------------------------------------?-----------------------------------

// 被观察对象目标类

Class Subject

{

// 对本目标绑定一个观察者 Attach( Observer );

// 解除一个观察者的绑定 DeleteAttach( Observer );

// 本目标发生改变了,通知所有的观察者,但没有传递改动了什么

Notity()

{

For ( …遍历整个ObserverList …)

{ pObserver ->Update(); }

}

// 对观察者暴露的接口,让观察者可获得本类有什么变动GetState();

}

//-------------------------------------------------------------------------------------------------------

// 观察者/监听者类
Class Observer

{

// 暴露给对象目标类的函数,当监听的对象发生了变动,则它会调用本函数通知观察者

Void Update ()

{

pSubject ->GetState(); // 获取监听对象发生了什么变化

TODO:DisposeFun(); // 根据状态不同,给予不同的处理

}

}

//-------------------------------------------------------------------------------------------------------

非程序语言描述:

A是B的好朋友,对B的行为非常关心。B要出门,此时A给了B一个警报器,告诉B说:“如果你有事,立刻按这个警报器告诉我。”。结果B在外面遇上了麻烦,按下警报器(Update()),B就知道A出了事,于是就调查一下B到底遇到了什么麻烦(GetState()),当知道B原来是因为被人打了,于是立刻进行处理DisposeFun(),派了一群手下帮B打架。

当然关心A的人可以不止一个,C,D可能也对A很关心,于是A这里保存一个所有关心它的人的链表,当遇到麻烦的时候,轮流给每个人一份通知。

二:单件模式Singleton
单件模式的设计意图和作用是: 保证一个类仅有一个实例,并且,仅提供一个访问它的全局访问点。

游戏中适用于单件模式的有:

1:所有的Manger。在大部分的流行引擎中都存在着它的影子,例如SoundManager, ParticeManager等。

2:大部分的工厂基类。这一点在大部分引擎中还是见不到的,实际上,我们的父类工厂采用唯一实例的话,我们子类进行扩展时也会有很大方便。

单件模式伪代码:

//-------------------------------------------------------------------------------------------------------

{

Static MySingleton; // 单件对象,全局唯一的。

Static Instance(){ return MySingleton; } // 对外暴露接口

}

//-------------------------------------------------------------------------------------------------------

三:迭代器Iterator

迭代器设计意图和作用是: 提供一个方法,对一个组合聚合对象内各个元素进行访问,同时又不暴露该对象类的内部表示。

游戏中适用于迭代器模式的有: 因为STL的流行,这个设计已经广为人知了,我们对任何形式的资源通一管理时,不免会将其聚合起来,或者List,或者Vector,我们都需要一个对其进行访问的工具,迭代器无疑是一个利器。

迭代器伪代码:

//--------------?----------------------------------------------------------------------------------------

// 迭代器基类

Class Iterator

{

Virtual First();

Virtual Next();

Virtual End();

Virtual CurrentItem(); // 返回当前Item信息

}

//-------------------------------------------------------------------------------------------------------

// 聚合体的基类

Class ItemAggregate

{

Virtual CreateIterator(); // 创建访问自身的一个迭代器

}

//-----------------?-------------------------------------------------------------------------------------

// 实例化的项目聚合体

Class InstanceItemAggregate : public ItemAggregate

{

CreateIterator(){ return new InstanceIterator(this); }

}

//-------------------------------------------------------------------------------------------------------

四:访问者模式Visitor:

访问者设计意图和作用是: 当我们希望对一个结构对象添加一个功能时,我们能够在不影响结构的前提下,定义一个新的对其元素的操作。(实际上,我们只是把对该元素的操作分割给每个元素自身类中实现了而已)

漸戏中适用于访问者模式的有: 任何一个比较静态的复杂结构类中都适合采用一份访问者。这里的“比较静态的复杂结构类”意思是,该结构类中元素繁多且种类复杂,且对应的操作较多,但类很少进行变化,我们就能够将,对这个结构类元素的操作独立出来,避免污染这些元素对象。

1:例如场景管理器中管理的场景节点,是非常繁多的,而且种类不一,例如有Ogre中的Root, Irrchit中就把摄象机,灯光,Mesh,公告版,声音都做为一种场景节点,每个节点类型是不同的,虽然大家都有共通的Paint(),Hide()等方法,但方法的实现形式是不同的,当我们外界调用时需要统一接口,那么我们很可能需要需要这样的代码

Hide( Object )

{ if (Object == Mesh) HideMesh(); if (Object == Light) HideLight(); … }

此时若我们需要增加一个Object新的类型对象,我们就不得不对该函数进行修正。而我们可以这样做,让Mesh,Light他们都继承于Object,他们都实现一个函数Hide(),醣么就变成

Mesh::Hide( Visitor ) { Visitor.Hide (Mesh); }

Light::Hide(Visitor ){ Visitor.Hide (Light); }

我们在调用时只需要Object.Hide(Visitor){ return Visitor.Hide(Object); }

这样做的好处,我们免去了对重要函数的修正,Object.Hide(Visitor){}函数我们可以永久不变,但是坏处也是很明显的,因为将方法从对象集合结构中抽离出来,就意味着我们每增加一个元素,它必须继承于一个抽象的被访问者类,实现其全部函数,这个工作量很大。

所以,访问者是仅适合于一个装载不同对象的大容器,但同时又要求这个容器的元素节点不应当有大的变动时才使用。另外,废话一句,访问者破坏了OO思想的。

访问者伪代码:

//-----------------------------------------------------------------------?-------------------------------

// 访问者基类

Class Visitor

{

Virtual VisitElement( A ){ … }; // 访问的每个对象都要写这样一个方法

Virtual VisitElement( B ){ … };

}

// 访问者实例A

Class VisitorA

{

VisitElement( A ){ … }; // 实际的处理函数

VisitElement( B ){ … }; // 实际的处理函数

}

// 访问者实例B

Class VisitorB

{

VisitElement( A ){ … }; // 实际的处理函数

VisitElement( B ){ … }; // 实际的处理函数

}

// 被访问者基类

Class Element

{

Virtual Accept( Visitor ); // 接受访问者

}

// 被访问者实例A

Class ElementA

{

Accecpt( Visitor v ){ v-> VisitElement(this); }; // 调用注册到访问者中的处理函数

}

// 被访问者实例B

Class ElementB

{

Accecpt( Visitor v ){ v-> VisitElement(this); }; // 调用注册到访问者中的处理函数

}

//-------------------------------------------------------------------------------------------------------

五:外观模式Fa?ade

外观模式的设计意图和作用是: 将用户接触的表层和内部子集的实现分离开发。实际上,这个模式是个纸老虎,之后我们看伪代码立刻就会发现,这个模式实在用的太频繁了。

游戏中需要使用外观模式的地方是: 这个非常多了,举几个比较重要的。

1:实现平台无关性。跨平台跨库的函数调用。

2:同一个接口去读取不同的资源。

3:硬件自动识别处理系统。

外观模式伪代码

//-------------------------------------------------------------------------------------------------------

// 用户使用的接口类

Class Interface

{

// 暴露出来的函数接口函数,有且仅有一个,但内部实现是调用了两个类

Void InterfaceFun()

{
// 根据某种条件,底层自主的选择使用A或B的方法。用户无须关心底层实现

If ( XXX )

{

ActualA->Fun();

}

Else

{

ActualB->Fun();

}

};

}

// 实际的实现,不暴露给用户知道

Class ActualA

{

Void Fun();

}

// 实际的实现,不暴露给用户知道

Class ActualB

{

Void Fun();

}

怎么样,纸老虎吧,看起来很高深摸测的命名而已。

//----------------------------------------------------------------------------------------------------?--

六:抽象工厂模式AbstractFactory

抽象工厂的设计意图和作用是: 封装出一个接口,这个接口负责创建一系列互相关联的对象,但用户在使用接口时不需要指定对象所在的具体的类。从中文命名也很容易明白它是进行批量生产的一个生产工厂的作用。

游戏中使用抽象工厂的地方有: 基本上任何有批量的同类形式的子件地方就会有工厂的存在。(补充一句:下面代码中的ConcreteFactory1实例工厂就是工厂,而抽象工厂仅仅是工厂的一个抽象层而已。)

1:例如,在音频方面,一个音频的抽象工厂派生出不同的工厂,有音乐工厂,音效工厂。音效工厂中又有一个创建3D音效节点的方法,一个创建普通音效节点的方法。最终用户只需要SoundFactory->Create3DNode( pFileName ); 就可以创建一个节点了。

2:场景对象。

3:渲染对象。

4:等等……

工厂与单件,管理器Manager关系一定是非常紧密的。

抽象工厂伪代码:

//-------------------------------------------------------------------------------------------------------

class AbstractProductA {}; // 抽象的产品A基类
class AbstractProductB {}; //抽象的产品B基类

// 抽象工厂基类
class AbstractFactory
{
public:
virtual AbstractProductA* CreateProductA() = 0 ; // 创建ProductA
virtual AbstractProductB* CreateProductB() = 0 ; // 创建ProductB
} ;

class ProductA1 : public AbstractProductA {}; // 产品A的实例1
class Produ?tA2 : public AbstractProductA {}; // 产品A的实例2

class ProductB1 : public AbstractProductB {}; // 产品B的实例1
class ProductB2 : public AbstractProductB {}; // 产品B的实例2

// 实例工厂1

class ConcreteFactory1 : public AbstractFactory
{
virtual AbstractProductA* CreateProductA() { return new ProductA1() ; }
virtual AbstractProductB* CreateProductB() { return new ProductB1() ; }
static ConcreteFactory1* Instance() { }    // 实例工厂尽量使用单件模式
} ;

// 实例工厂2

class ConcreteFactory2 : public AbstractFactory
{
virtual Ab?tractProductA* CreateProductA() { return new ProductA2() ; }
virtual AbstractProductB* CreateProductB() { return new ProductB2() ; }
static ConcreteFactory2* Instance() {} // 实例工厂尽量使用单件模式
} ;

}

//-------------------------------------------------------------------------------------------------------

客户端代码:

Void main()
{
AbstractFactory *pFactory1 = ConcreteFactory1::Instance() ;
AbstractProductA *pProductA1 = pFactory1->CreateProductA() ;
? AbstractProductB *pProductB1 = pFactory1->CreateProductB() ;
AbstractFactory *pFactory2 = ConcreteFactory2::Instance() ;
AbstractProductA *pProductA2 = pFactory2->CreateProductA() ;
AbstractProductB *pProductB2 = pFactory2->CreateProductB() ;
}

//-------------------------------------------------------------------------------------------------------

=======================================================

Flash中oop的设计模式

人问我flash的as应该怎么写,我可以很负责任地告诉他,想怎么写就怎么写,因为as以及flash内部的构成模式决定了它的高度自由化。理论上来说,用按钮的on事件,加上stop(),play(),gotoAndStop(),gotoAndPlay(),就可以实现一个flash里大部分的逻辑关系,而且源代码简单易懂。但是大多数人不会这么做,是因为这种方法实在太让人敬佩。稍有常识的程序员都会知道面对对象与面对过程的区别。Flash 的编程虽然只是以脚本的形式出现,并且还很不完善,比如,没有多继承,但已经初步体现了oop的思想。这篇文章现在总结一下flash中面对对象的设计模式问题,以及一些自创的思路。

设计模式是美国一位建筑大师(同时也是信息工程师,画家,机械工程师…的)克里斯蒂安.亚历山大首先提出来的,很快被软件界的技术员们所接受推广,成为软件工程里至高无上的法则之一(有兴趣的人可以找他的《建筑的永恒之道》一书看看,相信会受益非浅)。简单地说就是在面对对象的基础上,包括面对对象,把要设计的整体的各个部分模式化,层次化,细粒度化,高度复用化,可控化,人性化。其中至高无上的原则是建立在需求的基础之上,也就是说,无论做什么,人的需求要放在第一位考虑,从这个角度考虑整个系统是否足够合理。这门学问是非常有趣的,尤其在flash中,可以应用到很多很好玩的实例中去。下面我按照一些通用的设计模式,举例说明,有错误的地方,敬请高手指正:

1.抽象工厂模式(Abstract Factory)食堂里吃的东西很多,而我只想吃一样,那么食堂这个概念对我来说就是个抽象工厂,每个窗口可以看成它的一个具体实现,我要做的就是,去食堂,找到那个窗口,从窗口里买我要吃的东西。
举例:flash前台与asp后台的交互,访问某个动态页面,从数据库里取出需要的数据,通常的做法是在后台就把数据集解析成xml字符串,再送给swf。每个业务逻辑模块,所取出的数据结构,也就是xml的结构是不一样的,我们要针对各个具体的业务逻辑,对相应的xml字符串解析,转换成可供显示的数组。也要把flash里文本输入的内容转换成 xml字符串,提交给后台也面
AbstractFactory.as

程序代码 程序代码
//抽象工厂的接口
Interface AbstractFactory{
//生成xml解析工厂的具体实现
function createXmlParseFactory();
}

XMLParserGetFactory.as

程序代码 程序代码
//生成解析读入的xml的对象的工厂
class XMLParserGetFactory implements AbstractFactory.{
var xmlParser;
function XMLParserGetFactory(str:String){
//生成解析器的具体实现,在后面会提到
}
function createXmlParser(){
return xmlParser;
}
}

XMLParserPostFactory.as

程序代码 程序代码
//生成解析输出的xml的对象的工厂
class XMLParserPostFactory implements AbstractFactory.{
var xmlParser;
function XMLParserPostFactory(str:String){
//生成解析器的具体实现
}
function createXmlParser(){
return xmlParser;
}
}

这样,我们读入某个xml字符串时,在onLoad里面加入

程序代码 程序代码
//生成对留言板的留言列表解析的工厂
var xmlParser=new XMLParserGetFactory(“xmlParseGuestbookList”)
xmlParser= XMLParserGetFactory. createXmlParser()

备注:抽象工厂模式是软件工程里最常用的设计模式之一,实现过程在于,需要某个类的实例时,通过某个工厂创建,而不是直接创建,坦白地说,它加大了开发工作量,但是对程序的层次性变得分明和降低耦合度有极大帮助。

2.生成器模式(builder)还是那个说法,我要吃东西就去相应的食堂窗口,但我不能吃食堂窗口,窗口里的东西也许不少,我要跟师傅说,要这个,这个,还有这个。
举例:我已经建立了 xml解析器的工厂,现在要返回解析器本身,就让工厂创建,返回给我。
XMLParserGetFactory.as

程序代码 程序代码
//生成解析读入的xml的对象的工厂
class XMLParserGetFactory implements AbstractFactory.{
var xmlParser;
function XMLParserGetFactory(str:String){
//如果要求留言板列表解析器,就生成一个
if(str==” xmlParseGuestbookList”){
xmlParser=new xmlParserGuestbookList();
}
}
function createXmlParser(){
//返回所要求的解析器
return xmlParser;
}
}

我到了食堂窗口,如果师傅跟那儿抽烟,我还是吃不着东西。我说:师傅,打饭!师傅才会完成打饭这一动作。这是工厂方法模式,抽象工厂的实现通常用工厂方法模式来完成。
举例:还是上一条,我本来想用一句话带一个参数就实现具体xml解析器的实现,无奈构造函数没有返回值,所以必须用

程序代码 程序代码
xmlParser= XMLParserGetFactory. createXmlParser(xml,arrayID,arrayTitle);

实现。

3.抽象工厂模式,生成器模式和工厂方法模式需要灵活应用。 我前面一个人买了一条巨大的鸡腿,我说我也要一条,师傅说,就这一条
举例:单件模式的应用是相当广泛的,它确保每个实例在全局范围内只被创建一次,我们flash里的mc大多数是单件。内核里的核心组件也只是单件,比如我的消息映射列表(见后)。
按照单件模式的严格定义,应该让类负责保存它的唯一实例。但是我在Flash里还想不到怎么实现这一点,或者实现它的意义所在,但另外一点我们可以做到,就是在全局范围内只提供该对象的唯一访问点。这可以由层次关系做到,把对该对象的访问具体实现全部封装在下层,只给上层提供唯一的访问点(原因是,上层不知道这个单件的具体信息,比如路径)。
看我内核文件的一部分:

程序代码 程序代码
Core.as
//内核
class Core {
var strucGlobalParam:ConfigVariables;
//站点信息
var xmlConfig:XML;
//站点信息的xml化对象
var ArrayStructureInitial:Array;
//用来提供给loadObject对象的数组
var ArrayForBtn:Array;
//用来初始化导航条组件的数组
var objInitial:loadObject;
//读取影片的对象
var objMessageMap:MessageMap;
//消息映射组件
……
}

这是我的内核类也就是全站最核心类的数据结构。里面的数据只有通过下层的BasicMovie,OriginalFunctionObject等类(见后)直接访问。
备注,核心思想是,确保只有一个。

5.原型模式(protoType)到小炒窗口,看前面的哥们炒的青椒炒肉不错的样子。“师傅,我也要这样的。”
举例:这对flash的用户来说再熟悉不过了,我们经常用duplicateMovieClip()和
attachMovie()这两个函数。按照一个原型复制相应的实例,各自执行自己的动作。在我的blog列表,导航条的生成。。几乎用得到多项数据的地方就要用原型模式。

6.责任链模式
食堂里厨房最远的窗口没有白菜了,要告诉厨房,快送过来。
责任链模式:一个窗口一个窗口地传话,一直传到食堂,食堂一看不妙,赶快做好送过去。
中介者模式:专门派一个人负责传话,任何窗口没菜了,就要这个人赶快去厨房催。
观察者模式:厨房那边派一个盯着,看哪个窗口没菜了就开始大声嚷嚷。
举例:之所以要把这三个设计模式放在一块儿,是因为我在我的站里面结合这三者建立了一个好玩的东西,可以说是我的网站的核心所在。它解决了我的flash里面各个mc的通信问题。
比如,影片A放完了,要通知影片B开始播放,直接的做法是在A的最后一帧,写从A到B的相对路径或B的绝对路径,让B play()。这样做A和B的耦合性是相当高的,也就是说,相互依赖程度太高。运用设计模式的解决方案如下:

程序代码 程序代码
MessageMap.as
//消息映射类
class MessageMap extends Object {
var Message:String;
var MessageWatcher:Function;
var Target;
var MessageList:Array;
var Num_Msg:Number;
function MessageMap() {
Num_Msg = 0;
MessageList = new Array();
Message = "HANG_UP";
MessageWatcher = function (prop, oldVar, newVar, Param) {
for (var i = 0; i<Num_Msg+1; i++) {
if (newVar == MessageList[0]) {
MessageList[1].apply(MessageList[3], MessageList[2]);
if (!MessageList[4]) {
MessageList.splice(i, 1);
Num_Msg--;
i-=1;
}
}
}
};
this.watch("Message", MessageWatcher, "test");
}
function SendMessage(Msg:String, mc:MovieClip) {
Message = Msg;
}
function UpdateMessageMap(Msg:String, objFunction:Function, ArrayParam:Array, objRefer,IsMultiUsed:Boolean) {
MessageList[Num_Msg] = new Array();
MessageList[Num_Msg][0] = new String();
MessageList[Num_Msg][0] = Msg;
MessageList[Num_Msg][1] = new Function();
MessageList[Num_Msg][1] = objFunction;
MessageList[Num_Msg][2] = new Array();
MessageList[Num_Msg][2] = ArrayParam;
MessageList[Num_Msg][3] = objRefer;
MessageList[Num_Msg][4] = IsMultiUsed;
Num_Msg++;
}
function DeleteMessageMap(objRefer) {
for (var i = 0; i<Num_Msg; i++) {
if (MessageList[2] == objRefer) {
MessageList.splice(i, 1);
Num_Msg--;
}
}
}
}
class SubTemplateMovie extends BaseMovie {
var MovieRemoveFunction:Function;
function SubTemplateMovie() {
this.stop();
MovieStartFunction = function () {
Lock();
this.play();
};
MovieEndFunction = function () {
Lock();
this.play();
};
MovieRemoveFunction = function () {
this.stop();
SendMsg("SUB_TEMPLATE_REMOVED", this);
_parent.unloadMovie();
};
MovieMainFunction = function () {
stop();
SendMsg("SUB_TEMPLATE_OPEN", this);
};
UpdateMessage("LOADING_BAR_OVER", MovieStartFunction, null, this, false);
UpdateMessage("BACK_TO_INDEX", MovieEndFunction, null, this, false);
}
}

整个消息映射类相当于一个中介者,内部生成一个观察器,一旦触发消息,以责任链的方式执行。

9.桥接模式(Bridge)菜太淡,不合有些人的胃口,所以要求食堂的师傅,专门开一个窗口,专门在做好的菜里多加些辣椒。
我在自己的站里运用了桥接模式:所有的影片都继承自我定义的BasicMovie 类(BasicMovie继承自MovieClip类),但是在四个下级栏目的影片里,需要定义相同的方法和事件来响应消息,BasicMovie没有这些函数,不符合要求,这时候,在四个影片里都写一遍是愚蠢的,我又写了一个SubTemplateMovie类继承自BaseMovie,里面加进一些通用的方法,然后四个下级模板影片都继承它,这样大大简化了后期开发。

BasicMovie.as

程序代码 程序代码
//基类影片
/所有影片的原始类,一切影片的父类都继承此类而来
class BaseMovie extends MovieClip {
var isLocked:Boolean;
//初始类开始影片函数
var MovieStartFunction:Function;
//初始类影片主功能函数
var MovieMainFunction:Function;
//初始类结束影片函数
var MovieEndFunction:Function;
var GlobalParam
//初始类构造函数
function BaseMovie() {
}
//
//发送消息
function SendMsg(Msg:String, Mc:MovieClip) {
_root.objCore.objMessageMap.SendMessage(Msg, Mc);
}
//添加消息映射
function UpdateMessage(Msg:String, MsgMapFunction:Function, ArrayParam, obj, IsMultiUsed) {
_root.objCore.objMessageMap.UpdateMessageMap(Msg, MsgMapFunction, ArrayParam, obj, IsMultiUsed);
}
//删除消息映射
function DeleteMessage(obj) {
_root.objCore.objMessageMap.DeleteMessageMap(obj);
}
function GetGlobalParam() {
GlobalParam=_root.objCore.strucGlobalParam;
}
}

SubTemplateMovie.as

程序代码 程序代码
//下级模板影片类
class SubTemplateMovie extends BaseMovie {
var MovieRemoveFunction:Function;
function SubTemplateMovie() {
this.stop();
MovieStartFunction = function () {
Lock();
this.play();
};
MovieEndFunction = function () {
Lock();
this.play();
};
MovieRemoveFunction = function () {
this.stop();
SendMsg("SUB_TEMPLATE_REMOVED", this);
_parent.unloadMovie();
};
MovieMainFunction = function () {
stop();
SendMsg("SUB_TEMPLATE_OPEN", this);
};
UpdateMessage("LOADING_BAR_OVER", MovieStartFunction, null, this, false);
UpdateMessage("BACK_TO_INDEX", MovieEndFunction, null, this, false);
}
}

我要一碗汤,但是只有纸饭盒,还没勺,所以食堂的师傅给了我一次性的汤碗和勺,这叫适配器。
适配器解决的是某一个类的对外接口不合用的问题,可能是参数或者返回值类型不符等问题造成的,这时候我们需要在工作对象和这个类之间加一层间接的层次。
这个模式我在底层的数据交换层用过。我说过,flash和asp.net之间交换数据全以xml为载体。返回xml在底层只有三层,数据库操作,数据操作,数据显示,由数据操作层返回给数据显示层一个xml字符串就可以了。然后我就遇到一个小问题,在另一方面,我需要提交数据到数据库,也是提交一个xml字符串,但是我需要数据库里对应的表的数据集的xml表现形式的xsd验证!(一口气说完,差点没憋死)。就是说我至少需要取出这个表里的一条记录,问题在于,我封装的类从来只返回xml,没有返回xsd的。解决办法就是适配器,新建一个项目,加了一层专用于获得xml验证格式,这样就完成了不同接口之间的转换。
备注:适配器和桥接很象,都是在已有类不符合要求的时候,加入一层间接的元素以达到目的。不同的是适配器是解决不兼容接口之间的转换,桥接一般不涉及这个问题,只是完成一个一对多的转换。

11.外观模式(Facade)每天都要去食堂,每个人去不同的窗口吃不同的菜,很累,今天全寝室推举猴子去打饭:
你吃这个,三两饭,我吃那个,五两饭,所有人都只跟猴子一个人交涉,食堂所有的师傅也只见猴子一个人。
举例:这个模式在程序的上下层的通信之间可以应用得十分广泛。Asp的每个模块要去不同的数据,访问数据库的不同表,就要跟不同的下层数据访问组件打交道。就是说,每个mc模块必须知道,我要去哪个具体的数据访问组件取数据。每个模块要维持自己的一个,至少是字符串。
如果运用外观模式。我们可以让所有的需要数据交互的mc访问同一个aspx页面,比如getStrXml.aspx。只要传送一个标示符,就可以通知这个唯一的取数据的页面,访问哪个下层组件获取数据。下层组件不知道哪个mc要求数据,mc也不知道数据的具体来源,这样,上下层之间互相都显得不透明。这就降低了耦合度。

12.代理模式(Proxy)可能我们不是每个人每天都想吃饭,所以我们要求猴子每天中午必须在寝室,如果我们要吃,他就去,如果我们都不吃,他爱干嘛干嘛。
举例:这恐怕是每个人在flash里都会无意中用到的模式。比如,一个网站,它的下级栏目不用在整个网站初始化的时候一开始就读进来,但是我们要确保,在浏览者想看并且点击导航条上的某个按钮时,能够正确地读进相应的影片文件,前提是,我们必须在内部保留一个索引,可以称作代理。通常是一个空mc

13.策略模式(strategy)我每天先在食堂找座位,再打饭,再打菜,再买杯酸奶。这已经模式化。要是食堂有服务员,我也会要他这么做。
举例,策略模式是把一系列的算法封装起来,形成一个类。这个模式几乎是随时随地都可以整合到别的模式里去的,我的那一堆xml解析器实际上就是策略模式的应用,这个模式还应用到我网站的下层,因为flash提交给aspx页面的数据也是xml字符串,下层模块也需要相应的解析算法。同样的,我把对xml的解析封装进了一个类。

程序代码 程序代码
//Cs文件里的解析函数
Class DataModel.BlogMsgs{

Public DataSet parseXML(string strXml){
DataSet ds=new DataSet();
//。。把xml装载到DataSet 里
Return ds
}

}

东西不够吃?给你摆20面镜子~
师傅,东西还是只有一份。。。
关于这个模式十分抱歉,我暂时还没想到在flash里面的实现。需要举例说明的是,浏览器的机制是,在有大量文字的英文文档里,相同的字母共享一个 Flyweight,在内存里其实只占一份空间,然后在文档不同的地方显示,这样对于大量细粒度的效果来说,可以节省很多资源。有哪位同志想到了请一定告诉我,不胜感激。

15.访问者模式(Visitor)只要愿意,我随时都可以跑到哪个窗口打要吃的东西,前提是,我必须跑这一趟。
举例:我说过,我的所有mc都继承自BasicMovie这个类,但不是我的所有mc都要从后来获取数据库数据。获取数据库数据所要访问的信息,比如ip,路径,文件保存在配置文件里,初始化的时候读入内核,并且只有内核那里有一份。在BasicMovie里加入对这些全局变量的引用是不合适的,因为只有少数mc要用到,而且由于某些原因我无法再使用桥接模式(我已经有了SubTemplateMovie,不能多继承),所以我用了访问者模式。

BasicMovie.as

程序代码 程序代码
//获取全局变量
function GetGlobalParam() {
GlobalParam=_root.objCore.strucGlobalParam;
}

如果上级mc不执行这个函数,是不能获取全局变量的,如果要用,就执行。
也就是说,需要的时候,我去访问它。
备注:声明一个visit操作,使得访问者可以正确访问需要的类。

16.状态模式(state)我今天想吃面,师傅问我:要什么料?西红柿鸡蛋,排骨还是牛肉?
举例:状态模式是指将对象当前的某些状态局部化,当对象改变状态时,看起来好像改变了类。例子还是我的滚动条。如果要滚动的是文本框,就要引用一个TextField的Scroll, maxscroll属性,如果是mc,引用的是_y,_height属性,我用一个参数将二者区分,由一个if语句控制,让滚动条可以自由区别状态。
另外一个解决方案是定义ScrollBar的不同子类,这两者本质区别不大,在状态比较多时,可能要维持一个庞大的if算法,这样就用生成子类的方法比较好。

ScrollBar.as

程序代码 程序代码
//滚动条组件
function BindTo(mc,type:String,intMcHeight:Number,yinitial:Number){
ScrollType=type;
if(type=="TXT"){
scrollTxt=mc;
}
if(type=="MC"){
initialY=yinitial;
McHeight=intMcHeight;
scrollMc=mc;
}
}
function Scroll() {
if(ScrollType=="TXT")
this.onEnterFrame = function() {
scrollTxt.scroll = scrollTxt.maxscroll*mcBlock._y/(BgLength-BlockLength*3/2)
};
if(ScrollType=="MC"){
this.onEnterFrame=function(){
if(scrollMc._height>McHeight){
scrollMc._y=initialY-(scrollMc._height-McHeight)*mcBlock._y/(BgLength-BlockLength*3/2)}
}
}
}
[code][/code]
备注:这也是常见模式,在flash的逻辑控制里尤其随处可见

17.装饰模式(Decorator)在食堂吃饭,没筷子怎么行?我是从来不带饭盆的。师傅很人性化,每个窗口都放着一大把筷子,随用随拿。
这个模式如果用好,有的地方可以很省力。比如,我网站里的滚动条:

ScrollBar.as
[code][/code]
//滚动条组件
class ScrollBar extends BaseMovie {
var BgLength:Number;
var BlockLength:Number;
var mcBlock:MovieClip
var Width:Number;
var ScrollType;
var scrollTxt:TextField;
var scrollMc:MovieClip;
var McHeight:Number
var initialY:Number
function ScrollBar() {
}
function InitialScrollBar(BgLength, BlockLength) {
this.BlockLength = BlockLength;
this.BgLength = BgLength;
}
function BindTo(mc,type:String,intMcHeight:Number,yinitial:Number){
ScrollType=type;
if(type=="TXT"){
scrollTxt=mc;
}
if(type=="MC"){
initialY=yinitial;
McHeight=intMcHeight;
scrollMc=mc;
}
}
function Scroll() {
if(ScrollType=="TXT")
this.onEnterFrame = function() {
scrollTxt.scroll = scrollTxt.maxscroll*mcBlock._y/(BgLength-BlockLength*3/2)
};
if(ScrollType=="MC"){
this.onEnterFrame=function(){
if(scrollMc._height>McHeight){
scrollMc._y=initialY-(scrollMc._height-McHeight)*mcBlock._y/(BgLength-BlockLength*3/2)}
}
}
}
function ScrollMc() {
}
function StopScroll() {
this.onEnterFrame=null;
}
function Reset(){
mcBlock._y=0;
}
}

核心函数是BindTo(),把这个滚动条的实例绑定到某个动态文本框或者某个mc上,就可以实现滚动。
备注:装饰模式的思想是,在不影响其他对象的情况下,以动态,透明的方式给单个对象添加职责。

18.组合模式(composite)我中午吃六两饭,猪肉炖粉条,辣子鸡,鱼丸,咸鸭蛋,外加两杯酸奶(猪!)
这些东西都是对象,他们共同组成了我的午饭。
举例:应该说在Flash里组合模式是无处不在的,因为只要还有mc的嵌套,就有组合模式存在。几个mc装在一个mc里,这个装载用的mc称作容器。
但是就这么说,恐怕没人会重视这个模式,因为不管理不理解他我们都在用。他的确有很多种实现方式,我的方式之一是这样的。

blog.as

程序代码 程序代码
//我的Blog
class Blog extends BaseMovie {
//blog第一界面,包括日记列表,日历,最近留言
var mcBlogList: mcBlogList;
//blog第二界面,包括日记全文,回复,对该日记的留言。
var mcBlogDairy:MovieClip;
var currentState:String;
var currentDairyID:Number;
function blog(){
}
}

mcBlogList.as

程序代码 程序代码
//blog第一界面
class mcBlogList extends BaseMovie {
//最近留言
var recentMsgs:blogMsgsSC;
//日记列表
var blogList:BlogList;
//日历
var calendar:CalenderForBlog;

mcblogDairy.as
//blog第二界面
class mcBlogDairy extends BaseMovie {
//日记全文显示
var BlogDairy:BlogDairy;
//留言板
var GuestBook:BlogInputMsg;
//留言列表显示
var BlogMsgs:BlogMsgs;
}

然后里面每个组件都还包含另外的组件,比如滚动条,动态文本框什么的,我想说的是,我写在as里的mc嵌套模式并不一定就符合fla文件里的具体物理嵌套模式,有很多装饰性的mc不需要包含进来,也有很多具体原因,需要改写路径。比如在BlogDairy下,滚动条的实际路径是 BlogDairy.mc1.ScrollBar,不做成BlogDairy.ScrollBar可能是因为我需要mc1的动画,也可能是别的具体原因。但是我们可以在mc1的时间轴上加一句
_parent. ScrollBar =This.ScrollBar
把路径指向改写,达到我们要使用的模式,ScrollBar就是BlogDairy的直接成员。另外我没有语句初始化mc,我习惯在库里设置mc的linkage。
备注:虽然组合模式是每个人必不可少要用的,但正因为如此,我们可以想出他更多更好更灵活的实现方式

19.备忘录模式(memento)~师傅,晚上的鸡腿没中午的新鲜啊。~胡说!这就是中午的。
举例:开个玩笑,上面两句话不是备忘录模式的本意,实际上我一时想不出在食堂里备忘录是什么样子。备忘录的意思是,在不破坏对象封装型的前提下,保存对象的当前状态,当需要时,恢复这个状态或提取这个状态。
备忘录被广泛地运用到逻辑关系里,它似乎是目前我提到的唯一跟时间有关的模式,在控制论里可以涉及到因果系统。备忘录的应用非常广泛,最常见的是浏览器或网站的后退功能,返回到上一个界面,但是在我的站里没有用到,因为我的站是树状拓扑结构,每个栏目都只能唯一地从主界面进入或退回到主界面,那些网状拓扑结构的站点,每个栏目都可以通向其他的任何栏目,很可能就需要这么一个功能,其实现方法往往是维持一个堆栈型的数组。
另外一个我想实现的东西是网站内部自动记录,由于某些原因我暂时没有把它加到网站里。很简单,就是监视浏览者的每一步操作,在哪个栏目,停了多久,做了些什么之类,如果离开了,下次访问网站时让他选择是否直接进入上次浏览的界面(比如他上次在看我写的小说而没看完)。这个可以通过sharedObject实现,差不多也就是 flash内部的cookie。
备注:备忘录的实现要求还是很高的,在提取对象状态的时候不要破坏对象的封装性。理想的备忘录作为一个对象需要两个借口,一个给管理者,它不知道备忘录里封装了什么状态,只负责地把状态移交给需要的对象,一个留给原发者,原发者只能了解并操作备忘录里封装的状态,不能做别的操作。

小结:我会随时补充这篇文章。但是我要举的一些例子暂时已经说完了。其实设计模式远远不止这几种,经典的有23种,我已知的有41种,而这里只有19种,还有命令模式,解释器模式,迭代器模式,模板方法模式我没写到。我的站还用了一些我没有提到的,自己都还没细想过的设计模式。但是一一列举其实是意义不大的,有兴趣的同志们要做的就是接触一下这些设计模式的细节和思想,然后统统忘掉,就和张无忌学太极拳,先学后忘是一样的。招式要看,要学,但是要领会其中的深意,灵活地,创造地,相互结合,融会贯通地使用招式,不能拘泥于招式,更不能为了用招而用招。设计模式作为UML的重要组成部分,能够极大程度地促进我们的开发效率,使我们养成好的书写习惯,做出更人性,更和谐,更清晰,复用性和可控性更高的作品。

不要说你不是程序员,就可以跟着感觉走,随心所欲,当然我们无权干涉。我也说了,as本来就是想怎么写就怎么写,但接不接触,学不学习先进的思维模式,这也是你的自由。更不要说你是搞艺术的,头脑偏重感性,不适合接触这些,我之所以要顺带拿食堂举例,是想说明,我要说的其实是就Christian Alexander先生的,建筑的永恒之道,无论是建筑本身,还是任何软件工程,或者Flash的as,甚至Flash的矢量绘图,美工,平面设计,一直到世界这一整体,无不是遵循一个结构化的,由模式构成的永恒之道,有着惊人的高度相通和相似性。参悟了这一点,不仅对做Flash,对整个生活都会有新的看法。区别仅仅在于,从哪里开始入手思考,在这里,可以从Flash开始。

 

关于某些事务的小感

最近公司有人离职了,而且因为是做渲染的,他走了后,我的任务变重了,目前接手世界编辑器关于地形啊等等事务,还是蛮忙的,这也是没办法的事啦。我还有一个特效编辑器没做完,等做完差不多,我也该走了。说实话,创业公司真是挺累的,偶也算是这公司的元老级人物了,记得当时来的时候就只有个项目经理和主程,现在连主程都走了。哎,感慨万千啊。创业公司总有自己的难处的,算了,这些就不说了。

目前就剩下个烘焙了吧,偶参考的痞子龙的这篇文章,说是简单烘焙的方法,我也快实现了。大家也可以去看看。http://blog.csdn.net/pizi0475/archive/2010/11/18/6020060.aspx基本就是使用Ogre的动态阴影,然后渲到纹理当lightmap用,等我都实现了,再写篇文章记录一下心得,呵呵。

地形前段时间搞得也差不多了,主要搞了下ogre1.7地形的材质问题,地形受光跟物件的寿光程度不一样,导致颜色差别很大。再就是地形不支持无限点光的问题,再过几天吧,偶把这些问题的解决方法和代码贴出来给大家看一下。

现在真的很忙,身体也不太好了。把这个忙完,就剩特效编辑器了,做完特效差不多就得9月份了吧,到时看项目进展怎么样,到目前为止,对这个项目的风格玩法等等还算是比较认可的。说实话,现在在这公司里,薪水的确是蛮低的,这点很不满意啊,期待着涨涨薪水,O(∩_∩)O~到9月份项目要是看不到希望的话,哎,偶就该跳槽了,到那时候开个上w的薪水应该不过分吧,嘎嘎。所以,现在给自己打打气,我一定会努力的。

按照计划,之前已经看完了《head-first设计模式》和《代码大全》,接下来,要把四人组的《设计模式》给看完,再在项目里面应用一下,这样关于设计方面的知识就算是补得差不多了(之前由于关于设计方面知识的欠缺被老大狠狠的鄙视了一番,实在是强汗~~醉过醉过啊)。大家可以小小期待一下下篇关于Ogre地形问题和烘焙相关的心得,嘎嘎。好了,就先写到这里吧,胡扯了半天,看《设计模式》去了。

有关游戏开发的几点体会

1。还没有真正的次世代网游,更别指望它能赚钱好几次有朋友问我,次世代网游到底是什么东西我说,次世代网游就是模型至少上万面,贴图每张都起码2048,法线图,高光图,多层蒙版一个都不能少;动态光满天飘,还都是开着阴影的;体积云,体积雾,体积光,全都是立体的,酷;水面的反射,折射,波纹,浪花,样样精彩;超大型,超豪华场景,无限视野。就一个字:真实!哦不对,是两个字,超真实。这样的游戏用现在能配到的最好的机器,跑起来FPS也一定不允许超过15,否则那就不能叫次世代了。说白了,次世代就是你用当下的机器完全跑不起来的游戏,要么怎么能叫“次”世代呢。这样的游戏,不是让大多数玩家能玩得起来的,不是拿来卖钱的,就跟北京的商品房一样,是给大家去追捧的。最多,会等Intel,Nvidia来给开发商返点利。嗯,我是说,大概可能估计会有的吧。次世代的游戏其实已有不少了,比如战争机器,比如战神,比如彩虹六号……但次世代的网游还没有。魔兽是次世代吗?不是,完全不是。永恒之塔是次世代吗?也不是,它也还差的远。天下二,剑网三就差的更远了。2。真正赚钱的游戏技术都很普通也许你会说,真正的次世代游戏都还没有出来,你怎么就敢预言他们不能赚钱呢?是的,我不能,如果我有未卜先知的本领,那我早就不再需要靠做游戏来养活自己了。可是,我们却能够看到现在赚钱的游戏是什么样的,这些是明明白白摆在那里的。魔兽世界:把这个游戏誉为国内3D游戏的教程书完全不为过,不过你承不承认,策划也好,程序也好,美术也好,都从这里面学到了很多东西,模仿了很多东西,在目前国内的游戏里面,到处都能找到魔兽的影子。可是魔兽又用到了多神奇的技术?主角模型算上所有部件,3000多面,各部件的贴图组合在一起,512大小,没有法线没有高光,绝大多数还都只是一层贴图,偶尔有一些多层混合的。地形最简单的分块4层混合,最简单的lightmap。水面,把镜头拉远一点都能看出来贴图形状。天空盒,一个普通的m2模型。可是,魔兽所表现出来的整体场景效果,有哪一个游戏敢说超越呢?天龙八部,基于开源引擎Ogre制作的典范,也因为天龙八部鼓舞了国内好多使用Ogre开发的小团队。不得不承认,Ogre所使用的技术是最朴实的,朴实到我这样一个3D新手都能拿来修修改改,做点简单的demo。同样不得不承认,天龙的画面效果确实很一般,2.5D的场景,固定的视角,轻盈的有些像纸片人的模型,可是,这并不妨碍他每月近两亿的收入。梦幻,大话,DNF,征途,传奇……除了这些表面上能看到的技术以外,背后的技术是同样的道理。早期的单服务器,分线方式,依然沿用在现在很多主流的游戏服务器端,并且依然是非常赚钱的项目。而类似于BigWorld的高深架构,事实上也并没有成功的项目。如果把天下二的商业结果跟其他项目一比较的话。3。2D游戏比3D游戏赚钱我一样很认同,未来的趋势是3D,但是,那时候赚钱的3D项目不应该是现在这个样子的。以国内游戏玩家的年龄及文化层次来看,要让他们接受“右键旋转朝向,左键旋转视角”太过于困难,而即使是一个很熟悉3D操作模式的老玩家,进入到一个新的场景中,要分辨出“上北下南,左西右东”也是很烦人的一件事。如何尽可能的使用上3D的表现力,但又避免掉目前3D游戏的复杂操作模式,这要看未来谁先能走好这一步。但是,在3D真正应用起来之前,目前还是2D的天下。国内最赚钱的梦幻,还有大话系列,同样最高在线超过200万的DNF、征途,还有那不应被忘记了传奇。不用历数这些名字,文化部2009网游行业发展报告上统计的结果是,2D游戏收入占整个游戏行业收入达70%多。这也无怪乎腾迅到现在还在开发2D新项目,以3D起家的完美也要开2D项目,网易的大话到3代了还是2D,把unreal3应用得纯熟的韩国人也同样还在制作2D游戏。4。游戏开发并没有什么高深的技术首先需要明确的一点,游戏项目是工程项目,不是科研项目。工程项目的目的是在有限的人力跟财力之下实现出既定的需求,而这个需求从前面的分析可以知道,要求并不高,所以,需求的实现过程也就并没有多么高深。至少在我经历过的项目里,没有什么惊天地泣鬼神似的英雄人物,没有创造出多么伟大的算法,我们所做的,只是使用现在的技术,现有的方法,拼合成一个软件产品,一个融合了程序、美术、策划劳动力的软件产品。游戏开发的过程里,没有,也不需要多厉害的技术高手,需要的仅仅只是有耐心,有责任心的普通技术人员。5。游戏的卖点在内容而不是画面,但是画面不够好却没有机会去展现内容说这一点不是想强调到底是程序重要还是美术重要,或者是策划更重要。这三者是缺一不可,而且哪一方弱都不行的。我想说的是,游戏真正留住玩家靠的还是内容。一样是拿现在赚钱的游戏来说,梦幻没有华丽的3D场景跟画面,天龙有3D,但没人会说那里面有华丽的场景,DNF的2D画面还是非常粗糙的,唯独好一点的魔兽,但他的市场表现在国内游戏里面来说,并不算太强。但是好的画面在最开始的几分钟里却是相当重要的,这就好比是长的帅的人能够更吸引女孩子一样。也许你能用你的魅力,你的钱袋子来打动女人,但如果你穿着一件破衣服,脸上只有着残缺美,那你后面那些魅力,那些优点永远没有机会展示出来。游戏也是一样。至少,你的新手村一定要做到富丽堂皇。6。游戏并不需要追求太多的游戏性,提供一个交流的平台就行这是我最近的感悟。很多人玩游戏其实就是为了打发时间,我也问过很多沉迷于魔兽,沉迷于偷菜,沉迷于这些那些游戏的人,包括偶尔玩一下的,包括职业玩家,包括像我这样,为了游戏而玩一下的人。游戏靠什么来留住人,在这一点上达成共识并不难,那就是里面的朋友。所以,给玩家营造一个更好的交流氛围,交流环境,做到这一点了,游戏玩法可以要多俗有多俗。又在游戏里面,还有社区里面接触了一些新生代的玩家们,似乎家族是一个很流行的东西。这其实可以看作是以前游戏里公会的升级版。在某个儿童游戏里,一个玩家带着我去参观他们的家族,带我一个个拜见他们的官员。可我并没有看到这些官员的头衔,于是我问,你们这些官员是怎么来的?答曰:自己封的。就好像公园里的小道一样,有时候,游人们会按照自己的喜好在草地上走出一些新的路来,这些路才是最合理的。为什么不顺着这些玩家的路,把这些功能做的更强大一点呢。其实,把社群的功能做得更强大,更高级一点,那就像文明。或者做的更容易,更低龄一点,那就像过家家。不管是怎样,应该在系统里就增强了交流的便利性,甚至可以在玩家一加入到游戏中,就开始引导着他加入社群。只有在社群里,他才能找到家的感觉,他才会因为朋友们而留下来。当然,怎么找对这条路,走好这条路,可不像写下这几行字这么简单。

快速LightMap烘焙

什么是烘焙? 简单地说, 就是把物体光照的明暗信息保存到纹理上, 实时绘制时不再进行光照计算, 而是采用预先生成的光照纹理(lightmap)来表示明暗效果. 那么, 这样有什么意义呢?

好处:

  1. 由于省去了光照计算, 可以提高绘制速度
  2. 对于一些过度复杂的光照(如光线追踪, 辐射度, AO等算法), 实时计算不太现实. 如果预先计算好保存到纹理上, 这样无疑可以大大提高模型的光影效果
  3. 保存下来的lightmap还可以进行二次处理, 如做一下模糊, 让阴影边缘更加柔和

当然, 缺点也是有的:

  1. 模型额外多了一层纹理, 这样相当于增加了资源的管理成本(异步装载, 版本控制, 文件体积等). 当然, 也可以选择把明暗信息写回原纹理, 但这样限制比较多, 如纹理坐标范围, 物体实例个数...
  2. 模型需要隔外一层可以展开到一张纹理平面的UV(范围只能是[0,1], 不能重合). 如果原模型本身就是这样, 可以结省掉. 但对于大多数模型来说, 可能会采用WRAP/MIRROR寻址, 这只能再做一层, 再说不能强制每个模型只用一张纹理吧? 所以, lightmap的UV需要美术多做一层, 程序展开算法这里不提及....
  3. 静态的光影效果与对动态的光影没法很好的结合. 如果光照方向改变了的话, 静态光影效果是无法进行变换的. 而且对于静态的阴影, 没法直接影响到动态的模型. 这一点, 反而影响了真实度

肯定不只这几点,但我暂时只想到这几点

那么怎么生成lightmap呢?

最直接的办法: 光线追踪....(原理想想很简单, 按照物体定律来就可以了)

但是光线追踪这东西......就算用来离线生成我都嫌慢-_-

下面说的这个是利用GPU进行计算的, 跟实时光照没什么两样:

原理:

想想实时渲染的顶点变换流程: pos * WVP之后, 顶点坐标就变换到屏幕空间了[-1, 1]

如果VertexShader里直接把纹理坐标做为变换结果输出(注意从[0,1]变换到[-1,1]), 那么相当于直接变换到了纹理坐标系, 这时在PixelShader里还是像原来那样计算光照, 输出的结果就可以拿来做lightmap了

示例:

这是一个典型的Phong光照模型下的球(这里不考虑阴影效果, 对它不需要进行特殊处理):

这是VS:

 

  1. VS_OUTPUT vs_main( VS_INPUT Input )
  2. {
  3. VS_OUTPUT Output        = (VS_OUTPUT)0;
  4. Output.Position         = mul( Input.Position, matViewProjection );
  5. Output.Texcoord         = Input.Texcoord;
  6. float3 fvObjectPosition = mul( Input.Position, matView );
  7. Output.ViewDirection    = fvEyePosition - fvObjectPosition;
  8. Output.LightDirection   = fvLightPosition - fvObjectPosition;
  9. Output.Normal           = mul( Input.Normal, matView );
  10. return( Output );
  11. }

 

把原来的WVP变换改成变换到纹理坐标系:

 

  1. //Output.Position         = mul( Input.Position, matViewProjection );
  2. // transform to projection space
  3. Output.Position.xy      = Input.Texcoord * float2(2, -2) + float2(-1, 1);
  4. Output.Position.w       = 1;

 

输出的结果就成这样了:

保存下来可以直接使用. 这里我用的模型比较特殊, 本身的UV就满足前面提到的条件, 所以直接跟原纹理叠加就可以. 当然, 如果只保存明暗信息的话, 就不影响原纹理的复用, 因为通常lightmap不需要很高的精度:

有了lightmap, 再次画的时候就简单了, 只需要贴纹理, 光照大可以关掉:

如果还想要一更好的效果, 可以加入一些实时的全局光照算法, 如Dynamic Ambient Occlusion之类...阴影同理...

 

世界十大游戏培训学校

引言: 在开始阅读这篇文章之前,我们有必要先大概了解一下全球游戏行业的发展历史和研发分布情况。
北美游戏行业可以追溯到七十年代,迄今为止已经有四十年时间,日本游戏行业从八十年代到现在有三十年的时间,韩国游戏产业从九十年代末开始发展,有二十年的发展时间,中国的游戏行业虽然可以追溯到九十年代,但正式崛起却是在二十一世纪之初。

在北美、欧洲或日本,电视游戏占据了绝大部分市场,网络游戏只占不到10%。韩国和中国的情况则正好相反,几乎没有电视游戏市场,网络游戏几乎垄断游戏行业。
北美的游戏开发业集中于西海岸,自加拿大的温哥华向南,穿过西雅图到达加利福尼亚,最后延伸至德克萨斯。跨过大洋,在英国和法国也有基础扎实的游戏产业。在亚洲市场,很明显日本具有最强的开发实力。近十年来韩国的网游产业也在奋起直追,但受制于韩国本身的市场容量,其网游研发的实力逐渐被中国迎头赶上。同时由于人力成本相对较低,中国正在成为全球最重要的电视游戏外包研发基地之一。

而通过下文,我们不难发现,游戏教育的发展和游戏行业的发展密切相关。这足以说明,正是因为游戏产业的蓬勃发展才催生了对专业人才的大量需求,游戏教育产业才得以发展。               温哥华电影学院(加拿大) 一句话点评:老瓶(电影)装新酒(游戏)
除了强大的电影、电视、动画产业,温哥华还是为北美重要的游戏开发基地,存在EA等多个开发商。温哥华电影学院是加拿大最负盛名的电影学院,最早成立于八十年代,主校区处于温哥华的市中心,在大温哥华地区及蒙特利尔和多伦多市另有三个校区及实习场所。

温哥华电影学院的电影制作和3D制作专业是最悠久、最优秀的专业。2004年开始设立专门的游戏教育专业,主要开设课程有游戏设计,3D游戏美术,角色动画,声效课程等,课程周期一般为12个月。官网:http://www.vfs.com DigiPen Institute of Technology(美) 一句话点评:全球首家“电子游戏大学”
DigiPen创建于1988年,从1994年开始设立“电子游戏”项目班,是全球首家“电子游戏大学”。DigiPen总部座落于美国华盛顿州雷蒙德市,和大名鼎鼎的任天堂北美公司(Nintendo of America Inc.任天堂美洲和欧洲的运营中心)仅一条走廊之隔。
DigiPen在业界享有盛誉,专门培训电脑游戏设计相关人才,并提供学士和硕士学位课程,学士课程主要包括动画、游戏设计(分艺术与科学方向)、实时交互、计算机工程,硕士课程则以计算机科学为主。DigiPen要求学生每个学期都要制作独立游戏项目,其学生作品曾23次在独立游戏节奖项。每年申请该校入学的学生都在2.5万人左右,不过最后能被录取的只有200人。

DigiPen于2007年在新加坡设立了分校。官网:https://www.digipen.edu Guildhall at SMU (美)一句话点评:游戏专业也有本硕连读
SMU(Southern Methodist University南卫理公会大学)成立于1911年,是美国的一所教会私立大学,位于美国德克萨斯州,该校实力强劲,在2004年被NSCA排在美国20位,布什夫人劳拉即从该校毕业生。

Guildhall at SMU拥有美国首屈一指的游戏教育课程,提供正式学位。主要课程与实际的游戏开发挂钩,包括游戏美术、游戏程序、关卡设计(策划),其中硕士课程为17月,专业认证培训周期为22个月,此外还革命性的推出了教育领域的首个5年制本硕连读(计算机科学或艺术本科学位+数字娱乐领域的硕士学位)。官网:http://guildhall.smu.edu
Full Sail University一句话点评:娱乐行业职业教育的佼佼者
Full Sail公司位于美国佛罗里达州,是美国最著名的从事影视艺术和技术教育的集团公司之一,旗下包括洛杉矶电影学院和洛杉矶录音学院等高等院校。自1979年成立以来,Full Sail拥有超过31,000校友,毕业作品包括奥斯卡获奖作品,艾美奖和格莱美获奖项目,最畅销的视频游戏,票房排名第一的美国巡回演唱会等。
目前Full Sail同时有8000多人在校,提供28个学位课程,包括电影、媒体、音乐、游戏、设计等各个领域,其中游戏相关专业有游戏开发、电脑动画、游戏美术三个理学士课程,课程周期为21个月,以及为时1年的游戏设计硕士学位课程。更具特色的是,除了传统的校园教育,Full Sail的在线教育也提供正式学位。官网:http://www.fullsail.edu/
The Art Institutes(美) 一句话点评:北美最大的连锁教育机构
The Art Institutes在整个北美地区拥有超过40个教育分部,主要提供艺术创作和应用领域的硕士,学士和副学士学位(相当于中国的专科)课程以及其他无学位的教育与培训,涉及美食、设计、时装和媒体艺术等各个领域,以培养出符合行业需要的实际动手能力的人才为主。

在游戏教育方面,The Art Institutes于2003年开始获得电子游戏学位资格,提供以文学士为主的本科和专科学历教育,主要课程以美术方面为主,包括三维建模、动画、特效等,并兼顾游戏设计与编程。同时提供面对面的校园学习以及在线培训课程。官网:http://www.artinstitutes.edu
Gnomon School of Visual Effects (美)一句话点评:好莱坞的私家CG培训学校
GNOMON坐落于美国大名鼎鼎的好莱坞,与Zbrush开发公司Pixlogicmon在同一幢小楼里,这让它有得天独厚的条件,邀请资深业内人士以及好莱坞的艺术家们来为学生授课。报名者需要经过筛选才能获得入学资格,很多业内人士也会来进修以求不断提高。

GNOMON成立于1997年,建立的初衷是满足好莱坞电影公司的视觉需要,后来逐渐扩展到电子游戏领域。其课程涵盖了电影、电视和游戏几个不同行业所需要的技术技能,课程设置非常细致,游戏方面的有三维建模,角色动画,特效等。课程时间不等,既有长达三年的认证课程,也有短短9周的软件提高课,以全日制为主,同时提供在线课程。官网:http://www.gnomonschool.com/ Qantm College(澳大利亚及欧盟国家等)一句话点评:跨国连锁游戏培训
Qantm于1996年在澳大利亚成立,2004年被SCE教育集团收购,随后即在欧洲各国大力发展。目前Qantm在世界上众多城市设有分支,如澳大利亚的布里斯本、悉尼、墨尔本,英国的伦敦,荷兰的阿姆斯特丹,瑞士的苏黎世,德国的慕尼黑,奥地利的维亚纳,新加坡等。

Qantm每个分部的具体课程稍有不同,但总体上以游戏课程为主,如游戏设计与开发,3D动画,游戏音效等,另外还开设有网页设计课程。课程为全日制,时间从6个月到两年不等,某些学院学满两年可获得相关学位证书。官网:http://www.qantm.com AMG学院(日本)一句话点评:日本培训动漫游戏不分家
AMG于1993年成立,是日本著名的动漫游戏培训机构,在东京拥有4个培训基地,并在大阪设有分部。多年来AMG培养了大批动漫游戏人才,在业界享有很高的声誉,与日本的漫画、动画、游戏等行业联系紧密。此外,AMG还涉足电影投资与发行、动画制作、游戏开发等领域。

AMG的教育培训内容包括:游戏、动画、角色设计、漫画、剧本创作、配音等,课程一般为全日制两年。官网:http://www.amgakuin.co.jp KGCA(韩)一句话点评:韩国知名的专业游戏培训
1997年,韩国爆发经济危机,迫于生活压力人们更加渴望从游戏世界中获得满足,韩国的网吧及本土网络游戏如雨后春笋般发展起来,韩国政府也开始大力扶持游戏制作及相关产业。发展至今,韩国号称是世界上网络游戏产业最发达的国家之一,游戏产品大量出口到中国。

在这种大形势下,KGCA游戏学院于2001年在首尔成立,发展多年至今已经成为韩国业界知名的游戏学校,与卡普空公司、韩国著名大学明知大学建立了合作关系,其毕业生曾多次在韩国各类游戏大奖中获奖。

KGCA 游戏学院采用全日制教学,学期1年,课程包括程序、策划、美术。 官网:http://www.kgcaschool.com      GA游戏教育基地(中国)一句话点评:中国游戏培训的黄埔军校
上海是中国游戏研发的大本营,UBISOFT、KONAMI、EA、SEGA、2K、EPIC、ACTIVISION等全球著名游戏开发公司纷纷落户上海。网游兴起后上海的研发人才优势也成为网游企业的主要输血来源,盛大、九城、久游等总部均设在上海。

GA是中国最早成立的专业游戏教育机构,创办于2004年,位于上海商业中心徐家汇,和EPIC的中国公司在同一栋大楼里。不难看出,GA享尽上海研发人员众多的师资优势,大量邀请行业内资深在职开发人员授课,并且成为EPIC在中国唯一的教育合作伙伴,独家教授虚幻引擎3。

GA以职业教育为主,主要招收有一定基础的高校毕业生,以培养符合行业需要的实际动手能力为主,学生被要求在结业前参与基于商业游戏引擎的游戏项目制作,拿出可玩的游戏关卡作品来。GA具体课程包括美术和策划两大方面,具体有3D场景、3D角色、动画动作、原画、游戏策划,以及与EPIC合作开设的定向课程等,课程周期从2个月到6个月不等。官网:http://www.gamea.com.cn

国外的游戏教育

DigiPen的历史  1988年,Claude Comair在加拿大的温哥华市创办了计算机仿真和动画公司DigiPen。  1990年初,DigiPen公司开始提供三维计算机动画专业的培训计划。同年,该公司与任天堂北美分公司合作,为那些对视频游戏开发饶有兴趣的开发人员提供了一个专科培养计划。1994年,DigiPen应用计算机图形学院迎来了它的第一批学习电脑游戏编程的学生,这批学生在温哥华的校园内学习了两年的2D和3D电脑游戏编程。

随着视频游戏平台往更复杂、更精密的方向发展,DigiPen决定为交互计算产业提供一个本科级别的课程计划。依托于DigiPen工程师丰富的专业技术经验,他们设计了一个四年制的学位课程并得到了华盛顿州高等教育同等委员会(HECB)的授权。1996年的5月,HECB授权DigiPen颁发实时交互式仿真专业(Science in Real-Time Interactive Simulation)的本/专科学位,这是世界上第一个专门的计算机/视频游戏开发本科学位。2年后,DigiPen技术学院在位于美国华盛顿州的雷德蒙市正式成立,并且开设了交互式仿真专业的本/专的学位课程。

1999年,DigiPen增加了3D计算机动画的应用艺术专科学位。  Digipen的第一次毕业典礼于2000年7月22号举行,共有6位专科和5位本科毕业生发表了毕业演说。在毕业之前,11个毕业生中已经有9位在游戏领域找到了工作。2002年11月,DigiPen技术学院被职业学校和技术学院认证委员会(Accrediting Commission of Career Schools and Colleges of Technology)鉴定合格。因此,在2004年秋天,该学院又增加了以下学位项目:计算机工程本科(Bachelor of Science in Computer Engineering)动画制作本科(Bachelor of Fine Arts in Production Animation)计算机科学硕士(Master of Science in Computer Science)到2005年秋季, DigiPen已经拥有超过700名在校学生,其在课程上的要求始终贯彻了业界的最高标准。

学位授权和鉴定在通过了HECB的权威认证以及学位授权法案所制订的授予学位的最低教育标准要求后,从2006年3月15日开始,DigiPen技术学院可以颁发以下学位:实时交互仿真本科学位(Bachelor of Science in Real-Time Interactive Simulation)计算机科学硕士学位(Master of Science in Computer Science)计算机工程本科学位(Bachelor of Science in Computer Engineering)三维计算机动画的应用艺术大专学位(Associate of Applied Arts in 3D Computer Animation)动画制作的艺术本科学位(Bachelor of Fine Arts in Production Animation)DigiPen技术学院向职业学校和技术学院认证委员会(ACCSCT)申请了学位鉴定。申请过程中,ACCSCT的专家组成员与研究院的管理人员、全体教员和学生进行接触,从而对学校的教育项目和整体效果进行评估。在评比过程中,Digipen曾三次获得“杰出奖”。

ProjectFun计划除了专科学位项目外,DigiPen还为初、高中生提供了视频游戏编程和三维动画制作的学习机会。目前,DigiPen已有三个项目加入了”ProjectFUN计划”,包括:ProjectFUN车间从1994年起,DigiPen就为学生提供了为期1至2周的工作室实习计划,学生将有机会亲身体验到游戏编程和制作三维动画所涉及的内容并将和机器人一起工作。Project FUN技术学院在2000年秋季,DigiPen为对计算机科学课程感兴趣的中学生提供了一个相应的专业课程计划。目前在华盛顿州、加利福尼亚州威斯康星州、伊利诺斯州、俄亥俄州以及堪萨斯州都有ProjectFun技术协会的网站。Projec tFUN在线2005年5月,DigiPen推出了在线授课计划。让学生在家中便可参与整个课程计划。该计划是“车间学习计划”的一个补充。

学位项目DigiPen学院是一所以计算机科学教育为主的学校,侧重于将计算机科学应用在实时交互仿真程序、计算机工程和3D游戏上。DigiPen学院将理论和实际项目应用进行了创新和开拓性的结合,并且提供了很多的实习机会,一部分学生可以在DigiPen夏季工作室中实习。另一部分学生则有机会在任天堂、微软、EA、索尼娱乐和AmazedEntertainment、Valve等著名游戏公司进行实习。实时交互仿真本科专业(Science in Real-Time Interactive Simulation) DigiPen技术学院四年制的实时交互仿真本科专业共154学分,分8学期修满,每学期15周。这个专业的毕业生通常就业于计算机和视频游戏领域,职位可能是中级程序员、初级设计人员或者是工程设备人员。获得R.T.I.S本科学位的学生,在数学、图形学、计算机科学、交互仿真系统的设计与开发方面将会有非常扎实的理论基础和实践经验。这些学生至少会参与四个课程设计中的一个,每个设计都跨越两个学期,例如在不同平台上编写很多小游戏。部分学生的实践项目可以从DigiPen网页上下载,网址是:http://www.digipen.edu/programs/gallery/index.html。R.T.I.S专业毕业的学生拥有为基于文本的、滚动卷轴的、仿真和3D游戏进行设计、开发以及撰写帮助文档的能力。他们将通过团队合作来学习游戏设计、制作和编程的基本原理,能够撰写游戏设计文档和技术设计文档,学习进度管理的工具和技术并参与到几个游戏的整个制作过程中去。计算机工程本科学位(Bachelor of Science in Computer Engineering)DigiPen技术学院的计算机工程本科专业以为对人才要求苛刻的产业提供优秀人才为己任,该计划将理论基础知识和项目相结合,顺利完成计算机工程课程的学生将会获得以下的技能以及相应的专业工作机会:*在数学、物理和计算机科学方面拥有广泛的基础知识。*在电子工程方面的基础,包括:电路基本理论、特别是数字电路、微处理器、微控制器和嵌入式系统。*在小团队内进行设计、构建和测试原型系统的工作能力。每年都会有一些重要项目的开发,使学生有机会将理论知识转换为实际应用。*系统设计、软件工程、编码和系统集成方面扎实的基础技能。*业界标准硬件和软件应用技术方面的扎实基础知识。*专业的工作习惯和态度。学生们应该了解如何将专业评价运用到他们的工作中,并且有能力鉴定和创造出符合专业质量标准的作品,理解产品流程,可以为自己的作品制订合适的目标与进度表,并坚持贯彻下去,能够了解产品的压力和积极管理这种压力的方法。学生将长期研究产业的这一分支且能够巧妙而全面地论述他们在社会改良方面的责任。

在DigiPen,实时互动仿真本科、三维计算机动画应用艺术专科、动画制作艺术类本科和计算机科学硕士学等专业课程,都是为了致力于从事娱乐产业的学生准备的。计算机工程本科的学生在选择职业方面将会更广,这一点从以上的分析中就可以看出。该专业毕业生所从事的职位有诸如项目工程师、系统架构师、系统分析师、设计工程师、软件工程师和硬件/软件工程师这样一些职位。通常,游戏之所以会被用作教学范例,是因为游戏中所涉及的技术同样适用于其他广泛的领域。计算机工程的本科学位需要修154个学分,分8学期,每学期15周。一般是4个学年内完成。动画制作的艺术本科学位(Bachelor of Fine Arts in Production Animation)DigiPen技术学院从2004年秋天开始设立四年制的动画制作艺术专业本科学位。这个学位需要修满144个学分,花费8个学期,每学期15周。获得该学位的毕业生具备了从事3D动画、数字2D动画和动画前期制作的能力。随着动画产业的成熟,各公司更愿意聘用那些能够熟练使用专业商业软件和掌握传统动画技术的人才。因此,各工作室热衷于寻找那些在动画制作、传统美术、现代计算机软件和流媒体方面拥有广泛的理论、实践和技术技能,且能将它们综合在一起的美工。洞察力和长期的潜力变得尤其重要,同样重要的还有专业的责任心和恒心。动画产业的发展对DigiPen的教育提出了一系列重要的理论挑战。因此在课程的设计上必须经过很好的顺序组织,只有这样,才能让大多数的学生从中获益。DigiPen技术学院在动画制作方面的B.F.A专业就是为了满足这样的需求而诞生的。完成该课程的学生将会获得以下技能和合适的职业:
*在2D和3D动画制作经验方面深厚而广泛的基础。*关注某一制作领域,这样学生可以在毕业前有确定的就业选择并且通过论文来完成这一选择。*应用绘图方面扎实的基础和完整的技能。*描述故事的技能。包括口述故事,通过文字描述故事,通过对话、表演和电影等手段讲述故事。*使用标准硬件和软件的基本技能。熟悉现代接口和工作流程规范,同时了解在保持生产进度的同时如何学习新的软件。*拥有专业的职业习惯和态度。学习如何将职业批评利用和结合到工作中去,有能力鉴定并创造出符合专业质量标准的作品。理解产品流程同时,可以为自己的作品制订合适的计划目标并且遵守这个目标,了解产品的压力和处理压力的方法。3D计算机动画应用艺术专科课程(Associate of Applied Arts in 3D Computer Animation)DigiPen技术学院现在还开设了2年制的3D计算机动画应用艺术专科课程。这个专业共80个学分,分为4个学期完成,每学期15周,一般完成此专业需要2个学年。该专业的毕业生一般从事创作模型、结构图和3D动画方面的工作。随着3D电脑动画产业的成熟,各公司现在所需的电脑动画制作人才不仅要有3D软件使用经验,还要有极强的创造力。各工作室需要的人才除了掌握理论知识外,同时还要具有高水平的传统艺术技能。如果想要获得成功,动画制作人员必须对故事的发展、情节的设计、情节的串连、照明、照相合成和声音设计有深刻的理解。DigiPen在教学上使用的内容创新的教材保证学生最大的发挥其在数字媒体方面的潜力,为了帮助学生成为成功的动画制作艺术家,DigiPen会要求学生们在规定时间内独立或联合完成许多项目,就像他们在实际工作中将会遇到的一样。这些动画制作项目对为期4个学期的理论课程是一种深化。通过两年面向产品的实践项目课程,学生们逐步拥有了一批高质量的作品剪辑。当学生寻找工作时,这些作品剪辑能向各大公司展示自己的个人艺术视觉和技能。
申请要求实时交互仿真专业和计算机工程本科专业(Real-Time Interactive Simulation (R.T.I.S.) degree programs)的申请要求:熟练的英语水平,非英语母语国家必须达到TOEFL550(笔试)分或213分(机考)。达到12级或累计GPA至少达到2.5或相当于2.5。数学平均成绩达到“B”或者GPA达到3.0,包括有代数学、几何学、代数学Ⅱ、三角学、微积分预学课程(至少),如果可能再加上微积分/AP微积分。其他会考查的科目还有物理、化学和计算机科学。计算机科学硕士专业(Master of Computer Science degree program)的申请需求:熟练的英语水平,非英语母语国家申请者必须达到TOEFL550(笔试)或者213(机考)。完成本科学历并累计GPA至少达到2.5或相当于2.5。3D计算机动画学位专业(3D Computer Animation degree program)的申请需求:熟练的英语水平。非英语母语国家申请者必须达到TOEFL550(笔试)或者213(机考)达到12级或累计GPA至少达到2.5或相当于2.5。提交至少10个作品剪辑,这些剪辑要能够表明艺术范畴,特别是肖像/动物画、字体设计、建筑透视图等等。提交的作品述不退还,请邮寄复印件。动画制作专业(Production Animation degree program)的申请需求:熟练的英语水平,非英语母语国家申请者必须达到TOEFL550(笔试)或者213(机考)。达到12级或累计GPA至少达到2.5或相当于2.5。提交10到20份作品剪辑。剪辑中50%的作品要能表明学生的艺术范畴和技能。首选内容为动画样本、肖像/动物习作、字体设计、建筑透视图、风景画习作、雕刻和油画。另一半作品必须是直接来自于观察,不能是照片、其他平面资料或者学生的想象。如果可能,可以提供更多的作品供DigiPen分析。提交的作品述不退还,请邮寄复印件。
除了一般的要求外,对于申请者,DigiPen还会着重考虑一些重要的个人特质:一种强烈的达到目标的愿望。DigiPen是一个能够引起挑战兴趣的学校,每个人必须准备长时间的课程设计并且为通过考试而努力学习。教学的目标是将学生培养成一个有活力的产业设计工程师。逻辑思考能力。编程是一种逻辑性和组织性强的思考方式,有些人会发现比起其他工作,自己可能更适合做编程。程序员着眼于世界,分析事情为什么发生以及如何发生,而且他们会尝试着寻找如何让程序在计算机的仿真环境下运作的方法。对艺术创新的理解。程序员需要能够欣赏艺术家和艺术的思考方式,而且还要能在同等的水平上和艺术家共同工作。因为在制作高质量产品上,艺术和编程的联合是非常重要的。艺术家需要学习怎么与程序员共同工作,程序员可能是用线性方式来观察而不是以艺术方式看待事物。将自己的艺术感用在别人的设计中充满了挑战性,DigiPen可以帮助你如何面对挑战。在视频游戏产业中,对艺术家和程序员来说,不耻下问是必要的。因此,学习如何接受有建设性的批评是非常重要的。尊敬自己和同学。专业人员最好的个人品质就是尊敬自己和与你一起工作的人们。

游戏制作流程的简单总结……看了这些,你还敢开发游戏吗?

以下是游戏制作流程的简单总结:

一、计划阶段:首先,是项目计划阶段。

1、创意管理:第一步,是召开个会议,在会议中最常见的方法就是采取“头脑风暴法”。每个人都必须拿出自己的建议和想法,之后大家一起进行讨论。另外在会场内,会有专人进行会议记录。而在项目开发的前期则会有市场调查。

2、撰写草案:第二步,撰写策划草案,也叫意向书。撰写策划草案的目的在于,使得小组内每个成员对即将开发的项目有一个大体的认识,并且对目标进行明确。

3、市场分析:第三步,市场分析。决定了是否需要开发这个游戏。

1)、目标客户:最重要的一点是确定目标客户。即该游戏是面向核心玩家,还是普通的大众玩家。如果是面向核心玩家所开发的游戏,则需要游戏的难度更大一些;反之,如果是面向大众玩家开发的游戏,则需要游戏的难度简单一些。最好的方法是允许玩家自定义游戏的难度。

2)、成本估算:以网游为例,包括以下几个方面

·服务器:运行网络游戏所需花费的硬件方面的成本。成本中的大头。大约占到总成本的40%左右。

·客服:属于人力成本的范畴。网络游戏不同于单机游戏的部分在于,其不同于单机游戏的“售后不理”的销售模式。用户在玩这个游戏之后,运营商需要不断的提供更新和各种在线服务。

·社区关系专员:同上,属于人力成本的范畴。同其他方面的花销相比,这方面几乎可以忽略不计。

·开发团队:人力成本,这方面花费的真正大头在核心成员和天才制作人的薪资上。

·管理:管理方面花费的成本,这方面成本较少。

·用户帐号管理:发行成本的一部分,但也属于运营的范畴。至于成本几乎可以忽略不计。

·办公室、电脑、家具:这方面是大头,不过这次花费之后,开发下部游戏时基本上花费就不需要或者很少花费了。

·带宽:发行成本的一部分,但也属于运营的范畴。成本也是极高的,当然各地可能都不一样。

·网管:发行成本的一部分,同样属于运营成本的范畴。

·其他杂费:杂七杂八的一些费用,包括水电费、燃气费、可能还会包括买咖啡和茶叶的钱。

·宣传、广告和推广的费用:属于运营成本。应该说最好的宣传方法就是广告,但各种广告在花费上都不尽相同,这个就不细说了。

·客户端:制作游戏客户端、点卡、充值卡、印制游戏说明书、游戏包装、游戏赠品一类的成本。

4、需求分析:第四步,撰写需求分析书。这包括以下三个方面:

1)、美工需求:撰写美工需求分析书,内容包括需求图、工作量等。其中工作量需要以天来计。内容具体如下:

·场景:包括游戏地图、小场景等方面。

·人物:包括玩家角色、重要NPC(玩家队友、提供任务的NPC、主线剧情NPC等)、次要NPC(路人、村民等)、怪物、BOSS等。

·动画:动画方面估计每个公司的需求都不尽相同。如果公司能力有限,动画的制作可以考虑外包的方式。

·道具:主要需要考虑是否采取纸娃娃系统。

·全身像:人物的全身像方面。

·静画&CG:游戏中可能出现的静画和CG的需求。没有则不需要写。

·人物头像:人物的头像制作需求,其中包括人物的表情方面,包括喜、怒、哀、乐、悲等多种表情。

·界面:界面的需求,包括主界面、各项子界面、屏幕界面、开头界面、END界面、保存和载入界面等方面。

·动态物件:包括游戏中可能出现的火把、光影等方面。

·卷轴:又称为滚动条。根据游戏的情况来定具体的需求。

·招式图:根据游戏开发的具体情况决定是否有此需求。

·编辑器图素:各种编辑器的图素需求,例如关卡编辑器、地图编辑器等方面。

·粒子特效:3D粒子特效的需求。

·宣传画;包括游戏的宣传画、海报等方面的制作需求。

·游戏包装:游戏客户端的封面包装的制作。

·说明书插图:游戏说明书内附插图的制作需求。

·盘片图鉴:游戏客户端盘片上的图鉴的制作需求。

·官方网站:游戏官方网站的制作需求。

2)、程序需求:撰写程序需求分析书,内容具体如下:

·地图编辑器:包括编辑器的功能需求、各种数据的需求等。

·粒子编辑器:关于粒子编辑器的需求。

·内镶小游戏:包括游戏内部各种小游戏的需求。

·功能函数:包括游戏中可能会出现的各种程序功能、技术参数、数据、碰撞检测、AI等方面的需求。

·系统需求:包括升级系统、道具系统、招式系统等系统导入器的需求。

3)、策划需求

·策划的分工:包括剧本、数值、界面、执行等方面。

·进度控制:要时刻注意时间和开发进度的控制,需要写一个专门的项目进度表。

·例会:项目会以里程碑的形式呈现。当完成一个里程碑后,或者到达固定日期时,需要召开例行会议,除了成员彼此交流外,还需讨论开发中遇到的困难,进度是否有拖延等问题。

二、组织阶段:其次,是项目组织阶段。

1、确定日程:确定游戏开发的日程和进度安排。包括以下几个方面:

1)Demo版本阶段

·前期策划:前期策划和项目的规划。

·关卡设计:关卡设计阶段。

·前期美工:前期的美工制作。

·后期美工:后期的美工制作。

·程序实现:程序的实现,包括编码等。

2)Alpha版本阶段

·内部测试:主要是测试和完善各项功能,看一看是否有重大BUG。

3)Beta版本阶段

·外部测试:进一步测试和完善各项功能,并预备游戏的发行。

4)Release版本阶段

·游戏发行:项目完成阶段,开始正式的发行游戏。

5)Gold Release版本阶段

·开发补丁:开发游戏的补丁包、升级版本,以及 各种官方插件等。

2、确定人员:确定各个项目所需的人员。包括策划、程序、美工、测试、音乐、运营等方面。

3、分配任务:分配各个人员的具体的开发任务。

4、撰写策划书:正式撰写游戏策划书。

三、开发阶段:其三,是项目开发阶段。

作为策划来说,此阶段主要需做到同各方面保持顺畅的沟通,并处理各种游戏制作中的突发事件。其中需要做到与同事的沟通、同主管的沟通、同领导和老板的沟通等。

四、控制阶段:最后,是项目控制阶段。

1、时间

1)、成本控制:需要注意到开发成本的控制,包括服务器、客服、场租、人工(社区关系专员、开发团队、管理)、设备(办公室、电脑、家具等)、带宽、网管、宣传、广告和推广的费用等方面。

2)、市场变化:需要注意市场的因素。

·发行档期:需要注意发行档期,要赶在暑假和寒假之前发行。
·盗版因素:必须时刻注意盗版、私服等因素对游戏发行的影响。

3)、竞争对手的因素:需要时刻注意竞争对手的情况。毕竟,知己知彼,才能百战不殆。

2、品质

由于开发人员的水平大都参差不齐,所以必须根据制作人员的总体水平,决定作品的品质。既不能要求太高,亦不能要求太低,需要折中考虑。

3、突发事件

例如,老板的突击检查、项目投资人的突然撤资等,这些都必须全盘考虑。

4、控制成本

包括时间、品质等方面的成本控制。