本项目的所有代码开源地址:
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)();
网友评论