カテゴリー別アーカイブ: めざせ1万PV/day

cocos2d-x 3.17 Android に Admob SDK を組み込む

 

・ AdMobのライブラリをバンドル
  - app/build.gradle に以下を追加
dependencies {
    ...
    compile 'com.google.android.gms:play-services-ads:15.0.1'
}
・ パーミッション設定
  - app/マニュフェストに以下を追加
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
・ メタデータ、広告アクティビティの設定
  - AndroidManifest.xmlのapplicationタグに以下を追加
<meta-data android:name="com.google.android.gms.version"
           android:value="@integer/google_play_services_version" />
 
<activity
    android:name="com.google.android.gms.ads.AdActivity"
    android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|uiMode|screenSize|smallestScreenSize"
    android:theme="@android:style/Theme.Translucent" />
    
・ バナー広告を作成する処理
  - 以下を AppActivity.java に追加
import android.widget.LinearLayout;
import android.view.Gravity;
import com.google.android.gms.ads.AdRequest;
import com.google.android.gms.ads.AdSize;
import com.google.android.gms.ads.AdView;
.....
public class AppActivity extends Cocos2dxActivity {
    private AdView mAdView;  //  バナー広告
    .....
        // DO OTHER INITIALIZATION BELOW
        // 広告ビューのレイアウトパラメータを作成
        LinearLayout.LayoutParams adParams = new LinearLayout.LayoutParams(
                LinearLayout.LayoutParams.WRAP_CONTENT,
                LinearLayout.LayoutParams.WRAP_CONTENT);
 
        // 表示位置を下部中央に設定
        adParams.gravity = (Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL);
 
        // 広告ビューを作成
        mAdView = new AdView(this);
        mAdView.setAdSize(AdSize.BANNER);
        mAdView.setAdUnitId("ca-app-pub-XXXXXXXXXX/XXXXX");
        //mAdView.setAdUnitId(getString(R.string.banner_ad_unit_id));
 
        // テストデバイスのIDを指定してAdRequestを作成
        AdRequest adRequest = new AdRequest.Builder()
                .addTestDevice(AdRequest.DEVICE_ID_EMULATOR)
                .addTestDevice("XXXXXXXXXX")
                //.addTestDevice(getString(R.string.test_device_id))
                .build();
 
        // 広告を読み込む
        mAdView.loadAd(adRequest);
 
        // 広告ビューをアクティビティに追加する
        addContentView(mAdView, adParams);        
    }

以上で、バナー広告が表示できる。

のだが、現状ではなぜか画面下部に表示されず、画面左上に表示されてしまう。

【自分用メモ】#数独 解がひとつだけかチェック

(webで公開されてた)数独の問題100問に対して、解がひとつだけかどうかをチェックするプログラムを書いてみた。
アルゴリズムは単純な探索を用いるものだが、セルの値をビットマップで表現しているために、重複チェックが数値を用いるものに比べるとはるかに高速だ。
また、数字を入れるときに、重複チェックを行うのではなく、数字を使用するたびに各縦横ブロックの使用済みフラグをオンにしている。
結果、100問をチェックするのに要した時間は 0.3036ミリ秒だった。ということは、約30マイクロ秒/問でチェック可能ということになる。

ちなみに、単に解を見つけるだけ(最初の解がみつかった時点で終了)の場合は、220マイクロ秒/100問だった。ひとつだけかチェックする場合の約15倍高速ということになる。

プロジェクトにファイルを追加 #cocos2d-x #AndroidStudio

・ External Buld Files/Android.mk の LOCAL_SRC_FILES 部分を以下のように修正

LOCAL_SRC_FILES := $(LOCAL_PATH)/hellocpp/main.cpp \
$(wildcard $(LOCAL_PATH)/../../../Classes/*.cpp)

・Classes 以下にソース・ファイルを追加
・プロジェクトをいったん閉じて開く
→ プロジェクト名/cpp/MyGame/プロジェクト名/Classes 以下に追加されたソースが表示される

Qt5 再入門>Hello, World (Label使用、デザイナ非使用)

次はLabelウィジェットは使用するが、デザイナを使用せずに「Hello, World」を表示する方法を見てみよう。

QMainWindow は、ウィンドウ中央に表示するウィジェットを持つ。これを「セントラル・ウィジェット」と呼び、setCentralWidget(QWidget*) で指定することができる。
なので、ui セットアップ後に、Label オブジェクトを生成し、それをセントラル・ウィジェットとして指定してやればよい。

MainWindow::MainWindow(QWidget *parent) : (略)
{
    ui->setupUi(this);
    QLabel *label = new QLabel("Hello, World");
    setCentralWidget(label);
}

演習問題

  1.  QLabel ではなく QPushButton オブジェクトを生成し、セントラル・ウィジェットに指定してみなさい。

 

Qt5 再入門>Hello, World (デザイナ・Label使用)

まずは画面に「Hello, World」を表示してみよう。
それにはいくつかの方法があるが、まずは一番簡単なLabelを使ったものを紹介する。
下図の左側のプロジェクト部分の Form を展開し、mainwindow.ui をダブルクリックする。

そうすると、下図のようなデザイン画面に切り替わるはずだ。
左にウィジェット一覧があるので、そこからテキストを表示するためのウィジェットである Labelを探す。ウィジェットはあまりに多すぎて探すのが大変なので、上部のフィルター部分に「la」と入力すると、下図のように一番下に出てくるぞ。

左側のウィジェット一覧から「Label」をドラッグし中央のフォームにドロップすると、下図の様に Labelウィジェットが画面に配置される。

次に「TextLabel」の部分をダブルクリックし、「Hello, World」とキーボードから入力し、ラベルテキストを変更しよう。

これで、プログラムは完成なので、Ctrl + R を押して、ビルド&実行すると、下図のように表示されるはずだ。

デザイナ右下のプロパティ部分で、フォントやアライメントを指定できるぞ。
下図はフォントを大きくし、左右中央揃えに変更してみたものだ。

Ctrl + R で実行すると下図のようになるぞ。

演習問題

  1.  Label ではなく PushButton を配置し、テキストを「Push Me」してみなさい。

まとめ

  • form>ui ファイルをダブルクリックすることでフォームをデザインできるぞ
  • ウィジェットを画面に貼り付けることができるぞ
  • 目的とするウィジェットを探すときはフィルターを使うと便利だぞ
  • プロパティでウィジェットの属性を変更することができるぞ

Qt5 再入門>空のプロジェクト作成

久々にQtでアプリを作ろうと思ったら、いろいろすっかり忘れていたので、自分の備忘録としてもQt5 を使ったアプリの作成方法を記述しておく。

なお、Qt のバージョンは 5.9, Qt Creator のバージョンは 4.3.1を使用する

空のプロジェクト作成

まずは「ようこそ」の上部中央の【+ 新しいプロジェクト】をクリックして、新しいプロジェクトの作成を開始する。

作成するプロジェクトの種別を指定するダイアログ(下図)が表示される。
通常アプリを作成したいのであれば、下図の様に「アプリケーション」、「Qtウィジェットアプリケーション」を選び、【選択】を押す。

次にプロジェクト名、プロジェクトファイルのパスを入力する。

次にクラス名、ファイル名等を設定できるダイアログが表示される。
通常は特に変更する必要は無い。

最後に、プロジェクト管理、概要が表示されるので、問題が無ければ【完了】を押す。

以上で、プロジェクトが生成される。

プロジェクトが作成できたら Ctrl + R を押してみよう。
下図のような空のウィンドウが表示されるはずだ。

数独サイト

「数独」でぐぐった場合

234.0KPV/月、今日の数独20問

154.6KPV/月

224.9KPV/月

509KPV/月

参考:http://vivi.dyndns.org/ は 132.1KPV/月

 

 

2016年11月までの広告収入

■ 現状分析

下図はここ3年間の月ごとの(web+アプリ)広告収入の推移グラフ。

temp3

具体的な金額は公開していないが、今年の月々の収入は大学生のアルバイト程度で、サラリーマンの給料程度には届かず(しかもボーナスも無い)、広告収入だけで暮らしていけるレベルではない。
しかし、見てわかるように、前年比約3.5倍、指数関数的に増加しているので、このペースが続けば、1年後あたりには広告収入だけで暮らしていけるレベルになると期待している。
もちろん、今後もこれまでのようなペースで収入が増加していくという保証はまったくない。今後の開発、マーケティング活動、運次第である。

ちなみに、増加している総収入の推移は成長曲線に従うと考えられる。具体的にはロジスティック曲線だ。最初期は増加していることがわからないほど徐々に増加し、ある時点から指数関数的に急激に増加し、変曲点を経て導関数が減少し、上限に近づいていく。
毎月の収入は総収入を微分したものなので、初期の頃は指数関数だが、変曲点のところがピークになり、そのあとは徐々に減少していく。微分方程式で記述すれば dN/dx = rN(1-N/K) となる。

下図は月々の広告収入をwebコンテンツ(AdSense)とアプリ(AdMob)に分けたグラフ。

temp4

webコンテンツによる収入は多少の上下はあるが、おおむね緩やかに上昇している。
広告配信を行う無料アプリは、2014年8月からリリースを開始した。初期の頃は地をはうような収入であったが、アプリ数が増加し、また後で詳細に述べる「AIホールデム」のダウンロード(以下、DLと略す)数増加に伴い、2015年12月にはアプリ広告収入がwebコンテンツ収入を上回り、11月にはその月の総広告収入の約80%を占めるまでに至っている。

下図はアプリ収入の大部分を占める「AIホールデム」の毎月のDL数の推移だ。

temp

リリース直後はほとんどDLが無かったのが、2015年11月末に日本のTV番組(「1年の半分をカジノで過ごす東大卒の男」)に2012年「ポット・リミット・オマハ・シックス・ハンデッド」世界チャンピオンの木原直哉氏が出演してテキサスホールデムが紹介され、それにより日本からのDL数が一気に増えた。おいらはこれを「木原インパクト」と呼んでいる。

さらに、2016年8月中旬以降、DL数の伸びが急激に増えた。その理由ははっきりしていないが、Google Play にてブーストが効きづらくなったことが主な要因ではないかと考えている。

下図は、月々のDL数をUS・日本・その他の国に分けたもの。

temp

日本からのDL数は、「木原インパクト」の効果が徐々になくなってきていることにより徐々に減少していたが、8月が底で徐々に上向いてきている。
8月中旬から、世界各国からのDL数が急激に増えている。前述した様に、その理由は不明だ。

下図は「AIホールデム」の月々の広告収入をUS・日本・その他の国に分けたもの。

temp2

US, その他の国々からの収入は指数関数的に増加している。基本的に広告収入はDLが数に比例するのだが、日本・US以外の国々はクリック単価が低く、そのためにUSからの収入が最も多くなっている。

下図は8月中旬以降のアプリDAU(日々のアクティブユーザ数)のグラフ。

temp3

広告収入は基本的にDL数に比例すると書いたが、DLされてもすぐにアンインストールされたものは収入には結びつかない。また、アンインストールされなくても、ストレージに眠っているだけでも意味がなく、日々使用される(広告をクリックしていただく)ことが大事だ。そういう意味で、DAUは広告収入にダイレクトに結びつく重要な要素である。

8月中旬以降、DAUはほぼ線形に増加していて、11月に入ってから線形回帰の傾きが倍増している。これは、たんなるゆらぎかもしれないが、最近ヘルプ機能を徐々に実装してきた成果かもしれないと思っている。

下図は「AIホールデム」の1日ごとのDL数の推移グラフ。マッチ棒のようなマークは、アップデートを表す。

temp

一般的に、アップデートを行わないと継続的なDLが行われないと言うが、このグラフを見る限りでは、アップデートとDL数増加の明らかな因果関係は認められない。
むしろ、DL数が増加すると、開発意欲が湧き、アップデートしているような現状になっている。

が、アップデートが製品寿命を延ばす効果があるのは明らかであるので、今後も定期的に行っていくつもりだ。

■ 教訓

  • 中身の時代
    • ユーザ、スポンサー、場の提供者全員に対して有益か?
  • Google を介した口コミ (※ ユーザの積極的行動が不要)
  • プレイ時間の長期化・最大化を狙う
  • 以下の戦略が有効
    • 入り口を優しく
    • やりこみ要素
    • オンラインランキング(他のプレイヤーとの比較・競争)
    • トレーニング要素?
    • 実用性?

■ 今後の方針

  • 「AIホールデム」に約半分の工数をつぎ込み、ヘルプ・機能の充実、品質向上などを継続的に行う。
  • 新規アプリリリース
    • パズル系
    • ギャンブル系
      • バックギャモン
    • ツール系
  • 古いアプリのアップデートも行っていきたい。
    • 特に、古いアプリは見た目が悪く、ヘルプも皆無なので、そのあたりに工数をさきたい。

■ 今後の希望的予測

  • 日々のDL数の増加傾向はあと数ヶ月は続く
  • 「AIホールデム」累計DL数:2016年末は5万弱、2017年末は20万本~30万本
  • 広告収入の増加率は3倍/年が続く
  • 2017年中にウン10年前の大卒初任給を超える
  • 現在の大卒初任給並になるのは2018年以降

【cocos2d-x v3】 RadioButton の使い方

RadioButton クラスは v3.8 で追加された比較的新しいクラスだ。

  • RadioButtonGroup オブジェクトを生成し、子ノードとしてシーンに追加
  • 選択肢の分だけ、RadioButton を生成し、RadioButtonGroup オブジェクトに 追加し、シーンへも子ノードとして追加する
  • RadioButton オブジェクトにイベントリスナーを指定する
// Create a radio button group
auto radioButtonGroup = RadioButtonGroup::create();
this->addChild(radioButtonGroup);

// Create the radio buttons
for(・・・) {
        RadioButton* radioButton = RadioButton::create("cocosui/radio_button_off.png", "cocosui/radio_button_on.png");
        float posX = startPosX + BUTTON_WIDTH * i;
        radioButton->setPosition(Vec2(posX, winSize.height / 2.0f + 70));
        radioButton->setScale(1.2f);
        radioButton->addEventListener(CC_CALLBACK_2(LabelToggleTypeTest::onChangedRadioButtonSelect, this));
        radioButton->setTag(i);
        radioButtonGroup->addRadioButton(radioButton);
        this->addChild(radioButton);
}