精华内容
下载资源
问答
  • 行业资料-交通装置-一种新型流道结构的汽车引擎脚.zip
  • 什么是JavaScript引擎

    千次阅读 2015-07-23 22:58:59
    特别是你在使用JS引擎本来自动化应用程序时更是如此。自定义的JS对象能提供直接的程序服务,或者作为你的程序服务的接口。 有两种方法来创建JS引擎能使用的自定义对象: 写一个JS脚本,它创建一个...

    JavaScript是由Netscape开发的对象脚本语言,其特点是开发简单、功能灵活,目前已广泛应用于WEB页面及服务器应用程序中。HTML本身是静态的、不允许用户干预,但用JavaScript编写的脚本程序就可以在用户的浏览器端运行,可以同用户进行交互,从而实现动态页面。可以将JavaScript与嵌入WEB的大多数对象的事件(如鼠标点击、移动等)相关联,然后用自己的方式处理这些事件。JavaScript提供了丰富的内置函数及命令,能在浏览器中显示HTML、数值计算、多媒体播放、超级链接以及简单的交互窗口等,还可以使在浏览器中运行的小Java应用程序的性质改变从而很容易地改变控件或其它对象的行为而不必深入研究其本身的结构。

    JavaScript虽然是为Internet而开发的,但它的应用却不仅仅局限于Internet,事实上由于其面向对象的特性使得其适用范围非常广泛,只要我们的应用程序具有良好的对象机制,我们就可以借用JavaScript,从而实现很好的交互功能。

    SpiderMonkey是由C语言操作的JavaScript引擎,它支持JS1.4和ECMAScript-262规范。该引擎分析、编译和执行脚本,根据JS数据类型和对象的需要进行内存分配及释放操作。利用该引擎可以让你的应用程序具有解释JavaScript脚本的能力,目前已有若干个项目都采用了SpiderMonkey引擎,像K-3D、WebCrossing、WebMerger等。K-3D是用C++实现的3D建模与仿真系统,该系统内嵌SpiderMonkey引擎来提供自定义脚本(用户创建脚本生成像齿轮一样具有重复特性的复杂形体),也可用来驱动交互式的教学系统(用户可以使用一段JS脚本程序记录其交互过程,如移动鼠标、选择菜单、点击鼠标等)。WebCrossing利用SpiderMonkey实现了服务器端的脚本环境,提供了完全的Web-server脚本环境,服务器端的实现允许你在内置的、面向对象的数据库中创建永久对象,这样即可根据自己的需要扩展服务器环境。

    下面简要介绍在自己的应用程序中如何使用SpiderMonkey,最后给出一个简单的例子程序。

    如何使用引擎

    JS引擎一般作为共享库使用,应用程序调用引擎提供的API函数。引擎API函数大致分为以下几种:数据类型操作、RunTime控制、类与对象的创建和维护、函数与脚本执行、字符串操作、错误处理、安全控制、Debug支持。 一般情况下,在你的应用程序中只需使用某几类函数。例如,在进行JS调用之前你必须调用JS_NewRuntime函数来创建并初始化JS引擎。有些类型的函数,象安全控制类,提供可选择的特征。

    从概念上讲,JS引擎是你系统上的一个共享资源。通过将引擎API调用嵌入到应用程序中(包含jsapi.h文件),你可以请求JS引擎进行操作。接下来,引擎处理你的请求,并将结果或状态信息返回给你的应用程序。

    例如,假定你在使用JS引擎自动化应用程序,脚本应用程序鉴别用户并设置权限。首先,应用程序创建JS对象,该对象描述用户信息,包括姓名、ID、权限和可用的函数列表。在这种情况下,应用程序首先调用JS_NewObject创建对象。当JS引擎创建对象后,返回一个指针给应用程序。应用程序再调用JS引擎执行脚本。在创建用户对象后,应用程序即刻传递脚本给JS_EvaluateScript以便编译和运行。脚本或许取得并效验用户信息,然后建立用户存取的权利。

    JS引擎收到初始化请求后,给JS RunTime分配内存,应用程序使用的变量、对象和上下文(上下文)都保存在RunTime中。一个上下文是脚本的执行状态(JS引擎使用的)。每个同时存在的脚本或线程都必须有自己的上下文。单个的JS RunTime可以包含多个上下文、对象和变量。 几乎所有的JS引擎调用都需要一个上下文变量,应用程序在创建RunTime后,首先应调用至少一次JS_NewContext来创建一个上下文。上下文的实际数量依赖于程序中同时使用的脚本数。程序中每个同时存在的脚本都需要一个上下文。另一方面,如果某个时刻只有一个脚本编译和运行,那么你只需一个上下文给每个脚本重复使用即可。

    在创建上下文后,要调用JS_InitStandardClasses初始化引擎中的内置JS对象,包括Array、Boolean、Date、Math、Number和String。 即使在创建对象时传递一个特定的上下文给JS引擎,这个对象在RunTime中也是独立于上下文。任意脚本能与任意上下文建立联系以便存取任意对象。脚本、上下文相互之间完全独立,即使它们存取同样的对象。在给定的RunTime中,应用程序能用未指定的上下文存取任意对象。你可以创建独立的RunTime,一个用于共享上下文和对象,其余的用于私有上下文和对象。但注意,某个时刻只有一个线程能存取特定的上下文。 要让应用程序能识别JS,嵌入适当的引擎调用到你的程序中。大致有以下几个方面:

    1. 程序中包含jsapi.h。
    2. 程序中提供结构和变量声明。例如,如果你计划传递一个脚本给JS引擎,提供一个脚本字符串变量。用jsapi.h中定义的JS数据类型来声明变量。
    3. 使用JavaScript的脚本应用对象。通常这些对象与C程序中的结构和方法相对应。
    4. 将JS引擎API函数调用和变量引用插入到程序中,包括初始化内置JS对象、创建并配置用户自定义对象。
    5. 大多数JS引擎调用返回一个值。如果该值是NULL,一般表示错误发生。如果非NULL,表示成功,返回值一般是指针,程序需要使用或留到将来使用。应用程序应检查JS引擎调用的返回值。

    要让应用程序能解释JavaScript,你必须遵循某些JS API嵌入习惯。下面的例子简要说明需要嵌入到你的应用程序中去的一些API调用函数。大部分情况下,这些函数的插入顺序是很重要的。例如,在调用其他JS API之前必须初始化JS RunTime,同样在终止程序之前必须释放JS RunTime。

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    /* 包含JS引擎的API头文件 */
    #include "jsapi.h"
    .
    .
    .
    //主程序声明全局JS变量,包括RunTime、一个Context和一个全局对象,然后初始化JS RunTime、创建一个Context。
    int main(int argc, char **argv)
    {
      int c, i;
      /*声明全局JS变量,包括全局和自定义对象*/
      JSVersion version;
      JSRuntime *rt;
      JSContext *cx;
      JSObject  *glob, *it;
      JSBool builtins;
      /* 初始化JS RunTime,返回结果给rt */
      rt = JS_NewRuntime(8L * 1024L * 1024L);
      /* 如果rt为空,程序终止 */
      if (!rt)
        return 1;
      /* 创建一个Context,并将其与JS RunTime关联起来 */
      cx = JS_NewContext(rt, 8192);
      /* 如果cx为空,程序终止 */
      if (cx == NULL)
        return 1;
      /* 创建全局对象 */
      glob = JS_NewObject(cx, clasp, NULL, NULL);
      /* 实例化内置对象和全局对象*/
      builtins = JS_InitStandardClasses(cx, glob);
      .
      .
      .
      return 0;
    }

    如上面这个例子所示,调用JS引擎的应用程序必须首先创建JS RunTime,而且在终止程序之前要释放这个RunTime。在实例化RunTime后,即可创建自己的JS对象模型。对象模型决定了JS对象之间的关系,JS对象本质上是一种层次结构。缺省情况下,所有的JS对象都与全局对象相关联,它们都是全局对象的后代。当初始化标准的JS类时,你自动地得到一个全局对象:

    builtins = JS_InitStandardClasses(cx, glob);

    这个全局对象创建了一些基本的、被其它对象所继承的性质和方法。当你创建自定义对象时,它们自动使用全局对象所定义的性质和方法。你可以在自定义对象上重新定义这些性质和方法,从而重载这些缺省的性质和方法。当然,你也可以接受这些缺省的分配。 你可以在内置JS对象或其它自定义对象的基础上创建自己的对象。无论哪种情况,你所创建的对象都继承了层次链中父对象、一直上溯到全局对象的全部性质和方法。

    管理RunTime

    JS RunTime是内存空间,JS引擎利用它来管理上下文、对象和与JS函数及脚本相关的变量。在执行JS函数或脚本之前,首先要调用JS_NewRunTime来初始化一个RunTime。JS_NewRunTime函数携带一个unsigned整型参数,这个参数指定了在碎片收集之前分配给RunTime内存的最大字节数。例如:

    rt = JS_NewRuntime(8L * 1024L * 1024L);

    如上所示,JS_NewRuntime返回一个指向RunTime的指针。非NULL表示创建成功。

    正常情况下,一个程序只需一个RunTime。当然,根据需要创建多个RunTime并将它们保存在不同指针上也是可以的。

    JS_DestroyRuntime(rt);

    如果你创建了多个RunTime,务必在应用程序终止前将每个都销毁。

    管理上下文(Contexts)

    几乎所有的JS API调用都要求你传递一个上下文参数。在JavaScript引擎中一个上下文代表一个脚本,引擎传递上下文信息给运行脚本的线程。每个同时运行的脚本必须指派一个唯一的上下文。当一个脚本运行完后,它的上下文也不再有用,因此这个上下文可以重新指派给一个新的脚本,或将其释放。

    调用函数JS_NewContext为某个脚本创建一个新的上下文。这个函数需要两个参数:一个与该上下文相关的RunTime指针,分配给该上下文的栈空间字节数。如果调用成功,函数返回一个指针,它指向这个新建立的上下文。例如:

    JSContext *cx;
          .
          .
          .
    cx = JS_NewContext(rt, 8192);

    这个RunTime必须已经存在。你指派给上下文的栈空间必须足够大以便提供给使用该上下文的脚本所创建的变量和对象。注意,因为需要一些与分配和维护上下文相关的overhead,你必须做到:在应用程序中必须根据需要来确定创建上下文的数量;要确保上下文在被应用程序所需要时存在,而不是反复销毁和需要时重新创建。

    当某个上下文不再需要时,它应被销毁、释放内存资源给其它程序使用。根据应用程序中JS使用的范围,可以在使用完后及时销毁,或将其保留并反复利用直到应用程序终止。无论哪种情况,当上下文不再需要时都要调用函数JS_DestroyContext来释放它,这个函数携带一个指针参数,它指向要被释放的上下文:

    JS_DestroyContext(cx);

    如果你的应用程序创建了多个RunTime,那么,应用程序可能需要知道某个上下文是与哪个RunTime相关联的。这种情况下,可以调用函数JS_GetRuntime,同时传递该上下文作为参数。JS_GetRuntime返回一个指针,它指向合适的RunTime(如果存在的话):

    rt=JS_GetRuntime(cx);

    当你创建一个上下文,你要给它指派栈空间用于存放变量和对象。在一个给定的上下文中,你也能够存放大量的数据。但是,你必须将所需的栈空间尽可能地降到最小。调用JS_SetContextPrivate函数创建一个指针,它指向该上下文所需的私有数据,调用JS_GetContextPrivate函数得到这个指针以便你能存取这数据。你的应用程序负责创建和管理私有数据。

    要创建私有数据并将其与上下文相关联:首先,创建私有数据,即常规的C语言void* 变量;然后,调用JS_SetContextPrivate函数,并指定创建私有数据的上下文和指向该数据的指针。例如:

    JS_SetContextPrivate(cx,pdata);

    随后要获取这个数据指针,请调用JS_GetContextPrivate,并传递这个上下文作为参数。这个函数返回指向私有数据的指针:

    pdata=JS_GetContextPrivate(cx);

    <?xml encoding="US-ASCII"?>
    <!ELEMENT order (header,item+,price)>
    <!ELEMENT header (billing,shipping)>
    <!ELEMENT billing (name,address,creditCard)>
    <!ELEMENT shipping (name,address)>
    <!ELEMENT name EMPTY>

    对象的处理

    1.创建内置对象和全局JS对象

    JavaScript引擎提供若干个内置对象,使得你的开发任务得以简化。例如,内置数组(Array)对象使得在JS引擎中创建和操作数组结构很容易。类似地,日期(Date)对象提供了一个操作日期的统一机制。要了解内置对象支持的全部内容,请参阅JS_InitStandardClasses。 JS引擎一直使用函数和全局对象。通常,全局对象居留在幕后,为应用程序中创建和使用的其它JS对象及全局变量提供缺省范围。在创建自己的对象前,你必须初始化全局对象。函数对象使得对象具有和调用构造函数的功能。

    一个简单的API调用,JS_InitStandardClasses,初始化全局和函数对象、内置引擎对象,方便应用程序使用它们:

    JSBool builtins;
          .
          .
          .
    builtins = JS_InitStandardClasses(cx, glob);

    JS_InitStandardClasses函数返回一个JS布尔值,表示初始化成功与否。

    你也可以为应用程序指定另外一个不同的全局对象。例如,Navigator使用window作为其全局对象。要改变应用程序的全局对象,请调用JS_SetGlobalObject。要了解更多信息,请参阅JS_SetGlobalObject。

    2.创建并初始化自定义对象

    除了使用引擎内置对象外,你还可以创建、初始化并使用自己的JS对象。特别是你在使用JS引擎用脚本来自动化应用程序时更是如此。自定义的JS对象能提供直接的程序服务,或者作为你的程序服务的接口。

    有两种方法来创建JS引擎能使用的自定义对象:

    1. 写一个JS脚本,它创建一个对象、性质、方法、构造函数,然后将这个脚本传递给JS引擎。
    2. 将代码插入到你的应用程序中,它定义了对象的性质和方法,调用引擎来初始化一个新对象,然后通过额外的引擎调用设置对象的性质。这种方法的好处是,应用程序能包含操作对象的本地方法。

    无论哪种情况,如果你创建一个对象,然后让其存在于被其它脚本使用的RunTime中,你可以调用JS_AddRef和JS_AddNamedRoot使该对象为根。使用这些函数,确保JS引擎能跟踪这些对象并在碎片收集时清除它们。

    3.如何将自定义对象嵌入到应用程序中

    将自定义对象插入到应用程序中是很有用的,比如,当对象持续需要时,或者你知道有多个脚本需要使用一个对象。将自定义对象插入到应用程序中的步骤是:

    • 创建一个JSPropertySpec数据类型,将对象的属性信息指派给它,包括属性的GET和PUT方法名字。
    • 创建一个JSFunctionSpec数据类型,将被你的对象所使用的方法信息指派给它。
    • 创建实际的C函数,它们在响应你的对象方法调用时被执行。
    • 调用JS_NewObject和JS_ConstructObject函数,以便实例化该对象。
    • 调用JS_DefineFunctions函数来创建对象的方法。
    • 调用JS_DefineProperties函数来创建对象的属性。

    描述持续的、自定义的JS对象的代码必须放在靠近程序执行的开始部分,在那些依耐于先前已存在对象的代码之前。

    4.给对象提供私有数据

    象上下文一样,你可以将大量的数据与对象进行关联,而不是将这些数据直接存放在对象里。调用JS_SetPrivate函数来创建指向对象私有数据的指针,调用JS_GetPrivate函数来获取这个指针以便你能存取这些数据。你的应用程序负责创建和管理这些私有数据。

    创建私有数据并将其与对象关联的方法:

    1)创建私有数据,作为C语言的void*变量。 2)调用JS_SetPrivate函数,指定对象和私有数据指针。

    例如:

    JS_SetContextPrivate(cx,obj,pdata);

    随后,要获取这些数据,请调用JS_GetPrivate函数,将对象作为参数进行传递。这个函数返回指向对象私有数据的指针:

    pdata=JS_GetContextPrivate(cx,obj);

    数据处理

    1.处理JS数据类型

    JavaScript定义了自己的数据类型。有些数据类型直接对应于C语言中的副本。其它的,如JSObject、jsdouble和JSString,都是JavaScript独有的。

    通常,你可以在应用程序中像使用标准的C语言数据类型一样声明、使用JS数据类型,JS引擎对那些需要多于一个字存储空间的JS数据类型的变量保持单独的栈,例如:JSObject、jsdouble和JSString。引擎会周期性地检查这些变量,看看它们是否仍在使用,如果没有,引擎就碎片收集它们,释放存储空间。

    2.处理JS值

    除了JS数据类型以外,JS引擎也使用JS值,称其为jsvals。一个jsval本质上是一个指针,指向除了整型以外的JS数据类型。对于整型,一个jsval包含这个值自身。其它情况,指针被编码成包含额外信息。利用jsvals提高引擎的效率,允许API函数处理大量的潜在数据类型。 引擎API包含一组宏,用于测试一个jsval的JS数据类型。他们是:

    • JSVAL_IS_OBJECT
    • JSVAL_IS_NUMBER
    • JSVAL_IS_INT
    • JSVAL_IS_DOUBLE
    • JSVAL_IS_STRING
    • JSVAL_IS_BOOLEAN

    除了测试一个jsval的潜在数据类型外,也能测试它看是否是原始JS数据类型(JSVAL_IS_PRIMITIVE)。原始数据类型是undefined、null、boolean、numeric和string类型。

    你也可测试jsval指向的值是否为NULL(JSVAL_IS_NULL)或void(JSVAL_IS_VOID)。

    如果一个jsval指向一个JSObject、 jsdouble或 jsstr等JS数据类型,你可利用JSVAL_TO_OBJECT、 JSVAL_TO_DOUBLE、 JSVAL_TO_STRING将jsval转为它的潜在类型。

    3.处理JS字符串

    你在JavaScript中做的许多事情都会涉及到字符串,JS引擎实现了一个称为JSString的字符串数据类型和一个指向JS字符数组的指针类型即jschar,用类处理Unicode编码的字符串。这个引擎也实现了一组通用的Unicode字符串程序。最后,JS引擎也提供内置串的支持,两个或多个独立的字符串在内存中能共享一个串。对于JSString类型的字符串,这个引擎跟踪并管理串资源。

    一般说来,当你用JS引擎操纵字符串时,你应该用JS API串处理函数来创建和复制字符串。有字符串管理程序用于创建NULL结尾的字符串或者指定长度的字符串。同时,也有程序用于计算字符串长度、比较字符串。

    4.对Unicode和Interned字符串的支持

    像其他API调用一样,具有Unicode能力的API字符串函数的名字与标准的引擎API字符串函数的名字是一一对应的。例如,如果一个标准函数名为JS_NewStringCopyN,对应的Unicode版函数就是JS_NewUCStringCopN。具有Unicode处理能力的API字符串函数对于interned字符串也是可行的。

    为了节约空间,JS引擎为共享单个字符串实例提供支持。这种共享的字符串称为"interned strings"。当你事先知道程序中会创建一个特定的、文本字符串并且要多次使用它时,请利用interned字符串。

    引擎为interned字符串提供了若干个调用:

    • JS_InternString,用于创建或再次使用一个JSString。
    • JS_InternUCString,用于创建或再次使用一个Unicode类型的JSString。
    • JS_InternUCStringN,用于创建或再次使用固定长度的Unicode型JSString。

    5.安全控制

    对于JavaScript1.3,JS引擎增加了安全增强型API函数,用于编译和运行传递给引擎的脚本或函数。JS安全模型是基于Java安全模型的。这个模型提供了一个通用的安全接口,但是,具体的安全实现是由应用程序自己来完成的。

    安全机制用在能够支持JavaScript的应用程序中的一种通用情形是比较脚本的真实性或者限制脚本的交互性。例如,你可以比较一个应用程序中两个或多个脚本的代码库,只允许来自同一个代码库的脚本能够修改共享代码库的脚本属性。

    如果要实现安全JS,请按以下步骤:

    1)在程序中声明一个或者多个JSPrincipals类型的结构。

    2)实现将给数组提供安全信息的函数。这些函数包括:给你的应用程序提供一个principals数组,用一套给定的规则对JS对象的引用数进行加减操作的机制。

    3)用你的安全信息给JSPrincipals结构赋值,这个信息可以包括通用代码信息。

    4)在运行时间环境中,编译与执行全部脚本和函数。下面列出了这些API函数和它们的目的:

    • JS_CompileScriptForPrincipals:编译但不执行一段具有安全能力的脚本。
    • JS_CompileUCScriptForPrincipals:编译但不执行一段具有安全能力、Unicode编码的脚本。
    • JS_CompileFunctionForPrincipals:利用一个文本字符串创建一个具有安全能力的JS函数。
    • JS_CompileUCFunctionForPrincipals:利用一个Unicode编码的文本字符串创建一个具有安全信息的JS函数。
    • JS_EvaluateScriptForPrincipals :编译并执行一段具有安全能力的脚本。
    • JS_EvaluateUCScriptForPrincipals:编译并执行一段具有安全能力、用Unicode编码的脚本。

    程序样例

    以下是一个简单的样例程序,它从文件test.js中读入一段脚本,然后解释执行并输出结果。脚本中可嵌入自定义对象People,People对象具有属性name(表示该人的姓名)、address(表示该人的地址)及方法print(在屏幕上显示该人的姓名、地址信息)。

    例如:下面是一段简单的js脚本,它首先利用print方法输出该人的姓名和地址,然后将姓名和地址分别修改为John和Beijing,最后再次输出其姓名和地址,看是否修改正确。

    people.print();

    people.name="John";

    people.address="Beijing";

    people.print();

    下面是C源程序代码。

    #include "js.h"
    enum tagMY_PEOPLE {MY_NAME,MY_ADDRESS};
    static JSBool GetPeopleProperty (JSContext *cx, JSObject *obj, jsval id, jsval *vp);
    static JSBool SetPeopleProperty (JSContext *cx, JSObject *obj, jsval id, jsval *vp);
    static JSBool PeoplePrint(JSContext *cx, JSObject *obj, uintN argc, 
            jsval *argv, jsval *rval);
    typedef struct{
        char name[16];
        char addr[64];}PeopleInfo;
    static PeopleInfo m_ainfo={"myName","myAddress"};
    /*定义属性的 GETTER*/
    static JSBool GetPeopleProperty (JSContext *cx, JSObject *obj, jsval id, jsval *vp)
    {
        if (JSVAL_IS_INT(id)) {
            switch (JSVAL_TO_INT(id)) {
                case MY_NAME:
                    *vp=STRING_TO_JSVAL (JS_NewStringCopyZ (cx,m_ainfo.name));
                    break;
                case MY_ADDRESS:
                    *vp=STRING_TO_JSVAL (JS_NewStringCopyZ (cx,m_ainfo.addr));
                    break;
                }
        }
        return JS_TRUE;
    }
    /*定义属性的SETTER*/
    static JSBool SetPeopleProperty (JSContext *cx, JSObject *obj, jsval id, jsval *vp)
    {
        if (JSVAL_IS_INT(id)) {
            switch (JSVAL_TO_INT(id)) {
                case MY_NAME:
                    strncpy (m_ainfo.name, JS_GetStringBytes (jss), 15);
                    break;
                case MY_ADDRESS:
                    strncpy (m_ainfo.addr, JS_GetStringBytes (jss), 63);
                    break;
                }
        }
        return JS_TRUE;
    }
    /*定义print方法*/
    static JSBool PeoplePrint(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, 
       jsval *rval)
    {
        fprintf(stdout,"My Name is %s.\nMy Addr is %s.\n",m_ainfo.name,m_ainfo.addr);
        return JS_TRUE;
    }
    void main()
    {
        JSString* jss;
        char buf[5120];
        int len;
        jsval rval;
        JSRuntime *rt;
        JSContext *cx;
        JSObject *globalObj,*PeopleObj;
        JSClass global_class = {
                "global",0,
                JS_PropertyStub, JS_PropertyStub,JS_PropertyStub, JS_PropertyStub,
                JS_EnumerateStub, JS_ResolveStub,JS_ConvertStub, JS_FinalizeStub };
    /*定义People类的属性数组*/
    static JSPropertySpec PeopleProperties[] =
      {
        {"name", MY_NAME,    JSPROP_ENUMERATE },
        {"address",  MY_ADDRESS,     JSPROP_ENUMERATE },
        {0}
      } ;
    /*定义People类的方法数组*/
    static JSFunctionSpec PeopleMethods[] =
    {
        {"print",          PeoplePrint,     0},
                 {0}
            };
    /*定义People类*/
    static JSClass PeopleClass = {
            "people",0,
      JS_PropertyStub,JS_PropertyStub, GetPeopleProperty, SetPeopleProperty,
      JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub
    };
        typedef struct{}
          /* 初始化JS RunTime,返回结果给rt */
    rt = JS_Init(1000000L);
        if (!rt)return;
      /* 创建一个上下文,并将其与JS RunTime关联起来 */
        cx = JS_NewContext(rt, 5120);
        if (!cx)return;
      /* 创建全局对象 */
        if (!(globalObj = JS_NewObject (cx, &global_class, NULL, NULL)))return;
          /* 实例化内置对象和全局对象*/
    JS_InitStandardClasses (cx, globalObj);
    /*实例化People对象*/
    PeopleObj = JS_DefineObject (cx, globalObj, "People", &PeopleClass, 0,JSPROP_ENUMERATE);
    /*创建对象的属性*/
    JS_DefineProperties (cx,PeopleObj, PeopleProperties);
    /*创建对象的方法*/
    JS_DefineFunctions (cx,PeopleObj, PeopleMethods);
    FILE* fp;
    /*打开文件,读入脚本*/
        if (!(fp = fopen ("test.js", "r")))return;
        len = fread (buf, 1, 5120, fp);
        fclose (fp);
        if (len <= 0)return;
    /*执行一段脚本*/
        JS_EvaluateScript (cx, globalObj, buf, len, "", 1, &rval);
        jss = JS_ValueToString (cx, rval);
        fprintf(stdout,"The result is: %s",JS_GetStringBytes (jss));
    /*释放上下文*/
    JS_DestroyContext(cx);
    /*释放RunTime*/
    JS_DestroyRuntime(rt);
    return;
    }
    展开全文
  • 效果 文章目录效果前言使用情景步骤1. 下载安装并启用Power IK...包含但不限于下面这种部悬空的问题 步骤 1. 下载安装并启用Power IK插件 链接就不贴了,在商城直接搜索Power IK即可,支持最新的4.26版本 2. ...

    效果

    视频审核中

    前言

    先赞后聊,这东西太给力了!老王直呼好家伙!感谢Epic Games收购了这么多好东西免费送给开发者!

    使用情景

    Power IK是基于虚幻原有的运行时IK系统并结合了射线检测开发的一套非常简单易用的运行时IK插件。最最常见的使用情景应该就是脚底板位置的矫正了,本文就以此为例介绍一下Power IK的使用流程。

    下面的截图是没有使用IK矫正的情况:

    • 角色脚部在台阶上悬空

    在这里插入图片描述

    • 踩在斜坡上脚底板没有贴合斜面并且还陷了进去

    在这里插入图片描述
    仅使用虚幻原生的IK和物理系统也可以矫正这些问题,但是还是比较麻烦的,而且如果遇到了类似蜘蛛这样的多足生物动画,工作量就更大了。然而,使用Power IK可以以非常傻瓜的方式完美处理这些问题。下面就简述一下实现步骤。

    步骤

    1. 下载安装并启用Power IK插件

    链接就不贴了,在商城直接搜索Power IK即可,支持最新的4.26版本

    在这里插入图片描述
    如果在安装过程中出现了问题,请参看这篇文章《UE4.26 Power IK插件安装时的“Plugin “PowerIK“ failed to load”的问题解决办法》

    2. 创建一个地面专用的Trace Channel

    本文以第三人称模板为例

    上面说了Power IK也是基于射线检测的,所以要创建一个专用的Trace Channel,本文命名为“FootIKTrace”,注意要把预设中所有角色不可踩踏类型都设为Ignore

    在这里插入图片描述

    3. 使用Power IK Ground节点

    3.1 添加Power IK Ground节点

    Power IK Ground节点可以根据需要放到状态机中也可以放到AnimGraph中,本文中老王使用的是后一种方式。

    本文使用的是UE4_Mannequin,pelvis是它的骨盆也是两条腿IK链的根部,如果使用其它骨骼请根据实际情况设置

    在这里插入图片描述

    3.2 设置足部骨头

    添加双脚,并设置为对应的骨头

    • 双足分别为"foot_l/foot_r"
    • 此处我们可以看到Power IK是支持多足生物的

    在这里插入图片描述

    3.3 Ground Collision设置

    这里是设置地面射线检测的频段和射线的长度
    在这里插入图片描述

    3.4 Ground Slope设置

    这里设置的是脚底板是否贴合斜面以及稍稍增加一点偏移量以至于不要陷进去

    在这里插入图片描述

    3.5 Constrains 设置

    这个设置非常重要,防止膝盖向后弯曲

    在这里插入图片描述

    3.6 其它设置

    其它的设置可根据需要自行设置,不过其中有个Body Inertia选项,如果启用可以让动作更平滑,建议优先考虑。

    在这里插入图片描述

    编译一下,我们可以看到角色的脚部出现了两个控制器标志

    在这里插入图片描述

    运行一下

    • 脚底板自然贴合斜面

    在这里插入图片描述

    • 站在台阶上没有了脚部悬空的情况

    在这里插入图片描述

    展开全文
  • 游戏与引擎

    千次阅读 多人点赞 2014-07-15 22:58:15
    此篇文章献给初学游戏设计的开发者,希望能够帮助同学们各好的了解游戏与引擎。 1. 什么是游戏 2. 何为引擎 3. 引擎的由来 4. 引擎发展史

    此篇文章献给初学游戏设计的开发者,希望能够帮助同学们各好的了解游戏与引擎。


    1. 什么是游戏

       游戏的类型有很多种,而今天我们所谈,无疑是电子游戏。

         对于一般的开发者而言,游戏无非就是程序的代名词,一款游戏在研发人员的眼中恐怕与一般的软件开发无异,然而游戏的意义真的仅此而已吗?我们在游戏的过程中可以在一个二维或三维的虚拟世界中控制人或物让他们按照我们的要求进行互动从而获得乐趣,而这便是游戏独有的魅力——模拟与交互性。

         从游戏的特征上来看我们不难发现,电子游戏事实上就是一种虚拟的现实,这也是电子游戏被称之为继八大艺术之后第九大艺术的原因。它拥有八大艺术所具备的共性却又拥有自己独特的艺术样式,它能够使欣赏着不局限于第三方的身份去感受作品本身的气息,从而达到身临其境之感。无论是戏剧、电影、文学、又或是音乐,当我们每一个人作为欣赏者去品味这些创作者的艺术时,即使作品本身再完美,不同的人都将会有不同的感受,因为我们每个人与创作者的角度不同,这样欣赏者就会受到自身的限制而无法真正的还原艺术本身的灵魂。而电子游戏的交互式,却能够使人真正的融入到作品中,至少就目前而言这是其它任何一种艺术都望尘莫及的。也正是因为游戏本身的模拟与交互性注定了其发展的最终趋势——虚拟现实。


    2. 何为引擎

        人们对游戏引擎的定义是:用于控制所有游戏功能的主程序。通常在一个游戏开发的团队中会将工程师分为引擎程序员与游戏程序员,前者负责引擎系统的功能,例如游戏中的实时渲染,光影计算,人工智能,物理系统,动画技术及音乐等等;而后者则负责游戏的逻辑的实现,即游戏本身的玩法。通过这一点我们可以发现游戏引擎实际就是游戏的框架,它为前端开发者提供了各种各样的游戏中所需要的组件。有人将游戏引擎比喻为赛车的引擎,从游戏的性能角度来说这一比喻是很贴切的,引擎就像是一个导演一样指挥着各个功能模块协调操作,而游戏最终渲染出来的画面效果及运行时的流畅性与引擎也有着很大的关系(当然某些游戏被称作显卡杀手的原因也并非是引擎的关系)。说到这里有人可能会认为引擎工程师要比游戏研发工程师厉害很多,事实并非如此,引擎工程师更关心的对引擎系统组件功能的实现,而游戏研发工程注重的却是对游戏逻辑的抽象,着重点各有不同,却并无高低之分,因为游戏与引擎之间的分界线本就是模糊的。


    3. 引擎的由来

        在游戏开发的初期,并没有引擎这一概念,人们每开发一款游戏都会从零开始编写代码,这样便浪费了大量的时间和费用。后来人们便将某些具有类似题材的游戏代码整理出来作为下一款该类游戏的基本框架。所以,好的游戏引擎都是为了某种特定的游戏类型而设计的,越是通用的引擎(可以制作很多种游戏内容的引擎),它在特定平台运行特定游戏的性能就越一般,所以,不要指望某种可以横跨N多个平台制作N多种类型游戏的引擎性能会很牛X(实际上可以在任何平台运行任何游戏内容的引擎基本永远不会出现),因为高效的东西总是需要取舍的。


    4. 引擎发展简史

        关于世界上第一款游戏引擎的说法可谓众说纷纭,但是通常大家比较认同的是1992年3D Realms公司(该公司为Apogee Software公司划分出的独立开发部门)发布的 Wolfenstein 3D(德军司令部),这款游戏可谓是FPS(First Person Shoot,第一人称射击游戏)游戏的鼻祖,这也是后来3D游戏引擎与FPS游戏密不可分的原因。Wolfenstein 3D成功的在游戏中引入了Z轴的的概念,使平面增加了一个纵深空间。而这款引擎的作者便是id software公司的联合创始人John Carmark(约翰·卡马克),一个被赋予游戏之神称号的电玩游戏程序员,在Wolfenstein 3D发布不久之后,id SoftWare便发布了另外一款在引擎史具有重大意义作品——Doom(毁灭战士)。Doom引擎是世界上第一个被用于授权的引擎,而John Carmark的地位也从此在游戏界站稳了脚跟(目前卡马克已从id SoftWare公司离职,研发虚拟现实之眼)。

           在引擎的进化史上另外一款能够与Doom比肩的游戏便是Duke Nukem 3D(毁灭公爵3D),由Apogee Software公司1994年研发的Build引擎打造,毁灭公爵已经具备了如今我们所接触到的第一人称射击游戏所包含的绝大多数内容,但是Build引擎仍然无法被成为一个真正意义上的3D引擎,因为从引擎本身来讲Build并没有什么实质性的突破,然而,在1996年id software公司发布了Quake(雷神之锤)之后,这个局面被打破了。雷神之锤不仅能够完全支持粒子特效及动画,更重要的是实现了网络游戏的大众化,将网络游戏带到了人群中。

           与此同时,我们在来看看同期国内的情况,1995年,由大宇旗下的狂徒工作室研发的仙剑奇侠传诞生了,1996年,由河洛工作室研发的金庸群侠传问世,在这个期间,国内还并没有一款成型的游戏引擎,而这些DOS游戏也都是基于汇编语言完成的,尽管游戏本身的功能和画面以及所使用的技术并不如同期国外的产品,但这两款游戏在中国的游戏史上仍然具有非凡的意义,也是无数人心中永远的回忆。

           继雷神之锤之后,id software公司很快推出了雷神之锤2,在当时的3D引擎市场上占据了霸主之席。然而,在1998年Epic Games公司的Unreal(虚幻)闯入FPS世界之后,雷神之锤便出现了一个强劲的竞争对手。在1998年同时出现的还有另外两款引擎,一款是Looking Glass工作室研发的Dark引擎(后由于工作室倒闭引擎未能继续研发),而另外一款便是大名鼎鼎的半条命(Half-Life)了,其实包括我们在后期玩CS的时候也不难发现,这款游戏中始终留有雷神之锤的影子,这是因为半条命引擎正是基于雷神之锤1和雷神之锤2引擎打造。

           在进入了21世纪之后,引擎分化的趋势也逐渐展开,而在2000年左右的时候,国内也诞生了不少的游戏引擎,例如当年大名鼎鼎的梦幻西游及大话西游系列便是通过一款名为风魂的图形引擎打造,风魂引擎是云风在大学时期的一项作品,尽管现在看来这款引擎并不十分完美,但在当时也算红极一时。笔者早些年玩过的一款令我印象十分深刻的游戏便是可乐吧的奇遇(现已改名为奇遇之城),事实上这也是笔者玩过的第一款网络游戏,这款游戏是使用可乐吧的FancyBox引擎打造。同时国内的一些制作单机游戏的工作室也开始了引擎的研发,例如当年的仙剑2,轩辕剑3以及大富翁4,都是采用了大宇旗下的DOMO工作室自主研发的游戏引擎打造,而当年金山旗下的西山居工作室也是凭借了其自主研发的OverMax引擎打造出来复活、秦殇等黑马级别的游戏,同一时期的经典游戏还有很多,2002年可谓是中国单机游戏的最后一个巅峰,之后便彻底沦入了网游的时代。

           在2001年之后诞生的引擎大多以追求画面的真实和内容的真实为主,同时也在朝着网络的方向探索,而在2005年之后,昔日的小弟引擎也终成为了引擎界的巨头,05年Epic游戏公司的Unreal 3问世,07年 CryEngine 2强势登场,08年第一款使用Frostbite Engine(寒霜)引擎打造的战地:叛逆连队发布,无一不标识这新的引擎时代到来。

           而国内的引擎大多因为后期无人维护以及技术落后的原因纷纷被遗弃,国产单机游戏市场也在欧美大作的冲击下逐渐萎缩,也只有个别工作室在勉力支撑,而所使用的引擎也大多是引入了国外的引擎,例如仙剑4,仙剑5,仙剑5前传以及轩辕剑所使用的RenderWare引擎(曾用于制作战地2,GTA系列游戏等),除此之外大多数公司都已转型,直到近两年来单机游戏才有回暖的趋势。在近两年来的单机游戏作品中血雨算是一款成功之作,而国内四剑游戏也仅有古剑奇谭的表现能称得上用心制之作,古剑2的画面在国内的游戏中已经可以算是相当高的水准了;而同样在13年发布的三剑之一的轩辕剑6曾被人称作是砸了Unity的招牌,在笔者看来说是Unity砸了轩辕剑更为贴切一些,毕竟目前的Unity 3D引擎用来做大型PC的确是有些勉强;13年另外一款备受关注的单机PC大作便是由玄黄工作室打造的凡人修仙传了,这款号称国内第一款ARPG游戏的大作在耗时三年精心制作后终于上市,可上市不久之后玄黄却解散了,其中原因不言而喻。14年有一个令笔者十分振奋的消息便是河洛工作室重组了,这个当年打造了金庸群侠传,武林群侠传,三国群侠传的工作室终于再一次的回到了单机游戏的视野中,而在7月18日西山区的新作新剑侠传奇也将上市(这游戏的人物模型是剑网3吗??),尽管宣传片看起来很一般,但笔者相信这款游戏能够延续剑侠情缘系列的经典。

           除了国内的单机游戏之外,国内的网络游戏引擎的发展也可谓是进步神速,其中的代表作品便是金山的剑网3和完美世界,但是这两款引擎距离国外的高富帅引擎仍然有着不小的差距。好在2012年国内出现了两款号称次时代引擎的家伙,一款为方舟工作室自主研发的AkEngine,代表作武魂;而另外一款就是搜狐畅游的黑火引擎了,黑火引擎曾经发布了一段名为代号X7的宣传片,实际为与大宇合作将要打造的轩辕剑7,但从宣传片上来看黑火引擎的画面的确可以追上世界一流引擎的步伐了,但实际效果如何还是要等到作品真正发布时再做讨论。

        尽管目前可供我们选择的优秀游戏引擎有很多,但是一款能否制作出来黑马游戏并不在于引擎本身,而在于使用它的人。因为游戏界的至理名言是"内容为王(content is king)"。

    展开全文
  • 作为服务器端JavaScript引擎的典型代表,Rhino引擎具有广泛的平台支持和应用基拙。通过将Rhino引擎置于一个标准的Javaservlet中,便可构造出一个支持JavaScript的服务端脚本容器。借助Rhino引擎,Web开发者不仅能在脚本...
  • 3D引擎

    千次阅读 2010-05-21 22:05:00
    简介 3D引擎是将现实中的物质抽象为多边形或者各种曲线等表现形式,在计算机中进行相关计算并输出最终图像的算法实现的集合。 分类 3D引擎根据是否能够被主流计算机即时计算出结果分为即时3D引擎和离线3D引擎。PC...

    简介  3D引擎是将现实中的物质抽象为多边形或者各种曲线等表现形式,在计算机中进行相关计算并输出最终图像算法实现的集合。

    分类

      3D引擎根据是否能够被主流计算机即时计算出结果分为即时3D引擎和离线3D引擎。PC机游戏机上的即时3D画面就是用即时3D引擎运算生成的,而电影中应用的3D画面则是用离线3D引擎来实现以达到以假乱真的效果。

      3D引擎对物质的抽象主要分为多边形和NURBS两种。在即时引擎中多边形实现已经成为了事实上的标准,因为任何多边形都可以被最终分解为容易计算和表示的三角形。而在离线引擎中为了追求最好的视觉效果会使用大量的NURBS曲线来实现多边形很难表现出的细节和灵活性。

    定义

      3D引擎作为一个名词已经存在了很多年,但即使是一些专业的引擎设计师,也很难就它的定义达成一个共识。通常来说,3D引擎作为一种底层工具支持着高层的图形软件开发。你可以把它看成是对3D API的封装,对一些图形通用算法的封装,对一些底层工具的封装。我无法准确的定义3D引擎的含义和作用,因为针对不同的用户和开发项目,3D引擎完成的功能可能都有不同。因此,我将从功能的角度来定义3D引擎,这种定义法也许能更确切的表达出一个3D引擎的真实含义。

    功能

      3D引擎最基本的功能应该包括:

    1. 对3维场景的数据管理

      这里的数据管理是一个比较广泛的定义,不同的3D引擎也许会拥有其中一个或多个功能。这些功能包括:场景管理,对象系统,序列化,数据与外部工具的交互,底层3维数据的组织和表示。

      场景管理:这个名称相信对3D引擎有一定认识的朋友都很熟悉了。通常它和SceneGraph同时存在于一些架构方面的资料中。由于3D引擎可能会用来管理一些庞大的3D世界,在这个世界中物体与物体之间通常存在一些 相关/从属/影响与被影响关系,如何组织这些关系,并确切的将这些关系与3D引擎的其他功能联系起来,就是场景管理需要完成的工作。常有朋友问我场景管理是用的哪种算法。从我的理解来讲,场景管理是一种设计模式,而不是一个具体的算法,也许你会最终选择BSP/QuadTree/Portal/...作为场景管理树的结构,但是这些已经是实现层面的东西了,而且它们也远远不是场景管理的全部。因此我认为Scene Manager 和Scene Graph manager 这两个概念还是分开理解比较好。

      场景管理首先需要考虑如果表达场景中物体的关联关系,这部分通常是由场景图来实现的。通过一个一对多的树形结构已经可以满足要求,当然考虑到数据层的共享和维护,允许子树进行Clone也是前期设计时需要考虑的一个方面。再此之后,就需要考虑物体之间材质的继承关系,动态环境如何嵌入到你选择的场景图中。在一个考虑到交互和触发机制的引擎中,还需要考虑物体之间如何发送消息。(比如一个结合了物理引擎的场景)。实际上在整个引擎中你所涉及到的各种算法和设计,都或多或少的会和场景管理发生联系。比如在一个实现动态光影的引擎中,物体之间如何实现相互遮挡,光源的影响范围如何在场景图上继承,都是在设计时需要考虑的问题。

    2。功能合理的渲染器

      之所以要说是合理的渲染器,是因为一个引擎的渲染能力是由多方面决定的。比如一款以实时游戏作为目标的游戏,会选择基于光栅化的渲染算法。在这种设计前提下,几何体一级的数据不会过于详细,例如物体表面的BRDF,折射率,纹理坐标空间的变化率,切线空间的变化率(当然随着硬件能力的提升和Shader能力的发展,这些数据也会出现在一些比较高级的游戏引擎中),这时候即使你在设计初期就考虑到这些数据需求,并将它们表现在了Render中,最后也不会由任何意义。

    3。与外部软件的交互能力

      简单的说,就是开发工具。任何一款3D引擎如果没有开发工具都不能称为是完整的。这些开发工具可能是一些文件转换器,场景编辑器,脚本编辑器,粒子编辑器....

      有了上面3种功能,就可以称为3D引擎了。当然,如果要开发一款功能强大的引擎,那还有很多很多的功能需要满足,其中一些功能将在后面的章节中有详细的描述。

    发展历史

    引擎的诞生(1992年~1993年)

      1992年,3D Realms公司/Apogee公司发布了一款只有2兆多的小游戏——《德军司令部》(Wolfenstein 3D),稍有资历的玩家可能都还记得初接触它时的兴奋心情,用“革命”这一极富煽动色彩的词语也无法形容出它在整个电脑游戏发展史上占据的重要地位。这部游戏开创了第一人称射击游戏的先河,更重要的是,它在X轴和Y轴的基础上增加了一根Z轴,在由宽度和高度构成的平面上增加了一个向前向后的纵深空间,这根Z轴对那些看惯了2D游戏的玩家造成的巨大冲击可想而知。 Wolfenstein 3D引擎的作者是大名鼎鼎的约翰·卡马克,这位id Software公司的首席程序师正是凭借这款Wolfenstein 3D引擎在游戏圈里站稳了脚跟。事实上,《德军司令部》并非第一款采用第一人称视角的游戏,在它发售前的几个月,Origin公司就已经推出了一款第一人称视角的角色扮演游戏——《创世纪:地下世界》(Ultima Underworld),这款角游戏采用了类似的技术,但它与Wolfenstein 3D引擎之间有着相当大的差别,举例来说,《地下世界》的引擎支持斜坡,地板和天花板可以有不同的高度,分出不同的层次,玩家可以在游戏中跳跃,可以抬头低头,这些特性Wolfenstein 3D引擎都无法做到,而且从画面上看,《德军司令部》更接近漫画风格而不是传统的像素画面。 尽管从技术细节上看,Wolfenstein 3D引擎比不上《创世纪:地下世界》的引擎,但它却更好地利用了第一人称视角的特点,快速火爆的游戏节奏使人们一下子记住了“第一人称射击游戏”这个单词,而不是“第一人称角色扮演游戏”。《德军司令部》后来还发布过一款名义上的续集——《三元的崛起》(Rise of the Triad),这款游戏在Wolfenstein 3D引擎的基础上增加了许多重要特性,包括跳跃和抬头低头等动作。 引擎诞生初期的另一部重要游戏同样是出自id Software公司的一款非常成功的第一人称射击游戏——《毁灭战士》(Doom)。Doom引擎在技术上大大超越了Wolfenstein 3D引擎,《德军司令部》中的所有物体大小都是固定的,所有路径之间的角度都是直角,也就是说你只能笔直地前进或后退,这些局限在《毁灭战士》中都得到了突破。尽管游戏的关卡还是维持在2D平面上进行制作,没有“楼上楼”的概念,但墙壁的厚度可以为任意,并且路径之间的角度也可以为任意,这使得楼梯、升降平台、塔楼和户外等各种场景成为可能。 由于Doom引擎本质上依然是二维的,因此可以做到同时在屏幕上显示大量角色而不影响游戏的运行速度,这一特点为游戏创造出了一种疯狂刺激的动作风格,在这方面迄今为止大约只有《英雄萨姆》(Serious Sam)系列能与之相比,除此之外还没有哪款3D引擎能在大批敌人向你涌来的时候依然保持游戏的流畅,这也是为什么如今市面上的大部分第一人称射击游戏都在积极地培养玩家的战术运用能力、提高玩家的射击准确率而拒绝滥砍滥杀的主要原因之一。值得一提的是,尽管Doom引擎缺乏足够的细节度,但开发者仍然在《毁灭战士》中表现出了惊人的环境效果,其纯熟的设计技巧实在令人赞叹。 不过更值得纪念的是,Doom引擎是第一个被用于授权的引擎。1993年底,Raven公司采用改进后的Doom引擎开发了一款名为《投影者》(ShadowCaster)的游戏,这是游戏史上第一例成功的嫁接手术。1994年Raven公司采用Doom引擎开发《异教徒》(Heretic),为引擎增加了飞行的特性,成为跳跃动作的前身。1995年Raven公司采用Doom引擎开发《毁灭巫师》(Hexen),加入了新的音效技术、脚本技术以及一种类似集线器的关卡设计,使你可以在不同关卡之间自由移动。Raven公司与id Software公司之间的一系列合作充分说明了引擎的授权无论对于使用者还是开发者来说都是大有裨益的,只有把自己的引擎交给更多的人去使用才能使引擎不断地成熟起来。 《毁灭战士》系列本身就相当成功,大约卖了350万套,而授权费又为id Software公司带来了一笔可观的收入。在此之前引擎只是作为一种自产自销的开发工具,从来没有哪家游戏商考虑过依靠引擎赚钱,Doom引擎的成功无疑为人们打开了一片新的市场。

    引擎的转变(1994年~1997年)

      在引擎的进化过程中,肯·西尔弗曼于1994年为3D Realms公司开发的Build引擎是一个重要的里程碑,Build引擎的“肉身”就是那款家喻户晓的《毁灭公爵》(Duke Nukem 3D)。《毁灭公爵》已经具备了今天第一人称射击游戏的所有标准内容,如跳跃、360度环视以及下蹲和游泳等特性,此外还把《异教徒》里的飞行换成了喷气背包,甚至加入了角色缩小等令人耳目一新的内容。在Build引擎的基础上先后诞生过14款游戏,例如《农夫也疯狂》(Redneck Rampage)、《阴影武士》(Shadow Warrior)和《血兆》(Blood)等,还有台湾艾生资讯开发的《七侠五义》,这是当时(至今依然是)国内不多的几款3D射击游戏之一。Build引擎的授权业务大约为3D Realms公司带来了一百多万美元的额外收入,3D Realms公司也由此而成为了引擎授权市场上的第一个“暴发户”。不过从总体来看,Build引擎并没有为3D引擎的发展带来任何质的变化,突破的任务最终由id Software公司的《雷神之锤》(Quake)完成了。 《雷神之锤》紧跟在《毁灭公爵》之后发售,两者孰优孰劣一时之间成为玩家的热门话题。从内容的精彩程度来看《毁灭公爵》超过《雷神之锤》不少,但从技术的先进与否来看,《雷神之锤》是毫无疑问的赢家。Quake引擎是当时第一款完全支持多边形模型、动画和粒子特效的真正意义上的3D引擎,而不是Doom、Build那样的2.5D引擎。此外Quake引擎还是连线游戏的始作俑者,尽管几年前的《毁灭战士》也能通过调制解调器连线对战,但最终把网络游戏带入大众的视野之中的是《雷神之锤》,是它促成了电子竞技产业的发展。 一年之后,id Software公司推出《雷神之锤2》,一举确定了自己在3D引擎市场上的霸主地位。《雷神之锤2》采用了一套全新的引擎,可以更充分地利用3D加速和OpenGL技术,在图像和网络方面与前作相比有了质的飞跃,Raven公司的《异教徒2》(Heretic II)和《军事冒险家》(Soldier of Fortune)、Ritual公司的《原罪》(Sin)、Xatrix娱乐公司的《首脑:犯罪生涯》(Kingpin:Life of Crime)以及离子风暴工作室去年夏天刚刚发布的《安纳克朗诺克斯》(Anachronox)都采用了Quake II引擎。 Quake II引擎的授权模式大致如下:基本许可费从40万美元到100万美元不等,版税金视基本许可费的多少而定,40万美元的许可费大约需提取10%以上的版税金,100万美元的许可费则提取很少一部分版税金。这样算下来,《雷神之锤2》通过引擎授权所获得的收入至少有一千万美元,尽管游戏本身的销售业绩比起《毁灭战士》来要差很多,大约卖了110多万套,收入在4500万美元左右,但在授权金这一块它所获得的盈利显然要远远高于《毁灭战士》,此时的引擎已经从一种单纯的工具变成了一块令人垂涎欲滴的肥肉。 俗话说“一个巴掌拍不响”,没有实力相当的竞争者,任何市场都无法发展起来的。正当Quake II独霸整个引擎市场的时候,Epic Megagames公司(即现在的Epic游戏公司)的《虚幻》(Unreal)问世了。毫不夸张,第一次运行这款游戏的时候,我的确被眼前的画面惊呆了,尽管当时只是在300x200的分辨率下运行的这款游戏(四大悲事之一:玩游戏机器不够劲)。除了精致的建筑物外,游戏中的许多特效即便在今天看来依然很出色,荡漾的水波,美丽的天空,庞大的关卡,逼真的火焰、烟雾和力场等效果。从单纯的画面效果来看,《虚幻》是当之无愧的佼佼者,其震撼力完全可以与人们第一次见到《德军司令部》时的感受相比。 Unreal引擎可能是使用最广的一款引擎,在推出后的两年之内就有18款游戏与Epic公司签订了许可协议,这还不包括Epic公司自己开发的《虚幻》资料片《重返纳帕利》,其中比较近的几部作品如第三人称动作游戏《北欧神符》(Rune)、角色扮演游戏《杀出重围》(Deus Ex)以及永不上市的第一人称射击游戏《永远的毁灭公爵》(Duke Nukem Forever),这些游戏都曾经或将要获得不少好评。 Unreal引擎的应用范围不限于游戏制作,还涵盖了教育、建筑等其它领域。Digital Design公司曾与联合国教科文组织的世界文化遗产分部合作采用Unreal引擎制作过巴黎圣母院的内部虚拟演示,Zen Tao公司采用Unreal引擎为空手道选手制作过武术训练软件,另一家软件开发商Vito Miliano公司也采用Unreal引擎开发了一套名为“Unrealty”的建筑设计软件,用于房地产的演示。 这款与《雷神之锤2》同时代的引擎经过不断的更新,至今依然活跃在游戏市场上,丝毫没有显出老迈的迹象,实属难得。

     

    展开全文
  • 3D游戏引擎剖析

    千次阅读 2015-02-21 10:11:09
    介绍 自Doom游戏时代以来我们已经走了很远。 DOOM不只是一款伟大的游戏,它同时也开创了一种新的游戏编程...大量的新游戏根据已经存在的游戏引擎开发出来,而大多数都以ID公司的Quake引擎为基础, 这些游戏包括Coun
  • 让你彻底明白什么叫游戏引擎(2) 二、引擎的进化 曾经有一段时期,游戏开发者关心的只是如何尽量多地开发出新的游戏并把它们推销给玩家。尽管那时的游戏大多简单粗糙,但每款游戏的...
  • 1992年,3D Realms公司/Apogee公司发布了一款只有2兆多的小游戏—《德军司令部》(Wolfenstein 3D),稍有资历的玩家可能都还记得初接触它时的兴奋... Wolfenstein 3D引擎的作者是如今大名鼎鼎的John Carmack,这位id
  • 游戏引擎扫盲

    千次阅读 2009-07-13 12:14:00
    以下是摘自日本著名杂志《FAMI通》... 一、什么是引擎 我们可以把游戏的引擎比作赛车的引擎,大家知道,引擎是赛车的心脏,决定着赛车的性能和稳定性,赛车的速度、操纵感这些直接与车手相关的指标都是建立在引擎的基
  • 游戏引擎剖析

    千次阅读 2012-06-27 13:02:01
    为了解决“如何在IPHONE上创建一个游戏”这个大问题,我们需要首先解决诸如“如何显示图像...我们将会讨论一个游戏引擎的所有主要部分,包括应用程序框架、状态机、图像引擎、物理引擎、声音引擎、玩家输入和游戏逻辑。
  • 游戏引擎基础

    千次阅读 2011-03-22 16:34:00
    <br />游戏引擎基础(一)(渲染和构造3D世界) 来源:IIEEG03-22-2011 第1部分: 游戏引擎介绍, 渲染和构造3D世界 <br />介绍  自Doom游戏时代以来我们已经走了很远。 DOOM不只是一款...
  • 地鼠 gopherchess是用go编写的快速(可能)的cr国际象棋引擎。 要运行测试,请执行以下操作: 去测试 要运行小象,请执行以下操作: 去建造 ./gopherchess
  • 本文介绍了Rhino脚本引擎,如何在Java中使用脚本引擎调用javascript,以及javascript和java间的交互,并给与示例代码。
  • 实现了简单的搜索引擎,爬虫,网页处理 建立正派索引,倒排索引,实现检索
  • 物理引擎与游戏引擎

    万次阅读 2012-10-27 08:26:26
    找到这些,特意送给那些分不清物理引擎和游戏引擎的童鞋们 物理引擎: 物理引擎通过为刚性物体赋予真实的物理属性的方式来计算它们的运动、旋转和碰撞反映。为每个游戏使用物理引擎并不是完全必要的——简单的...
  • 游戏引擎演化史

    千次阅读 2010-07-09 20:55:00
      一、什么是引擎  我们可以把游戏的引擎比作赛车的引擎,大家知道,引擎是赛车的心脏,决定着赛车的性能和稳定性,赛车的速度、操纵感这些直接与车手相关的指标都是建立在引擎的基础上的。...
  • IPHONE游戏引擎介绍

    2010-08-20 22:29:00
    程序员用高层次的本来定义角色和属性,engine就负责来渲染。来源:http://www. GarageGames.com cocos2d: 是port到IPhone上的流行的2D游戏引擎。它有很多引人入胜的屏幕特效,比如翻页,cinematic wipes.来源...
  • 搜索引擎探讨

    千次阅读 2005-04-19 21:16:00
    一,GOOGLE简介 Google(www.google.com)是一个搜索引擎,由两...2000年7月份,Google替代 Inktomi成为Yahoo公司的搜索引擎,同年9月份,Google成为中国网易公司的搜索引擎。 98年至今,GOOGLE已经获得30多项业界大奖
  • 3D游戏引擎FAQ

    千次阅读 2011-03-22 21:08:00
    hanhonglei@cuc.edu.cn<br />blog:http://hanhonglei.spaces.live.com/<br /><br /><br />1. 3D引擎(3D engine)、3D编程语言(3D language)和3D创作系统(3D authoring system)的区别是什么? 3D引擎是3D...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 22,384
精华内容 8,953
关键字:

引擎脚是什么