hyoromoのブログ

最近はVRSNS向けに作ったものについて書いています

非公式アプリ「二次元画像詳細検索」をiOS/Androidで公開

主にえろい画像を検索する「二次元画像詳細検索」サイトの非公式アプリ*1として、iOS/Androidの両プラットフォーム向けにアプリを公開しました。

https://itunes.apple.com/jp/app/id793248344

https://play.google.com/store/apps/details?id=jp.hyoromo.nijisearch

 

Webサイトがスマホ対応されてなく、iOS/Androidだと画像をアップロードして画像検索出来なかったので本アプリを作りました。

クライアントアプリでローカルの画像をアップロードして検索、URLを入力して検索する事が可能です。

iOSAndroidの現時点での違い

AndroidはブラウザからURLを本アプリに共有する事で手軽に画像検索出来ます。iOSにその機能はありません。

今後のアップデート予定

アイコンとスクリーンショットが両プラットフォームともヤッツケなので変更する予定です。

追記(2014/02/11)

Windowsストアアプリに移植しました。

非公式アプリ「二次元画像詳細検索」をWindowsストアで公開 - hyoromoのブログ

*1:非公式ではありますが、サイト管理者様への許可は頂いています

上げて落とすアポー

前回「AppleにリジェクトされそうなiOSアプリを作ってみた」を書きましたが、リジェクトされる事なく version 1.0.0 をリリース出来ました!
より好みアプリランキング
カテゴリ: エンターテインメント, 仕事効率化

(゚∀゚ノノ゙パチパチパチパチ
やったーー、Appleがついにデレたのか!デレたのか!!













version 1.0.1 申請

審査に通過しないと思っていたので適当に作っていた「アプリアイコン」「スクリーンショット」を綺麗に作り直し、使い勝手の向上や細かい不具合を取り除いて...
アップデート申請!
 ↓
(一週間経過)
 ↓
リジェクト
 ↓
(´;ω;`)

機能自体は一切変えていないのにリジェクトされるとは...

リジェクト理由

リジェクト番号は 2.25 、理由はApp Storeに似ているからダメ。されると思ったこのリジェクト。

最後に一言

最初に言えよ!と思うも、たぶんAppleのレビュワーとやり取りしても解決しないんだろうなあ...

AppleにリジェクトされそうなiOSアプリを作ってみた


App Store眺めてても香ばしいアプリばかりなので、そういったアプリをフィルタリングして表示するアプリを作って先ほど申請しました。特定の開発者名/アプリ名やNGワードを設定することでフィルタリングできます。
作ったのはいいけど、ランキングはAppleにとってセンシティブなのでおそらくリジェクトされるでしょうねー。

iOS7からUIBarButtonItemに画像設定する方法が変わってた

UIBarButtonItem *item = [[UIBarButtonItem alloc] initWithImage:[[UIImage imageNamed:@"画像名"] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal]
                                                                          style:UIBarButtonItemStylePlain
                                                                         target:self
                                                                         action:@selector(イベント名:)];
self.navigationItem.rightBarButtonItem = item;

ポイントは imageWithRenderingModeUIImageRenderingModeAlwaysOriginal を指定する事。これはiOS7から追加されており、指定しないと UIImageRenderingModeAutomatic がデフォルト設定され、ボタンが真っ青になってしまいます。

CocosBuilderでマルチ解像度対応

今回はCocos2d向けUI作成ツール「CocosBuilder」を使ってマルチ解像度対応したUIを作っちゃおう!な内容を書きます。Cocos2d-xのセットアップが未だな場合は前回エントリーを参照ください。

実施環境

  • CocosBuilder 3.0 α5
  • Cocos2d-x 2.1.4

今回の目標

CocosBuilderを使ってiOS/Android向けにマルチ解像度に対応したUIを作成する。

CocosBuilderをインストール

CocosBuilderページからどうぞ。利用しているCocos2d-xのバージョンと対になるCocosBuilderのバージョンが存在する為、よくバージョン番号を確認してからダウンロードしてください。

CocosBuilder上でUI専用プロジェクトを新規作成

  1. CocosBuilderを起動
  2. メニュー上の「File > New > Project」を選択
  3. 新規プロジェクト名を設定してCocos2d-xで作成したプロジェクト内に作成*1
  4. 新規作成したプロジェクト内の「Resources」フォルダ内にはテンプレUIがありますが、邪魔になるので全て削除
  5. Cocos2d-xで作成したプロジェクト直下にある「Resources」ディレクトリを削除

UI専用プロジェクトの設定変更

  1. メニュー上の「File > Publish Settings」を選択
  2. HTML5のチェックを外し、Androidにチェックを入れる*2

UIファイルを新規作成

今回は横向きの画面を作成します。

  1. メニュー上の「File > New > Interface File」を選択
  2. 「Create a new Document」ダイアログが表示され、CocosBuilder上での表示解像度を選ばされます。今回は「iPhone Landscape」にチェックが付いている状態のまま「Create」ボタンを押下
  3. 初回起動させるUIファイル名は「MainScene」と付けます。他の名前を設定したい場合は「メニュー > Project Settings」を選択して「Start ccb-file name」の設定を変更する必要があります
  4. UIプロジェクトの「Resources」ディレクトリ内にファイル作成*3
表示解像度の変更/切り替え

「Create a new Document」ダイアログ上で設定した表示解像度は、CocosBuilderのメニューにある「Document > Edit Resolutions」から編集できます。表示解像度の種類を増やすとメニューにある「Document > Resolutions」から表示解像度毎の見た目に切り替えて確認できます。

UI作成

  1. 画像をUI上に配置する場合「UIプロジェクト > Resources」直下に「resources-auto」ディレクトリを作成し、このディレクトリ内に画像を追加していきます。なお、追加する画像はUIファイル作成時に設定したスケールがベースサイズ(scale 4.0)となる
  2. 適当に作成。今回は分かりやすいように上下左右中央にCCSpriteを配置
  3. メニュー上の「File > Save」を選択してUIファイルを保存
  4. メニュー上の「File > Publish」を選択してCocos2d向けのファイルを生成

UI読み込み

Cocos2dxで作成したプロジェクト内の「Classes > AppDelegate.cpp」を開いて「AppDelegate::applicationDidFinishLaunching」メソッド内に以下のコードを追加します。なお、今回は横向きを想定しての数値設定な為、もし縦向き対応させる場合は縦横の設定値を全て逆にする必要がある

bool AppDelegate::applicationDidFinishLaunching()
{
    // initialize director
    CCDirector *pDirector = CCDirector::sharedDirector();
    pDirector->setOpenGLView(CCEGLView::sharedOpenGLView());
    
    /* ここから追加コード */
    
    CCSize designSize = CCSizeMake(480, 320); // ベースサイズ
    CCSize resourceSize;
    CCSize screenSize = CCEGLView::sharedOpenGLView()->getFrameSize();
    
    std::vector<std::string> searchPaths;
    std::vector<std::string> resDirOrders;
    
    TargetPlatform platform = CCApplication::sharedApplication()->getTargetPlatform();
    if (platform == kTargetIphone || platform == kTargetIpad) {
        searchPaths.push_back("Published-iOS");
        CCFileUtils::sharedFileUtils()->setSearchPaths(searchPaths);
        
        if (screenSize.height > 768) {
            resourceSize = CCSizeMake(2048, 1536);
            resDirOrders.push_back("resources-ipadhd");
        } else if (screenSize.height > 640) {
            resourceSize = CCSizeMake(1536, 768);
            resDirOrders.push_back("resources-ipad");
        } else if (screenSize.height > 480) {
            if (screenSize.width < 1536) {
                // 4インチ
                resourceSize = CCSizeMake(1136, 640);
            } else {
                // 3.5インチ
                resourceSize = CCSizeMake(960, 640);
                }
            resDirOrders.push_back("resources-iphonehd");
        } else {
            resourceSize = CCSizeMake(480, 320);
            resDirOrders.push_back("resources-iphone");
        }
        
        CCFileUtils::sharedFileUtils()->setSearchResolutionsOrder(resDirOrders);
    } else if (platform == kTargetAndroid) {
        if (screenSize.height > 1200) {
            resourceSize = CCSizeMake(1200, 800);
            resDirOrders.push_back("resources-xlarge");
        } else if (screenSize.height > 960) {
            resourceSize = CCSizeMake(960, 640);
            resDirOrders.push_back("resources-large");
        } else if (screenSize.height > 480) {
            resourceSize = CCSizeMake(720, 480);
            resDirOrders.push_back("resources-medium");
        } else {
            resourceSize = CCSizeMake(568, 320);
            resDirOrders.push_back("resources-small");
        }
        
        CCFileUtils::sharedFileUtils()->setSearchResolutionsOrder(resDirOrders);
    }

    pDirector->setContentScaleFactor(resourceSize.width / designSize.width);
    CCEGLView::sharedOpenGLView()->setDesignResolutionSize(designSize.width, designSize.height, kResolutionFixedHeight);

    /* ここまでが追加コード */

    // turn on display FPS
    pDirector->setDisplayStats(true);
    
    // set FPS. the default value is 1.0/60 if you don't call this
    pDirector->setAnimationInterval(1.0 / 60);

    ScriptingCore* sc = ScriptingCore::getInstance();
    sc->addRegisterCallback(register_all_cocos2dx);
    sc->addRegisterCallback(register_all_cocos2dx_extension);
    sc->addRegisterCallback(register_all_cocos2dx_extension_manual);
    sc->addRegisterCallback(register_cocos2dx_js_extensions);
    sc->addRegisterCallback(register_CCBuilderReader);
    sc->addRegisterCallback(jsb_register_chipmunk);
    sc->addRegisterCallback(jsb_register_system);
    sc->addRegisterCallback(JSB_register_opengl);
    sc->addRegisterCallback(MinXmlHttpRequest::_js_register);
    sc->addRegisterCallback(register_jsb_websocket);
    
    sc->start();
    
    CCScriptEngineProtocol *pEngine = ScriptingCore::getInstance();
    CCScriptEngineManager::sharedManager()->setScriptEngine(pEngine);
    ScriptingCore::getInstance()->runScript("main.js");
    
    return true;
}

コードはCocosBuilderのメニュー上の「Help > CocosBuilder User Guide」の「4c」とほぼ同じです。リソースの読み込み先を指定し、端末解像度に合わせてUIをスケールさせてます。

スケール方法

CCEGLView::sharedOpenGLView()->setDesignResolutionSize は最後の引数に設定する値はスケール方法となっており以下の値が設定可能です

意味
kResolutionExactFit 画面比率を無視して、端末解像度に合わせて設定する。はみ出しや余白が生じない
kResolutionNoBorder 画面比率を維持して、端末解像度いっぱいに設定する。縦横のどちらかがはみ出る
kResolutionShowAll 画面比率を維持して、端末解像度に合わせて設定する。縦横のどちらかに余白が生じる
kResolutionFixedHeight 画面比率を維持して、端末解像度の高さに合わせて設定する。横がはみ出しや余白が生じる
kResolutionFixedWidth 画面比率を維持して、端末解像度の幅に合わせて設定する。縦がはみ出しや余白が生じる
別のUIファイル読み込み方法

上記サンプルコードは「main.js」を読み込む事で「MainScene.ccbi」を読み込んでいます。jsを介さなくても以下のようにcpp側からccbiファイルを直接読み込むことが出来ます。

cocos2d::extension::CCNodeLoaderLibrary *lib = cocos2d::extension::CCNodeLoaderLibrary::newDefaultCCNodeLoaderLibrary();
cocos2d::extension::CCBReader *reader = new cocos2d::extension::CCBReader(lib);
CCScene *scene = reader->createSceneWithNodeGraphFromFile("MainScene.ccbi");
pDirector->runWithScene(scene);

Xcodeで実行

  1. Cocos2d-xで作成したプロジェクトをXcodeで起動
  2. プロジェクト上から「Resources」を削除
  3. UIプロジェクト内の「Published-iOS」フォルダを追加。フォルダ追加の際に「Folders」項目を「Create folder references for any added folders」に設定しておくと楽できます*4
  4. Buildして端末上で確認

Androidで実行

assetsへ必要ファイルをコピーさせる

Cocos2dxで作成したプロジェクト内の「proj.android > build_native.sh」をテキストエディタで開き、以下のように置き換えます。

# 以下の2行を
# copy Resources/* into assets' root
cp -rf "$APP_ROOT"/Resources/* "$APP_ANDROID_ROOT"/assets

# 以下の2行に置き換え
# copy CocosBuilder//Published-Android/* into assets' root
cp -rf "$APP_ROOT"/(UI専用プロジェクト名)/Published-Android/* "$APP_ANDROID_ROOT"/assets
実行
  1. Cocos2d-xで作成したプロジェクトをAndroidで起動
  2. Buildして端末上で確認

まとめ

iOSはシミュレータでだいたい大丈夫そうなのが分かりましたが、Androidはそんなに確認してないので今回の方法だと問題あるかも...

*1:今回は「CocosBuilder」という名前でプロジェクト直下に作成しています

*2:xsmallはもう対応しなくても良いと思うのでチェックを外していますが、別に付けたままでも良いと思います

*3:Layerを複数作成する場合、Layer専用ディレクトリを用意した方が整理出来て良いです

*4:groupとして追加すると、ファイルが増える度にイチイチ追加する必要がある為

Cocos2d-xの環境構築


Cocos2d-x 3.0 αが先日リリースされたようですが、今回は安定版の2.1.4を使っていきます。ちなみにXcodeEclipseはインストール済みを想定して書いてますのであしからず。

実施環境

  • Mac OSX 10.8.4
  • Cocos2d-x 2.1.4
  • Android NDK 8e
  • Eqlipse 4.2.2
  • Xcode 4.6.3

今回の目標

開発環境を整えて初期プロジェクトをiOS/Android端末へデプロイする。要はこの記事のトップに貼ってある画像の画面を起動させる事が目標です。

Android NDK のセットアップ

Android DeveloperサイトのNDKページからダウンロードしてきます。ただし、Cocos2d-x 2.1.4バージョンだと NDK r9 を使うとエラーになる為、今回はr8e を使用しました。
ダウンロード出来たらファイルを解凍して適当なディレクトリに配置してください。Android SDKディレクトリと同じ階層に置いておくと分かりやすいと思います。

Eclipse上の環境設定

Eclipseを起動してメニュー上から「Eqlipse >環境設定」を選びます。「Android > NDK」にある「NDKLocation」項目へ「/(Android NDKを配置したディレクトリ)/android-ndk-r8e」を設定します。
同じように環境設定から「C/C++ > Build > Environment」で「Add」ボタンを押下し、「Name」項目に「NDK_ROOT」、「Value」項目に「/(Android NDKを配置したディレクトリ)/android-ndk-r8e」を設定します。

Cocos2d-x のセットアップ

Cocos2d-xのwikiからダウンロードしてきます。Cocos2d-x/Cocos2d-HTML5/Cocos2d-XNAとありますが、Cocos2d-xをダウンロードしてください。
ダウンロード出来たらファイルを解凍して適当なディレクトリに配置してください。なお、Cocos2d-x 内にプロジェクトが生成されたり、tool類があるので分かりやすい場所に置いたほうがいいです。

Android SDK/NDKインストール ディレクトリを設定

cocos2d-x-2.1.4/create-android-project.sh ファイルの最初にある二行を以下のように置き換えます。

NDK_ROOT_LOCAL="/(Android NDKを配置したディレクトリ)/android-ndk-r8e"
ANDROID_SDK_ROOT_LOCAL="/(Android SDKを配置したディレクトリ)/android-sdk"

cocos2d-x-2.1.4/template/android/build_native.sh ファイルの二行目に以下の一文を挿入します。

NDK_ROOT="/(Android NDKを配置したディレクトリ)/android-ndk-r8e"
Cocos2d-xのAndroid向けライブラリ libcocos2dx を追加

Eclipseを起動してメニュー上から「File > Import」を選びます。「Android > Existing Android Code Into Workspace」を選択し、「Import Projects」画面のRoot ディレクトリ項目に「/(cocos2d-xを配置したディレクトリ)/cocos2d-x-2.1.4/cocos2dx/platform/android/java」を指定して「Finish」ボタンを押下します。

プロジェクトを新規作成

ターミナル上から以下のように create_project.py を実行する事でプロジェクトを新規作成できます。以下の例ではプロジェクト名「Cocos2dJsHoge」で、パッケージ名「jp.hoge.cocos2djshoge」で、開発言語「JavaScript」を指定して作成しています。

$ cd cocos2d-x-2.1.4/tools/project-creator
$ ./create_project.py -project Cocos2dJsHoge -package jp.hoge.cocos2djshoge -language javascript
proj.ios		: Done!
proj.android		: Done!
proj.win32		: Done!
New project has been created in this path: /(cocos2d-xを配置したディレクトリ)/cocos2d-x-2.1.4/projects/Cocos2dJsHoge
Have Fun!

create_project.py のオプションは以下のようになっています。

オプション名 意味 具体的な指定名 備考
project プロジェクト名
package パッケージ名 .は2つ以上付けないとエラーになります
language 開発言語 cpp
lua
javascript

実行後のログにエラーが表記されていない事を確認し、問題が無ければ cocos2d-x-2.1.4/projects 以下に作成されたプロジェクトを使用します*1

端末へデプロイ

iOS

以下を実行してXcodeを起動させます。Cocos2dJsHoge にあたる箇所は自身が作成したプロジェクト名に読み替えてください。
/(cocos2d-xを配置したディレクトリ)/cocos2d-x-2.1.4/projects/(プロジェクト名)/proj.ios/(プロジェクト名).xcodeproj

Xcode上のShemeが「cocos2dx」になっている場合は「プロジェクト名」に切り替えてから「Run」してください。これで問題なく起動するはずです。

Android

Eclipseを起動してメニュー上から「File > Import」を選びます。「Android > Existing Android Code Into Workspace」を選択し、「Import Projects」画面のRoot ディレクトリ項目に「/(cocos2d-xを配置したディレクトリ)/cocos2d-x-2.1.4/cocos2dx/projects/(プロジェクト名)/proj.android」を指定して「Finish」ボタンを押下します。
プロジェクトを右クリックして、「Run As > Android Application」を選択すれば端末へデプロイされます。
もしプロジェクト内でエラーが発生している場合、「Android NDK のセットアップ」と「Cocos2d-x のセットアップ」を見直してみてください。

まとめ

Cocos2d-x/Android NDK/Xcodeとバージョン依存が激しそうですね。次回はIDEについて書く予定。

*1:途中でエラーが発生してもプロジェクト作成はされます。ですが、後々どこかしらで問題が発生するので利用するのはやめた方が良いです。

iOS向けに「タスクを倒せ」アプリをリリースしました


タスク管理×ゲーム的なノリのアプリです。タスク消化する時にストレス解消も兼ねたい人は以下バナーからDLしてみてください。

主な機能

タスク消化に掛かる時間(0:01〜23:59)に応じてタスクと言う名のモンスターが生成され、タスクの進捗はモンスターを殴ってHPを減らすことで管理します。
まぁ一発ネタ以上でも以下でもないアプリとなってます。

一方的に感謝したい対象

余談

今回利用させてもらったモンスターの一部に露出度の高いのも居たのですが、特に引っかかることもなく審査に通りました。人外ならどんな格好でもOKなのかもしれませんね(そこまでテストしてないだけかもしれませんが...)。