自作:描画クラスについて

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
スティアラ

自作:描画クラスについて

#1

投稿記事 by スティアラ » 10年前

初めまして、スティアラと申します。
フォーラムルールは目を通しましたが、
間違っている部分等有りましたら、ご指摘、お願い致します。

一応分からないところなどはGoogle先生に聞いてみたのですが、
私の検索する能力が弱い?為か、あまりhitしませんでした...
ですので、ここで質問させて頂きます。

それからプログラム経歴は2週間程でまだまだひよっこです。
用語など、大きく間違っている可能性もあります...
それでも見ていただけると嬉しいです。

前置きが長くなってしまいましたが、本題に入ろうと思います。
現在描画クラスなるものを作成しています。
描画する際にCDraw(描画クラス)のint Draw(void)を呼び出すだけで各種描画が出来る様になっています。

コード:

// 描画する数
const int DRAW_NUM = 2;

// 以下のようにnewで使用するクラスを生成します。
CDraw *pDraw[DRAW_NUM] = new CDraw(); // 描画管理
CDraw *pImg = new CGraph(); // 画像
CDraw *pBox = new CBlock();  // 図形

// 描画するものは全てこのpDrawへ
pDraw[0] = pImg; // 画像
pDraw[1] = pBox; // 図形

// 画像の読み込み等を行います
pImg->GSHandle("Dat/Gph/Test.png");
if (pImg->GSHandle() == -1) return -1;

// その後、void GSDrawFlag(bool)で描画フラグをtrueにし、
pImg->GSDrawFlag(true); // 描画対象にする
pBox->GSDrawFlag(true); // 描画対象にする

// int Draw(void)を呼び出すと各クラスごとにオーバーロードした描画関数が呼び出される、といった仕組みです。
for (int i = 0; i < DRAW_NUM; i++) {
  pDraw[i]->Draw();
}
このCDrawクラスに新しく文字列の描画を管理するクラスを追加しようとしましたが、
そうなると無駄な仮想関数が増え、メモリの消費も微々たるものですが、あまり宜しくないかと思いました。

この描画方法以外に何かないでしょうか?

やりたい事としては、以下の3つです。
・カプセル化(現状で出来ているかどうかも怪しいですが)
・メモリの節約(出来れば)
・一つの描画関数で描画(オーバーロードをしたりして、呼び出すときは上の例の様に描画関数をfor文で回したいと思っています。)

ヒントだけでも良いので、ご教授のほど宜しくお願いします。

使用環境
OS : windows8
コンパイラ : Visual Studio Express 2012 for Windows Desktop
ライブラリ : DXライブラリ

以下、現在のソースコードになります。
(フィールド内描画は縦スクロールシューティングゲームのフィールド内の描画を行うべく、
 X座標、Y座標にフィールドの左上座標を足して、描画位置をフィールド内にずらしている物です。)
一応記載(分からなくなるといけないので)

コード:

class CBattle {
public:
  static const int STAGE_SX = 64; // フィールドの左上X座標
  static const int STAGE_SY = 32; // フィールドの左上Y座標
};

コード:

 /*h*/
// 描画クラス
class CDraw {
public:

  CDraw(void) :
    DrawFlag(false), Blend(255), X(0), Y(0) {} // コンストラクタ
  ~CDraw(void) {}                              // デストラクタ
  
  int Draw(void); // 描画

  bool GSDrawFlag(void) { return DrawFlag; } // 描画フラグの取得
  void GSDrawFlag(bool i) { DrawFlag = i; }  //     〃    の設定
  int GSBlend(void) { return Blend; }        // 透明度の取得
  void GSBlend(int i) { Blend = i; }         //   〃  の設定
  float GSX(void) { return X; }              // X座標の取得
  void GSX(float i) { X = i; }               //  〃  の設定
  float GSY(void) { return Y; }              // Y座標の取得
  void GSY(float i) { Y = i; }               //  〃  の設定
  
  // 仮想関数
  virtual int DrawSystem(void) = 0; // 描画方式

  // 画像用
  virtual int GSHandle(void) { return 0; }        // 画像ハンドルの取得
  virtual void GSHandle(int i) {}                 //      〃     の設定
  virtual float GSSize(void) { return 0.0; }      // 大きさの取得
  virtual void GSSize(float i) {}                 //   〃  の設定
  virtual float GSAgl(void) { return 0.0; }       // 角度の取得
  virtual void GSAgl(float i) {}                  //  〃 の設定
  virtual bool GSFlag(void) { return false; }     // 透過フラグの取得
  virtual void GSFlag(bool i) {}                  //     〃    の設定
  virtual bool GSTurnFlag(void) { return false; } // 反転フラグの取得
  virtual void GSTurnFlag(bool i) {}              //     〃    の設定

  // 図形用
  virtual float GSX2(void) { return 0.0; }        // 右下X座標の取得
  virtual void GSX2(float i) {}                   //    〃    の設定
  virtual float GSY2(void) { return 0.0; }        // 右下Y座標の取得
  virtual void GSY2(float i) {}                   //    〃    の設定
  virtual int GSColor(void) { return 0; }         // 色情報の取得
  virtual void GSColor(int i) {}                  //   〃  の設定
  virtual bool GSFillFlag(void) { return false; } // 塗り潰しフラグ
  virtual void GSFillFlag(bool i) {}              // 塗り潰しフラグ

  // ここに文字列の描画を管理する関数を追加する予定

private:

  bool DrawFlag; // 描画フラグ
  int Blend;     // 透明度
  float X, Y;    // XY座標
};


// 画像クラス(DrawGraph用)
class CGraph : public CDraw {
public:

  CGraph(void) : Flag(true), TurnFlag(false) {} // コンストラクタ
  ~CGraph(void) {}                              // デストラクタ

  int DrawSystem(void); // 描画方式
  
  int GSHandle(void) { return Handle; }      // 画像ハンドルの取得
  void GSHandle(int i) { Handle = i; }       //      〃     の設定
  bool GSFlag(void) { return Flag; }         // 透過フラグの取得
  void GSFlag(bool i) { Flag = i; }          //     〃    の設定
  bool GSTurnFlag(void) { return TurnFlag; } // 反転フラグの取得
  void GSTurnFlag(bool i) { TurnFlag = i; }  //     〃    の設定

private:
  
  int Handle;    // 画像ハンドル
  bool Flag;     // 透過フラグ
  bool TurnFlag; // 反転フラグ
};


// 画像クラス(DrawGraph用、フィールド内描画)
class CGraphF : public CGraph {
public:

  int DrawSystem(void); // 描画方式
};


// 画像クラス(DrawRotaGraph用)
class CGraphRota : public CDraw {
public:
  
  CGraphRota(void) : Size(1.0),
    Agl(0.0), Flag(true), TurnFlag(false) {} // コンストラクタ
  ~CGraphRota(void) {}                       // デストラクタ

  int DrawSystem(void); // 描画方式
  
  int GSHandle(void) { return Handle; }      // 画像ハンドルの取得
  void GSHandle(int i) { Handle = i; }       //      〃     の設定
  float GSSize(void) { return Size; }        // 大きさの取得
  void GSSize(float i) { Size = i; }         //   〃  の設定
  float GSAgl(void) { return Agl; }          // 角度の取得
  void GSAgl(float i) { Agl = i; }           //  〃 の設定
  bool GSFlag(void) { return Flag; }         // 透過フラグの取得
  void GSFlag(bool i) { Flag = i; }          //     〃    の設定
  bool GSTurnFlag(void) { return TurnFlag; } // 反転フラグの取得
  void GSTurnFlag(bool i) { TurnFlag = i; }  //     〃    の設定

private:

  int Handle;    // 画像ハンドル
  float Size;    // 大きさ
  float Agl;     // 角度
  bool Flag;     // 透過フラグ
  bool TurnFlag; // 反転フラグ
};


// 画像クラス(DrawRotaGraph用、フィールド内描画)
class CGraphRotaF : public CGraphRota {
public:

  int DrawSystem(void); // 描画方式
};


// 図形クラス
class CBlock : public CDraw {
public:
  
  CBlock(void) : X2(0.0),
    Y2(0.0), FillFlag(true) {} // コンストラクタ
  ~CBlock(void) {}             // デストラクタ

  int DrawSystem(void); // 描画方式
  
  float GSX2(void) { return X2; }            // 右下X座標の取得
  void GSX2(float i) { X2 = i; }             //    〃    の設定
  float GSY2(void) { return Y2; }            // 右下Y座標の取得
  void GSY2(float i) { Y2 = i; }             //    〃    の設定
  int GSColor(void) { return Color; }        // 色情報の取得
  void GSColor(int i) { Color = i; }         //   〃  の設定
  bool GSFillFlag(void) { return FillFlag; } // 塗り潰しフラグ
  void GSFillFlag(bool i) { FillFlag = i; }  // 塗り潰しフラグ

private:

  float X2, Y2;  // 右下XY座標
  int Color;     // 色情報
  bool FillFlag; // 塗りつぶしフラグ
};


// 図形クラス(フィールド内描画)
class CBlockF : public CBlock {
public:

  int DrawSystem(void); // 描画方式
};

コード:

 /*cpp*/
//------------------------------------------------------------------------------
//  概略   : 画像の描画
//  引数   : なし
//  戻り値 :  0 : 成功
//           -1 : エラー発生
//  解説   :  画像の描画を行います。
//           Blendの値が大きい程不透明に、小さい程透明になる様描画します。
//------------------------------------------------------------------------------
int CDraw::Draw(void)
{
  if (GSDrawFlag()) {
    if (SetDrawBlendMode(DX_BLENDMODE_ALPHA, GSBlend()) == -1) return -1;
    if (DrawSystem() == -1) return -1;
    if (SetDrawBlendMode(DX_BLENDMODE_NOBLEND, 0) == -1) return -1;
  }
    
  // 成功
  return 0;
};


//------------------------------------------------------------------------------
//  概略   : 画像の描画
//  引数   : なし
//  戻り値 :  0 : 成功
//           -1 : エラー発生
//  解説   :  画像の描画を行います。
//------------------------------------------------------------------------------
int CGraph::DrawSystem(void)
{
  if (!GSTurnFlag()) {
    if (DrawGraphF(GSX(), GSY(), GSHandle(), GSFlag()) == -1) return -1;
  } else {
    if (DrawTurnGraphF(GSX(), GSY(), GSHandle(), GSFlag()) == -1) return -1;
  }

  // 成功
  return 0;
}


//------------------------------------------------------------------------------
//  概略   : 画像のフィールド内描画
//  引数   : なし
//  戻り値 :  0 : 成功
//           -1 : エラー発生
//  解説   :  画像のフィールド内描画を行います。
//------------------------------------------------------------------------------
int CGraphF::DrawSystem(void)
{
  if (!GSTurnFlag()) {
    if (DrawGraphF(GSX() + CBattle::STAGE_SX, GSY() + CBattle::STAGE_SY, GSHandle(), GSFlag()) == -1) return -1;
  } else {
    if (DrawTurnGraphF(GSX() + CBattle::STAGE_SX, GSY() + CBattle::STAGE_SY, GSHandle(), GSFlag()) == -1) return -1;
  }

  // 成功
  return 0;
}


//------------------------------------------------------------------------------
//  概略   : 画像の描画
//  引数   : なし
//  戻り値 :  0 : 成功
//           -1 : エラー発生
//  解説   :  画像の描画を行います。
//           サイズ指定や角度の変更が出来ます。
//------------------------------------------------------------------------------
int CGraphRota::DrawSystem(void)
{
  return DrawRotaGraphF(GSX(), GSY(),
    GSSize(), GSAgl(), GSHandle(), GSFlag(), GSTurnFlag());
}


//------------------------------------------------------------------------------
//  概略   : 画像のフィールド内描画
//  引数   : なし
//  戻り値 :  0 : 成功
//           -1 : エラー発生
//  解説   :  画像のフィールド内描画を行います。
//           サイズ指定や角度の変更が出来ます。
//------------------------------------------------------------------------------
int CGraphRotaF::DrawSystem(void)
{
  return DrawRotaGraphF(GSX() + CBattle::STAGE_SX,
    GSY() + CBattle::STAGE_SY, GSSize(), GSAgl(), GSHandle(), GSFlag(), GSTurnFlag());
}


//------------------------------------------------------------------------------
//  概略   : 図形の描画
//  引数   : なし
//  戻り値 :  0 : 成功
//           -1 : エラー発生
//  解説   :  図形の描画を行います。
//------------------------------------------------------------------------------
int CBlock::DrawSystem(void)
{
  // 選択カーソルの描画
  return DrawBox((int)GSX(), (int)GSY(),
    (int)GSX2(), (int)GSY2(), GSColor(), GSFillFlag());
}
長文、失礼致しました。

スティアラ

Re: 自作:描画クラスについて

#2

投稿記事 by スティアラ » 10年前

最初の例のCDraw *pDraw[DRAW_NUM] = new CDraw();の = new CDraw()は要りませんね、
正しくはCDraw *pDraw[DRAW_NUM];です、すみません。

アバター
usao
記事: 1887
登録日時: 11年前

Re: 自作:描画クラスについて

#3

投稿記事 by usao » 10年前

基底クラス CDraw で規定すべきインタフェースは何なのか? を整理されてみると良いのではないでしょうか.
おそらくですが,CDrawの存在目的は
>int Draw(void)を呼び出すだけで各種描画が出来る
であるはずです.(つまり,Draw()なる仮想関数の型を規定すること.)
であれば,CDrawにて規定するメソッドは最低限 Draw() のみでよいと思います.

コード:

//これだけかな.
class CDraw
{
public:
  virtual ~CDraw(){}
  virtual int Draw() = 0;
};
すべての派生クラスに必要になるものだけを基底クラスで用意する.
(インタフェースクラスじゃなくてもいいや,というのであっても,CDrawに他に入れるとしても描画フラグくらいかな?)

個々の派生クラスで必要なものは派生クラスで用意する.
・画像の表示に必要なメソッド → CGraph にあればよい
・図形の表示に必要なメソッド → CBlock にあればよい
・文字列に必要なメソッド → 新しく作る文字列描画用クラスにだけあればよい

で,仮に,画像と図形とで共通して必要な機能があって(例えば透明度),それらをまとめたいようなことがあるならば,
CDrawから派生した それらの共通要素を持つクラス を作り,CGraphとCBlockはそこから派生させればよいと思います.

スティアラ

Re: 自作:描画クラスについて

#4

投稿記事 by スティアラ » 10年前

usao様、有難うございます。
なるほど、CDrawには必要最低限のものを、
共通して使うものがあれば新しくクラスを作成し、
そこから派生させると。(解釈これであっているのかな?

今まで一つのクラスにしようと頭が固くなっていたかもしれません。
教えて下さった事を生かし、今から作成してみようと思います。

結果が出次第、ここで報告をさせて頂きます。

スティアラ

Re: 自作:描画クラスについて

#5

投稿記事 by スティアラ » 10年前

修正が終わりましたので、上げさせて頂きます。
(usao様、大分遅れてしまいました、すみません。)
この前のソースコードと見比べてみて、どうでしょうか?
まだおかしい部分などありましたらご指摘お願いします。

※正確に動作する事は確認出来ています。

コード:

// 描画クラス
class CDraw {
public:

  virtual ~CDraw(void) {}     // デストラクタ
  virtual int Draw(void) = 0; // 描画
};


// 描画共通クラス
class CDrawCommon : public CDraw{
public:
  
  CDrawCommon(void) :DrawFlag(false), Blend(255), X(0.0), Y(0.0) {} // コンストラクタ
  virtual ~CDrawCommon(void) {}                                     // デストラクタ

  virtual int Draw(void);           // 描画
  virtual int DrawSystem(void) = 0; // 描画方式

  bool GSDrawFlag(void) { return DrawFlag; } // 描画フラグの取得
  void GSDrawFlag(bool i) { DrawFlag = i; }  //     〃    の設定
  float GSX(void) { return X; }              // X座標の取得
  void GSX(float i) { X = i; }               //  〃  の設定
  float GSY(void) { return Y; }              // Y座標の取得
  void GSY(float i) { Y = i; }               //  〃  の設定
  int GSBlend(void) { return Blend; }        // 透明度の取得
  void GSBlend(int i) { Blend = i; }         //   〃  の設定
  
private:

  bool DrawFlag; // 描画フラグ
  float X, Y;    // XY座標
  int Blend;     // 透明度
};


// 画像クラス(DrawGraph用)
class CGraph : public CDrawCommon {
public:

  CGraph(void) : Flag(true), TurnFlag(false) {} // コンストラクタ
  virtual ~CGraph(void) {}                      // デストラクタ

  virtual int DrawSystem(void); // 描画方式
  
  int GSHandle(void) { return Handle; }      // 画像ハンドルの取得
  int GSHandle(int i) { return Handle = i; } //      〃     の設定
  bool GSFlag(void) { return Flag; }         // 透過フラグの取得
  void GSFlag(bool i) { Flag = i; }          //     〃    の設定
  bool GSTurnFlag(void) { return TurnFlag; } // 反転フラグの取得
  void GSTurnFlag(bool i) { TurnFlag = i; }  //     〃    の設定

private:
  
  int Handle;    // 画像ハンドル
  bool Flag;     // 透過フラグ
  bool TurnFlag; // 反転フラグ
};


// 画像クラス(DrawGraph用、フィールド内描画)
class CGraphF : public CGraph{
public:

  virtual int DrawSystem(void); // 描画方式
};


// 画像クラス(DrawRotaGraph用)
class CGraphRota : public CDrawCommon {
public:
  
  CGraphRota(void) : Size(1.0),
    Agl(0.0), Flag(true), TurnFlag(false) {} // コンストラクタ
  virtual ~CGraphRota(void) {}               // デストラクタ

  virtual int DrawSystem(void); // 描画方式
  
  int GSHandle(void) { return Handle; }      // 画像ハンドルの取得
  void GSHandle(int i) { Handle = i; }       //      〃     の設定
  float GSSize(void) { return Size; }        // 大きさの取得
  void GSSize(float i) { Size = i; }         //   〃  の設定
  float GSAgl(void) { return Agl; }          // 角度の取得
  void GSAgl(float i) { Agl = i; }           //  〃 の設定
  bool GSFlag(void) { return Flag; }         // 透過フラグの取得
  void GSFlag(bool i) { Flag = i; }          //     〃    の設定
  bool GSTurnFlag(void) { return TurnFlag; } // 反転フラグの取得
  void GSTurnFlag(bool i) { TurnFlag = i; }  //     〃    の設定

private:

  int Handle;    // 画像ハンドル
  float Size;    // 大きさ
  float Agl;     // 角度
  bool Flag;     // 透過フラグ
  bool TurnFlag; // 反転フラグ
};


// 画像クラス(DrawRotaGraph用、フィールド内描画)
class CGraphRotaF : public CGraphRota {
public:

  virtual int DrawSystem(void); // 描画方式
};


// 図形クラス
class CBlock : public CDrawCommon {
public:
  
  CBlock(void) : X2(0.0), Y2(0.0), FillFlag(true) {} // コンストラクタ
  virtual ~CBlock(void) {}                           // デストラクタ

  virtual int DrawSystem(void); // 描画方式
  
  float GSX2(void) { return X2; }            // 右下X座標の取得
  void GSX2(float i) { X2 = i; }             //    〃    の設定
  float GSY2(void) { return Y2; }            // 右下Y座標の取得
  void GSY2(float i) { Y2 = i; }             //    〃    の設定
  int GSColor(void) { return Color; }        // 色情報の取得
  void GSColor(int i) { Color = i; }         //   〃  の設定
  bool GSFillFlag(void) { return FillFlag; } // 塗り潰しフラグ
  void GSFillFlag(bool i) { FillFlag = i; }  // 塗り潰しフラグ

private:

  float X2, Y2;  // 右下XY座標
  int Color;     // 色情報
  bool FillFlag; // 塗りつぶしフラグ
};


// 図形クラス(フィールド内描画)
class CBlockF : public CBlock {
public:

  int DrawSystem(void); // 描画方式
};
呼び出し方については前と変わりません。
ただ宣言の時に型を派生クラスの型に変更しました。

仮想デストラクタについては知識不足でした。
(コレ→ virtual ~CDraw(void) {} // デストラクタ)
前のコードのままであると、基底クラスのデストラクタだけしか、
呼ばれなかったのですね、勉強になりました。

zxc
記事: 79
登録日時: 11年前
住所: 日本の背骨(?)あたり

Re: 自作:描画クラスについて

#6

投稿記事 by zxc » 10年前

  描画クラスはあくまで描画を行うクラスであるはずです。座標などの情報がもちろん必要になるでしょうが、それはこのクラス以外にもいえることだと思います。それならば必要な座標などの情報をこのように扱うのではなく、座標クラスや画像ハンドルクラス等のクラスをあらかじめ作っておき、描画クラスがそれらのインスタンスを持つような構造にするほうが、(あくまで私の個人的な好みに過ぎませんが)望ましいかと思います。

スティアラ

Re: 自作:描画クラスについて

#7

投稿記事 by スティアラ » 10年前

zxc様、有難うございます。
こういうことでしょうか?

コード:

// 座標管理クラス
class CCoordinate {
public:
  CCoordinate(void) : X(0.0), Y(0.0) {} // コンストラクタ
  virtual ~CCoordinate(void) {}         // デストラクタ
  
  float GSX(void) { return X; }  // X座標の取得
  void GSX(float i) { X = i; }   //   〃  の設定
  float GSY(void) { return Y; }  // Y座標の取得
  void GSY(float i) { Y = i; }   //   〃  の設定
private:
  float X, Y; // XY座標
};

// 画像ハンドルクラス
class  CHandle {
public:
  CHandle(void) : Handle(0) {} // コンストラクタ
  virtual ~CHandle(void) {}    // デストラクタ

  int GSHandle(void) { return Handle; }      // 画像ハンドルの取得
  int GSHandle(int i) { return Handle = i; } //      〃     の設定
private:
  int Handle; // 画像ハンドル
};

// 画像クラス
class CGraph : public CDrawCommon, public CCoordinate, public CHandle {
  // 以下略
}
CGraphRota内のSizeやAngle、CBlock内のX2やY2、Colorなどはさらに別クラスにしたほうがよいのでしょうか?

あと思ったのですが、描画クラス(CDraw)と画像クラス(CGraph)等が
同一ヘッダ内にあるのもおかしいですね、ファイル分別しておきます。

zxc
記事: 79
登録日時: 11年前
住所: 日本の背骨(?)あたり

Re: 自作:描画クラスについて

#8

投稿記事 by zxc » 10年前

  おおよそそれであっていますが、CGraphクラスが随分沢山のクラスを継承しているように思われます。本当に継承で表現すべき関係なのかを考えてみてください。例えばスクロールバーとウィンドウのように、あるクラスAで表現されるものがクラスBで表現するものに複数あったとしても何もおかしくないようなら、それは継承ではなくインスタンスを持たせる等にすべきかと思います。他にも様々な考え方とクラス同士の関係があるので、それらしいものを調べるなりして選んでください。どれが適切かは作っている本人が判断すべきだと思うのです。

  また、AがBを継承しているなら、AとBは、Bとして取り扱える(例えば猫クラスをライオンクラスと虎クラスが継承しているなら、猫クラス、ライオンクラス、虎クラスは猫クラスとしても扱える)と言うことを表現することだと自分は思っています。CGraphを座標クラスとして取り扱う場面が出てくるなら仕方ないかもしれませんが、なかなかそのような状況は想像し難いです。

  自分でしたらColor等もそれぞれクラスを作ろうとするかもしれませんが、設計や好み、手間に見合うだけのメリットが得られるか等の問題もあるので一概にそうした方が良いとは言えないと思います。

アバター
usao
記事: 1887
登録日時: 11年前

Re: 自作:描画クラスについて

#9

投稿記事 by usao » 10年前

Draw()とDrawSystem()の2つがある意味がよくわからないのですが,
ひょっとして,各具象クラスでの実際の描画処理が定義されるのは
Draw()ではなくてDrawSystem()の方なのでしょうか?
(だとしたらDraw()の役目は何?ということになるけど…)

あと,constにできるメソッドはconstにしとくと良いかと思います.


何をどこまで小分けにするのか,については,それらのクラスの実際の利用状況というか
「どういうものを表しているの?」といったことがわからないと何とも言えない部分があると思います.
座標の方はまだしも
その画像ハンドルクラスというのは一体何の役目を担っているのですか?

nil
記事: 428
登録日時: 12年前

Re: 自作:描画クラスについて

#10

投稿記事 by nil » 10年前

メンバ関数の名前が非常にわかりづらいと思います。
usaoさんの仰っているDrawSystemもそうですが、GS~というのは特にわかりにくいです。

これは個人的な好き嫌いなのですが、
getterとsetterはそれぞれGet~, Set~とした方がいいと思います。

あと、気になったのは、実際にこのクラス群を使うにあたって、
コードの描画部に、それぞれ

コード:

GSX(posX);
GSY(posY);
GSSize(size);
GSAngle(angle);
GSTurn(false);
...
...
というふうにsetterを並べることに成るのでしょうか?

これでは不便ではありませんか?

スティアラ

Re: 自作:描画クラスについて

#11

投稿記事 by スティアラ » 10年前

名前ですか...どんな名前をつけたらよいか分からず、
現状に至ります(英語を少し勉強したほうがよさそうですね...

GSは確かに分かりにくいかもですね、名前をAccessorにすべきでした。
涼雅様のおっしゃる通り、GetとSetに分ける方がいいのかもしれませんね。
(といいますか、そうしておきます。

画像ハンドルクラスに分ける理由はまだよく分かっておりません...
とりあえず分けてみたというところです...

constはそうですね、つけておきます。

Drawについて
Drawに直接、描画関数の中身を書いてもよいのですが、
その場合にはCGraph、CGraphRota等ひとつひとつにこれを書かなければなりません。

コード:

  if (GSDrawFlag()) {
    if (SetDrawBlendMode(DX_BLENDMODE_ALPHA, GSBlend()) == -1) return -1;
    // 描画
    if (SetDrawBlendMode(DX_BLENDMODE_NOBLEND, 0) == -1) return -1;
  }
これはDrawSystemを捨て、Draw内に書いたほうがよいのでしょうか?

涼雅様のおっしゃっているsetterを並べることについてですが、
そうする以外にまだ方法を知りません...
参考サイトなどを教えて頂けると嬉しいです。

スティアラ

Re: 自作:描画クラスについて

#12

投稿記事 by スティアラ » 10年前

↑書き忘れていました、すみませんm(__)m
usao様、涼雅様、有難うございます。

アバター
usao
記事: 1887
登録日時: 11年前

Re: 自作:描画クラスについて

#13

投稿記事 by usao » 10年前

DrawSystem()とDraw()がそれぞれ中で何をやっているのかこちらには不明なので
以下想像ですが,

要するにやりたいことは,たとえば

コード:

CDraw *pDrawItem = new CGraph;
...
pDrawItem->Draw();
とすることによって,描画を可能とすること,だったのだと思うのですが,
コードを見るとCGraphではDraw()がオーバーライドされておらず,この場合,
CDrawCommon::Draw()が呼ばれることになりますね.
CDrawCommonはCGraphが描画すべき画像ハンドルを持っていることすら知らないわけなので,
CDrawCommon::Draw()の中で何かそれを解決するための方策が行われているはずで,
それがDrawSystem()なのでしょうか? つまり

コード:

void CDrawCommon::Draw()
{
  if (GSDrawFlag()) {
    if (SetDrawBlendMode(DX_BLENDMODE_ALPHA, GSBlend()) == -1) return -1;
    {
        DrawSystem();  //実際の描画コードはこの中にある
    }
    if (SetDrawBlendMode(DX_BLENDMODE_NOBLEND, 0) == -1) return -1;
  }
}
こんな形になっているということでしょうか.
で,DrawSystem()がpublicとして公開されているのは,
フラグと透明度設定の状態を無視した描画をしたいときもあるから,といった理由でしょうか.
もしそうであれば,そういう形で構わないと思いますが,
(他の方も指摘されているように)DrawSystem()のような関数名では,それが何をやっているのかが
非常にわかりづらいので,「名は体をあらわす」状態を心がけられたほうが良いと思います.

スティアラ

Re: 自作:描画クラスについて

#14

投稿記事 by スティアラ » 10年前

usao様、有難うございます。
DrawSystemをpublic公開しなくていいですね、すみません...
publicは関数、privateは変数と区別して考えてしまっていました。

Draw、DrawSystem内などは一番最初に記載しているのですが...

アバター
usao
記事: 1887
登録日時: 11年前

Re: 自作:描画クラスについて

#15

投稿記事 by usao » 10年前

>Draw、DrawSystem内などは一番最初に記載しているのですが...
本当ですね……なぜか宣言側しか見えていませんでした.
大変失礼しました.


あとは実際にはDraw()を持つべき対象は何なのか
(画像毎に描画位置などを保持する形が好ましいのかどうか)とかいう話もあるのかもしれませんが,
それはこのスレッドの話の範囲外でしょうかね.

アバター
へにっくす
記事: 634
登録日時: 11年前
住所: 東京都

Re: 自作:描画クラスについて

#16

投稿記事 by へにっくす » 10年前

スティアラ さんが書きました:名前ですか...どんな名前をつけたらよいか分からず、
現状に至ります(英語を少し勉強したほうがよさそうですね...
ここだけ反応しますが、別に英語にこだわる必要はありませんよ。凝った英語を使ったって、見る人が分からなければ意味ありませんし。
ローマ表記でもよいですし、極端な話、以下のように日本語で書いたって構わないんです(私が持ってるVS2005では日本語表記が使えます)。
まあ私はふだん、日本語では書きませんけど、、(^^;

コード:

#include <stdio.h>
 
int カウント = 0;
 
int main(void) {
    for(カウント=0; カウント<10; カウント++) printf("%d\n",カウント);
    return 0;
}
VS2005コマンドラインでコンパイルして実行

コード:

>cl 1.c
Microsoft(R) 32-bit C/C++ Optimizing Compiler Version 14.00.50727.762 for 80x86
Copyright (C) Microsoft Corporation.  All rights reserved.

1.c
Microsoft (R) Incremental Linker Version 8.00.50727.762
Copyright (C) Microsoft Corporation.  All rights reserved.

/out:1.exe
1.obj

>1
0
1
2
3
4
5
6
7
8
9
written by へにっくす

アバター
usao
記事: 1887
登録日時: 11年前

Re: 自作:描画クラスについて

#17

投稿記事 by usao » 10年前

これは完全に私の好みかもしれませんが,
もし私が「画像」をクラスとして作るなら…こんな形になったりするかも.
(おそらくDXライブラリを使われておられるのだと思いますが,私は該ライブラリを知らないので
 実情にそぐわない部分があるかもしれません)

コード:

//※細部は省きます.

class CImg //画像
{
public:
  CImg() : m_hImg(0) {}  //※「無効なハンドルの値」を表す値が0でいいのだとして※
  void SetImgHandle( int hImg ){  m_hImg=hImg;  }

  bool DrawImg( 位置, 透明度=100, 反転するかどうか=false );  //※不透明を表す値が100なのだとして※
  bool DrawImg( 位置, 大きさ, 角度, 透明度=100, 反転するかどうか=false );

  //※画像をファイルからロードする機能をこのクラスに持たせるならば,
  bool LoadImg( const char *FilePathName );
  //のようなメソッドもあるかもしれないが,その場合,
  //SetImgHandle()を用いた使い方もできるようにするのかしないのか,可能とするならば
  //安全に同居するための仕組みが必要

  //その他,画像の縦横サイズなどの情報を参照できるメソッドとかもあるかも.
  int GetImgWidth() const;  //みたいな.
private:
  int m_hImg;
};

//CDrawを継承するのは 画像データを描画に用いる クラス
//このクラスは自身の座標や状態から「どうやって描画すればいいか」を知っている.
class CCharacter : public CDraw
{
public;
  virtual void Draw();  //現在の自身のデータに基づいて,CImgクラスを用いた描画を行う
private:
  //座標等,キャラクタの情報
  座標 m_Pos;
  状態 m_State;
  ...
 //このキャラクタが描画に用いる画像
  CImg m_Img;  //※完全に内部に持って管理してしまうならこう
  CImg *m_pImg;  //※どこかにあるCImgオブジェクトへのポインタだけを知っていればよい,というのであればこうとか.
};
[追記]
これだとCImgの存在意義がかなーり薄い気もしますが,それは置いといて,
今考えている void Draw(); というインタフェースでは,
引数が全くないので描画のための各種情報をどうにかしてDraw()を実装する側が解決せねばらなず,
結果として大量のSetterをつかってあらかじめ情報を知らせておかねばならず,面倒に見えます.
例えばゲーム等であればどこにどう描画すればいいのかを知っているやつが既にいるはずなので,
そいつがDraw()の主体である方が良いのではないかな?という
(画像とか図形という単位なのはDraw()の主体として細かすぎるというか).

ただしアプリケーションによっては画像や図形,文字列等自体が主たるデータとかいうこともあるかもしれません.
その場合はCGraph等のようなものになるのが自然かもしれません.
(PowerPointの劣化品みたいなのを作る場合とか?)

スティアラ

Re: 自作:描画クラスについて

#18

投稿記事 by スティアラ » 10年前

へにっくす様、usao様、有難うございます。
へにっくす さんが書きました: ここだけ反応しますが、別に英語にこだわる必要はありませんよ。凝った英語を使ったって、見る人が分からなければ意味ありませんし。
ローマ表記でもよいですし、極端な話、以下のように日本語で書いたって構わないんです(私が持ってるVS2005では日本語表記が使えます)。
まあ私はふだん、日本語では書きませんけど、、(^^;
面白いですね、日本語でも動作するのは聞いた事もありませんでした。
私も日本語では多分書きませんけど...
難しい単語など、変数名を見てそれが何か分からなければローマ表記にする様にします。
有難うございました(^^)
usao さんが書きました:これは完全に私の好みかもしれませんが,
もし私が「画像」をクラスとして作るなら…こんな形になったりするかも.
(おそらくDXライブラリを使われておられるのだと思いますが,私は該ライブラリを知らないので
 実情にそぐわない部分があるかもしれません)
なるほど...座標などの情報はキャラクター側が持てばよい、ということですね。
しかしこの場合だと本当にCImgの存在意義がなくなりそうです。
DXライブラリではDrawGraph等の描画関数が用意されていますので、
CImgの存在意義としては画像ハンドルを持たせられる...といったところでしょうか?
それとDXライブラリの使用については最初に記載しております。
usao さんが書きました:今考えている void Draw(); というインタフェースでは,
引数が全くないので描画のための各種情報をどうにかしてDraw()を実装する側が解決せねばらなず,
結果として大量のSetterをつかってあらかじめ情報を知らせておかねばならず,面倒に見えます.
引数を持たないのはfor文で回し、全ての描画を一括して行える様にする為です。
(この考え方が駄目なのかもしれませんね...
初期化に関してはコンストラクタに引数を持たせ、
一括して情報を知らせてあげる様にした方がいいですね。
その後、座標を変更する際等はやはりsetterを使わざるえませんが。

キャラクターが描画クラスを継承する事については思いつきませんでした。
少し考えてみます。

アバター
usao
記事: 1887
登録日時: 11年前

Re: 自作:描画クラスについて

#19

投稿記事 by usao » 10年前

>引数を持たないのはfor文で回し、全ての描画を一括して行える様にする為です。
これ自体に問題があるのではなく
そのforで回される対象って実際なんですか?ということですね.
(「描画するものリスト」か何かに登録しておいて,そのリストに対してfor&Draw()されるとしたら,
 リストに登録されるものって何(どういう単位か)という.)
個々の画像 というレベルの粒度(?)でこの仕組みを扱うのが やることに対して適しているかどうか,というか.

>あとは実際にはDraw()を持つべき対象は何なのか
>(画像毎に描画位置などを保持する形が好ましいのかどうか)とかいう話もあるのかもしれませんが,
>それはこのスレッドの話の範囲外でしょうかね.
…という気もするので,それはそれで別の話にした方がいいかもしれませんね.

アバター
usao
記事: 1887
登録日時: 11年前

Re: 自作:描画クラスについて

#20

投稿記事 by usao » 10年前

>DXライブラリではDrawGraph等の描画関数が用意されていますので、
>CImgの存在意義としては画像ハンドルを持たせられる...といったところでしょうか?

No.17のコードの状態だと,
「画像のロード&いらなくなったら捨てる」機能を持たせていれば,まぁ少しはなんかしてる感がありますが,
そうでないなら,実際になんというライブラリ関数を使って描画しているかを隠しているだけですね.
(そもそもハンドルで扱えるところまではライブラリがやってくれているので,そこからさらにやることは少ない.)

こんなこと↓する意味があるかどうかは別として,
例えばこうすれば,CCharacterクラスは自身の描画処理がDXライブラリで行われていることを知らずに済みますね.
(私はこういうことをするのがわりと好きです.)

コード:

//※例によって細部は省略しています
class CImg
{
public:  //描画用メソッドの型だけを規定
  virtual bool DrawImg( 位置, 透明度=100, 反転するかどうか=false ) = 0;  //※不透明を表す値が100なのだとして※
  virtual bool DrawImg( 位置, 大きさ, 角度, 透明度=100, 反転するかどうか=false ) = 0;
};

class CDxLibImg : public CImg
{
  //※No.17でのCImgと一緒.
  //DrawImgをオーバーロードして,中ではDXライブラリの関数を使う
}

//CCharacterはAttach()で指定されたオブジェクトを用いて描画を行う.
class CCharacter : public CDraw
{
public:
  void Attach( CImg *pImg ){  m_pAttachedImg = pImg;  }
  void Detach(){  Attach(NULL);  }
  virtual void Draw(){  m_pAttachedImg->DrawImg()を使う }
private:
  CImg *m_pAttachedImg;
};

スティアラ

Re: 自作:描画クラスについて

#21

投稿記事 by スティアラ » 10年前

usao様、有難うございます。
なるほど、隠蔽する事によって余計な情報を教えなくてよくなりますね。

とりあえず現在はキャラクター側に描画クラスを派生させてみています。
出来次第、またここであげますね。

アバター
usao
記事: 1887
登録日時: 11年前

Re: 自作:描画クラスについて

#22

投稿記事 by usao » 10年前

オフトピック
>出来次第、またここであげますね。
その際,NO.5のように微妙に相手を名指ししたような雰囲気を出してしまうと
他の方からの意見が得られにくくなるような気もしますので,気を付けられた方がよいかも?

スティアラ

Re: 自作:描画クラスについて

#23

投稿記事 by スティアラ » 10年前

こちらの都合で本当に申し訳ないのですが、
親からこの掲示板の利用を禁じられてしまいました...
(自分でよく考えて組んでほしいから、だそうです)

中途半端に質問が終わってしまい、とても気持ちが悪いのですが、
これで質問は終了とさせて頂きます...

usao様、zxc様、涼雅様、へにっくす様、本当に有難う御座いました。

...この場合、解決してはいないけれど、
解決!にチェックを入れた方が良いのでしょうか?

zxc
記事: 79
登録日時: 11年前
住所: 日本の背骨(?)あたり

Re: 自作:描画クラスについて

#24

投稿記事 by zxc » 10年前

  完全に解決しなくとも、どの程度どのような方法で解決できそうなのか、もしくはどの程度解決されたのかを明確にしていただければ、今後第三者がここのやり取りを見て参考にできると思うので、私個人は条件さえ満たせば解決で問題ないかと思います。

ISLe
記事: 2650
登録日時: 13年前
連絡を取る:

Re: 自作:描画クラスについて

#25

投稿記事 by ISLe » 10年前

#もう見てないかもしれませんが。
わたしはプログラミング言語は道具だと思っているので、道具の使い方を自分で考えるというのは無駄なことではないかと思います。

描画関数の引数に対応するメンバ関数が用意されていて、クラスが描画関数そのものですよね。
つまり手続きをクラスにしているので、クラスの設計として良くないです。

コンストラクタで必要なパラメータをすべて渡し、構築されたインスタンスは常にDrawで描画できる状態であるべきです。
メンバ関数(というかメソッド)は、例えば画像クラスなら『画像』というオブジェクトの振る舞いとして相応しいものを定義しましょう。
moveやmoveToで表示座標を移動するとか、turnLRで反転フラグがオン・オフするとか。

閉鎖

“C言語何でも質問掲示板” へ戻る