安卓游戏开发手册(三)

原文:zh.annas-archive.org/md5/677EF72CE0EEA561393A2FD5106AE241

译者:飞龙

协议:CC BY-NC-SA 4.0

第八章:性能和内存优化

优化是任何开发周期中最重要的任务之一。尤其是对于游戏来说是不可避免的。游戏优化显著提高了性能。通过优化,可以针对更多的硬件平台。

您已经了解到安卓支持一系列硬件平台。每个平台都有单独的配置。通过优化硬件资源的使用,游戏可以在更多的硬件平台上运行。这种技术也可以应用于视觉质量。并非所有设备都具有相同的显示质量,因此为低分辨率优化资源可以节省大量的存储空间以及运行时的堆内存。

在编程中,开发人员经常编写中间代码,然后忘记对其进行优化。这可能导致大量的性能损失,甚至导致游戏崩溃。

我们将通过以下主题讨论安卓游戏开发中各种优化的范围:

  • 安卓游戏中的优化领域

  • 性能和内存管理之间的关系

  • 安卓中的内存管理

  • 安卓中的处理段

  • 不同的内存段

  • 内存优化的重要性

  • 性能优化

  • 增加帧率

  • 性能优化的重要性

  • 常见的优化错误

  • 最佳优化实践

安卓游戏中的优化领域

我们都知道在任何开发项目中都需要优化。在游戏开发的情况下,这一事实仍然如此。在游戏开发项目中,流程始于有限的资源和设计。开发后,预期游戏能在尽可能多的设备上以最高质量运行。为了实现这一点,内存和性能优化变得必不可少。因此,让我们讨论以下四个优化领域:

  • 资源优化

  • 设计优化

  • 内存优化

  • 性能优化

资源优化

资源优化基本上是优化艺术、声音和数据文件。

艺术优化

我们已经讨论了许多优化技术和工具。在这里,我们将讨论艺术优化的必要性。

艺术在游戏中在视觉上是最重要的部分。提高艺术品的显示质量会增加处理和存储成本。

大纹理占用大量内存。然而,将艺术放大以适应更大分辨率的屏幕会影响视觉质量。因此,必须取得平衡。此外,各种安卓设备对纹理大小有各种限制。此外,着色器在较大纹理上的工作需要更多时间。

开发人员常犯的一个错误是对完全不透明的纹理使用 alpha 信息。这会显著增加纹理大小。

艺术资源可以根据艺术风格进行优化。许多开发人员使用单色纹理而不是渐变色。单色信息可以容纳在 8 位像素数据中。这再次节省了磁盘空间和处理时间。

尽管存在这些优化范围,开发人员可能不会全部使用,以增加灵活性,从而在不花费太多时间进行优化的情况下创建高质量的视觉艺术。

声音优化

声音是游戏中另一个重要的资源。音频可以被压缩以节省空间和精力。在安卓游戏行业中,一种常见做法是对长音频文件使用压缩格式。

在运行时压缩和解压文件需要时间。因此,如果 SFX 被压缩,动态使用可能会成为问题。它可能会触发显著且可见的卡顿。开发人员喜欢对 SFX 使用未压缩格式,并对长时间连续播放的声音(如背景音乐)使用压缩格式。

数据文件优化

有时,游戏开发人员使用单独的数据文件来创建灵活的项目结构,以便与外部工具交互或获得更好的数据接口。这些文件通常以文本、XML、JSON 或二进制格式存在。开发人员可能会创建自己的二进制模型数据格式。

如果使用正确的算法,二进制数据可以快速处理。数据优化并没有太多技术性。然而,开发人员始终需要检查数据量和总文件大小。

设计优化

设计优化用于增加游戏的可扩展性、质量体验、灵活性和耐久性。主要方法是围绕核心游戏概念重组或修改游戏参数。

让我们从功能的角度将这一部分分为两部分:

  • 游戏设计优化

  • 技术设计优化

游戏设计优化

游戏在游戏设计优化阶段可能与最初的想法完全不同。设计优化是基于某些任务进行的。开发人员需要找到不同的方式来传达基本的游戏理念。然后,他们可以选择最佳的方式,进行一些分析。

游戏设计应该足够灵活,以适应运行时变化,以改善整体体验并增加用户数量。高度优化的游戏设计足够高效,可以预测用户行为、各种设备上的游戏性能,甚至货币化。

游戏控制系统设计必须足够优化,以便轻松完成所有任务。游戏控制应该易于发现和理解。对于 Android 触摸设备,控件的放置也非常重要。

技术设计优化

技术设计优化仅限于开发周期。它设置了项目结构、程序结构、开发平台依赖等。

技术设计文档还规定了游戏的范围和规模。这些规范有助于在设备上顺利运行游戏,因为硬件平台已经在技术设计文档中涵盖。

这是一个预开发过程。这份文件需要处理一些假设。这些假设应该足够优化,以便在实时情况发生时进行演变。

技术设计还可以在开发过程中处理以下任务。通过优化这些任务,实施和执行将更加容易:

  • 程序架构

  • 系统架构

  • 系统特性

  • 定义的依赖关系

  • 影响

  • 风险分析

  • 假设

所有这些任务都可以优化,以便更轻松地进行更好的开发周期,游戏将更加精致,并且性能更高。

内存优化

内存优化对于任何软件开发过程都是必需的。内存根据硬件配置有其物理限制,但游戏和应用程序不能为每个设备单独制作。

在技术设计中,应该提到游戏在所有目标硬件平台上的内存使用范围。现在,游戏占用的内存超出预期是非常常见的情况,最终导致游戏崩溃。开发人员会收到内存溢出异常。

为了避免这种情况,有两个主要的事情需要注意:

  • 保持内存峰值在定义范围内

  • 不要在内存中保留不必要的数据加载

Android 使用分页和映射来管理内存使用。不幸的是,它不提供内存交换。Android 知道在哪里找到分页数据并相应地加载。

以下是一些优化 Android 游戏内存的技巧。

不要在运行时创建不必要的对象

开发人员经常在循环内创建中间数据对象。这会留下内存印记,供垃圾收集器收集。以下是一个例子:

//Let's have an integer array list and fill some data
List<int> intListFull = new ArrayList<int>();
//Fill data
for( int i = 0; i < 10; ++ i)
{
  intListFull.add(i);
}

// No we can have two different approach to print all 
// values as debug log.
// Approach 1: not optimized code
for ( int i = 0; i < intListFull.size() ; ++ i)
{
  int temp = intListFull.get(i);
  Log.d("EXAMPLE CODE", "value at " + i + " is " + temp);
}
// List size will be calculated in each cycle, temp works 
//as auto variable and create one memory footprint in each 
//loop. Garbage collector will have to clear the memory. 

// Approach 2: optimized code
int dataCount = intListFull.size();
int temp;
for ( int i = 0; i < dataCount ; ++ i)
{
  temp = intListFull.get(i);
  Log.d("EXAMPLE CODE", "value at " + i + " is " + temp);
}
// only two temporary variable introduced to reduce a foot 
//print in each loop cycle.

尽可能使用基本数据类型

用户定义的数据类型比原始数据类型占用更多的内存空间。声明一个整数所占用的空间比将整数嵌入类中要少。在 Android 中,如果开发人员使用Integer类而不是int,数据大小会增加四倍。

对于 Android 编译器(32 位),int消耗 4 字节(32 位),而Integer消耗 16 字节(128 位)。

对于现代 Android 设备,有限使用这种数据类型可能对内存没有显著的影响。然而,大量使用非原始数据类型可能会导致大量的内存块,直到开发人员或垃圾收集器释放内存。

因此,开发人员应避免使用enum,而是使用静态最终的intbyteenum作为用户定义的数据类型,比原始数据类型占用更多的内存。

不要使用未管理的静态对象

在旧版 Android 中,静态对象不会自动销毁是一个常见问题。开发人员过去需要手动管理静态对象。在新版 Android 中,这个问题已经不存在。然而,在游戏中创建许多静态对象并不是一个好主意,因为静态对象的寿命等于游戏的寿命。它们会长时间地直接阻塞内存。

使用太多静态对象可能导致内存异常,最终导致游戏崩溃。

不要创建不必要的类或接口

每个类或接口在其实例中都有一些额外的绑定空间。模块化编程方法要求在编码结构中尽可能多地进行分解。这与类或接口的数量成正比。这被认为是一种良好的编程实践。

然而,这对内存使用有影响。更多的类消耗更多的内存空间来存储相同数量的数据。

使用最小可能的抽象

许多开发人员在多个层次上使用抽象以获得更好的编程结构。限制自定义库的某一部分并仅提供选择性的 API 非常有用。在游戏开发方面,如果开发人员只开发游戏,那么抽象的使用并不是非常必要的。

抽象导致更多的指令,直接导致更多的处理时间和更多的内存使用。因此,即使抽象有时可能很方便,开发人员在开发游戏时使用抽象之前应该三思而后行。

例如,一个游戏可能有一组不同的敌人。在这种情况下,创建一个单一的敌人接口,并为不同的敌人对象实现它,有助于创建一个简单和方便的程序层次结构。然而,不同的敌人可能有完全不同的属性。因此,抽象的使用将取决于游戏设计。无论情况如何,如果开发人员使用抽象,那么它将始终增加要在运行时处理的指令集。

对服务进行检查

服务对于在后台完成一个任务非常有用,但在处理和内存方面非常昂贵。除非必要,开发人员不应该保持服务运行。自动管理服务生命周期的最佳方法是使用IntentService,它在工作完成后将结束。对于其他服务,开发人员有责任确保在任务完成后调用stopServicestopSelf

这个过程对游戏开发非常有效,因为它积极支持用户和开发人员之间的动态交流。

优化位图

位图是游戏中最重的资源。在游戏开发中,大部分堆内存都被位图使用。因此,优化位图可以显著优化运行时堆内存的使用。

通常,将位图加载到内存所需的内存由以下公式给出:

BitmapSize = BitmapWidth * BitmapHeight * bytePerPixel

例如,如果以ARGB_8888格式(4 字节)加载一个 480 x 800 大小的位图,内存将如下:

位图大小 = 480 x 800 x 4 = 1536000 字节〜1.5mb

在 Android 中,格式可以是以下类型之一:

  • ARGB_8888(4 字节)

  • RGB_565(2 字节)

  • ARGB_4444(2 字节)(在 API 级别 13 中已弃用)

  • ALPHA_8(1 字节)

每个位图将根据前述公式占用内存。因此,建议根据需要将位图加载到内存中,以避免不必要的堆使用。

释放不必要的内存块

就像我们之前讨论释放内存一样,同样的方法也可以应用于任何对象。任务完成后,实例应设置为 null,以便垃圾收集器可以识别并释放分配的内存。

在游戏状态机中,类结构应提供一个接口来释放实例化对象的内存。可能会出现这样的情况,其中一些成员对象已完成其任务,而另一些仍在使用中,因此等待整个类实例被释放是一个坏主意。开发人员应选择性地释放未使用对象的内存,而不删除类实例。

使用 zipalign 和 ProGuard 等外部工具

ProGuard 工具通过删除未使用的代码和使用安全和编码的命名结构重命名类、字段和方法,有效地缩小、优化和混淆代码。ProGuard 可以使代码更加紧凑,这直接影响 RAM 的使用。

在游戏开发中,开发人员经常使用许多第三方库,这些库可能已经使用 ProGuard 预编译。在这些情况下,开发人员必须配置 ProGuard 以排除这些库。还可以保护代码库免受盗窃。

zipalign 可用于重新对齐发布的 APK。这进一步优化 APK,以使用更少的空间并具有更紧凑的大小。通常,大多数 APK 构建框架会自动提供 zipalign。但是,开发人员可能需要在少数情况下手动使用它。

性能优化

性能意味着游戏在目标平台上运行的流畅程度,并在整个游戏过程中保持良好的 FPS。在 Android 游戏的情况下,我们已经了解到各种硬件配置的广泛范围。在所有设备上保持相同的性能实际上是不可能的。这就是开发人员选择目标硬件和最低硬件配置的原因,以确保游戏的性能足够好以发布。但是,期望也因设备而异。

在实际开发约束中,性能优化受限于目标硬件集。因此,内存在开发过程中有自己的优化空间。

从编程角度来看,性能优化可以通过更加关注编写和构造代码来实现:

  • 尽量每个任务使用最少的对象

  • 尽量减少浮点数的使用

  • 尽量减少抽象层

  • 尽可能使用增强循环

  • 避免为内部使用的变量使用 getter/setter

  • 对常量使用 static final

  • 尽量减少内部类的使用

尽量每个任务使用最少的对象

创建不必要的对象会增加处理开销,因为它们必须在新的内存段中初始化。多次使用相同对象执行相同任务要快得多。以下是一个例子:

public class Example
{
  public int a;
  public int b;

  public int getSum()
  {
    return (a + b);
  }
}
//Lets have a look on un-optimized code
// Here one object of Example class is instantiating per loop //cycle // Same is freed and re-instantiated
public class ExecuterExample
{
  public ExecuterExample()
  {
    for ( int i = 0; i < 10; ++ i)
    {
      Example test = new Example();
      test.a = i;
      test.b = i + 1;
      Log.d("EXAMPLE", "Loop Sum: " + test.getSum());
    }
  }
}
// Optimized Code would look like this
// Here only one instance will be created for entire loop
public class ExecuterExample
{
  public ExecuterExample()
  {
    Example test = new Example();
    for ( int i = 0; i < 10; ++ i)
    {
      test.a = i;
      test.b = i + 1;
      Log.d("EXAMPLE", "Loop Sum: " + test.getSum());
    }
  }
}

尽量减少浮点数的使用

在机器级语言中,不存在整数或浮点数。它总是表示真或假的位(在技术语言中为 0 和 1)。因此,整数可以直接由一组位表示,但浮点数需要额外的处理开销。

直到某个时间点,编程语言中没有使用浮点数。后来,转换出现了,并且引入了额外的处理要求。

尽量减少抽象层

很明显,抽象需要每个层面额外的处理。因此,随着抽象层的增加,处理变得更慢。

尽可能使用增强循环

在数组和列表解析的情况下,增强的for循环比通常的传统for循环要快得多,因为它没有迭代变量系统,可以直接访问每个数组或列表元素。

这是一个非增强循环的例子:

int[] testArray = new int[] {0, 1, 2, 3, 5};
for (int i = 0; i < testArray.length; ++ i)
{
  Log.d("EXAMPLE", "value is " + testArray[i]);
}

这是一个增强循环的例子:

int[] testArray = new int[] {0, 1, 2, 3, 5};
for (int value : testArray)
{
  Log.d("EXAMPLE", "value is " + value);
}

避免内部使用变量的 getter/setter

使用 getter 和 setter 来访问或更改对象的任何内部元素的状态。在高级推理中,它不遵循数据封装的基本概念。然而,在 Android 游戏开发中广泛使用 getter 和 setter。

在许多情况下,开发人员从类对象内部使用 getter 和 setter。这不必要地增加了处理时间,导致性能下降。因此,开发人员应尽量少使用 getter 和 setter,并确保它们不被内部使用。

使用静态 final 来定义常量

常量在运行时不应更改。对于全局常量,数据直接与类对象相关联。因此,我们需要解析类对象才能访问它。

使用静态是一个很好的主意,可以摆脱这个额外的进程。使用静态常量可以显著增加元素的可访问性。然而,开发人员也需要检查内存使用情况。

尽量少使用内部类

每个内部类都会增加一层处理。有时,为了以高效和可读的方式构建代码库,使用内部类是很好的。然而,这会增加处理开销。因此,开发人员应尽量少使用内部类以优化性能。

性能和内存管理之间的关系

在 Android 游戏开发中,性能和内存优化经常相互冲突。为了保持游戏的视觉质量,必须使用更好的艺术资源,这最终会增加内存开销和性能滞后。

优化内存需频繁进行内存操作,导致性能下降。为了提高性能,对象必须能够顺利处理。显然,两者都不能达到极端水平。

在它们之间取得平衡是优化整个游戏以顺利运行而不耗尽内存的唯一方法。

Android 中的内存管理

让我们讨论一下 Android 中的内存管理系统。它直接影响游戏开发过程。在 Android 中,游戏被视为应用程序。开发人员经常在游戏的运行时和最小化状态下遇到内存问题。有三个主要主题需要讨论以了解工作原理:

  • 应用程序共享内存

  • 内存分配和释放

  • 应用程序内存分配

应用程序共享内存

Android 使用 Linux 内核,Linux 使用“共享”页面在运行进程或服务之间共享相同的内存段。例如,Android 经常在进程之间共享“代码”内存。很多时候,外部库和 JVM 的可执行代码内存可以安全地在进程之间共享,而不会创建死锁。数据页面可以在进程之间暂时共享,直到一个进程修改了共享内存。

Android 为每个应用程序或进程分配专用内存。这称为私有内存。同一进程也可能使用共享内存。Android 会自动设置一个上限,取决于两者的总和,以确定进程或应用程序何时会被终止,特别是在后台运行时。这个上限称为比例设置大小PSS):

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

如果一个应用的 PSS 很高,那么这个进程可能被 Android 杀死的可能性很高。特别是如果应用程序依赖一些后台活动或服务来执行某些任务,这种情况可以通过编程方式处理以保持内存使用情况,开发人员必须确保游戏在任何时候使用的内存尽可能少,特别是当应用程序进入后台时。在后台释放不再需要的内存和对象,并在进入后台时断开不再需要的任何共享内存可能是一个不错的主意。这将减少您的应用程序被 Android 系统意外杀死的机会。

内存分配和释放

Android 内存管理系统为每个应用程序定义了一个虚拟上限,即逻辑堆大小。如果有必要,可以增加这个逻辑堆大小,但前提是有空闲内存可用。然而,这个逻辑堆大小并不是应用程序的实际分配内存。计算得到的 PSS 是在运行时可能变化的实际物理上限,并且存在共享内存依赖。

应用程序内存不能使用比 PSS 更多的物理内存。因此,在达到此限制后,如果应用程序尝试分配更多内存,那么它将收到系统抛出的OutOfMemoryError。在紧急情况下,Android 可能会杀死其他空闲或后台进程以为运行中的应用程序腾出内存。在这些情况下,应用程序内存将被释放:

  • 如果应用程序退出

  • 如果进程变得不活动,而其他进程需要内存

  • 如果应用程序因任何原因崩溃

应用程序内存分配

Android 为每个应用程序设置了堆大小的硬限制,以维持多任务环境。根据设备的 RAM 容量,确切的堆大小限制因硬件配置而异。如果应用程序达到堆容量并尝试分配更多内存,它将收到OutOfMemoryError,并且应用程序将被 Android 杀死。

开发人员需要检查设备上可用内存的数量,然后确定平均目标内存使用量。开发人员可以通过调用getMemoryClass()来查询操作系统的内存量。这将返回一个整数,表示应用程序堆可用的 MB 数。

Android 中的处理段

游戏基本上是功能上的一个应用程序。多个应用程序或游戏可以在 Android 平台上运行。但是,对于游戏来说,一次只有一个游戏是活动的,而其他应用程序在后台运行。

让我们看看 Android 如何处理其应用程序。

应用程序优先级

Android 设置了运行应用程序的优先级,并且根据需求可以杀死低优先级的运行应用程序。

每个应用程序都使用一些内存和处理带宽。可能出现多个应用程序同时运行的情况。如果一个新应用程序想要运行,那么 Android 会为新应用程序分配内存和处理带宽。如果没有足够的带宽或可用的处理,那么 Android 会杀死一个或多个优先级较低的运行中的应用程序。

Android 通过以下状态设置优先级:

  • 活动进程

  • 可见进程

  • 活动服务

  • 后台进程

  • 空进程外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

活动进程

活动进程基本上是指与平台频繁通信并在前台运行的进程。当必要时,这个进程是 Android 中最后一个被杀死的。

活动进程满足以下标准:

  • 它在前台运行

  • 它是可见的

  • 至少有一个 Android 活动正在运行

  • 它与用户界面积极交互

  • 所有事件处理程序处于活动状态

可见进程

这个过程基本上是一个活动的进程,不在前台,也不与用户界面交互。这是 Android 平台的第二高优先级。

这个过程的标准如下:

  • 它在后台运行

  • 它有可见的活动

  • 它不与用户界面交互

  • UI 事件处理程序不活动

  • 进程事件处理程序是活动的

活动服务

活动服务是支持进行中的进程而没有可见界面的服务。Android 将首先终止这些服务,然后才是实际的活动进程。

此服务遵循以下标准:

  • 它没有可见的界面

  • 它支持或为相应的活动进程工作

  • 它在后台运行

后台进程

后台进程基本上是最小化或不活动的进程。这些进程在屏幕上不可见。这些进程的线程不运行,但应用程序状态保存在内存中。这些进程容易被处理器终止。这些进程在中断后可以恢复。

这些是不活动/最小化的进程。它们保留在内存中。应用程序保持暂停状态。

空进程

空进程也称为空进程。空进程实际上是空的。它在内存中不保存任何应用程序数据或状态。这个进程有最高的优先级,以便被操作系统终止。

应用程序服务

Android 应用服务是实际应用程序过程的一部分。这些服务可以在父进程内部和外部运行。

让我们澄清关于服务的两个常见误解:

  • 服务不是一个独立的进程

  • 服务不是线程

事实上,服务是应用程序过程的一部分,而不是独立的进程。服务不是线程。它们是在后台运行的进程的一部分,即使主应用程序处于暂停状态,它们也会继续运行。

服务旨在执行单个任务,不会回调父应用程序。这就是为什么它们可以在应用程序关闭后继续运行。

服务生命周期

服务由父应用程序进程启动,如下所示:

Context.startService();

启动后,服务开始在后台执行单个任务。任务完成后,服务可以停止自己。例如,简单的文件下载服务在成功下载任务后会停止。许多游戏开发者在他们的游戏中使用这些功能来提高用户体验。

这些服务可以与一个或多个进程绑定以实现交互。应用程序可以向绑定的服务发送请求并获得响应,从而创建服务器-客户端架构。但这些绑定的服务在最后一个应用程序组件绑定到服务之前有限的生命周期。

资源处理

Android 有自己的资源处理结构。它有一些预定义的资源类型:

  • 可绘制资源

  • 布局资源

  • 颜色资源

  • 菜单资源

  • Tween 动画资源

  • 其他资源

可绘制资源

所有可绘制资源都属于这个类别,包括帧动画。Android 提供了专门用于所有可绘制资源的res/drawable/项目路径。所有位图、各种 XML 和预定帧动画都可以放在这里。

这些可以通过R.drawable类访问。

布局资源

所有定义的布局都属于这个类别。Android 提供了专门用于所有布局文件的res/layout/项目路径。布局对于定义应用程序 UI 非常有用。

这些可以通过R.layout类访问。

颜色资源

颜色资源基本上是一个颜色列表,随着适用对象视图的改变而改变。Android 将其存储在层次结构中的res/color/文件夹中。

这些可以通过R.color类访问。

菜单资源

所有菜单内容都可以在这里定义。Android 提供了专门用于所有drawable资源的res/menu/项目路径。

这些可以通过R.menu类访问。

Tween 动画资源

所有 Tween 动画资源都属于这个类别。Android 提供了专门用于所有 Tween 动画资源的res/anim/项目路径。

这些可以通过R.anim类访问。

其他资源

所有其他资源都放在res/values/文件夹中。许多开发人员在这个类别下定义了样式的字符串。

这些可以通过R.values类访问。

不同的内存段

在应用程序运行时,根据行为使用了三种主要的内存段:

  • 堆栈内存

  • 堆内存

  • 寄存器内存

堆栈内存

所有自动变量和处理过程中的运行时分配将存储在堆栈内存段中。垃圾收集器在使用后释放内存。因此,与堆栈内存相关联的没有手动内存管理过程。

然而,大量使用自动变量也可能导致内存错误。这就是为什么我们已经讨论过为什么最小化不必要的自动变量声明是必要的原因。

堆栈内存也用于执行程序指令。每个指令都被解析为一个单独的操作,并由解释器放入堆栈中。然后,使用递归过程来执行所有指令堆栈并返回结果。

让我们看看堆栈内存如何处理对象和基本类型:

public class ExampleClass
{
  public ExampleClass()
  {
    int bitMapCount = 0;  // primitive type
    Bitmap testBmp = BitmapFactory.decodeFile("bitmap path"); // Object loading
    bitMapCount = 1;
  }
}

在这个例子中,bitMapCount是一个int局部变量,直接存储在堆栈中。这个变量使用的内存将在作用域结束后立即被释放。

然而,testBmp是一个位图对象,将被分配在堆中,但引用将存储在堆栈中。当程序指针离开作用域时,引用将被自动删除,垃圾收集器可以识别为testBmp分配的堆内存具有零引用,并释放这个内存段。

堆内存

堆内存是存储所有类实例和数组实例的段。JVM 在实例化任何对象时分配这个内存。

垃圾收集器在应用程序运行时不会自动操作这个内存段。开发人员有责任在使用后释放内存。在 Android 的情况下,只有在运行应用程序中没有对内存段的引用时,垃圾收集器才会释放内存。

游戏资源是存储在这个内存段中的主要元素。艺术是其中最重要的资产。因此,优化位图对堆内存的使用有直接影响。开发人员经常为资产分配内存并且不会打破引用。这导致内存块在整个运行时期被占用。

以下是一个例子:

// create a bitmap in a class constructor having global
// scope with public access
public class ExampleClass
{
  public Bitmap testBmp;
  public ExampleClass()
  {
    testBmp = BitmapFactory.decodeFile("bitmap path");
  }
}

在这个例子中,位图的内存将在使用后仍然被占用,直到ExampleClass实例在内存中。解释器没有立即释放内存段的指令,因为testBmp仍然引用了分配给位图的内存。

我们可以通过一些修改以以下方式优化这个问题:

public class ExampleClass
{
  public Bitmap testBmp;
  public ExampleClass()
  {
    testBmp = BitmapFactory.decodeFile("bitmap path");
  }
  // create a method to free memory allocated for the
  // bitmap after use
  public void unloadBitmap()
  {
    testBmp = null;
  }
}

在这种情况下,在使用位图后调用unloadBitmap()将从testBmp中删除加载的位图的引用。因此,垃圾收集器将找到这个内存位置为零引用内存,并释放它以供其他分配使用。

寄存器内存

在 Android 开发中,开发人员不必担心寄存器内存。寄存器直接与处理器相关联,处理器将最重要和经常使用的数据存储在这个内存段中。

寄存器内存是任何应用程序运行时使用的最快的内存段。

内存优化的重要性

无论游戏如何,外观如何,设计得多好,如果游戏在目标平台上无法运行,那么它就不会成功。我们已经知道 Android 有各种硬件配置。

硬件的主要变化是特定于处理器和内存。在处理器方面,这取决于其速度和质量。在内存或 RAM 方面,只取决于容量。

即使在今天,Android 设备的 RAM 也可以从 512MB 到 4GB 不等。内存优化应该始终以设计为目标的最低 RAM 为目标。因此,内存优化对于在最小可用 RAM 上运行游戏非常重要。

有时,开发人员将峰值使用量限制在目标内存限制内。然而,他们在测试设备上执行,这大部分时间并不反映实时情况。总是存在误差范围。因此,并不总是真实情况下游戏在一定的 RAM 限制下运行时,总是能提供相同的内存。这就是内存优化发挥重要作用的地方。它在创建游戏在实时情况下运行的缓冲范围方面起到了很大作用。

可能存在这样的情况,即使应用程序不需要所需的 RAM 量,也会耗尽内存。这清楚地表明应用程序存在内存泄漏问题。内存泄漏是游戏开发中最常见的问题之一。正确优化内存有助于解决这个问题。

内存优化的另一个方面是增加游戏保持在后台的概率。当应用程序进入后台时,如果 Android 需要为其他前台应用程序释放内存空间,可能会杀死应用程序。内存优化确保应用程序在运行时占用尽可能少的内存。因此,对于使用较少内存的应用程序,可以将状态数据保存在缓存中更长时间。

许多游戏在后台使用游戏服务。如果应用程序不活动,那么服务也有可能被操作系统杀死。

优化整体性能

早些时候,我们仅从编程角度讨论了性能优化。让我们讨论 Android 游戏性能优化的其他方面。

开发人员可以通过以下几点从设计到开发优化性能:

  • 选择基本分辨率

  • 定义可移植范围

  • 程序结构

  • 管理数据库

  • 管理网络连接

选择基本分辨率

从 Android 游戏开发的角度来看,选择基本分辨率可能是最重要的设计决策。基本分辨率定义了图形或视觉元素的比例。开发人员选择的分辨率越大,存储和处理时间就越多。基本分辨率还负责存储位图的质量和颜色信息。相对较低的分辨率不需要在可见资产中包含许多细节,这可以优化位图数据。然而,随着分辨率的增加,需要更多的数据来保留细节。最终,这对处理有重要影响。

随着技术的进步,Android 设备的分辨率越来越大。因此,开发人员现在选择更大的分辨率来支持更高范围的设备。

定义可移植范围

这也是设计阶段的优化。在这个阶段,开发人员需要决定支持的硬件平台范围。这包括各种配置。我们已经知道,Android 设备范围包括在内存、处理速度、图形质量等方面存在大量变化。

如果范围支持类似设备的可移植范围,那么优化变得更容易。然而,这并不适用于大多数游戏开发情况。通常,开发人员应将优化分为三个部分:

  • 低性能设备

  • 平均性能设备

  • 高性能设备

因此,理想情况下,应该有三层优化来正确定义可移植范围。

程序结构

程序结构是另一个非常重要的技术设计决策,对于性能和内存优化都很重要。这包括我们已经讨论过的所有编程优化参数。

此外,程序层次结构对性能也很重要。通常,开发人员会创建不必要的中间调用来解析多个层。一些单例类在这里有助于显著优化性能。正确的游戏状态机设计也有助于优化性能。

管理数据库

有许多游戏主要是数据驱动的。在这种情况下,需要正确管理数据库。

例如,一个问答游戏必须在数据库中维护一个问题库,以避免频繁更新游戏构建。数据库查询需要时间来执行,因为中间还有一个网络层。因此,游戏层发送查询到数据库。然后,数据库获取数据,相应地绑定并发送回游戏。然后,游戏必须解绑接收到的数据以使用它。使用最少的查询调用是最小化性能开销的唯一方法。使用更快的数据库也有助于游戏表现良好。

管理网络连接

现代游戏已经发展到多人游戏和服务器控制机制,这减少了频繁更新游戏构建的工作。在这两种情况下,网络连接需要以适当的方式实现。目前主要有两种类型的多人游戏架构:

  • 回合制多人游戏

  • 实时多人游戏

相对来说,管理回合制多人游戏系统比实时多人游戏系统要容易。还有另一种名为异步多人游戏的多人游戏模式。

每个网络调用都会导致性能延迟,因为游戏依赖于来自服务器的数据。因此,客户端-服务器架构需要优化,以实现以下目标:

  • 较少的延迟时间

  • 较少的层处理

  • 较少的对服务器的 ping 次数

增加帧率

性能优化的最终目标是提高帧率。高帧率自动提供流畅的游戏体验。然而,开发人员必须确保帧率效果在游戏中以流畅和效果的形式可见。

对于当前的移动游戏行业来说,2D 游戏或中等规模的 3D 游戏的平均 FPS 为 60 被认为是高性能。另一方面,大型 3D 游戏可能认为平均 FPS 为 30-35 是良好的性能。

具有更高 FPS 的高性能游戏为改善用户体验提供了进一步的视觉效果。这直接影响货币化。

性能优化的重要性

正如我们刚刚讨论的,性能优化直接影响帧率,而帧率又直接影响游戏体验。然而,性能优化还有其他重要性:

  • 由于非优化的程序,游戏可能会崩溃或进入无响应状态

  • 性能优化也直接影响内存

  • 性能优化可以扩大支持的硬件平台范围

常见的优化错误

游戏行业现在是增长最快的行业之一。为了跟上速度并在市场上站稳脚跟,许多公司计划缩短开发周期并限制优化。在这种情况下,开发人员通常会有意或无意地犯以下错误:

  • 编程错误

  • 设计错误

  • 错误的数据结构

  • 错误使用游戏服务

编程错误

编程是一个手动的过程,犯错是人之常情。因此,显而易见,没有错误和完全优化的游戏编码。然而,程序员可以通过几种方式最小化错误,以获得优化的游戏代码库。让我们讨论在 Android 开发游戏时程序员犯的主要错误。

程序员经常创建许多临时变量并忘记跟踪它们。通常,这些变量会占用不必要的内存并增加处理调用。

排序在游戏开发中被广泛使用。有几种排序算法。大多数情况下,开发者选择方便的技术而不是高效的技术。对于大型数组或列表,这可能会导致严重的流程延迟。

为了方便访问,使用太多静态实例也是一个不良的实践。使用静态可能会加快处理速度,但制作太多静态实例并不是一个好主意,因为它会在其生命周期内占用大量内存空间。许多程序员甚至忘记手动释放这些内存。

创建抽象层并广泛使用它们会使流程变慢。然而,这通常是一个良好的编程实践,但对于游戏编程来说,只在有限的情况下有所帮助。

方便的循环使用是游戏中另一个不良的编程实践。有几种处理循环的方法。程序员应该首先确定哪种方法最适合算法。

游戏编程大多是关于逻辑开发而不是技术。为某些任务建立完美的逻辑可能需要时间。许多游戏程序员并不考虑执行一个任务的多种方式。大多数情况下,这会留下很大的优化空间未被发掘。

设计错误

设计师在定义硬件范围和游戏范围时经常犯错误。这两个因素都是创建优化游戏设计的非常重要的因素。

另一个错误是将目标分辨率定错。目标分辨率直接影响艺术资源的大小。定错目标分辨率会导致不必要的缩放,增加额外的处理开销。

错误的游戏数据结构

数据结构是游戏编程中不可避免的一部分。Android 支持动态数组初始化。然而,许多开发人员更喜欢使用列表来存储数据。列表比数组慢得多。只有在绝对必要时才应该使用列表。

为数据驱动的游戏找到完美的数据结构是开发者的责任。适当的技术设计应该包括数据结构模型及其使用。

错误使用游戏服务

服务在某些时候非常有用。在现代游戏行业中,服务用于数据的下载/上传,推送通知,游戏中的深度链接,或者服务器连接。然而,服务会带来巨大的处理和内存消耗成本。运行服务也会导致大量的能耗。

因此,只有在没有其他办法时才应该强制使用服务。

最佳优化实践

有一些定义明确且合乎逻辑的优化技术可供选择。我们将讨论与 Android 游戏开发相关的主要范围和领域:

  • 游戏设计约束

  • 游戏开发优化

  • 游戏数据结构模型

  • 使用游戏资源

  • 处理缓存数据

设计约束

定义目标硬件平台并承认其限制总是最佳实践。技术设计可以根据它来构建开发约束。

可扩展性和可移植性也应该在设计游戏时确定。这应该给开发者一个初步的平台限制以及其他约束。我们已经讨论了设计优化。在进入开发之前,所有这些部分都应该进行评估。

在设计游戏时,需要固定目标屏幕大小和分辨率,并创建适合多种分辨率的布局。这是因为 Android 有许多不同的屏幕大小,正如前面所讨论的。

选择最低的 Android 版本和目标 Android 版本在构建开发项目时给开发者带来了优势,因为支持的 API 级别和平台功能已经定义好了。

开发优化

这是优化中最重要的部分之一。以下是一些成功进行优化开发过程的提示:

  • 使用尽可能多的安卓提供的文件夹结构,以便项目可扩展性。

  • 根据安卓提供的 dpi 列表使用资源格式。

  • 开发人员应避免缩放图像。这有效地减少了内存和处理开销。

  • 对于多种用途使用精灵也是创建动画的良好实践。

  • 平铺技术在减少内存消耗方面非常有用。

  • 覆盖onDraw()方法始终是刷新旧渲染管道并使用系统化绘制顺序的良好实践。

  • 尽可能使用基于 XML 的布局;然而,游戏对于这个安卓功能的使用范围非常有限。

数据结构模型

数据结构是游戏程序设计中不可避免的部分,无论游戏的规模如何。每个游戏都会处理各种目的的数据,如排序、搜索、存储等。

有许多数据结构模型可用于各种操作。每种操作都有其优点和缺点。开发人员必须根据需求选择最有效的方法。

让我们以数组和链表之间的数据存储比较为例。实际上,链表比数组更灵活和动态。然而,这种特性会导致处理速度较慢和内存消耗较高的代价。

开发人员可能并不总是需要存储动态数据。例如,如果需要存储板球队数据,那么数组就足够了,因为每边总是有 11 名球员,并且在游戏过程中不能修改。在这种特定情况下,这将使过程比使用链表更快更高效。

在另一种情况下,对于射击游戏,开发人员无法预测用户在游戏过程中可能发射的子弹数量。因此,队列数据结构将是最有效的,以处理所有发射的子弹。

类似地,堆栈和树结构可以在适当的情况下选择。对于排序和搜索算法也可以采用相同的方法。

资产使用技术

我们已经对游戏资产进行了分类。现在让我们从优化技术和最佳实践的角度来讨论它们。

艺术资产

一组艺术资产可以应用单独的优化技术。艺术资产是游戏的面孔。因此,必须确保视觉足够吸引人,以开始游戏。

正如我们已经讨论过的,更好的艺术资产会消耗内存和性能。然而,这可以最小化到一定程度。有几种艺术资产优化工具。然而,使用不合适的工具可能会导致数据丢失,最终导致视觉质量不佳。

艺术在视觉质量方面不应妥协。通常,艺术家开发的资产在游戏中不能完美反映,因为优化不当。

我们已经讨论了艺术资产应该如何制作。现在,让我们假设一些艺术只使用 8 位数据空间作为原始格式,但是导出时是 24 位格式。那么,开发人员可以使用工具将资产优化为典型的 8 位格式,而不影响视觉质量。

这个规则也适用于完全不透明的资产。开发人员可以摆脱透明信息,以获得优化的艺术资产。

音频资产

音频资产也是独立的资产。音频已经成为扩展用户体验的非常重要的资产。音频配置可以根据频率、位深度和压缩技术的广泛范围而变化。每种配置变化都有不同的处理和内存消耗水平。

因此,声音优化也是优化过程中非常重要的一部分。在安卓游戏开发行业中的常见做法是为 SFX 和音乐文件选择两种不同的音频格式。

开发人员通常忽视的一件事是音频信息数据。一些安卓设备有特定的频率上限,但当使用更多频率时,声音通常会更好。因此,确定安卓游戏声音的上限是一个技术设计层面的步骤。因此,每个声音都应该在接近范围内制作。

声音设计师需要在限制内保持质量。通过这种方式,音频资产可以在开发时进行优化。

其他资产

除了艺术和音频,游戏中可能还会使用其他数据资产。数据格式可以是任何形式,如二进制、文本、XML、JSON 或自定义。自定义格式基本上与二进制格式相同,只是加了一些加密。

在游戏开发中,将数据集分开使用是一种常见做法。单独的数据集有助于构建项目结构,并灵活地使用相同的代码来产生不同的输出。通常,开发人员更新数据源以更新完整的游戏体验,而无需创建新的 APK。这在长期内减少了开发时间,以便维护游戏并进行简单的更新。

从优化的角度来看,这些数据源应该被优化到足够快速地处理并且不消耗太多内存。然而,读写外部文件需要时间。通常,二进制文件是处理速度最快且大小最小的。然而,在读取二进制数据后,必须对其进行解析以在游戏中使用,这最终会增加处理时间。

最常用的数据格式是 XML 和 JSON。安卓库支持它们两者,包括通用解析器。开发人员可以在不进行额外处理的情况下获得可用的数据。然而,数据可以根据游戏的要求在游戏过程中进行操作。

处理缓存数据

缓存是一个类似于 RAM 的内存段,但比传统 RAM 更快的功能。处理器可以更快地访问这个段。因此,从逻辑上讲,缓存应该只存储经常使用的数据。

处理缓存数据的最佳方式是监控应用程序内存的使用情况。通常,操作系统应至少有 10%的空闲内存可用。经测试,一个应用程序可以使用平均 2%的总空闲内存。

然而,开发人员无法在技术上控制缓存。他们只能确保最常用的元素被优化得足够完美,以便执行器自动为它们使用缓存内存。

总结

优化是任何软件开发中最重要的任务之一,尤其是在游戏开发中,逻辑编程占据了技术编程的主导地位。对于技术编程来说,有大量的优化工具和技术可供使用,因为它有最常见的算法来实现。然而,在游戏编程的情况下,每个游戏玩法都需要不同的算法集。在许多情况下,还需要单独制作人工智能算法。因此,程序员很有可能需要找到一种有效的方法来优化新编写的算法。

我们已经讨论了在安卓游戏开发中所有可能的优化范围。技术优化是强制性的,因为它有固定的指导方针要遵循。然而,逻辑开发将取决于游戏算法及其要求。因此,对于游戏开发人员来说,优化安卓游戏是额外的努力。

有时,开发人员会过度优化游戏。这是不推荐的。过度优化通常会降低游戏的质量。因此,在技术设计时,应声明优化情况。

大多数大规模开发过程都有一个单独定义的优化任务集。一些开发者选择开发动态优化过程。这意味着开发者在不同阶段、不同规模上优化游戏。这两种过程都是有效的,但第一种在逻辑上更合理,因为定义一个单独的任务总是会给出整体优化的暂定时间。这有助于更好地管理整个游戏开发过程。

所有优化过程都经过测试阶段的验证。所有设计、工程和艺术工作都在游戏开发的这一阶段进行测试。我们将在本书的下一章更深入地讨论测试。

第九章:测试代码和调试

“无 bug 的产品是一个神话”是开发行业中常见的短语。一个无问题和无故障的应用程序或任何其他产品在理性上是不可能的。然而,开发人员总是可以尽量减少 bug 和问题的数量,以便游戏可以尽可能少地出现问题,并以最大可能的效率支持最多的平台。

我们将通过以下主题讨论 Android 游戏开发中各种调试方面的范围:

  • Android AVD

  • Android DDMS

  • Android 设备调试

  • 监控内存占用

  • 不同调试语句的战略放置

  • Android 游戏中的异常处理

  • 在跨平台引擎中工作时调试 Android

  • 最佳测试实践

Android AVD

AVD 是调试 Android 游戏最重要和重要的部分。在最初阶段,该概念始于模拟器。有一些预定义的模拟器可以用于在开发 PC 上运行构建。Android 模拟器提供了类似实时设备的界面。

AVD 具有一些功能,可以提供设备 RAM、Android 版本、屏幕大小、显示 dpi、键盘和不同的视觉皮肤。旧版 AVD 大多看起来都一样。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

在当前版本的 Android Studio 中,提供了大多数 Android 设备类别。开发人员可以根据目标开发平台创建 AVD。

类别如下:

  • Android 手机

  • Android 平板电脑

  • Android 电视

  • Android 可穿戴设备

AVD 可以通过 Android SDK 中提供的 AVD 管理器工具来创建或操作。AVD 管理器可以管理 AVD 的每个属性。该工具还可以帮助开发人员创建自定义 AVD。

让我们来看看每个不同 AVD 的属性因素:

  • 名称

  • 分辨率

  • 显示尺寸

  • Android 版本 API 级别

  • Android 目标版本

  • CPU 架构

  • RAM 数量

  • 硬件输入选项

  • 其他选项

  • 扩展 AVD 设置和创建

AVD 的名称

名称仅用于识别 AVD。可以分配任何内容,并且以后可以更改。在创建时也可以更改预定义的 AVD 名称。

AVD 分辨率

AVD 分辨率是可见性的最重要因素之一。有一些预定义的分辨率标准,但它们也可以更改。如今,大多数开发人员选择在实际硬件平台上广泛使用的分辨率。

分辨率的另一个用途是检查和验证游戏的显示可移植性。大多数游戏都是以目标分辨率制作的。然后,可以在各种分辨率上测试游戏以检查兼容性。

通常,如果纵横比相同,多个分辨率不会产生任何问题。然而,在 Android 的情况下,我们可以找到不同设备的多个纵横比。AVD 的分辨率因子有助于适应游戏并检查其在多个纵横比下的兼容性。

AVD 显示尺寸

这是 AVD 上的可见空间或可见显示区域。一个高分辨率的 AVD 可以有一个小的显示区域。这直接意味着 AVD 具有高 dpi 值,这意味着更高的显示质量。

AVD 的这一部分有助于确保游戏的视觉质量。然而,在开发系统中设置实际显示区域并不总是可能的,因为开发系统有自己的显示限制。

Android 版本 API 级别

在开发 Android 游戏时,开发人员需要将 API 使用限制在某个版本上。API 版本可能会在将来的 Android 版本中被弃用,甚至停止使用。为了检查这一因素,开发人员可以为 AVD 设置 API 版本。

Android 目标版本

这是将用于运行 AVD 的 Android 版本。这可以验证清单目标 Android 版本和最低版本范围。

CPU 架构

Android 设备主要使用三种 CPU 架构:armeabi、armeabi-v7 和 x86。这对游戏没有直接影响。然而,处理速度和质量会随着 CPU 架构的不同而有所变化。

开发人员应该记住,实际设备上具有不同 CPU 架构的游戏性能总是会与 AVD 上的表现不同。因此,它可能给开发人员一个性能的想法,但需要在实际设备上进行测试。

RAM 数量

RAM 数量指定了 AVD 可用的总内存量,可用于检查游戏在各个级别的内存消耗。

最好预测各种设备的内存溢出问题。通过在 AVD 上同时运行多个应用程序,可以创建一个实时克隆。默认值设置为 66MB。开发人员可以根据需求设置任何值。

外部存储也可以定义为虚拟设备的 SD 卡。

硬件输入选项

在 Android 设备上,可以有许多类型的硬件输入分布在各种硬件中。最常见的变体如下:

  • 触摸屏

  • 触摸板

  • 键盘

  • 自定义控制器

  • 硬件按钮

许多硬件平台选择了这些变体的组合。AVD 为所有这些输入系统创建了一个虚拟系统。

其他选项

还有一些其他选项可供操作。如果开发系统连接了摄像头,那么 AVD 也可以使用前置和后置摄像头。

此外,虚拟加速计、传感器等可以与 AVD 关联。

扩展 AVD 设置

通过现代 AVD 管理工具可以制作自定义 AVD。开发人员可以设计具有自定义外观和完全自定义硬件配置的虚拟设备。

Android DDMS

DDMS 可用于分析运行中应用程序的所有运行时详细信息,如内存消耗、进程调用等。

Android DDMS 的主要功能是提供端口、在设备上进行屏幕截图、线程详细信息、堆详细信息和 Logcat 处理。此服务可用于欺骗呼叫和短信。

Android DDMS 广泛用于设备调试。特别是在游戏开发过程中,它经常被用作逐行调试系统。这对于识别不需要的加载对象和资产,以及跟踪运行时异常非常有用:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Android DDMS 可用于执行以下活动。

连接 Android 设备文件系统

DDMS 可以连接到设备文件系统,并提供基于文件浏览器的操作,通过 PC 在设备上复制、修改或删除任何文件。然而,这种方法或功能对 Android 游戏开发并不是非常重要。

性能分析方法

另一个有趣的 DDMS 功能是对某些方法的分析或跟踪矩阵。它提供以下主题的信息:

  • 执行时间

  • 操作次数

  • 单元格数量

  • 执行期间的内存使用

扩展此功能,开发人员甚至可以通过调用startMethodTracing()stopMethodTracing()来控制方法的数据分析。

开发人员需要关注两件事:

  • 在 Android 2.1 之前,设备上必须安装有 SD 卡,并且应用程序需要有读写权限

  • 从 Android 2.2 开始,设备可以直接将分析数据流式传输到开发 PC

线程信息监控

DDMS 提供了所选设备上每个进程运行的每个线程的详细信息。然而,游戏大多在单个线程上运行。随着设备的不断改进,游戏也在使用多线程功能来支持渲染、处理、文件 I/O 和网络等各种操作。

堆信息监控

DDMS 为运行中的进程提供了堆使用情况。对于游戏开发人员来说,跟踪执行期间的游戏进程堆非常有用。

跟踪内存分配

这对于跟踪运行时对象的每个内存分配非常有用。这可以给出每个类的每个特定对象的每个细节。这意味着开发人员可以找出每个类占用多少内存。这有助于以更有效的方式实现内存优化。

监控和管理网络流量

从 Android 4.0 开始,DDMS 具有详细网络使用选项卡,用于跟踪游戏何时发出网络请求。使用此功能,开发人员可以监视网络数据传输。这个选项对于优化网络开发非常有用。它可以通过在使用网络套接字之前对其应用“标签”来区分不同的流量类型。

使用 Logcat 跟踪日志信息

日志是跟踪几乎任何东西的最有用的调试技术。在运行时正确使用日志来检查某些对象的数据或值是一个很好的实践。对于游戏的逻辑开发非常有用。

在游戏开发中,不同游戏的逻辑需求将不同。因此,必须有大量的代码是第一次编写的。预定义的测试用例是不可用的。可以使用 DDMS 中的 Logcat 来克服这种不足。

Logcat 提供以下类型的日志信息:

  • 冗长的

  • 调试

  • 错误

  • 警告

  • 信息

模拟设备操作

正如我们之前讨论过的 Android 虚拟设备一样,DDMS 也可以在 AVD 上工作。因此,模拟实时场景以调试正在开发的游戏变得更加容易。

最常用的仿真如下:

  • 模拟来电

  • 模拟收到消息

  • 模拟运行时网络状态更改

这三种情况是运行时最常见的情况。因此,这些情况可以在没有物理设备的情况下进行检查。自 Android 设备开始以来,中断处理一直是困难的。事实上,如果中断没有得到正确处理,这对程序员来说可能是一场噩梦。

在中断后,游戏崩溃/冻结/重新启动的常见问题。很多时候,一些不必要的服务或进程可能会中断,并且它们可能会在中断期间改变游戏状态。在 AVD 上模拟每种可能的中断总是加快调试或中断处理过程的一个额外优势。

Android 设备测试和调试

Android 设备调试是任何 Android 游戏开发过程中最重要的部分。让我们将这个主题分成两个部分:

  • 设备测试

  • 设备调试

设备测试

游戏开发者面临的主要挑战是在大量不同的设备上运行游戏。这些不同的设备包括不同的显示器、不同的分辨率、不同的 Android 操作系统版本、不同的处理器和不同的内存容量。由于这些原因,Android 设备测试很重要,必须付出很大的努力和计划。

通常,在游戏开发周期中,第一点测试由开发人员进行。这个过程确保游戏在设备上运行。

然后,测试人员或一组测试人员从各个方面在不同的设备上测试游戏。这是设备测试的主要部分。

通常,主要的测试阶段根据游戏开发阶段分为四个部分:

  • 原型测试

  • 完整测试

  • 回归测试

  • 发布测试或运行测试

换句话说,在每个类别中有类似的分布,如下所示:

  • Pre-alpha 测试

  • Alpha 测试

  • Beta 测试

  • 发布候选测试

还有许多其他可能遵循典型软件测试的测试程序。然而,在游戏开发中,通常会遵循这些方法。让我们简要描述这些阶段。

原型测试

开发人员和设计师一起开发基本游戏想法的可玩阶段,具有初始的游戏规则。这些规则和游戏玩法在原型测试阶段进行测试。

理想情况下,核心游戏玩法在这个阶段进行测试,以分析游戏概念的可行性、潜力和范围。

原型测试可能是游戏开发过程中最重要的部分。这个阶段决定了游戏概念的未来,并有助于为概念开发元游戏和货币化模型。

全面测试

通常情况下,在每个阶段提交的前几个构建被提交进行全面测试。这会揭示游戏的每一个可能的问题,包括崩溃、冻结、视觉问题、可玩性、游戏规则和设计缺陷。

大多数问题通常在这个阶段报告,这最终意味着该游戏构建的可能完成时间和工作量。

回归测试

回归测试是在全面测试之后进行的。开发人员、设计师和制作人在全面测试期间对每个问题进行评估。他们选择要解决的问题,问题解决后,提交给测试团队进行回归测试。

在回归测试中,测试人员通常选择问题并专门检查它是否真的解决了。如果问题在修复的构建中发生,则测试人员会重新打开问题进行下一个回归周期。这个周期会持续,直到所有报告的问题都得到解决。

发布测试或运行测试

这可能是游戏测试中最机械化的测试阶段。在这个阶段,测试人员在各种目标设备上运行通过的回归测试构建,只是为了检查游戏是否在该硬件上运行。这就是为什么这个阶段经常被称为“运行测试”的原因。

尽可能多地使用物理设备进行此段测试以进行兼容性检查。在这个测试阶段之后,创建最终设备支持列表。几乎不可能安排所有可用的设备并对它们进行运行测试。因此,开发人员根据其配置和性能对设备进行分组。行为相似的设备被放在同一类别中,实际上只有一两个设备被安排用于整个组的运行测试。

设备调试

我们已经看到设备测试主要是测试人员的工作。现在,我们将看到设备调试基本上是开发人员的工作。然而,通常情况下,开发人员和测试人员都会进行调试。

在游戏行业中,设备调试主要用于查找运行时崩溃、冻结、内存问题、网络问题和性能问题。通过设备调试,开发人员收集以下信息:

  • 运行时最大堆消耗

  • 各种设备的平均 FPS 或多套设备

  • 不必要的加载对象

  • 硬件按钮行为

  • 网络请求和响应

使用断点

在设备调试的情况下,断点非常有用。游戏线程在断点处暂停,可以通过 DDMS 获得状态信息。游戏编程主要涉及定制算法,可能在运行时产生一些异常行为。在这种情况下,断点非常有用。开发人员可以在断点后逐行调试逻辑,以找到并修复行为的根本原因。

监视内存占用

内存占用是在运行时使用内存的迹象和方式。从游戏内存使用优化的角度来看,监视内存占用非常重要:

  • 检查日志消息

  • 检查堆更新

  • 跟踪内存分配

  • 检查整体内存使用

  • 跟踪内存泄漏

检查日志消息

使用日志消息一直是最有效和最直接的调试技术。消息日志对于跟踪程序控制流和运行时对象跟踪非常有用。

Dalvik 消息日志

Dalvik 消息日志对于跟踪内存很有用。每当发生垃圾收集时,垃圾收集器可以通过 Dalvik 日志消息打印以下信息:

  • 垃圾收集原因:此信息显示了触发垃圾收集的原因。原因可以是GC_CONCURRENTGC_FOR_MALLOCGC_HPROF_DUMP_HEAPGC_EXPLICITGC_EXTERNAL_ALLOC

  • 释放的内存量:此部分说明了垃圾收集器释放的内存量(以 KB 为单位)。

  • 当前堆内存状态:这显示了堆内存使用的百分比和活动对象内存/总堆内存。

  • 外部内存状态:可能会有一些分配外部内存的操作。这部分显示了分配的内存/垃圾收集限制。

  • 垃圾收集器暂停时间:暂停时间在垃圾收集开始时和结束时触发。通常,在堆较大的情况下,暂停时间会更长。

ART 消息日志

ART 消息日志还能够显示或跟踪内存印记。但是,除非明确请求,否则不会触发。

如果垃圾收集器暂停时间超过 5 毫秒,或者垃圾收集器执行时间超过 100 毫秒,则会打印垃圾收集器日志。在 ART 的情况下,以下信息可以显示为日志:

  • 垃圾收集原因:在 ART 日志消息中,开发人员可以将ConcurrentAllocExplicitNativeAllocCollectorTransitionHomogeneousSpaceCompactDisableMovingGcHeapTrim作为收集原因。

  • 垃圾收集器的名称:ART 有几种不同的垃圾收集器可以参与收集过程。可以通过收集日志的字段了解名称。ART 有这些收集器:Concurrent Mark SweepCMS)、Concurrent Partial Mark SweepCPMS)、Concurrent Sticky Mark SweepCSMS)和 Marksweep plus Semispace。

  • 释放的对象计数:这显示了垃圾收集器从内存中释放的对象总数。

  • 释放的内存量:这显示了垃圾收集器释放的总内存量。

  • 释放的大对象计数:这显示了从大对象范围中由收集器释放的对象数量。

  • 从大对象中释放的内存量:这显示了从大对象范围中由收集器释放的内存量。

  • 当前堆内存状态:这与 Dalvik 日志中的相同——活动对象计数/总堆内存。

  • GC 暂停时间:在 ART 暂停时间部分,这与运行垃圾收集器修改的对象引用数量成正比。与 Dalvik 不同,ART CMS 垃圾收集器在收集过程结束时只有一个暂停时间。

检查堆更新

开发人员可以每次更新时检查堆使用情况。这可以清楚地显示内存印记。可以使用多种工具来监视堆。市场上有很多设备内存监视器可用。DDMS 设备监视器就是其中之一。它是一个强大的工具,在游戏运行时观察堆使用情况。

Android SDK 自带了一个内置的设备监视器,位于<sdk>/tools/monitor

Android Studio 中的内存监视器对于 Android Studio 用户非常有用。监视器可以与 Android 应用程序交互,以观察每次垃圾收集时的堆更新。通过这种方式,Android 开发人员可以了解应用程序各个部分的确切内存使用情况。

有时,开发人员会打开/关闭方法来检查确切的堆使用情况。因此,进一步优化变得更容易。

跟踪内存分配

这对于内存优化很有帮助。内存分配可以通过分配跟踪器进行监视。

在一定阶段的内存优化之后,需要进行内存分配跟踪。这有助于识别每个对象的内存分配。通常,许多无用的对象会留在内存中。开发人员可以识别这些对象并将它们移除,以实现更大的内存优化。

内存分配跟踪器在 Android SDK 的设备监视器和 Android Studio 的分配跟踪器中都可用。

然而,并不需要从性能关键的代码路径中删除所有分配;然而,分配跟踪器可以帮助开发人员识别代码中的重要问题。例如,一些应用程序可能在每次绘制时创建一个新的Paint对象。将此对象移入全局成员是一个简单的修复方法,有助于提高性能:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

让我们快速查看所获得的分配信息:

  • s1:这是当前正在跟踪的对象包

  • s2:这显示已选择分配选项卡

  • s3:这用于启动/停止跟踪对象

  • s4:这更新包分配

  • s5:这显示分配详情

在游戏开发中,内存中的对象数量是巨大的,因此手动跟踪对象的分配和释放非常困难。这个监控工具有助于发现在优化过程中可能被忽视的隐藏点。

检查整体内存使用

Android 游戏的整体内存使用分布在 RAM 的不同段中。这为应用程序的性能和内存安全性提供了一个大致的概念。

基本上有两种类型的分配。

私有 RAM

这是游戏在运行时使用的专用内存部分。Android 操作系统将此内存分配给应用程序。私有 RAM 分为两个部分:

  • 清理 RAM

  • 脏 RAM

私有脏 RAM 是最昂贵的,因为它只能被特定应用程序使用(在我们的情况下,是一个 Android 游戏)。

比例设置大小(PSS)

这部分 RAM 被多个进程使用。基本上是共享内存。任何应用程序进程独有的 RAM 页面直接影响其 PSS,而与其他进程共享的页面仅按比例影响 PSS 值。

跟踪内存泄漏

内存泄漏对软件开发构成严重威胁。因此,追踪内存泄漏并解决它是绝对必要的。当一个进程分配内存并丢失引用指针时,就不可能在进程内释放内存。

有一些调试工具可以追踪内存泄漏。然而,还有另一个免费且更有效的解决方案。开发人员可以随时监视内存消耗。游戏在更新循环中运行。因此,可以跟踪不同游戏周期的内存峰值。如果峰值不断增加,意味着内存的分配/释放存在泄漏。现在,开发人员可以检查每个对象的大小并追踪泄漏。这个过程的另一个好处是在内存中找到不必要的对象以及内存泄漏。

不同调试语句的战略放置

调试语句是任何开发过程中最重要的部分。通过调试语句可以跟踪和追踪任何事物。然而,作为系统打印调用,每个调试语句都会对性能产生影响,这直接影响运行时的 FPS。这就是为什么调试语句的放置策略是绝对必要的。

让我们看看与以下类别相关的策略:

  • 内存分配

  • 跟踪对象状态

  • 检查程序流程

  • 跟踪对象值

内存分配

在游戏开发对象周期中,对象应该在初始化时分配一次,并在销毁时释放。然而,由于手动编程错误,开发人员忘记释放内存。在这种情况下,当系统自动调用垃圾收集器时,内存将被清理。这样就观察到了性能上的延迟。

现在,作为追踪这种错误的战略放置,应该在构造函数和析构函数中放置两个调试消息。

此外,初始化每个对象后放置一个调试语句可以确保对象成功初始化。这可以显示它消耗的内存量。

在运行时跟踪对象状态

对象可以在游戏过程中的任何时候初始化。现在,初始化过程中的任何外部依赖都可能导致分配失败。因此,对象进入空状态,如果不正确处理,可能会导致异常。

一个成功的调试语句和一个失败的调试语句(带有原因)可以帮助开发人员纠正问题。

很多时候,错误的释放也会改变对象的状态。因此,调试语句可以确定这个地方。开发人员可以借助调试语句来解决对象和程序流的问题。

检查程序流程

每个方法中的调试语句清楚地显示了调用层次结构和程序流程。一个模块化的程序可以通过这个系统进行测试。然后,每个模块的开始都可以用一个调试语句进行测试。

任何错误或不必要的调用都可以通过这个过程来移除或纠正。正确的程序流程可以确保运行时的一定帧率。因此,这种方法可以用来优化性能。

跟踪对象值

即使对象成功初始化,内容可能也不正确。因此,放置一个调试语句来检查加载/初始化的内容是必要的,以避免未来的冲突。

当从外部来源加载数据时,这是非常有用的。调试语句用于验证初始化后加载的数据。任何程序模块都可以使用对象跟踪方法进行设计,从而得到更好的编程结构。

Android 游戏中的异常处理

异常处理可能不是调试的一部分,但它有助于减少异常和不必要的应用程序崩溃。

Android 中的异常处理与 Java 异常处理相同。

语法

异常处理的标准 Java 语法如下:

try
{
  // Handled code here
} 
catch (Exception e)
{
  // Put debug statement with exception reason
}
finally
{
  // Default instruction if any
}

可疑的代码应该放在try块中,并且异常应该在catch块中处理。如果模块需要执行一些默认任务,那么将其放在finally块中。catchfinally块可能并不总是在异常处理中定义。然而,建议在每个try块失败时处理异常,这是一个良好的编程实践。这个过程需要分析模块,找出任何脆弱的代码块。

这是一个处理异常的简单例子,还包括其他易受攻击的默认任务。

这是最初的程序设计:

try
{
  // Task 1 which might throw exception
}
catch ( Exception e)
{
  // Handles exception
}
finally
{
  // Task 2 which might throw exception
}

程序应该这样写:

void func1()
{
  try
  {
    funcTask();
  }
  catch ( Exception e)
  {
    // Handles exception
  }
}

void funcTask()
{
  try
  {
    // Task 1
  }
  finally
  {
    // Task 2
  }
}

开发人员应该记住以下几点:

  • try块只能与catch块一起使用

  • try块只能与finally块一起使用

  • try块可以与catchfinally块一起使用

  • try块不能单独使用

  • 嵌套的try...catch是可能的,但不建议作为良好的编程实践

范围

根据异常类型和原因,有很多预定义的异常范围。然而,在游戏开发过程中处理的主要异常如下:

  • 空指针异常

  • 索引越界异常

  • 算术异常

  • 输入/输出异常

  • 网络异常

  • 自定义异常

空指针异常

这是游戏开发中最常见的异常之一。当代码中引用任何空对象时,会抛出NullPointerException。开发人员应该跟踪对象的初始化和使用来纠正这个问题。

这是一个例子:

class A
{
  public int num;
  public A()
  {
    num = 10;
  }
}
// some method in other class which is called during runtime.
void testFunc()
{
  A objA = null;
  Log.d("TAG", "num = " + objA.num);
}

这将抛出一个异常,因为objA被初始化为 null。因此,这个对象在内存中找不到,引用指针也不存在。现代智能编译器可以在编译时检测到这个明显的异常,但代码可能是这样的,我们定义了另一个包含testFunc()方法的类:

class RootClass
{
  public A objA;
  public RootClass()
  {
    objA = null;
    testFunc();
  }

  void testFunc()
  {
    Log.d("TAG", "num = " + objA.num);
  }
}

在这种情况下,大多数智能编译器无法检测到即将发生的异常。为了处理这个问题,开发人员应该在testFunc()方法中添加几行代码:

void testFunc()
{
  try
  {
    Log.d("TAG", "num = " + objA.num);
  }
  catch (NullPointerException e)
  {
    Log.d("TAG", "Exception:: " + e);
  }
}

索引超出范围异常

当访问一个索引地址时抛出此异常,该地址应该是连续内存分配的一部分,但实际上并不是。在游戏开发中,最常见的是ArrayIndexOutOfBoundsException

例如,如果一个数组包含五个字段,程序尝试访问超过五个字段,那么就会抛出此异常。让我们看一下这段代码:

int[] arrayNum = new int[5];
for ( int i = 0; i < 5; ++ i)
  arrayNum[i] = i;

Log.d("TAG", "arrayNum[5] is " + arrayNum[5]);

在这里,异常将出现在日志语句中,因为arrayNum[5]表示数组中的第六个元素,而该元素不存在。

算术异常

数学表达式可以表示一个未定义的值,但在编程方面,“未定义”无法定义。因此,会抛出ArithmeticException

例如,如果解释器尝试将任何值除以零,那么结果变为未定义,这将作为异常抛出。在计算 tan 90°的值时也会出现相同的结果。

一个简单的情况可能是这样的:

void divideFunct(int num, int deno)
{
  try
  {
    Log.d("TAG", "Division Result = " + (num / deno));
  }
  catch (ArithmeticException ae)
  {
    Log.d("TAG", "number cannot divided by zero");
  }
}

输入/输出异常

计算系统的输入/输出功能取决于其硬件。然而,在游戏中,输入/输出异常发生在读/写操作期间。大多数游戏都是数据驱动的。基本原则是向游戏软件提供数据以控制游戏中的元素。这些数据通常存储在单独的二进制、文本、XML 或 JSON 文件中。

作为位于特定路径的单独文件,这些文件可能会丢失,特别是当这些数据文件从其他位置下载时,因为可能会出现连接中断,文件可能无法保存。在这种情况下,当游戏软件尝试加载这些文件时,就会抛出IOException

让我们看一个快速的例子:

try 
{
  File dir = Environment.getExternalStorageDirectory();
  File objFile = new File(dir, "tmpPath/myfile.txt");
}
catch (IOException e) 
{
  Log.d("TAG", "Error reading file :: " + e);
}

网络异常

这是多人游戏的时代,这需要强制性的网络连接。因此,应用程序取决于现有网络连接的质量和连接性。然而,移动网络连接状态可能随时发生变化。通常,游戏开发人员忽略网络错误,导致游戏运行中崩溃、冻结或某些故障。

常见的异常处理包括HttpRetryExceptionUnresolvedAddressExceptionNetworkErrorException。如果任何 HTTP 请求不能自动重试,那么就会抛出HttpRetryException。如果应用程序想要连接到某个地址,但该地址未找到,那么就会抛出UnresolvedAddressExceptionNetworkErrorException用于处理任何网络故障,如网络丢失/中断、使用错误协议的网络等。

自定义异常

这通常用于两个目的:

  • 游戏异常处理

  • 游戏支持工具异常处理

游戏过程中可能会在运行时创建逻辑异常。然而,在游戏开发中,这种异常的范围很小。大多数 Android 开发人员不会这样做。

工具编程也是游戏开发过程中的重要部分。因此,如果需要,可能的异常应该由自定义异常处理。

在使用跨平台引擎进行 Android 调试

现代游戏编程通常不针对单一平台。大多数游戏都是跨平台的。跨平台游戏引擎对这种开发非常有用。

大多数引擎都配备了内置的性能分析器,并提供一些调试游戏的功能。然而,性能分析器功能完全依赖于特定游戏引擎的制造商。

所有本地平台都提供完整的调试信息。游戏引擎创建一个包装器,自动从一个平台配置切换到另一个,并在一个共同的用户界面中显示性能分析器的详细信息。

然而,这些跨平台调试工具会消耗额外的处理和内存。在某种程度上,它们限制了游戏资源的消耗到一定水平,并带有误差范围。

最佳测试实践

在 Android 游戏开发行业中有许多用于测试的标准。测试确保应用程序发布后的正确性、稳定性、功能行为和耐久性。Android 游戏测试的最常见方法是手动测试。

然而,这个过程绝对不是最佳的。作为 Android 开发人员,单元测试始终是一种最佳实践,可以节省时间并获得准确的测试结果。

工具和 API

有几种工具和 Android API 可用于执行测试过程。其中一些是内置的,如 Android 测试支持库、Dumpsys、Monkeyrunner 等。

大多数这些测试工具可以通过命令行触发,并通过 Android 调试桥运行。

Monkey 工具创建一个虚拟环境,模拟用户的点击、触摸、滑动等操作,以确定实时结果。Monkey 可以通过以下命令运行:

adb shell monkey –p <Game Package Name> <Event Count>

Dumpsys 在 Android 应用程序运行时提供系统状态。可以通过以下命令触发:

adb shell dumpsys <option>

Dumpsys 能够提供关于运行服务、输入系统、网络状态、RAM 使用等信息。

测试技术

在游戏行业中,通常使用两种测试技术:自动化测试和手动测试。我们已经简要讨论了手动测试过程。现在让我们来看看自动化测试。

自动化测试需要工具和额外的编程工作。游戏 UI、内存消耗、网络连接和输入系统测试可以自动化。单独的测试在模拟器上或实际设备上运行,以确定测试结果,并将其保存在开发系统的指定位置。

可以编写单元测试代码来验证游戏的单个模块的逻辑。单元测试可用于测试应用程序的最小可能组件,如元素、类和方法。单元测试进一步分为两个阶段:

  • 本地测试

  • 仪器化测试

本地测试

这种类型的单元测试在本地机器上运行在 JVM 上。这节省了大量的测试时间。本地测试要么不依赖于 Android 框架,要么依赖有限,可以通过虚拟对象满足。

仪器化测试

仪器化测试对 Android 框架有完全的依赖,必须在 Android 模拟器或 Android 设备上运行。这种测试技术用于测试 Android 游戏的运行时行为。它可以提供正在运行的应用程序的所有系统和调试信息。然而,这种技术不能轻易地与虚拟对象一起使用。开发人员需要在 Android 环境中定义测试对象数据,然后才能运行测试。

总结

任何开发过程如果没有质量和性能保证都是不完整的。测试是开发阶段,需要在技术和逻辑上验证游戏是否能在真实市场中运行。

测试、调试和分析游戏的阶段确保了针对目标 Android 平台范围的最佳质量。通常,Android 游戏在少数 Android 设备上可以运行,但在所有目标设备上都不能运行。开发人员可以通过详细的测试程序识别和解决一些特定设备的问题。

第十章:Android 在 VR 游戏中的范围

从简单的角度来看,“虚拟”和“现实”是两个相反的词。因此,一个自然的问题是它们如何能一起表示某种意义。这个短语描述了通过数字计算系统体验想象的或真实环境的经历。

游戏环境也是想象的或实时的。然而,这些环境不会通过触摸、气味、声音和视觉来呈现实时体验。因此,游戏在虚拟现实VR)的帮助下有了新的探索范围。

让我们通过以下主题探讨 VR 在 Android 游戏中的概念和范围:

  • 理解 VR

  • 游戏中的 VR

  • Android 在 VR 的未来

  • 为 VR 设备开发游戏

  • Cardboard SDK 简介

  • 使用 Cardboard SDK 开发游戏的基本指南

  • 通过 Google VR 进行 VR 游戏开发

  • Android VR 开发最佳实践

  • Android VR 游戏市场的挑战

  • 扩展的 VR 游戏概念和开发

理解 VR

在数字计算世界中,VR 意味着数字计算创建的实时环境。这意味着环境并不存在于地球上,但可以通过数字计算体验。然而,并不总是必须 VR 总是复制真实环境。它有能力复制一个想象的世界或环境,可以显示在计算机屏幕或 VR 头盔(头戴式显示器)设备上(图片来源:lh3.ggpht.com/uv8mx61-jsrbcu-EPNw1wIi4BCXg7338alepVlr7xKbKJf7eZ9EXT2U3roA8SWx1RC8=h900-rw):

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Shadowgun VR 游戏的实际屏幕显示

VR 的演变

VR 概念似乎代表了现代技术,但事实是 VR 概念是在 20 世纪第二季度引入的。1935 年,斯坦利·G·韦恩鲍姆写了一篇名为《皮格马利翁的眼镜》的短篇科幻小说,在其中发现了一个护目镜的描述。护目镜描述了通过触觉和气味的虚拟体验的全息记录。从技术上讲,它定义了虚拟现实。

在 20 世纪中叶,这个概念通过视觉、气味、触觉和声音的虚拟化得到了改进。最终,在 1968 年,伊凡·萨瑟兰和他的学生鲍勃·斯普劳尔创造了世界上第一个 VR 头戴显示设备。

现代 VR 系统

现代 VR 设备在 1990 年后得到了发展。它们更轻,具有更好的显示和计算设备。世嘉在 1991 年为街机游戏和游戏机开发了世嘉 VR。该设备配备了液晶显示屏、立体声耳机和惯性传感器。

后来,在 21 世纪之后,VR 设备在许多方面得到了改进。许多技术公司对开发更好的 VR 系统表现出了浓厚的兴趣。如今,VR 设备在市场上是商业化的。VR 现在已经集成在最新的移动设备中,配备了输入控制器系统。

有许多公司开发在 VR 设备上运行的应用程序,用于多种目的。VR 技术的许多其他用途正在不断推出和改进。

使用 VR

VR 每天都在现代世界的许多领域扩展。让我们快速看一下 VR 可用性的领域:

  • 视频游戏

  • 教育和学习

  • 建筑设计

  • 美术

  • 城市设计

  • 动态图片

  • 医疗疗法

视频游戏

视频游戏在技术上由显示、声音和各种类型的交互系统组成。VR 设备已被证明具有运行游戏应用程序所需的所有必要组件。VR 的游戏化始于 20 世纪末。从那时起,VR 一直被用于游戏行业。

游戏基本上是一个互动娱乐系统。VR 只是支持视频游戏系统的环境。VR 系统可以将用户带入游戏世界与元素进行互动。

我们将在本章后面详细讨论 VR 在游戏中的作用。

教育和学习

实地考察和教育科目的可视化对学习过程有很大的影响。很多时候,不可能对每个科目提供实际的课程。虚拟现实有助于在许多教育主题上创造虚拟、实际和视觉上的影响。许多学院和培训师使用这种方法进行更好的教学。

培训是虚拟现实教育的另一个重要方面。例如,虚拟现实被用来培训飞行员在发达国家驾驶战斗机。这降低了事故的发生几率,培训候选人可以体验驾驶喷气式飞机的实时感受。

它被广泛用于培训医学生进行各种领域的治疗。

建筑设计

虚拟现实在建筑设计中被广泛使用。它可以在不实际实施的情况下浏览拟议的设计。许多建筑公司使用虚拟现实来展示设计。

有许多虚拟现实软件可以从建筑设计的数字副本中构建虚拟现实应用程序。

美术

这是虚拟现实的一个较少为人所知和较少被探索的用途。然而,许多优秀的艺术家已经利用虚拟现实来创造一个可导航的艺术虚拟世界。一些艺术博物馆可以通过虚拟现实技术进行虚拟参观。

城市设计

在现代世界中,城市设计和规划使用虚拟现实来模拟和验证设计。城市设计也用于发现设计中的漏洞和缺陷。在城市/城镇重建、交通规划、景观设计等方面,虚拟现实技术使城市设计变得更加容易。

电影

我们可以找到一些电影运用了虚拟现实技术的概念。电影《阿凡达》就是一个很好的例子。整个概念都建立在虚拟现实技术之上。这个概念描绘了一个虚拟的生活和活动,借助技术,角色可以在现实中不在场的情况下体验虚拟世界。

电影通过虚拟现实模拟已经变得多维化。如今,观众的体验通过虚拟现实得到了提升。

医疗疗法

虚拟现实疗法VRT)在医学科学中非常受欢迎,特别是在心理治疗中。据记录,全球虚拟现实疗法的成功率超过 90%。

虚拟现实疗法主要用于治疗恐高、恐飞、恐虫、恐动、公开演讲等人群,创造一个受控的虚拟环境。

Android 游戏中的虚拟现实

在 Android N 的最新版本发布之前,Android 并没有直接支持虚拟现实。谷歌意识到虚拟现实是应用的未来。此前,谷歌发布了 Cardboard SDK 来开发 Android 上的虚拟现实应用。这个 SDK 仍然存在于市场上,并被广泛使用。

市场上已经有许多针对 Android 虚拟现实头盔的游戏。虚拟现实头盔的数量日益增加。虚拟现实以前并不是主流的 Android 游戏开发的一部分,但据信它很快将成为主流,因为 Android 现在已经包含了一个专门的虚拟现实设置。

Android 虚拟现实游戏的历史

在 70 年代末,虚拟现实系统开始以更好的设备迅速发展。结果是虚拟现实在 2016 年被纳入主流 Android SDK。最新的 Android 设备都支持虚拟现实。据信,大多数即将推出的设备都将支持虚拟现实头盔。

以前,操作虚拟现实头盔需要高端 PC 或游戏机。但现在,虚拟现实头盔被设计成支持移动设备。虚拟现实头盔被视为 Android 可穿戴设备的一部分,具有高配置。

技术规格

从技术上讲,虚拟现实系统一直存在严重的延迟问题。然而,随着技术的改进,延迟正在减少,体验也在变得更好。一些著名的虚拟现实头盔包括 Oculus Rift、HTC Vive、三星 Gear VR 等。

让我们来看看哪些 VR 设备直接兼容安卓设备。以前,VR 设备中有集成显示器。然而,现在,安卓设备可以直接与具有多个输入处理器的 VR 头盔相关联。VR 头盔面临的一个限制是它们只兼容特定的移动手机,因为它们自身的物理尺寸和硬件规格。VR 头盔设计用于适配特定的屏幕尺寸。然而,市场上有一些支持多种屏幕尺寸的 VR 套装。

当前安卓 VR 游戏行业

安卓 VR 游戏行业正在迅速增长。几乎所有新手机都支持 VR 应用。许多设备制造商提供专门为特定手机设计的外部 VR 套装。

以前,体验 VR 需要单独的设备,比如 Oculus VR 套装。然而,借助安卓 VR 开发,大多数移动设备都能运行 VR 应用,并且可以通过外部 VR 套装来体验。

安卓在 VR 中的未来

众所周知,VR 游戏正在占领游戏市场。安卓正在不断发展。最新发布的安卓 N 版本具有全新的 VR 支持维度。这清楚地表明安卓在 VR 游戏方面有着巨大的潜力。谷歌有可能正在开发一个未来的 VR 专用平台。

市场上会有更多兼容 VR 的设备。因此,安卓平台上的 VR 游戏有着光明的未来。

谷歌 Daydream

谷歌 Daydream 是下一代 VR 开发平台。据说它是谷歌 Cardboard 的继任者。最新的安卓 N 将包括对谷歌 Daydream 的支持,并且已经决定将支持 Daydream 的手机称为“Daydream-ready phones”。

谷歌 Daydream 和 Android N 将把安卓上的 VR 游戏带到数字游戏世界的新高度。游戏的体验和质量将会更好、更流畅、更逼真。

针对 VR 设备的游戏开发

移动游戏行业中有很大的空间可以用于 VR。基于安卓和谷歌 VR 平台,开发者现在正在针对 VR 开发游戏。VR 游戏在性质上与其他游戏不同。它将用户带入游戏世界。当然,游戏设计和规划也与其他移动游戏不同。

VR 游戏设计

VR 并不适合每种游戏类型。因此,VR 游戏设计需要相应调整。在游戏中有角色时,VR 游戏更适合,最好是第一人称射击游戏或一些 RPG 或赛车游戏。

设计师需要记住整个游戏世界必须通过游戏由用户来体验。因此,游戏体验是任何 VR 游戏最重要的因素。

一般来说,游戏设计师从一个想法开始设计游戏。然后,相应的控制、环境和体验被考虑进去。然而,在 VR 游戏的情况下,开发者或设计师已经有了一组定义好的特性,他们通过设计来实现这个想法。

VR 目标受众

全球有数十亿部手机。然而,只有很少一部分实际上兼容 VR 并且能够流畅运行 VR 游戏。随着时间的推移,越来越多的设备具备了 VR 功能。

在安卓上玩 VR 游戏不仅需要手机,还需要兼容的 VR 头盔。并不是每个用户都会去购买额外的设备来玩 VR 游戏。这就是为什么休闲玩家不是 VR 游戏的主要目标受众。相反,典型的玩家和游戏爱好者现在是实际的目标受众。

VR 的用途广泛。其中一个主要用途是模拟,包括教育。教育过程的游戏化为学生开辟了一个巨大的目标受众。另一个主要目标受众是对新事物充满好奇和活力的年轻人。

VR 游戏开发的限制

VR 游戏开发并不需要非凡的技能。开发人员应该熟悉并精通安卓系统,足够高效地理解 VR 规格和平台限制。在安卓平台上开发 VR 游戏时有一些限制:

  • 有限的手柄支持

  • 有限且特定的目标受众

  • 有限的控制

  • 有限的图形质量和最大体验

Cardboard SDK 简介

Google Cardboard 是谷歌于 2014 年开发并发布的 VR 平台,用于与智能手机配合使用的头戴设备。该平台旨在鼓励大规模的低成本 VR 应用程序开发,至今已被证明是成功的。2016 年 5 月 18 日,谷歌宣布 Daydream 是该平台的下一个步骤。

“Cardboard”这个名字来源于用硬纸板制成的 VR 设备的概念,这使得设备的成本大大降低。然而,许多第三方公司正在使用各种材料遵循相同的构建架构,以增加其风格和质量。

目前,Google Cardboard 只能用于为安卓和 iOS 创建 VR 应用程序。这改变了 VR 开发的概念,原来只限于典型的设备和硬件规格:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Cardboard 头盔组件

典型的 Google Cardboard 头盔包括以下部分:

  • 一块剪成精确形状的硬纸板

  • 45 毫米焦距镜片

  • 磁铁或电容贴

  • 钩和环尼龙扣

  • 一个橡皮筋

  • 一个可选的近场通信标签

硬纸板设备的每个部分都是预装的或者有一个机械槽可以安装。组装整套设备非常容易和快速。橡皮筋最后安装到头盔上。然而,用任何方式拿着组装好的 VR 头盔都能实现 VR 体验的目的。

组装套件后,将兼容的智能手机插入 VR 头盔的设备槽中,并由相应的组件固定在那里。

Cardboard 应用的工作原理

兼容 Google Cardboard 的应用程序将智能手机显示图像分成两部分,每个眼睛一部分。可以通过每个 45mm 镜片看到图像。它对每个显示部分应用桶形畸变以抵消镜片的枕形畸变。因此,创建了一个完整的广阔的 3D 世界。

最初的 Cardboard 头盔可以容纳屏幕尺寸达 5.7 英寸(140 毫米)的手机,并使用磁铁作为输入按钮,这也需要智能手机设备中的指南针传感器。后来,按钮被一个导电杠替代。

升级和变种

谷歌更新了设计,并于 2016 年发布了下一代 Cardboard VR 头盔,可与 6 英寸(150 毫米)显示屏的手机配合使用。它还用导电杠更新了输入按钮,触发智能手机屏幕上的触摸事件,以实现更好的设备兼容性。

Google 允许多家供应商和制造商使用不同的材料和风格制造兼容 Cardboard 的头盔。今天,我们可以看到这种产品的许多变种。

使用 Cardboard SDK 开发游戏的基本指南

为 Cardboard SDK 或其他任何 VR 组件开发游戏与其他安卓游戏不同。让我们通过以下几点快速了解 Cardboard 开发风格和标准的基础知识:

  • 启动和退出 VR 游戏

  • VR 设备适应

  • 显示属性

  • 游戏组件

  • 游戏控制

  • 游戏音频设置

  • 用户焦点辅助

  • 终极 VR 体验

启动和退出 VR 游戏

通常,在启动安卓游戏后,它会执行一些自动任务并带用户进入菜单选择操作。在 VR 游戏中,需要花时间将安卓设备正确安装到 VR 头盔上,因此开发人员在启动游戏后不会执行任何自动任务。游戏应该等待用户在适合运行的完美状态下开始。

为了更好和更常见的体验,游戏应该提示用户使用 VR 标志或按钮来开始 VR 游戏。

标准 VR 游戏有两种可能的退出方式:

  • 按下返回按钮

  • 按下主页按钮

按下返回按钮

如果 VR 有一个用于显示退出弹出窗口的 2D 界面,那么使用返回按钮是最好的选择。在玩安卓 VR 游戏时,不太可能意外按到返回按钮,因为设备安装在 VR 头显上。通常情况下,只需按一次返回按钮即可退出游戏,因为符合上述标准。否则,退出弹出窗口可以起到作用,类似于非 VR 游戏。

按下主页按钮

通常情况下,按下主页按钮会将安卓应用程序推到后台,而不会关闭应用程序,在 VR 游戏中也是如此。

VR 设备适应

使用 Cardboard SDK 的安卓 VR 游戏应该适应 VR 头显的物理特性。Google Cardboard SDK 具有自动执行此任务的功能。开发者可以依赖 SDK 根据 VR 头显调整应用程序设置和配置。Cardboard SDK 本身包含了几种特定 Cardboard 设备的调整设置。SDK 可以为 VR 头显的几种特定镜片配置立体设置和矫正失真。

建议开发者使用 Cardboard SDK 功能,支持尽可能多的 VR 头显,以便单个游戏为用户提供最佳的 VR 体验,而不会出现任何麻烦。

显示属性

在许多安卓设备中,有一个名为“Lights Out”的功能。在这些设备中,主页、菜单和返回控件被隐藏在“Lights Out”功能下。VR 游戏使用滑屏技术通过 VR 头显镜片生成 3D 体验。这就是为什么在全屏模式下运行 VR 游戏非常必要。系统控件或状态栏可能会出现在用户的外围视野中,阻挡或分散他们的注意力,影响真正的 VR 体验。

游戏内组件

通常情况下,VR 游戏体验是通过设备屏幕在环境中进行的。在游戏过程中,很少会触发任何弹出窗口或其他不需要的组件。

开发者不应调用任何会在游戏过程中触发任何弹出窗口或不需要的中断的 API。安卓目前不支持任何 2D 组件渲染。强制渲染 2D 元素可能会导致 VR 显示的迷失。即使不是这样,用户也需要将设备从 VR 头显中取出,然后执行所需的操作来摆脱弹出窗口,这一点都不方便。

游戏控件

安卓 VR 头显只有一个按钮。因此,在 VR 游戏中,控件设计不遵循传统方式。让我们来看看 VR 游戏的控件方案。

控件概念

UI 控件通常出现在游戏启动时。开发者应该将 UI 控件放在初始视野范围内,以便用户可以找到它们开始游戏。如果控件不在可见范围内,用户可能会感到困惑。在这种情况下,他们可能会四处寻找控件,或者直接离开游戏。在这两种情况下,用户可能会失去对游戏的兴趣。

在玩游戏时,如果有任何用户界面,这些控件需要随着视野移动。否则,用户可能需要回到 UI 元素所在的位置。

控件类型

虽然头显设备只有一个控制单元,但可能有几种使用按钮和其他选项的方式。最常见的控件类型如下:

  • 融合按钮

  • 视觉倒计时

融合按钮

Cardboard VR 头盔只有一个按钮在设备的一侧。它可以用来点击目标。这个按钮的一个用途是触发 VR 世界中的虚拟按钮,它将融合。这意味着在关注虚拟融合按钮一段时间后,将触发相应的任务。然而,这可能会令人沮丧,因为用户需要等待那段时间。为了解决这个问题,开发者应该在可能的情况下给用户一个立即点击虚拟按钮的选项:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

可视倒计时

在使用带有计时器的熔丝按钮时,用户可能会在不知情的情况下关注按钮,并在一定时间后,它会改变游戏状态。在这种情况下,用户可能会感到困惑,无法继续相同的游戏体验。开发者应该通过视觉方式指示用户,在一定时间内会发生某些事情:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

熔丝按钮指示

我们已经知道 VR 游戏不支持 2D UI 按钮。因此,开发者使用熔丝按钮。熔丝按钮可以是游戏中的任何元素。必须有指示来引导用户关注特定的熔丝按钮。然后,可以在倒计时或点击时执行操作。

例如,开发者经常使用一些发光、闪烁、摇晃或其他动态机制来使对象可点击。周围的任务或动作由环境来定义以指示任务。

控制放置

当元素足够大以便关注时,激活熔丝按钮总是一个好的做法。这可以避免用户产生很多困惑。此外,场景中不应该有难以定位并可能造成困惑的相邻熔丝按钮。

通过 Google VR 进行 VR 游戏开发

谷歌通过 Google VR 发布了一个针对 Android 的 VR 开发工具包,其中包括 Android SDK 和 Android NDK。这些 SDK 支持 Cardboard 和 Daydream VR 平台。

开发者可以通过以下任务跳入 VR 游戏开发:

  • 头部跟踪系统

  • 空间音频

  • 动态渲染

  • UI 处理

  • 3D 校准

  • 镜头失真校正

  • 立体几何配置

让我们来看看用于 VR 游戏开发的 Android SDK:

  • 使用 Android SDK 的 Google VR

  • 使用 Android NDK 的 Google VR

使用 Android SDK 的 Google VR

我们将通过 Android SDK 来看一下 VR 开发。可以使用 Gradle 来构建 VR 应用程序。Gradle 可以独立使用,也可以与 Android Studio 一起使用。

开发者可以使用 Android Studio 之外的其他工具,但强烈建议在 Android 构建中使用 Android Studio。这是在 Android 平台上开发 VR 应用程序最方便的方法。

开发者需要检查以下因素,以便为 Android 创建 VR 应用程序构建:

  • Android Studio 版本 1.0 或更高

  • Android SDK 版本 23 或更高

  • Gradle 版本 23.0.1 或更高

使用 Android Studio 可以避免用户配置 Gradle 设置来构建应用程序包。它还可以帮助开发者识别并在需要时更新 Gradle。

开发者可以选择使用 Gradle 来构建 Android 应用程序项目。在这种情况下,开发者需要手动编辑每个模块的build.gradle文件,以包括 Gradle 构建的.AAR声明。

修改必须这样做:

dependencies
{
  compile(name:'audio', ext:'aar')
  compile(name:'common', ext:'aar')
  compile(name:'core', ext:'aar')
}

repositories
{
  flatDir
  {
    dirs 'libs'
  }
}

Android Studio 会自动进行这些更改,并为每个模块声明依赖项。这将告诉 Gradle 在相应模块的libs子目录中查找三个.AAR声明。如果没有名为libs的子目录,则开发者需要在模块目录内创建一个libs子目录,并手动复制所需的.AAR文件。

使用 Android NDK 的 Google VR

使用 Android NDK 进行 VR 应用开发与 SDK 开发并没有太大的不同。它需要以下组件:

  • Android Studio 版本 1.0 或更高

  • Android NDK

  • Google VR SDK for Android

建议使用 Android NDK 与 Daydream 开发平台。因此,开发者需要为 Daydream SDK 设置开发环境。

Google VR 开发工具包从版本 v0.8.0 的测试版开始支持 NDK 开发。从版本 v0.8.1 开始,它包括了一个本地的头部跟踪系统来增强开发。

Android SDK 足以开发 Cardboard 的 VR 游戏,但一些开发者喜欢使用 C++等本地语言来开发游戏。一些开发者选择使用 C++和 OpenGL 来开发 VR 游戏,以便更好地理解技术。这样,VR 游戏也可以在其他 VR 平台上使用。

Android VR 开发最佳实践

开发者在开始使用 Cardboard 开发 VR 体验之前,需要有编写 Android 常规游戏的经验。以下是开发者在为 Google Cardboard 开发 VR 游戏时需要注意的几个方面:

  • 绘制调用限制

  • 三角形数量限制

  • 保持稳定的 FPS

  • 克服过热问题

  • 追求更好的音频体验

  • 设置适当的项目设置

  • 使用适当的测试环境

绘制调用限制

VR 游戏显然是 3D 游戏,需要进行广泛的渲染过程。将绘制调用最小化以限制渲染时间并减少 GPU 开销是一种良好的实践。

一般来说,根据当前可用设备的列表,开发者应该将每帧的渲染调用限制在 100 次。在当前行业中,大多数开发者都在努力将绘制调用保持在 50 到 100 之间。

三角形数量限制

我们已经讨论了在 3D 游戏中顶点和三角形的功能。相同的逻辑也适用于 VR 游戏。然而,在 VR 游戏中保持性能比普通的 3D 游戏更加困难。这就是为什么 VR 游戏通常使用 100k 以内的三角形数量。

目前,性能良好的 VR 游戏的平均三角形数量约为 50k 至 80k。开发者需要简化所有的 3D 对象,并将它们优化为可能的最小三角形和顶点,以在运行时获得良好的 FPS。

保持稳定的 FPS

对于任何 Android 游戏来说,保持稳定和良好的 FPS 是必要的。Android 的 VR 游戏也不例外。通过上述限制,开发者可以减少渲染时间以获得更好的性能。

VR 游戏使用分屏技术,这是一个繁重的过程。因此,开发者应该决定并使用尽可能少的游戏对象或元素,以保持稳定的 FPS。

对于 VR 游戏开发者来说,以有限的资源提供更好的视觉效果是一个巨大的挑战。设计和创建艺术资源是一个重要部分。使用最少的三角形来制作低多边形模型会产生较差的视觉质量。然而,通过对模型提供出色的纹理支持和在虚拟现实世界中进行战略光照映射,可以改善这种质量。

克服过热问题

过热是 Android VR 游戏的常见问题。由于 CPU 和 GPU 的广泛使用,设备在运行 VR 应用时会发热。开发者无法完全解决这个问题。然而,开发者可以优化 VR 游戏以减少处理器使用。游戏应该限制网络使用和其他设备组件,以最小化电池消耗。

更好的音频体验

Android VR 游戏是在额外的 VR 设备的支持下进行的,例如 Google Cardboard 或类似设备。我们已经在本章讨论过这些设备。这些设备没有音频支持;VR 游戏默认使用设备扬声器。

没有适当的音频体验,虚拟现实体验就不完整。在游戏中使用 3D 环境音频并建议用户在玩 VR 游戏时戴上耳机,这总是一个好的做法。

设置适当的项目设置

在项目设置 VR 项目设置正确可以在未来避免开发者的头疼。特别是为了获得更好的项目性能,很重要在项目开始时正确设置质量设置。没有先前的项目配置,整个项目和性能规划都不会有成果。

使用适当的测试环境

为了任何游戏的成功,特别是对于大规模游戏如 VR 游戏,设置测试环境是非常重要的。开发者必须了解每个开发阶段的状态,以便他们可以做出未来的决定,使游戏变得更好。通过这种方式,开发过程可以顺利进行。

建议您从 VR 设备外部运行 VR 游戏进行测试。还建议您使用 adb 检查每个调试条件和语句。由于游戏必须使用 VR 设备进行测试,因此很难使用普通的调试桥接。开发者需要设置无线调试桥接来克服这个问题。调试桥接也可以用于从 VR 设备外部运行和停止游戏。通过这种方式,开发者可以节省大量时间,用于改进游戏。

安卓 VR 游戏市场的挑战

我们已经了解了在安卓平台上开发 VR 游戏的技术挑战。现在,让我们看看开发者在开发或为安卓平台上的 VR 游戏进行货币化时可能面临的其他挑战:

  • 目标受众少

  • 游戏类型有限

  • 长时间游戏时间

  • 设备支持有限

  • 实时约束

目标受众少

很少有安卓用户熟悉 VR 概念和技术。大多数用户只是普通的手机持有者,没有 VR 头盔。因此,已经有一大部分受众不在 VR 游戏的范围内。这就是为什么 VR 游戏市场受众有限于拥有 VR 头盔的人群。

游戏类型有限

我们已经看到了 VR 游戏中可能的游戏类型。VR 游戏不能支持迄今为止发布的所有游戏类型,可能在不久的将来也无法做到。这种限制对于安卓 VR 游戏市场来说是一个严重的挑战,它影响了其在获得盈利地位和设计货币化方面的地位。

长时间游戏时间

安卓 VR 游戏必须使用配备安卓手机的 VR 头盔进行游戏。通常游戏时间较长,需要时间和精力来设置一个可玩的环境。

安卓游戏用户通常沉迷于快速和灵活的游戏时间。大多数游戏可以立即暂停和恢复,方便游戏。然而,VR 游戏不能立即暂停或恢复。用户更喜欢在有长时间空闲的时候玩 VR 游戏。

设备支持有限

安卓 VR 游戏需要高水平的硬件配置来运行游戏。硬件平台必须有足够的能力来处理游戏,渲染单元必须以最短的时间内以最大可能的质量渲染游戏。

市场上有很多廉价和低配置的手机。数百万安卓用户使用这些手机。然而,大多数手机无法稳定且可接受的 FPS 运行 VR 游戏。安卓 VR 游戏的开发者不得不排除这些设备。这种限制显著减少了受支持设备的数量。

实时约束

大多数 VR 游戏玩家是游戏玩家或游戏爱好者。然而,他们在玩 VR 游戏时也有一些实时约束。用户或玩家必须选择一个游戏情境,其中可能中断的机会最小。

玩家通常更喜欢坐在一个地方或者在宽敞的地方玩游戏,以避免发生任何意外。他们的眼睛被 VR 头盔遮住,所以用户需要采取这些安全措施。这些问题无法解决,这影响了 VR 游戏市场,导致了低会话次数和时间。

扩展的 VR 游戏概念和开发

我们只谈到了 Android 的 VR 游戏方面的一些内容。这些想法已经被实施或正在实施。然而,虚拟游戏还有更广泛的概念。

游戏开发者现在正试图利用 VR 技术制作实时体验。有一些类似数字游戏的实时游戏,比如彩弹激光标签等。借助 VR 技术,这些体验可以达到一个新的水平。在一个与 VR 应用环境物理同步的预定义竞技场中使用 VR 头盔可以让用户进入游戏。这种游戏概念已经开始成形。一些用于 VR 游戏的测试竞技场已经通过各种其他物理设备和传感器的支持被创建出来。这些设备和传感器可以实时跟踪用户的动作,并通过 VR 头盔显示在虚拟世界中复制出来。

诸如行走、蹲下、在虚拟世界中触摸某物以及射击虚拟敌人等简单动作已经被实现。开发人员和研究人员正在不断改进。然而,出于以下原因,Android 平台尚未迈出这种 VR 开发的步伐:

  • Android 是一个最适合便携设备的移动操作系统。

  • 大多数 Android 设备是移动电话或平板电脑。

  • 在 Android 上管理一个具有大型物理设置的专用硬件平台是困难的。实时操作系统RTOS)对于这类系统的性能要比 Android 好得多。

  • 这种 Android 设置的市场前景不佳,成本可能会很高。

尽管在大规模设置 Android VR 游戏中存在这些问题,但人们相信 Android 很快将成为这类系统的一部分。

总结

这是科技时代。VR 技术已经将游戏体验提升到了一个新的水平。Android 现在是游戏开发最为进步的平台。将两个领先的平台结合起来肯定可以将移动游戏体验提升到一个新的水平。

在 VR 游戏中,用户有机会置身于游戏环境中。然而,在为 Android 开发具有 VR 功能的游戏时存在许多限制。谷歌已经宣布了即将推出的 VR 开发平台 Daydream,其中包括带有独立控制器的扩展控制。

VR 游戏行业正在迅速增长。它有自己的一套优势和劣势。然而,毫无疑问,游戏体验远比传统的游戏系统要好得多。因此,可以毫不夸张地说,Android VR 游戏行业的未来是光明的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值