Android game development tools upgraded

Android game development tools upgraded

Different hardware manufacturers have brought devices of different sizes and experiences to Android users. Therefore, we have been working hard to help developers present games to as many Android devices as possible and make the development process more efficient and easy. This article will introduce you to many new Android game development tools and game debugging, packaging and distribution techniques.

More efficient game development tools

To do one's work well, one must first sharpen his tools. We have made a lot of optimizations for development tools. Game engines are mainly written in C and C++, and most Android APIs are designed to be called by managed code such as Kotlin. Therefore, we have implemented the ability to debug C/C++ code and managed code at the same time in Android Studio, so that you can set breakpoints in Kotlin and C/C++ code respectively, as shown in the figure below, and then track the execution in the two programming environments respectively. You can even jump between managed code and native code to observe the execution.

△ Demonstration of debugging managed code and C/C++ simultaneously through Android Studio

On the other hand, Android Studio can speed up your code writing through automatic code completion, and also supports you to quickly insert JNI function prototypes to program in two different environments. In addition, Cmake and Gradle are used in the build process, which allows you to better utilize portable builds.

For developers writing C/C++ cross-platform games with Visual Studio on Microsoft Windows operating systems, we provide an Android Game Development Extension (AGDE) in the Android Game Development Kit (Android Game Development Kit) launched in July 2021. It can further simplify your development process and help you build directly for Android devices in the Visual Studio environment with a series of debuggers and performance analysis tools that support C and C++. And AGDE can be easily integrated with a variety of build systems, and can also be easily integrated into your workflow using Unreal Engine, so that you don’t need to use a separate set of tools and build systems for desktop devices, game consoles, and Android devices.

The process of configuring AGDE is also very simple. After the extension is installed, switch to your Visual Studio project and add the Android APK template. You can access various common Android development tools in the toolbar, such as SDK and NDK Manager, Virtual Device Manager, Device File Manager, Logcat, and Performance Analyzer, as shown below:

Android toolbar in Visual Studio

After configuring the Android build target in the project, you only need to operate it like developing a standard desktop Visual Studio target. All operations related to building, deploying, and debugging are the same. You can easily set breakpoints in the debugger, switch to the disassembled code to view the values ​​in registers and memory blocks, and view concurrency through parallel stacks.

Debugging Android build targets using Visual Studio

In addition, you can not only search log output and filter by type in the dedicated Logcat panel, but also quickly access the independent CPU and memory analyzers originally provided in Android Studio through AGDE, as shown in the right figure below:

△ Searchable Logcat panel (left); separate CPU and memory analyzers (right)

We designed a new interface for these tools, enhanced several features and supported native memory sampling. The combination of Android Studio and the Android Game Development Extension provides you with a rich set of tools to develop games efficiently.

Android Game Development Kit

As the saying goes, a good horse needs a good saddle. Having these handy tools is not enough, we also need to integrate these tools into Android's managed code API. To this end, we provide a new C/C++ library for you to use in the Android Game Development Kit (AGDK).

GameActivity

GameActivity is almost a native implementation (C/C++) of the Android standard activity. It works well with the Jetpack library and various Android interface libraries. This allows you to write game loops entirely in C/C++ while taking advantage of various libraries built on top of Jetpack. In addition, GameActivity will be rendered into a SurfaceView, so you can easily mix Android interface elements, such as WebView, MapView, and views required by various services such as the advertising SDK. In this way, you only need to integrate the game loop logic in managed code through a simple class that loads the C/C++ game module. The relevant code is as follows:

 < ? xml version = "1.0" encoding = "utf-8" ? >
< androidx . constraintlayout . widget . ConstraintLayout
xmlns : android = "http://schemas.android.com/apk/res/android"
android : id = "@+id/container"
android : layout_width = "match_parent"
android : layout_height = "match_parent" >
< EditText
android : id = "@+id/username"
android : layout_width = "0dp"
android : layout_height = "wrap_content" >

△ The view to be displayed

 public class MyGameActivity extends GameActivity {
static {
// Load your game library
System . loadLibrary ( "game" );
}
}

Minimal managed code

You need to modify the meta-data in the AndroidManifest.xml file to tell GameActivity which library to start the game loop from.

 activity android : name = ".MyGameActivity" android : label = "@string/app_name" >
< meta - data android : name = "android.app.lib_name" android : value = "game" / >

△ Modify AndroidManifest.xml

GameActivity provides you with several native callback methods that match Android's lifecycle events. These event callbacks can be easily integrated into your game loop.

△ Callback method corresponding to Android life cycle

Below is a very simple code, we will show you an example based on the native_app_glue library. The native_app_glue library provides an unusual execution mode.

 void android_main ( struct android_app * app ) {
// Your game engine
NativeEngine * engine = new NativeEngine ( app );
// Your game loop
engine- > GameLoop () ;
delete engine ;
}

△ Example based on native_app_glue

Here, the android_main() function will be called in a new thread that is different from the main thread. You can get Android lifecycle events from the ALooper associated with the thread, like this:

 while ( 1 ) {
int events ;
struct android_poll_source * source ;
// If no animation occurs, block the process until an event is captured
while (( ALooper_pollAll ( IsAnimating () ? 0 : - 1 , Null , & events , ( void ** ) & source )) >= 0 ) {
// Handle the event
if ( source != NULL ) {
source - > process ( mApp , source );
}
}
}

△ Use ALooper to obtain and handle Android life cycle events

In addition to capturing lifecycle events, you can also use this method to monitor file descriptors.

Frame Pacing API

The frame pacing API can help developers solve the delay caused by shorter game frames and avoid the delay caused by longer game frames. If the device supports the refresh rate selection function, it can provide players with more flexible and smooth display effects.

After implementing GameActivity, you can choose to use OpenGL/ES or Vulkan to render content to the surface. No matter which API you choose, the Android Frame Pacing library will help you properly handle the rendering process. It will synchronize the game logic and rendering loop with the Android display subsystem and underlying display-related hardware to achieve smoother rendering.

Oboe API

△ Oboe API

A well-made game cannot do without excellent sound effects, which is also the capability provided by Oboe audio library. You can use its API on Android 4.1 and higher systems. On devices with API level 27, Oboe will use AAudio to coordinate the hardware and software on the device as much as possible to achieve the lowest audio latency. For devices with lower versions, Oboe will use OpenSL ES to ensure compatibility as much as possible.

While Oboe introduces many new features such as resampling, format conversion, high-performance channel number conversion, etc., it also has built-in solutions to some known audio problems.

Game Input

The Android Game Development Kit also provides two libraries that can interoperate with GameActivity to handle soft keyboard and handle input signals in the game.

Game text input

GameTextInput does a lot of complex work at the bottom level. It connects the Android system's soft keyboard to your in-game text editor, and also includes operations for showing and hiding the soft keyboard.

△ Text input logic in the game

If you use this library with a GameActivity, the system will automatically configure this, whether or not you use native_app_glue. See the code below, the GameTextInput library will pass the input state to your game so that your text editor can correctly reflect the state of the IME.

 /**
* Get the last received text input status
*/
void GameActivity_getTextInputState (
GameActivity * activity ,
GameTextInputGetStateCallback callback ,
void * context );

△ Modify the AndroidManifest.xml file

Gamepad Input

Another common input device in games is a game controller. You can take advantage of a physical game controller by using the Game Controller library. This library notifies your game when a controller is connected or disconnected from the device, and provides information about the button layout, directional axes, and other key controller metadata.

The Game Controller library is also encapsulated at the bottom level, allowing you to seamlessly connect to a variety of handles without complex implementation, and even accept the mouse as an input device.

Support big screen games

Enjoy gaming on your Smart TV

If your game can be controlled with the D-pad and runs properly in landscape mode, it will run on many TV devices.

To support running on Smart TV, you need to make some changes to the AndroidManifest.xml file:

 // You need to declare these permissions in multiple uses-feature tags:

android . hardware . touchscreen
android . hardware . faketouch
android . hardware . telephony
android . hardware . camera
android . hardware . nfc
android . hardware . location . gps
android . hardware . microphone
android . hardware . sensor

// If necessary, add android.required="false"

△ Modify the AndroidManifest.xml file

You need to declare these permissions in the manifest as non-essential, i.e. required="false". This is because many of the permissions and functions you mentioned in the AndroidManifest are not necessary, and smart TVs often do not support these functions, such as touch screens, cameras, accelerometers, etc. You can declare that the game supports using the remote control as a handle by adding the following code:

 < uses - feature
android : name = "android.hardware.gamepad"
android : required = "false" / >

△ Declare that the game supports using a remote controller as a controller

If necessary, you can declare android:required="true" to indicate that the TV needs to check whether the remote control is available before starting the application.

Running on Chrome OS

Chrome OS has now become the second largest desktop operating system and has a large number of gamers. It can run Android games directly and has a built-in Google Play Store. Players can play games that support horizontal screen on devices running Chrome OS. Most devices provide a touch screen for players to operate. For some devices without a touch screen, touch screen operations are usually simulated through a mouse or trackpad. Of course, games that directly support mouse and keyboard input often give players a better gaming experience.

You can capture mouse or trackpad events in your game using code similar to the following:

 fun onClick ( view : View ) {
view.requestPointerCapture ( )
}

override fun onCapturedPointerEvent ( motionEvent : MotionEvent ): Boolean {
// Captured pointer events often provide relative positions
horizontal valOffset : Float = motionEvent . x
val verticalOffset : Float = motionEvent . y
return true
}

△ Capture mouse or touchpad event code example

You can use the above code to capture the mouse or trackpad cursor on Android with API level 26 or higher for more precise control. For example, in most scenarios, you may want to keep the virtual controls that interact with the user at the appropriate relative size even on larger screens. This requires you to take different screen sizes and screen display densities into account and calculate the size of the virtual controls. According to the following code, you can get the display metrics of the current display, then get the density and pixels per inch of the X and Y axes, and then calculate the scaling ratio of the virtual controls.

 val dm = resources . displayMetrics
// For precise scaling
val xdpi = dm . xdpi
val ydpi = dm . ydpi

// Calculate DPI using scaling factor
val densityDpi = dm . density * 160.0 f
val scaledDensityDpi = dm . scaledDensity * 160.0 f

△ Get the DisplayMetrics of the screen in managed code

You can also use dm.density and dm.scaledDensity to get the approximate scaling factor, where 1.0 corresponds to a DPI value of 160. ScaleDensity is used to scale the fonts of Android apps based on user preferences, so if your game supports this feature, it will definitely give users a better experience.

Sometimes, for performance reasons, you may want to set an upper limit on the display density. If you wish, you can use surfaceHolder.setFixedSize to automatically and economically scale the interface. This not only saves memory (RAM), but also reduces the number of pixels that need to be colored, further saving power and reducing heat. Refer to the following code for details:

 var width = mSurfaceView .width
var height = mSurfaceView . height
val dm = resources . displayMetrics

if ( dm . density > maxDensity ) {
val newScaleFactor = maxDensity / dm .density
if ( newScaleFactor != scaleFactor ) {
width = ( newScaleFactor * width ). toInt ()
height = ( newScaleFactor * height ). toInt ()
mSurfaceView . holder . setFixedSize ( width , height )
}
}

△ Use surfaceHolder.setFixedSize to scale the interface

You can also use C/C++ code to automatically implement scaling, such as the following code:

 int32_t ret = ANativeWindow_setBuffersGeometry (
window , width , height , 0 );

△ Using C/C++ to implement automatic scaling

Because touch events always occur in screen coordinates, whether you implement it in managed code or C/C++, you will need to adjust touch events to match the new interface.

Different game engines have different back buffer scaling methods. As shown in the figure below, Unity, Unreal Engine, and Godot have obvious differences in this regard.

Comparison of different game engine methods for scaling the back buffer

Unity can scale the backbuffer in a variety of ways. You can adjust the maximum DPI value in the Android Player settings: first select Fixed DPI, and drag to select an appropriate DPI threshold. Unreal Engine 4 supports mobile content scaling factors, which provide several additional options beyond the device's native resolution. Godot allows you to scale the rendered content in a variety of ways, and you can use the base window width to avoid rendering at too high a DPI. In addition, Godot also supports the screen DPI value through scripting.

If you need your game to support Chrome OS devices running on more architectures, you will also need to add more ABI items to the build script:

 externalNativeBuild {
cmake {
abiFilters 'armeabi-v7a' , 'arm64-v8a' , 'x86' , 'x86_64'
}
}

△ Add x86/x86_64 to the Gradle build script

This is because many devices running Chrome OS use x86 or x86_64 architecture. If you use a game engine to develop Android games, you can view the currently known engine versions that support x86/x86_64 from the figure:

△ Example of an engine version that supports x86/x86_64

When you are ready to distribute your game on the Google Play Store, simply select these additional architectures and upload them to the same Play store listing. This unified distribution approach will greatly simplify the process of distributing your game.

Android App Bundle is a file format designed specifically for the Android platform. It allows you to include binary library files of various architectures in the same package without increasing the file size. Google Play will then automatically generate a dedicated APK file for each platform for distribution and download.

Handling larger materials

Distribute game resources using PAD

△ Use PAD format based on Android App Bundle

Many games need to load a huge amount of resources and material files, such as 3D models, textures, sound effects, video cutscenes, etc. Play Asset Delivery (PAD) is an extension format for Android App Bundle. With it, you can publish a single artifact to the Google Play Store, which contains both the code and resource parts of the game.

Using Play Asset Delivery

The PAD format has been extensively improved and optimized to provide you with a more efficient game distribution experience. When you use PAD to deliver game resources, it ensures that the code and resource versions are consistent, so that users can get the latest binaries and resources as soon as they open the game, without having to wait for resource updates. And Google Play's automatic update feature can also help you automatically handle incremental updates, allowing users to directly download the updated parts of the existing game version without having to re-download the entire game. Another benefit of using PAD is the optimization of content downloads, which means that users can load the necessary resources when they first run the game, and then continue to load on demand when new content is needed.

Using texture compression to differentiate between devices

You can use texture compression formats to divide these contents, and Google Play will help you select the most appropriate textures to distribute to different devices, thus ensuring that your game can achieve the highest rendering efficiency and the best rendering effect on most devices.

△ Use texture compression to divide content distribution

Use device category

△ Use device categories to distinguish

We are currently working on implementing the function of targeted distribution by device category, so that you only need to provide the resource files required by different categories in each set of resources. You can divide according to information such as RAM size, device model, and hardware characteristics such as physical screen size, so as to cover a larger group of devices with smaller installation packages.

Summarize

Improving the efficiency of Android game development is not only the expectation of every developer, but also our unremitting ideal over the years. Through this article, we share some tools and techniques for efficient Android game development: the new Android game development extensions, Android GPU inspector, GameActivity, soft keyboard, game controller and high-performance audio library and Android performance tuning tools added to the Android Game Development Kit; in addition, we show you the powerful ability of the Play Asset Delivery format in distributing game resources. I hope these contents can deepen your understanding of Android development and help you develop popular game works!

<<:  Android 14 first exposure: flip the cake

>>:  A generation of legendary phones is finally abandoned? iOS 16 may remove support for iPhone 6S/SE

Recommend

80% of American chestnuts disappeared, the culprit was a chestnut epidemic

Produced by: Science Popularization China Author:...

You can pause the voice and read the text! WeChat new function experience

WeChat, which used to be updated frequently, has ...

WeChat public account project, you can earn 3000+ a month by copying and pasting

Everyone knows that due to the large population b...

Is plant-based meat healthier than animal-based meat?

Plant-based meats are slightly inferior to animal...

Can Xiaomi become a Fortune 500 company?

This article is reprinted from Fortune Chinese we...

After being cheated, it became a priceless treasure

Today's protagonist is not an ordinary wardro...

Why do some glues fall off easily, while others are as good as welding?

Why can glue be used to stick things together? Of...

How can operations improve APP retention rate? ?

With the rapid development of mobile Internet , p...

Information flow advertising: characteristics and trends!

Feed ads are ads that are inserted into the updat...

How to use mind mapping in product operations?

Mind mapping, as a tool, is now used in all walks...

Kuaishou, with 500 million users: Who is the marginalized party?

After 6 years of establishment, the number of use...

Review! How to operate an active and high-quality community?

The author of this article has conducted a detail...