目次

gamelibとは何か

この授業のために開発された簡易的なゲームライブラリとアプリケーションのプログラムです。
ライブラリとアプリケーションを分けることで、
統一されたシステムをベースにした柔軟なゲーム開発が可能になります(はず…)。
ゲームシステム(ヒットポイント管理、ゲームクリア・オーバー条件、ステージマップ管理、敵キャラ行動プログラム)等は
ライブラリに任せ、具体的なステージ構成はアプリケーション側にプログラムしましょう。
難易度の異なる複数のステージを作ったりする際には、ライブラリで構築した関数や構造体を使い、
使用する関数やパラメータ等を変更する事で実現します。
ライブラリに任せる部分とアプリケーションに任せる部分を切り分けてプログラムする設計が重要です。
最初は提供されているライブラリやアプリケーションのプログラムを修正する事で課題を達成し、
次にライブラリを本格的に変更して独自のゲームシステムを構築しましょう。

gamelibのディレクトリ構造

application

具体的なゲームアプリケーションはここに作成します。
shooting_gameディレクトリにサンプルとなる以下の基本ファイルが保存されています。

main.c
shooting_game.c
shooting_game.h
Makefile
exec.sh

include

  • include/gamelib/

gamelibのヘッダファイルのディレクトリです。 以下のファイルが含まれています。

gamelib.h
game_map.h
self_agent.h
enemy_agent.h
interaction.h
  • include/ode/

Open Dynamics Engine(ODE)のヘッダファイルのディレクトリです。

  • include/drawstuff/

ODEに付属しているODEを簡易に実行し、表示する環境のヘッダファイルのディレクトリです。


src

ソースファイルのディレクトリです。

  • src/ode-0.12/ あるいは src/ode-0.11.1/ ODEのソースコードの圧縮ファイルを解凍すると現れるディレクトリです。
    物理シミュレーション、衝突判定、表示や操作のためのライブラリ等がおさめられています。
    MAKEスクリプトを実行する事で自動的にコンパイルとインストールが行われます。
  • src/gamelib/ 本ライブラリの本体のソースコードが保存されています。
    以下のファイルが存在します。
    gamelib.c
    game_map.c
    self_agent.c
    enemy_agent.c
    interaction.c
    Makefile

プログラム説明

アプリーケーションソースコード

  • Makefile

makeを行う際の情報を書き込む。

  • メイン関数を記述するファイル
    application/shooting_game/main.c
  • drawstuffへの関数等の登録
    dsFunctions fn; // drawstuffに登録する情報を格納する構造体を宣言
    fn.version = DS_VERSION; // drawstuffのバージョンを登録する。
    fn.start = &start; //物理シミュレーション開始時に実行される関数(start)を登録する。
    fn.step = &simLoop;//各ステップ毎に実行される関数(simLoop)を登録する。
    fn.command = &command;//キーボードのキーが押された時に実行される関数(command)を登録する。
    fn.stop = &stop;//シミュレーション終了時に実行される関数(stop)を登録する。
    fn.path_to_textures = "./textures/";//テクスチャの画像ファイルを保存しているディレクトリの場所(./textures)を登録する。
  • ODEによる物理シミュレーションの実行
    dInitODE2(0); // ODEの初期化(詳細は参考サイトか参考文献で)
    dsSimulationLoop (argc,argv,600,500,&fn); //物理シミュレーションと表示を開始(画面サイズ600x500)
    dCloseODE(); // ODEの修了処理
    画面サイズを小さくすると処理が軽くなりますので、
    演習室PCでは遅くなる場合に試してみて下さい。
  • ステージ定義等を記述するファイル
    application/shooting_game/shooting_game.c
    application/shooting_game/shooting_game.h
    ODEを簡易に実行するdrawstuffに登録するコールバック関数を定義します。
    定義された関数はmain関数の中で登録している。
  • 物理シミュレーション開始時に一度だけ呼び出される関数
    void start();
    以下、内容解説
    initialize_gamelib(); // gamelibの初期化。必ず最初に行う。
    dAllocateODEDataForThread(dAllocateMaskAll); // ODEの初期化
    
    float default_view_position[3] = {0.0f,0.0f,3.0f};
    float default_view_direction[3] = {0.0f,30.0f,0.0f};
    dsSetViewpoint (default_view_position, default_view_direction);
    
    // マップの作成
    // マップの座標(x,y) x:西→東(0→2)、y:南→北(0→2) と設定 
    make_dead_end_walls(0,0, FROM_NORTH );
    make_t_junction_walls(0,1, FROM_EAST );
    make_dead_end_walls(0,2, FROM_SOUTH );
    make_turn_walls(1,0, FROM_EAST_TO_NORTH );
    make_cross_road_walls(1,1);
    make_turn_walls(1,2, FROM_SOUTH_TO_EAST );
    make_turn_walls(2,0, FROM_NORTH_TO_WEST );
    make_turn_walls(2,1,FROM_WEST_TO_SOUTH );
    make_dead_end_walls(2,2, FROM_WEST );
    
    initialize_self_agent( 0,0, 100,M_PI/2 ); /*セルフエージェントを初期化。構造体のデータはself_agent.hで定義されている。 */
    set_first_person_view_point(); /* ファーストパーソンビューに切り替える */
    make_enemy_agent(0,0,1, 10); // enemy_agent 0番の定義
    make_enemy_agent(1,0,2, 10); // enemy_agent 1番の定義
  • シミュレーションステップ毎に呼び出される関数
    void simLoop( int pause );
    以下はアップデート内容
    update_gamelib(); /* gamelib全体のアップデート。主にODEの処理。中身はgamelib.cに記述*/
    
    update_self_agent();  /*自機のアップデート。中身はself_agent.cに記述*/
    
    /* 視点切り替え処理。view_point_switchのラベルに従って視点切り替え */
    if( view_point_switch == BEHIND_VIEW ){
       /* Behind mode */
       set_behind_view_point();
       visualize_self_agent();
    }else{
       /* First person view mode*/
       set_first_person_view_point();
    }
    visualize_self_agent_bullets();
    visualize_map();
    
    //敵エージェントの更新
    if( true == enabled_enemy_agent( 0 ) && 0 == get_enemy_agent_hit_point( 0 ) ){
      /* もし0番目のenemy_agentが存在し、そのヒットポイントが0の時 */
      destroy_enemy_agent(0); // 0番目のenemy_agentのメモリを解放
      printf("destroy_enemy_agent(0)\n")
    }
    if( true == enabled_enemy_agent( 1 ) && 0 == get_enemy_agent_hit_point( 1 ) ){
      /* もし1番目のenemy_agentが存在し、そのヒットポイントが0の時 */
      destroy_enemy_agent( 1 ); // 0番目のenemy_agentのメモリを解放
      printf("destroy_enemy_agent( 1 )\n")
    }
    
    if( true == enabled_enemy_agent( 0 ) ){
      update_enemy_agent( 0 ); // 0番目のenemy_agentの更新
      visualize_enemy_agent( 0 );
    }
    if( true == enabled_enemy_agent( 1 ) ){
      update_enemy_agent( 1 ); // 1番目のenemy_agentの更新
      visualize_enemy_agent( 1 );
    }
    
    // ゲーム終了処理
    if( false == enabled_enemy_agent( 0 ) && false == enabled_enemy_agent( 1 ) ){
      printf("Congraturations! Game Clear!\n");
      stop();
      exit(0);
    }
    if( get_self_agent_hit_point() <= 0 ){
      printf("You lose! Game Over!\n");
      stop();
      exit(0);
    }
  • キーボードからの入力を受け付ける関数
    void command( int c );
  • 終了処理を行う関数
    void stop();

ライブラリソースコード

  • ゲームシステム全体を管理する関数を記述するファイル
    include/gamelib/gamelib.h
    src/gamelib/gamelib.c
  • プログラム中に必要な資産を管理する仕組み
    一旦全てのデータはGameObject?構造体に格納されて管理される。
    struct GameObject{
      enum ObjectType object_type;
      void* data;
    };
    enum ObjectType?GameObject?に格納されたデータがどのような種類かを示している。
    この値に基づいて "void* data" をキャストすることが可能になる。
    enum ObjectType{
      GROUND,
      WALL,
      SELF_AGENT,
      SELF_AGENT_BULLET,
      ENEMY_AGENT,
    };
    voidポインタはどのようなポインタでも格納できる万能なポインタである。
    ただし、ポインタで指し示している先がどのようなデータか把握していないとデータを読む事ができない。

    キャストとは、ある型の変数を別の方の変数として使用するC言語の仕組みである。
    以下のように用いる。
    void* void_p;
    double* double_p
    double_p = (double*) void_p;
    
    int i = 10;
    double d;
    d = (double)i;
  • gamelib.cに記述された関数
    • プログラムの最初にシステム全体を初期化するための関数
      void initialize_gamelib();
  • プログラムの最後にシステム全体の最終処理をするための関数
    void finalize_gamelib();
  • 毎回のアップデートをする関数
    void update_gamelib();
    主にODEの物理シミュレーションのアップデートを行う。
    dSpaceCollide (space,0,&nearCallback); /* ODEの衝突計算 */
    dWorldStep (world,SIMULATION_TIME_STEP); /* ODEの力学シミュレーション1ステップ */
    dJointGroupEmpty (contactgroup); /* ODEの衝突情報の開放 */
  • ODEで2つの物体が近づいて、衝突しそうになった時(衝突している時)に呼び出されるコールバック関数
    void nearCallback( void *data, dGeomID geom1, dGeomID geom2 );
    Self Agent と Enemy Agentの間等の衝突処理を行う。
  • 自機エージェント構造体定義と関数を記述するファイル
    include/gamelib/self_agent.h
    src/gamelib/self_agent.c

    • 自機の情報を格納する構造体
      struct SelfAgentData{
        dBodyID body_ID; /* ODEの物理計算に必要なID(実際はポインタ) */
        dGeomID geom_ID; /* ODEの衝突計算に必要なID(実際はポインタ)*/
        int hit_point; /* 自機のヒットポイント*/
        dReal direction_angle; /* 自機の方向。東が0ラジアン */
        dVector3 pulling_force; /* 自機を移動させるための力をセットする変数 */
      };
      • direction_angleの角度と向き
        東:    0 [rad] (  0[deg])
        北:  M_PI/2 [rad] ( 90[deg])
        西:  M_PI   [rad] (180[deg])
        南: -M_PI/2 [rad] (-90[deg])
  • 自機から発射される弾丸の情報を管理する構造体。
    struct SelfAgentBulletData{
      dBodyID body_ID;
      dGeomID geom_ID;
      int countdown_timer;
      /*
        発射されると初速度を与え、タイマーに値をセットする。
        ステップ毎にタイマーをカウントダウンして、0になったら位置をリセットする。
        値が0の場合、物理シミュレーションと衝突判定を行わない。
      */
    };
  • 自機のデータを生成する関数
    void initialize_self_agent( int map_x, int map_y,
                          int initial_hit_point,
                          dReal initial_direction_angle);
  • 自機のポインタを安全に消去する関数
    void destroy_self_agent();
  • 自機をアップデートする関数
    void update_self_agent();
  • 自機の背後から視点に切り替える関数
    void set_behind_view_point();
  • 自機の一人称視点に切り替える関数
    void set_first_person_view_point();
  • 自機を操作するコマンドを入力して、必要な処理を行う関数
    void command_self_agent( int command );
  • 自機から弾丸を発射する関数
    void self_agent_shoot_gun();
  • 自機を可視化する関数
    void visualize_self_agent();
  • 自機の弾丸を可視化する関数
    void visualize_self_agent_bullets();
  • 自機の位置を返す関数
    const dReal* get_self_agent_position();
  • 自機のヒットポイントを返す関数
    int get_self_agent_hit_point();
    以下の値を直接参照する事もできるが、 ヒットポイントの処理について何らかの変更を行いたい時に関数化しておくと便利。
    self_agent_data->hit_point;
  • 自機のヒットポイントを増減する関数
    void change_self_agent_hit_point( int hit_point ); 
    正の値で増加し、負の値で減少する。 以下のように直接操作する事もできるが、 ヒットポイントの処理について何らかの変更を行いたい時に関数化しておくと便利。
    self_agent_data->hit_point --;
  • 敵エージェント構造体定義と関数を記述するファイル
    include/gamelib/enemy_agent.h
    src/gamelib/enemy_agent.c
  • 敵機の情報を格納する構造体
    struct EnemyAgentData{
      bool enabled;
      int hit_point;
      dBodyID body_ID;
      dGeomID geom_ID;
    };
  • 敵機を初期化する関数
    void initialize_enemy_agent();
  • 敵機のデータを生成する関数
    void make_enemy_agent( int enemy_agent_index, int initiali_position_map_x, int initial_position_map_y, int initial_hit_point );
  • 敵機を可視化する関数
    void visualize_enemy_agent( int enemy_agent_index );
  • 敵機をアップデートする関数
    void update_enemy_agent( int enemy_agent_index );
  • 敵機を安全に消去する関数
    void destroy_enemy_agent( int enemy_agent_index );
  • 敵機のヒットポイントを返す関数
    int get_enemy_agent_hit_point( int enemy_agent_index );
    以下の値を直接参照する事もできるが、 ヒットポイントの処理について何らかの変更を行いたい時に関数化しておくと便利。
    enemy_agent_data->hit_point;
  • 敵機の存在を示す関数
    bool enabled_enemy_agent( int enemy_agent_index );
    敵機が存在していればtrue、破壊されていればfalseを返す。
  • ゲームマップの構造体定義と関数を記述するファイル
    include/gamelib/game_map.h
    src/gamelib/game_map.c
  • マップの情報を格納する構造体
    • 壁の情報を保存
      struct WallData{
        dGeomID geom_ID; /* ODEの衝突計算に使うID*/
        dBodyID body_ID; /* ODEの物理計算に使うID。実際には壁は移動しないがbodyIDが無いとdGeomIDを設定できないため */
        dJointID fixed_joint_ID; /*空間に壁を固定するためのジョイント。固定するだけなのでfixedジョイントを用いる*/
      };
      
      struct MapData{
        dReal center_position[2]; //[0]->x, [1]->y
        int wall_size;
        struct GameObject wall_object[MAP_ONE_SQUIRE_MAX_WALL_SIZE];
         /*現在、"WALL"しか代入されないためこの情報は使用されていないが、必要に応じて意味のある情報に書き替えても良い*/
        struct WallData wall_data[MAP_ONE_SQUIRE_MAX_WALL_SIZE];
         /*voidのポインタとして管理する事で、様々なオブジェクトを格納してマップ要素を構成する事は可能。
          そのオブジェクトが何かはwall_objectで指示すれば良い*/
      };
  • マップの初期化をする関数
    void initialize_map();
  • マップの情報を安全に消去する関数
    void destroy_map();
  • 直線的な通路を生成する関数
    int make_straight_walls( int map_x, int map_y, enum DIRECTION direction );
  • 曲がる通路を生成する関数
    int make_turn_walls( int map_x, int map_y, enum DIRECTION direction );
  • T字路を生成する関数
    int make_t_junction_walls( int map_x, int map_y, enum DIRECTION direction );
  • 交差点を生成する関数
    int make_cross_road_walls( int map_x, int map_y);
  • 行き止まりを生成する関数
    int make_dead_end_walls( int map_x, int map_y, enum DIRECTION direction );
  • game_map.cの内部で使用する壁を生成する関数
    int make_wall( dReal wall_center_position_x, dReal wall_center_position_y,
                  dReal wall_direction_x, dReal wall_direction_y,
                  dReal wall_length,
                  struct GameObject* wall_object );
  • game_map.cの内部で使用する2次元ベクトルを回転する関数
    void rotate_90deg_clockwise( dReal* vec2 );
    void rotate_90deg_anticlockwise( dReal* vec2 );
    void rotate_180deg( dReal* vec2 );
  • マップを可視化する関数
    void visualize_map();
  • インタラクションのための関数を記述するファイル
    include/gamelib/interaction.h
    src/gamelib/interaction.c
    自機と敵、弾と敵がぶつかった時の処理プログラム。
  • 自機の弾丸と敵機が接触したときの処理関数
    void self_agent_bullet_hits_to_enemy_agent( struct SelfAgentBulletData* self_agent_bullet_data,
                                                struct EnemyAgentData* enemy_agent_data );
  • 自機と敵機が接触したときの処理関数
    void contact_self_agent_and_enemy_agent( struct EnemyAgentData* enemy_agent_data );

トップ   編集 凍結 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2018-03-23 (金) 19:50:16 (237d)