2017年6月10日土曜日

UnityでNPC作りたい_前編

Unityで敵さんのNPCを作るとき、色々方法はあるらしいのですが、今回はQiitaからビヘイビアツリーなる物をEditor上で作れるシステムがあり、それを弄って使おうと思ったらサンプルの構成や各ファイルの意味が理解できなかったので、自分なりにまとめた。
Editor拡張のFrameworkを使ってBehaviour Designer のようなAIシステムを作る。



Unityちゃんのプレハブについて
最初からあるようなやつ(=AIに関係ないやつ)
Transform
位置(X,Y,Z)と姿勢(ピッチ、ヨー、ロール)の情報。

Animator
アクション時のアニメの設定。
(これないと動けなくなる)

Rigidbody
物理エンジンに関わる各係数の情報。

CapsuleCollider
当たり判定の設定。
(これないと床をすり抜けて落ちる)

AIに必要なやつ
ThirdPersonCharacter
動く際のパラメーター。要はステータスみたいなモノ。
スタンダードアセットについてくるスクリプト。
(これないとスポーンした直後にアクションできないので宙に浮いたまま動かなくなる)

ActionController
ハイキックの状態保持やアニメーションを行うために有る。
(これないと走り続けて落下する)

Pown
スポーン地点に戻る為にある?(正直わからない)
(これないと回復しようとする際、相手に向かって走り続ける)

BTreeAction
AIの行動処理があるスクリプト。
(これないとそもそもスポーンした直後にアクションできないので宙に浮いたまま動かなくなる)

BTreeDecoratorFunc
AIの条件式があるスクリプト。
(これないとスポーンした直後にアクションできないので宙に浮いたまま動かなくなる)

BTreeManager
Btreeの操作を行うスクリプト。
(これないとスポーンした直後にアクションできないので宙に浮いたまま動かなくなる)

RunTimeNodeEditor
画面上にNodeEditorを表示するスクリプト。
(これないとゲーム開始時にNodeEditorの動きが見れない)

設定されている各スクリプトの説明
BTreeManager
AIの一番最初に動くやつ。最初はこれを見てね。
こいつはAIの読み込み、構築が主な仕事内容。
構築が終わったらメソッド「Update」で
延々とノードの実行、非実行を行い、AIを動かす。

Start
AIのスタート地点です。
別途指定されているAIファイルへのパスを基に、AIファイルをロードする。
開始ノードを探し、そこからノードの作成を行い、BTreeを構築する。
ちなみに指定されているファイルは「BTreeSample」なので、
そのファイルを消したり書き換えたりすると動きが変わるよ。

CreateNodes
ノードの作成、登録を行う。
「Start」から呼ばれる。
具体的なノード作成は「CreateBehaviorTreeBase」に投げる。
作成は投げ、変数への登録はこいつがする。

ちなみに、登録前に構築したBtreeの全ノードが「Ready」状態か確認しています。
Startノードはまあ開始してるわけですが、それ以外にも「Ready」状態じゃない場合、
「ResetCoroutineStart」が2回呼ばれて、再初期化を試みます。
普通はロード時、全てReady状態なので、たぶんリスポン用ですねこれ。

CreateBehaviorTreeBase
ノードの具体的な作成を行う。
「CreateNodes」から呼ばれる。
Btree特有のプロパティやアクションの設定をしてくれる。

ResetCoroutineStart:Btreeの再構築を行う。
具体的な処理は「ResetCoroutine」に投げる。


ResetCoroutine
最初に停止場所がある。※コルーチン:処理の中断、再開を行えるプログラム構造。
ノードの全削除、トップノードからの再登録を行う。

ChangeColorTask
ノードの実行と非実行を切り替える処理。
なんにしてもノードの実行はこいつが握ってます。
そしてこいつは「Update」で常に呼ばれ、ノードを動かします。

BTreeDecoratorFunc
Btreeのデコレーターノードに適用されるメソッド群がここにあります。
要はAIの行動の条件となる処理が、ここに全てあるわけです。

ここに定義されているメソッドは、エディター上で使用可能で、
逆にここで定義しないと、それはエディター上で使用できません。
つまりここで条件を書き、エディター上で条件分岐ノード(デコレーターノード)として
始めて使えるようになるわけです。

BTreeAction
Btreeのアクションノードに適用されるメソッド群です。
要はAIの行動処理が、全てここにあるわけです。

つまりここで条件を書き、エディター上で行動ノード(アクションノード)として
始めて使えるようになるわけです。

ちなみにダメージを受ける処理もここに有ります。

ActionController
「BTreeAction」で行われるアクション時、
アニメーションを動かしたり、ログを出力しているのがここです。
それ以外のことはしてません。

これを自前のゲームキャラクターに持たせるとなると、これらのスクリプトにあるステータス参照、アニメーション参照、各ロジックを色々弄くりまわす必要が出てくる。

次はパッドコントローラーを通した入力を前提に、NPCを動かすとかしてみる予定。


2017年4月23日日曜日

CentOS7でgmailのメール送信しようとしたら二段階認証でつまづいた

※CentOS7でgmailのメール送信の設定自体はすでにゴロゴロあるので書いてないよ。
※要は二段階認証で引っかかった所以外は見所がないよ。

まとめるとタイトルの通りで、googleアカウントに二段階認証がついてると、postfixでの「sasl_passwd」のパスワードが「アカウントのパスワード」ではダメになります。

詳しくは以下の通りです。ちなみに以下のURLで色々辿るとアプリのパスワードが作れます。それで通せます。
二段階認証の場合に必要な追加の作業

下はいつもの通りのブログです。

前回までのあらすじ
引越し先の借屋でインターネット環境がゴミクズそのものだった。
なのでSoftbank Airでネットに接続だ。
・・・・・・・・・・・・・・・・・・・・・・・・
・・・・・・・・・・・・
・・・・・・
・・・
ソフバンエアはポート転送ができない。
つまり自宅のサーバーが外部ネットワークに公開できない。
マイクラサーバーが立てられない。色々できない。
一応解決方法はあるみたいだけどめんどいし、
結局VPSは借りないといけないので・・・・・・
・・・・・・
・・・
ConoHaのVPSを借りた。

理由は
最重要:VPSである。
重要:初期費用無し。
重要:最安プランで千円切る。
おまけ:ConoHachanKAWAII

ていうかVPSでさくらに対抗できるのこの子以外見当たらなかった・・・
初期費用0円はすごいし、最安プランでも十分に良い。

とゆーわけで
Redmine立てた。最近のRedmineはコマンド5つ書くだけでいいんだね。
でもRedmineからメール飛ばないと不便だにゃあ。
CentOS7系で、postfixのみでメール送信したーい!
なんか大前提となる知識が圧倒的不足していたのでメモ。

知識
■SMTP
メール送信のプロトコル名です。
要は「こう言う方式で信号が送られてきたらメールと解釈して処理してね」
と言うメール送信時の規約です。
メールを送信・転送するためのプロトコル。受信とかできない。
※メール受信したいなら、POP3とか言うメール受信のプロトコルで動いているソフトウェアを別途で入れてね

■postfix(ポストフィックス)
簡単にいうと:
 メールを送信するためのソフトウェア。受信とかできない。
 本当に送信だけ。でも転送もできるよ。
難しくいうと:
 SMTPサーバーとなるソフトウェア。

■どうやってメールが送られる?
①SMTPに則った信号(要はメール)をネットに垂れ流そうとします。
②メールサーバ(postfix)がメールに乗っている宛先のドメインをDNSに聞きます。
③DNSから帰ってきたIPアドレスの場所に送られます。
要はIPアドレスさえ分かればメール送れる。
一応"@"以降に"[999.999.999.999]"って感じで指定すれば届く。
でもIPアドレスを特定するのは果てしなくめんどいのでやめとこう。


やりたいこと
メールを送信したい。

嫌なことが起きたこと
でもpostfixでテキトーに設定し、
"root@asanes.jp"とかいう感じの架空のアドレスを送信元アドレスにして
gmailに送信すると、1回は受け取ってくれるが
「おめーのメール、送信元のドメインがDNSに無いからスパムな」
と言われ、一定時間gmail側で完全に拒否られた。
1回は届くけど、スパムあんど一定時間完全拒否とかいうコンボ。
まあ当たり前よな。

多分gmail以外でもそんな感じだろうし何よりRedmineで受け取る先は
gmailの予定だからスパム扱いは困る。

要はメールのドメインを取得すればいいんだけど、月100円も嫌です。
ConoHachanは月630円でにゃんにゃんできるからいいけど。

じゃあ、gmail名義で出せばいいじゃない
とゆーわけで自分の持ってるgmailのアドレスでメールを送信します。
送信元のアドレスがDNSにあればいいんだよ!

とゆーわけでgmailのアドレスを送信元のアドレスにするのですが
「承認してねーよ、詐称してんじゃねーよ」
怒られる。そりゃそうだ。

仕方ないので承認しまーす。
sasl_passwdを設定してー。
承認しましたー。

「ユーザーとパスワードがあってねえよ」
はぁ?
いや正しいんですけど間違いなく。どういうことなの。
そういやなんかURLあるなこのログ。

二段階認証の場合に必要な追加の作業

アプリ用のパスワード登録して、それを書いたら通った。
二段階認証おそるべし。

2017年3月16日木曜日

コマンドプロンプトでgroongaのまとめ


groongaさん日本生まれの英国仕様なのでドキュメントが日本人向けでないです。でもgroongaさんはDBだそうなので、DB的に使ってみようとした際のTipsです。ちなみにコマンドプロンプトです。以下cmdです。

OS:Win7
Ver:groonga7.0.0_x64[zip版]
前提:コマンドプロンプトでgroonga.exeがあるフォルダにcdコマンドで移動済み。

DB作成、削除
DB作成
めんどくさいのでgroongaと同じフォルダにDBを作ります。注意点として、groonga.exeを実行したcmdでやってはいけません。通常のcmdで、groonga.exeのフォルダまで移動して打ってね。
groonga -n --encoding sjis ./[テーブル名]
これを打つとDB作成と同時にDBにアクセスします。
ちなみにsjisでエンコードしてないと(cmdのエンコがsjisの拡張版cp932だから)cmdで日本語が扱えません。英国生まれなのでそんなことドキュメントに体系的に書いて無いので最初から日本語使えなくて即死します。日本生まれのメリットを初手から潰してくるgroongaさんまじぱねっす。
DB削除
消し方はあれです。なんかファイル作られてるでしょ。それをゴミ箱にぽいして。更新日付順に並び替えば上から4個くらいがなんか作られてるのでそれを捨てて。

DBへのアクセス
注意点として、groongaexeを実行したcmdでやってはいけません。通常のcmdで、groonga.exeのフォルダまで移動して打ってね。
groonga ./【テーブル名】
はい、DBにアクセスします。以降のTipsはDBにアクセスした状態で打ってね!!
テーブルの作成、削除
テーブルの作成
はい、普通のテーブルの作り方です。
table_create --name 【テーブル名】 --flags TABLE_HASH_KEY --key_type 【型】
型ってなんですか?って感じだけど、groongaのテーブル作成は非常に特異です。テーブルを作成する際、主キーとなるカラムと一緒に作ります。それ以降のカラムは別のコマンドで随時追加していく感じになります。SQL的に言うと以下の感じを1行でぶち込みます。
Create Table 【テーブル名】 {
 _id int64 autoincrement
,_key 【型】 not null primary_key
}
ちなみに_idとか_keyとか言うカラム名は固定でしかも付いてきます。くそですね。一応_idとか取れるらしいが通常はあっても無くても極限性能でなければ人間の感じ取れる性能差は変わらないので気にしなくていいらしいです。

あと型は色々あります。以下を参照。
データの種類
テータの型
カラムの追加
下の感じです。
column_create --table 【テーブル名】 --name 【カラム名】 --flags COLUMN_SCALAR --type 【型】
ちなみにカラムに配列を指定することもできます
column_create --table 【テーブル名】 --name 【カラム名】 --flags COLUMN_VECTOR --type 【型】
完全にAlterTableのColumnAddのノリですね。

あと型は色々あります。以下を参照。(2度目)
データの種類
テータの型

テーブルの削除
削除するテーブルを参照してる他のテーブルが無ければこれで消せます。
table_remove 【テーブル名】
消せない場合は消しちゃうと色々影響でかいという事なのでがんばって影響されるテーブルを探して順次依存を解消していこうね。

レコードの登録、更新、削除
いよいよ更新系クエリですね。

登録と更新は以下のとおり。ん?更新も兼ねているのかって?そうだけど。
load --table [テーブル名]
[
{【カラム名】:【値】}
]
SQL的に言うとINSERT … ON DUPLICATE KEY UPDATEですね。ちなみに更新は主キー、つまり_keyの値で判断してるよ。ただのInsertは無いよ。

複数のカラムに値を入れるとか、複数のレコードを一気に登録したい場合
load --table [テーブル名]
[
 {【カラム名】:【値】,【カラム名】:【値】}
,{【カラム名】:【値】,【カラム名】:【値】}
,{【カラム名】:【値】,【カラム名】:【値】}
]
主キーに適当な文字列を入れたい場合は以下のような感じ
load --table 【テーブル名】
[
 {_key:"いろは"}
,{_key:"にーほ"}
,{_key:"へいと"}
]

削除は以下のとおり
delete --table 【テーブル名】 --filter "【Where句】"
ちなみに主キー直指定で1個ずつ消したりもできる。

消してぇ・・・・全消ししてえよ・・・・!!
って方は以下のトランケートで
truncate --table 【テーブル名】

レコード検索
ただWhere句がまたしても癖の塊なのでドキュメントを参考にしながら組み立てるといいです。
select --table 【テーブル名】 --filter "【Where句】"
ちなみにLimitOffset句もある。
select --table 【テーブル名】 --offset 【数値】 --limit 【数値】


おまけ
エスケープとか、Windowsのパスとか、日本のお値段としてよく使う「\」なんだけど、バグでエスケープがドキュメント通りにいきません。
・「"」でクオート時、「\"」「\\」を中に入れると「\"」「\\」が出る⇒エスケープもそのまま出す。
・「\'」「\(」を中に入れると「'」「(」が出る⇒エスケープされた文字が出る。
ちなみに以下の文字列をloadコマンドで登録すると
load --table DataObj
[
{_key:"\a\b\c\d\e\f\g\h\i\j\k\l\m\n\o\p\q\r\s\t\u\v\w\x\y\z\\1\2\3\4\5\6\7\8\9\0"}
]
"a\bcde\fghijklm\nopq\rs\t\u0000xyz\\1234567890"
エスケープ込みの特殊文字入れすぎでひどい。

2017年2月15日水曜日

VB.NET:フォルダ優先で一覧を表示させる

ファイル・フォルダ一覧のパスがあるけどフォルダを優先して出したい。
深さ優先探索みたいなソートを再帰無しで書きたい。
そんなときに!

下のコードの表示先はListBox1だから気を付けてね。

やってることは簡単で、
符号の順序を利用してソートすれば、
再帰的なソートを必要とするモノでも再帰コード書かなくていいよ、速いよって事。

並び替えるモノを符号化してソートすると意外と簡単にできたりする。
もちろん一旦符号化しないといけないからその分の時間は掛かるけどね。

Dim folders As String() = System.IO.Directory.GetDirectories("C:\hogehoge\", "*", 1)
Dim files As String() = System.IO.Directory.GetFiles("C:\hogehoge", "*", 1)

'ソート
Array.Sort(folders)
Array.Sort(files)


'見つけたものを次々に符号化
Dim 符号リスト As New Hashtable
Dim パス As String
Dim ノードリスト As String()
Dim ノード As String
Dim インデックス As Int32 = 0
For Each パス In folders
  ノードリスト = パス.Split("\"c)
  For Each ノード In ノードリスト
If Not 符号リスト.ContainsKey(ノード) Then
  符号リスト(ノード) = "," & インデックス.ToString("D6")
  インデックス += 1
End If
  Next
Next
For Each パス In files
  Dim ファイルデータ = New System.IO.FileInfo(パス)
  ノードリスト = パス.Split("\"c)
  For Each ノード In ノードリスト
If ノード = ファイルデータ.Name Then
  符号リスト(ノード) = "-" & インデックス.ToString("D6")
  インデックス += 1
ElseIf Not 符号リスト.ContainsKey(ノード) Then
  符号リスト(ノード) = "," & インデックス.ToString("D6")
  インデックス += 1
End If
  Next
Next



'ソートリストを用意
Dim sss As New SortedList(Of String, String)
Dim aaa As New Text.StringBuilder



'Keyは符号化したやつ、
For Each パス In folders
  ノードリスト = パス.Split("\"c)
  aaa.Clear()
  For Each ノード In ノードリスト
aaa.Append(符号リスト(ノード))
  Next
  sss.Add(aaa.ToString, パス)
Next
For Each パス In files
  Dim ファイルデータ = New System.IO.FileInfo(パス)
  ノードリスト = パス.Split("\"c)
  aaa.Clear()
  For Each ノード In ノードリスト
aaa.Append(符号リスト(ノード))
  Next
  sss.Add(aaa.ToString, パス)
Next


For Each パス In sss.Values
  ListBox1.Items.Add(パス)
Next

2017年1月28日土曜日

SAI2で定期自動保存

ちなみにVBSの実行タスクはこれね。

タイトル通りです。
SAI2で謎落ちとか謎エラーとかで保存がああああああってなるので、正直結構辛いのでVBSでSAI2のファイルを定期的に自動保存するスクリプト書いてみた。

15分に1度、「sai2 (*)」という文字が入っているタイトルを探して、それをアクティブにしたのちCtrl+Sキーを押すというもの。よくある「sai2が先に立ち上がってないとだめ」という事はないので自由に叩きましょう。

ちなみに実行後、無限ループするから多重実行は気を付けてね。多重実行したときとか、要らないときはVBSはタスクからキルしてね。

あとVBSが何なのかとか、VBSの作り方とか、起動の仕方とか、ソースの環境依存の問題とかはググればなんとかなるよ。たぶんね。

以下ソース
'寝るミリ秒数
Dim SleepTime
SleepTime = 15*60*1000'15分間に1度動く
Dim strName
'strName= "PaintTool SAI"'前方一致(常に一定時間後保存を行う)
strName= "sai2 (*)"'後方一致(拡張子が.sai2のファイルを編集しているときのみ保存を行う)
'始まるよー
Main()

'メイン関数
Function Main()
  Dim objShell
  'シェルのオブジェクトを作成する
  Set objShell = CreateObject("WScript.Shell")

  On Error Resume Next
  Do
    If objShell.AppActivate(strName) Then objShell.SendKeys("^s")
    WScript.Sleep SleepTime'ここでスリープ
  Loop
  GetError()
  Err.Clear
  On Error Goto 0

  Set objShell = Nothing
End Function

'例外通知
Function GetError()
  GetError = True
  If Err.Number <> 0 Then
    MsgBox "例外:" & Err.Number & ":" & Err.Description
    Exit Function
  End If
  GetError = False
End Function

2017年1月21日土曜日

win10からメモリを100MBくらい開ける

win10のパソコン仕入れたけど全然全くメモリに余裕がないよ!って感じのまとめ。
その1
以下のフォルダにメモリが若干食われるコルタナちゃんとウィンシェルちゃんがいる。

C:\Windows\SystemApps\
Microsoft.Windows.Cortana_cw5n1h2txyewy
ShellExperienceHost_cw5n1h2txyewy

こいつらが地味にメモリ食うので止める。
・コルタナちゃん
30~60MB:止めるとwin内での検索ができなくなるけどそれくらいしかデメリット無い
・ウィンシェルちゃん
30MB:止めるとwinボタンが無効になる。デスクトップにシャットダウンとかのショートカット置くなりして対策するか緊急用としてじゃね。

その2
60MB近く食うwindows defenderなるものがいるけど、これは別のアンチウイルスソフト(Avastとか)入れれば消えてくれる。Avastちゃんは25MBくらいなのでまあまあまあ。

その3
「dwm.exe」というのが地味にメモリを食っていく。一応どっかの時計みたいに延々とメモリリークするわけではない。
溜まってたらキルして一旦メモリを吐き出して貰おう。コマンドプロンプトだと以下の感じ。
taskkill /F /IM "dwm.exe"


最後に
全部やると100MBくらい空いてくれる。
これとは別にちゃんとメモリークリーンもしようね。