FreelyApps

個人によるアプリ開発の日記です。アプリの収入だけで生活できるようになるのが目標です。UnityでAndroid向けのゲームアプリを作成しています。


    アプリ『トランプ・ジン・ラミー』を公開しました。
    Android/iOS https://goo.gl/PYKFYG

    2016年01月

      このエントリーをはてなブックマークに追加 Clip to Evernote
    UIの位置を調整する場合はスクリーン座標を基準に考えるのが最も良いです。スクリーン座標とは表示するディスプレイ上でのピクセル単位の座標です。
    Unityでは左下が(0,0)、右上が(幅,高さ)となるように座標を定めています。カメラのところにちょろっと説明が載っています。
    こういったゲームビューなら右上の座標は画面のサイズになります。
    gameview

    なぜスクリーン座標で考えると良いのかというと、画面上でどこに表示されているかを直接表しているためです。画面上の位置が表示にそのまま関係するため最もわかりやすいのです。

    3DとUIを連携したい場合
    わかりやすい例で言うと3D空間上にいる物体の近くにUIを常に出したいといったことがあるでしょう。これはキャラクターにHPのバーを表示し続けるといったことが該当します。
    キャラクターが3Dだとすると、キャラクターの位置は3D空間上での位置を表しています。(モデルの中心位置に一致することでしょう。)x,y,zの3成分があるベクトルで表されますが、この数字はワールド座標であるはずです。空間上の位置から画面上のどこ(スクリーン座標)に表示されるのかを求める必要があるわけです。これはキャラクターを移しているカメラから変換行列をかけてもらい求めます。Unityではこの行列計算は、カメラコンポーネントを取得してWorldToScreenPointを位置に適用するだけなので簡単です。
    キャラクターのスクリーン座標がわかったら、UIの位置を補正するなどしてUIのスクリーン座標を決めます。頭上にHPを出したければ、キャラクターのスクリーン座標に適当な量yを増やせばいいです。このスクリーン座標をUIの座標にして、それをUIにセットすれば目的が達成されます。RectTransformUtility.ScreenPointToLocalPointInRectangle(RectTransform rect, Vector2 screenPoint, Camera cam, out Vector2 localPoint)を使えば、あるRectTransform内でのローカル座標を求めることができます。rectは設定したいUIの親になることがほとんどになるでしょう。camはCanvasに使っているカメラを渡します。オーバーレイモードならnullにします。localPointには結果を取得するための変数を渡します。これで得られたlocalPointを設定したいUIのRectTransform.localPositionに設定すると完成です。

    UI同士を連携したい場合
    UIのCanvasが異なるなど単純には位置を求められない場合もスクリーン座標を介することで位置を連携することができます。
    あるUIの位置がスクリーン座標でどこになるかが分かれば良いことになります。これはRectTransformUtility.WorldToScreenPoint(Camera cam, Vector3 worldPoint)を使うと可能です。なぜかこれについてはドキュメントに載っていないようです。使い方は引数からわかるようにUIを表示しているカメラとRectTransform.position(ワールド座標)を渡します。
    スクリーン座標からUIの座標を求めることは既に述べたので、これでどちらにも変換ができます。


    UIのもつ座標→スクリーン座標とその逆であるスクリーン座標→UIのもつ座標の変換方法があれば自由に位置を調整できるということになります。
    • UIのもつ座標→スクリーン座標はRectTransformUtility.WorldToScreenPoint
    • スクリーン座標→UIのもつ座標はRectTransformUtility.ScreenPointToLocalPointInRectangle
    を使うことで可能です。
    注意点はピボットの位置がRectTransformの位置である(localPositionとかはピボットの位置を表しているということ)ということです。変換を行うときに微妙に位置がずれるときはピボットの位置がセンターだったり、トップだったりと統一がされていない可能性があります。

    意外とありそうなミスとしてはアクティブでないUIの座標を取得してしまうことです。このときの座標は正しくないようなので、起こりやすい間違いです。 これは消していたいUIの座標を取りたいという時に困るのですが、どうしようもないようです。

    以上のような変換はスクリプトで制御したい場合に必要になることが多いでしょう。Canvasの異なるUI同士の座標をそろえたりする機能が今のところなさそうなので、こういった方法が要ると思っています。
    もっと簡単な方法があると良いのですが…… 

      このエントリーをはてなブックマークに追加 Clip to Evernote
    多くのゲームでは対戦相手がいるはずで基本的にはその行動をプログラミングしなければいけません。この行動処理をゲームではAIと呼んだりします。

    実のところAIは考えているわけではなく、決まった処理を行っているだけです。ルール上決まった行動を自分の置かれた状況に合わせて実行することで考えているように見えるのです。状況というのはゲーム内で知れる情報の集まりです。自分の持っている手札であったり、すでに捨てられたカードが何かといったものです。イカサマがありなら、本来知りえない情報も追加できます。(個人的にはつまらないのでやめた方が良いと思いますが、強くするのが簡単でしょう。)
    状況が決まったら、あとはひたすら状況ごとにどうするかを書いておけば良いです。大富豪とかなら、自分の番であり最後の一枚を持っていて出せる状況であれば、とにかく出すべきです。そういったことをプログラム的に表現していくと大量のif文とswitch文によって場合分けしていけば良いでしょう。
    この場合分け(状況の種類)が多くなると、細やかな対応が可能なためAIがより人間らしく強くすることができます。場合分けが少ないと同じ行動を取りやすくなるので、なるべく状況を細かく分けるのが良いです。

    上に書いたことは言うのは簡単ですが、やるのは非常に難しいです。まずゲームのルールを熟知しなくてはなりません。どのようにしたときが最も良いのか、どうすることが悪いのかがわからなければ勝つための行動を作ることはできないからです。 
    特にゲームの序盤などは情報が少ないためにどういった行動をとるべきかは作り手の考えに大きく左右されることでしょう。終盤は取れる選択肢自体が少なくなることが多いので、そこまで悩むこともないはずです。

    こういったAIは固定された行動をとります。処理は早いし、プログラムの更新でAIが変更できるのが利点です。現在までのゲームではほとんどのゲームがこのような方法で作られています。

     

      このエントリーをはてなブックマークに追加 Clip to Evernote
    今年はAndroidだけでなくiOS向けにアプリをリリースしようと考えています。そのためにはMacが必要です。初めて買うので、使い道の多そうなノート型MacBook Proを買おうと思っています。
    すぐ欲しかったのですが、どうも新型の発売が近いようで少し様子見をしているところです。

    またiOSの実機での確認のため、iPod Touchを買おうと思います。iPhone 6が一番普及している端末でしょうが、ちょっと高いしすぐ7とかが出そうなのでしばらくはiPhoneは買わないつもりです。今使っているiPodが8GBだったので、32GBで十分だと思っています。

    2つ合わせると、20万円は超える程度のお金はかかりそうです。機材もそれなりにしますが、Apple Developer Programへの参加も1年ごとに登録料がかかります。
    色々と難しいところがありますが、日本でのiPhoneの使用率を考えると無視できない規模だと思います。早いうちにiOSの対応ができることが今年の目標でもあります。

      このエントリーをはてなブックマークに追加 Clip to Evernote
    以前、同じ内容で記事を書いたのですが、より良い方法がUnity5.3では行えるようです。

    rn-custom_coroutine
    Unity5.3で新しく使えるようになったカスタムコルーチンというものを使います。 公式の説明を見るとCustomYieldInstructionクラスを継承して、keepWaitingプロパティのgetをオーバーライドすれば新しいyieldオペレーションが作れます。
    yieldオペレーションとは、yield return ~とするときの~の処理のことを言っているのだと思います。(この記事ではそうだと思って書くことにします。)
    keepWaitingがtrueであればyieldオペレーションが処理を返さず継続し、falseになると処理を抜けます。このプロパティにDebug.Logを仕込んだところ毎フレーム呼ばれていたので、コルーチンで無限ループ内にyield return 0;というような書き方で行うのと同じと考えて良いでしょう。

    以前の方法のあまり良くない点は、処理をクラス内に書いていなければいけなかったため、あるクラスのstaticメソッドにするかクラス内での利用しかできないようになっていたことです。色々なところから自由に呼び出すということを考えると、その処理は独立した1つのクラスになっている方が見通しが良いのでそうすべきだと思っていました。
    メソッドに処理がある場合は、呼び出し方がStartCoroutineを介するというのもいまいちだと思います。StartCoroutineを使うと、渡すパラメータの個数の制約があること、わずかにコードが増えること、文字列での呼び出しだとエディター上で編集しにくいことが良くないです。
    新たな方法では導入が手間ですが、その後の作業を減らしてくれるため良い方法だと思います。WaitUntilやWaitWhileを使っても同じことができますが、よくある同じ処理をいちいち書くのは無意味なので、以下のようにカスタムコルーチンを作りました。

    上のソースは、ある時間処理を待たせるがスキップも可能であるというyieldオペレーションになります。使い方は
    yield return new SkippableWaitForSeconds(10, () => Input.GetMouseButtonUp(0));
    のようにします。この例だと10秒待つ処理であり、もしその間にマウスの左ボタンが上げられたらスキップするということになります。
    スキップするかの判定を外から渡せるため、色々と使えるようになっています。

      このエントリーをはてなブックマークに追加 Clip to Evernote
    12月のPVは4753でした。
    2015-12pv


    先月とほぼ同じですが少し増えました。年末の閲覧数の低下を考えるとそれなりに増えたように感じます。いまだにUnityの始め方的な記事の方が人気を集めているので、なんとかゲームを作る過程の話とかここだけで取り上げている珍しい話とかの記事が人気にならないかと思ったりします。

    正月ということで初旬はあまり大きな活動ができないとは思いますが、「一年の計は元旦にあり」と言いますしどうするか考えるのが最も重要だと思います。

    ナポレオンという個人的に好きなトランプゲームを題材にしたゲームが昨年最も成果を出したこともあり、トランプゲームのアプリを本年も出そうと思っていました。自分があまり知らないゲームでも面白そうなものやアプリ向きだと思うものを作っていき、どうなるかを試してみたいです。
    1つだけではそれが成功なのか判断しにくいし、単なるまぐれかもしれません。似たような方向性で2つ成功すればそれはかなり良い方法なのだと言えると思います。
    とりあえず作ってみたというのではなく、このアプリを出す意味は何かということを考えていくつもりです。 

    今年もよろしくおねがいします。 

    このページのトップヘ