Last-modified: Mon, 03 Jan 2005 00:15:01 JST
[dynamic,cache:on]
powered by tds-1.6.2
09:10 起床, 10:30 出社。
実装。
小数部のビット幅や、 固定小数点数を記憶するために内部的に用いる整数型などはすべてポリシークラスに分離。 後で、簡単に調整できるようにしておく。
スクリプト内部で生成する C++ オブジェクトの寿命管理に関して、 実装の枠組みをスクリプト担当のメインプログラマと話し合い。 結局、 仮想デストラクタだけ定義した基底クラス (仮に IObjInScript としておく) を用意して、 スクリプト中で動的に作成するインスタンスは std::list に boost::shared_ptr<IObjInScript> を突っ込んで終わりにする。 コードがざっくり短くなった。
生産性を単位時間あたりの生成コード数で計ると、 私の仕事はしばしばマイナスになる。
他の人の書いたコードのチェック。 int, float といったプリミティブ型やベクトル型を typedef なしで多用するのは、 後々のメンテナンスを考えると止めた方が良いだろう。
float move_speed; // 速度
こういうコード。 他人 *1にとっては、 「1 フレームあたりの移動量」なのか「1 秒あたりの移動量」なのか分からない。 コードを保守するためには、 前後のコードをしばらく追って意味を解明する必要があり、 かなり手間が掛かる。
今 typedef する僅かな手間を惜しんで、 後で長い時間を費やして悩むのは愚かだ。
| - | 推奨 | 捨て捨て |
|---|---|---|
| オブジェクト寿命管理 | スマートポインタを使う。 | 手で delete する。 |
| 文字列 | 寿命管理を明確にするため、内部でコピーするか否かをコメントに書く。あるいは std::basic_string<> を使う。 | 引数は全部 char* だけ。どこでコピーするかは明確になっていない。その操作が、ポインタが指す先を上書きするかどうかも不明確。 |
| 固定小数点数 | 専用のクラスを作成する。 | プリミティブな整数型をそのまま使い、手作業でシフトする。 |
| 型 | 意味に応じて typedef する。 | プリミティブな整数・浮動小数点数型をそのまま使う。 |
| コレクションやアルゴリズム | STL など再利用可能な既存のパーツを使う。自前で実装する時には、他でも使えるように汎用性を考慮しておく。 | 汎用性の低いコードを自前で実装。結果として似て非なるデータ構造が大量にできて、また構造体内部構造に依存したアクセス方法がコード全体にばらまかれるため、非常に追いにくくなる。 |
ある程度の規模のプログラムを書く場合、 どうしてもこの手の事柄に注意を払う必要が出てくる。 「常識」と言ってしまえばそれまでだけど、 プログラミング言語の本 (プログラミング言語 C++ とか) には出てこない話ではある。
必要な人間には、 とりあえず「プログラミング作法」あたりを読んでもらうか?
21:00
09:10 起床, 10:30 出社。
Hieralchical State Machine 改修。 入退場動作中に、その入退場動作を引き起こしたシグナルを取得できるように。 これまでは遷移後の入場動作に情報を受け渡すために使用していたメンバ変数を削除し、 情報伝達をシグナルに一本化。
データの流れが明確になった。
演算子を定義。 必要最小限の演算子だけ手で書いて、後は Boost Operator ライブラリに自動生成させる。楽だ。
そういえば ANSI C++ の規格によると負数の右シフトは「実装依存」とのことで、 念のため当該部分を #ifdef で括っておく。 幸い私が使ってる処理系では算術シフトなので、 そのまま >> 演算子を使えるけど。
メインプログラマから、タスク管理に使えるソフトが何かないかという話。 私は今のところは、 モニタの脇に TODO を記述した付箋紙を貼り付けて済ませて至るのだけど、 さすがにそれで管理できる状態ではなくなりつつある。
二人で howm , howm-mode.vim を試してみる。 後で Outlook と PalmDesktop も試してみよう。
しばらく前 からひきずっている話。 そろそろ抜本的に解決したいので、 担当部署にその旨をメール。 結局、 ディスクや使えるパーツをサルベージした上で、 マザーボードごとごっそり交換することに。
担当者と立ち話ついでに、 機材の手配について非公式な話。
先日、 チームに人は配属されているにも関わらず、 その人に割り当てる機材が届かずに困ったことがあった。 決裁や何やらの関係で「そういうものだ」という話になっていたけど、 話を聞く限り、うまく手配しておけばタイムラグを無くせそうだ。 一度、決裁者と機材調達の現場の人間を個別に捕まえて手順を詰めておこう。
プログラマの一人と、 プログラミング作法に関して、 世間話を交えつつお話。
21:30
09:30 起床, 10:30 出社。
昨日の件、続き。 新規に用意してもらった PC (Windows マシン) も、私のところで環境設定中にお亡くなりに。
開発用の PC は次のような手順で準備している。
私の手元に届くということは、 少なくとも OS やソフトウェア類のインストールは順調に済んでいる。 にもかかわらず 3 の段階で問題が出るということで謎が深い。
私の席には他にも開発用 PC (Linux マシン) などが置いてあるのだけど、 それらは問題なく動いているので、電源などの問題ではなさそう。 ま、
ささやき えいしょう いのり ねんじろ!
* 本番の環境では動きませんでした *
というのは良くあることだ。
いずれにせよ、 このままだと仕事に支障が出るので、 至急で別のマシンをもう一台手配してもらう。
手元にあるもう一台の PC (Linux マシン) でコード書き & howm-mode.vim のテスト。
例によって cvs のベンダーブランチに突っ込んで cvs update -j XXX -j XXX でマージ完了。 こちらのプログラムとリンクして試してみるも、 特に問題なく動いている感じ。 良し良し。
以前からこちらが要望を出していた件 (メモリ管理方針の変更) に対応して頂いたとのことで、 近日中に今のプログラムに大きく手を入れる予定。 メモリ管理まわりに関わっているのはメインプログラマと私の二人だけだから、 二人まとめて二日ぐらい拘束すればケリがつくだろう。
進捗確認。
今週は「全て順調」とはいかず問題点がいくつか出てきた。 ケースバイケースで対処。
メッセージ通信のメッセージではなく文字列表示の方。
凝った処理をするためには、 「色を変える」「キー入力待ち」といったデータを埋めたテキスト (タグ付きテキスト) ファイルを用意しておき、 それをコンバートしてバイナリデータ列に変換した上で、 実機上で再生することになる。
そのコンバータとタグ付きテキストの仕様に関して気になる点があったため、 担当プログラマに確認。 いくつか問題点が出てきたので、 その場で順に潰していく。 設計方針まで決めて、後は実装よろしくお願いしますという感じで。
Unicode 対応をうたっているエディタでも、 実際には「ASCII, JISX 0201, JISX0208 以外の文字集合は使えません」というものも多い。 Windows 上で動くエディタだと vim, xyzzy, 秀丸 (ver.4) あとはメモ帳あたりは、 Unicode でラテン系の文字セットを正しく扱える *1。
別のマシンがきたので、そちらの環境整備。
今度はネットワーク管理部署との連絡に不手際があり管理者の手を煩わせたけど、 ハードウェアの方は大丈夫そう。 データをバックアップから復帰して、 必要なソフトをインストールしてる途中で時間切れ。
21:00.
09:30 起床, 10:30 出社。
チームのプログラマの一人に、 ハードコーディングしている部分について具体的な問題点を挙げ、 データドリブンにするようにお願いする。
仕事が早く優秀なプログラマなのだけど、 規模が大きいプログラムを書く経験が不足しているように見受けられたので、 ここ数日はそのギャップを自覚してもらうべく、 実際のコードを前にして問題点を指摘してきた。
ただ、 もう十分に問題点は理解しただろうし、 何かコード書くたびに私に突っ込まれてるのも心臓に悪いと思うので、 そろそろ口は出さないように。 代わりに、会社の私物書籍棚から コードコンプリート を出してきて、 ちょうど今日の事例に該当する「テーブル駆動型プログラミング」の章に付箋をつけて貸与。
だいたい私が言ってる話なんて、目新しいことは何もなくて
あたりで語り尽くされてる。
strlen, strcpy, ... などに相当する関数を順次実装しようかと思っていたけど、 std::basic_string<> を特殊化すればことが足りそうなので、その方向で調査。 Traits クラスを書いてサクッと実装終わり。
企画側のカウンターパートとなる人間とミーティング。 本来はメインプログラマと企画側のカウンターパートの計二人で話せば事足りる内容だが、
ために参加。
スケジューリングが微妙になってきた。
必要な作業の洗い出し。 これは旧来のインターフェースと新規インターフェースを一時的にでも併用するのは難しくて、 一気に切り替えるしかない。
まとまった時間を取り、一気にやってしまおう。
Hieralchical State Machine のシグナルの要件を、 POD から DefaultConstructible & Assignable に変更。 シグナルの内部データを private 化して、 エラーチェックを強化。
22:50.
来週はもう少し早く帰ろう。
09:30 起床、10:30 出社。
そんなんで、ほぼ一日終わり。
私の手伝いをお願いしているプログラマに移動コリジョンを組み込んでもらっているので、 しばらく切っていたコリジョン表示機能を復活。 近いうちに、 デバッグ機能を対話的に on/off できるメニュー項目を実装する必要アリだな。
19:30. 今週は早く帰って、さっさと寝る方向で。
Win32 で使用すると cmigemo での検索がうまくいかない。 どうもパイプ経由で cmigemo を起動すると半角スペースが余計につくようなので、 cmigemo のソースコードに手を入れて対処。
09:00 起床, 10:00 出社。
再検討。
ゲームオブジェクトの制御をスクリプトドリブンに移行する予定なのだけど、 それに先だってデータベースを拡張する必要がある。 今後のことを考えて、 既存の CSV ファイルを拡張するのではなく一気に XML ベースに移行することに。
MSDN ライブラリと XML の書籍片手に、 Visual Studio.NET 2003 についてくる XML デザイナと InfoPath 2003 と戯れる。 思いのほか XML Schema の規格が深い。 モノにするには、もう少し時間かかりそう。
20:10.
Visual Studio.NET 2003 と InfoPath 2003 を使っていたら、 5 つボタンとチルトホイールが心底欲しくなった。 Visual Studio.NET 2003 がマウスジェスチャーに対応していれば、 5 つボタンなんて要らないんだけど。
XML 文書をプログラムで読み込んで処理する方法。 .NET を使うなら
これでおしまい。
using System;
using System.Xml.Serialization;
using System.IO;
// スキーマから自動生成したクラス `keyboard' を格納してある名前空間
using org.issei.xsdtest;
namespace xsdtest
{
/// <summary>
/// XML スキーマ `keyboard' に従った XML 文書を解析する
/// </summary>
class KeybaordParser
{
/// <summary>
/// アプリケーションのメイン エントリ ポイントです。
/// </summary>
[STAThread]
static void Main(string[] args)
{
XmlSerializer serializer = new XmlSerializer(typeof(keyboard));
TextReader reader = new StreamReader("xsdtest.xml");
keyboard kb = (keyboard)serializer.Deserialize(reader);
// これでおしまい
// あとは kb の先にツリーが生成されているので、適当にアクセスすると読み出せる。
Console.Write(kb.key[0].label[0].Text[0]);
Console.Write(kb.key[0].label[1].type1);
Console.Write("\n");
Console.Write(kb.key[0].label[1].Text[0]);
Console.Write(kb.key[1].label[0].Text[0]);
Console.Write("\n");
}
}
}
Java でも JAXB とか使うとバインドできる みたいだけど、インストール面倒なのでとりあえずパス。
09:30 起床, 10:30 出社。
方針変更に伴う作業を一気に行う。 目に見えて読み込み速度が改善された。
メモリ領域にもかなり余裕ができて一安心。 メモリ管理の方針に関しては、これで確定。 二度といじらない方向で。
常に必要なデータなのだし、 毎回ファイルから読み込む必要もあるまい。 というわけで ELF ファイルの .data セクションに直接埋め込み。
アライメントの設定を忘れてハマる。 これはライブラリ側で assert() すべきだ、 ということで後でメール書いておこう。
というか立ち話。 決まることあり決まらぬことあり。
必要最小限のファセットを設定したスキーマ定義を書いて、 InfoPath で入力画面を作る方法は理解した。
InfoPath は基本的にはフォームを対話的に作るためのソフト。 フォームのデザインは HTML と同程度には自由が利き、 また入力データの検証も XML スキーマに基づいて自動的に行われる。 ただし入力したデータに対して計算を行ったり、 複数のテーブルに分散したデータを動的に結合しながら処理するのは難しい。 そういう用途には Excel や Access を使うか、 RDBMS をバックエンドとした Web アプリケーションを組むのが正解か。
あと unique, key 制約のかけ方と、 JScript を用いて細かい処理を行う方法を理解したら、 誰か捕まえて既存の CSV データを XML に移行してもらおう。
22:00. ダメだ……。
C FAQ 曰く、対処方法は次の二択。
私が今月前半に実装してた Hierarchical State Machine では、 状態を表現するのに関数ポインタを使っているので同じ問題に出くわしました。
Practical Statecharts in C/C++ に掲載されている Quantum Framework では 1 の方式を採用していたのですが、 クラステンプレートで書き直していたらソースコードが煩雑になったので、 私は 2 の方針で書き直して使ってます。 概略、こんな感じ。
template <typename T>
class QsmState
{
public:
typedef struct QsmState (T::*QsmStateHandler)();
QsmState(QsmStateHandler handler)
: m_handler(handler)
{}
operator QsmStateHandler() const
{
return m_handler;
}
private:
QsmStateHandler m_handler;
};
09:00 起床, 10:00 出社。
InfoPath に食わせるスキーマとフォームデザインの関係で謎だった部分が判明。
現状の CSV ファイルを置き換えるに足るスキーマを書いて移行作業中。 明日には終わる。
作成した XML ファイルと、 別のデータファイルから最終的なバイナリを作成するプログラムを書く必要アリ。 この部分はサブプログラマにお任せする方向で。
スクリプトにもスタートアップルーチン (gcc だと crt0.o 相当) が必要だ、 という話になる。 プログラマがスクリプト実行開始直前にいろいろ環境設定しておいて、 スクリプタには、 その環境を前提としてスクリプトを書いてもらう。
スクリプトと C++ のコードとのやりとり処理。 エフェクト担当プログラマが「汎用エフェクトのシステム部分」「ゲーム個々のシーン固有部分」をどう扱うかで悩んでいたので話し合い。 汎用エフェクトがゲーム中のコンテクストを関知するのはマズいので、
とするのが良かろうという結論に。 ……図を書かないと話が見えんな。
調査。 経路を見つけるだけなら A* で終わりだけど、 自然に見えるように動かしたいとなると話がややこしく。 複数のオブジェクトが同時に動くとなると、なおのこと。
書棚を漁って計算幾何学, ロボット工学方面でいくつか情報を見つける。
20:00.
ANSI のオンラインストアに、 改訂された C++ の規格書が US$18 で登場。 書籍版を 先日購入したばかり だが、 買わざるをえまい。
09:30 起床, 10:30 出社。
既存の CSV データを XML に移行完了。 私の方は、これでしばらく XML 関連の作業は中断。
今後の予定
データベース中にスクリプトファイルの識別子なども埋め込む必要があるため、 スクリプトを実機に組み込むのに先立って 2 の作業が必要。 ここまでケリがついたら、 改めて状態遷移に手を入れるか。
配置決め他、いろいろ。
アルゴリズムの検討。
障害物の位置が固定なら (たとえばマップ上の建物とか)、 事前に可視グラフを計算しておくのが良さそうだが、 障害物が動くとなると可視グラフを動的に計算する必要があり重そう。
むしろマップをグリッドに分割して A* で経路を見つけ、 その経路を更に 2 pass ぐらいかけて改良するのが良いんじゃないか、 という話に。 細かい話はともかく、 大枠はこれで行けそうな気がしてきた。
進捗確認ほか。
企画側から、新しく追加したい要素の話が出てくる。 まだアイデアレベルの話で、 実現できるか否か、 あるいは実現できたとしても挙動や画像のクオリティを保てるかが微妙なところ。
本格的に仕様に組み込むには、 少なくとも以下の事項を明確にしておく必要がある。
このあたりを決めるに当たって参考になりそうなソフトを自社ブランドで見つけたので、 そちらの開発者に話が聞けるか調べてもらうことに。
チームのプログラマの面々で。
今のチームで新メンバー歓迎会以外で飲みに行ったのは、始めてのような気がする。 ま、たまにはね。
7.5β版の提供開始。 機能をクラス図の作成に制限した Community Edition が登場。
相変わらず State Chart で、
という状況で s1 から s11 に遷移させようとすると矢印が思い通りの位置に引けない。 そもそも UML の規格では複合状態 (他の状態を包含する状態) と単純状態 (他の状態を包含しない状態) を明確に区別していて、 オブジェクトは常に単純状態にあることが要求されるから、 s1 から s11 への遷移というのが想定範囲外だから仕方ないか。
現実には、 複合状態に留まることを認めても実行効率に大した悪影響はないし、 むしろ不要なデフォルト遷移が減って状態図はすっきりするため、 私が書いてるフレームワークでは複合状態への遷移を認めている。 あとで MagicDraw 社に、 このあたりの背景説明と共に「複合状態から、その複合状態が包含する子状態への遷移の矢印を思い通りの位置に書きたい」と要望を出しておくか。