cocos2d-xでnendアイコン広告を表示させるサンプルゲーム (Android編)

Android

現時点で最新の、
cocos2d-x v2.2.2ベース+Nend SDK for Android 2.3.3で説明します。
特にcocos2d-xは3.0以降で大幅に仕様変更予定だそうですが、
とりあえず現状最新の安定版という事で2.2.2を選択しました。

サンプルのソースコード(iOS/Android共通)ありますので、
コードだけ欲しい方は下の方のgithubへのリンクからどうぞ。

この記事ではcocos2d-xのプロジェクト作成から書いております。
広告表示に関する箇所は、中段の「 Icon広告表示制御コード追加」以降です。

以下、Cocos2d-x,NendSDKのダウンロード、ビルド環境作成が済んでいる人は読み飛ばしてOK
ーーー【事前準備】ここから

Nend SDKのダウンロードは、Nend登録後、アプリを登録した後に行えます。
(アプリ公開前でもGooglePlayの予定URLを登録で大丈夫です)

1.Cocos2d-x v2.2.2 をダウンロード
Download Cocos2d-x Cocos2d-html5 CocoStudio | Cocos2d-x
↑からCocos2d-xのv2.2.2を選択

2.Nend新規登録
nend.net(ネンド)スマートフォン広告で日本最大級の運用型アドネットワーク(スマホweb広告/アプリ広告/アイコン広告対応)
↑からアプリ・メディアパートナー様を選択、登録。

3.GooglePlay登録用のアプリパッケージ名を作成しておく
Nendにアプリを登録する時に必要。まだ登録前でも大丈夫なので、登録予定のものを考えておく。
例) com.maxigundan.App.BikeKawasakiBike

4.Nendにログインし、広告枠の管理−サイト/アプリ−新規サイト/アプリの作成
上のパッケージ名含む、必要な情報を申請、登録。

5.広告枠の管理−広告枠
登録されている項目に、”SDK“があると思いますので、そこからDL。

※この記事を書いた時の仕様です。
使い方が分からない場合、サポート様に問い合わせてみてください
丁寧に教えて頂けると思います。

6.libcocos2dx.jarを作成
cocos2d-xでゲーム作成するのに、最初に一度だけ必要になる。

メニューのFile-Import選択、General-Existing Projects into Workspaceで
Select root directoryのBrowseボタンから、
~/cocos2d-x-2.2.2/cocos2dx/ のフォルダを指定。
自動的にいくつかプロジェクトが認識されるので、
“libcocos2dx”のみを選択、Finishを押すと環境が読み込まれる。
Build Project から、ライブラリを作成する。
binフォルダにlibcocos2dx.jarができていれば正常終了

【プロジェクト作成手順】
1.Cocos2d-xプロジェクト作成

作成するアプリ名は”TestGameNendIconAd”、パッケージは”com.MyCompany.TestApp”
フォルダは”~/cocos2d-x-2.2.2/”としています。
各自、自分の環境のパスに読み替えてください。

ターミナルを起動し、以下のコマンド実行

cd ~/cocos2d-x-2.2.2/tools/project-creator/
python create_project.py -project TestGameNendIconAd -package com.MyCompany.TestApp -language cpp

正常に各プラットフォーム全部Done!が表示されればOK
(失敗する場合は大抵パーミッション周りかpythonバージョンかpythonパス関連)

2.Nend SDKライブラリのコピー

cocos2d-x-2.2.2/projects/TestGameNendIconAd/ というフォルダができている。
その中に色々なプラットフォームのプロジェクトができているので、
proj.android 内に “libs” フォルダを作成して、
Nend SDKの環境内にある、nendSDK-2.3.2.jar をlibsフォルダにコピーする

3.Native(cpp)のビルド

Eclipse用のプロジェクトに組み込まれているので
Eclipseからできるみたいだけどよく分からないので手動で行った。

手動で./build_native.shを実行

    cd ~/cocos2d-x-2.2.2/projects/TestGameNendIconAd/proj.android
./build_native.sh

ビルドが走るのでしばらく待つ。

エラーが発生せず、

    Install        : libcocos2dcpp.so => libs/armeabi/libcocos2dcpp.so
make: Leaving directory(略

まで終わっていればNative側は正常終了している。

4. Eclipse起動、環境インポート(最初の1回のみ必要)

メニューのFile-Import選択、General-Existing Projects into Workspaceで
Select root directoryのBrowseボタンから、
~/cocos2d-x-2.2.2/projects/TestGameNendIconAd/proj.android のフォルダを指定。
自動的にTestGameNendIconAdプロジェクト環境が認識されるので、
Finishを押すと環境が読み込まれる。

5. ビルド設定

./build_native.sh を手動で実行しているので、Eclipseからはビルドしないよう、
Propatires – Builders から “CDT Builder”を外しておく。

ーーー【事前準備・組み込み手順】ここまで

以上で、サンプルのHelloworldが動く環境と、
Nendアイコンを表示できる環境が整いました。

Icon広告表示制御コード追加

使い回しができるように、広告表示専用のstatic Classを作成し、
さらに、cppファイルから制御するために、JNIを作成します。

JniHelperを使う方法は、おかひろさんの記事、zaruさんのコードを参考にさせていただきました。
Cocos2d-x上からObjective-C/Javaのコードを実行する – おかひろの雑記
zaru/Cocos2DX_AdStir · GitHub

static Classは、Activity起動時にそのActivityを登録する方法で保持し、
後々cppから呼ばれた時に、保持していたActivityオブジェクトを使って、
runOnUiThread()を使って制御する仕組みです。

com/MyCompany/NativeIF/IconAdMgr.java
・Activity登録用メソッド
ここでついでにアイコン周りの初期化もしています。
TestGameNendIconAdのonCreate()の中から、
IconAdMgr.setActivity(this); のように呼び出します。

	public static void setActivity(Activity activity) {
mActivity = activity;
mDensity = activity.getResources().getDisplayMetrics().density;
_iconAdLayout = new RelativeLayout(mActivity);
RelativeLayout.LayoutParams rootParams = new RelativeLayout.LayoutParams(FP, FP);
rootParams.addRule(RelativeLayout.ALIGN_PARENT_TOP);
mActivity.addContentView(_iconAdLayout, rootParams);
initIconAdParameters();
}

・アイコンパラメータ初期化
IconViewの一つ一つを制御するのは非常に面倒で、
NendAdIconLayoutを使う方が格段に楽なのですが、
せっかく作りましたのでこれをサンプルコードに含んでいます。

	//initialize global icon params
private static void initIconAdParameters()
{
if(NEND_ICON_NUMS>4) {
ICNAD_SPACE = false;
ICNAD_WIDTH = 50;
ICNAD_HEIGHT = 50;
ICNAD_SHOW_TITLE = false;
}else{
ICNAD_SPACE = true;
ICNAD_WIDTH = 75;
ICNAD_HEIGHT = 75;
ICNAD_SHOW_TITLE = true;
}
//手動でIconViewを設定しておく
//(細かい配置にこだわらなければ、絶対にNendAdIconLayout使った方が楽!
// Nend SDK同梱サンプルソースやalbatrusさんのページが参考になります)
mIconViewArray = new NendAdIconView[NEND_ICON_NUMS];	//alloc array
for(int i=0; i<NEND_ICON_NUMS; i++) {
mIconViewArray[i] = new NendAdIconView(mActivity);	//initialize
mIconViewArray[i].setTitleColor(Color.WHITE);
mIconViewArray[i].setIconSpaceEnabled(ICNAD_SPACE);
mIconViewArray[i].setTitleVisible(ICNAD_SHOW_TITLE);
if(NEND_ICON_NUMS>4) {
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB){
//Honeycomb以降はsetScaleが使えるのでViewごと縮小する(それ以外は諦める)
float scaleX = (float)ICNAD_WIDTH/(float)NEND_DEFAULT_SIZE;
float scaleY = (float)ICNAD_HEIGHT/(float)NEND_DEFAULT_SIZE;
mIconViewArray[i].setScaleX(scaleX);
mIconViewArray[i].setScaleY(scaleY);
}
}
}
// get resolution
WindowManager wm = (WindowManager) mActivity.getSystemService(Context.WINDOW_SERVICE);
Display disp = wm.getDefaultDisplay();
// 手動で各アイコンのマージン計算する
mIconDispWid = ICNAD_WIDTH*mDensity;
mIconOffset = ((float)(disp.getWidth()/NEND_ICON_NUMS)- mIconDispWid)/2;
mIconMargin = (float)(disp.getWidth()/NEND_ICON_NUMS) - mIconDispWid;
}

・アイコン広告の作成・表示

	// ---------------- For Native Methods ---------------
// C2dxのNativeから呼ばれるもの
public static void createView(float yPos)
{
if(_iconAdLoader!=null)
return;
final float mYPos = yPos;
mActivity.runOnUiThread(new Runnable() {
@Override
public void run() {
DbgLogD(TAG, "createView:"+mYPos);
_iconAdLoader = new NendAdIconLoader(mActivity, ICON_SPOT_ID, ICON_API_KEY);
//一個一個追加していく
for(int i=0; i<NEND_ICON_NUMS; i++) {
//位置調整は手動
NendAdIconView iconView = mIconViewArray[i]; //temp obj pointer
RelativeLayout.LayoutParams iconParam = new RelativeLayout.LayoutParams(WC, WC);
iconParam.setMargins((int)mIconOffset+(int)(mIconMargin+mIconDispWid)*i, (int)mYPos, 0, 0);
iconView.setLayoutParams(iconParam);
_iconAdLayout.addView(iconView);
_iconAdLoader.addIconView(iconView);
}
_iconAdLoader.loadAd();
}
});
}

・アイコン位置変更

    public static void locateView(float yPos)
{
if(_iconAdLoader==null)
return;
final float mYPos = yPos;
mActivity.runOnUiThread(new Runnable() {
@Override
public void run() {
DbgLogD(TAG, "locateView:"+mYPos);
//一個一個変更
for(int i=0; i<NEND_ICON_NUMS; i++) {
NendAdIconView iconView = mIconViewArray[i]; //temp obj pointer
RelativeLayout.LayoutParams iconParam = new RelativeLayout.LayoutParams(WC, WC);
iconParam.setMargins((int)mIconOffset+(int)(mIconMargin+mIconDispWid)*i, (int)mYPos, 0, 0);
iconView.setLayoutParams(iconParam);
}
}
});
}

・アイコン広告の表示・解放
VisibleをGONEでも良いかもしれないがなんとなく・・・

    public static void releaseView()
{
if(_iconAdLoader==null)
return;
mActivity.runOnUiThread(new Runnable() {
@Override
public void run() {
DbgLogD(TAG, "releaseView");
//IconView解放
_iconAdLayout.removeAllViews();
_iconAdLoader.pause();
_iconAdLoader = null;
}
});
}
C++コードから呼び出すためのJNIとC++ラッパー追加

cppファイルの中身は同じような物が長くなりそうなので割愛します・・・
下側のgithub内に全く同じコードがありますので、
興味がある方はご覧ください。

IconAdNative.h
ここで定義されているメソッドを他のコードから呼び出す。

namespace Cocos2dExt {
class IconAdNative
{
public:
static void createView(float yPos);
static void locateView(float yPos);
static void releaseView();
static void pauseView();
static void resumeView();
static void refreshView();
};
}

IconAdNative.cpp
完全にただのラッパー

namespace Cocos2dExt
{
void IconAdNative::createView(float yPos)
{
IconAdNative_createViewJNI(yPos);
}
void IconAdNative::locateView(float yPos)
{
IconAdNative_locateViewJNI(yPos);
}
void IconAdNative::releaseView()
{
IconAdNative_releaseViewJNI();
}
void IconAdNative::pauseView()
{
IconAdNative_pauseViewJNI();
}
void IconAdNative::resumeView()
{
IconAdNative_resumeViewJNI();
}
void IconAdNative::refreshView()
{
IconAdNative_refreshViewJNI();
}
}

IconAdNativeJni.h

extern "C"
{
extern void IconAdNative_createViewJNI(float yPos);
extern void IconAdNative_locateViewJNI(float yPos);
extern void IconAdNative_releaseViewJNI();
extern void IconAdNative_pauseViewJNI();
extern void IconAdNative_resumeViewJNI();
extern void IconAdNative_refreshViewJNI();
}

IconAdNativeJni.cpp
createのところだけ

	void IconAdNative_createViewJNI(float yPos)
{
JniMethodInfo methodInfo;
if (!getStaticMethodInfo(methodInfo, ADMANAGER_CLASS, "createView", "(F)V"))
{
return;
}
methodInfo.env->CallStaticVoidMethod(methodInfo.classID, methodInfo.methodID, (jfloat)yPos);
methodInfo.env->DeleteLocalRef(methodInfo.classID);
}

これで、”IconAdNative.h”をcppからincludeして、
Cocos2dExt::IconAdNative::createView(100);
と実行すると、上から100pixelの所からアイコン広告が表示される。
みたいなのが実現できます。

【アレンジ】
・消去前にアイコン位置を画面外に
なんかのバグで万が一アイコンが消えなかった事を考えて、
アイコン位置を画面外にずらしてから消去処理をすると、
万が一の時のユーザークレームを防げるかも

・表示前にアイコン位置を画面外に
広告表示まで、ロード時間がどうしてもかかるため、
表示するタイミングより早い段階で
アイコン位置を画面外にして「先読み」をしておく。
そして、実際の表示したいタイミングではアイコン位置をずらすだけ。
すると、ロード時間無く表示されているように見える。

サンプルコード

よくある使い方として、上記のコードを使った、
サンプルのゲームを作りました。
1〜5の何が出るか当てるだけの数当てゲームです。
超能力の調査みたいな感じで。

下のgithubからどうぞ。

MaxiGundan/TestGameNendIconAd · GitHub

ページ右メニューの”Download ZIP”から、一式ZIPでダウンロードできます。

組み込み手順、ビルド手順は、README.md(テキストファイル)に書いてありますので、
一つ一つ、実行してみて下さい!

以下のようなゲームができていればOK!(下はiOSのもの)
f:id:maxigundan:20140125001822p:plain:w240f:id:maxigundan:20140125001639p:plain:w240

以上、つらつら書きましたが、我流ですので、
こうした方がいいよ!これダメだよ!っていうのがあれば、
教えて頂けると大変うれしいですm(_ _)m

ではでは。

ブログだけ見て帰るん?(´・ω・`)
↓いつでもフォローしてくれていいねんで?
twitter: @maxigundan
facebook: マキシぐんだん | Facebook

コメント

タイトルとURLをコピーしました