SyntaxHighlighter

2012年3月29日木曜日

用語の整理

やりたいことの名前が分かってきた。超適当にタスクとか呼んでたけど、どっちかっていうとスレッドとかプロセスとかいう名前だった。処理の分割の単位のこと。
スレッド ⊆ プロセス ⊆ タスク

多分やりたいのはマルチプロセスじゃなくて、マルチスレッド処理だと思う。

もう少し先を見据えておく

処理速度にこだわるならマルチコア対応だろう。
でもこれは雰囲気で言ってみただけで、実際のところこの言葉の意味は分からない。
人生で全く勉強してこなかったツケがかなりまわってきている。
専門・大学でこれらをちゃんと勉強した人がちょっと羨ましい。

なんとなくのイメージだと、1つのCPUだけじゃなくて複数のCPUを使って処理をして、高速化してくれるような印象だ。これって、C++で書いたソースのレベルで記述するものなのだろうか。それともコンパイル時にうまいこと勝手にやってくれたり、実行時に環境側がなんとかしてくれるのだろうか。

並列計算ってことだよな多分。Wikipedia読む限りだと、巷で話題のHaskellとか使わない限りは、自分で何とかしろって感じに見える。Haskellで調べてたらそれっぽい定義があった。リンク先で並行/並列/分散プログラミングの定義がされている。なるほど。

分散計算は明らかに普通のゲームには向いてないと思う。ハクスラとか適用できる要素が分からない。Googleがギガントでも開発したらそれに使うかもしれないけど。
並行計算はどうなんだろう。できる部分とできない部分が有ると思う。多分、キャラクタ同士の関係の計算を分離する必要があると思う。

boost::MPIとかboost::Treadとかそれっぽいけど違いが分からない。調べてみよう。

別に今すぐ導入するとかじゃなくて、今後導入するとなったときに根本的にプログラム書き直さないとダメとかなると非常にだるいので、そうならないように予め調べておこうと思う。

2012年3月27日火曜日

たくさんの敵の処理 現状編

どうやって処理の大きさを測るかという問題に対してはタスクシステムの導入がいいかもしれない。

現状だと、毎フレーム処理したり監視したり更新したりする必要のあるオブジェクトにはすべてvoid Step(int current_time)みたいなインターフェイスのメンバ関数があって、毎フレームそれを実行している。

簡潔ではあるが、外からは何をしているのかは分からないし、処理の大きさはそのオブジェクトしか分からないので、最適化しにくい。まぁ、結局処理の大きさはキャラクタ数と密集度でだいたい決まるので分かるといえばわかるのだけど、これはキャラクタがどれもだいたい同じ大きさの処理という前提があるからだ。しかし、今後そうである保証は無い。

それを逆に、保証してしまえば良い。
だいたい同じくらいの処理の大きさにStepを分割して、タスクシステムに処理を登録。
タスクシシテムは数を数えるだけで1Stepあたりの資源を簡単に把握できる。
タスクに優先度を設定すれば資源の分配がより効率的になる。

…でも、タスクシステムに処理を登録するかどうかっていつ誰が判断するんだ?

1.キャラクタが生成されたとき
2.衝突したとき
3.毎フレーム存在するもの全部登録

現状のStep関数を回して、そこから必要なタスクを生成登録するのがベターかな。

たくさんの敵の処理

Hey, Scripting Guy!のコラムが楽しくてそっちばかりずっと読んでた。
でも、先週CUI童貞を卒業したばかりなので、PowerShellを有効に使ってるとはいえない。
繰り返し動作は積極的にCUIに任せて行きたい。

閑話休題。

リアルタイム処理なアクションゲームにおいてパフォーマンスは非常に重要だ。
速度こそ命である。
現在MyGameは以下のような問題を抱えている。

・だいたい自機・敵機・弾合わせて500個くらいが限界
・敵機が自機を捕捉した状態だと50~100個くらいが限界
・捕捉すると敵が自機周辺に密集するので50個ぐらいで60fpsを割る

このパフォーマンスはIntel® Core™ i7-960でデバッグモードで実行したときのもの。
その環境で動かないゲームなんて現状産廃にしかならない。

まだ、実際に処理時間を計ったわけではないので計る必要がある。
しかし、だいたいの改善方針を立てた(実のところ実際に計るのが面倒だったため、方針ばかり考えていた。

前提として、敵が適切に分散・停止していれば1万個でも問題ないというのはBox2Dを使い始めた初期に実験して確かめた。
大事なのは不要な処理をしないことと、大きな処理でも1/60秒以内に必ず結論を出すことだ。
この2つはまったく別のアプローチなので分けて考える。

不要な処理をしないというのはヒューリスティクスな問題だ。
いくつか不要と思われる処理がある。

明らかに遠くにいる敵が毎フレーム自機を探索するのは(プレイヤーの体験として)無駄である。幸い自動生成された迷路は部屋ごとの関係性を出力しやすいので、同じ部屋にいる者同士のみが探索を行ったり、少し拡張して探索範囲は隣の部屋まで、といったこともできそう。
現状、近くにいる敵の探索方法も効率的ではない。しかし、機能も充分とはいえないので改善するにはまだ早い。
Box2DのBullet処理も悩みの種だ。Bulletは弾同士がすり抜けないように弾道を再帰的に計算してくれるのだが、当然これが重い(自作するよりも遥かに効率的で素晴らしいのだけどね)。どれくらい重いかというと、経験的には同じ処理時間なら8倍くらい物体の密度に差が出せる。特に密集するとヤバイ。敵に密集させないように行動させるか、Bulletを外すか、敵の数を減らすか、という問題になる。これは一番目の答を選びたい。Box2Dは物体が物体にめり込んだ場合、物体の中心点同士の関係に応じて斥力が働いて上手く距離をとってくれるが、中心点が重なると(充分に近いと)くっついてしまう。深刻なバグというほどでもないが、発生頻度は決して低くないし、Bulletを外すとこの現象はさらに発生しやすくなる。しかも一度発生すると「宇宙の 法則が 乱れる!」ので、そのb2Worldを長期間稼動させるならこれは避けたい。

あと、毎フレーム処理(出力)しないというのも大事な方法だと思う。
これはもう一つのアプローチにも関連する。

大きな処理でも短い時間に分割して処理したり、とりあえずの暫定的な結論をだす機能があればフレームレートに影響を与えないかもしれない。将棋囲碁ソフトなんかは自然にやってのけてると思う。
例えば、税金の使い方みたいにあらかじめ予算を組んで、その予算内で仕事してください、と各部署に頼むみたいに。末端の人間のやることが決まっているのでこの方法は上手く働くと思う。でも、「予算足りないのでこっちにまわしてください><」みたいな自体には対応できない。だから予算の配分が何よりも重要になる。これは実際に計ってみるしか無いし、お役所が前例主義なのはシステム的に仕方ない。でも、ある程度大まかに分けたら、あとは分割しすぎないほうが資源は自然に効率的に分配される。
あと、どうやって大きな処理を分割するかという問題になる。分け方には縦割りと横割りがある。縦割りは省庁ごとの分割、描画とか衝突とかAIとか。横割りは、AIが「考えること」を時間数で分割して、前のフレームと今のフレームと次のフレームが連携して1つの問題に取り組む。

そもそも横割りが必要なほどの巨大な処理をするべきかという問題もある。処理が充分に小さければこんなことは考える必要が無いのだ。でも、100体でも1000体でも問題なく動くゲームにはこの仕組みが必要になるかもしれない。まぁ、実際には1000体になったらどうするか、という問題を末端に丸投げしているだけなのだが。仕事増えたけど、予算変わらないけど、優秀なキミタチならなんとかしてくれるよね、と頼む。そして、頼まれた側は可能な限り手抜きする。精度を落としたり、AIを単純にしたり、描画をシャギらせたり。でも、待って欲しい。はじめから手抜きが許されるなら、いままで100体でやっていたリッチな処理は無駄だったんじゃないだろうか。そう考えると初めから1000体で最適化しておけば効率的だったのではないだろうか。

これは部分最適と全体最適の問題である。1000体で最適化しておけば良かったというのは、部分最適の経験が蓄積したから全体最適の結論として言えるわけで、処理の前にはそんなことは分からなかったのである。全体最適されたシステムは効率的だが、汎用性が低い。だから問題の本質は、「そのシステムはあらゆる事態に対処すべきか否か」である。

あらゆる事態とはどんな事態だろうか。ゲームにおける事態の幅は、動くオブジェクトの数が多いか少ないかしかない。これは事前に分かることだ。PCゲームにおいては処理環境の性能不足という不測の事態もあるが、これも事前に分かることだ。

しかし、事前に分かるといってもその調整は誰かがやらなくてはいけない。手作業でやると、機能の追加のたびに調整員が死ぬ。なんという労働集約型ビジネス。こんな環境は人類のためにさっさと駆逐しなくてはいけない。

汎用性の高い横割りシステムを作って、それを少し動かした後、勝手に全体最適化してくれるシステムが文句なしに最強だ。多分既に誰かが作ってて名前があるはずだけど、知らないので調べてみよう。

あぁ、結局まだ何もしていない。

2012年3月26日月曜日

週末にやったこと

やったことを細かく記述しよう。
意味のある記述をしようとするからよくない。
実際何もやってないのに書いてやった気分になるのはよくない。

週末やったこと
・仮想OS(VMWare Player)に興味を持った
・Emacsに再び興味を持った(drill-instructorに叱られたいと思った)
・自分の使う環境を、車輪の再発明でも自分で構築することに興味を持った(DIY?)
・やりたいことと自分のスキルのバランスが取れてないから、小さいことからやっていこうと思った
・RSSフィードを編集して効率的にネット巡回しようと思ったけど面倒臭くて投げた
・Google Readerからやりたいけど方法が分からなかった
・AVAとBF3はたくさんやった。どっちもM14ずっと使ってた。M14は美しい。

結論
・何もやってない。

どっかの2chまとめで読んだけど、ネットを巡回するだけの存在だけど、ネットの波に乗れてないからサーファーでもなくて、浜辺でうろうろしている不審者、みたいな記述がまさに自分のことだと思った。

2012年3月24日土曜日

本当に足りないゲーム

来週から本気出す

月曜日(3/19)から今(土曜日)に至るまでほとんど何も進んでない。
完全に寄り道してた。
.Net Frameworkで遊んでた。

.Net Frameworkは必要なものはたいてい揃っている気がするから、何かしようと思ったらその手段のありかを探すのだけど、探す時間が伸びるとだれる。かといって自分で作るのも悔しい。あと、自分で作るならC++で書きたい。

あと、C++/CLIは.Net FrameworkをC++で利用するためのもので、C#でC++で書いたものを利用するものではないらしい。後者をしたいのだけど、方法がよくわからない。


ハクスラの方は一週間寝かせたので、作業は進まなかったけど、脳内仕様はわりと固まった。

基本的には、妄想だけ膨らんでいた機能やコンテンツをバッサリ切り落として、個人製作可能な範囲にまとめる方向にした。例えば武器やスキルの種類だけ作業量が増えるのだけど、操作は単調にしたくないのでスキルは減らしたくないし、武器のカスタマイズ性も損ないたくないので、武器の種類を大幅に減らした。
個人的に近接攻撃があまり好きではないので、それを減らす方向で。殴るのは嫌いだけど、ショットガンは好き。敵より短いリーチで戦うのが嫌い。その理由については多くあるのだけど、今は話がそれるので簡単にしか書かない。いつか書くかもしれない。

殴りが楽しいハクスラは既に競争相手が多すぎるというのもある。
Diablo 3は既にスタンバってるし。
Titan QuestのチームがGrim Dawn開発してるし。
Dark Questやその他多くのコンソールARPGも殴りが基本だ。
MythosやLineage Eternalなんかも多分気持ちの良い殴りゲーだろう。

自分はHackもSlashもそんなに好きではない。
Diablo 2もそれほどプレイしなかった。
ハマったのはHellgateであってその中でも銃器使いのMarksmanや万能職のEvokerが好きだった。

こいつらの戦いの唯一の美しいあり方は「接近される前に倒す」である。
つまり接近して殴られたら死ぬ。
近付けば効率よくダメージを与えられるが、被弾リスクが高い。
これは非常にシンプルだ。


そういう意味ではFPSのSerious Samみたいなコンセプトが好きだ。
大量の敵が押し寄せてきて、効率的に捌かないとあっという間に囲まれて死ぬようなゲーム。


それに対して、敵にちんたら歩いて近寄って目の前で盆踊りするようなゲームはだめだ。
気泡緩衝材をつぶしているような気分になる。
ひねり潰したい衝動に駆られる。欲求不満になる。
ヒットアンドアウェイなんてのも、結局のところハイリスクな飛び道具でしかない。
敵の胸元に飛び込むのは手下のゾンビがやればいいことで、プレイヤーの仕事じゃない。

Serious Samのようなゲーム性は近接職でもできないことはないだろうけど、非常に調整が難しいだろう。例えば、完璧に立ち回ってもチマチマと削られるのは悪いストレスだ。しかし、完璧に立ち回ればノーダメージとなると、無双シリーズのような単調な戦闘(好みでない)か、DMCシリーズのようなプレイヤーにシビアなレスポンスを求めるゲームになる。DMCはとても好きだけど、ハクスラはある程度だらだらやるゲーム(…ですよね?)なので戦闘中に0.2秒単位の回避を求める緊張を与えるのは悪いストレスになる可能性が高い。いや、操作に熟練してフローに入っちゃえば、緊張が転化して普遍的な気持ち良さを提供するんだろうけど、その習熟コストは万人が払えるものじゃない。これは多くのハードコアなゲームが抱える問題だ。

その点Serious Samは操作自体は単純なのだけど、素早く行動の優先順位を考えるという緊張がある。これはさっきも書いたように構造自体がシンプルだから、慣れるのは簡単だ。慣れてしまえば考えてること自体を忘れて、ひたすら俺Tueeeを味わえる。まぁ、そうなると、やってることはドラクエやWizardryのコマンド戦闘と大差ないかもしれないけど。気持ちよければいいのです。

ただ、ドラクエの戦闘は素晴らしいのだけど、ドラクエにはできない戦闘を実装したい。Diablo 3やLineage Eternalみたいな規模のゲームで実装できない、全くスケールしない実験的なキワモノにしたい。ハクスラの本質的な快感のあり方を調味料にして、それでようやく食えるようなものにしたい。具体的に書いてもいいけど、公開するとモチベーションが下がりそうだから書かないことにしよう。


来週から本気出せればいいね。

2012年3月23日金曜日

寄り道その2

C#でできることがなんとなくわかったので満足した。
そういえばC++はダメだけど、C#だとUnityを無料版で弄れたような。
今度弄ろう。


C#とか弄って、.NetFrameworkすげーってなってPowerShellやべーってなってる。
なんか日々やってることはもっと便利に自動化できることに気付いて感動してる。
ゲーム作ってる場合じゃない気がしてきた。
というか、PCとかプログラムとかの本来の用途がわかってなかったのかもしれない。
文系という免罪符の下にくっそ狭い世界しか見ようとせず生きてきたようだ。


味を占めてさらに別言語も弄ってみたいと思った。
Webアプリとか通信とかさっぱりなのでPHPとApacheをインスコした。
導入がめんどくさくてそこで力尽きた。

2012年3月21日水曜日

寄り道

自分はC++以外の言語に触れたことが無い。
ゲーム作ろうと思って3ヶ月前に学び始めた次第。

ただ、ゲーム作るついでに学んだことで色々できるようになってくると、製作中にこんなアプリ欲しいなぁと欲が出てきたりする。そんなわけでC#でWindows Presentation Foundation(WPF)を弄って簡単なWindowsアプリ(ToDoリスト的なもの)作ってみている。実のところ、そんな簡単なアプリケーションすら作ったこと無い。

WPFはびっくりするほど簡単にそれっぽいものが作れる。

簡単な自分用アプリを作るとき、特に実行速度が要求されないような場合はC#を使うようになるかもしれない。



Design and Evolution of C++を読んだ後にC#の仕様を見るとなかなか面白い。
Cとの互換性のために嫌々搭載されてるような機能がバッサリ切り落とされている。
あとC++みたいなスピードに拘らなければならないみたいな脅迫観念が無くて、ユーザーが落とし穴に落ちにくく、より簡単に安全に使えるように考えられてると思う。
まだ1日しか使ってないけど、比較するとなかなかに美しい言語だと思う。

ただ、多重継承が無いのは不便じゃないのかな?
わからない。



ゲームのUIなんかはC#でプロトタイプ作るのもアリだと思う。
そもそも言語が出力するものが違うので、そのまま流用は出来ない(と思う)けど、プロトタイプは色々試せるものの方がいい。

2012年3月19日月曜日

ひとつずつ、着実に

今回は課題こそ決して難しいものではないが、過程において得るものが多かった。
テストの存在はスタックトレースを考えた頃から自分の中で重要度を増していった。

原因が分かりにくいデバッグはだるい。
この世から抹殺したい。

テスト。
テストコードとテスト対象(実装したい機能)を平行して書く。
CreateMaze()を書くためにCreateMazeTest()を書いて、場合によってはCreateMazeTest::DrawMaze()まで書く。
視覚的に一瞬で結果が分かればモチベーションも高まる。
CreateMaze()の仕様は実はMazeクラスとMazeTest()を書いたときに大体決まる。

ただあんまりテストコードが肥大化するとテストコードのテストコードが必要になる気がする。
このあたりはまだ分からない。

作る前に完全な仕様を思い浮かべるのは困難だ。
まず手を動かしながら考える方がいい。
何を出力したいか、どんな機能が必要かという事をテストコードから考え、仕様を逆算することも出来る。

機能と機能を組み合わせたときに足りない機能が見えてくることもある。
そのとき追加した機能をすぐにテストしたい。
単体テストのコードがあれば、もう片方の機能が出来上がってなくてもすぐテストできる。

テストが前提になると1つの課題が小さくなる。
なぜなら複雑なテストは組み合わせの数だけテストが膨大になり、面倒だからだ。
小さな課題は解決しやすい。
大きな課題を小さな課題に分割する指標としてテストの存在は大きい。

コード読解は面倒だ。
意味は分かっても、完全に正しいかどうかは分からない。
人間の目で判断する作業は非常に神経をすり減らすものだ。
時間が経ってブラックボックス化してしまった機能も、テストコードさえあれば「とりあえず動いている」ことはすぐに確認できる。

テストコードを書くことはいい事ずくめだ。

自動生成ダンジョンのプロトタイプ

アルゴリズムは洗練されてないし、生成がデシ秒単位でとても遅いけどとりあえず出来た。


一応、迷路の大きさは可変。
boostのdynamic_bitsetとか導入した。

マスの大きさを変えられたり、もうちょっと通路が環になればいいと思う。

2012年3月16日金曜日

Unity神輿

Unityが猛烈に気になる。
余りに進化の速度が早い。
Asset Storeで売られてるツールが安くてコンパクトで強烈に見える。
導入したら楽しくなるだろうな、というのが簡単に想像できる。
「乗るしかない、このビッグウェーブに」なのか。

Unity神輿なんだよな。
何もしてなくても競争に晒される。
勝つためには一人では力不足で何かを担ぐしかない。
神輿から恩恵を受ける変わりにUnityに貢献する。
勿論ユーザーが受け取ってるモノの方が圧倒的に多いのだけど。
それを信仰すればするほど、信じる他なくなるのが怖い。

とりあえず、いつか書いたけど、今の環境で作り上げてから考えよう。
Unityへ移植してリッチにするのはそれからでも良いし。
Diablo3への後出しジャンケンも出来るし(笑…っていいのかこれ……

Unity。 RivalTheoryチームが怖い
別に業界人じゃないけど、この人の気持ちが今はすごく分かる。

2012年3月15日木曜日

部屋の自動生成

前回迷路作ったので今回は部屋を作った。
連絡通路の方向を決めれば適当にランダムな部屋を作る。

部屋の形状の情報をブロック単位(普通のRogue部屋)で出力するか、ローカル空間(迷路の1マス分、セル)に対する相対座標にするか迷ったけど、汎用性を考慮して後者にした。でも、いまのところブロックでも出力可能な部屋しか生成してない。


セル間の通路の道幅をランダムにしたけど、見栄え的に1つの通路は同じ幅の方がいい気がする。
一つの通路は[部屋Aからの通路,セル間連絡通路、部屋Bからの通路]で構成される。

次は連絡通路作ろう。


ゲームに反映するまでの残り工程
・連絡通路作成
・迷路、部屋、連絡通路の合成
・Box2Dへの変換



ふと思ったのだけど、ゲーム作っているよりこの部品製作の方が楽しい。
多分、仕様を考える→書く→テストする→正しく出力される、の過程がスムーズだし、出力結果がすぐ目に見える(Dxライブラリだとすぐ書ける)だと思う。
ゲーム部の記述はオブジェクト同士の関係性の記述や、それらの処理フローの記述ばかりで、ヴィジュアル的には非常に地味だ。しかも複雑でバグが見えにくく、テストしにくくて頭が痛い。
小さいものを書くのがいいね。

2012年3月13日火曜日

胡散臭い迷路

迷路自動生成アルゴリズムを参考にさせて頂きました。
ただ、細かいところが怪しくて微妙に道幅が広い。

壁倒し法なので一応全部の通路が繋がっていることが保障されるはず。

48x48

64x64

120x120

実際に使うには一番上の迷路ですら広すぎるのでもっと小さくするかも。
迷路の1ブロックを1部屋(もしくは通路)に見立てて以下のように(Rogue形式)で連結。


それをBox2Dのstatic_bodyとして出力しつつ、自前のゲーム部の壁キャラクタとして登録する。Box2Dは凸型シェイプしかサポートしないので、地味にめんどくさそう。

2012年3月12日月曜日

ランダムに生成されるダンジョン

ローグっぽくてもいいけど、迷路にするのはなんか微妙。
さまざまなアクションが生かされる舞台である必要がある。
いいアルゴリズムはないだろうか。

マンデルブロ集合とかいうフラクタル?とかなんとかが面白そうと思って調べた。

そしてリンクを参考に簡単にDxLibで出力した。
右上の数字は計算回数。つまり、大きいほどより複雑に出力される。













これがダンジョン生成に使えるかというと、非常に難しいと思う。
適当に複雑な図形を出力することは出来るけど、それなら別にフラクタルじゃなくてもいいし。

部屋と通路の組み合わせ以外の方法は何かないだろうか。
模索中。


(同日追記)
Maze generation algorithmというらしい。
とりあえず迷路が手に入れば、あとはRogue形式で部屋を作ればいいのか。
当たり前の話なんだけど気付くのに時間がかかった。
迷路は部屋と部屋の連結の表現であって、部屋は出入り口さえ作れば中身はどうでもいい。
抽象化のレベルが1つ上がった。

このジャンル、先人の創意工夫の歴史が多くてサーフィンしてると面白い。

汎用ゲーム実行フロー

・できる?

できない → しない
できる → いつかやっといて

・俺のターン

・タスク消化

三者面談
A→できる?→B
B→できる?→C
C→回答→B
B→回答→A
A→じゃ、やります→B
B→やっといて→C

このフローから分かることは、仕事をこなすことも重要だが、先んじて何をするかを決めることも同じく重要ということ。末端のオブジェクトは何が出来るかを常に公開していなくてはいけないし、上流のオブジェクトは最小限の命令で必要なオブジェクトを働かせることが望ましい。

社会の縮図を感じる。

2012年3月11日日曜日

細かい変更

skillやweaponに対してuseやinvokeやreloadみたいなインターフェイスで使ってたけど、命令が増えると思い通りに動かない。
命令間の整合性を保つために、コマンドを呼んだ時に可能なら即実行じゃなくて、命令を少なくともそのフレームの間はスタックしておいて、優先順位をつけつつ不要不可能な命令は無視してそのフレームの終わりにまとめて実行する方がよさそうだ。

reloadをshootでキャンセル可能にしたのはいいけど、それらを同時に実行できるとかいうわけの分からないことになったのでそういう問題が発生した。あと、shootの後、次のshootが可能になるまでの間隔はreload出来ないほうがいいかもしれない。shotgunのshootがreload連発でRoFが向上するとか言うわけの分からない状態を直そう。

2012年3月9日金曜日

単体テスト?

テスト駆動開発ってかっこいいな。
printfもどきじゃなくて、assertマクロ使えよ。
って言うか、それよりもちゃんとテストしろよってことか。


ゲームの方は、銃の弾倉オプションとしてチューブマガジン実装した。
普通の弾倉はQueueだけどチューブはStack。
最後に入れた弾が最初に出るので、弾の種類を臨機応変にすれば楽しく立ち回れる…かも。

リファクタリング成果

リファクタリング成果という名の日記。

・だいたい30%ぐらい効率が向上した。
敵100体から130体ぐらい動かしてもOKの変化。内部でどうなってるか分からないので、30%というのは実に適当な数字だ。効率ってなんだよ。

・標準STLのアルゴリズム
だいたい使えるようになったのでループが見やすくなった。以前は関数オブジェクトのことを関数のポインタかなにかだと思ってました。ただのクラスですね。

・生ポインタ撲滅運動ができた。
設計がだいぶまともになったのでshared_ptr,weak_ptr,unique_ptrの使い分けが出来るようになった。nullptrとの比較じゃなくてexpired()使うようになったので非常にお行儀がよくなったと思う。でも、他ライブラリと連携する場面だと、ナマポ使わざるを得ない。
静的記憶でもよさそうな場面でも、継承することを考えるとポインタで持ってた方がメモリ的には(継承元の使わない機能とかあると)無駄がなかったりするような気がする、けど、実際の効率は知らない。
所有権が明確になるので、積極的にポインタが使えるようになる。そのおかげでコピーや情報の更新の手間が大分減る。

・バグの特定スキルが向上した
デバッグが長引くと異常なまでに萎えてくる。これは重要。

・ゲームの開発意欲が若干低下した
あれ?
なんか、人としての視野が若干狭くなった感が否めない。

2012年3月4日日曜日

無題

機能が明らかなクラスは演算子をオーバーロードすると見た目がすっきり。
クラス名は名詞、関数名は動詞にしてるけど、両者の語源が同じなら関数オブジェクトにしてしまったほうが良いのかもしれない。
見た目が変わってないので、相変わらず進捗SSは無いです。


Ameroadの話題、熱いなぁ。早いしスマートだし。

2012年3月3日土曜日

時代が早くしろと言うのです

開発にスピード感がない。
最適化のためにリリースが遅れるのは悪みたいな風潮が辛い。最適化のスピードがハードウェアの進歩よりも遅いなら無駄と言われても仕方ないような気もする。でも、ハードウェアの性能が10倍になるのに5年かかって、ソフトウェアの効率を10倍にするのに5年かかるとしたら、どっちもちゃんと仕事すれば5年後には開発開始当時の100倍の体験が出来るよね。18ヶ月で等倍の効率のソフトウェアをリリースしてもその時点では18ヶ月前の2倍(cf.ムーアの法則)の体験しかできない。

まぁ、机上の空論と一蹴されるような話ですね。
企画クラッシャーにならないように頑張ろう。



以下、まったり開発の試行錯誤。


const修飾子つければダウンキャストしていいんですね、知らなかった。
推奨される事はないだろうけど、こういう書き方も出来るんだなーと。
つい多用したくなりそうだ。

こんなのが必要な場合、関数fの引数の型のBaseクラスの設計が悪いとは言えそう。
もう一段階抽象度を上げれば解決しそうだけど、まぁ、優先度は低いので後でやろう。



もう一つ設計の問題(解決済み)
何かのクラスに何かの値をセットしたいとき。

クラスTが充分に小さかったらこれでいい(かもしれない)のだけど、コピーコストが無視できないときがある。
どっかでT作って捨てる処理が1回余分に発生するので。
その時右辺値参照が便利そうなのだけど、そのためにはSet関数の引数のconst外さないといけない、と思う。

めんどくせー。

ゲームのプログラムで値をセットするためのオブジェクト(ただのラッパー)なんてどうせ一時的なものなので、constなんていらなかったということですね。




あと、ハマったことのメモ。
MSVC++ 2010でのコンパイルエラー

error C2248: 'std::unique_ptr<_ty>::operator =' : private メンバー (クラス 'std::unique_ptr<_ty>' で宣言されている) にアクセスできません。

unique_ptrをprivateなメンバー変数に持つクラスをコピーしようとすると発生した。同様に代入もダメ。自動生成されるコピーコンストラクタじゃ対処できないので、自分で書かないといけないってことらしい。
上手いこと自動でやってくれないのね、って思ったけど良く考えるとそれも困るのか。unique_ptrで管理されるインスタンスの所有権が曖昧にならないよう、コピーメンバ関数みたいなので実装したほうがいいかもしれない。

コピーメンバ関数?

メンバが増えると書き直さないとダメだけどとりあえずこれでいいのかもしれない。
・引数にとったクラスのprivateメンバってアクセスしていいのね…(自身からのアクセスってことになるからなのか?当然引数にconst付いてるとこんなこと(swap)は出来ない)
・copy実行すると引数にとったクラスのメンバー変数のポインタ(pimpl)はnullptrになる


【同日追記】
そもそも最初からunique_ptrで管理してればコピー関数なんていらないかもしれない。
新しくインスタンスが作られないので。

これならポインタを付け替えるだけなので、コピーコンストラクタが呼ばれない。
関数に渡すときはunique_ptrごと参照で渡す。
つまるところ、unique_ptrは感染するということになるのだろうか。

2012年3月1日木曜日

ダメな開発例を学んだ

リファクタリング作業もほとんど終わり。
でも、こんな作業2度とやりたくないとか思ってます。

今までの開発は”とりあえず動くもの”を作って、そこに機能を追加していく形でした。個人開発なので適切な表現か分かりませんが、アジャイルと言えると思います。機能を追加してすぐ試せるので、モチベーションが下がりにくいですし、バグも早い段階で取り除けます。

しかし、コードの複雑化により、機能の追加が困難になってきました。そこでリファクタリングすることにしました。

今後の機能追加に耐えられるよう、柔軟で使いやすい設計を考えました。今までの資産も流用できるようにしました。その後、コーディング作業に取り掛かりました。しかし、リファクタリング開始前に考えた設計では必要な機能が足りず、リファクタリングしながら順次機能追加をしていきました。

そして頭がこんがらがりました。
進捗状況や作業中のコードと完成したコードの区別がわからなくなりました。
そのうち脅迫されたようにコンパイルを通すだけの作業になりました。

コンパイルは通ったが即エラーが!単純なものでしたが。

今回の経験で色々な教訓が生まれました。
まとめると以下の2点です。

・自分はメモとか苦手
未完成のコードとそうでないコードを分けるためにコメントとかしません。
それでも大丈夫な作業形態にすべきです。

・作業は小さく
そもそも、今回だって一度に一気にリファクタリングする必要なんてなかったのです。
それに終わりの見えない作業は誰だって苦痛です。



とりあえず、明日には2/22時点と同等の機能をもったもののところまで終わりそうです。