首 页技术文章资源下载WAP论坛用户中心繁體中文
设为首页
加入收藏
联系我们
您当前的位置:中国WAP技术门户网站 -> 技术文章 -> 手机编程 -> Symbian -> 游戏开发 -> 文章内容 退出登录 用户管理
热门文章
· [转载] wap2.0技巧篇
· [转载] WAP 2.0简介
· WML语言基础(WAP建站...
· [转载] WAP/WEB网站建设
· JSP技术在WAP开发中...
· [图文] WML语言基础(WAP建站...
· WML语言基础(WAP建站...
· [转载] 《女性安全期测算》...
· [转载] 跟你详说WAP
· asp.net开发wap程序...
相关文章
 
开发Smartphone游戏
文章作者:不详 [ 收藏此页到365Fav ]
文章来源:转载 [ 收藏此页到365Key ]
发布时间:2005-9-21 9:25:08 减小字体
文章编辑:小凯 增大字体
游戏的开发

  移动电话上的游戏开发过程与基于PC的游戏开发过程类似。PC游戏的开发过程包括从无图形到图形化,从单个玩家到多个玩家,从不相连接到Internet互联。经过这么多年,移动电话游戏已相当于从无图形发展到低层次图形化的PC游戏。尽管很多游戏开发者已经开始包含了对更好图形的支持,但是目前移动电话带有的内建游戏几乎都没有图形化。

  有了Smartphone,移动电话业可能获得与PC游戏市场类似的巨大收益。预计为Smartphone发布第一批游戏是已经存在的Windows和Pocket PC游戏。因为开发人员可以使用相同的开发工具、编程语言和操作系统API(应用程序编程接口),将这些游戏转换为Smartphone游戏的成本很小。

  游戏正在转换到Smartphone上

  游戏的开发和质量都很依赖于目标平台的能力和可供使用的游戏引擎。作为Smartphone软件开发工具包(SDK)的补充,下面的游戏引擎是可用的:

  · Fathammer's X-Forge? 3D Game Engine

  · Tao's Group intent multimedia Java (J2ME MIDP) platform

  · Amiga Anywhere

  点击这些链接可以查看到它们为Smartphone用户提供的丰富的游戏能力。

  编写高效率游戏

  用户和开发者之间的一个通常的误解是现代的ARM处理器在速度上与Pentium处理器相近。可是那种比较无法正常反映ARM处理器的能力。老式的Pentium速度是基于ARM的Smartphone和Pocket PC的数倍。这归咎于处理器本身和支持它的平台。

  Pentium是超级标量的(它在一个时钟周期内执行一条以上的指令),它有五个平行的执行单元和一个综合的浮点运算单元。在大多数PC中通常建有内部的L1缓存和丰富的外部L2缓存。

  目前基于ARM的Smartphone和Pocket PC的标量是最好的(它们在一个周期内能执行一个指令)。但是指令集有严格的限制,只包含最基本的指令。更多的高级指令不存在,只能在软件中模拟。

  另一个问题是怎样使用指令和数据填满处理器以保证它一直全速度运行。大多数的设计使用单个16位总线处理指令和数据。因为所有的指令是32位的,为了填满代码指令管道,总线的速度必须是处理器的两倍。情况不是这样的,因为总线的速度比处理器慢。处理器速度是总线的2到4倍,一个66MHZ,16位的总线最多只能给33MHZ的ARM处理器提供足够的指令(不包括你要处理的数据)。为了解决这个问题,大多数ARM处理器包括了一个指令缓存和一个数据缓存。典型的指令和数据缓存的大小都是8Kb,有一些有32Kb。只要请求的代码指令或者数据在缓存中,CPU就可以全速度直接从缓存中取,不需要通过缓慢的内存总线。但是一旦开始访问没有载入缓存的代码和数据,效率就切换到<33MHZ(给定的是66MHZ,16位总线)。实际上,将ARM处理器从133MHZ降为2MHZ很简单,只有把数据使用低效率的方式组织。

  但是如果有错误的数据类型和低效率的代码,这还算是快的。执行大量的除法,或者滥用浮点数据类型,CPU将只能每秒钟执行20万条代码指令。

  内存访问和带宽

  Smartphone也可以装备多个基于ARM的处理器,每一个有不同的内存访问花消,但是你会发现仅有太小的缓存和太慢的内存总线,以至于你不能忽略这种花消。

  例如,处理器运行频率为132MHZ,而内存总线是16位的,并运行在66MHZ。每次你读取不在处理器缓存中的字节,处理器首先要填充一个完整的缓存线(cache line)。一个缓存线也许是16个字(在ARM体系结构中一个字等于32位或者4个字节),这意味着一个缓存线是16×4=64字节。由于内存总线是16位的,在完成前它需要32个周期填充,更糟的是,总线速度只有处理器的一半,因此处理器在读取该字节前将停止64个周期。因此要确信缓存线填充是值得的。同样,要确认内存是紧密组合的,并检查内存访问模式看是否可以重新排列结构使运行效率更高。如果你有规律的访问一个结构中的一个数据成员并且处理大量的这种结构,看看是否能移动这些特定数据到自己的数组中。

  因为这个原因,尽可能使用字节(8位)或者双字节(16位),因为ARM处理器在内存载入寄存器过程中能将无标记、标记字节和双字节扩展为字。但是,在从寄存器保存标记值到字节和双字节内存位置时,编译器将产生两条额外的转换指令,目的是确保如果寄存器中的值太大而无法填充指定的内存位置时,值可以保持自己的标志位。在ARM上,一个转换可能是自由的--几乎每一条正常的指令都可以与一条转换指令耦合--这依赖于编译器的效率。这是你对内部循环必须知道的信息。每次使用字节或者双字节变量,在可能的情况下都使用无标志的数据类型。

  内存管理

  你也许知道通用的内存管理程序和函数,例如malloc、realloc和new (通常是malloc的包装)速度都非常慢。你最好分配前台需要的内存并使用自己的内存管理程序。这是你的游戏项目中的最重要的子系统。在开发期间,你能轻易地插入一致性检查、测试错误指针,并确认所有的释放和删除与分配相匹配。

  最好分配大小结构相等的数组并使用位掩码(bitmask)来处理分配和取消分配。

  消息系统

  最重要的第二个系统应该是可靠的消息系统,不是指的传统Windows消息泵系统。游戏对象间所有的交互都可以通过你的专用消息系统实现。这包括设置消息发送时间(time-of-delivery),这样你就可以在未来的某个时刻向对象发送消息。例如当游戏玩家选择开启电源项,你可以简单的在5秒内给自己发送一个"激活电源"消息。由于没有保证对象在消息送达时仍然是活动的,你永远不能使用指针。句柄是实现的方法。有了一个这样的系统,很容易添加重放(replay)函数,因为你的中心消息系统可以在游戏进行时简单地保存所有消息到一个文件中。接着重放系统简单地从该文件中读回所有消息并按次序发送所有消息。这对于调试很好--简单地添加一个控制台或者记录文件,在那儿你可以实时看到所有消息--或者执行准确相同的消息流直到应用程序崩溃的位置。

  甚至对象的建立和删除也应该使用消息,用户的输入也是一样的。唯一丢失的是对象的所有者信息,你能把该消息系统扩展到另一个计算机--它是多用户系统的基础。因为所有的交互都通过该消息系统完成,你的游戏逻辑的消息没有什么区别,无论它是人、AI玩家还是网络玩家发送的。

  资源管理

  重复一遍,不要使用指针访问对象。所有的资源都要用句柄来引用。为了提高效率,你可能允许锁定/解除锁定短代码段中资源,但是资源永远不能跨越一个时段锁定(不要锁定多个页面)。通过添加一个用户计数器,你能重复使用只读资源并节约内存。而且即使用户计数器返回为零也不必真正地释放资源。通过将资源保持在内存中,你在下次需要这些资源时几乎不需要时间载入它们。一个好的办法是分配足够的内存来存放你同时需要的所有资源,或者75%的系统空闲内存,无论哪个最大。通过使用额外的内存存储资源这种途径,你能利用更强大的设备。

  你的资源管理器应该知道怎样重新载入每种资源项。有了这种知识,就能够释放资源项拥有的内存并重新载入它们,而不影响剩余的游戏代码。释放所有资源内存是放弃焦点给其它应用程序的一种自然的响应,再次获得焦点时重新载入它们。这种情况应该自动发生,对于剩余的代码应该完全透明。

  不要使用浮点运算

  ARM处理器对于浮点数学运算没有原本(native)支持。所有的浮点运算都在浮点模拟器中运行,速度很慢。在浮点函数中需要上百万次运算的现象并不少见。这就是游戏项目使用定点(fixed point)运算代替的原因。定点实际上仅仅是一个整数,在那儿你指定了一定数量的位作为值的分数部分。通常1000以下的所有数字都是数的分数部分。为了表达0.500,简单地放大1000倍成为500。困难的部分是在任意时刻都可以想到这些不可见的小数点。加法和减法工作得很好:500+500=1000(或者0.500+0.500=1.000)。乘法和除法就有问题了:500*500=250000(或者0.500*0.500=250.000)出错了。在两个定点值相乘后,你得处理结果。如果结果除1000,就是对得结果(250.000/1000=0.250是正确的)。因此乘法中,要执行通常的乘法并将结果正常化。

  这是另一个有趣的话题。在正常化前,中间结果中数据的范围是多少?在上面的例子中,执行乘法时,可能超出了变量的位数, 意味着溢出了并丢失了结果的标志部分。解决技巧是确认使用可以保留最大结果的中间结果数据格式。当两个32位值相乘时,中间结果值应该是64位。在正常化后,位数再次变为32。

int Multiply16_16_by_16_16( int a16_16, int b16_16 )
{
__int64 tmp32_32;
int result16_16;
tmp32_32 = a16_16;
tmp32_32 *= b16_16;
// result is now 32:32
tmp32_32 >>= 16; // chop off the lower 16 bits
result16_16 = ( int ) tmp32_32; // chop off the upper 16bits.
// result is now back at 16:16
return result16_16;
}

  除法的做法相反:先乘在除。

  通常的定点格式是16:16,前面的16位是整数部分,低16位是小数部分。在我目前的游戏项目中,我使用了大量不同的格式,为了在游戏引擎不同部分使用不同值的范围。我使用了2:30、8:24、16:16、24:8、28:4、2:14、8:8、11:5、2:8和4:4。它们中的大多数是32位值,也有一些是16位、10位和8位的。

 

[1] [2]  下一页

 
[] [返回上一页] [打 印] [收 藏]
∷相关文章评论∷    (评论内容只代表网友观点,与本站立场无关!) [更多评论...]

关于我们  |   版权声明  |   广告服务  |   帮助中心  |   联系我们  |   网站地图  |   友情链接 
Copyright © 2004-2005 Wapzj.Com. All Rights Reserved .
粤ICP备05000730号 在线人数: