トップページgamedev
1001コメント599KB

タスクシステム総合スレ part3

■ このスレッドは過去ログ倉庫に格納されています
0001名前は開発中のものです。2008/11/09(日) 11:51:40ID:+pjnJyQQ
タスクシステムについての議論、相談、質問、雑談などのスレです

part2 http://pc11.2ch.net/test/read.cgi/gamedev/1196711513/
part1 http://pc11.2ch.net/test/read.cgi/gamedev/1173708588/
0793名前は開発中のものです。2009/01/29(木) 22:21:12ID:CK8Av1bR
>792
そいつは御本人様で確定だろ女子高生的に考えて
0794名前は開発中のものです。2009/01/29(木) 22:29:58ID:/PUT5suM
>>790
誰?レスつけてないじゃん

>>791
は?誰?何聞いてるの?
オブザーバーはタスクシステムじゃないってw
まだ納得してないの?

>>792
>ご本人じゃないなら無視すればいいのに。。。よくわかんない人でつ
お前もレスつけなきゃいいのにねw
一番熱心にIDかき集めてきたの君だけどw
0795名前は開発中のものです。2009/01/29(木) 22:34:32ID:CK8Av1bR
すげぇチキンだなコイツ
0796名前は開発中のものです。2009/01/29(木) 22:46:01ID:/PUT5suM
>>795
お前こそなにか主張はねぇよかよw
0797名前は開発中のものです。2009/01/29(木) 22:55:32ID:CK8Av1bR
なんでオレに話しかけてくんだこのニワトリ
世話役の奴ちゃんと面倒見ろよ
0798名前は開発中のものです。2009/01/29(木) 23:05:24ID:C5KCdvlq
おまえにまかせた
0799名前は開発中のものです。2009/01/29(木) 23:14:57ID:/PUT5suM
>>797
ん?主張がないなら俺の勝ちだけど?w
0800名前は開発中のものです。2009/01/29(木) 23:20:53ID:tPxukM8x
イタタタ
0801名前は開発中のものです。2009/01/29(木) 23:24:21ID:/PUT5suM
>>800
おw
また頑張ってID集めてくんのか?w
自分のがナチュラルに痛いくせに人のこというのか?
0802名前は開発中のものです。2009/01/29(木) 23:26:29ID:/PUT5suM
お前等、何度もいうけどデザパタよく読まないで書き込むからこういうことになるんだぞ
次はパターンも目的ぐらいは自分が適用した理由に添えられるように努力しろよ
いまのままじゃ恥ずかしいぞお前等
0803名前は開発中のものです。2009/01/29(木) 23:38:46ID:KxuOv8bV
イベントドリブンなプログラムでobserverは基本中の基本だろ……
コールバックをOOPスタイルに抽象化したのがobserverだぞ
発言が面白すぎるので愛でさせてもらってるけどな
0804ID:2rWIRnW32009/01/29(木) 23:47:12ID:QSSosLPK
>>794
>は?誰?何聞いてるの?

いや、だから過去IDでコテ名乗ってるんだが
そうやって自分の都合の悪いときだけ痴呆症を発症されても困るんだわ
まず>>700。これは>>738でも催促しているよな。頼むわ。な。

>オブザーバーはタスクシステムじゃないってw

今度はなんの話だい?初っ端の>>672で既に回答は出してるよな
>>772でもそれは指摘してるよな。何度書いてもすぐ忘れるんだな
08057622009/01/29(木) 23:48:20ID:e5MgZbFT
だーもーお前ら整理してって言った自分が悪いのもわかってるけど、もうどうでもいいよw
自分はデザパタ本のオブザーバー読む機会が出来たから、ほー程度に思ってたが。

結局現在の論点は>>685->>686な状況を考えたとき、オブザーバーパターンが適用できるか。でしょ?
だれかあってるかどうか理由もつけていってよ。俺?今読んでる無理。

0806名前は開発中のものです。2009/01/30(金) 00:04:31ID:9+H4SV2g
>>804
だからお前誰なんだよw

>>805
はぁ?冒頭の目的読むだけでこりゃちげーってわかるべw
0807名前は開発中のものです。2009/01/30(金) 00:06:54ID:9+H4SV2g
>>805
>結局現在の論点は>>685->>686な状況を考えたとき、オブザーバーパターンが適用できるか。でしょ?
全然違うじゃん
そもそも>>686なんてタスクシステムと関係ないじゃん
完全にスレ違いな上に言ってることも間違ってる
0808名前は開発中のものです。2009/01/30(金) 00:14:45ID:5R1NkGJS
>>805
普通に可だとおも
監視者(人とか)に対して監視対象(センサーとか)の数が多くて
その状態変化が滅多に起きないなら監視者が監視対象の状態を
毎回毎回全走査するよりもイベント駆動にするよ

それがobserverパターンになっていても何も不思議じゃないし
0809名前は開発中のものです。2009/01/30(金) 00:17:13ID:ffjsoOsM
>>806
いや、冒頭の目的なら問題ないだろ。

いくら読んでもイベントと相違がみえねぇ。
強いてあげるなら、イベントを発生させる要因が、イベントを受け取るやつらから来る(≒相互参照)、という特殊な状況な事くらいか??
でもこれは本で挙げた例がそうなってるだけで、ここは重要ではないな。

>>807
いや・・・だから・・・タスクシステムは直接関係ない話題が延々と続いてるって事実がホントわかってないのがいるのか・・・
何度も俺や他のやつらが言ってるじゃん・・・何で人のレス読まないかなー

>>772よ、つまり>>807見たいのがいるんだよ。
0810ID:2rWIRnW32009/01/30(金) 00:55:05ID:JU1rNfjo
>>809
そうみたいだな。参った
0811ID:2rWIRnW32009/01/30(金) 01:07:41ID:JU1rNfjo
>>806
>だからお前誰なんだよw

俺の名前欄を見ろって。それでCTRL+Fでスレ検索しろよ。頼むよ。な。

>>807
>そもそも>>686なんてタスクシステムと関係ないじゃん
>完全にスレ違いな上に

それは>>685で断ってる

    【>>2が一切サポートしない機能の話しになるからアレだが】

スレ違いだと思うならグダグダ食ってかかる前に「スレ違いだろ氏ねカス」って開口一番に喚いとけって

>言ってることも間違ってる

確認するが、>>2と関係ない話という前提でも間違ってるって言ってるのか?正気か?
お前…「スレ違いだろ氏ねカス!」、俺…「この文盲野郎!バーカバーカ!」で決着させてもいいんだぞ?
いいのか?続けるぞ?

ではどうぞ。間違ってるところはどこ、説明してくれ、と延々再三催促してるからな。頼むわ。な。
あと俺もう寝るから。まぁ頑張って長考してくれ。な。
次に反応するのはたぶん数日後とかになるから別に焦らなくていい
続けたくなくなったら「スレ違いだろ氏ねカス!」ってちゃんと書くように
0812名前は開発中のものです。2009/01/30(金) 01:27:49ID:kL+m0iCz
直近の流れはぶったぎって書く

タスクシステム総合スレの1らしきものがあったので読んでみた

http://www.23ch.info/test/read.cgi/gamedev/1173708588/

見事に話題ループしてて笑ったw
0813名前は開発中のものです。2009/01/30(金) 06:22:51ID:9+H4SV2g
>>811
あれあれ?キレちゃったの?w
0814名前は開発中のものです。2009/01/30(金) 07:12:22ID:9+H4SV2g
>>809
おw
やっと冒頭の目的を読んだ奴が出現
そうかそうかやっと読んだかw
まあ、読んだならわかると思うけど









どうみてもオブザーバー=タスクシステムですw
ありがとうございましたw
0815名前は開発中のものです。2009/01/30(金) 07:27:07ID:65fIVgj5
不思議だよね
明らかにタスクシステムなのにこの点を指摘する人がでてこないの
0816名前は開発中のものです。2009/01/30(金) 09:41:25ID:+pNTqaYg
えーと聞いていいかな
タスクシステム=オブザーバー・パターンという場合、そのタスクシステムはどういうもので
サブジェクトとオブザーバーはどこにあって、それはどういう振る舞いをするの?

タスクシステムって>>2を見る限りはリストひとつになんでもかんでも放り込んでごった煮にして
一定の時間間隔で定期的に巡回UPDATEする仕掛けを提供するだけで後はおまえらで勝手にやってね
というようなものにしか見えないんだけど、どこにオブザーバー・パターンがあるの?
0817名前は開発中のものです。2009/01/30(金) 10:52:34ID:88nsX3SX
>>816
リストひとつになんでも放り込んで
→VSYNCイベントを受け取りたいオブザーバを登録して

一定の時間間隔で定期的に巡回UPDATE
→VSYNCイベントをオブザーバにnotify

ほら同じだ
0818名前は開発中のものです。2009/01/30(金) 11:26:26ID:ffjsoOsM
>>814はびっくり発言連発するからほっとくとして。

>>817
それってまさにデザインパターンを強引に適用した、あるいは強引にそうみなそうとした、じゃね?
果たしてフレームの更新をsubjectの状態の変化と捉えるか普通? いや、捉えられないって言ってるわけじゃないけど。
また、パターン全般は再利用性があることが前提になる。もちろんクラスライブラリにしても意味のないパターンもあるが、
イベントなんてJavaやC#ならデフォがいる。そのくらいクラスライブラリ化が簡単に出来るものだ。

となると。オブザーバーパターンは、最低限のメソッドに提供することが前提で(可能な限り自由性を持たせる)、
クラスのある言語ならクラスライブラリとして構築できなきゃビミョーなんじゃないの?

でそう考えると。>>553に類似する構造が前提になりそうなんだが。
さてさてこのスレで散々語られてたタスクシステムはどうでしょうか。

0819名前は開発中のものです。2009/01/30(金) 11:45:35ID:88nsX3SX
>>818
そうかなぁ
オブザーバってのは割り込みハンドラやシグナル、
イベントディスパッチャ/コールバックのようなものを
OOのデザパタとして記述したものでしょ
Document/Viewみたいなのにも使われるから、適用範囲はもっと広いけど

>>2はアセンブラかせいぜいCで記述されたものだろうから、そりゃ表面的には
違うだろうさ、だが本質的には別に大した違いじゃないように見えるけどな

VSYNCをイベントとして「捉えない」ほうが、俺には意味が分からないけど
0820名前は開発中のものです。2009/01/30(金) 12:04:53ID:88nsX3SX
何となく論点の違いが分かった

タスクシステムとオブザーバは=ではないでしょ、そりゃ
タスクは昔のゲーム設計の一手法に過ぎないから、OOのデザパタほど
抽象化も汎化もしていない(し、その必要も無い)

別に誰もそんなことは主張してないと思うよ(少なくとも俺は)
0821名前は開発中のものです。2009/01/30(金) 16:47:08ID:O2nIHOeq
デザパタは過去の技法をパターンとして集めただけだぞ?
抽象化されていなからデザパタより格下という論法がわからん
0822名前は開発中のものです。2009/01/31(土) 00:48:06ID:vZh4GSBD
ゆーき先生の本がわかりやすいよね
0823名前は開発中のものです。2009/01/31(土) 02:06:18ID:knmkZjZM
>>817
>→VSYNCイベントを受け取りたいオブザーバを登録して

タスクシステム=>>2では全ゲームオブジェクト(タスク)は必ずただひとつのリスト(タスクリスト)に
登録されることが義務付けられているぞ。ゲームオブジェクトに選択の自由なんて全然無いからな
どんな性質のゲームオブジェクトだろうと必ずVSYNC発生毎に通知を受けなければならないんだよ

タスクシステムというのは、ゲームオブジェクトとはVSYNCに依存して当然、依存しないなんてあり得ない
VSYNC発生の度に通知を受けることを全ゲームオブジェクトが望んでいるに決まっている、という仕組み
CodeZineのコードはゲームオブジェクト生成と同時に暗黙のうちに唯一のリスト(タスクリスト)に登録する

たとえばゲーム開始時点で生まれて一定時間経過後に何らかの行動を始めるゲームオブジェクトがあるとする
タスクシステムではこういう性質のゲームオブジェクトも生まれると同時にタスクリストに登録する
VSYNC発生の度に通知を送り続ける。このゲームオブジェクトは通知を受けるたびに行動開始の時間かどうかを
自分でチェックしなければならない。まだ行動開始の時刻でなければ何もせずに処理を返す。時間がくるまで
そういうことを延々繰り返す

このゲームオブジェクトが本来受け取りたいイベントというのは行動開始時間で、VSYNCイベントとの依存関係は
本来はない。でもタスクシステムではVSYNC(一定周期の)通知機能しか提供しないから仕方なくこれを代用して
自分でポーリングを行なっている

タスクシステムでは依存関係があろうがなかろうが通知を全員に送る。オブザーバー・パターンの目的とは違う
0824名前は開発中のものです。2009/01/31(土) 02:30:33ID:2y83CUUn
デザインパターンで安全にタスクシステムを構築できるということについて
具体的に否定できるヤツは一人もいないなw

ファビョって否定してるやつが数人いるようにみえるがID変えてるだけのアホが一人なんだろうな。
0825名前は開発中のものです。2009/01/31(土) 02:41:36ID:8CtHI7i5
>>823
んーちょっとよくわかんない

> このゲームオブジェクトが本来受け取りたいイベントというのは行動開始時間で、
> VSYNCイベントとの依存関係は本来はない。

より高い抽象度では、「時刻Xになったら行動開始」だけども、
実装レベルでは、結局のところVSYNC割り込み単位でのフレーム更新という
「必要」が先立ってるんでしょ?
コルーチンや継続のようなものが使えるのなら、VSYNC単位で微分せずに
もっと自然に書けるだろうけども、
「その設計では」VSYNCイベント通知が「必要」だから、そう作ってあるのでは?

設計の良し悪しとか、無駄が多いとかはいくらでも言えると思うんだけど、
「オブザーバとは違う」ということにこだわることにそんなに意味があるようには
俺には見えないけどねえ

オブザーバは単なるパターンだから、
オブザーブする対象は別にVSYNCイベントだろうがタイマだろうが構わないわけでしょ
0826名前は開発中のものです。2009/01/31(土) 02:44:15ID:rIovvj90
>>824
安全には無理でしょ
明示的な引数がない時点でプログラムの作法云々なんてもう
気にしない組み方だと思うけどね

update();

で動くのと

update(jiki,teki,tama,unko);

で動くのとじゃ
プログラムとしては絶対に下のがいい
上は結局、その関数で何が必要なのか要素がまったくわからない
アクセスしているものを知るには中身のプログラムを読むしかないし
0827名前は開発中のものです。2009/01/31(土) 04:32:28ID:gO0Oi008
趣味プログラマにはワケワカメw
ごった煮リスト+メッセージプロシージャでこれからも頑張っていきます( ^ω^;)ゞ
0828名前は開発中のものです。2009/01/31(土) 11:36:23ID:9d5EHsE6
>>826
> プログラムとしては絶対に下のがいい

あんた、どんだけ素人なんだ…。
本当にプログラムが1行でも書けるのか。
0829名前は開発中のものです。2009/01/31(土) 11:54:07ID:ZWCB0Sk3
素人目にも、上( update(); )のほうがよさそうに見えるのだが、俺はおかしいのか。
0830名前は開発中のものです。2009/01/31(土) 12:58:57ID:p4gnaDmU
いや、やはり下の方がいいね。
下手にクラス変数に他のオブジェクトへのポインタを持たせたり、グローバル変数(シングルトン含む)を使ってしまうと、
オブジェクト間の関連が複雑になって、わけがわからなくなる。
各メソッドに処理に必要な情報(メディエータとか)渡すようにすると、
末端のオブジェクトは実にシンプルになる。

JavaのAWT/Swingでよく使うpaint(Graphics g)みたいにね。

0831名前は開発中のものです。2009/01/31(土) 13:16:50ID:rIovvj90
>>828-829
素人もいいところだな
じゃ、上(update();)でアクセスしてるデータは何と何?

update関数の中をすべてみないとわからないでしょ?
これがグローバル変数の最大の害
下(update(jiki,teki,tama,unko);)ならjiki,teki,tama,unkoインスタンスにアクセスしていて
仮にソースでグローバル変数を使わないという決まりをきちんと守っていた場合
update関数によってこれら以外のインスタンスが変更されることは絶対にないという
ソースを読む側の確信がもてる
これはバグを追う場面でも強力に働く
これがキチンと守られているかどうかで
開発期間やプロジェクトで出る総バグ数がまるで違う結果になる(俺の経験)
だからタスクシステムはバグが増える

ヘッダファイルにしても同じ
必要なヘッダを必要な分だけインクルードしてるソースなら影響するクラスがわかりやすい
が、タスクシステムはごった煮ソースになるので
ほぼ全クラスを一括インクルードしなければ動かないとかかなり糞
これではバグがいつまでたっても減りませんわw
0832名前は開発中のものです。2009/01/31(土) 13:31:15ID:8N26Dxd2
安全性ってのは2つの観点があるんじゃね?
・メモリ上のオブジェクト寿命の保証
・データ確定性の保証

データ確定性というのは「今このデータ更新中だからアクセスしないでね」っていう期間に
ちゃんと排他制御出来てること(更新してるやつ以外はアクセスしないで待ってること)。

上(update();)はスマートポインタ使うから安全って言いたいのかもしれないけど、
スマートポインタが解決できるのはメモリ上のオブジェクト寿命の保証のみ。
データ確定性の保証は別途対策が必要。

それに比べて下はオブジェクト間の関係性が単純化できているから
データ確定性の保証もしやすい。
だから下が良い。
0833名前は開発中のものです。2009/01/31(土) 14:22:57ID:qt9xmuQG
>>831
>>ほぼ全クラスを一括インクルードしなければ動かないとかかなり糞
お前タスクシステムで組んだこと一度もねーだろ
0834名前は開発中のものです。2009/01/31(土) 14:27:19ID:rIovvj90
>>833
あるし、ちゃんとタスクシステムでゲームを3本ぐらいコサエタよ
どれも途中参加だったけどかなり苦痛だったな
0835名前は開発中のものです。2009/01/31(土) 14:29:40ID:qt9xmuQG
>>834
じゃあソースの分け方が下手なだけだ、タスクシステムだからって理由でそんなことには絶対ならない
0836名前は開発中のものです。2009/01/31(土) 14:34:18ID:rIovvj90
>>835
ふーん、じゃそれでいいよ
ただ、そうしないとごった煮判別のところでやりにくいだけだと思うけどね
どうせわからないんだから一括でインクルードしちゃえばいいじゃん
って俺は思ったけどね(タスクシステムプロジェクトに参加してるときは)
グローバル変数も当然のように使いまくりになるしいまさらそんなところ争っても
大した違いにならないのでこの話(ヘッダの話)はここで終わりにしてくれ頼む
0837名前は開発中のものです。2009/01/31(土) 14:49:50ID:9d5EHsE6
>>830
> JavaのAWT/Swingでよく使うpaint(Graphics g)みたいにね。

Graphicsのような汎用contextを引数として渡すのは構わない。
826はupdate(jiki,teki,tama,unko);のようにそのゲーム専用でかつそのタスク専用のcontextを渡しているわけで、
そんなものを渡すとその部分を抽象化できなくなる。

>>831
> じゃ、上(update();)でアクセスしてるデータは何と何?
> これがグローバル変数の最大の害

グローバル変数を使うだなんて一言も言ってないし、実際updateメソッドのなかでは
グローバル変数なんかにはアクセスしない。

> update関数によってこれら以外のインスタンスが変更されることは絶対にないという
> ソースを読む側の確信がもてる

そんなことは全く保証されないし確信が持てるわけではない。
updateメソッドでは自由に他のインスタンスにアクセスできる。
0838名前は開発中のものです。2009/01/31(土) 14:57:52ID:qt9xmuQG
>>836
そうやって一括でインクルードするからわからなくなるって自分で言ってんじゃないの?矛盾してるよ、
ソースがしっかり分かれていればupdateの引き数で判断しなくても何がインクルードされてるかで判断できるよ。
0839名前は開発中のものです。2009/01/31(土) 14:59:25ID:9d5EHsE6
>>832
> 上(update();)はスマートポインタ使うから安全って言いたいのかもしれないけど、

そんなことは俺は言っていない。

updateの引数として、汎用性のないcontextを渡すと呼び出し部分も呼び出される部分も抽象化できない。
それが最大の弊害であり、やるべきではない理由である。

>>833
実際831はド素人。「タスクシステムはごった煮ソースになる」の時点でド素人。

template<class Context> class Task
{
virtual void update(Context context);
};
こう抽象化しておいて、std::list<Context> tasksに対してforeachでupdateを呼び出すだけ。
「ほぼ全クラスを一括インクルードしなければ動かない」なんでド素人もいいところ。


0840名前は開発中のものです。2009/01/31(土) 15:02:01ID:9d5EHsE6
>>836
> ただ、そうしないとごった煮判別のところでやりにくいだけだと思うけどね

「ごった煮判別」ってなんだ?

> グローバル変数も当然のように使いまくりになるしいまさらそんなところ争っても

タスクシステムを使ってようが、グローバル変数なんてひとつも使わないぞ。

あんたみたいなド素人、仕事に参加されると迷惑きわまりない。
俺が教えてやるから、何がしたいのか詳しく書いてみな。俺がお手本を見せてやんよ。
0841名前は開発中のものです。2009/01/31(土) 15:09:27ID:j5ds1u2H
一括インクルードとかグローバル変数使いまくりとか、
単にそのチームが酷かっただけのように思えるが。
0842名前は開発中のものです。2009/01/31(土) 15:12:32ID:8TBQ0Fdj
ID:rIovvj90は途中参加って言ってるし。
ゼロからタスクシステムを組んでみたら、どういうものか分かると思う。
そうすればグローバル変数とか関係ないことがわかる。

>>841
そういう理由があっても、それがすべてと思って批判するのはどうかと思う。
0843名前は開発中のものです。2009/01/31(土) 15:13:38ID:8CtHI7i5
いや発言のレベルが流石に低すぎるから
ただの釣りか、BASICやHSPぐらいしか知らないド素人なんでしょ

OOPを知らないのは確実だけど、Cでもちょっと抽象化したコードを
読み書きしたことはなさげ
0844名前は開発中のものです。2009/01/31(土) 15:18:02ID:rIovvj90
>>839
だからそれってソースをみたときに何が渡されてるのか確定できんの?
0845名前は開発中のものです。2009/01/31(土) 15:18:54ID:rIovvj90
単純に>>826の問題は解決してないように見えるけど?
0846名前は開発中のものです。2009/01/31(土) 15:20:49ID:9d5EHsE6
>>832
何故そこでスマートポインタが出てくるのか意味不明なんだが、
updateで引数がないということは次のようになっていると俺は想定している。

template <class Context>
class Task
{
public:
Task(const Context& context_) : context(context_) {}
virual void update();
private:
Context context;
};

それぞれのタスクはこのTaskクラスから派生させる。

updateメソッドでは、this.context に対してアクセスするので、スマートポインタなんか使う必要はないし
グローバル変数も使わない。
0847名前は開発中のものです。2009/01/31(土) 15:21:53ID:rIovvj90
>>846
>、this.context に対してアクセスするので、
これが何か知らないんだけど説明してくれない?
0848名前は開発中のものです。2009/01/31(土) 15:23:19ID:9d5EHsE6
>>844
> だからそれってソースをみたときに何が渡されてるのか確定できんの?

何が言いたいのかよくわからん。

「何が渡されてるか」って、updateの引数がないのだから、何も渡されていない。
C++でメソッド呼び出しなら、thisが渡されている。

と確定できるが?
0849名前は開発中のものです。2009/01/31(土) 15:25:08ID:rIovvj90
>>848
仮に呼び出し側で>>862のような違いを
見つけたいソース(=引数を明示的にしたい)を書きたい場合にはどうするの?
0850名前は開発中のものです。2009/01/31(土) 15:25:28ID:rIovvj90
>>862
>>826
0851名前は開発中のものです。2009/01/31(土) 15:27:05ID:9d5EHsE6
>>847
>>、this.context に対してアクセスするので、
> これが何か知らないんだけど説明してくれない?

templateになっていて、ゲームを作りたいなら、そのゲームでタスクにとって必要なcontextを入れるんだ。

例えば、シューティングゲームで敵の弾だけ列挙したくて、それをタスクリストからdynamic_castなどで型判別するのが
嫌なら、このcontextに

std::list<Task*> enemy_shot_tasks;

というstd::listを持たせておく。そうすれば、敵の弾に対してforeachしたりできる。
描画するのにGraphicsクラスが必要なら、それもこのcontextに持たせておく。
0852名前は開発中のものです。2009/01/31(土) 15:28:55ID:9d5EHsE6
>>849
> 仮に呼び出し側で>>826のような違いを見つけたいソース
> (=引数を明示的にしたい)を書きたい場合にはどうするの?

呼び出し側は、単に、一定のタイミングごとにupdateを呼び出すだけの存在であって、
呼び出し側に違いが現われるのは論理的におかしく、設計がまずい。

だから、呼び出し側にそのような違いを見いだそうとすること自体がおかしい。
0853名前は開発中のものです。2009/01/31(土) 15:33:03ID:8CtHI7i5
>>849
詳細で個別的なメソッド呼び出しが必要で適している状況ではそうすればいいし、
そうするだけだよ

上のupdate()のような例では、呼び出し側は、オブジェクト間の差異を
意識したくない、統一的に扱いたいから、より抽象度が高い方法でやるだけさ

差異を選択的に無視して、問題をそれに適した/適切な抽象度で
扱えるようにすることが「設計」でしょ

車の運転をしているときに、エンジンに使われているネジのことなんぞ
いちいち気にしたくはないわけだ
0854名前は開発中のものです。2009/01/31(土) 15:38:27ID:j5ds1u2H
>>842
俺もそう思うよ。
批判すべきはチームの設計・開発体制であって、タスクシステム自体の是非はまた別の問題。
ID:rIovvj90はそのへんの問題点の切り分けが出来てないんだな。
坊主憎けりゃ袈裟までってやつか。
途中参加した3本が全部別々のチームなんだったら、流石にその不運には同情するが。
0855名前は開発中のものです。2009/01/31(土) 15:44:45ID:9d5EHsE6
俺には 826 で何がしたいのかいまひとつわからないのだが、タスクシステムから
callbackがかかるタイミング(ビデオゲームならV_SYNCごととでも思っとくれ)
以外のタイミングで、他のタスクの更新メソッドを呼び出してやる必要がある場合を
考えてみる。

普通、ゲームでそういうコードが必要になることは稀ではあるが、そのとき、
updateメソッドのなかで他のupdateを呼び出す、

> update(jiki,teki,tama,unko);

のようなことがしたい、というなら動機はわからなくはない。

この場合、jiki,teki,tama,unkoの4つのオブジェクトが生きていることを
保証してやる必要がある。

C#やJavaのような言語であれば、オブジェクトが生きていることは
保証されるのでDisposeされていないかをチェックする。

C++なら、オブジェクトが生きていること自体が保証されないので例えば、
Task chainに対して、
tasks.isContain(jiki)
のような判定が必要である。
std::listに対してこれをやると結構のオーバーヘッドになり得るので、
特定の型のstd::listを用意するか、もっと高速に判定できるコンテナ
(std::mapなど)をContext(>>846)に持たせておきこれをチェックするのが普通。
0856名前は開発中のものです。2009/01/31(土) 15:49:35ID:8N26Dxd2
>>846
そのContextとやらでポインタ使うことになるっしょ。
そこでスマートポインタ使うから安全って言うのかと思った。
そうでなければどういう意味で安全といったの?

std::list< Task<Enemyとか> *> m_bullets;

init(*jiki,*teki,*tama,*unko){ ←こことか、
  m_bullets.push_back(new Task<Enemyとか>(jiki,teki,tama,unko)); ←ここで外部データへのポインタ使ってる。安全じゃない
}
enterFrame(){
  foreach bullet (m_bullets) {
    bullet.update(); ←ここで渡すのを初期化時に移しただけ。状況はむしろ悪化してる
  }
}

#template分かんねえwww
#newまわり恐らく書き方違うだろうけど意図は大体通じるよね?
0857名前は開発中のものです。2009/01/31(土) 15:57:08ID:9d5EHsE6
>>856
> そこでスマートポインタ使うから安全って言うのかと思った。
> そうでなければどういう意味で安全といったの?

すまんが、俺は「安全」という言葉は一言も言ってない。
「安全」と言ったのは俺じゃない。

俺は、オーバーヘッドがあるから、スマートポインタを使わなくて済むところでは
使わないし、この手のタスクをコントロールするのにスマートポインタは持ち出さない。
またオブジェクトが生きているかどうかの判定については >>855 で書いた。

ただ、
> Contextとやらでポインタ使うことになるっしょ。

については、このContextが保持しているstd::listなりstd::mapなりは、
Taskの解体の時に自動的にここから該当タスクのポインタをremoveするので
このstd::listなりstd::mapなりにあるオブジェクトが実在して、かつ生きている
ことだけは保証される。だから>>855 の方法で問題ない。
0858名前は開発中のものです。2009/01/31(土) 16:00:48ID:9d5EHsE6
いま読み返してみたら、855の書き方が悪かったので以下補足&修正とお詫び。

> Task chainに対して、
> tasks.isContain(jiki)
> のような判定が必要である。

だけど、tasksから一度removeされて、同じメモリがオブジェクトに割り当てられる
ことがあるので、このjikiというのは、オブジェクトのアドレスやポインタではなく
incremental ID(いわゆるhandle)だ。

誤解を生じさせる書き方をして済まない。
0859名前は開発中のものです。2009/01/31(土) 16:14:46ID:8CtHI7i5
contextって俺は長命オブジェクトをイメージしてるんかと
思ったけど、違うの?
マネージャなりメディエータなり

よくある子に親への参照を持たせているようなケースは、
親が先に死なないデザインなら安全

オブジェクト間の相互参照グラフが無軌道に複雑化する場合は、
確かにGCなしでは酷いことになるだろうし
IDルックアップを毎回やるのは遅そうだな
0860名前は開発中のものです。2009/01/31(土) 16:21:35ID:rIovvj90
>>852
その状態でなんで>>826,830-832の内容を否定するの?
俺が書いたのは>>831のみだけど
その状態をダメだって言ってるのが>>826,830-832の内容なわけ

ソースの記述で引数を明示的に表現しなければならないって話なのよ?
タスクシステム使うと完全に>>826,830-832の問題をどうにもできないでしょ?
ソースの記述で引数を明示的に表現できる?
(ま、別にする必要がないって主張をもってるからタスクシステム派なんだろうけどさw)
0861名前は開発中のものです。2009/01/31(土) 16:28:02ID:9d5EHsE6
>>859
> contextって俺は長命オブジェクトをイメージしてるんかと
> 思ったけど、違うの?

もちろん、Contextオブジェクトの寿命はあらゆるTaskよりは
長いことは保証しなければならないし、保証されると仮定してプログラムする。

でもタスクフレームワークとして見たとき本質的なのはそこじゃなくて、
そのアプリ固有のcontextをTaskから切り離してTaskの呼び出しを抽象化するのに
ここをtemplate classにする必要があるということ。

> よくある子に親への参照を持たせているようなケースは、
> 親が先に死なないデザインなら安全

>>858 のようにhandleを持たせるのが嫌なら、boost::shared_ptrを用いて
 std::list<boost::shared_ptr> tasks;
としておくというのは一理あるんだな…でも、

> オブジェクト間の相互参照グラフが無軌道に複雑化する場合は、

循環参照するようなケースはshared_ptrではどうにもならないし
GCがある言語で書いたほうがスマートではあるな。

> IDルックアップを毎回やるのは遅そうだな

実際はオブジェクト数の上限は決まっていると仮定して良くて、
hash tableを使って実装するので、その部分は実はそんなに遅くはないよ。

たいていはhash値を計算してメモリを一度lookupするだけで済むので。
だから、ID lookupで実装するのがスマートだと思うな。
0862名前は開発中のものです。2009/01/31(土) 16:30:05ID:9d5EHsE6
>>860
> ソースの記述で引数を明示的に表現しなければならないって話なのよ?

何故そんな必要があるのか、そのメリットがどこにあるのか俺には全く理解不能だ。
0863名前は開発中のものです。2009/01/31(土) 16:38:26ID:8CtHI7i5
なんとなく論点のズレが分かった

ID:rIovvj90
は、タスクマネージャからのupdate()呼び出し
以外の関数呼び出しは一切存在しない(あらゆるオブジェクト間の相互作用を
それで解決する)プログラムを仮定しているように見える

他の人は(ID:9d5EHsE6)は、誰もそのようなものは仮定していない

普通に引数を使うところでは勿論使うわけで、
あくまでジェネリックなupdate()を書く時の作法として
どっちが適切かという話をしていただけでしょ
0864名前は開発中のものです。2009/01/31(土) 16:41:05ID:9d5EHsE6
>>863
正解。
0865名前は開発中のものです。2009/01/31(土) 16:43:43ID:rIovvj90
>>863
違うってなんで曲解するんだ?
update関数の中でアクセスするインスタンスがソースの記述から
わからないのがダメだって言ってるんだ(もちろんダメだと思わなければそれまでだがw)

>>826,830-832で言ってることがすべてだって
これがわからないって経験値が低いぜ
わかってやってるってのも俺的にはちょっと考えにくいんだけどね
0866名前は開発中のものです。2009/01/31(土) 16:46:49ID:8CtHI7i5
>>865
> update関数の中でアクセスするインスタンスがソースの記述から
> わからない

???
C++だからthisポインタ越しに、オブジェクト参照をたどるだけでしょ
参照はメンバ変数に持っているのだし

何が「わからない」のかが分からない
0867名前は開発中のものです。2009/01/31(土) 16:49:34ID:9d5EHsE6
>>865
> update関数の中でアクセスするインスタンスがソースの記述から
> わからないのがダメだって言ってるんだ

何度でも言うが、そんなものはわかる必要がないんだ。

Javaのupdate(Graphics g)メソッドひとつにしても
updateメソッドのなかでGraphics以外のオブジェクトにアクセス
することは当然あるし、それを禁じる方法はないし、
update(Graphics g)というシグネチャを見てGraphicsにしかアクセス
しないと判断することは出来ないし、
実際そんなコーディングスタイルで書く必要もないし、
そんなコーディングスタイルを強要されるとまともにプログラムを書けない。
0868名前は開発中のものです。2009/01/31(土) 16:52:11ID:9d5EHsE6
すべてのタスクファイルのヘッダをincludeして
それが普通だと思っているID:rIovvj90みたいなド素人と
話していても時間の無駄なので俺は、ID:8CtHI7i5と勝手に話を続ける。
0869名前は開発中のものです。2009/01/31(土) 16:52:32ID:9d5EHsE6
■ ID lookupの周辺。

typedef TaskHandle unsigned int;
struct HashEntry
{
TaskHandle handle;
Task* task_ptr;
};

typedef HashTable HashEntry[max_of_hash_entry];

Taskクラスのコンストラクタでは、TaskHandleとしてincremental IDを付与して
HashTableに登録するコードを書く。Taskクラスのデストラクタでは、HashTable
からremoveするコードを書く。

TaskHandleから具体的な型に変換するのは
template<class TaskClass>
TaskClass* TaskHandleToPtr(TaskHandle h)
{
Task* p = HashTableからhのTaskを取得();
if (typeid(p)!=typeid(TaskClassのインスタンス))
return null;
return (TaskClass*)p; // このcastは安全
}

こうなるな。
0870名前は開発中のものです。2009/01/31(土) 16:56:11ID:9d5EHsE6
>>869 の続き。

TaskHandle enemy1;
TaskHandle enemy2;

に対して

EnemyTask* enemyTask1 = TashHandleToPtr<EnemyTask>(enemy1);
EnemyTask* enemyTask2 = TashHandleToPtr<EnemyTask>(enemy2);
if (enemyTask1!=null && enemyTask2!=null)
{
 // これらのタスクは生存している
 update_something(enemyTask1,enemyTask2);
}

という生存チェックが必要になるな。仕方ないと言えば仕方ないが、
使う前に必ず必要なのがちょっとうざい気はする。
0871名前は開発中のものです。2009/01/31(土) 16:58:07ID:8CtHI7i5
>>869
まあ概ね想定どおりっすね
俺の考えを言うと、

・C/C++なら、そもそもオブジェクトの相互参照グラフを整理する
 のがベスト

・問題が不可避な場合にはGC, スマポ, ID管理などの解決方法があるが、
 スマポは良く知られているように巡回参照には無力(そもそもグラフが
 複雑化したから欲しくなったはずなのだから、それでは意味が無い)
 
 ID管理が一番シンプルでポータブル、仮に全てが利用できると
 仮定した場合、性能や特失に関しては研究の余地あり(ただ、ゲームでは
 いずれにせよGCは利用しにくいでしょうね)

ってとこかしら
0872名前は開発中のものです。2009/01/31(土) 17:00:55ID:9d5EHsE6
>>871
>(ただ、ゲームではいずれにせよGCは利用しにくいでしょうね)

これは何故?俺は、C#で商用ゲームプログラムを書いたけど
別にGCがあるので困るということはなかったのだが。

どんなことが問題だと思ってるの?
0873名前は開発中のものです。2009/01/31(土) 17:03:36ID:8CtHI7i5
>>872
優秀な世代別GCで、決してワールドがストップしないと
確信できるケースでは、問題ないかもしれません
その確信が持てないなら、ゲームでは難しいかもしれません

ということです
0874名前は開発中のものです。2009/01/31(土) 17:06:51ID:9d5EHsE6
>>873
> 優秀な世代別GCで、決してワールドがストップしないと
> 確信できるケースでは、問題ないかもしれません

それが確信できないとそもそもXNAでプログラミングなんて出来ないわけで…。

あ、もちろん、大きなリソースを解放するときは要注意なのでそのタイミングは
なるべくコントロールしてやる必要があるけども。それはC++でも一緒なわけで…。
0875名前は開発中のものです。2009/01/31(土) 17:07:52ID:9d5EHsE6
>>870 の続き。

結局、TaskHandleという汎用型があまりよくない気がするな。

TaskHandle<T>にして、operator T*() を用意して暗黙で変換できる
ようにしたほうがいいかもね。

これなら

TaskHandle<Enemy> enemy1;
TaskHandle<Enemy> enemy2;

に対して

try {
// これらのタスクが生存していなければ暗黙の変換のときに例外が飛ぶ
update_something(enemyTask1,enemyTask2);
// update_somethingのシグネチャは、update_something(Enemy*,Enemy*)
} catch {}

とか。こっちのほうが少しシンプルかも。これは、どう? > ID:8CtHI7i5
0876名前は開発中のものです。2009/01/31(土) 17:08:52ID:8CtHI7i5
>>874
いやその、「C#でゲームプログラミングは不可能である」という主張ではないので
誤解無きよう
そういう意味では、「GCはゲームではありえない」と読み取れるので、
強い主張すぎたかな、訂正します
0877名前は開発中のものです。2009/01/31(土) 17:12:32ID:9d5EHsE6
>>876
いやまあ、C#で弾幕シューティング作ったら、やっぱり
GCが変なタイミングで動いてときどきカクカクなるから
object poolingするコードをtemplateで書きまくったとか
そういうことは日常茶飯事なので、GCに対して世間の目が
冷たいのはよくわかってるつもり。

このスレの趣旨に見合う形で話を戻すと、GCつきのほうが
タスクのinteractionは楽に書けることは書けるけども、
それでもC++でも >>875 のように書けるなら、さほど手間は
変わらないと思う。
0878名前は開発中のものです。2009/01/31(土) 17:16:15ID:rIovvj90
>>866
それは別クラスのポインタの保持をするってこと?
まあ、ようは関数読んだときにアクセスしてるクラスがわからないようなのはダメってことよ
当然そういうメンバに別クラスのインスタンスのポインタを保持させるようなのも禁止だよ

>>867
それができるんだよ
グローバル変数・関数の使用禁止(当然スタティックとかも禁止)とか徹底して
メンバに別クラスのインスタンスの保持禁止にするのをちゃんと徹底すれば
後、可能性があるのは引数とメンバ変数ぐらいだろ?
こうするとバグが比較にならないほど減るぞ

自分で一度この方式でプログラム組んでみてほしいね
決して面倒臭くない
むしろ開発が進むにつれこっちのが作りやすいとわかるはず

しかも読む人間もソースを追いやすいからバグの発見も早い
0879名前は開発中のものです。2009/01/31(土) 17:20:08ID:9d5EHsE6

>>878
> メンバに別クラスのインスタンスの保持禁止にするのをちゃんと徹底すれば
> 後、可能性があるのは引数とメンバ変数ぐらいだろ?

別クラスのインスタンスの保持をすると何故いけないと思うんだ?

親オブジェクトが子オブジェクトのstd::listなんかを持っているのは普通であり、
当たり前だろ?これを禁止するなら、どのオブジェクトがある親オブジェクトに
対する子オブジェクトを持っていると言うんだ?具体的にソース書いて見せてくれ。
0880名前は開発中のものです。2009/01/31(土) 17:24:54ID:8N26Dxd2
>>857
了解しました。スマートポインタは無かったことに。
あと「メモリ上のオブジェクト寿命の保証」が対策済みで問題ないのは了解しました。

それはそれとしてゲームオブジェクト間の「データ確定性の保証」
もしくはオブジェクト間関係の見える化の推進度合いの観点では
依然として「引数を明示的に表現する」ほうがupdate(void)よりも分かりやすい
と考えてるんですが、その点どうお考えですか?
update(void)メソッド呼び出しの中で他のupdateを呼び出す場合に
update(jiki,teki,tama,unko);と書くこと自体はその是非はともかく存在は想定されてますよね。

以下のように
Scene::update(void);
Player::update(void);
Enemy::update(void);
Bullet::update(void);
と全てをタスク化するのではなく、タスクの数はもっと減らして

Scene::update(void) { ←タスクはこいつだけ
  player.update(jiki,teki,tama,unko);
  enemy.update(jiki,teki,tama,unko);
  bullet.update(jiki,teki,tama,unko);
}
としてやればだれがいつjiki, teki等を使っているのかが見やすくなる。
また、playerはTaskを継承しなくて良くなるのでPlayerクラスだけを抜き出して
test_player_class.cppとかいうコードを作ってPC上でクラスの単体テストすることもかなりやりやすくなる。
思うにTask導入しちゃうとタスクフレームワーク使わなければ単体テストすら満足にできなくなってるんじゃないかと。

update(void)を自動的に定期的に呼び出すのは要らないと言っているのではなく、
それを使った上でさらにそのメソッド内でupdate(jiki,teki,tama,unko)を導入することの利点について考えたこと有りますか?
きちんと比較したことありますか?という辺り
0881名前は開発中のものです。2009/01/31(土) 17:27:48ID:9d5EHsE6
>>878
ひょっとして
> メンバに別クラスのインスタンスの保持禁止にする

の「インスタンス」には「std::list<EnemyTask*>」のようなものは
含まれないのか?これも立派な「インスタンス」だと思うんだが。

何かコンピュータ用語以前に、ID:rIovvj90は日本語が不自由で
何が言いたいのかよくわからない。

そもそも俺にしても >>875 のようなスタイルで書いているわけで
別のTaskのインスタンスなど(compositionでの)保持はしない。

しかしHandleは保持する。それは、参照するのに必要だからである。
0882名前は開発中のものです。2009/01/31(土) 17:39:37ID:9d5EHsE6
>>880
あなたの想定しているように、ゲーム画面ではプレイヤと弾と敵が
存在するが、タイトル画面ではそんなものは存在しないという場合、
タイトル画面を構築に不要なものを排除して、タスク間のinteractionを
なるべく簡素で見える形にしたいという動機は当然ありえる。

それでも
> Scene::update(void) {
>  player.update(jiki,teki,tama,unko);
>  enemy.update(jiki,teki,tama,unko);
>  bullet.update(jiki,teki,tama,unko);
>}
は良くない。この書き方はド素人くさい。
0883名前は開発中のものです。2009/01/31(土) 17:41:19ID:rIovvj90
>>882
>は良くない。この書き方はド素人くさい。
良くない理由はなんで?
0884名前は開発中のものです。2009/01/31(土) 17:41:49ID:8N26Dxd2
>>882
そう、結局そこに帰結する。
>この書き方はド素人くさい。

この1点の是非
0885名前は開発中のものです。2009/01/31(土) 17:43:39ID:j5ds1u2H
メンバもグローバルも駄目なら、
update(jiki,teki,tama,unko)を呼ぶ側のクラスは
jiki,teki,tama,unkoをどこに持ってるんだ?
main関数のローカルに持って、延々と渡していくのか?

まあ、そんなことより、
ID:9d5EHsE6のタスク周りの実装をもう少し聞きたいな。
新しいContextを追加すると、Taskのリストがひとつ増えるんだよね?
そのリストは誰がどういうふうに持つの?
0886名前は開発中のものです。2009/01/31(土) 17:48:59ID:9d5EHsE6
>>882 そういう動機なら

class SceneXXXContext
{
GameGlobalContext* globalContext;
Jiki jiki;
Teki teki;
Tama tama;
Unko unko;
}
こう書いて、

public SceneXXX<GameGlobalContext> : public Task<GameGlobalContext>
{
virtual void update(const GameGlobalContext& globalContext)
{
this->grobalContext = globalContext;
my_task.update(this.context);
}
TaskList<SceneXXXContext> my_task;
SceneXXXContext context;
};
こう書くべきだろう。
0887名前は開発中のものです。2009/01/31(土) 17:49:22ID:9d5EHsE6
>>886 の続き。さらに抽象化して、

template <class GlobalContext,class SceneContext>
public Scene : public Task<GameGlobalContext>
{
virtual void update(const GameGlobalContext& globalContext)
{
this->grobalContext = globalContext;
my_task.update(this.context);
}
TaskList<SceneContext> my_task;
SceneContext context;
}

こうとか。

ID:rIovvj90,ID:8N26Dxd2 の設計と上の設計との大きな違いは、このクラスが
使い回せるし、他の具体的などのTaskクラスにも依存していないということだ。
0888名前は開発中のものです。2009/01/31(土) 17:51:28ID:9d5EHsE6
>>885
> ID:9d5EHsE6のタスク周りの実装をもう少し聞きたいな。
> 新しいContextを追加すると、Taskのリストがひとつ増えるんだよね?

増えない。Contextはタスク階層ごとに必要となるだけ。cf. >>886
0889名前は開発中のものです。2009/01/31(土) 17:56:00ID:8CtHI7i5
>>880
> オブジェクト間関係の見える化の推進度合い

詳細を「隠したい」場合と「見たい」場合があるはずなので、
その場合はどっちですか、という話になるだけでは。
ネジ一本のツクリまで気にしなければ運転できないような車は設計の欠陥で、
「見える」ことが常に良いことである、という発想は誤りです。
OOPのカプセル化やポリモーフィズムの意味を理解してください。

>>885
直接のインスタンス参照ではなく、事実上参照代わりに使えるハンドル(ID)を
持っていると書いてあったと思うけど。
勿論それは寿命が微妙な短命オブジェクトの話で、
寿命管理が明確な長命オブジェクトは直接参照でしょう。
0890名前は開発中のものです。2009/01/31(土) 17:58:00ID:8N26Dxd2
>>889
ネジ一本のツクリまで気にして設計してある車でなければ運転したくないです。
運転手の話したいの?
設計者の話でしょ?
0891名前は開発中のものです。2009/01/31(土) 18:00:52ID:8CtHI7i5
>>890
クラスAを作るとき、クラスAを利用する人間は、クラスAのユーザになる。
どちらも同じ人間かもしれないが、クラスはユーザに対しては詳細を
隠蔽するように働き、汚い泥仕事はその中に閉じ込め、問題の局所性を
高める。
本当にネジを気にしなければならないコードを局所化するわけだ。

OOPどころか、構造化プログラミングの基本中の基本ですので、
一から勉強しなおして下さい。
0892名前は開発中のものです。2009/01/31(土) 18:05:52ID:9d5EHsE6
>>891
> 問題の局所性を高める。

そのためには、あるオブジェクトが実装のために利用するオブジェクトの
種類について >>882 のように制約をかけたいという欲求はあるのでは。

だからこそ俺は、template <class Context>とContextを用いて、
こいつにしかupdateメソッドのなかではアクセスしないという制約
のかけ方を示し >>886 、さらにそれを抽象化して >>887
何故、update(jiki,teki,tama,unko);と書くのが良くないのかに答えた。
■ このスレッドは過去ログ倉庫に格納されています