# HG changeset patch # User e055722 # Date 1235553421 -32400 # Node ID 47d6428a0af6bb57ebab2f391b1815319cdbdf2a # Parent 8454b822d557839ca948dcd9b1be7337448d2392 change tex file. diff -r 8454b822d557 -r 47d6428a0af6 A-5-4-055722/A-5-4-055722.tex --- a/A-5-4-055722/A-5-4-055722.tex Wed Feb 25 10:37:04 2009 +0900 +++ b/A-5-4-055722/A-5-4-055722.tex Wed Feb 25 18:17:01 2009 +0900 @@ -26,9 +26,9 @@ \thispagestyle{fancy} \section{研究背景・目的} -当研究室では学生実験において、PlayStation3を用いた並列的なゲームプログラムの作成を行っている。PlayStation3にはCellと呼ばれるCPUが搭載されており、作成したプログラムはCellに最適化させる必要がある。そこで使用されるのが当研究室で開発したCeriumレンダリングエンジンである。 - Ceriumには、Taskの管理やデータの転送などを行うTaskManager、オブジェクトのレンダリングを行うRenderingEngine、ゲームの場面(Scene)やルールをTree構造に格納したSceneGraphがある。Ceriumを用いたゲームプログラムの例題としてPlayStation2で動作していたゲーム作品の移植を行った。その際、オブジェクトの描画が正常に行われない、衝突判定の位置ずれが生じる等の不具合が発生した。\\ -本研究ではCeriumの中でもSceneGraphに着目し、SceneGraph単位での単体テストを行うことで、、オブジェクトごとの振る舞いや描画をチェックする。これにより、先に述べたゲームの不具合を解消し、正常な動作が行われる事を目指す。 +当研究室では学生実験において、PlayStation3を用いた並列的なゲームプログラムの作成を行っている。そこで使用されるのが当研究室で開発したCeriumレンダリングエンジンである。Ceriumを用いたゲームプログラムの例題としてPlayStation2で動作していた超弾帝(スーパーダンディ)というゲームの移植を行った。\\ +その際、オブジェクトの描画が正常に行われない、衝突判定の位置ずれが生じる等の不具合が発生した。超弾帝には約100種類に及ぶオブジェクトが存在し、今後も同様な不具合を修正していくとすると、学生実験の進行に大きな支障をきたす事となる。\\ +本研究ではCeriumの中でもSceneGraphに着目し、SceneGraph単位でのテストを行うことで、、オブジェクトごとの振る舞いや描画をチェックする。これにより、ゲームのデバッグを容易にし、今後の学生実験におけるゲームの移植や改良、作成を円滑にすることができる。 \section{SceneGraphによるゲームフレームワーク} \subsection{SceneGraphの特徴} @@ -48,48 +48,82 @@ 生成したSceneGraphはset\_move\_collisionという関数によってmoveやcollisionが実装される。 \subsubsection{move} - オブジェクトの動作や状態遷移を記述する。各オブジェクトは複数のmove関数を持っており、set\_move\_collision関数によって状態遷移する。例を以下に示す。 + オブジェクトの動作や状態遷移を記述する。各オブジェクトは複数のmove関数を持っており、set\_move\_collision関数によって状態遷移する。簡単なプログラム例を以下に示す。 + +{\scriptsize +\begin{verbatim} +static void +boss1_move_right(SceneGraphPtr node, int screen_w, int screen_h) { + node->xyz[0] += node->stack_xyz[0]; + if(node->xyz[0] > screen_w-280) { + node->set_move_collision(boss1_move_left, boss1_collision); + } +} -\begin{itemize} -\item move\_left…左に移動するだけの関数 -\item move\_right…右に移動するだけの関数 -\end{itemize} +static void +boss1_move_left(SceneGraphPtr node, int screen_w, int screen_h) { + node->xyz[0] -= node->stack_xyz[0]; + if(node->xyz[0] < 280) { + node->set_move_collision(boss1_move_right, boss1_collision); + } +} +\end{verbatim} +} -オブジェクトは最初move\_leftによって左に移動する。しかし、そのままだといずれ画面外に消えてしまう。そこでmove\_left関数中で条件分岐を立て、画面外ぎりぎりの座標になったらset\_move\_collisionでmove\_rightに切り替え、 -右移動に切り替える。しかし、このままでもいずれ画面外に消えてしまう為、再びset\_move\_collisionに切り替える。 -これを繰り返す事により、オブジェクトが常に画面内に描画されている状態を保つ事が出来る。 +オブジェクトはboss1\_move\_leftによって左に移動する。しかし、そのままだといずれ画面外に消えてしまう。そこでboss1\_move\_left関数中で条件分岐を立て、画面外ぎりぎりの座標になったらset\_move\_collisionでmove\_rightに切り替え、右移動に切り替える。しかし、このままでもいずれ画面外に消えてしまう為、再びset\_move\_collisionに切り替える。これを繰り返す事により、オブジェクトが常に画面内に描画されている状態を保つ事が出来る。 \subsubsection{collision} - オブジェクトの衝突判定を記述する。オブジェクト同士が触れた時に行う動作を決定する。例えばシューティングゲームなら弾丸が敵や自機に当たった時にダメージを受ける、ゲームオーバーになる、などの判定を行う。こちらも条件分岐により、set\_move\_collisionで状態遷移が可能である。 - -\subsubsection{SceneGraphTree} - SceneGraphを用いたゲームプログラムでは各オブジェクトはTree構造で繋がっている必要があり、各々のSceneGraphは addChildで子供となるSceneGraphの登録、addBrotherで同じ親を持つSceneGraphの登録を行い、親子関係を持つ。(図\ref{fig:sgbuild}) - -\begin{figure}[htbp] -\includegraphics[width=8.5cm,height= 9.0cm]{pic/SGbuild.eps} -\caption{SceneGraphTree} -\label{fig:sgbuild} -\end{figure} + オブジェクトの衝突判定を記述する。オブジェクト同士が触れた時に行う動作を決定する。例えばシューティングゲームなら弾丸が敵や自機に当たった時にダメージを受ける、ゲームオーバーになる、などの判定を行う。こちらも条件分岐により、set\_move\_collisionで状態遷移する。 \section{CppUnitを用いたSceneGraphのテスト} \subsection{CppUnitとは} - CppUnitはxUnitの一つであり、C++の単体テストを自動化するframe workである。 CppUnitの特徴は、テストケースを増やす事が容易であり、1つの事象に対して様々なテストケースを同時にテストする事が出来る。また、羅列したテストケースは一括で実行、結果の表示ができる。 + CppUnitはxUnitの一つであり、C++の単体テストを自動化するframe workである。 CppUnitの特徴は、テストケースを増やす事が容易であり、1つの事象に対して様々なテストケースを同時にテストする事が出来る。また、羅列したテストケースは一括で実行、結果の表示ができる。(図\ref{fig:cpptest}) + +\begin{figure}[htbp] +\includegraphics[width=8.5cm]{pic/test_state.eps} +\caption{CppUnitTest} +\label{fig:cpptest} +\end{figure} \subsection{ゲームプログラムのテスト} 3つのSceneGraphを持つオブジェクトのテストを行った。このオブジェクトは本体の他に左右にパーツを1つずつ持つ。 - 本体をTreeのrootとして左右のパーツがその子供になっている。ここで、各オブジェクトのSceneGraphはその親や子、兄弟に対するアドレスを保持している。従って、パーツオブジェクトのテストを行いたい場合は、そのオブジェクトのRootである本体から辿れば、オブジェクトの各パラメータを参照する事が出来る。そこで、Rootのアドレスを取得するgetSGP()という関数を作成した。getSGP()関数によって取得してきたRootのアドレスを使って、各オブジェクトが定義された通りにx,y,zの値を保持しているかテストした。(図\ref{fig:sgtest}) - -\begin{figure}[htbp] -\includegraphics[width=8.5cm]{pic/test_part.eps} -\caption{SceneGraphTest} -\label{fig:sgtest} -\end{figure} + 本体をTreeのrootとして左右のパーツがその子供になっている。\\ + ここで、各オブジェクトのSceneGraphはその親や子、兄弟に対するアドレスを保持している。従って、パーツオブジェクトのテストを行いたい場合は、そのオブジェクトのRootである本体から辿れば、パーツオブジェクトの各パラメータを参照する事が出来る。\\ + そこで、Rootのアドレスを取得するgetSGP()という関数を作成した。getSGP()関数によって取得してきたRootのアドレスを使って、各オブジェクトの座標を取得し、その初期化が正しいか、状態遷移において正しい値を保持いるかテストした。 +\newpage +{\scriptsize +\begin{verbatim} +void +sgTest::rootTest() { + test_init(); + + sg_root->print_member(); + CPPUNIT_ASSERT_EQUAL((float)width/2, sg_root->xyz[0]); + CPPUNIT_ASSERT_EQUAL(0.0f, sg_root->xyz[1]); + CPPUNIT_ASSERT_EQUAL(-100.0f, sg_root->xyz[2]); +} -テストの結果、全てのオブジェクトが定義されたx,y,zの値を保持している事が確認出来た。しかし、move,collision中の -各オブジェクトの座標は確認出来なかった。これはにテストを走らせた時点で全てのテストケースを同時にテストしている為である。 +void +sgTest::childTest() { + while (sg_root) { + if(sg_root->children != NULL) { + sg_root->children->print_member(); +... + sg_root = sg_root->children; + } else if(sg_root->brother != NULL) { + sg_root->brother->print_member(); + CPPUNIT_ASSERT_EQUAL(0.0f, sg_root->brother->xyz[0]); +... + sg_root = sg_root->brother; + } else { + ... +\end{verbatim} +} + +テストの結果、全てのオブジェクトが正常に初期化されているのが確認出来た。しかし、move,collision中の各オブジェクトの座標は確認出来なかった。これはテストを走らせた時点で全てのテストケースを同時にテストしている為、全てのテストケースにおいて初期化がなされた時点での座標の情報しか参照できない為である。 \section{評価} -前述した通り、CppUnitは羅列したテストケースを一括で実行、結果の表示を行うframe workである。しかし各オブジェクトの座標や傾き等はmoveやcollisionにより常に変化している。これらの動作をテストするにはCppUnitには不向きである。よって完全にオブジェクトの振る舞いをテストするには、move,collisionに対応した全く新しいテスト手法を考える必要がある。 +CppUnitによるテストはオブジェクトの座標などの初期値はテスト出来るが、move,collisionによって変化した値をテストするのには不向きである。よってCppUnitはmove,collisionの各関数を抜き出して状態遷移をするかどうかの条件分岐に対して適用するのが適当である。 \thispagestyle{fancy} \begin{thebibliography}{9}