NinaLabo

個人ゲーム開発者の技術メモ

【C#】三角関数で2点間の線の長さと角度を計算する

下記のようなスキルツリーのミニマム版みたいなものを実装しているのですが、ボタンとボタンを繋ぐ線の長さと角度は計算して配置しています。

f:id:ninagreen:20161218030829p:plain

特定の2点間を線でつなぐのを Unity でどう書けばいいのか、いつもやりかたを忘れてしまうのでまとめておきます。

2点間の線の長さ

下記のような直角三角形があるとして、 

f:id:ninagreen:20161218035038p:plain

C^2 = A^2 + B^2 なので、

斜辺Cは、C = {\sqrt{A^2 + B^2}} で求められます。

 Unity で書くとこんな感じですかね。Powは累乗、Sqrtは平方根です。

float diffX = toX - fromX;
float diffY = toY - fromY;

float width = Mathf.Sqrt (Mathf.Pow (diffX, 2) + Mathf.Pow (diffY, 2));
lineTransform.sizeDelta = new Vector2 (width, lineTransform.sizeDelta.y);

lineTransform は、幅が1pxの画像のTransformです。

2点間の角度

同じく以下の直角三角形があるとして、

f:id:ninagreen:20161218035538p:plain

tanθ = B/A なので、

角度は、θ = tan^{-1}(B/A) = atan(B/A)

で求められます(あってるかな...)。atanはアークタンジェント(逆正接)です。高校ぐらいで習ったような気もしますが、使わないと忘れますね。

Unity だと atan を求める関数として、 Mathf.Atan と Mathf.Atan2 の2個用意されているのですが、そもそも atan は -π/2〜π/2 までの制限があり、xが正の値と負の値で区別がつかなくなってしまうので、360度で計算するときは Atan2 のほうが便利らしいです。

Unity のコードだとこんな感じ。Atan2関数は、第一引数がyで、第二引数がxです(これよく間違います...)。あと、yの値は上がプラスで下がマイナスなので別の座標系の場合は変換する必要があります(これもよく間違います...)。Atan2で求められる角度の単位はラジアン(Radian)なので Mathf.Rad2Deg で掛け算して、度(Degree)にしています。

float diffX = toX - fromX;
float diffY = toY - fromY; 

float radian = Mathf.Atan2(diffY, diffX);
float degree = radian * Mathf.Rad2Deg;
lineTransform.eulerAngles = new Vector3 (0, 0, degree);

 

ローグライクゲーム制作を振り返って(2016年)

2016年もあと少しで終わりですね。少し気が早いかもしれませんが、2016年のゲーム制作を振り返ってみようと思います。

3. プレアルファ(Pre-α)前半(2016/1〜2016/4)

キャラクターが3Dになりましたね。あと、当初はキャンディクラッシュみたいに縦横両対応にしようと考えていたのですが、縦画面のみにしました。仕様変更でUIを変更するたびに縦画面でも横画面でもチェックしないといけないのが、想像よりも工数がかかったのでやめたのですが、今振り返ってもやめてよかったと思ってます。個人開発の場合は全体的に工数が足りないので、ゲームを面白くするところ以外はどんどん削っていかないと完成しませんね。

もう1つ大きな改善点としては、コントローラーボタンを押してキャラを動かしてたのですが、行きたい場所をタップしたら目的地に向かうように変更しました。スマホで快適にローグライクゲームを遊ぶにはどういうUIにするのがいいのか、試行錯誤しながら色々悩んでいた時期でもあります。

youtu.be

4. プレアルファ(Pre-α)後半(2016/5〜2016/12)

 今年の夏ぐらいはモチベーションが落ちて開発が止まっていたこともあったので、日数のわりにあまり進捗しませんでしたね(本当はもうアルファぐらいまで出来てる予定でした...)

操作方法やUIの配置が固まってきたのがこの時期です。フリックでマップをスクロールさせたり、ピンチインアウトで拡縮したり、獲得した道具は下に並べて見やすくしたり、通路は自動でダッシュするようにしたりしました。モンスターも40種類、アイテムも60種類ほど実装して、問題点はありつつもダンジョンで一通り遊べるようになってきました。

あと大きな点として、データの自動セーブと途中再開の実装をしました。結構ゲームを作っちゃったあとに保存と再開の仕組みを入れたのですが、これが想像以上に大変で1ヶ月以上はかかっちゃいました.... 

ダンジョン外の実装にも着手しました。街を導入し、NPCを配置し、会話できるようにして、簡単なクエストも入れました。当初はシンプルにダンジョン部分だけ実装してリリースしようと思ってたのですが、作ってるうちにやりたいことが増えちゃいましたね。これが吉と出るか凶と出るかは結構不安なところではあります。

www.youtube.com

関連記事

2015年の振り返りはこちらから

ninagreen.hatenablog.com

 

ローグライクゲーム制作を振り返って(2015年)

2016年もあと少しで終わりですね。少し気が早いかもしれませんが、ここまでのゲーム制作を振り返ってみようと思います。

2016年を振り返る前に、2015年を振り返ってなかったので(汗)、まずはプロジェクトの初期の頃をまとめました。

1. 潜伏フェーズ(〜2015/9)

本格的にゲームをつくりはじめたのは、2015年9月からでした。それまでも、Objective-Cでローグっぽいものを途中まで制作したりしていましたが、挫折してエターナったりしていまして....いい加減何かちゃんと作ろうと思い始めたのがこの頃です。

この時点ではダンジョンマップの自動生成、キャラの移動、フロアの移動が実装されているだけですね。まだまだゲームと呼べるものではなかったです。

youtu.be

今振り返っても、このシンプルなビジュアルは嫌いじゃないですね。ただ、このビジュアルだと敵のモンスターのバリエーションを出すのが大変だということに気づき、後にキャラは3Dボクセルで置き換えることになります。

2. プロトタイプフェーズ(2015/9〜2015/12)

見た目はあまり変わってませんが、モンスターに攻撃したり、アイテムが使えるようになったり、レベルアップしたり、死亡したり... 

結構バグはありつつも、ダンジョンの基礎部分の実装がされてます。

youtu.be

プロトタイプフェーズで実装した内容を下記に書き出しました。すでに結構な実装量なんですよね。昔パズルゲームを作ったことがありますが、それに比べてローグライクゲームはとにかく実装することがたくさんあるゲームだなと思った記憶があります。そしてこれだけ実装しても、まだゲームの面白さがわかるまでには至らないのかと思ったりもしました。懐かしいです。

・マップの自動生成/ミニマップ表示/階段でフロア移動/

・プレイヤー移動/向き変更/攻撃/通路でダッシュ/レベルアップ/HP自然回復/満腹度/足踏み/攻撃ミス

・モンスター配置/移動AI/攻撃AI/プレイヤー死亡

・アイテム初期配置/アイテム取得/装備/使う/投げる/置く/アイテム効果実装(草、パン、巻物)

モンスターハウス/突風(ターン数超過)/モンスター特殊攻撃(力下げ、睡眠、吹き飛ばし)

・アイテムドロップ/罠/状態異常実装

関連記事

2016年の振り返りはこちらから

ninagreen.hatenablog.com

 

Unity 5.5 にアップデートしたら TexturePacker の画像が崩れてしまう件

Unity を 5.3.6f1 から 5.5.0f3 にアップデートしたら、見た目がおかしくなってしまいました(左:BEFORE、右:AFTER)。

f:id:ninagreen:20161210032025p:plain  f:id:ninagreen:20161210031740p:plain

 川(水たまり?)の画像のエッジ部分がずれてしまってます。表示が崩れてしまった部分はTexturePackerで画像をまとめていた箇所でした。Unity Editor上で見ると、画像が正しく分割されてない(正確には何も分割されてなくて、パッキングした画像がそのまま出てしまっている)状態でした。

ネットで同じ症状の人がいないか調べても検索に出てこなくて、インポートし直したり、リフレッシュしてみたり、TexturePacker本体をアップデートしたり、Texture Packer Importer をアップデートしたりしてみたのですが、どうしても解決できず・・・

こうなったら Unity をダウングレードしようと思って 5.4.3f1 にしたところ、Sceneファイルを開こうとすると今度はUnityが落ちるようになりました。Unity 5.5 でセーブしたシーンは Unity 5.4 では開けないのでしょうか..

詰んでしまったようです... \(*T▽T*)/ワーイ♪

 

仕方ないので Unity 5.5 をもう1回ダウンロードしてきてインストール。プロジェクト直下にある Library フォルダと Temp フォルダを削除して、再度Unityを起動。

f:id:ninagreen:20161210040652p:plain

・・な、なおってるっ!Σ( ̄ロ ̄lll)

なぜ・・・なぜ・・・・

いや、なおって良かったんですが、すごく気持ちが悪いです... (_ _|||)

【Unity】Unity で ゲームデータをセーブするのに FlatBuffers を使ってみる(導入編)

永続化したいデータ(ゲームを終了しても残しておきたデータ)をどうやって保存するのが最適なのかはいつも悩みます。今開発中のゲームはサーバを使用しないつもりなので、データはローカル(端末)に保存するつもりですが、パッと思いつくだけでも色んな実装方法が考えられますね。

  1. PlayerPrefs に保存
  2. SqlLite に保存
  3. オブジェクトをJsonファイルに変換して保存
  4. オブジェクトをバイナリに変換して保存

今回は比較的大量のデータを高速で保存したかったので「オブジェクトをバイナリに変換して保存」を採用しました。今までは MessagePack を使ってオブジェクトをバイトデータに変換してたのですが、さらに速いと噂の FlatBuffers を使ってみることにしました。FlatBuffers は cocos-2dx や Facebook でも採用されているみたいです。

FlatBuffers のインストール

導入するまでが結構面倒です(そのうち改善されるとは思いますが..)

Windows だとexeファイルが用意されているようなので簡単そうですが、Macだとソースコードからビルドして実行環境を作らないといけません(*1

FlatBuffers のソースコードをダウンロード

下記の FlatBuffers の github に行って...

github.com

右側の 「Clone or download」からソースコード一式をダウンロード

f:id:ninagreen:20161007141957p:plain

ダウンロードしたファイルは解凍して適当な場所に置いてください。

CMake のインストール

CMake がインストールされてなければ、下記サイトへ行って...

Download | CMake

Mac用をダウンロード

f:id:ninagreen:20161007142626p:plain

ダウンロードしたファイルをダブルクリックしてアプリケーションをインストール。

CMake の実行

インストールした Cmake.app をダブルクリックして起動すると、下記の画面が立ち上がるので...

f:id:ninagreen:20161007142925p:plain

[Where is the source code] に 先ほどダウンロードしたFlatBuffersのソースコード(flatbuffers-master)を指定

[Where to build the binaries] には任意のフォルダを指定(ビルドしたファイルが格納される場所です。flatbuffers-build とか適当なフォルダを作成して選択すればOK)

Configure ボタンを実行するとこんな画面が...

f:id:ninagreen:20161007143358p:plain

赤くてびっくりしましたが、気にせずGenerateボタンを実行

f:id:ninagreen:20161007143526p:plain

下のウィンドウに Generating doneと出てれば完了。出力先に指定したフォルダに各種ファイルが生成されてるはず。

Make を実行

ターミナルを開いて、先ほど出力先に指定したフォルダに移動して

make

を実行!終わったら、

./flattests

を実行してみて、「ALL TESTS PASSED」と出力されればインストール成功!

 Unity で FlatBuffers を使用するための準備

スキーマファイルを作成

とりあえず動かすことが目標なので、UserData というテーブルの中にCoinNum変数があるだけの構造を定義しました。

namespace Rogue;

table UserData {
coinNum:int;
}

root_type UserData; 

これを UserData.fbs というファイル名で保存しました。公式のサンプルにならって拡張子を fbs (FlatBuffersの略だと思われる)にしましたが、中身は単なるテキストファイルです。拡張子を txt にしても問題なく動きました。

クラスを自動生成

バイナリデータをC#で扱うためのクラスファイルを、スキーマファイルから自動生成します。

./flatc -o [出力先のパス] -n [スキーマファイルのパス(ex: UserData.fbs)]

実行すると出力先のフォルダに UserData.cs が生成されるはずです。生成されたクラスは Unity のAsset フォルダ内の任意の場所に置いてください。

FlatBuffers ライブラリを Unity へインポート

github からダウンロードしたフォルダ(flatbuffers-master)のnetフォルダ配下にある FlatBuffers フォルダを Unity の Assetフォルダ以下へコピー。

実装サンプル

書き込み処理サンプル

バイナリデータを保存する処理のサンプルです。 Startを呼んで値を設定してEndを呼んで最後にFinishという流れで書かないとエラーになります。

// 事前に using FlatBuffers; が必要
FlatBufferBuilder fbb = new FlatBufferBuilder (1);

// 値を設定する前に Start を呼び出す必要があるみたい
UserData.StartUserData (fbb);

// コイン数を15枚で設定
UserData.AddCoinNum (fbb, 15);

// 値の設定が終わったら End を呼び出して..
Offset<UserData> offset = UserData.EndUserData (fbb);

// 最後に Finish すると バイナリデータが生成されるのかな
UserData.FinishUserDataBuffer (fbb, offset);

// 最終的にバイナリデータをファイルに書き出して完了
using (MemoryStream ms = new MemoryStream

    (fbb.DataBuffer.Data, fbb.DataBuffer.Position, fbb.Offset)) {
    File.WriteAllBytes(filePath, ms.ToArray());
    Debug.Log("SAVED !");

}

filePath には  

Path.Combine (Application.persistentDataPath, "UserData.bytes")

などを出力先のパスを設定してください。

読み込み処理サンプル

読み込みのほうが簡単ですね。

if (File.Exists (filePath)) {

    ByteBuffer bb = new ByteBuffer (File.ReadAllBytes (filePath));

    UserData userData = UserData.GetRootAsUserData (bb);
    Debug.Log ("## user coin num = " + userData.CoinNum);
}

あとがき

導入の手軽さで言えば、MessagePack のほうが圧倒的に簡単ですね。JSONで出力してて遅いなと思った時は MessagePack に簡単に移行できます。シリアライズの実装も MessgePack だと1行で済むところが、FlatBuffers だと スキーマファイルを作成して、決められた順序でデータをセットしなきゃいけないので(子要素がある場合は子要素から順番にシリアライズしないといけないとか)、開発コストがかかりそうです。

MessagePack もそこそこ速いので、データ量が多くなければ速度差はそこまで気にならないかもしれないですね。ただ、MessagePack だとオブジェクトを丸ごとシリアライズして保存するので保存ファイルに定義データが含まれるのですが、FlatBuffersだとスキーマが別ファイルなので、ファイルサイズが小さくて済みそうです。

あと、FlatBuffers は生のバイナリデータを持ったまま、必要な時に必要な分だけパース処理をするので、大量にデータはあるんだが実際に使用するデータはごく一部の場合は、FlatBuffes のほうがかなり速くはなりそうです。

 

参考資料 

 C# での FlatBuffers を使う流れが解説してあります。

qiita.com

運用面での考察が興味深いです。

qiita.com

英語ですけど、1番わかりやすかったです。

exiin.com

FlatBuffers が何故速いのか、とても参考になりました。

qiita.com

*1:後から知ったのですが、Homebrewでもインストールできるみたいです。こっちのほうが簡単だったかも。

rwinslow.com

【Unity】MagicaVoxel のモデルに Blender でアニメーションをつけて Unity で動かす(前編)

以前の記事では、MagicaVoxel で3Dドットモデルを作成して、Unity に取り込んで動かすまでをやりました。

ninagreen.hatenablog.com

実際には、3Dドットのボクセルモデルに攻撃モーションなどのアニメーションをつけたいので、MagicaVoxel でエクスポートしたオブジェクトをそのまま Unity に取り込むのではなく、一旦 Blender 取り込んでアニメーションを追加してから Unity にインポートする方法を試してみることにします。

Blender の インストール

下記のサイトからダウンロードします。

www.blender.org

私の場合は Mac なので、

Blender 2.77a for Mac OSX

のZipをダウンロードしました(2.77a は 執筆時点での最新版)

ダウンロードしたZipファイルを解凍して、アプリケーションフォルダなど任意のフォルダに置けばインストールは完了です。フォルダ内の Blender.app をダブルクリックすれば、Blender が起動します。

MagicaVoxel のモデルを Blender にインポート

不要な立方体を削除する

Blender を起動すると、デフォルトで立方体が作成されるので削除しておきます。立方体を左クリックで選択して(選択しても反応があまりないので不安になりますが、オレンジの枠で囲まれてたら選択されてます)、x キーを押すと下記のような確認ダイアログが表示されるので Delete をクリックします。

f:id:ninagreen:20160921191002p:plain

ショートカットキーを覚えられないという方は、右上に Unity でいうHierarcy Viewみたいな小さなウィンドウがあるので、そこからでも操作できます。立方体オブジェクト(Cubeという名前になってます)を選択後、右クリックして Delete を選択しても削除できます。

f:id:ninagreen:20160921192708p:plain

MagicaVoxel のデータをインポート

  1. File > Import > Wavefront (.obj) を選択
  2. MagicaVoxel で エクスポートした objファイルをダブルクリック

灰色のかなり大きい(?)状態で、モデルが Blender にインポートされました。(マウスのホイールで視点の拡大縮小ができます)

f:id:ninagreen:20160921191630p:plain

モデルのサイズを小さくする

モデルを選択した状態で s キー(左のToolタブのScaleボタンでもよい)を押してマウスを動かせばモデルのサイズを変更できます。Scale値を直接入力したい場合は、その状態で数値を入力しEnterを押してください。例えば、0.2 と入力してEnterを押せば 20% の大きさになります。実行後は、左下の Resize の Vector が すべて 0.2 になっているのが確認できます。

f:id:ninagreen:20160921194357p:plain   f:id:ninagreen:20160921194400p:plain

テクスチャーを設定 

下のほうの丸いアイコンを選択して、テクスチャを選択すると色が付きます。

f:id:ninagreen:20160921195048p:plain  f:id:ninagreen:20160921195109p:plain

ライトの設定

顔にライトが当たってなくて暗くなっているので、ライトの位置を調整します。右上のHierarcy から Lamp を選択。デフォルトではかなり遠くにあるので、マウスホイールで視点を縮小してください。

f:id:ninagreen:20160921195907p:plain

左下にある浮き輪みたいな丸は関係ないのでご注意を。(最後に選択した位置を表してるだけっぽいです)Tool の Translate ボタンを選択してマウスを動かせば位置を移動できます(見えやすくするだけなので適当な位置で大丈夫なはず)

f:id:ninagreen:20160921201419p:plain

ファイルをセーブする

一度ファイルを保存しておきましょう。File > Save で 場所とファイル名を設定して、Save Blender File を押せば完了です。

Unity に取り込む

慣れないツールで疲れたので、まだアニメーションはつけてないですが、一度 Unity にインポートして動作確認することにしました。

1. File > Export > FBX (.fbx) を選択

2. 左のサイドバーの Selected Objects にチェックをつける(チェックしないと Cameraや Lamp オブジェクトも一緒にエクスポートされてしまいます)

3. Scale の値を 100 に変更(100にするとBlender上での座標値1とUnity上での座標値1が同じになるそうです)

f:id:ninagreen:20160921221716p:plain

4. 任意の場所を設定し、右上の Export FBX ボタンを押します。

5. エクスポートした FBX ファイルを Unity にドラッグ&ドロップ

6. Materialフォルダが自動的に生成されるので、中にあるマテリアルのテクスチャ画像を設定 

f:id:ninagreen:20160921222927p:plain

 

無事、インポートできましたー!

f:id:ninagreen:20160921225117p:plain

 

あとがき

Blender の UI や操作が独特で、慣れるまで時間がかかりそうです。また、MagicaVoxel でモデルを変更したら、1回Blenderに取り込んでから Unity に取り込まないといけないので、モデルの微調整する場合に手間がかかりそうです。でも、無料で提供してもらえるのは本当に有難いことですし、もう少し使ってみようかなと思います。とりあえず、次の後編ではアニメーションをつけるところまでいきたい!

追記:後編書きました!

ninagreen.hatenablog.com

参考記事

b00.sakura.ne.jp

github.dev7.jp

semakimomo.net

【Unity】マルチタッチの開発に役立つ Unity Remote

ピンチイン、ピンチアウトで拡大縮小する処理を Unity で実装する際に、いちいちビルドして実機に転送して確認だと開発効率が悪いので Unity Remote を使ってみたのですが、結構使えたので導入手順を記載しておきます。

Unity Remote を使えば、Unity Editor 上の画面とデバイスの画面が同期されるので、ソースコードを修正したらデバイスですぐに確認することができます。マルチタッチだけではなく、加速度やジャイロなどの端末固有の入力処理を開発するときに使えそうです。

導入手順(思ったよりも簡単でした)

1. iOSの場合、App Storeから Unity Remote 5 をインストールする

Unity Remote 5

Unity Remote 5

  • Unity Technologies ApS
  • ユーティリティ
  • 無料

2. PC と 端末 を ケーブルで接続する

3. Unity の メニューから Editor > Project Settings > Editor を選択する

4. Editor Settings のインスペクタで、Unity Remote の Device を 接続した端末に変更する

5. 端末にインストールした Unity Remote アプリを起動する

6. Unity の再生ボタンを押す

注意点

Unity Remote は便利だったのですが、マルチタッチの場合に TouchPhase.Ended の入力が取れないようです。

TouchPhase で 判定しないように書くこともできるみたいですが、今からそのために入力処理を書き換えるのは避けたかったので、最悪、End(手を離した)イベントが受け取れなくても致命的なエラーにならないようにすることで対処しました。

forum.unity3d.com

forum.unity3d.com

Unity3D:タップ操作の監視(領域指定付き) - devlog [naru design]

参考記事

qiita.com