Mac OS Sierraで「ろ」のキーにbackslashを割り当てる

今までKarabiner-Elementsでなんとかしようとしてたけどうまくいかなくて鬱屈とした日々を送っていたのですが、今日ひさしぶりにトライしてみようとググってみたら、こんな記事を見つけました。

ubutun.blogspot.jp

「英かな」というアプリを使うといけると。

⌘英かな

早速試してみたら簡単に導入できて快適。

元記事では直接バックスラッシュ指定していなかったけど、直接バックスラッシュ指定しても問題なさそうだったのでそういうふうにしています。

f:id:wkpn:20170625143544p:plain

こんな感じ↑

数字が徐々に変わって目的の数値に行くスクリプト

f:id:wkpn:20170623190340g:plain
ゲームのUIで、こんな感じの演出ってよくあると思います。スクリプトを書きました。

以下のスクリプトをTextコンポーネントを持ったオブジェクトに貼り付けて、SlideToNumber( from_number, to_number, duration )を呼べば、from_numberからto_numberへduration秒かけて遷移します。

using System;
using System.Collections;
using UnityEngine;
using UnityEngine.UI;

[RequireComponent(typeof(Text))]
public class SlideNumberEffectController : MonoBehaviour {
    public Action OnComplete = null;//終わった時のコールバック

    private Text  text;
    private float speed;
    private float number;
    private float targetNumber;

    private Coroutine playCoroutine = null;

#if UNITY_EDITOR
    [SerializeField]
    private int debugToNumber = 10;
    [SerializeField]
    private float debugDuration = 1.0f;
#endif

    void Awake()
    {
        text = GetComponent<Text>();
    }

    //
    // 数値をすぐにセット
    //
    public void SetNumber( int n )
    {
        number = (float)n;
        text.text = ( (int)number ).ToString();
        if( playCoroutine != null )
        {
            StopCoroutine( playCoroutine );
            playCoroutine = null;
        }
    }

    //
    // from_number から to_number に徐々に移行
    //
    public void SlideToNumber( int from_number, int to_number, float duration )
    {
        SetNumber( from_number );
        SlideToNumber( to_number, duration );
    }

    //
    // 今の値から から to_number に徐々に移行
    //
    public void SlideToNumber( int to_number, float duration )
    {
        targetNumber = to_number;
        speed = ( ( targetNumber - number ) / duration );

        if( playCoroutine != null )
        {
            StopCoroutine( playCoroutine );
        }
        playCoroutine = StartCoroutine( "slideTo" );
    }

    private IEnumerator slideTo()
    {
        while( true )
        {
            var delta = speed * Time.deltaTime;
            var next_number = number + delta;
            text.text = ( (int)next_number ).ToString();

            number = next_number;

            if( UnityEngine.Mathf.Sign( speed ) * ( targetNumber - number ) <= 0.0f )
            {
                break;
            }
            yield return null;
        }
        playCoroutine = null;;
        number = targetNumber;
        text.text = ( (int)number ).ToString();
        if( OnComplete != null )
        {
            OnComplete();
            OnComplete = null;
        }
    }

#if UNITY_EDITOR
    [ContextMenu( "Test" )]
    void Test()
    {
        SlideToNumber( debugToNumber, debugDuration );
    }
#endif

}

おわり。

Unityでビルドした後、XCode上でSiginingのTeamを指定するのがめんどくさかったけどUnity側で設定できた。

だいぶ前から使っていて、前回の記事でもすでに使っていたのですが、ブログにメモしていなかったので書いておきます。

以前からUnityでiOS用にビルドした後にXCode上でSiginingのTeamの部分を設定するのがめんどくさいなぁと思っていました。

ここ↓
f:id:wkpn:20170623133038p:plain

Unity5.6になったときに気づいたんですが、Player SettingsにAutomatically SignっていうのとAutomatic Sigining Team Idってのがあるんですね。

これ↓
f:id:wkpn:20170623133110p:plain


うっほほーいと思って、Team IdのところにXCode上で表示される自分のTeam名(Ken Watanabe)を入れてみたもののうまくいかない😨

調べてみると、こちらに同様の質問がありました。
https://forum.unity3d.com/threads/ios-developer-team-id-how-does-it-work.435411/


Sign in with your Apple ID - Apple Developer
に飛んでMemberのところに出てくるTeam IDを入れればOKです。

これ↓
f:id:wkpn:20170623133333p:plain

おわり

UnityアプリのiOS版にアドフリくんを導入する際にXCode上での操作をしたくないので頑張ってみた。

アドフリくんとは

アドフリくんとは、俗に言うSSPというものです。

SSPとはSupply Side Platform(サプライ サイド プラットフォーム)の略語で、簡単に言うといくつかあるアドネットワークから適したものを自動で選んでくれて収益を最大化してくれるツールです。

今回色々と事情があって自作のUnityアプリにアドフリくんを入れてみることにしました。

基本的には丁寧なマニュアルが用意されているので、それに従えば導入できます。

しかしiOS版の導入の仕方が、マニュアルそのままだとXCode上での操作がありちょっと手間なのでUnity上で全部やってしまえるように多少工夫しました。

それをここにメモしておきます。(まずは軽くで良いのでマニュアルを一度読むことをオススメします。)

ADFMovieReward.framework を追加

マニュアルでは、ADFMovieReward.framework をXcodeにドラッグ&ドロップします。

と書いていますが、ビルドのたびにいちいちXCode上で操作するのはめんどくさいです。Unity Cloud Buildもできなくなっちゃうし。

なので、ADFMovieReward.frameworkをAssets/Plugins/iOSの下にぶっこみます。

しかし、そのままだとエラーが出てしまいました。

'ADFMovieReward/ADFmyMovieReward.h' file not found

と言われてしまいます。

ファイルがどこにあるかわかんないのでエラーになってるようです。

ぶっこんだファイルがどこにいったかというと、$(PROJECT_DIR)/Frameworks/Plugins/iOS の下にあります。

なので、これをSearch Pathに入れてあげるため、以下のようなコードを書きます。

using System.IO;
using UnityEditor;
using UnityEditor.Callbacks;
using UnityEditor.iOS.Xcode;

public static class XcodePostProcessBuild
{
    [PostProcessBuild]
    public static void OnPostProcessBuild(BuildTarget target, string path)
    {
        if (target != BuildTarget.iOS)
        {
            return;
        }

        var project = new PBXProject();
        project.ReadFromFile(PBXProject.GetPBXProjectPath(path));

        //Search Framework pathを追加
        string target_name = project.TargetGuidByName("Unity-iPhone");
        project.AddBuildProperty(target_name, "FRAMEWORK_SEARCH_PATHS", "$(PROJECT_DIR)/Frameworks/Plugins/iOS");
        project.WriteToFile(PBXProject.GetPBXProjectPath(path));
    }
}

これをXcodePostProcessBuild.csなどと名前をつけて、Assets/Editor以下に置いておきます。

-ObjC -fobjc-arc フラグを追加

Other Linker Flagsに-ObjCと-fobjc-arcを指定とあるので、これをframeworkを選択してinspectorから設定します。
Compile flagsと書いているけれどもOther Linker Flagsにちゃんと追加されるみたい。

f:id:wkpn:20170621212513p:plain


他のAdNetworkのframeworkも容赦なくぶっこむ

ADFMovieReward.frameworkを入れただけでは、各社の広告は表示されません。各社のAdNetworkプラグインもインストールする必要があります。

これもマニュアルによると、XCode上でドラッグ・アンド・ドロップというふうに書かれていますがめんどくさいのでAssets/Plugins/iOSに予めぶっこんどきます。

フォルダ階層が深いものもありますが、中から引き出してぶっこみます。

こんな感じ↓(全ファイルが収まらないのでスクショを3枚合成してます)


f:id:wkpn:20170825141715p:plain

Privacy Descriptionの追加

このままで来たバイナリをAppleに提出すると、Privacy Descriptionがないよっと怒られます。
Cameraに関するDescriptionは最近のUnityではPlayer Settingsで記述できますので、そちらで書いておきます。

こんな感じ。

f:id:wkpn:20170621212549p:plain

Calendarsにもアクセスが入るようです。そちらに関してはスクリプトで追加します。先のOnPostProcessBuildに以下を追加します。

// Add Privacy Description For Adfurikun
var plistPath = Path.Combine(path, "Info.plist");
var plist = new PlistDocument();
plist.ReadFromFile(plistPath);
plist.root.SetString("Privacy - Calendars Usage Description", "Advertisement would like to use Calendars.");
plist.WriteToFile(plistPath);

まとめ

以上で完了。なんとかXCode上で何もしなくて良くなりました!

その他

この作業をしている途中で、

ld: library not found for -lPods-Unity-iPhone

というエラーに悩まされたのですが、Unityを最新版にしたら解決しました。
Unityを最新にせずに、XCodeのバージョンを上げたのが問題だったのかも...

【unity】プログラマーがデザイナーとコンポーザーと協力してゲームを作った話【 #Economicity 】

f:id:wkpn:20170619094010p:plain
新作ゲーム「街づくりパズル エコノミシティ – ECONOMICITY -」をリリースしました!

Economicityのせいで電車を乗り過ごしたというご意見もあり、業が深いゲームを作ってしまったなと反省しております。

ダウンロードリンクはこの記事の最下部にまとめてありますので 未プレイの方はぜひダウンロードお願いします!

このアプリですが、開発はプログラマー(私 @waken )とデザイナー( Kotoriさん )とコンポーザー( Shiibaさん )の3人体制で作りました。

お世話になっている京ゆにのnaichiさんの記事を真似て自分も開発を振り返ってみます。
blog.naichilab.com

開発期間

4月頭〜5月中旬(最初のリリースまで)

2ヶ月弱。ただし本開発の前に試作をいくつか作って遊んでもらっています。

3月末に4つ作った試作を何人かに遊んでもらい、その中で一番好評だったものを製品化することにしました。そして4月頭にイラストレーターのKotoriさんに相談しました。

その後4月中旬にShiibaさんに開発中のものを見てもらい、作曲をお願いしました。

BitSummit前にリリースするのが目標だったので、一応ほぼ計画通りにリリースできました。ただ、最初は色々とバグが多かったです。

リリースしてから今に至るまで、バグの修正や演出の追加などで、ちょこちょこアップデートを繰り返しています。

役割分担

  • ゲームデザイン わけん
  • アート全般 Kotori
  • BGM Shiiba
  • UI アドバイス Kotori
  • 効果音(フリー素材を探す) わけん Shiiba
  • プログラム わけん
  • ストア準備 わけん Kotori(ストア用素材)
  • 開発環境準備 わけん
  • テキスト わけん
  • 広報 わけん
  • 英語翻訳 Laura Cronell, American Time Inc. (部活の後輩の奥さん)
  • テストプレイ ギークハウス京都東福寺住民の方々や遊びに来てくれた方々など多数


アートをKotoriさんに、BGMをShiibaさんにお願いして、残りはだいたい自分って感じです。2人にはUIとか効果音など色んな所でアドバイスを頂きました。

翻訳は最初自分で頑張ったんですが、部活の後輩で仙台で英会話教室をやっている方が、ゲームを遊んでくれた後に添削を申し出てくれました。
http://american-time.jp/com/

また、ギークハウス京都東福寺には色んな方が遊びに来てくれるので、その都度、遊んでもらって感想を頂きました。

使ったツールとか

Bitbucket

bitbucket.org

基本的に自分のバックアップ用で、他の人は使わず。

基本コマンドラインで使用。コミット数は約250。1人でやっているのでコミット単位はかなり雑。

branchはdevelopブランチを切って、そこで基本開発。わりと特殊な機能を実装する時だけfeature○○というブランチをきって、そっちで作業してdevelopにmerge。developはリリースする時にmasterにmerge。

Unity Collaborate

Unity製バージョン管理ツール。

Artを上げてもらったり、ArtやBgmを実装した後の確認をしてもらうのに利用。

まだβ版なので、たまにUnity再起動しないと変な感じになることがあるけど、超簡単、超便利。

Unity Cloud Build

自動ビルドツール。

超簡単にCollaborateで上げたやつをビルドしてくれる。iOSは証明書周りがめんどくさくてちゃんと使ってなかった。

Android版のビルドは簡単に使えたけど、実機確認したい時はクラウドビルド待ってられなくて結局ローカルビルドしていた...

というわけで、あまり有効に機能しなかった。

運用方法は今後の課題。

Slack

コミュニケーションツール。チャンネルは6つ。

economicityチャンネル

economicityに関わること全般

economicity-artチャンネル

economicityのartに関わること全般

economicity-soundチャンネル

economicityのsoundに関わること全般

economicity-storyチャンネル

economicityのstoryに関わること全般。ストーリーってほどしっかりしたものがあるわけでもないのですが、なんとなく背景のネタ出し的な感じに利用。

build-economicityチャンネル

Unity Cloud Buildの開始と結果を飛ばすチャンネル。ビルドエラーになることは皆無だったんでビルド結果情報が役に立ったということは無かったのですが、ここにメッセージが飛ぶと、あっリソース上がったなってのが分かったのが良かったです。

ego-searchチャンネル

naichiさんのパクリ。IFTTTを使ってTwitter上で「Economicity」とか「エコノミシティ」で検索した結果を飛ばしてきてる。

IFTTT

なにかをトリガーに何かをするサービス。上記のego-searchチャンネルに使用。

Google Drive, Dropbox

基本的にUnity CollaborateやSlackで事足りることが多いのだけど、たまにデータの受け渡しに使うことがありました。

タスク管理ツール

使用せず。自分がローカルでテキストエディタ使ってタスクを羅列するだけ。

音楽と画像に関してはSlackでいついつまでにこのリソース欲しいです。って言ってました。

楽ちん。

その他

タスク管理術ってほどでもないですが、マイルストーンを決めて、そっから1週間ごとの目標を決めて、そっから1日ごとの目標を決めて...っていうふうにしてました。

あとは、それぞれの目標を前倒しで達成してゆっくりするぞーって気持ちで作ってました。

それにより、ゆっくりはできなかったけど一応当初の目標であるBitSummit前にリリースできました。

ゲームを遊ぶ日

途中のマイルストーンで一緒に、製作途中のゲームをプレイする日というのを設けました。

細かい作業に没頭していると、ゲーム自体を遊ばなくなりがちなのでオススメです。

実際遊んでみるといろいろな問題が顕になって焦ります。

アートの人にも「あっこういう仕様ならこういうデザインのほうが良いかも...」っと色々気づいてもらえてgoodでした。

反省点

反省点は、ここに挙げたもの以外にも多々あるのですが、目立ったところをいくつか。参考になれば幸いです。

  • イベントギリギリに仕上げると、広報素材が間に合わないので1週間前ぐらいに仕上がるぐらいがちょうど良い。
  • バランス調整が難しそう...は鬼門。ちゃんと最後までバランス調整してみてからプロジェクトを進めるかどうか判断したほうが良い。
  • もっと仕様をFixしてからArtと音楽を発注すべきだった。会社では難しかったけど個人開発でこの規模のゲームなら、ほぼほぼ仕上げてから絵と音楽を発注ってできる気がする。(今回は〆切をBitSummitに合わせてたから難しかったけど)
  • 試遊会にて、自分が面白いでしょ!って思っているところとユーザーが楽しいって感じているところが違うことがある。今回はズレてた気がする。
  • 自分の作るゲームに関しては、試遊はゲームに慣れていなく、空気を読まずに意見を言う人にやってもらったほうが良い。つまり子供が良い。

uGUIで2色補完する(黒を○色、白を○色にする)

f:id:wkpn:20170609133118p:plain

こういう3種類の絵を出したい時に、色違いのテクスチャーを用意するのってめんどくさいですよね?

見た目の色違いだけなのに、テクスチャに色を乗算するだけではどうにもならないし... けどなんとか、左端の白黒のテクスチャ1枚で済ませたい。

黒色の部分を○○色に、白色の部分を○○色に...っと指定できたら良いのになぁ... っとは全人類が思うところです。

ということで自作。

って言っても大したことはしていません。

シェーダーの用意

まず、Shaderを用意します。Unityのビルトインシェーダーを元に作っていくので、まずは以下からダウンロード。

Unity - Update


f:id:wkpn:20170609133629p:plain


シェーダーをダウンロードしたら、中にあるUI-Default.shader(builtin_shaders-***\DefaultResourcesExtra\UI\UI-Default.shader)をUnityのプロジェクトにインポートします。

シェーダーのカスタマイズ

1. UI-DefaultをリネームしてUI-Complement2っていう名前にします。
2. Shader内の頭の部分を以下の用に修正します。
Shader "UI/Default"

Shader "UI/Complement2"
3. プロパティ部分(Properties{}の中)に以下を追加します。
_ComplementColor0 ("Complement Color 0", Color) = (0,0,0,0)
_ComplementColor1 ("Complement Color 1", Color) = (1,1,1,1)
4. CGPROGRAM〜ENDCGの間のどこかテキトーな場所に以下を追加します。
fixed4 _ComplementColor0;
fixed4 _ComplementColor1;
5. カラー計算部分を以下のように修正します。
half4 color = (tex2D(_MainTex, IN.texcoord) + _TextureSampleAdd) * IN.color;

half4 tex_color = tex2D(_MainTex, IN.texcoord);
half4 color;
color.rgb = lerp( _ComplementColor0, _ComplementColor1, tex_color.r ) * IN.color.rgb;
color.a = tex_color.a;

_TextureSampleAddは、Alpha8モードのときに必要らしいけど、Alpha8モードは想定していないので、除外します。

マテリアルを作って設定する

Shaderを右クリックしてCreate -> Materialとすると、そのシェーダーを使ったマテリアルができます。

インスタンスごとに色を変える

上記のマテリアルをImageに割り当てるととりあえず動くのですが、全インスタンスでマテリアルが共有されちゃうので同じ色になっちゃいます。

なので、こんなスクリプトを書いてコンポーネントとして追加します。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class ComplementTestObj : MonoBehaviour {
    [SerializeField]
    Image image;

    [SerializeField]
    Material matPrehab;

    [SerializeField]
    Color color0 = Color.black;

    [SerializeField]
    Color color1 = Color.white;

	void Start () {
        var mat = Instantiate( matPrehab );
	mat.SetColor("_ComplementColor0", color0);
	mat.SetColor("_ComplementColor1", color1);
        image.material = mat;
    }
}

あとは、以下のようにImage、Material、Color0、Color1を指定すればOK。

f:id:wkpn:20170609135352p:plain

ちょいとめんどくさいけど、これでいちいち色違いのテクスチャを作らなくて済みます。



play.google.com

Unityで作ったアプリのAndroid版で set_interactable can only be called in main thread などというエラーが出て困った話

Unityで作ったアプリのAndroid版で set_interactable can only be called in main thread などというエラーが出て困っておりました。

メインスレッド以外でset_interactable呼ぶなや!ってことみたいです。

どうもAdMobのinterstitialがCloseした時のCallbackで色々やってたのが良くなかったみたいです。
具体的には、以下のようなコードのCloseCallbackの中身が良くなかったです。

interstitial = new InterstitialAd (ad_id);
request = new AdRequest.Builder ().Build ();
interstitial.LoadAd(request);
interstitial.OnAdClosed += CloseCallback;

CloseCallbackではフラグを立てるだけにして、Updateの中でflagを監視し、flagが立ったらやりたいことをする。っというようにすることで解決できました。

プラグインの用意するcallbackはメインスレッドで呼ばれない可能性があるので、中身に詳しくなければ複雑な処理はしないほうが良いなと思いました。