cocos2d-x v3.17とPhotonを連携する(iOS/Android)

# 概要
掲題の通りです。[photon](https://www.photonengine.com/ja/photon) はC++ SDKも存在しているため、cocos2d-xのv3.17で動かすところまで作成します。

また、Androidではcmakeでビルドすることをゴールにします。

## 動作環境
* cocos2d-x v3.17
* Android NDK r17d
* Mac OSX 10.14
* cmake 3.6
* XCode 10.3
* Photon SDK v4.1.14.0

# photonとは
マルチプレイでのオンライン対戦をさせるためのリアルタイム通信エンジンです。

本家サイトへ行くとこのように記載されてます。
https://www.photonengine.com/ja-JP/Realtime
> インディーかプロのディベロッパーかを問わず、誰でもリアルタイムマルチプレイヤーゲームを開発してグローバルに配信可能です。同期・非同期ゲームプレイを作って、カスタムのWebhookをコーディングしよう。

# SDKを落とす
まずは、PhotonのサイトからSDKを落とします。
https://www.photonengine.com/ja/sdks

今回は v4.1.14.0 を落として以下のように配置しました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/163629/6e03d42f-c45b-b43e-b224-7263418ba2c3.png)

# iOS側の設定
まずはiOS側から設定をします。

## Header Search Pathsの追加
以下のフォルダを `Header Search Paths` に追加します。

* Photon-iOS-Sdk_v4-1-14-0

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/163629/5a453ac4-de1b-4197-4b66-34b201ad2929.png)


## Other Linker Flagsの追加
次に、以下を `Other Linker Flags` に追加します。

* `-lCommon-cpp_$(CONFIGURATION)_$(PLATFORM_NAME)`
* `-lPhoton-cpp_$(CONFIGURATION)_$(PLATFORM_NAME)`
* `-lLoadBalancing-cpp_$(CONFIGURATION)_$(PLATFORM_NAME)`

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/163629/e0362f0f-985d-8c31-4995-12111d341cd2.png)


## Library Search Pathsの追加
最後に、以下のフォルダを `Library Search Paths` に追加します。

* Photon-cpp/lib
* Common-cpp/lib
* LoadBalancing-cpp/lib

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/163629/fe70a488-601c-14be-8110-f5bd6730aa4e.png)

これで完了です。

# Android側の設定
今回Android側はcmakeを使って行います。
CMakeLists.txt を以下に作成します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/163629/f55fafc9-ca23-2597-a3e3-3cd7e0f683cd.png)

```cmake:Photon-AndroidNDK-Sdk_v4-1-14-0/CMakeLists.txt
cmake_minimum_required(VERSION 3.6)

project(photon)

set(PHOTON_ROOT_PATH ${CMAKE_CURRENT_SOURCE_DIR})

message(STATUS "PHOTON_ROOT_PATH:" ${PHOTON_ROOT_PATH})
message(STATUS "CMAKE_BUILD_TYPE:" ${CMAKE_BUILD_TYPE})
message(STATUS "ANDROID_ABI:" ${ANDROID_ABI})

if (${CMAKE_BUILD_TYPE} MATCHES "Debug")
    set(PHOTON_BUILD_TYPE debug)
else()
    set(PHOTON_BUILD_TYPE release)
endif()

message(STATUS "PHOTON_BUILD_TYPE:" ${PHOTON_BUILD_TYPE})
message(STATUS "COMMON_PATH:" ${PHOTON_ROOT_PATH}/Common-cpp/lib/common-cpp-prebuilt/libcommon-cpp-static_${PHOTON_BUILD_TYPE}_android_${ANDROID_ABI}.a)

add_library(photon_common STATIC IMPORTED)
set_target_properties(photon_common PROPERTIES
    IMPORTED_LOCATION "${PHOTON_ROOT_PATH}/Common-cpp/lib/common-cpp-prebuilt/libcommon-cpp-static_${PHOTON_BUILD_TYPE}_android_${ANDROID_ABI}_libc++.a"
    IMPORTED_LINK_INTERFACE_LANGUAGES "CXX"
    LINKER_LANGUAGE "CXX")

add_library(photon STATIC IMPORTED)
set_target_properties(photon PROPERTIES
    IMPORTED_LOCATION "${PHOTON_ROOT_PATH}/Photon-cpp/lib/photon-cpp-prebuilt/libphoton-cpp-static_${PHOTON_BUILD_TYPE}_android_${ANDROID_ABI}_libc++.a"
    LINKER_LANGUAGE "CXX"
    IMPORTED_LINK_INTERFACE_LANGUAGES "CXX"
    )

set(PHOTON_LOAD_SRC ${PHOTON_ROOT_PATH}/LoadBalancing-cpp)

set(PHOTON_HEADER
    ${PHOTON_LOAD_SRC}/inc/AuthenticationValues.h
    ${PHOTON_LOAD_SRC}/inc/Client.h
    ${PHOTON_LOAD_SRC}/inc/FriendInfo.h
    ${PHOTON_LOAD_SRC}/inc/internal/AuthenticationValuesSecretSetter.h
    ${PHOTON_LOAD_SRC}/inc/internal/MutablePlayerFactory.h
    ${PHOTON_LOAD_SRC}/inc/internal/MutableRoomFactory.h
    ${PHOTON_LOAD_SRC}/inc/internal/PlayerFactory.h
    ${PHOTON_LOAD_SRC}/inc/internal/PlayerMovementInformant.h
    ${PHOTON_LOAD_SRC}/inc/internal/PlayerMutableRoomPointerSetter.h
    ${PHOTON_LOAD_SRC}/inc/internal/PlayerPropertiesCacher.h
    ${PHOTON_LOAD_SRC}/inc/internal/PlayerPropertiesUpdateInformant.h
    ${PHOTON_LOAD_SRC}/inc/internal/PuncherClient.h
    ${PHOTON_LOAD_SRC}/inc/internal/RoomFactory.h
    ${PHOTON_LOAD_SRC}/inc/internal/RoomPropertiesCacher.h
    ${PHOTON_LOAD_SRC}/inc/internal/Utils.h
    ${PHOTON_LOAD_SRC}/inc/LobbyStatsRequest.h
    ${PHOTON_LOAD_SRC}/inc/LobbyStatsResponse.h
    ${PHOTON_LOAD_SRC}/inc/MutablePlayer.h
    ${PHOTON_LOAD_SRC}/inc/MutableRoom.h
    ${PHOTON_LOAD_SRC}/inc/Peer.h
    ${PHOTON_LOAD_SRC}/inc/Player.h
    ${PHOTON_LOAD_SRC}/inc/RaiseEventOptions.h
    ${PHOTON_LOAD_SRC}/inc/Room.h
    ${PHOTON_LOAD_SRC}/inc/RoomOptions.h
    ${PHOTON_LOAD_SRC}/inc/WebFlags.h
    )

set(PHOTON_SRC
    ${PHOTON_LOAD_SRC}/src/AuthenticationValues.cpp
    ${PHOTON_LOAD_SRC}/src/Client.cpp
    ${PHOTON_LOAD_SRC}/src/FriendInfo.cpp
    ${PHOTON_LOAD_SRC}/src/internal/AuthenticationValuesSecretSetter.cpp
    ${PHOTON_LOAD_SRC}/src/internal/MutablePlayerFactory.cpp
    ${PHOTON_LOAD_SRC}/src/internal/MutableRoomFactory.cpp
    ${PHOTON_LOAD_SRC}/src/internal/PlayerFactory.cpp
    ${PHOTON_LOAD_SRC}/src/internal/PlayerMovementInformant.cpp
    ${PHOTON_LOAD_SRC}/src/internal/PlayerMutableRoomPointerSetter.cpp
    ${PHOTON_LOAD_SRC}/src/internal/PlayerPropertiesCacher.cpp
    ${PHOTON_LOAD_SRC}/src/internal/PlayerPropertiesUpdateInformant.cpp
    ${PHOTON_LOAD_SRC}/src/internal/PuncherClient.cpp
    ${PHOTON_LOAD_SRC}/src/internal/RoomFactory.cpp
    ${PHOTON_LOAD_SRC}/src/internal/RoomPropertiesCacher.cpp
    ${PHOTON_LOAD_SRC}/src/internal/Utils.cpp
    ${PHOTON_LOAD_SRC}/src/LobbyStatsRequest.cpp
    ${PHOTON_LOAD_SRC}/src/LobbyStatsResponse.cpp
    ${PHOTON_LOAD_SRC}/src/MutablePlayer.cpp
    ${PHOTON_LOAD_SRC}/src/MutableRoom.cpp
    ${PHOTON_LOAD_SRC}/src/Peer.cpp
    ${PHOTON_LOAD_SRC}/src/Player.cpp
    ${PHOTON_LOAD_SRC}/src/RaiseEventOptions.cpp
    ${PHOTON_LOAD_SRC}/src/Room.cpp
    ${PHOTON_LOAD_SRC}/src/RoomOptions.cpp
    ${PHOTON_LOAD_SRC}/src/WebFlags.cpp
    )

list(APPEND PHOTON_SRC ${PHOTON_HEADER})
add_library(photon_loadbalancing SHARED ${PHOTON_SRC})
target_link_libraries(photon_loadbalancing photon photon_common)
target_include_directories(photon_loadbalancing
        PRIVATE ${PHOTON_ROOT_PATH}
)
```
そして、プロジェクトルートのCmakeLists.txtにも追記します。

```cmake
# (省略)

if(NOT ANDROID)
    add_executable(${APP_NAME} ${all_code_files})
else()
    add_library(${APP_NAME} SHARED ${all_code_files})
    # 以下の1行を追加
    add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/vendor/Photon-AndroidNDK-Sdk_v4-1-14-0) 
    add_subdirectory(${COCOS2DX_ROOT_PATH}/cocos/platform/android ${ENGINE_BINARY_PATH}/cocos/platform)
    target_link_libraries(${APP_NAME} -Wl,--whole-archive cpp_android_spec -Wl,--no-whole-archive)
endif()

target_link_libraries(${APP_NAME} cocos2d)
target_link_libraries(${APP_NAME} photon_loadbalancing) #追加
target_include_directories(${APP_NAME}
        PRIVATE Classes
        PRIVATE ${COCOS2DX_ROOT_PATH}/cocos/audio/include/
        PRIVATE vendor/Photon-AndroidNDK-Sdk_v4-1-14-0/ # 追加
)
```

あとは普通にビルドしたら通ると思います。

# サンプルコード
サンプルコードは以下を参考にすると作成できると思います（ぼくもまだ勉強中だからそんな書けない…)

cocos2d-xとPhotonRealTimeの連携
https://qiita.com/aihara_kohei/items/2d87f8e61a4d1cb3fe2c

(バージョンが違うので若干引数とか違ったりしますが、それは公式サイト見ればわかる部分だからそんなハマらないと思う)

# 参考
cocos2d-xとPhotonRealTimeの連携
https://qiita.com/aihara_kohei/items/2d87f8e61a4d1cb3fe2c

Photon C++ Client API
https://doc-api.photonengine.com/en/cpp/current/

Realtimeイントロ
https://doc.photonengine.com/ja-jp/realtime/current/getting-started/realtime-intro