Android 游戏开发扩展程序示例演示了如何使用该扩展程序的主要功能。本主题介绍了这些示例以及运行它们所需的设置。
以下示例可在下载页面上获取
- HelloJNI:一个入门项目。
- Endless-Tunnel:一个仅限 Android 的项目。
- Teapot:一个适用于 Windows 和 Android 的跨平台项目。
- AssemblyCode-Link-Objects:一个包含汇编源代码的模板项目。
开始之前
安装 Android 游戏开发扩展程序和示例。如需了解详情,请参阅快速入门。本主题还介绍了如何构建和运行示例,并以 Android 版的 Teapot 示例为例。
项目配置指南介绍了如何为使用该扩展程序的项目配置设置,例如添加 Android 平台和 APK。
HelloJNI
HelloJNI 示例是一个简单的项目,在应用窗口中显示“Hello From JNI”消息。该项目为 Windows 和 Android 使用不同的源代码集。
- Android 源代码和 Gradle 构建脚本目录:HelloJNI\AndroidPackaging
- Windows 源代码和 Visual Studio 项目目录:HelloJNI
当您构建项目时,Visual Studio 会将以下设置传递到应用级 build.gradle
文件。您可以通过修改 Gradle 构建脚本来更改这些设置。
MSBUILD_NDK_VERSION
MSBUILD_MIN_SDK_VERSION
MSBUILD_JNI_LIBS_SRC_DIR
MSBUILD_ANDROID_OUTPUT_APK_NAME
MSBUILD_ANDROID_GRADLE_BUILD_OUTPUT_DIR
设置并运行示例
- 在 Visual Studio 中,打开并构建 HelloJNI 示例。
- 添加一个 Android arm64-v8a 平台。如需了解详情,请参阅添加 Android 平台。
- 将Android APK 项添加到新平台。
- 编译项目。
- 添加以下 Android 平台,然后将 Android APK 项添加到每个平台:Android-armeabi-v7a、Android-x86 和 Android-x86_64。
- 构建并运行示例。
Endless-Tunnel
Endless-Tunnel 示例是一款 Android 游戏,玩家在其中收集白色方块并尝试到达隧道尽头。它从 Github 上的 Android NDK 仓库中的一个 OpenGL 示例移植而来。该示例不提供 Windows 版游戏。
该示例已配置其设置和 Android 平台,因此您无需任何修改即可在 Visual Studio 中构建和运行项目。当您打开解决方案时,解决方案资源管理器会显示以下模块
- endless-tunnel:显示游戏逻辑的应用模块。
- glm:OpenGL Math 仓库的快照,它被构建为一个静态库。
- native_app_glue:一个与 NativeActivity 对象通信的 NDK 封装容器。
Teapot
Teapot 示例显示了一个使用 OpenGL ES 渲染的经典茶壶,并已移植到 Android 游戏开发扩展程序,以演示以下功能
- 跨平台项目开发:您可以为 Windows 和 Android 构建 Teapot 示例。
- 自定义 Android 打包用法:Gradle 构建脚本已移至示例的根目录,即
Teapot.sln
文件所在的位置。 - 自定义 Android 配置,演示如何使用 Address Sanitizer (ASan) 和 Hardware Address Sanitizer (HWASan)。
Teapot 示例的实现分为多个部分,这对于大型跨平台应用和游戏来说很常见
GameApplication
模块:定义用户操作和应用状态,例如用户旋转茶壶或更新应用统计信息。GameEngine
模块:实现核心渲染模块。
要在 Android 上设置和运行示例,请参阅快速入门。要在 Windows 上设置和运行示例,请执行以下操作:
- 安装 GLEW
- 下载并解压缩 GLEW。
- 将二进制文件从
$your-glew-directory\bin\Release\x64
复制到%SystemRoot%\system32
。
- 安装 freeglut
- 下载并解压缩 freeglut。
- 将
$your-freeglut-directory\bin\x86\freeglut.dll
复制到%SystemRoot%\system32
。
- 添加 freeglut 项目依赖项
- 在 Visual Studio 中打开
Teapot.sln
。 - 在菜单中,依次点击 Debug > x64 > Local Windows Debugger。
- 在解决方案资源管理器中,右键点击 GameApplication,然后依次选择 Properties > C/C++ > General > Additional Include Directories。
- 将
$your-freeglut-dir\include
添加到路径中。
- 点击确定。
- 选择 Linker > General > Additional Library Directories。
- 将
$your-freeglut-dir\lib\x64
添加到路径中。 - 点击确定。
- 选择 Linker > General > Additional Library Directories。
- 将
freeglut.lib
添加到路径中。 - 点击确定。
- 在 Visual Studio 中打开
- 添加 GLEW 项目依赖项
- 在解决方案资源管理器窗格中,右键点击 GameApplication,然后依次选择 Properties > C/C++ > General > Additional Include Directories。
- 将
$your-glew-dir\include
添加到路径中。 - 点击确定。
- 选择 Linker > General > Additional Library Directories。
- 将
$your-glew-dir\lib\Release\x86
添加到路径中。 - 点击确定。
- 选择 Linker > General > Additional Library Directories。
- 将
glew32.lib
添加到路径中。 - 点击确定。
- 在 Windows 上运行示例
- 在 Visual Studio 工具栏上,点击 Local Windows Debugger 运行按钮。
- 示例应如下所示
AssemblyCode-Link-Objects
这是一个模板项目,演示了如何从汇编和 C/C++ 源代码生成 Android 原生库。主要组件包括
AssemblyCode-Link-Objects
:由 C++ 和汇编源代码构建的主 Android 原生库。StaticLib
:一个辅助静态库,可导出from_static_lib_assembly_code_as
函数。
该项目支持多种架构。每种受支持的架构都有自己的源文件,用于实现从 StaticLib
导出的函数。您应该只包含您正在构建的平台的汇编源文件。此项目通过使用自定义构建工具在构建中包含汇编文件。
设置和构建示例
- 在 Visual Studio 中,验证是否已为汇编文件配置自定义构建工具
- 在解决方案资源管理器中,右键点击汇编文件,然后点击属性。这将打开该文件的属性页对话框。
- 选择配置和平台,例如 Android-arm64-v8a 的所有配置。
- 确保 General > Exclude from Build 设置为 No。
- 确保 General > Item Type 设置为 Custom Build Tool。
- 如果有要应用的更改,请点击应用。
- 确保 Configuration Properties > Custom Build Tools > Command Line 设置为
$(AsToolExe) -o "$(IntDir)%(FileName).o" %(FullPath)
。NDK 包含一个用于每个 CPU 架构的单独汇编器,并且$(AsToolExe)
映射到正确的汇编器。此示例使用 NDK 工具链构建 x86 和 x86_64 Android 项目。如果您想为 x86_64 Android 平台使用 yasm,请改用$(YasmToolExe)
。 - 确保 Configuration Properties > Custom Build Tools > Outputs 设置为
$(IntDir)%(FileName).o
。此字符串必须包含在 Command Line 设置中。 - 确保 Configuration Properties > Custom Build Tools > Link Objects 设置为
Yes
。
例如,Android-arm64-v8a 设置应与以下屏幕截图类似
- 构建项目。这将构建
libAssmeblyCodeLinkObjects.so
文件- 打开
AssemblyCode-Link-Objects.sln
文件。 - 在菜单中,点击 Build > Build Solution。
- 打开
- 要确认函数已正确导出到 Android 库,请使用 nm.exe NDK 工具
- 在命令行中,转到示例目录。
- 转到您的构建生成的 Android 库位置。默认位置类似于
$sample_dir\$solution_configuration\$solution_platform\$platform
,对于 arm64-v8a 平台,则类似于$sample_dir\Debug\Android-arm64-v8a\arm64-v8a
。 - 通过运行以下命令验证导出的符号部分是否包含这些函数
…\ndk\toolschains\llvm\prebuilt\windows-x86_64\aarch64-linux-android\bin\nm.exe --defined-only …\Debug\Android-arm64-v8a\arm64-v8a\libAssmeblyCodeLinkObjects.so
在输出中,您应该看到一个包含以下内容的符号列表
T from_shared_object_assembly_code_as
T from_static_lib_assembly_code_as
PoolAllocator
PoolAllocator 示例是一个 Android 应用,它拥有一个基于池的内存分配器,可以非常高效地提供固定大小的内存块。
该分配器在初始化时使用 mmap
预分配整个内存。空闲块使用链表进行跟踪。然后,内存分配是一个快速的 O(1)
操作,返回链表的头部,而解除分配也是一个 O(1)
操作,因为它将内存块添加到链表的尾部。
该示例有两个用于使用 HWASan 的解决方案配置。
HWASan
:此配置演示了将 HWASan 与自定义内存分配器一起使用的最简单方法。内存分配器的内部实现被替换为malloc
/free
调用,这些调用由 HWASan 自动跟踪。虽然内存分配器不再作为基于池的分配器运行,但 HWASan 仍然可以帮助您识别重要的内存 bug,例如释放后使用 (use-after-free)。HWASan-Advanced
:此配置演示了如何将 HWASan 完全集成到自定义内存分配器中,而无需更改分配器使用的原始分配机制。它使用 HWASan 标记方法来标记预分配池中的内存块,将块大小向上舍入到 HWASan 要求的最小块大小,并在块返回池中时重置标签。
使用 HWASan
配置,因为它更简单,可以帮助您识别常见的内存 bug。如果您想了解 HWASan 的工作原理,或者想在使用 HWASan 的同时保留内存分配器的内部语义,可以探索 HWASan-Advanced
配置的实现。