2019年1月31日木曜日

gccで指定したアーキテクチャのバイナリをコンパイルする方法



自作エミュレータで学ぶx86アーキテクチャ コンピュータが動く仕組みを徹底理解!
という本を買って、はじめの部分を読んでいると実機と本とで出力される内容が違った部分にいきなり出くわしたので、その解決法をメモしていく。

注意点


原因はこちらが使っているCPU(x86_64)のアーキテクチャが本が想定しているもの(i386)と違うのが原因なので、本が誤っているわけではないので注意!


解決法


gccとldそれぞれにi386で処理してくれとオプションを指定することで解決できた。

gcc -c -o xxx.o input-file.c ..なんか色々なオプション.. -m32 -fno-pie
ld ..なんか色々なオプション.. -m elf_i386 --oformat=binary

GCC

gccのオプション-m32を指定することで、32bit環境のコードを生成してくれるようになる。
-m32のドキュメントはこちら

ただこれだけだと、 ldコマンドで

undefined reference to `_GLOBAL_OFFSET_TABLE_'

とエラー起きたので、 -fno-pieも追加で指定する必要がある。

gccはデフォルトでposition-independent executables (PIE)と呼ばれるプログラムコードが実際に動作するPC上のメモリの好きなところに配置されても正しく実行できるようにしている。

が、その分余分なコードを生成するのだが、今回は勉強のためなのでそのような仕組みはいらず、-fno-picを指定して上げる必要があった。

ld

ldでも-mオプションでエミュレートしたい環境を指定する。指定できるものはld -Vで確認できる。

今回は32bit環境なので、ld -Vにあったelf_i386を指定した。

--oformatオプションは出力されるオブジェクトファイルのバイナリフォーマットを指定するものだ。

指定できるものはobjdump -iで確認できる。binaryは何でもいいよ的なもの。



2019年1月26日土曜日

Git コミットの内容を分割して、コピー&ペーストする

作業をしていて、他のブランチでコミットした内容を使いたいという状況に陥った。
masterにあればいいのだがないので、なんとかして取り出したい。

さらに取り出したい内容は一つのコミットに色々な作業内容を含めたままプッシュしてしまっているときた。

 今までだと、諦めて作業を進めていたが、Gitは便利なもので他のコミットの内容をコピーできたり、コミット内容を後から分割できることを知ったので、そのやり方をメモしていく。

 参考サイト
gitで他ブランチの特定のコミットを取り込む方法
gitで1つのコミットを複数のコミットに分割する

コミットから取り出したい内容を分離


まず、取り出したい作業内容をコミットから分離する。

取り出したいコミットをする前の状態に戻る。
git reset <分離した作業内容があるコミットの一つ前>
あとは適時作業内容を分割してコミットしていき、取り出したい作業分をまとめたコミットを作成する。

git rebaseを使った方法もある。上のやり方は直前のコミット内容を分離したい時には便利だが、もっと昔のものとなると大変なので、そのときはgit rebaseを使用する。


Gitで数個前のcommitを遡って分割する


 git cherry-pick

次にgit logを使って取り出したいコミットのIDをメモしておく。

ここまで来たら、コミットのコピーを使いたいブランチに戻り、git cherry-pickを使う。

git cherry-pick <commit-id>

これで目的は達成できた。

2019年1月25日金曜日

git コミットの範囲を指定したPushのやり方。

gitでpushしようとしたときにプッシュしたくないコミットが出てきたので、うまいことそのコミットだけ除いてプッシュしたかったので、調べてみた。

参照仕様


Gitの公式ドキュメントの例にgit push origin HEADとあったので、じゃあHEAD~でひとつ前のコミットを省いてプッシュできるのかなと思ったら以下のようなエラーが起きた。

 remote part of refspec is not a valid name in HEAD~

HEAD~はrefspecのリモート部分では有効な名前ではないという英文で、悲しいかなHEAD~は使えないようだ。

git push origin HEADのHEADの部分はrefspec(参照仕様)を指定する部分だそうで、HEADはローカル環境の最新のコミットではないみたいだ。

参照仕様は+<src>:<dst>で表記される。

push時に参照仕様を使う場合は以下のようになる。

git push origin master:refs/heads/master
# こんな感じの意味になる。

git push リモート名 リモート先のブランチ名:ローカルブランチの参照の名前
ちなみにプルのときはプッシュとは反対でローカルの参照名を指定してからリモートの方を指定する形になる。

git fetch origin master:refs/remotes/origin/master
#こんな感じの意味になる
git fetch ローカル名 ローカルのブランチ名:リモートブランチの参照名

うん、git pushではコミットを指定してプッシュすることができないようだ。

ちなみに全ての参照の名前を確認したいときはgit show-refを使うといいようだ。

ローカルのHEADをずらしてからプッシュ

git pushではできないことが分かったので、ローカルのHEADをずらしてやってからプッシュすればできるのではないかと考えたので、HEADのずらし方を調べてみる。

参考サイト

HEADがローカルの最新コミットを指していない状態をGitではDetached HEADと呼んでいるそうだ。

今回の場合はわざとDetached HEAD状態にして、プッシュを行う。

Detached HEADにする方法はいくつかあるみたいだ。


  • git checkoutを使う方法
  • git reflogを使う方法
  • git reset --hardを使う方法
  • git revert を使う方法


今回はgit reflogを使う方法を試してみた。

git reflogを使うとコミットしたものがメッセージと共に表示される。

表示されるコミットにはそれぞれHEAD@{X}とXに番号が割り当てられている。(最新のコミットが0であとは昇順に並んでいる)

それで、HEADにしたいコミットの番号を使って

git checkout HEAD@{X}

とコマンドを打つと無事Detached HEADな状態にできる。(git checkoutは最終的には使っている)

あとはプッシュしてやると、初めの目的であるコミットの範囲を指定したプッシュができる。

と思ったらできなかった。

fatal: You are not currently on a branch.
To push the history leading to the current (detached HEAD)
state now, use

    git push origin HEAD:<name-of-remote-branch>


どうやら、Detached HEADな状態ではプッシュする際は参照仕様を指定してあげる必要があるみたいだ。

エラーメッセージにコマンドの使い方を教えてくれているので、その通りに実行してみよう。

git push origin HEAD:master

これで無事プッシュできた。

最後に


あとは、HEADを最新コミットに戻してあげるのを忘れずにすればOKだ。

一度この操作を行うと、ローカルでの最新コミットにHEADを移しても、Detached HEADな状態とGitは見るみたいなので、同じ操作が必要になる。

だから、なるべく区切り良いところでコミットすることを心がけることが大事だとは思うが、うっかりミスをするのが常なので、リカバーできるようになると安心でしょう。


2019年1月22日火曜日

Travis CIのMatrixについて

Travis CIについて簡単に調べたので、その中のmatrixについてメモ

Matrixとは


複数のjobを実行する機能のこと。

これを利用すると、言語のバージョンや異なる環境でのテストを実行することができる。

実行したい環境を列挙していくと、その組み合わせの分jobが自動的に実行される。

# rvmとgemfile,envの各値を組み合わせた数のjobが実行される。
# 下のだと2x2x2の8jobが実行される。
rvm:
  - 2.5
  - 2.2
gemfile:
  - gemfiles/Gemfile.rails-3.2.x
  - gemfiles/Gemfile.rails-3.0.x
env:
  - ISOLATED=true
  - ISOLATED=false

# matrixを使って、jobの環境を直接指定できる。
# 以下は2つのjobが実行される。
matrix:
  include:
  - rvm: 2.5
    gemfile: gemfiles/Gemfile.rails-3.2.x #値は省略せずに書くこと
    env: ISOLATED=true
# - で一つのjob環境になる。
  - rvm
    gemfile: gemfiles/Gemfile.rails-3.2.x
    env: ISOLATED=false

基本的に上のコードの初めのやり方が簡単なのだが、一部の組み合わせは除外したいという場合も出てくる。 そのようなときはmatrix.excludeを使うと除外したい環境を指定できる。
# rvmとgemfile,envの各値を組み合わせた数のjobが実行される。
# 下のだと2x2x2の8jobが実行される。
rvm:
  - 2.5
  - 2.2
gemfile:
  - gemfiles/Gemfile.rails-3.2.x
  - gemfiles/Gemfile.rails-3.0.x
env:
  - ISOLATED=true
  - ISOLATED=false

# 以下、除外したい環境を指定する。
matrix:
  exclude:
  - rvm: 2.5
    gemfile: gemfiles/Gemfile.rails-3.2.x #値は省略せずに書くこと
    env: ISOLATED=true

#以下のように書くとrvmが2.5のものはすべて除外される。
matrix:
  exclude:
    - rvm: 2.5

基本はバージョンや環境を列挙していけばあとはTravis CIがよろしくやってくれる。 matrixは除外したい環境があるときに使うのが、一番やりやすい書き方と思う。


トピック matrix.allow_failures


失敗してもいい組み合わせがあるときはmatrix.allow_failuresを使って指定するといい。
デフォルトだとmatrix.allow_failuresを指定されたjobが失敗しても、その時点では終了とは見なされず、そのjobは最後まで実行され、余計な時間を取ってしまうことになる。
失敗したら可能な限り早く終了したとマークしたいときは、matrix.fast_finishをtrueにするといい。
# rvmとgemfile,envの各値を組み合わせた数のjobが実行される。
# 下のだと2x2x2の8jobが実行される。
rvm:
  - 2.5
  - 2.2
gemfile:
  - gemfiles/Gemfile.rails-3.2.x
  - gemfiles/Gemfile.rails-3.0.x
env:
  - ISOLATED=true
  - ISOLATED=false

# rvmが2.5のものはすべて失敗してもOK
matrix:
  fast_finish: true  # 失敗したら、可能な限り早くjobが終わったことを告げるためのパラメータ
  allow_failures:
  - rvm: 2.5

2019年1月12日土曜日

Direct3D12について雑記 その2 GPUへのコマンド発行

・GPUへのコマンド発行

DX11とは違い、DX12ではGPUへコマンドを発行するために使用するインターフェイスは増えている。

DX11ではID3D11DeviceContextのみでコマンドの発行を行っていたが、DX12ではそれを以下のものへ分割したものになっている。

  • ID3D12CommandQueue : 実際にコマンドをGPUに発行するもの
  • ID3D12CommandAllocator : コマンドの記録領域
  • ID3D12GraphicsCommandList : コマンドを記述していくもの

この中でID3D12GraphicsCommandListがID3D11DeviceContextと似たインターフェイスになっているので先に紹介する。


・コマンドを記述するためのもの ID3D12GraphicsCommandList


使い方はID3D11DeviceContextと変わりない。
シェーダの設定がDX12で大きく変わったので、ID3D11DeviceContextのVSSetXXX()やPSSetXXX()がなくなって、ID3D12PipelineState、ID3D12RootSignatureの設定に置き換わっている。

その一方でレンダーターゲットや深度バッファのクリアー関数、頂点バッファのバインドは同じように使える。
(ただしDX12でビューの仕様が変わっているので、そこは異なる)

変わっていない部分は以下のものになる。
  • Input-Assembler Stage (IA) : 頂点バッファ、インディクスバッファ、Primitive Topologyの設定を行う。
  • Stream-Output Stage (SO) : ジオメトリシェーダで出力するバッファの設定を行う。
  • Rasterizer Stage (RS) : ビューポート/シザー領域の設定を行う。
  • Query : GPUのタイムスタンプやSOステージの出力結果の情報、描画で実際に書き込まれたピクセル数などを問い合わせることができる。ただし、ID3D12QueryHeapで結果を受け取る記録領域をこちらで用意しないといけない。
  • リソースのクリアー、コピー : そのまま。コピーに関しては専用のID3D12CommandQueue/ID3D12GraphicsCommandListを作ることができる。詳しくは下の方で。
  • Draw/Dispatchコール : バリエーションは減っている。ただし、Indirect Draw/DispatchはExecuteIndirect関数に置き換わっていて、やり方は変わっている。

変わった部分は以下のものになる。

  • シェーダ/パラメータの設定 : ID3D12RootSignature/ID3D12PipelineStateを使って設定するようになっている。
  • Output-Merger Stage (MO) : 上と同じ。Blend StateやDepth Stencil StateなどはID3D12PipelineStateで設定することになっている。レンダーターゲットの指定は変わっていないが、ID3D12PipelineStateでそのフォーマットを決める必要がある。

    シェーダ/リソースの設定をID3D12RootSignature/ID3D12PipelineStateで行うようなった影響を受けている。

    これら二つでシェーダの設定を行うようになったことで、Graphics Pipelineの切り替えコストが減っている。

    ただ、その分、同じシェーダを使うが不透明/半透明の二通りで描画したい、加算合成で描画したいなど、ちょっとした状態の違いを持つものでも、すべて異なるID3D12PipelineStateを作る必要があるので、管理はめんどうになっている。

    上のようなケースだと余分に容量を使用したり、コンパイルの時間がかかってしまう問題があるが、ID3D12PipelineLibraryを使うことで軽減は出来る。ただ、あくまでコンパイルとデータ容量の削減をしてくれるだけで、そのバリエーションの分ID3D12PipelineStateを作り、その切り替えはこちらでする必要がある。

    新しく増えたものは以下のものになる。

    • Reset/Close : コマンドを記述する際は毎回Resetを行い、明示的にCloseする必要がある。
    • リソースのバリアー指定 : DX12では各Draw/Dispatch時のリソースの使われ方を指定する必要がある。GPU内のキャッシュの扱いに影響する。DX11ではドライバーが行っていた。

    ・ID3D12GraphicsCommandListの種類。

    ID3D12GraphicsCommandListには用途に合わせて以下の種類がある。
    • D3D12_COMMAND_LIST_TYPE_DIRECT : 全コマンド記録可能
    • D3D12_COMMAND_LIST_TYPE_COMPUTE : コンピュートシェーダとコピー関連のコマンドを記録できる。
    • D3D12_COMMAND_LIST_TYPE_COPY : コピー関連のコマンドしか記録できない
    • D3D12_COMMAND_LIST_TYPE_BUNDLE : 毎フレーム同じ内容になるコマンドをまとめて使いまわせるようにするときに使う。c++でいうプリコンパイル済みヘッダーみたいなもの。使えるコマンドに制約がある。ID3D12GraphicsCommandList::ExecuteBundle()で記録したコマンドを他のID3D12GraphicsCommandListに書き込むことができる。
    • D3D12_COMMAND_LIST_TYPE_VIDEO_DECODE/D3D12_COMMAND_LIST_TYPE_VIDEO_PROCESS : 動画関係のコマンドを作るときに使われるみたい。

    上三つが基本的な種類になる。
    D3D12_COMMAND_LIST_TYPE_DIRECTを使っていれば問題はない。
    ただ、GPUにはグラフィックスパイプライン用のキューとコンピュートシェーダ用のキュー、コピー用のキューを持ち、GPU(によって)はそれぞれ独立して実行できる。

    このキューの種類はID3D12CommandQueueの作成時に指定でき、効率的なアプリを作るなら、意識してコマンドを作る必要が出てくる。

    以上がID3D12GraphicsCommandListの簡単な紹介である。

    基本的な使い方の流れは以下のものになる。
    1. ID3D12GraphicsCommandList::Resetする
    2. GPUにやらせたいことを記録していく。
    3. ID3D12GraphicsCommandList::Closeで記述を終える
    4. ID3D12CommandQueueを使ってGPUにコマンドを伝える。
    ID3D12GraphicsCommandListはあくまでGPUへのコマンドの記録のみを行うものである。

    記録のみで実行はしないので、複数のスレッドで同時にGPUへのコマンドを作成することができるようなった。(DX11でもDeffered Contextを使えばできるが、暗黙のルールが多くDX12でそれらが明示的になった感ある。)

    ちなみにDX11のID3D11DeviceContextにはImmediate ContextとDeffered Contextの二種類あったが、ID3D12GraphicsCommandListはDeffered Contextと同じものだ。


    ・コマンドの記録領域 ID3D12CommandAllocator

    ID3D12GraphicsCommandListを作るときとリセットするときは実行したコマンドの記録領域となるID3D12CommandAllocatorが必要になる。

    一つのID3D12CommandAllocatorに対して複数のID3D12GraphicsCommandListが利用できる。
    が、スレッドフリーではないので各スレッドごとに一つのID3D12CommandAllocatorを作る形になる。

    ID3D12CommandAllocatorはResetしない限りメモリを延々と確保し続ける。気が付いたらテクスチャよりメモリを取っていたことも出かねないので、必要な分のコマンドを記録したらResetしないといけない。

    ただし、ResetはGPUがID3D12CommandAllocatorが確保したメモリを使っていないときにしかできない。つまり、ID3D12CommandAllocatorにコマンドを記録しているID3D12GraphicsCommandListの内容をGPUが実行しているときはID3D12CommandAllocatorのリセットはできないので注意が必要だ。

    また、ID3D12CommandAllocatorにもID3D12GraphicsCommandListと同じ数の種類がある。
    同じ種類のID3D12CommandAllocatorは同じ種類のID3D12GraphicsCommandListしか使用できない。

    ・GPUへコマンドを発行する ID3D12CommandQueue


    実際にGPUへコマンドを発行するにはID3D12CommandQueueを使用する。

    ID3D12CommandQueueは基本的にID3D12GraphicsCommandListを受け取り、GPUへ発行する役割をもつ。

    あとはタイムスタンプの取得、Reserved Resourceと呼ばれる仮想GPUメモリへのコピー/更新機能がある。

    ID3D12CommandQueueにもID3D12GraphicsCommandListと同じく種類があり、以下の3種類だ。
    • D3D12_COMMAND_LIST_TYPE_DIRECT : 全てのコマンドが使用できる。グラフィックス関係に使われるのがほとんど。
    • D3D12_COMMAND_LIST_TYPE_COMPUTE : コンピュートシェーダとコピー関連のコマンドを実行できる。使っているデバイスによってはグラフィックスパイプラインと同時に実行できるものがあり、非同期コンピューティングと呼ばれている。
    • D3D12_COMMAND_LIST_TYPE_COPY : コピーコマンドを実行できる。GPUとCPU間を高速でデータを転送するPCI Expressに最適化されている。
    使用しているデバイスによっては種類が異なるID3D12CommandQueueを同時に実行できる場合がある。この特性を生かさないとDX11より性能を引き出すことはできない。

    特にコンピュートシェーダとグラフィックスパイプラインを並列で動作させることを非同期コンピューティングと呼び、最適化する上で重要な意味を持つ。

    ただ、AMDのGPUが最初に対応した歴史から(GCNアーキテクチャから)、AMD以外のGPUでは思ったより性能が出ないこともある。NVIDIAもPascal世代(GTX10XX)以降から対応しているが、AMDのものよりかは効果は出ない。

    (NVIDIAはVR向けのSingle Pass Stereo機能を先に実装したりと、進化の方向が異なっているので、AMDと比べてどちらが優秀とは言えない。)

    非同期コンピューティングは使用しているデバイスの影響を受けやすいものであることは覚えておいた方がいい。



    以上でGPUにコマンドを発行するために使用するものについてみてきた。
    がこのままだと、GPUがいつ処理を終えたのかがわからない。

    なので、次はID3D12Fenceについて見ていく。

    ・同期処理


    GPUに発行した処理が終わったことを確認するにはID3D12Fenceを使用する。

    上記のインターフェイスを使うことでGPUにコマンドを発行できる。
    しかし、このままだとGPUがその発行したものをいつ処理し終えたかは確認することはできない。

    このままだと、どのタイミングで前フレームの描画が完了したかわからず、でたらめのタイミングでID3D12CommandAllocatorをリセットせざる終えない。

    いわゆる同期待ちができない状態である。

    そのためまだGPUが使っていないのにコマンドが消えてしまったというNULLポインターエラーっぽいバグが発生してしまう。(しかも、どのタイミングで起きるかわからないおまけ付きで)

    このような場合のためにID3D12Fenceが用意されている。

    同期待ちをしたいコマンドを記録したID3D12CommandAllocatorをID3D12CommandQueueで発行した後にID3D12CommandQueue::Signal関数にID3D12Fenceを渡してあげることで、同期待ちのタイミングを作ることができる。

    同期待ちにはWindowsAPIのWaitForSingleObject関数を利用する。

    そのためID3D12FenceはWinAPIのCreateEvent関数で作成したHANDLEと一緒に作成する必要がある。

    //ソースコード
    
    //ID3D12Fenceの作成
    ID3D12Fence fence;
    auto hr = device->CreateFence(initialValue, fenceFlag, IID_PPV_ARGS(&fence));
    HANDLE handle = CreateHandle(nullptr, FALSE, FALSE, nullptr);
    
    // 実行したいコマンドを作成
    
    ...
    commandQueue->ExecuteCommandLists(...);
    
    //同期待ちしたいタイミングを指定
    commandQueue->Signal(fence, nextValue);
    
    
    
    //同期待ち
    
    if (fence->GetCompletedValue() < nextValue) {
      auto hr = fence->SetEventOnCompletion(nextValue, handle);
      if (SUCCESSED(hr)){
        WaitForSingleObject(handle, waitMilliseconds/*-1でタイムアウトなし*/):
      } else {
        //エラー発生
      }
    }
    
    commandQueue->Signal()で同期ポイントを作る。

    GPUがこのSignal部分までコマンドを実行すると、指定したfenceの内部カウンターをnextValueに更新する。

    fenceの内部カウンターはID3D12Fence::GetCompletedValue()で取得できる。

    後は内部カウンターの値がnextValueになっていないか確認したら、ID3D12Fence::SetEventOnCompletion()とWaitForSingleObject()を使って同期待ちする。

    余談だが、commandQueue->Signal()はGPU駆動の同期待ちである。
    CPU上からID3D12Fenceを利用して同期待ちしたいときはID3D12Fence::Wait()を使うといい。

    ・ID3D12Fenceの同期待ちはカウンターを使ったもの


    ID3D12Fenceを使った同期待ちはUINT64型のカウンター一つづつ進めていくものになる。
    そのため、一回同期ポイントを作るたびに1つカウンターを進める処理になるため、桁あふれという限界がいずれ来る。

    なので、ある周期ごとにリセットした方がいいのではないかと考えるだろう。

    しかし、UINT64型なら60FPSで毎フレーム当たり1回同期しても、
    一時間当たり21万ほどのカウンタが進むのだが、一年たっても限界には程遠いので問題にはならない。よほど細かく同期しないと限界は来ないと考えた方がいい。


    ・ID3D12FenceはマルチGPU間での同期待ちにも使える


    ちなみにID3D12Fence作成時に渡すD3D12_FENCE_FLAGSによっては複数のGPU間の同期用のID3D12Fenceも作ることができる。


    2019年1月10日木曜日

    2018年振り返り

    平成も30年で終わりなのかと思っていたら、そういえば31年もあったなと最近実感し始めたこの頃。

    簡単に昨年の振り返りをしてみようと思う。

    1~3月

    退職して自宅で安静にしていた。何もしないのも暇だったので、伊福部昭について調べて動画を作っていた。2月の少しの間Vulkanを触っていたが、風邪をひいたっきり、そのまま放置している。


    4~5月

    どんな風の吹き回しか、raspberry-pi3でC++自作ビルドシステムを作っていた。
    watagashi-buildsystem

    実装にはBoostを初めて本格的に使用した感があった。
    コマンドライン引数のパースを行ってくれるboost::program_optionsは業務で使っていたが、ここで初めてBoost.Rangeと呼ばれるものに触れた。
    Boost.Rangeについての自分の認識は「次世代のループ文」、「フィルターを使ってリストから使いたいデータを振り分けられる便利なもの」という感じだ。

    for文だとあまりにも制約が少なすぎるため、コピーを行うfor文なのか、検索を行うfor文なのかどうかコードを読まないと判別できないという問題があるそうだが、Boost.Rangeを使えば、使用しているAdapterやAlgorithmで何をしているのかわかるという利点がある。その分、やりたいことができるAlgorithmとかを覚える必要があるのが大変だった。

    Githubに公開したのは5月の終わりごろ、慣れない英語でREADMEを初めて書いた。
    設定ファイルはJSON形式で記述できるようにしていた。


    6~7月

    自作のビルドシステムの設定ファイルにはJSONを使っていたが、実際使ってみると長ったらくなって書きづらいと感じたので、また気が狂ったのか独自言語を実装し始めた。

    英語を流暢に扱えるわけではないのに、英語そのままでビルド対象を記述できるよう目指した。なので、ほかの一般的な言語のパーサーで使用しているライブラリは使っておらず、苦労しながら実装していた記憶がある。

    データ記述言語を目指していたので、簡単なデータの宣言とリスト、オブジェクトの対応程度で収めようと考えていたが、OS間の差異を吸収しようとするとif文が必要になってきたり、関数、コルーチンを作り始めたりとだんだん収集が付かなくなって、中間言語を作るべきかと悩んだあたりで開発は中断している。

    ちなみに文法はこんな感じ。(GithubのREADMEがJSONを使っていた時のままだ…)
    for文はない。

    8~10月

    漢字を題材にしたゲームを作り始める。
    当初はテトリスっぽいものを目指していたが、作業量の多さに疲弊して、なんとか自動でデータを生成できないかと画像処理を利用したツールを作ったりなんやりしていくうちに迷走。9月末にはSteamに出すと思いながら、プロトタイプができたのは10月末当たり。作ったツールも特定の漢字で1時間ほど処理がかかるというほぼフリーズに近い欠陥が見つかり、プロトタイプも面白いのかと疑念がわき断念。

    ちなみにニコニコ動画に進捗動画を公開している。

    ただ、10月末当たりにボイロゲームジャムという私的なイベントがあると知り、それに参加。期限は2週間ほどで、ドスン!というゲームをUnityroomに公開した。
    楽しめたのだが、ゲームを作りきるのもなかなか大変だなと感じた。


    11月

    ゲームを作り切るという経験がないことに気が付いたので、簡単なミニゲームをいくつか作ってUnityRoomに公開していった。公開した中で、一筆工場というゲームは上の漢字を題材にしたゲームを作るための技術的な確認をするために作ったゲームだが、これだけでも割と遊べそうだなと思う。ただイラストやシナリオといった要素を作る能力がまだないことも実感した。

    12月の前半

    Unity 2D Challengeというコンテストにゲームを投稿すべくナナイロスクアロというゲームを作成する。期間は2週間ほど。UniRxのObserverを初めて使った。

    ここでもビジュアル的要素の魅力がかけている、他のゲームと見比べるとどうしても見劣りしてしまうなと感じた。

    ただ、今回は4ステージ程ではあるが、遊んでいる人のことを考えてレベルデザインしていったのはいい経験になったと思う。(実際にどれくらい効果があったのかはわからないが)
    それに作っていて楽しかったので、それでよしと、期間内に作りきったと思えたのが良かったと言える。


    12月の後半

    Web周りについて勉強をし始める。
    HTML,CSS,JS,Ruby on Railsと今までやってきていなかったことを勉強でき知識の幅が広がったと思う。

    最終的にはVue.jsを使って、ポートフォリオページを公開できるところまでした。

    今後、実際にゲームを公開するにあたって、紹介ページを作ることができるようになったのは非常にプラスだと思う。

    ちなみにちょっとした隙間に第二回ボイロゲームジャムに4時間ほど作ったゲームを公開した。
    もっと速く作れるようになるとは思うが、作って公開できるところまでもっていく力が少しはついたのかなと思う。


    あとがき

    振り返ってみると、やったことにかなり脈略がない+作ったものほぼ途中で放置しているという印象を受ける。

    今年は何をするにもやりきることを目標にしたい。

    • 上手なデザイン/シナリオを作れるようになる。(ゲーム制作)
    • オンラインゲームを作って公開する。(ゲーム制作)
    • FireBaseについて勉強する。(サーバー, ゲーム制作)
    • DX12についてまとめてBlogに公開する。(これまでの活動のまとめ)

    これらを目標に行動していきたい。







    2019年1月7日月曜日

    Unity Project Tinyのドキュメントを読んだ。

    前々から興味があったので、ドキュメントを読んで軽くまとめる。

    サンプルとか見て思った感想は、処理部分がHierachyビューの方にあるので初めは戸惑ったが、慣れるとコードが散らからずいい感じになるんじゃないかなと。ECSなのでよく考えてから作る必要があると感じた。

    Entity

    いわゆるデータ型みたいなもの。GameObjectのパラメータ部分になる。
    制作物のビルドブロックの単位となる。
    何か処理を行いたときは後のコンポーネントを使う。

    Entity Group

    Tiny Projectに所属するもの。好きな数のEntityをグループ化できるもの。 Entity Groupを使うことで階層構造内のEntityをアレンジできる。 EntityGroupはTransform階層と同じものを用意している。 複数個プロジェクト内には配置できる。 その際は実行時にLoad/Unloadされる。 プロジェクトにはAssetのように格納される。(拡張子は.utdata)

    プロジェクトに存在するEntityGroupのひとつは必ず、Startup Groupに指定しないといけない。Startup Groupに指定されたEntityGroupは起動時に自動で読み込まれる。 指定されていないものは実行時に要求されたときに読み込まれる。

    Components

    Components build-inとcustomの2種類ある。 UnityのGameObjectと似てはいるが Entity-Component-System(ECS)パターンで操作されるので違うものである。
    (ちなみにコメント的な説明文が書けるのはちょっと嬉しい。)

    Prefabs

    Unityのものと似ているが、すべての機能をカバーしてはいない。
    カバーしている機能は以下のもの

    • Instanceで変更した部分をPrefabに反映する(Inspector上のApply/Revert)
    • プロパティ/コンポーネント/Entityの上書き


    Building

    Playボタンを押すとビルドされ、そのまま動作をブラウザ上で確認できる。
    単にビルドするときはTiny ProjectのインスペクターにあるBuild Configurationセクションからできる。

    Scripting

    いくつか種類がある。

    ut.ComponentSystem

    Entityデータを処理する関数. Entity Filtersと組み合わせて使うと便利。 同じ条件を持つものの共通処理とかに向いている。
    ut.ComponentSystemを継承することで自由にカスタマイズできる。

    Fence

    スケジュールシステムによって使われる空っぽのノード。 ut.Sharedに全てのFenceは存在する。
    現状、以下の種類がある

    • InputFence
    • UserCodeStart
    • UserCodeEnd
    • RenderingFence
    • PlatformRenderingFence


    Entity Filters

    与えられた範囲からEntityを抽出したり、フィルタリングする。(Reactive Extensionsっぽい)
    ut.EntityFilterから派生させることでカスタマイズできる。
    Systemがこれを使い処理を行いたいモデルを抽出する。

    Behaviours

    ut.ComponentBehaviour及び、その派生先のこと。 MonoBehaviourのようなもの。 OnEntityEnable, OnEntityUpdate, OnEntityDisable関数をオーバーライドできる。 が、OnEntityUpdateはut.ComponentSystemで行った方がECS的に最適。
    ut.executeAfter, ut.executeBeforeデコレータで実行順序を制御できる。
    けれど、システムやフェンスの順序を制御すことはできない。

    Entity Command Buffers:(Advanced Topics Low-level)

    EntityCommandBufferを使うことでコマンドを変更したものを作ることができ、あとでWorldにコミットすることができる。 コマンドバッファにはentityの作成/削除、コンポーネントの追加/編集/削除が記録できる。

    tsconfig.json:(Advanced Topics)

    Unityのプロジェクトフォルダーに作られる(Tinyプロジェクトのフォルダーではないので注意) 変更したいときは、tsconfig.override.jsonをTinyプロジェクトがあるフォルダーに作る必要がある。 tsconfig.override.jsonとtsconfig.jsonの内容をマージしたものが最終的には使われる。

    2019年1月3日木曜日

    Vue.js その3

    前回に引き続きVueガイドを見ていく。

    トランジション

    CSSトランジェクションというCSSから状態の変化に応じたアニメーションを制御できるものがあって、Vue.jsでももちろん利用できる。利用したいときはtransitionタグで囲む。
    <transition name="fade">
      <p>トランジションさせたい要素</p>
    </transition>
    
    もちろんこのままだと、アニメーションしないのでCSSを指定してあげる必要がある。 以下の状態がある。
    • v-enter: 要素が挿入されたときの状態
    • v-enter-active: 挿入中の状態
    • v-enter-to: 挿入が終わったときの状態
    • v-leave: 要素が削除されるときの状態
    • v-leave-active: 削除中の要素
    • v-leave-to: 削除が終わったときの状態

    実際にスタイルを定義するときは上の'v'をtransitionタグに付けた名前を接頭語につけるといい。 ない場合はv-をそのままつけるといい。

    トランジションの内容はそこに書く。

    .fade-enter-active {
      transition: opacity .5s;
    }
    .fade-enter {
      opacity: 0;
    }
    
    ちなみにここまで見たものをVue.jsではenter/leaveトランジションと呼んでいる。
    appear属性を使うと初回描画時でもトランザクションを行えるようになる。
    • appear: 初回描画時のトランザクションを有効化する
    • appear-class: 指定したCSSクラスを使ってトランザクションを行う
    • appear-to-class
    • appear-active-class
    もちろんJSの関数も設定できる。
    • v-on:before-appear
    • v-on:appear
    • v-on:after-appear
    • v-on:appear-cancelled
    transitionタグ内のv-if、v-elseとかを使ったタグの切り替え時でもトランザクションは行える。 transitionタグの中に切り替わるタグがあるなら各々にkey属性を付けることを推奨している。

    トランジション時の振舞の指定

    2つの要素が同時にイン/アウトするとき、デフォルトだと同時に処理される。 場合によっては不自然に見えることもあるので、そのときはmode属性で振舞を変更できる。
    • in-out: 新しい要素のトランジションを先に処理し、終わったら現在の要素をトランジションする
    • out-in: in-outの反対

    他のCSSフレームワークとの連携

    Vue.jsではもちろん、ほかのCSSフレームワークを利用できる。 そのときは以下の属性を指定してあげるといい。 先頭のv-がなくなって、末尾に-classが追加された感じだ。
    • enter-class: 要素が挿入されたときの状態
    • enter-active-class: 挿入中の状態
    • enter-to-class: 挿入が終わったときの状態
    • leave-class: 要素が削除されるときの状態
    • leave-active-class: 削除中の要素
    • leave-to-class: 削除が終わったときの状態

    Javascriptフック

    トランザクションの状態に合わせてJavascriptの関数を呼び出すこともできる。 以下、公式ガイドから。
    
    <transition
      v-on:before-enter="beforeEnter"
      v-on:enter="enter"
      v-on:after-enter="afterEnter"
      v-on:enter-cancelled="enterCancelled"
    
      v-on:before-leave="beforeLeave"
      v-on:leave="leave"
      v-on:after-leave="afterLeave"
      v-on:leave-cancelled="leaveCancelled"
    >
    </transition>
    
    <script>
    // jsの関数とCSSトランザクションは組み合わせることができる。
    // ただし、jsだけ使用したときはenterとleaveに設定した関数内でdoneコールバックを呼び出す必要がある。
    methods: {
      // --------
      // ENTERING
      // --------
      beforeEnter: function (el) {
        // ...
      },
      // CSS と組み合わせて使う時、done コールバックはオプションです
      enter: function (el, done) {
        // ...
        done()
      },
      afterEnter: function (el) {
        // ...
      },
      enterCancelled: function (el) {
        // ...
      },
    
      // --------
      // LEAVING
      // --------
      beforeLeave: function (el) {
        // ...
      },
      // CSS と組み合わせて使う時、done コールバックはオプションです
      leave: function (el, done) {
        // ...
        done()
      },
      afterLeave: function (el) {
        // ...
      },
      // v-show と共に使うときだけ leaveCancelled は有効です
      leaveCancelled: function (el) {
        // ...
      }
    }
    </script>
    

    リストトランジション

    v-forなど、リスト化された要素でトランジションを行いたいときはtransition-groupタグを使う。 ただし、以下の制約がある。
    • デフォルトでは子要素はspanタグとして扱われる。(tag属性で切り替え可能)
    • v-moveは使えない
    • 中の要素は必ずkey属性を持たせないといけない。
    • 内部ではFLIPを使っているため、スタイルにdisplay: inlineが指定されていると動作しない
    <style>
    .list-item {
        display: inline-block;
        margin-right: 10px;
    }
    .list-enter-active, .list-leave-active {
      transition: all 1s;
    }
    .list-enter, .list-leave-to /* .list-leave-active for below version 2.1.8 */ {
      opacity: 0;
      transform: translateY(30px);
    }
    //新しく要素が追加されたとき、他の要素をアニメーションさせるときに使う。(v-move)
    .list-move {
        transition: transform 1s;
    }
    </style>
    
    <transition-group name="list" tag="p">
    <span v-for="item in items" v-bind:key="item" class="list-item">
        {{ item }}
    </span>
    </transition-group>
    
    ちなみにdata属性とdelay機能を組み合わせることで、アニメーションのタイミングをズラすことができる。

    Vueコンポーネントでのトランジション

    Vueコンポーネント内でtransition、transition-groupを使うときはルート要素に配置しないといけない。

    最後にガイドにあった文章を引用する

    動的なトランジションを作成する究極の方法は、プロパティでトランジションの性質を変えながら試行錯誤することです。小さく聞こえるかもしれませんが、本当の限界はあなたの想像力だけなのです。

    2019年1月2日水曜日

    Vue.jsについて その2

    前回に引き続きVue.jsの公式ガイドを見ていく。

    Vueコンポーネント


    Vueを使うとhtml内で自作したタグを使うことができる。関数を定義して使う感じ。
    <div id="components-demo">
      <button-counter text="これは自作タグです"> {{ text }} </button-counter>
    </div>
    
    <script>
    //自作したタグの定義(グローバル登録)
    Vue.component('button-counter', {
      props: ['text'], //関数の引数的なもの。タグの属性として値を指定する。
      data: function () { //関数として初期化することで、複数使ったときに値が独立してくれる。(公式で関数でないといけないと書いてある)
        return { count: 0 }
      },
      template: '<button v-on:click="count++">You clicked me {{ count }} times.</button>'
    });
    varapp = new Vue({el: '#components-demo'});
    </script>
    
    Vue.component関数で自作タグを定義できる。Vue.jsではこのコンポーネントを組み合わせてWebページをつくることを推奨している。 定義するときに指定できるパラメータは以下のものになる
    • template: 自作タグの本体.ここに書かれたものがHTML内で展開される。
    • props: 引数的なもの。HTML内で属性として値を渡せる。HTMLでは大文字は小文字として扱われるのでハイフン(-)で区切った名前を付けた方がいい

      ちなみに型を指定することもできる。

    • data: Vueインスタンスと同じ感じ。ただし関数として定義しないといけない。

      ※そのまま値を設定してもいいが、使われている全てのコンポーネントで共通な値として扱われるので管理が難しくなるので、公式では推奨していない。

    • computed. watch, methods: これらもVueインスタンスと同じ感じで使える。ただしelはない
    Vue.componentでコンポーネントを定義する。第一引数にその名前を付けるが、ケバブケース(my-component-name)パスカルケース(MyComponentName)のどちらかで名付けないといけない。
    ケバブケースはHTML内で使うときもケバブでないといけないが、パスカルケースの場合はケバブ・パスカルのどちらでもいい。 ただ特別な理由がない限り、ケバブケースで名前を付けた方がいい。

    グローバル定義とローカル定義

    上のサンプルコードではグローバルとしてコンポーネントを定義している。グローバルは名前の通りでどこからでも参照できるコンポーネントを表す。 プログラミングにおいてグローバルというものは避けるべきという認識があって、Vueコンポーネントにおいてもそれと変わらず、乱用すると不必要なリソースを食う。

    そのため、ローカル登録というものを用意しており、基本こちらを使うべきである。

    //自作したタグの定義(グローバル登録)
    var app = new Vue({
      components: { //ローカルコンポーネントの登録
        'component-A': {...},
        'component-B': {...},
      }
    });
    

    モジュールシステムとの連携

    javascriptのモジュールには詳しくないのだが(他もあまり詳しくないのだが…)、そのような機能を使うにはBabelやらWebpackといったものを利用するそうだ。

    Vue.jsでもそのようなものを使うことを想定しており、自作のコンポーネントについてはファイルに分けて管理することを推奨している。

    プロパティバリデーション

    Vueコンポーネントの定義の歳にpropsでプロパティを定義できるが、その際にバリデーションを指定できる。

    公式ガイドが読みやすくてそちらを見た方が早い気がだんだんしてきているが、一応コードを下に書く。

    function Person(firstName, lastName) {
      this.firstName = firstName;
      this.lastName = lastName;
    }
    Vue.component('my-component', {
      props: {
        // 基本的な型の検査 (`null` は全ての型にマッチします)
        propNumber: Number,
        propBoolean: Boolean,
        propString: String,
        propArray: Array,
        propObject: Object,
        propPerson: Person, //instanceof()で検証しているので自作の型でもOK
        // 複数の型の許容
        propB: [String, Number],
        // 文字列型を必須で要求する
        propC: {
          type: String,
          required: true
          default: 100 // デフォルト値の指定
        },
        // デフォルト値つきのオブジェクト型
        propE: {
          type: Object,
          // オブジェクトもしくは配列のデフォルト値は
          // 必ずそれを生み出すための関数を返す必要があります。
          default: function () {
            return { message: 'hello' }
          }
        },
        // カスタマイズしたバリデーション関数
        propF: {
          validator: function (value) {
            // プロパティの値は、必ずいずれかの文字列でなければならない
            return ['success', 'warning', 'danger'].indexOf(value) !== -1
          }
        }
      }
    })
    

    スロット

    スロットは Web Components spec draft にある<slot>要素にそったものになる。 スロットは以下のようなものになる。'navigation-linkコンポーネント内の<slot>の部分が"Your Profile"に置き換わり、より自由なコードが書けるようになる。

    <div id="app">
        <navigation-link url="/profile">
        Your Profile
        </navigation-link>
    </div>
    
    <script>
    Vue.component('navigation-link', {
        props: {
            url: String
        },
        template: `
            <a
                v-bind:href="url"
                class="nav-link"
            >
                <slot></slot>
            </a>`
    })
    var app = new Vue({
        el: "#app",
    });
    </script>
    

    <slot>は複数書くことができる、以下のVueコンポーネントは3か所置き換えることができる。

    <div class="container">
      <header>
        <slot name="header"></slot> //ここと
      </header>
      <div>
        <slot></slot> //ここと
      </div>
      <footer>
        <slot name="footer"></slot> //ここと
      </footer>
      <div>
        <slot></slot> //ここ。
        //同名、または無名なslotは一つにすること。
        //動作はするが、各々の所で記述された内容が統合されて、各場所に展開される。
      </div>
    </div>
    
    実際に使うときは以下のようになる。slot名を指定するときはnameではなくてslot属性。うっかり間違えたので気を付けたい。
    <base-layout>
        <template slot="header"> <-- ヘッダーに変換される -->
            ヘッダー
        </template>
    
        <p>メイン</p> <-- メイン だぶり に変換される -->
    
        <p slot="footer"> <-- フッターに変換される -->
          フッター
        </p>
    
        <p> <-- メイン だぶり に変換される -->
          だぶり。
        </p>
    
    </base-layout>
    

    ちなみにVueコンポーネント内のslotタグ内に何か記述したら、HTMLで何も記述しなかった時それが代わりに使われる。 いわゆるデフォルト値というものだ。

    タブインターフェイスとkeep-alive

    Vue.jsを使うとタブインターフェイスも簡単に作れる。componentタグv-bind:isがタブ切り替えの重要点だ。
    <div id="app">
        <button
            v-for="tab in tabs"
            v-bind:key="tab"
            v-bind:class="['tab-button', {active: currentTab === tab}]"
            v-on:click="currentTab = tab">
            {{ tab }}
        </button>
    
        <component
    //新しく定義した'tab-part1' か 'tab-part2'コンポーネントが実際に設定される
            v-bind:is="currrentTabComponent"
            class="tab">
        </component>
    </div>
    
    <script>
        Vue.component('tab-part1', {
            template: `
                <div>
                    タブその1
                </div>
            `,
        })
        Vue.component('tab-part2', {
            template: `
                <div>
                    タブその2
                </div>
            `,
        })
        var app = new Vue({
            el: "#app",
            data: {
                currentTab: 'part1',
                tabs: ['part1', 'part2']
            },
            computed: {
                currrentTabComponent: function() {
                    return 'tab-' + this.currentTab.toLowerCase();
                }
            }
        });
    </script>
    
    しかしこのままだと、あるタブで何か操作した状態はタブを切り替えたらリセットされる。 それを防ぎたいときはkeep-aliveを使うといい。
    <keep-alive>
        <component
            v-bind:is="currrentTabComponent"
            class="tab">
        </component>
    </keep-alive>
    
    ここまででVue.jsの機能を大体みてきた。こちらのページにエッジケースについて解説しているので、より詳しく知りたい/困ったときに参照するといい。

    要素 & コンポーネントへのアクセス

    プログラム的なイベントリスナー

    循環参照

    代替テンプレート定義

    強制更新

    まだまだあるVue.jsの機能。次はトランジションやミックスインとか見ていきたい。

    2019年1月1日火曜日

    Vue.jsについて


    Nuxt.jsを使ってポートフォリオサイトを作ろうかと思ったので、Vue.jsについて調べた。 以下、その調べたものについてのメモ

    前書き


    公式サイトに大体書いてある。
    まぁ、それだけではいまいち頭にピンっとこないので他のサイトも調べていたのが今までのパターンだけど、公式サイトで紹介されていたScrimbaというサイトにビデオチュートリアルがあったので助かった。 公式サイトは読みやすいのでそこいらのサイトよりおすすめである。

    Vue.jsの使い方

    こんな感じになる。 scriptタグの部分を開発者ツールのコンソールから変更すると元のファイルを編集せず、挙動を確認できるのでお手軽である。
    
    <div id="app">
        {{ message }}
    
        <p v-show="doShow">
            v-showで表示/非表示を切り替えられる<br>
            頻繁に切り替えるときに向いている
        </p>
    
        <!-- if文がある -->
        <p v-if="doShow">
            「v-if」で条件付きでタグの表示を制御できる<br>
            あまり変化がないものに使う
        </p>
        <p v-else-if="doElseShow === true">else if 文もある</p>
        <p v-else> else文もある</p>
    
        <!-- for文もある -->
        <p v-for="text in books">{{ text }}</p>
    
        <button v-on:click="clickButton">
            「v-on」でイベント処理が行える<br>
            指定するものは,"method"で定義する
        </button>
    
        
        <button v-on:click="clickButton" v-on:keyup.enter>
            「v-on」でイベント処理が行える<br>
            指定するものは,"method"で定義する
        </button>
    
        <!-- 自作のタグを作れる. 下は複雑な例 -->
        <!-- v-bind:keyで必ずkeyを渡す必要がある -->
        <ol>
            <custom-tag
                v-for="item in list"
                v-bind:obj="item"
                v-bind:key="item.id"></custom-tag>
        </ol>
    </div>
    
    <!-- HTMLに複数あってもいい -->
    <div id="app2">{{message}}</div>
    
    <script>
        //テンプレートの定義
        Vue.component("custom-tag", {
            props: ["obj"],
            template: '<li>{{ obj.text }}</li>'
        });
    
        var app = new Vue({
            el: "#app",
            data: {
                message: "Hello Vue!",
                doShow: true,
                doElseShow: true,
                books: [
                    "Anguler",
                    "React",
                    "Vue",
                ],
                list: [
                    {id: 1, text: "カス"},
                    {id: 2, text: "タム"},
                    {id: 3, text: "タグ"},
                ]
            },
            methods: {
                clickButton: function() {
                    this.message += "-";
                }
            }
        });
        var app2 = new Vue({
            el: "#app2",
            data: {
                message: "Dive into web!"
            }
        });
        app.message = "Change Vue!";
    </script>
    
    
    使っているVue.jsの機能は以下のものになる。 その他にも以下のものがある。

    Vueはデータフロープログラミング的

    これをVueではリアクティブと呼んでいる。 基本的にdataとして宣言した変数はリアクティブシステムの対象になっているが、Object.freeze()を使うと値の変更をできないようにできる。
    
    var obj = {
      foo: "bar"
    };
    Object.freeze(obj); //変更を防ぐ
    new Vue({
      el: "#app",
      data: obj
    })
    

    Vueインスタンスのライフサイクル

    Vueインスタンスにもライフサイクルがあって、以下のものがフックできる。 フック関数の定義にはアロー関数は使用してはいけない。絶対に
    1. created
    2. mounted
    3. updated
    4. destroyed
    
    new Vue({
      data: {
        a: 1,
      },
      created: function() {
        console.log('created| a is: ' + this.a);
      },
      mounted: function() {
        console.log('mounted| a is: ' + this.a);
      },
      updated: function() {
        console.log('updated| a is: ' + this.a);
      },
      destroyed: function() {
        console.log('destroyed| a is: ' + this.a);
      }
    })
    

    データバインディング

    データバインディングのやり方には以下の種類がある
    1. ”Mustache” 構文( {{}} )

      基本的な使い方。jsの式が使える

    2. v-bind & v-on

      htmlタグの属性を指定するときに使う「<p v-bind:属性名="js式">」と使う
      v-bindは':',v-onは'@'で省略できる。

    3. ちなみに修飾子と呼ばれるものもある。

    算出プロパティ

    「{{ }}」の中に式は書けるが、あまり複雑なものを書くことはVueは推奨していない。そのようなときは算出プロパティを使うことを勧めている。
    
    new Vue({
      data: {
        a: 1,
      },
      computed: { //算出プロパティの定義
        reversedMessage: function() {
          return this.message.split('').reverse().join('');
        },
        a: { //getter, setterの定義もできる
          get: function() { return 'prefix ' + a; }
          set: function(newValue) { a = newValue; }
        }
      }
    })
    //使うときは以下の通り
    <p> {{ reversedMessage }} </p>
    
    メソッドを定義するのと同じことだが、算出プロパティは依存関係にもとづいて処理結果がキャッシュされる利点があるので、どんどん使っていこう。

    監視プロパティ

    監視プロパティというデータの変更に合わせて処理をフックできるものがある。 指定したデータの変更を監視できるので、用途に合わせて使い分けよう。
    
    new Vue({
      data: {
        a: 1,
      },
      watch: { //監視プロパティの定義
        a: function(var) {
          console.log('changed a: ' + a);
        }
      }
    })
    //使うときは以下の通り
    <p> {{ reversedMessage }} </p>
    

    フォーム入力の補助機能

    フォーム入力もサポートしている。 v-modelを使って、入力結果を受け取りたいデータを指定する。 入力した値を自動的に設定した値に代入してくれるので、便利。


    以上、基本的な機能についてみてきた。公式ドキュメントにはまだまだ機能の解説が続いているが、疲れたのでここでいったん閉じる。