GamePlay3D 集成 Android、项目源码分析

2020-03-06  本文已影响0人  Lucky胡

本项目的所有代码开源地址:
https://github.com/Hujunjob/GamePlay

将Gameplay源代码拉取下来:
https://github.com/gameplay3d/GamePlay

gameplay :存放了引擎所需的代码
samples : 存放了各种实例代码
tools : 提供了工具encoder转换工具和luagen

但是直接拉取下来的代码,可以在XCode上跑起来,有一些小bug,根据错误提示可以修改,完成后可以在iOS上跑起来。

如何集成到Android系统上跑起来呢?
可以参考最上面项目里的,成功在当前最新的Android环境下跑起来了。

项目分析

利用CMake搭建环境。
cpp下的CMakeLists作为主编译文件,引入gameplay和samples作为子编译部分。

# gameplay library
add_subdirectory(gameplay)

# gameplay samples
add_subdirectory(samples)

gameplay文件:
gameplay里面存放了所有的引擎相关的代码和资源,cmake里将其打包到名为"gameplay"的静态库中。

samples文件
里面存放了很多个实例项目,比如broswer项目。
samples里的CMake文件里,将gameplay静态库、需要的外部依赖external-deps、各种其他依赖库GLESv3/android等添加到依赖,供实例项目使用。

samplers的子目录browser
是个实例项目,其cmake就将其cpp/h文件打包为动态库:sample-browser.so,
将samples的cmake里的依赖链接到sample-browser.so上。

之后在项目中中引入该动态库sample-browser.so就能调用了。

源码分析

demo使用的是NativeActivity,即大部分代码用native层写,而不是用java写的。
NativeActivity里会通过jni调用底层的C++代码,调用的入口是ANativeActivity_onCreate方法。

void ANativeActivity_onCreate(ANativeActivity* activity,
        void* savedState, size_t savedStateSize)

方法里的ANativeActivity包含了activity的各种回调,包括了activity的生命周期、窗口变换等回调。可以在native层实现这些回调。
Google的NDK实现的NativeActivity的Demo里提供了一个示例,可以直接用。
android_native_app_glue.cpp
android_native_app_glue.h

使用了android_native_app_glue后,我们可以直接在生命周期的回调里(ANativeActivity_onCreate/onStart/onResume等)写入自己的逻辑。

本项目里,我们直接使用android_native_app_glue里自带的生命周期代码,不需要添加额外的逻辑。

我们需要实现android_main方法,这里作为程序的入口。方法的实现在gameplay-main-android.cpp里。

void android_main(struct android_app* state)
{
    // Android specific : Dummy function that needs to be called to 
    // ensure that the native activity works properly behind the scenes.
    app_dummy();
    
    __state = state;
    Game* game = Game::getInstance();
    Platform* platform = Platform::create(game);
    GP_ASSERT(platform);
    platform->enterMessagePump();
    delete platform;
    
    // Android specific : the process needs to exit to trigger
    // cleanup of global and static resources (such as the game).
    exit(0);
}

这里面保存了android_app,里面有各种application相关的句柄,包括activity/Alooper/ANativeWindow/activityState/thread等等。

这里出现了两个gameplay框架的重要类:Game和Platform。

/**
 * Defines the base class your game will extend for game initialization, logic and platform delegates.
 *
 * This represents a running cross-platform game application and provides an abstraction
 * to most typical platform functionality and events.
 *
 * @see http://gameplay3d.github.io/GamePlay/docs/file-formats.html#wiki-Game_Config
 */
class Game{}

Game类是所有游戏场景的基类,需要实现game的生命周期相关的几个方法。

#include "gameplay.h"
using namespace gameplay;

class MyGame : public Game
{
//游戏场景初始化时回调,这里面可以加载资源等初始化操作
    void initialize();
//游戏场景结束时回调,销毁资源
    void finalize();
//update和render都是每次刷新时回调
    void update(float elapsedTime);
    void render(float elapsedTime);
};

本项目中,实现类是SamplesGame.cpp。

Platform类是平台相关的类,里面保存了game实例。不同的平台有不同的实现,Android、iOS、PC、Mac有4个实现。初始化和使用方法为:

    Platform* platform = Platform::create(game);
    GP_ASSERT(platform);
    platform->enterMessagePump();

分析SamplesGame.cpp

是Game类的子类,用来作为本项目的主场景。
此场景里可以实现多个场景的切换,但是只有一个Game。那如何实现呢?
项目写了个基类Sample,伪造了一个Game,可以进入、退出、刷新等操作。在Game场景里的initize/finalize/render/update里,调用Sample的实现类的相应方法,实现这些子类场景的渲染。

分析几个重要部分:

    /**
     * Adds a sample.
     * 
     */
    static void addSample(const char* category, const char* title, void* func, unsigned int order);
    /**
     * Function pointer type that is used to create a SampleGame.
    *  这个部分非常有趣。这个Game有多个Sample场景,但是并不是一开始就实现实例,采用保存了Sample子类的名字,
     */
    typedef void*(*SampleGameCreatePtr)();

上一篇下一篇

猜你喜欢

热点阅读