科技行者

行者学院 转型私董会 科技行者专题报道 网红大战科技行者

知识库

知识库 安全导航

至顶网软件频道基础软件如何开发Smartphone游戏?(2)

如何开发Smartphone游戏?(2)

  • 扫一扫
    分享文章到微信

  • 扫一扫
    关注官方公众号
    至顶头条

Smartphone是第一款有足够处理能力和图形能力的移动电话,它将我们希望的PC平台的游戏经验带到了移动世界。本文给出了开发Smartphone游戏的详细过程,供大家参考!

作者:IT专家网  来源:IT专家网  2007年9月1日

关键字:

  • 评论
  • 分享微博
  • 分享邮件

资源管理

重复一遍,不要使用指针访问对象。所有的资源都要用句柄来引用。为了提高效率,你可能允许锁定/解除锁定短代码段中资源,但是资源永远不能跨越一个时段锁定(不要锁定多个页面)。通过添加一个用户计数器,你能重复使用只读资源并节约内存。而且即使用户计数器返回为零也不必真正地释放资源。通过将资源保持在内存中,你在下次需要这些资源时几乎不需要时间载入它们。一个好的办法是分配足够的内存来存放你同时需要的所有资源,或者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位的。

不要使用除法

游戏项目不应该执行单个除法。ARM处理器也没有除法的原本支持。每次执行除法将花费几百万次周期。理论上一个132MHZ的ARM处理器每秒能够处理1.32亿条指令(如果50%进行了变换可以处理2.64亿条)。但是CPU每秒中最多只能处理70000次除法。如果游戏每秒显示70个页面,假设描绘每个页面执行仅仅1000次除法,处理器就满速度运行了。

试着用移位和/或乘法代替除法。除以16可以写作右移4位。更复杂的除法能用移位和/或乘法的组合完成。

除法也可以使用查找(lookup)表执行。但是如果分子和分母都是32位的,就需要一个两维的查找表,它远远超出了内存的容量。解决得方法是减小问题的范围。

在表达式a / b中,在不改变最后结果的情况下可以插入乘以1,即a * 1 / b产生相同的结果。另外,可以重新组织乘法和除法的次序,例如写为a * (1 / b )。现在除法简化为1 / b,只需要一个一维查找表了。你可以通过减小精度进一步减小查找表。在大多数情况下16位精度是足够的,查找表就只需要64K了。通过查找b中最重要的位(most significant bit,MSB),你能使用这些信息向上或者向下变换b和结果以适用于32位值,并保持最高可能的分辨率。即使包括了随机访问除法查找表来填充缓存线的时间,执行周期也少于100个--比编译器提供的标准除法速度提高了20倍--只减小了一点点精度。

使用数据类型提供足够的分辨率来处理问题的范围。

内存访问是获得高性能代码的最重要的方式。这意味着应该使用尽可能小的数据类型满足问题的需要。在网眼中真的需要16位索引吗?能不能将位数减少为8?使用最大256个边、256个顶点、256个亮度/阴影值、256个多边形、256个法线和256个相应的纹理,你也许不得不将一些网眼拆分为多个更小的网眼。它得好处是内存访问更快。

你怎样使用正常的向量?你主要用于亮度计算或者可视化测试吗?我为自己的向量组件使用2:8的定点格式,意味着可用范围是-1.99609375 到+1.99609375,分辨率为0.00390625。我使用8位小数分辨率满足1.4度分辨率下360度的需要。在小屏幕(例如176x220)中,没有人可以分辩除亮度有+/- 0.7度差错的点。它的好处是我能把x、y和z组件存储在一个字中。

为每个部件使用查找表

为每个预先计算的项建立查找表只会花费一点内存访问。与复杂的数需计算函数相比(它需要执行几百万条指令),这是划算的,尽管你不得不放弃一部分内存来存储查找表。

查找表的典型元素是倒数除法(1 / x)、正弦计算、颜色混合和亮度。在我目前的游戏项目中,几乎实体环境映射和亮度/阴影通道都使用一对预先计算查找表来执行。

游戏有趣的地方是我们试图使人们相信它们是活生生的世界的一部分。如果它看起来好、感觉正常,我们就达到了目的,无论我们使用什么方法使它发生。足够好是我们优化的目标。

    • 评论
    • 分享微博
    • 分享邮件
    邮件订阅

    如果您非常迫切的想了解IT领域最新产品与技术信息,那么订阅至顶网技术邮件将是您的最佳途径之一。

    重磅专题
    往期文章
    最新文章