グレインの備忘録

プログラミング関係とかをつらつらと。

UMLをテキストで書ける「PlantUML」を試す

UML図を書くフリーのツールにはいろいろあるが、テキストコマンドで書けるものの一つに「PlantUML」がある。

テキストベースで書けると何がいいかというと、

などの点が挙げられる。

使い方等

PlantUML自体はJavaで書かれたテキストプロセッサであるが、Web上でこれを試せるサービスがある。

PlantUML Web Server

リファレンスはここにある。

PlantUML

クラス図・フローチャートのほかにも色々とかけるらしい。

使用例

テキスト

@startuml
start
:ボールを移動;

repeat
  :Reflectorを一つ取り出す;
  if (ボールと衝突したか?) then (yes)
    :ボールの移動方向を変える;
  else (no)
  endif
repeat while (Reflectorはあまだあるか?)

stop
@enduml

出力

f:id:grainrigi:20170830235007p:plain

これは積極的に使っていきたい。

OOP初心者がブロック崩しを作ってみる その1

オブジェクト指向の設計やコーディングについて自分なりに情報を集め始めてからかなり経って、自分なりに手法というものがある程度見えてきた。

ということで、それの実践としてひとつ簡単なゲームを制作してみたいと思う。

概要

今回作るのはよくある美少女を剥ぐ感じのブロック崩しである。

理由は友人にもらったネタがこれだったからだけであって、それ以上の理由はない。

設計の指針

まずオブジェクト指向の原則として

  • クラスはなるべく疎結合にする
  • 小さなクラスを多数組み合わせる
  • データを求めるのではなくメッセージをやり取りする

などの原則があるのでそれを意識する。

さらに、GoFデザインパターンの中でも有用なものは積極的に取り入れていく。

※主に以下のサイトの影響を受けている

オブジェクト指向の設計と実装の学び方のコツ - SlideShare

オブジェクト指向できていますか? - SlideShare

再考: GoF デザインパターン - Qiita

その1:要求分析

今回はブロック崩しがどんなソフトであるか具体的に分析しながら設計を考えてみる。

実際のゲームではメニューやら設定やらもあるのだが今回はコア部分のみに注目する。

f:id:grainrigi:20170830231955p:plain

非常に簡略だが図を書いてみた。

ブロックがメッシュ状になっているのは画像を分割した図を想定しているからだ。

ここでボールの動きに注目すれば、

  • 普段は一定速度で動き続ける
  • 壁やパドルにぶつかったら跳ね返る
  • ブロックにぶつかったらブロックを壊して跳ね返る

ということになる。

つまり、ボールは「移動するか」「跳ね返るか」のどちらかの動きをする。

そうすれば、とりあえず「壁」「パドル」「ブロック」はすべて「ボールを跳ね返らせるもの」として抽象化できそうだ。

とりあえず跳ね返らせるものなのでReflectorという名前でくくっておくことにする。

ボール関係の処理

ボールに関する処理を簡単にまとめてみる。

とりあえず1フレーム分の処理。

f:id:grainrigi:20170830235007p:plain

ボールを移動した後、各オブジェクトと衝突判定を行う。

とりあえず正しく動くようにするため、衝突判定は全オブジェクトに対して行うことにした。

「壁」「パドル」「ブロック」といった衝突対象の違いを考慮しなくて良くなったので、割と簡単な処理になった。

パドル関係の処理

パドルもReflectorの一つで、衝突判定はよそで勝手にやってくれる。

したがって、パドルが関心を持つ必要があるのは自身の移動のみである。

とりあえず、左キー、右キーで左右に移動できるようにしてみよう。

f:id:grainrigi:20170831001201p:plain

衝突を考えなくて良いのでかなりシンプル。

ブロック関係の処理

ブロックもReflectorの一つで、衝突判定自体を自身でする必要はない。

しかし、衝突された時には自身を消さなければならない。

ということで、こんな感じになるだろうか。

f:id:grainrigi:20170831001912p:plain

衝突したかどうかを情報として使うので、ブロックの処理はボールの処理より後になるだろう。

処理のまとめ

各々のオブジェクトが担当する処理は概ね明確になったので、これらの組み合わせ方を考える。

フロー図ではこんな感じだろうか。

f:id:grainrigi:20170831002328p:plain

これでコア部分で必要な処理が明確になった。

無論、この構造が最後まで完璧に通るとは思わないが。

次回予告

次回 「OOP初心者がブロック崩しを作ってみる その2」ではコア部分の処理のクラス化について考えていく。

括弧の自動補完にlexima.vimを使う

以前の設定ではキーマップを駆使した汚い括弧補完を使っていた。

探してみると、もっと良さげなプラグインがあったのでそれに置き換えてみる。

導入

dein_lazy.tomlに追加。

[[plugins]]
# lexima
repo = 'cohama/lexima.vim'
on_i = 1

後はインストールすれば終わり。

括弧を補完に頼らず入力しても「())」みたいにならないし、いい感じである。

deoplete環境でneosnippetを使えるようにする

neosnippetはスニペットを挿入できるプラグインだが、機能的にdeopleteと干渉する部分があるので少し工夫をする必要がある。

メモ程度に設定方法を残しておく。

参考:neovim で deoplete + neosnippet の連携をする

導入

dein.tomlとdein_lazy.tomlに以下のとおりに追記する。

※tomlファイルを活用しているが、hook_post_source内のスクリプトをinit.vim内に書けば同じことである。

[dein.toml]

[[plugins]]
# snippets
repo = 'Shougo/neosnippet-snippets'
[dein_lazy.toml]

[[plugins]]
# neosnippet
repo = 'Shougo/neosnippet.vim'
hook_source = '''
  "Ctrl+Kにターゲットジャンプ割当
  imap <C-k> <Plug>(neosnippet_expand_or_jump)
  smap <C-k> <Plug>(neosnippet_expand_or_jump)
  xmap <C-k> <Plug>(neosnippet_expand_target)
  if has('conceal')
    set conceallevel=2 concealcursor=niv
  endif
'''
on_i  = 1
on_ft = ['snippet']
depends = ['neosnippet-snippets']

[[plugins]]
# deoplete
repo = 'Shougo/deoplete.nvim'
hook_source = '''
  let g:deoplete#enable_at_startup = 1
  "Tab補完の設定
  inoremap <expr><tab> pumvisible() ? "\<C-n>" :
        \ neosnippet#expandable_or_jumpable() ?
        \    "\<Plug>(neosnippet_expand_or_jump)" : "\<tab>"
'''
on_i = 1

操作方法

  • Ctrl+Nで候補切り替え
  • 候補を選択した状態でCtrl+Kでスニペット挿入
  • 以後Ctrl+Kで入力位置移動

deinを真面目に設定してみる(TOML)

deinはvimrcに設定を書くだけでも使える。

しかし、一般的にはTOMLと呼ばれる外部ファイルに書くらしい。

TOMLファイルを利用する

とりあえずTOMLを使う準備をしよう。

init.vimに以下の記述を追加する。

set runtimepath+=~/.vim/dein/repos/github.com/Shougo/dein.vim

let s:dein_dir = expand('~/.vim/dein')
let s:toml_dir = expand('~/.config/nvim')

"dein settings
if dein#load_state(s:dein_dir)
    call dein#begin(s:dein_dir)

   "Load TOML
    let s:toml = s:toml_dir . '/dein.toml'
    let s:lazy_toml = s:toml_dir '/dein_lazy.toml'

    call dein#load_toml(s:toml, {'lazy': 0})
    call dein#load_toml(s:lazy_toml, {'lazy': 1})

   "finalize
    call dein#end()
    call dein#save_state()
endif

この設定では、

  • deinは「~/.vim/dein/repos/github.com/Shougo/dein.vim」にcloneされている
  • TOMLは「~/.config/nvim/」以下に保存

となっている。必要に応じて該当箇所を変更すること。

起動時ロードと遅延ロード

次は、TOMLファイルに使いたいプラグインを列挙する。

ここで一つ注意する必要があるのが「遅延ロード」の存在だ。

今まで普通にdeinを使っていれば、プラグインは起動時にロードされていた。

しかし、「遅延ロード」を用いると、起動時より少し後にプラグインがロードされる。

これを用いることにより、起動時のロードを最小限にできることで起動速度が上がるらしい。

では、実際にTOMLを書いてみよう。

まずは起動時用。

# [dein.toml]

#以下のようにレポジトリ名を書くだけで良い
[[plugins]]
repo = 'Shougo/dein.vim'

[[plugins]]
# Lighline
repo = 'itchyny/lightline.vim'

[[plugins]]
# tender
repo = 'jacoborus/tender.vim'

ここでは利用していないが、他にもカスタマイズができるらしい。

参考:dein.vimによるプラグイン管理のマイベストプラクティス - Qiita

次に、遅延ロード用。

# [dein_lazy.toml]

[[plugins]]
# deoplete
repo = 'Shougo/deoplete.nvim'
hook_post_source = '''
    let g:deoplete#sources#clang#libclang_path = '/usr/lib/llvm-3.8/lib/libclang-3.8.so.1'
    let g:deoplete#sources#clang#clang_header = '/usr/include/clang'
    let g:deoplete#enable_at_startup = 1
'''

[[plugins]]
# deoplete-clang
repo = 'zchee/deoplete-clang'

基本は起動時用と同じだが、遅延ロードでは「hook_post_source」というオプションが利用できる。

これは、プラグインが遅延ロードされた直後に実行するコマンドを指定するものである。

プラグインの追加設定をiniv.vimに書くとロード前に実行されてしまうので、それを防ぐためにここに書く。


とりあえず導入だけをやってみた。

有り難みもそのうちわかってくるようになるんだろう、多分。

Doxygenを導入してみる

Doxygenはソースに埋め込んだコメントを元にドキュメントを作成するツール。

メモ程度に導入方法をまとめておく。

導入

sudo apt -y install doxygen doxygen-gui graphviz

あとは、

doxywizard

を実行すればGUIが出てくるので、ウィザード通りにすすめる。

スニペット

ファイル

/**
* @file
* @brief 
* @author 
* @date 
* @details 
*/

@file ファイル名(必須) @brief 一行説明(必須) @author 作成者 @date 作成日 @details 詳細説明

関数

/**
* @fn 
* @brief 
* @param
* @retval
* @details 
*/

@fn プロトタイプ宣言(必須) @brief 一行説明(必須) @param 引数 構文:@param[in/out] <引数名> <説明> @retval 戻り値 構文:@retval <値> <説明> @details 詳細説明

変数

//! 説明

変数宣言行の上に書く。

クラスとかは上3つを組み合わせればいける。


参考文献

Ubuntu に doxygen / graphviz をインストール

最近覚えた便利アプリ[doxygen]