安卓 3D 游戏开发入门指南(八)

原文:Beginning Android 3D Game Development

协议:CC BY-NC-SA 4.0

十一、Android 本地开发套件(NDK)

Abstract

本章涵盖了 Android 本地开发工具包,或 NDK。我从 NDK 的概述开始,讨论 NDK 实际上是什么,然后检查为了使用这个工具包开发 Android 程序必须满足的系统和软件需求。然后,讨论 Java 本机接口,或 JNI,包括如何使用它来创建在从 C/C++ 代码编译的本机代码中运行的函数,并可以从我们在本书中使用的默认 Java 框架内的 Java 函数中调用。接下来,给出了一个使用 JNI 的“Hello World”示例,该示例提供了创建一个简单 Android 程序的分步指南,该程序使用 JNI 和用 C 语言编写的本机代码来输出字符串。最后,我们将展示另一个动手操作的示例,它从我们的无人机网格游戏中提取一些现有代码,并将现有的 Java 代码转换为本地代码。

本章涵盖了 Android 本地开发工具包,或 NDK。我从 NDK 的概述开始,讨论 NDK 实际上是什么,然后检查为了使用这个工具包开发 Android 程序必须满足的系统和软件需求。然后,讨论 Java 本机接口,或 JNI,包括如何使用它来创建在从 C/C++ 代码编译的本机代码中运行的函数,并可以从我们在本书中使用的默认 Java 框架内的 Java 函数中调用。接下来,给出了一个使用 JNI 的“Hello World”示例,该示例提供了创建一个简单 Android 程序的分步指南,该程序使用 JNI 和用 C 语言编写的本机代码来输出字符串。最后,我们将展示另一个动手操作的示例,它从我们的无人机网格游戏中提取一些现有代码,并将现有的 Java 代码转换为本地代码。

NDK 概述

NDK 是一组工具,旨在与现有的 Android 开发工具(如 Eclipse)一起工作,将从 C 和 C++ 代码编译的本机代码嵌入到 Android 程序中。NDK 可以用来将 C/C++ 代码编译成一个库,然后由 Eclipse 用来编译最终的 Android 应用。一个重要的问题是,只有 Android 操作系统版本 1.5 (Cupcake)或更高版本可以使用 NDK 在 Android 应用中嵌入本机代码。

NDK 系统要求

需要完整的 Android SDK 安装(包括所有依赖项)。需要 Android 1.5 SDK 或更高版本。

支持的操作系统包括:

  • Windows XP (32 位)或 Vista (32 位或 64 位)
  • Mac OS X 10.4.8 或更高版本(仅限 x86)
  • Linux (32 位或 64 位;Ubuntu 8.04 或其他使用 GLibc 2.7 或更高版本的 Linux 发行版)

所需的开发工具:

  • 对于所有开发平台,都需要 GNU Make 3.81 或更高版本。GNU Make 的早期版本可能可以工作,但是还没有经过测试。
  • 还需要 awk 的最新版本(GNU Awk 或 Nawk)。
  • 对于 Windows,需要 Cygwin 1.7 或更高版本。NDK 不适用于 Cygwin 1.5 安装。

Note

Cygwin 程序可以从 www.cygwin.com 下载。

Android 平台兼容性

由 NDK 生成的针对特定 CPU 架构的本机代码需要最低 Android 操作系统版本,具体取决于所针对的 CPU。

  • ARM,ARM-NEON 目标代码需要 Android 1.5(API 3 级)及更高版本。实际上,目前几乎 100%的可用 Android 设备至少是 1.5 或更高。
  • x86 目标代码需要 Android 2.3 (API Level 9)及更高版本。
  • MIPS 目标代码需要 Android 2.3 (API Level 9)及更高版本。

安装 Android NDK

安卓 NDK 主安装文件位于安卓官方网站 www.android.com 。NDK 是一个 zip 文件,你必须下载并解压到你的硬盘上。(见图 11-1 。)

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

图 11-1。

Android NDK downloads

如果您在 Windows 平台上进行开发,您必须下载并安装 Cygwin,这是一个 Unix 风格的命令行界面,允许您在 PC 上执行 Unix 命令。(见图 11-2 。)

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

图 11-2。

Cygwin Unix command shell for Windows

安卓 NDK 的使用方法

有两种方法可以使用安卓 NDK。

  • 使用 Android Java 框架,并使用 Java 本地接口或 JNI 从基于 Java 的 Android 程序中调用本地代码。
  • 使用 Android SDK 提供的 NativeActivity 类正常替换 Java 语言生命周期回调,如onCreate()onPause()onResume()等。,用 C/C++ 写的原生代码。但是原生活动必须运行在 Android 操作系统 2.3 版(API Level 9)及更高版本上。此外,一些 Android 框架服务不能本地访问。

在这一章中,我将介绍如何使用 JNI 从 Java 框架中访问本地代码。

Java 本地接口概述

JNI 允许在 Android 虚拟机中运行的 Java 代码与用其他编程语言(如 C、C++ 和汇编语言)编写的应用和库一起运行。本节将讨论 Java 接口指针。处理本机 C/C++ 编码方法,包括与 JNI 一起使用的变量类型、本机 C/C++ 函数所需的命名约定以及这些函数所需的输入参数。给出了将本机函数集成到 Java 代码中的过程。本节还提供了如何从 Java 中使用本机代码以及如何从本机代码中使用 Java 函数的示例。

Java 接口指针

C/C++ 中的本机代码通过 JNI 函数访问 Java 虚拟机,这些函数是通过 Java 接口指针访问的。JNI 接口指针是指向 JNI 函数的指针数组的指针。(见图 11-3 。)

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

图 11-3。

The Java Interface Pointer

加载和链接本机 C/C++ 方法

为了在 Android Java 代码中使用本地类(参见清单 11-1),您必须

Load the compiled library by using the System.loadLibrary() function.   Declare the native class that is defined in the C/C++ source code as native in the Android Java code by using the native keyword in a function declaration.

清单 11-1。从 Android Java 代码加载和链接本地 C/C++ 方法

package robs.gldemo.robsgl20tutorial;

class GLES20TriangleRenderer implements GLSurfaceView.Renderer

{

/* this is used to load the 'hello-jni' library on application

* startup. The library has already been unpacked into

* /data/data/com.example.hellojni/lib/libhello-jni.so at

* installation time by the package manager.

*/

static {

System.loadLibrary("hello-jni");

}

public native String  RobsstringFromJNI();

}

命名本机函数

Java 代码中声明的本机函数必须根据特定格式与本机 C/C++ 代码中声明的函数名匹配,如下所示:

The function starts with “Java.”   It is followed by the package name “robs_gldemo_robsgl20tutorial” from the example in Listing 11-1.   This is followed by the class name “GLES20TriangleRenderer” from the example in Listing 11-1.   Next comes the function name “RobsstringFromJNI” from the example in Listing 11-1.

在清单 11-2 中可以看到完整的函数名。

清单 11-2。原生RobsstringFromJNI()函数

jstring

Java_robs_gldemo_robsgl20tutorial_GLES20TriangleRenderer_RobsstringFromJNI (JNIEnv* env, jobject thiz )

{

return (*env)->NewStringUTF(env, "Rob’s String Text Message!");

}

本机函数参数

本地函数的参数列表总是以一个指向 JNIEnv 的指针开始,它是 Java 接口指针,例如,在清单 11-2 的本地函数中的env

JNIEnv* env

第二个参数是对对象的引用,如果本地函数是非静态的,例如清单 11-2 中的本地函数示例中的thiz

jobject thiz

但是,如果本机函数是静态的,第二个参数是对其 Java 类的引用。

C 与 C++ 本机函数格式

清单 11-2 中的函数是利用 Java 本地接口的 C 本地函数。C++ 版本略有不同,但是底层机制是相同的(见清单 11-3)。主要区别是

The extern "C" specification   The change from (*env)-> to env-> for accessing the JNI functions   The removal of env as the first parameter of the JNI function call

清单 11-3。相当于 C++ 的本机函数

extern "C" /* specify the C calling convention */

jstring

Java_robs_gldemo_robsgl20tutorial_GLES20TriangleRenderer_RobsstringFromJNI (JNIEnv* env, jobject thiz )

{

return env->NewStringUTF("Rob’s String Text Message!");

}

本地类型

JNI 本地数据类型及其 Java 等价物包括

  • jboolean:这种本机类型相当于布尔型 Java 类型,大小为无符号 8 位。
  • jbyte:这种本机类型相当于 byte Java 类型,大小为 8 位。
  • jchar:这种本机类型相当于 char Java 类型,大小是无符号的 16 位。
  • jshort:这种本机类型相当于短 Java 类型,大小为 16 位。
  • jint:这种本机类型相当于 int Java 类型,大小为 32 位。
  • jlong:这种本地类型相当于 long Java 类型,大小为 64 位。
  • jfloat:这个本机类型相当于 float Java 类型,大小为 32 位。
  • jdouble:这种本机类型相当于双 Java 类型,大小为 64 位。

参考类型

JNI 包括一些对应于各种 Java 对象的引用类型。参见图 11-4 ,了解分层视图中这些参考类型的列表。

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

图 11-4。

Reference type hierarchy

JNI 签名类型

JNI 使用 Java 虚拟机的签名类型表示,这些签名类型用于定义特定的函数,包括其返回值类型和输入参数的类型。签名类型如下:

  • z 布尔类型
  • b 字节类型
  • c 字符类型
  • s 短型
  • I int 类型
  • j 长型
  • f 浮动型
  • d 双型
  • l 完全合格级;完全合格的类别
  • [ type type[]数组
  • (arg-types) ret-type(方法)返回类型
  • 五.无效

例如,Java 方法

long JavaMethod1(int number, String str, int[] intarray1);

具有以下类型签名:

(ILjava/lang/String;[I)J

另一个例子是 Orientation 类中的AddRotation()函数。

void AddRotation(float AngleIncrementDegrees)

这个函数的签名类型是

(F)V

F表示浮点输入参数,而V表示 void 返回类型。

从 Java 调用本机代码和从本机代码访问 Java 方法

要从 Java 代码中调用本机函数,您可以使用不带额外标识信息的损坏前缀的本机函数名。例如,要调用清单 11-5 所示的本机函数AddRotationNative(),可以使用清单 11-4 所示的代码。

清单 11-4。从 Java 调用本机代码

void AddRotationToObject(Orientation O, float AngleAmount)

{

AddRotationNative(O, AngleAmount);

}

清单 11-5 中显示的本地函数AddRotationNative()为定向对象调用AddRotation()函数,该定向对象被传递到函数中并保存在Orient变量中。

AddRotationNative()功能执行以下操作:

Gets the class of the Java object Orient by calling the GetObjectClass() JNI function and assigns it to the OrientationClass variable   Gets the method id of a specific function by calling the GetMethodID() JNI function with parameters including the function name, which is "AddRotation"; the function signature type, which is "(F)V"; and the Java class object that contains the function, which is OrientationClass. This method id is assigned to the MethodID variable.   Calls the Orient Java object’s AddRotation() function with parameter RotationAngle by calling the CallVoidMethod() JNI function

清单 11-5。从本机代码访问 Java 方法

Java_robs_gldemo_robsgl20tutorial_Physics_AddRotationNative(JNIEnv* env,

jobject thiz,

jobject Orient,

jfloat RotationAngle)

{

/*

GetObjectClass

jclass GetObjectClass(JNIEnv *env, jobject obj);

*/

jclass OrientationClass = (*env)->GetObjectClass(env, Orient);

/*

GetMethodID

jmethodID GetMethodID(JNIEnv *env, jclass clazz, const char *name, const char *sig);

*/

jmethodID  MethodID = (*env)->GetMethodID(env,

OrientationClass,

"AddRotation",

"(F)V");

/*

NativeType Call<type>Method(JNIEnv *env, jobject obj, jmethodID methodID, ...);

*/

(*env)->CallVoidMethod(env, Orient, MethodID, RotationAngle);

}

JNI 函数

除了清单 11-5 中讨论的,还有很多 JNI 函数。例如,如果我们要调用的 Java 函数返回一个双数值,那么对于返回 void 的函数,我们必须调用CallDoubleMethod()函数而不是CallVoidMethod。我们不会在这里尝试和讨论每一个 JNI 函数,因为这不是 JNI 的参考手册。如果您想了解更多关于支持的 JNI 功能的完整列表,请访问 http://docs.oracle.com/javase/6/docs/technotes/guides/jni/spec/functions.html#wp9502

Note

JNI 规格的主要网站是 http://docs.oracle.com/javase/6/docs/technotes/guides/jni/spec/jniTOC.html

Android JNI Makefile

Android makefile ( Android.mk)是一个描述您想要编译到 NDK 编译系统的本机代码的文件。

LOCAL_PATH变量保存源文件的位置。NDK 编译系统已经定义了my-dir的值,指向包含Android.mk makefile 的当前目录。你要做的是把这个 makefile 文件放在 JNI 目录下,连同你要编译的所有 C 源代码文件。

LOCAL_PATH := $(call my-dir)

CLEAR_VARS变量已经由 NDK 构建系统定义,并指向一个 makefile,该 makefile 将清除构建系统中使用的许多局部变量。

include $(CLEAR_VARS)

LOCAL_MODULE变量设置将从本地源代码文件生成的库名。库名格式将是前缀“lib”+“hello-jni”+后缀“.so”。但是,如果库名已经以“lib”开头,则前缀“lib”不会添加到最终文件名中。

LOCAL_MODULE    := hello-jni

LOCAL_SRC_FILES变量保存 C/C++ 源文件的名称,NDK 编译系统将编译这些文件并从中创建最终的库。

LOCAL_SRC_FILES := hello-jni.c

BUILD_SHARED_LIBRARY变量由 NDK 构建系统定义,指向一个 makefile 文件,该文件收集并处理构建最终库所需的所有信息。

include $(BUILD_SHARED_LIBRARY)

完整的 makefile 如清单 11-6 所示。

清单 11-6。Android JNI Makefile

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE    := hello-jni

LOCAL_SRC_FILES := hello-jni.c

include $(BUILD_SHARED_LIBRARY)

实际操作示例:“来自 JNI 和本地代码的 Hello World”

在这个动手示例中,讨论了一个简单的“Hello World”示例,其中实际的字符串“Hello World from JNI 和本机代码”是从本机 C 代码生成的,并返回给 Java 调用者,然后在那里打印到日志窗口。

首先,我们必须为 Android 项目创建jni目录。选择要在其中创建jni目录的主项目目录。转到文件➤新➤文件夹,调出新文件夹对话框窗口。在文件夹名称编辑框中输入文件名“jni ”,点击完成按钮,创建一个名为jni的新目录。(见图 11-5 。)

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

图 11-5。

New Folder window dialog

jni目录应该出现在主项目目录下。(见图 11-6 。)

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

图 11-6。

Creating the jni directory

接下来,通过选择文件➤新➤文件在jni目录下创建一个新文件,以打开一个新文件窗口对话框。(见图 11-7 。)

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

图 11-7。

New File window dialog

键入“Android.mk”作为文件名,然后单击 Finish 按钮创建新文件。双击 Package Explorer 窗口中的文件,在 Eclipse 源代码区域显示文本。将清单 11-6 中的 makefile 代码复制到新文件中,并通过选择文件➤全部保存来保存它。

接下来,重复前面的步骤,为 C 源代码文件创建一个新文件,命名为“hello-jni.c”,将清单 11-7 所示的源代码复制到hello-jni.c

清单 11-7。Hello-Jni.c 源代码

#include <string.h>

#include <jni.h>

// package = com.robsexample.glhelloworld;

// class = MyGLRenderer

jstring

Java_com_robsexample_glhelloworld_MyGLRenderer_RobsstringFromJNI(JNIEnv* env,

jobject thiz )

{

return (*env)->NewStringUTF(env, "Hello World from JNI and Native Code.");

}

清单 11-7 显示了本机 C 函数RobsstringFromJNI()。该函数通过调用NewStringUTF()函数创建一个新的 Java 字符串,并将该字符串返回给 Java 调用者。

接下来,必须使用 NDK 编译系统编译本机代码。为了做到这一点,我们必须启动 Cygwin Unix 模拟器,如果您使用 PC 进行 Android 开发,它允许您在 Windows PC 上运行 Unix 命令。

您必须使用 Unix 命令导航到您之前创建的jni目录。使用“cd …”命令将目录更改为上一级目录,命令“cd foldername”将当前目录更改为文件夹名。使用“ls”命令列出当前目录中的文件和文件夹。使用“pwd”命令获取当前所在的目录路径。

您必须转到根目录,并将目录更改为cygdrive/文件夹。然后将目录更改为存储 Android 项目的驱动器,并转到本地源文件所在的特定文件夹。一旦你进入包含 makefile 和源代码的jni目录,你必须从你下载并解压到硬盘的 Android NDK 中运行ndk-build脚本。例如,假设您的文件在/cygdrive/c/AndroidWorkSpaces/WorkSpace1/MainActivity/jni目录中。您可以在当前目录下通过输入脚本的完整路径来执行ndk-build脚本,比如/cygdrive/c/AndroidNDK/andoird-ndk-r9/ndk-build。然后,构建脚本将执行并产生如图 11-8 所示的输出。

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

图 11-8。

Running the ndk-build script in the jni directory

ndk-build脚本将处理您的本地代码文件,并将它们打包到一个名为libhello-jni.so的共享库,该库位于libs/armeabi目录中。(见图 11-9 。)

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

图 11-9。

The shared library generated by the ndk-build script

修改 MyGLRenderer 类

为了使用编译后的本地代码,我们必须对上一章的动手示例中的 MyGLRenderer 类进行一些修改。

必须使用loadLibrary()函数加载带有本机代码的共享库。

static {

System.loadLibrary("hello-jni");

}

库中的本机 C 函数必须用 native 关键字声明,才能被识别和使用。

public native String  RobsstringFromJNI();

onDrawFrame()函数中,String变量TestJNIString被赋予调用RobsstringFromJNI()函数的返回值。该返回值包含在调试日志语句中。(参见清单 11-8。)

清单 11-8。修改onDrawFrame()功能

String  TestJNIString = RobsstringFromJNI();

Log.e("RENDERER", "JNI STRING = " + TestJNIString);

运行程序。您应该在日志窗口中看到调试语句。log 语句的最终输出如图 11-10 所示。

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

图 11-10。

JNI test results in Log window

实践示例:将本机功能添加到无人机网格游戏案例研究

这个动手的例子将演示如何将我们的无人机网格游戏的一部分从 Java 代码转换为本机 C 代码,以及如何从本机 C 代码调用 Java 函数。

在本机代码中计算重力

重力计算可以在我们的无人机网格游戏中修改,这样实际的重力计算就可以用 C 编译,并在 Android 上用本机代码执行。为此,我们必须修改hello-jni.c文件和物理类。

修改hello-jni.c文件

必须修改hello-jni.c文件以包含 C 源代码。

Gravity变量保存我们的 3D 游戏世界的重力加速度值。

float Gravity = 0.010f;

ApplyGravityToObjectNative()函数计算我们游戏中重力加速度应用后物体的新加速度。然后返回这个新的加速度。(参见清单 11-9。)

清单 11-9。计算物体的新的 Y 加速度

jfloat

Java_com_robsexample_glhelloworld_Physics_ApplyGravityToObjectNative(JNIEnv* env,

jobject thiz,

jfloat YAccel)

{

YAccel = YAccel - Gravity;

return YAccel;

}

修改物理课

接下来,必须修改物理类来调用 native 类。

必须在物理类中将ApplyGravityToObjectNative()函数声明为原生函数。

native float ApplyGravityToObjectNative(float YAccel);

ApplyGravityToObject()函数通过用对象的当前 y 加速度调用本机函数ApplyGravityToObjectNative()来计算加速度的新 y 分量。(参见清单 11-10。)

清单 11-10。调用本机重力计算函数

void ApplyGravityToObject()

{

// Do Native Apply Gravity

float YAccel = m_Acceleration.y;

m_Acceleration.y = ApplyGravityToObjectNative(YAccel);

}

从本机代码旋转对象

使用 Java 函数演示对象从本机 C 代码的旋转需要修改hello-jni.c文件、Physics 类和 MyGLRenderer 类。

修改hello-jni.c文件

必须修改hello-jni.c文件来添加本地类AddRotationNative()

AddRotationNative()函数几乎与我们在清单 11-5 中讨论的函数相同。不同之处在于完整的函数名涉及不同的包和类。AddRotationNative()所做的是将RotationAngle度加到对象的旋转上,该对象的方向由输入的Orient参数表示。这是通过调用实际的 Java 语言方法"AddRotation()"来完成的。(参见清单 11-11。)

清单 11-11。添加旋转

Java_``com_robsexample_glhelloworld_Physics

jobject thiz,

jobject Orient,

jfloat RotationAngle)

{

/*

GetObjectClass

jclass GetObjectClass(JNIEnv *env, jobject obj);

*/

jclass OrientationClass = (*env)->GetObjectClass(env, Orient);

/*

GetMethodID

jmethodID GetMethodID(JNIEnv *env, jclass clazz, const char *name, const char *sig);

*/

jmethodID  MethodID = (*env)->GetMethodID(env, OrientationClass,"AddRotation", "(F)V");

/*

NativeType Call<type>Method(JNIEnv *env, jobject obj, jmethodID methodID, ...);

*/

(*env)->CallVoidMethod(env, Orient, MethodID, RotationAngle);

}

修改物理课

物理类也必须被修改以使用自然旋转函数。

必须在 Physics 类中用 native 关键字声明AddRotationNative()函数。

native void  AddRotationNative(Orientation O, float RotationAngle);

AddRotationToObject()函数调用AddRotationNative()函数在对象上执行旋转,并充当本机函数的 Java 包装器接口。(参见清单 11-12。)

清单 11-12。AddRotationNative()的包装功能

void AddRotationToObject(Orientation O, float AngleAmount)

{

AddRotationNative(O, AngleAmount);

}

通过添加 Java 函数AddRotationToObject()来修改UpdatePhysicsObject()函数,该函数调用本地 C 函数来旋转对象,作为物理更新的一部分。旧的AddRotation()功能也被注释掉了。(参见清单 11-13。)

清单 11-13。修改UpdatePhysicsObject()功能

void UpdatePhysicsObject(Orientation orientation)

{

// 0\. Apply Gravity if needed

if (m_ApplyGravity)

{

ApplyGravityToObject();

}

// 1\. Update Linear Velocity

/

m_Acceleration.x = TestSetLimitValue(m_Acceleration.x, m_MaxAcceleration.x);

m_Acceleration.y = TestSetLimitValue(m_Acceleration.y, m_MaxAcceleration.y);

m_Acceleration.z = TestSetLimitValue(m_Acceleration.z, m_MaxAcceleration.z);

m_Velocity.Add(m_Acceleration);

m_Velocity.x = TestSetLimitValue(m_Velocity.x, m_MaxVelocity.x);

m_Velocity.y = TestSetLimitValue(m_Velocity.y, m_MaxVelocity.y);

m_Velocity.z = TestSetLimitValue(m_Velocity.z, m_MaxVelocity.z);

// 2\. Update Angular Velocity

/

m_AngularAcceleration = TestSetLimitValue(m_AngularAcceleration, m_MaxAngularAcceleration);

m_AngularVelocity += m_AngularAcceleration;

m_AngularVelocity = TestSetLimitValue(m_AngularVelocity,m_MaxAngularVelocity);

// 3\. Reset Forces acting on Object

//    Rebuild forces acting on object for each update

m_Acceleration.Clear();

m_AngularAcceleration = 0;

//4\. Update Object Linear Position

Vector3 pos = orientation.GetPosition();

pos.Add(m_Velocity);

// Check for object hitting ground if gravity is on.

if (m_ApplyGravity)

{

if ((pos.y < m_GroundLevel)&& (m_Velocity.y < 0))

{

if (Math.abs(m_Velocity.y) > Math.abs(m_Gravity))

{

m_JustHitGround = true;

}

pos.y = m_GroundLevel;

m_Velocity.y = 0;

}

}

//5\. Update Object Angular Position

// Add Rotation to Rotation Matrix

//orientation.AddRotation(m_AngularVelocity);

// Call Native Method

AddRotationToObject(orientation, m_AngularVelocity);

}

修改 MyGLRenderer 类

最后,必须修改 MyGLRenderer 类。

必须修改CreateArenaObjectsSet()函数,以将旋转力应用到竞技场对象,从而演示在旋转对象中使用原生函数。应用于竞技场对象的旋转力值保存在RotationalForce变量中,并设置为 5000。ApplyRotationalForce()功能用于对竞技场物体施加实际的力。(参见清单 11-14。)

清单 11-14。修改竞技场对象集创建功能

void CreateArenaObjectsSet(Context iContext)

{

m_ArenaObjectsSet = new ArenaObjectSet(iContext);

// Cube

float RotationalForce = 5000;

float MaxVelocity = 0.1f;

ArenaObject3d Obj = CreateArenaObjectCube1(iContext);

Obj.SetArenaObjectID("cube1");

Obj.GetObjectStats().SetDamageValue(10);

Obj.GetObjectPhysics().GetMaxVelocity().Set(MaxVelocity, 1, MaxVelocity);

Obj.GetObjectPhysics().ApplyRotationalForce(RotationalForce, 1);

// Add new Object

boolean result = m_ArenaObjectsSet.AddNewArenaObject(Obj);

///

Obj = CreateArenaObjectCube2(iContext);

Obj.SetArenaObjectID("cube2");

Obj.GetObjectStats().SetDamageValue(10);

Obj.GetObjectPhysics().GetMaxVelocity().Set(MaxVelocity, 1, MaxVelocity);

Obj.GetObjectPhysics().ApplyRotationalForce(RotationalForce, 1);

// Add new Object

result = m_ArenaObjectsSet.AddNewArenaObject(Obj);

}

从本机代码计算碰撞的反作用力

为了计算碰撞的反作用力,必须对hello-jni.c文件和物理类进行修改。

修改hello-jni.c文件

必须通过添加两个函数来修改hello-jni.c文件。

DotProduct()函数计算两个向量(x1,y1,z1)和(x2,y2,z2)之间的点积并返回。(参见清单 11-15。)

清单 11-15。计算两个向量的点积

float DotProduct(float x1, float y1, float z1,

float x2, float y2, float z2)

{

return ((x1 * x2) + (y1 * y2) + (z1 * z2));

}

CalculateCollisionImpulseNative()函数计算两个物体相互碰撞产生的碰撞反作用力,并返回值。(参见清单 11-16。)

清单 11-16。计算碰撞的反作用力

jfloat

Java_com_robsexample_glhelloworld_Physics_CalculateCollisionImpulseNative(JNIEnv* env,

jobject thiz,

jfloat CoefficientOfRestitution,

jfloat Mass1,

jfloat Mass2,

jfloat RelativeVelocityX,

jfloat RelativeVelocityY,

jfloat RelativeVelocityZ,

jfloat CollisionNormalX,

jfloat CollisionNormalY,

jfloat CollisionNormalZ)

{

// 1\. Calculate the impulse along the line of action of the Collision Normal

//float Impulse = (-(1+CoefficientOfRestitution) * (RelativeVelocity.DotProduct(CollisionNormal))) /

//                        (1/Mass1 + 1/Mass2);

float RelativeVelocityDotCollisionNormal = DotProduct(RelativeVelocityX, RelativeVelocityY, RelativeVelocityZ, CollisionNormalX, CollisionNormalY, CollisionNormalZ);

float Impulse = (-(1+CoefficientOfRestitution) * RelativeVelocityDotCollisionNormal)/(1/Mass1 + 1/Mass2);

return Impulse;

}

修改物理课

物理类也必须修改以实现反作用力计算。

CalculateCollisionImpulseNative()函数必须声明为本机函数才能使用。

native float CalculateCollisionImpulseNative(float CoefficientOfRestitution,

float Mass1,float Mass2,

float RelativeVelocityX,  float RelativeVelocityY, float RelativeVelocityZ,

float CollisionNormalX, float CollisionNormalY, float CollisionNormalZ);

必须修改ApplyLinearImpulse()函数,以便它调用CalculateCollisionImpulseNative()函数来计算碰撞的反作用力。对现有的反作用力计算进行了评论。(参见清单 11-17。)

清单 11-17。修改ApplyLinearImpulse()功能

void ApplyLinearImpulse(Object3d body1, Object3d body2)

{

float m_Impulse = 0;

/*

// 1\. Calculate the impulse along the line of action of the Collision Normal

m_Impulse = (-(1+m_CoefficientOfRestitution) * (m_RelativeVelocity.DotProduct(m_CollisionNormal))) / ((1/body1.GetObjectPhysics().GetMass() + 1/body2.GetObjectPhysics().GetMass()));

*/

m_Impulse = CalculateCollisionImpulseNative(m_CoefficientOfRestitution,

body1.GetObjectPhysics().GetMass(),

body2.GetObjectPhysics().GetMass(),

m_RelativeVelocity.x,

m_RelativeVelocity.y,

m_RelativeVelocity.z,

m_CollisionNormal.x,

m_CollisionNormal.y,

m_CollisionNormal.z);

// 2\. Apply Translational Force to bodies

// f = ma;

// f/m = a;

Vector3 Force1 = Vector3.Multiply( m_Impulse, m_CollisionNormal);

Vector3 Force2 = Vector3.Multiply(-m_Impulse, m_CollisionNormal);

body1.GetObjectPhysics().ApplyTranslationalForce(Force1);

body2.GetObjectPhysics().ApplyTranslationalForce(Force2);

}

运行程序。在图 11-11 中,自然计算出的重力应该拉向地面物体,例如坦克。竞技场物体应该如图 11-12 旋转。碰撞后作用在物体上的碰撞力应该使物体相互偏离,如图 11-13 所示。

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

图 11-13。

Collision between player’s ammunition and an arena object with reaction force calculated natively

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

图 11-12。

Arena object turning from natively called rotation

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

图 11-11。

Tank falling from natively calculated gravity

摘要

在这一章中,我介绍了 Android 本地开发工具包(NDK)。我首先概述了 NDK 到底是什么,以及使用 NDK 需要哪些系统要求、软件要求和实际的 Android 硬件要求。然后,讲述了 Java 本机接口,或 JNI,并用来演示 Java 函数如何调用用 C 编写的本机函数,以及用 C 编写的本机函数如何用于调用 Java 函数。然后介绍了一个简单的“Hello World from JNI 和本机代码”实践示例,并带您一步步地将本机代码实现到现有的 Java 程序中。最后,我们展示了另一个实践示例,展示了如何将本机代码集成到我们现有的无人机网格游戏案例研究中。

十二、发布和营销您的最终游戏

Abstract

在这一章中,我将介绍你最终游戏的出版和营销。我首先讨论如何创建用户将要安装的最终游戏发行版文件。然后,我将介绍如何通过复制发行版文件并将其安装在实际的 Android 设备上来测试它。接下来,我将介绍一个 Android 市场列表,您可以在其中上传游戏发行文件进行销售和/或下载。然后,众多支持 Android 的广告网络呈现给那些想通过广告从他们的游戏中赚钱的人。提供了评论 Android 游戏的游戏网站列表。最后,列出了其他对 Android 游戏开发者有帮助的网站。

在这一章中,我将介绍你最终游戏的出版和营销。我首先讨论如何创建用户将要安装的最终游戏发行版文件。然后,我将介绍如何通过复制发行版文件并将其安装在实际的 Android 设备上来测试它。接下来,我将介绍一个 Android 市场列表,您可以在其中上传游戏发行文件进行销售和/或下载。然后,众多支持 Android 的广告网络呈现给那些想通过广告从他们的游戏中赚钱的人。提供了评论 Android 游戏的游戏网站列表。最后,列出了其他对 Android 游戏开发者有帮助的网站。

创建最终分发文件

您将提交给用户下载和安装的最终发行版文件是一个从安装了 Android 开发工具的 Eclipse 程序生成的.apk文件。

要开始创建一个.apk分发文件,选择 File ➤ Export from Eclipse,如图 12-1 所示。

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

图 12-1。

Selecting Export from the File menu

应该会弹出“导出窗口”对话框。在 Android 文件夹下,选择导出 Android 应用,然后单击下一步按钮。(见图 12-2 。)

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

图 12-2。

Exporting an Android application

接下来,应该会弹出导出 Android 应用窗口。点击 Browse 按钮,选择一个要导出的 Android 项目,并将其转换成一个.apk分发文件。一旦选择了一个项目,就会检查是否有任何可能妨碍项目打包的错误。然后,单击“下一步”按钮进入下一个屏幕。(见图 12-3 。)

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

图 12-3。

Select application to export

应该会出现密钥库选择窗口。选择“创建新的密钥库”单选按钮。单击浏览按钮并选择要存储新密钥库文件的目录。在密码框中键入密码,并在确认框中确认密码。单击“下一步”按钮继续。(见图 12-4 。)

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

图 12-4。

Create a new keystore selection

现在应该会显示密钥创建窗口。填写此表格将创建一个密钥,用于签署您的申请。填写表格,然后单击“下一步”按钮。(见图 12-5 。)

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

图 12-5。

Key Creation window Note

建议您将密钥库文件备份到安全的位置。如果您想要更新当前使用这个密钥库文件发布的游戏,您将必须使用这个密钥库文件。

应该会出现目的地和密钥/证书检查窗口。单击 Browse 按钮为您的分发文件.apk输入一个目录和文件名。单击 Finish 按钮开始创建您的最终发行版.apk文件。(见图 12-6 。)

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

图 12-6。

Creating the final .apk file

测试发行版.apk文件

现在让我们测试您刚刚创建的发行版.apk文件,将它安装在 Android 设备上。首先,必须将.apk文件复制到实际的 Android 设备上。有很多方法可以做到这一点,取决于你使用的是什么版本的 Android 操作系统,你的 Android 上安装了什么软件(比如 FTP),你设置了什么网络连接。我将演示适用于所有 Android 操作系统的复制方法,无论您安装了什么文件传输软件或设置了什么网络连接。为此,我们可以使用 Android Debug Bridge (adb) push 命令将文件放在通过 USB 电缆连接到计算机的设备上。该命令的一般形式如下:

adb push Filename LocationOnAndroidDevice

使用位于C:\Android\adt-bundle-windows-x86\sdk\platform-tools的 adb 将MainActivity.apk文件放到安卓设备上的位置/sdcard/Download的具体命令是

C:\Android\adt-bundle-windows-x86\sdk\platform-tools\adb push MainActivity.apk /sdcard/Download

C:指的是安装 Android SDK 的驱动器盘符,可能会根据您存储 SDK 的位置和您使用的具体操作系统而有所不同。执行完命令后,MainActivity.apk文件现在应该在您的 Android 设备上的/sdcard/Download了,假设这个目录已经存在。(见图 12-7 。)

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

图 12-7。

Copying MainActivity.apk on an Android device

在尝试安装.apk文件之前,如果您使用的是 2.2 等较旧版本的 Android 操作系统,您必须转到“设置➤应用”部分,并选中“未知来源”下的复选框,该复选框允许安装来自未知来源的应用。在更高版本的 Android 操作系统上,你必须在设置➤安全下查找。(见图 12-8 。)

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

图 12-8。

Allowing installation of .apk files from unknown sources

回到 Android 的文件管理程序,导航到你复制了.apk文件的目录。点击.apk文件开始安装过程。应该会出现一个屏幕,询问您是否要安装该应用。单击安装按钮。(见图 12-9 。)

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

图 12-9。

Installing the .apk

安装完成后,应出现另一个屏幕,确认.apk已成功安装。(参见图 12-10 。)

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

图 12-10。

App installed verification screen

点击打开按钮开始无人机网格游戏。(参见图 12-11 。)

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

图 12-11。

The game running from the newly installed .apk file

既然你的游戏已经安装并运行在 Android 设备上,是时候开始营销你的游戏了。

Android 市场和政策列表

本节列出了一些 Android 市场,您可以在其中上传您的应用供其他用户下载。每个市场都有自己的政策,这些政策会根据市场情况经常变化。例如,谷歌最近收紧了对其 Google Play 市场销售的应用中可以使用的广告类型的限制。亚马逊最近取消了其在 Amazon.com 商店销售游戏和应用的年费。

Google Play

Google Play 是主要的 Android 市场。注册 Google publisher 帐户的链接是

https://play.google.com/apps/publish

使用谷歌钱包需要支付 25 美元的一次性注册费。如果你想出售物品,你还需要一个谷歌钱包商家账户。您可以在 Google 开发者控制台中导航至财务报告➤立即设置商户帐户选项卡,申请 Google 钱包商户帐户。这应该会带你到谷歌钱包网站注册成为一个商家。

您可以通过开发者控制台快速发布和取消发布您的应用或游戏。谷歌在公开你的安卓程序之前不会对其进行筛选。

Google 政策的完整描述位于

http://play.google.com/about/developer-content-policy.html

Note

如果您决定在游戏中加入广告,请确保它们符合 Google Play 的广告政策,否则您的游戏可能会被禁止,您的帐户可能会永久停用。

应用商店

亚马逊运营着一个安卓应用和游戏商店,你可以在里面出售你的游戏或者提供免费下载。注册开发者账户的网址是

https://developer.amazon.com/welcome.html

注册是免费的。如果你通过亚马逊的 Appstore 销售程序,你将获得该商品标价的 70%。

您需要将游戏提交给 Amazon 进行测试和验证,然后才能下载或购买。复习一般需要几天。

三星应用商店

三星运营着自己的安卓商店,你可以上传你的应用和游戏出售或免费下载。作为开发人员登录的 web 链接是

http://seller.samsungapps.com/login/signIn.as

注册是免费的。如果您通过商店销售游戏,您将获得物品标价的 70%。

在销售或下载之前,您必须将游戏提交给三星审查。复习通常需要一周时间,但这取决于你选择测试游戏的设备数量。三星专门用不同型号的三星手机和平板电脑测试您的游戏,具体取决于您选择的型号。

阿普唑仑(抗抑郁药物)

Aptoide 不同于之前讨论的商店,因为每个开发者或发行者管理他/她自己的商店,并且用户必须下载 Aptoide 客户端并安装它,以便从这些商店下载和安装 Android 软件。官方网站是

www.aptoide.com

以下是官方网站的描述:“Aptoide 是一个网站,你可以通过一个软件客户端 Aptoide 将免费的应用下载到移动 Android 设备上。在 Aptoide 中,你还可以上传安卓应用,与他人分享。”

资本主义

Appitalism 是一个类似于 Google Play 的应用商店,开发者可以在其中销售或上传免费应用进行分发。官方网站是

www.appitalism.com

不收报名费。

利润方面,一件物品价格的 70%返还给开发商。

GetJar

GetJar 允许你在它的网站上免费发布你的游戏或应用。主要网站是

www.getjar.mobi

开发者登录链接是

http://developer.getjar.mobi

GetJar 声称其网站每天有超过 300 万次下载。但是,GetJar 不接受付费应用。

SlideMe

SlideMe 是一个 Android 应用和游戏商店,你可以上传你的免费和付费 Android 游戏进行分发和/或销售。官方网站是

http://slideme.org/

没有开发者费用。

社会主义者 Io 商城

社会主义者 Io Mall 是一个 Android 应用和游戏商店,接受免费和付费应用。官方开发者网站是

https://developer.soc.io/home

提交应用或游戏是免费的。

自己的 WebSite.Com

请记住,使用 Android,您可以在自己的网站上发布您的最终发行版文件。然而,如果你希望为此获得收入,你可能不得不依赖其他实体,如处理信用卡和借记卡交易的支付处理器,或为你的程序用户点击他们的广告付费的广告网络。

Android 广告网络列表

从你的游戏或应用中赚钱的一种方式是使用 Android 广告网络,根据用户点击网络在你的游戏中放置的广告的数量向你支付费用。每个广告网络通常都有自己的软件开发工具包(SDK ),你必须将它集成到你的游戏中。SDK 通常由一个以.jar文件形式的 Android 库和使用该库中的函数来显示广告的代码组成。不同的广告网络有不同风格的广告可供选择。这一部分首先列出了 Android 开发者社区中一些比较突出的公司,然后列出了其他广告网络和营销公司,它们可能对 Android 开发者赚钱和推广他们的游戏有用。

AppFlood

AppFlood 是 PapayaMobile 的一个广告系统,总部位于中国北京,在美国旧金山和英国伦敦设有办事处。它有一个网站

http://appflood.com/

它提供以下类型的广告:

  • 通知广告:这些广告类型是推送到用户 Android 手机的通知。
  • 图标广告:这些广告类型在用户手机屏幕上放置一个图标。请注意,这种类型的广告对许多用户来说很烦人,可能不符合 Google Play 的最新广告政策。

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

图 12-14。

AppFlood more games ad

  • 更多游戏广告:这些广告显示一个大游戏广告,以及四个小游戏广告。(参见图 12-14 。)

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

图 12-13。

AppFlood app list

  • 应用列表:这些广告模仿了典型的 Android 应用/游戏商店的外观和感觉。(参见图 12-13 。)

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

图 12-12。

AppFlood interstitial ad

  • 间隙广告:这是全屏广告,通常在游戏中的自然断点处显示,如关卡结束或游戏结束。(参见图 12-12 。)

阿帕维兹

Appwiz 是一家成立于 2012 年的广告网络,其网站位于

www.appwiz.com

它提供给开发者的广告类型有

  • 搜索图标:用户的主屏幕上有一个搜索图标。但是,请注意,这种类型的广告对许多用户来说是非常讨厌的。
  • 书签:书签放置在用户的 web 浏览器中。
  • Offer wall:在 Appwiz 提供的其他子格式之间动态优化的全屏广告,如 AppWall、SmartWall、对话广告、视频广告和富媒体。
  • 高级广告:放置在主屏幕上的快捷方式,链接到免费应用和热门交易。

铅螺栓

LeadBolt 是一家成立于 2010 年的广告网络,位于澳大利亚悉尼。它的网站是

www.leadbolt.com

可用的广告类型有

  • 旗帜
  • 推送通知
  • 主屏幕图标
  • 浏览器书签
  • 空隙的

AppBucks

AppBucks 是一家位于美国佛罗里达州迈尔斯堡的广告网络。该公司的网站是

www.app-bucks.com

AppBucks 提供的广告类型有

  • 横幅广告:横幅广告显示横幅,通常横跨屏幕的顶部或底部。

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

图 12-16。

AppBucks slider ad

  • 滑动广告:这种类型的广告在壁纸和面向服务的应用中效果很好,从屏幕的一侧滑出。(参见图 12-16 。)

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

图 12-15。

AppBucks interstitial ad

  • 插播广告:这种类型的广告填满整个屏幕,通常用于游戏中的关键点,以引起用户的注意,例如一个关卡的结束。参见图 12-15 中 AppBucks 的插播广告示例。

移动核心

MobileCore 是一家位于以色列特拉维夫的广告网络,成立于 2009 年。该公司的网站是

www.mobilecore.com

MobileCore 提供的广告类型有

  • AppWall 广告:提供其他应用或交易的半屏或全屏广告。开发者将从 AppWall 产生的每次点击或安装中获得报酬。
  • 滑动广告:从屏幕一侧滑出的广告。

AdMob

AdMob 由谷歌运营,如果你希望你的应用符合谷歌的市场政策,它可能是最安全的。违反这些政策会导致你的游戏或应用被禁和/或你的账户被冻结。AdMob 的网站是

www.google.com/ads/admob/

AdMob 有以下类型的广告:

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

图 12-18。

AdMob interstitial ad

  • 插播广告:插播广告是大型全屏广告,旨在吸引眼球。(参见图 12-18 。)

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

图 12-17。

AdMob banner ad

  • 横幅广告:这些广告占据屏幕的一小部分,允许用户点击进入更详细的信息页面或网站。(参见图 12-17 。)

启动应用

StartApp 是 2010 年开始的移动广告平台。总部设在美国纽约,公司的网站是

www.startapp.com

提供的广告类型有

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

图 12-23。

StartApp splash screen

  • 闪屏:在程序加载时显示广告。(参见图 12-23 。)

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

图 12-22。

StartApp search box

  • 搜索框:显示一个有用的滑动搜索框。(参见图 12-22 。)

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

图 12-21。

StartApp exit ad

  • 退出广告:显示当用户点击后退按钮或主页按钮退出应用时出现的广告。(参见图 12-21 。)

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

图 12-20。

StartApp 3D banner ad

  • 横幅广告:3D 横幅广告。(参见图 12-20 。)

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

图 12-19。

StartApp interstitial ad

  • 间隙广告:全屏广告出现在开发者选择的任何位置。(参见图 12-19 。)

其他广告网络和营销相关公司

下面的列表涵盖了广告网络和营销相关的公司,它们可能对你的游戏营销和从游戏中投放的广告中赚钱都有帮助。

  • Aarki ( http://aarki.com ): Aarki 是一家位于加州硅谷的移动广告供应器。
  • AdColony(http://adcolony.com):AdColony 于 2011 年推出,是一家领先的移动视频广告和货币化平台,以闪电般的速度播放清晰的高清视频,并推动内容的深度参与。
  • Adfonic ( http://adfonic.com ): Adfonic 是一个移动广告购买平台,总部位于伦敦。
  • AdIQuity(http://adiquity.com):AdIQuity 是一个全球移动广告平台,帮助移动发行商和应用开发者从他们的移动库存中获得高额收入。它还帮助广告公司、广告网络和其他媒体购买者获得高质量的全球移动流量。
  • AdMarvel(www.admarvel.com):AdMarvel 是全球最大的出版商、代理商和运营商使用的移动广告优化工具。
  • Admoda ( www.admoda.com ): Admoda 是一个移动广告网络。它的主要重点是为基于绩效的营销部门和联盟营销部门提供流量。
  • Applifier(www.applifier.com):Applifier 通过交叉推广,帮助各种规模的游戏和应用发行商增长应用。
  • Apprupt ( www.apprupt.com ): Apprupt 由移动营销专家组成。
  • Avocarrot(www.avocarrot.com):Avocarrot 是一家专门从事高参与度原生广告的独特移动广告网络。从一系列可定制的广告单元中进行选择,以创建无缝的用户体验,从而带来更高的收入。
  • buzz city(www.buzzcity.com):buzz city 是一个全球性的广告网络。
  • chart boost(www.chartboost.com):chart boost 是一款专注于游戏的手机游戏服务。
  • Epom(http://epom.com):Epom 成立于 2010 年,专注于广告服务和广告管理。
  • 第四屏广告( www.4th-screen.com ):成立于 2006 年,现在是 Opera 软件集团的一部分,第四屏广告是欧洲领先的优质移动广告销售机构。
  • Hunt Mobile Ads(www.huntmads.com):Hunt Mobile 是领先的独立移动广告公司,面向西班牙语市场,包括所有拉丁美洲和美国西班牙语市场,并提供发现、建立品牌和利用移动互联网领域的解决方案。
  • InMobi ( www.inmobi.com ): InMobi 是一个基于表现的移动广告网络,由 Soft Bank 和 Kleiner Perkins cau field&Byers 支持。该公司于 2007 年在印度成立,并在多个国家设有办事处。
  • inner active(http://inner-active.com):inner active 是一个面向移动发行商的全球程序化广告栈,专注于视频、超本地和应用内搜索广告。
  • Jampp ( www.jampp.com ): Jampp 是一个领先的数据驱动的移动应用营销平台,连接了大量的移动广告网络和实时竞价交易所。
  • Kiip ( www.kiip.com ): Kiip 提供虚拟成就的真实奖励。
  • Komli Mobile(www.komlimobile.com):Komli Mobile 是全球领先的移动广告和出版网络。
  • lean market(www.lean.com):lean market 专门研究营销效率问题。
  • loop me Media(http://loopme.biz):loop me 是智能手机和平板电脑上社交广告发现领域的全球领先先驱。LoopMe 使消费者能够对广告进行反馈(“喜欢”、“停止”和“分享”),这增加了点击互动、品牌参与度和通过社交认可的价值。
  • MdotM ( www.mdotm.com ): MdotM 是一家移动营销服务公司。
  • media lets(http://medialets.com):media lets 是一家移动广告公司。Medialets 的移动和平板广告服务平台 Servo 提供先进的测量技术和分析以及简化的活动管理。
  • 千禧传媒(www.millennialmedia.com):千禧传媒是一家移动营销和广告公司。
  • MKmob ( www.mkmob.com/ ): MKmob 是一个全球性的移动广告网络。
  • MMedia ( http://mmedia.com ): MMedia 是一个移动广告和货币化网络。
  • Mobbnet ( www.mobbnet.com ): Mobbnet 是一个全球性的广告网络。
  • Mobfox ( www.mobfox.com ): MobFox 是一家移动广告网络,在 iPhone、Android、黑莓、Windows Mobile 和移动网站上运营。
  • Mobgold ( www.mobgold.com ): MobGold 帮助广告商在各种移动设备上接触目标用户,并帮助出版商将他们的移动流量货币化。
  • mobile fuse(www.mobilefuse.com):mobile fuse 是一个移动广告网络,由战略上精选的优质网站和应用组成,覆盖 8500 万唯一用户。
  • 移动理论( http://mobiletheory.com ):移动理论提供移动广告和服务。
  • Mocean Mobile(www.moceanmobile.com):Mocean Mobile market place(MMM)是全球最大的移动广告市场。
  • Mojiva ( www.mojiva.com ): Mojiva 是一家专注于智能手机和平板电脑的移动广告网络。它最出名的是 Mojiva tab,这是一个专门为平板电脑设计的广告网络。
  • MoPub ( www.mopub.com ): MoPub 是专为移动出版商打造的托管广告服务解决方案。
  • Nexage ( www.nexage.com ): Nexage 通过增加移动广告收入和降低运营成本的解决方案来加强出版商和开发商的移动广告业务。
  • OnMOBi ( http://on-mobi.com ): OnMOBi 是一家专注于游戏和金融的广告网络。
  • place play(www.placeplay.com):place play 是一个针对 iOS 和 Android 的移动广告网络。
  • play haven(www.playhaven.com):play haven 是一家专注于游戏的移动广告公司。
  • ponti flex(www.pontiflex.com):ponti flex 是一家专注于注册式广告的移动广告公司。
  • Revmob ( www.revmobmobileadnetwork.com ): Revmob 为 Android 和 iOS 提供移动广告。
  • sell aring(www.sellaring.com):sell aring 提供移动广告,专注于替代现有铃声的音频广告。
  • send droid(http://senddroid.com):send droid 是一家专注于 Android 推送通知广告的移动广告公司。
  • session m(www.sessionm.com):session m 是一家专注于游戏的移动广告公司。
  • Smaato ( www.smaato.com ): Smaato 是全球领先的移动广告交易所。Smaato 的 SMX 平台是全球领先的移动实时竞价广告交易所,帮助移动应用开发商和出版商增加全球广告收入。
  • Sofialys(www.sofialys.com):Sofialys 提供移动广告和营销解决方案,包括广告服务器和移动广告网络。
  • sponsor pay(www.sponsorpay.com):sponsor pay 是一家广告货币化公司。
  • strike ad(www.strikead.com):strike ad 是一家总部位于美国和英国的移动广告公司。
  • Tapgage ( www.tapgage.com ): Tapgage 是一个移动的间隙广告网络,帮助应用开发者和出版商从他们的应用和网站中赚钱。
  • 塔皮特。( www.tapit.com ): TapIt!提供移动广告。
  • Tapjoy ( www.tapjoy.com ): Tapjoy 是一家移动广告公司,允许用户安装一个应用来代替游戏内支付。
  • think near(www.thinknear.com):think near 是一家专注于基于位置的广告的移动广告公司。
  • toda cell(www.todacell.com):toda cell 是一家优质的移动广告公司。
  • trade mob(www.trademob.com):trade mob 总部位于欧洲,提供移动应用营销。
  • Vserv ( www.vserv.mobi ): Vserv 是一家专注于新兴市场的移动广告交易所。
  • Wapstart ( wapstart.ru/en ): Wapstart 是一家俄罗斯移动广告公司。
  • Webmoblink(www.webmoblink.com):Webmoblink 是一家领先的移动广告网络,面向拉丁美洲(西班牙语和葡萄牙语)和美国西班牙语市场。
  • Widespace(www.widespace.com):Widespace 是一家总部位于欧洲的优质移动广告网络。
  • XAd ( www.xad.com ): XAd 提供基于位置的移动广告。
  • y brant Mobile(www.ybrantmobile.com):y brant Mobile 通过定向广告活动提供移动广告。
  • YOC 移动广告( http://group.yoc.com ): YOC 移动广告是欧洲最大的优质移动广告网络,在英国、德国、法国、西班牙和澳大利亚这五个主要市场拥有强大的影响力。
  • YOOSE ( www.yoose.com ): YOOSE 是一个专注于定位广告的移动广告网络。
  • Zumobi ( www.zumobi.com ): Zumobi 是一家移动媒体和广告公司。

Android 游戏评论网站列表

本部分列出了评论 Android 游戏的网站。Android 游戏评论网站是为你的游戏获得免费宣传的绝佳场所。其中一些网站专门致力于 Android,而另一些则是多平台的 Android 板块。

其他对 Android 开发者有帮助的网站列表

下面的列表包含了其他对 Android 开发者有帮助的网站。在这些网站中,有一些提供免费图形和图形相关工具。

  • 打开剪贴画( www.openclipart.org ):包含公共领域和免版税的图形。
  • 矢量公开股票( www.vectoropenstock.com ):包含自由矢量剪贴画
  • Blender 3D 渲染器( www.blender.org ):适用于 Mac OS X、Linux 和 Windows 的免费 3D 模型生成器和渲染器。
  • 用安卓赚钱( www.makingmoneywithandroid.com ):专注于用安卓赚钱的网站。有一个论坛,里面有很多关于 Android 可用的最佳广告网络的讨论。

摘要

在这一章中,我讨论了你的游戏的出版和营销。我首先介绍了如何为你的游戏创建最终发行版文件,以及如何在实际的 Android 设备上测试这个最终发行版文件。接下来,我介绍了一些可用的 Android 市场,你可以在那里出售你的游戏或者提供免费下载。然后,我提出了一个广告网络列表,通过让这些广告网络在你的游戏中放置广告供用户查看和点击,你可以从中赚钱。接下来,我提供了一个游戏评论网站的列表,您可以从这些网站上获得免费的游戏宣传。最后,给出了其他有用网站的列表。

本书共分两篇,第一篇介绍了Android 3D游戏开发的基础知识,主要对OpenGL ES的相关内容进行了介绍。   章 名主 要 内 容   第1章 英雄还看今朝—Android简介本章介绍了市场上主流的手机平台,同时也分析了未来手机平台的发展趋势及Android平台的前景   第2章 数风流人物—当前流行游戏类型简介本章以分类的方式简要地介绍了当前流行的游戏的玩法,游戏的视觉效果,游戏的设计及《仙剑》等著名游戏的历史   第3章 不积跬步,无以至千里—游戏开发基础知识本章初步介绍了游戏开发的基础知识   第4章 千里之行,始于足下—3D开发基础知识本章介绍了3D开发中的基础知识,包括OpenGL ES的介绍及OpenGL ES中绘制模型的原理,并通过点、线和三角形的绘制介绍了OpenGL ES中模型的几种绘制方式。最后介绍了3D场景中常用的两种投影方式,并通过例子比较了这两种投影的区别   第5章 愿君多采撷,此物最相思—光照效果的开发本章介绍了光照的基础知识,包括环境光、散射光及镜面光   第6章 为伊消得人憔悴——纹理映射本章主要介绍了纹理的基础知识,以及纹理的不同拉伸方式和纹理过滤高级技术,从绘制三角形开始到绘制地月系,可能会经历很长时间,但是这对以后的学习是有帮助的   第7章 海阔凭鱼跃,天高任鸟飞—3D基本形状的构建在本章中介绍了圆柱体、圆锥体、圆环、抛物面、双曲面和螺旋面在OpenGL ES中的渲染方法。这些基本形状在3D世界中应用广泛,在构造一些复杂物体时,经常会运用这些基本形状来进行拼装组合   第8章 执子之手,与子偕老—坐标变换本章介绍了坐标变换的应用。绘制3D场景的过程,主要是旋转和平移操作的组合,通过合理的堆栈操作,就比较容易绘制出所需的3D场景   第9章 孤帆远影碧空尽—摄像机与雾特效在本章中,首先对摄像机及其配置做了介绍。摄像机在3D编程中至关重要,没有正确的配置,摄像机可能不能获得想要的场景效果。然后对雾特效做了具体介绍,应用雾特效可以使场景更加逼真,并且可以减少场景渲染量来提高性能   第10章 假作真时真亦假—混合本章主要为读者介绍了混合,从混合的背景知识到如何配置源因子和目标因子。在介绍源因子和目标因子的时候,向读者介绍了一些预定义常量和一些常用的组合方式,以及如何启用混合   第11章 蓦然回首,那人却在灯火阑珊处—3D高级技术本章主要为读者介绍了3D的一部分高级技术。每一项技术通过讲解其原理和案例,使读者对3D高级技术有一定的了解   第12章 心有灵犀一点通—传感器在本章中,向读者介绍了Android中传感器的相关知识。包括传感器的种类、配置,并且着重介绍了姿态传感器的应用   第13章 千锤万凿出深山—游戏中的数学与物理在本章中对3D游戏中可能会用到的数学及物理知识进行了简单的介绍,这在3D游戏开发中是相当重要的。游戏中的核心算法,基本上都要用到数学和物理知识。一款游戏的性能很大程度上取决于游戏设计的算法   第14章 山舞银蛇,原驰蜡象—AI基本理念本章主要介绍了AI、AI引擎的基本组成与设计,以及游戏AI中图的搜索和模糊逻辑,其中游戏AI中图的搜索为本章的重点。在本章中详细介绍了5种算法的原理与实现   第15章 独上高楼,望尽天涯路—开发小秘籍本章介绍了地图设计器、多键技术、虚拟键盘、查找表技术、状态机、AABB边界框、穿透效应、拾取技术,以及天空盒和天空穹在OpenGL ES中的应用 第二篇以7个比较大的案例来说明Android平台下3D游戏的开发流程,通过这7个案例的讲解,读者对3D游戏的开发将会有更深层次的理解。   章 名主 要 内 容   第16章 体育类游戏——《疯狂投篮》本章介绍了Android 3D游戏《疯狂投篮》的开发。通过该案例向读者介绍了在Android平台下进行3D游戏开发的相关知识和基本流程,并对游戏开发中的编程技巧进行了介绍,并主要介绍了篮球与地面、墙面及篮框的碰撞检测及运动动画的实现方法   第17章 益智类游戏——《旋转积木》本章介绍了Android 3D游戏《旋转积木》的开发。主要介绍了积木旋转的不同状态的实现方法和地图设计器的应用   第18章 休闲类游戏——《摩天大楼》本章介绍了Android 3D游戏《摩天大楼》的开发。主要介绍了楼层与楼层之间的衔接与碰撞及掉落后翻转动画的实现   第19章 动作类游戏——《3D空战》本章介绍了Android 3D游戏《3D空战》的开发。主要介绍了飞机的构造方法和我方战机与敌方战机的操控及动画实现   第20章 桌面类游戏——《激情台球》本章介绍了Android 3D游戏《激情台球》的开发。主要介绍了台球与台球的碰撞检测实现、台球与球桌的碰撞检测实现和进球的判定实现   第21章 射击类游戏——《抢滩登陆》本章介绍了Android 3D游戏《抢滩登陆》的开发。主要运用了灰度图生成技术并且主要介绍了坦克运动的实现方法及炮弹碰撞检测的实现   第22章 竞技类游戏——《乡村飙车》本章介绍了Android 3D游戏《乡村飙车》的开发。主要介绍了运用分层绘制和拼接绘制的策略进行场景的优化绘制,并且对场景部件进行了分类控制   本书面向的读者   本书的内容详细,且几乎涵盖了Android 3D游戏开发所有相关的技术,并向读者介绍了真实项目的开发流程,主要面向以下读者。   Android的初学者   本书详细介绍了OpenGL ES的基础知识,并对Android 3D游戏程序的开发进行了介绍。作为一名Android的初学者,通过本书的学习可以快速全面地掌握Android 3D游戏开发的相关知识,稳健地步入Android 3D游戏开发人员的行列。   有一定Android基础且希望学习Android 3D游戏开发的读者   有一定Android基础的读者通过阅读本书的前半部分便可快速掌握OpenGL ES的基础知识,然后通过7个真实案例的学习迅速掌握Android平台下应用程序的开发。   在职的开发人员
随着智能手机移动嵌入式平台硬件性能的不断提升,3D游戏应用也逐渐普及开来。《Android 3D游戏开发技术宝典:OpenGL ES 2.0》结合作者多年从事3D游戏应用开发的宝贵经验,全面介绍了与Android平台相关的必知必会的基础知识及大型完整3D案例,讲解上由浅入深,循序渐进,起点低、终点高,既适合初学者学习,也适合有一定基础的读者进一步提升之用。另外,由于OpenGL ES 2.0的着色语言通用于各种移动嵌入式平台,因此,《Android 3D游戏开发技术宝典:OpenGL ES 2.0》中与着色器开发相关的60%左右的内容还可供iPhone、Windows Mobile、MeeGoo等平台的开发人员参考。 全书共22章,其中第1章与第2章为Android平台相关的一些基础知识;第3章~第10章介绍了基于OpenGL ES 2.0进行3D应用开发的一些必知必会的基本知识;第11章~第15章介绍了一些高级特效的实现方法;第16章~第17章介绍了3D游戏开发中相关的一些物理、碰撞检测知识以及常用的3D物理引擎JBullet;第19章介绍了3种人机交互的高级技术;第20章~第22章给出了3个完整的大型3D游戏案例,总代码量接近6万行。同时为了便于读者的学习,《Android 3D游戏开发技术宝典:OpenGL ES 2.0》附赠的光盘中包含了书中所有案例的完整源代码,同时给出了最后3个完整大型3D游戏案例的讲解视频,最大限度地帮助读者快速掌握相应的开发技术。 《Android 3D游戏开发技术宝典:OpenGL ES 2.0》适合Android程序员、游戏开发者及Android爱好者学习,也可以作为相关培训学校和大专院校相关专业的教学用书。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值