ドーナツ型の円を複数描きたい

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

ドーナツ型の円を複数描きたい

#1

投稿記事 by タンタル » 8年前

いつもお世話になっております。
今回お聞きしたいことは、中抜きの円(ドーナツの形)を複数描く方法です。

現状それっぽいものができましたが、まだまだ問題点が多いです。
それっぽいものは以下のソースコードです。

コード:

FieldManagerEX::FieldManagerEX(){
	SetDrawValidAlphaChannelGraphCreateFlag(TRUE);
	this->graph = MakeScreen(GAME_WINDOW_WIDTH + GAME_WINDOW_OFFSET_X, GAME_WINDOW_HEIGHT + GAME_WINDOW_OFFSET_Y, TRUE);
	SetDrawValidAlphaChannelGraphCreateFlag(FALSE);
}

void FieldManagerEX::draw(){
	SetDrawScreen(this->graph);//円を描くバッファ
	ClearDrawScreen();
	for (list<FieldEX*>::iterator it = this->field.begin(); it != this->field.end(); ++it){
		SetDrawBlendMode(DX_BLENDGRAPHTYPE_ALPHA, 100);//ドーナツの外側部分を塗りつぶす
		DrawCircle((*it)->getPosition().x + GAME_WINDOW_OFFSET_X, (*it)->getPosition().y + GAME_WINDOW_OFFSET_Y, (*it)->getHeadR(), GetColor(255, 0, 0);
		SetDrawBlendMode(DX_BLENDGRAPHTYPE_NORMAL,0);//内側部分を黒で上書き
		DrawCircle((*it)->getPosition().x + GAME_WINDOW_OFFSET_X, (*it)->getPosition().y + GAME_WINDOW_OFFSET_Y, (*it)->getTailR(), GetColor(0, 0, 0));

		SetDrawScreen(DX_SCREEN_BACK);//ゲームプレイ用のバッファへコピー
		SetDrawBlendMode(DX_BLENDGRAPHTYPE_ALPHA, 100);
		DrawGraph(0, 0, this->graph, TRUE);
	}
}
問題点(要望)
1・黒を透過色にしたい。(現在の状態ですと、外側円の外側、内側円の内側は黒で塗りつぶすのですが、その黒色をゲームプレイ用のバッファにまでもってきてしまう。)
  試しにmain関数で背景を白く塗りつぶすように設定したら、結果はドーナツを描くときだけ背景が真っ黒になりました。それ以外では白になりました。
2・ドーナツが重なる個所では、後で書いた方のドーナツ(上に書いたドーナツ)がその内側円を塗りつぶしてしまうため、先に書いたドーナツ(下のドーナツ)が欠けてしまう。
  つまり、先に書いたドーナツが"○"から"C"のようになってしまう。"C"の欠けた部分が、別のドーナツによって黒く上書きされているという状態です。

アルファチャンネル自体は有効のようで、赤いドーナツが薄い色になって描画されます。この点は維持しつつ上記の問題点を解決したいです。


個人的に考えた解決方法は、
for(ドーナツの個数分){
・円バッファをクリア。
・円バッファにドーナツを一つ書く。
・ゲームプレイ用バッファにコピー。
}
ですが、1の問題があるため、結局画面全体が黒く塗りつぶされてしまうため、意味がありませんでした。
別の方法として、ドーナツ円の書かれた画像を使ってしまうという手も考えましたが、内側円と外側円の半径は独立しているため、画像戦法も難しいかなと思います。(単純な拡大縮小では対応できない。)
外側円を塗りつぶした画像と、内側円を塗りつぶした画像を用意して、マスク処理でドーナツにしてしまうという方法もあるとは思うのですが、処理が重いからおすすめしないという記述が多く困っております。

問題ではありませんが、挙動がおかしい部分があります。
DrawGraph(0, 0, this->graph, TRUE);の個所について、座標を(0,0)にしようが、(1000,1000)にしようが円の書かれる場所が変わりません。
考えられる理由がありましたら、教えていただけると幸いです。

注文が多く申し訳ありませんが、皆様のアイデアをいただけると幸いです。
どうかよろしくお願いします。

Rittai_3D
記事: 525
登録日時: 11年前

Re: ドーナツ型の円を複数描きたい

#2

投稿記事 by Rittai_3D » 8年前

DxLib::DrawCircleGauge()を使ってみてはどうでしょうか。

参考になれば→http://ktstg.blog.shinobi.jp/Entry/826/
リンク先では中抜きではないですが、中心が透過してある画像を用いればできるかと思います。

※実験していませんし、もしかしたら、やりたいことを履き違えているかもしれません。もしそうならすいません。
初心者です

アバター
みけCAT
記事: 6734
登録日時: 13年前
住所: 千葉県
連絡を取る:

Re: ドーナツ型の円を複数描きたい

#3

投稿記事 by みけCAT » 8年前

タンタル さんが書きました:問題点(要望)
1・黒を透過色にしたい。(現在の状態ですと、外側円の外側、内側円の内側は黒で塗りつぶすのですが、その黒色をゲームプレイ用のバッファにまでもってきてしまう。)
  試しにmain関数で背景を白く塗りつぶすように設定したら、結果はドーナツを描くときだけ背景が真っ黒になりました。それ以外では白になりました。
2・ドーナツが重なる個所では、後で書いた方のドーナツ(上に書いたドーナツ)がその内側円を塗りつぶしてしまうため、先に書いたドーナツ(下のドーナツ)が欠けてしまう。
  つまり、先に書いたドーナツが"○"から"C"のようになってしまう。"C"の欠けた部分が、別のドーナツによって黒く上書きされているという状態です。
最初の1回しか

コード:

SetDrawScreen(this->graph);//円を描くバッファ
ClearDrawScreen();
を呼び出していないからではないでしょうか?
(実験していません。予想です。)
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

アバター
みけCAT
記事: 6734
登録日時: 13年前
住所: 千葉県
連絡を取る:

Re: ドーナツ型の円を複数描きたい

#4

投稿記事 by みけCAT » 8年前

タンタル さんが書きました:問題ではありませんが、挙動がおかしい部分があります。
DrawGraph(0, 0, this->graph, TRUE);の個所について、座標を(0,0)にしようが、(1000,1000)にしようが円の書かれる場所が変わりません。
考えられる理由がありましたら、教えていただけると幸いです。
円(ドーナツ)を1個だけにしても場所が変わらないのでしょうか?
もし1個だけにすると変わるようになるのであれば、No: 3と同じ理由である気がします。
2個目以降の円(ドーナツ)はDX_SCREEN_BACKに直接描かれるため、DrawGraph(0, 0, this->graph, TRUE);の座標を変えても影響しないと思います。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

タンタル

Re: ドーナツ型の円を複数描きたい

#5

投稿記事 by タンタル » 8年前

Rittai_3Dさん、みけCATさん
ご返信ありがとうございます。

Rittai_3Dさん
申し訳ありませんが、私がやりたいこととは用途が異なっているかもしれないですね。
ドーナツを欠けさせたい(円形のゲージなど)わけではなく、ドーナツの厚み(?)を変化させたいので、一枚絵の単純な拡大縮小では表現が難しそうです。

みけCATさん
とりあえず、その二行をfor文の中に入れて実行しました。

コード:

FieldManagerEX::FieldManagerEX(){
    SetDrawValidAlphaChannelGraphCreateFlag(TRUE);
    this->graph = MakeScreen(GAME_WINDOW_WIDTH + GAME_WINDOW_OFFSET_X, GAME_WINDOW_HEIGHT + GAME_WINDOW_OFFSET_Y, TRUE);
    SetDrawValidAlphaChannelGraphCreateFlag(FALSE);
}
 
void FieldManagerEX::draw(){
    for (list<FieldEX*>::iterator it = this->field.begin(); it != this->field.end(); ++it){
        SetDrawScreen(this->graph);//円を描くバッファ
        ClearDrawScreen();
        SetDrawBlendMode(DX_BLENDGRAPHTYPE_ALPHA, 100);//ドーナツの外側部分を塗りつぶす
        DrawCircle((*it)->getPosition().x + GAME_WINDOW_OFFSET_X, (*it)->getPosition().y + GAME_WINDOW_OFFSET_Y, (*it)->getHeadR(), GetColor(255, 0, 0);
        SetDrawBlendMode(DX_BLENDGRAPHTYPE_NORMAL,0);//内側部分を黒で上書き
        DrawCircle((*it)->getPosition().x + GAME_WINDOW_OFFSET_X, (*it)->getPosition().y + GAME_WINDOW_OFFSET_Y, (*it)->getTailR(), GetColor(0, 0, 0));
 
        SetDrawScreen(DX_SCREEN_BACK);//ゲームプレイ用のバッファへコピー
        SetDrawBlendMode(DX_BLENDGRAPHTYPE_ALPHA, 100);
        DrawGraph(0, 0, this->graph, TRUE);
    }
}
こうしますと、1の問題の関係でか、最後のドーナツ以外が最後のドーナツを描くときの黒塗りつぶしによって消滅してしまいます。
問題点を2点あげましたが、よくよく考えてみますと実質解決しなければならない問題は一つで、
・MakeScreenで作ったバッファ上のデータを、どのように黒だけ透過色にしたうえでコピーしてくるか
なのかもしれないです。
MakeScreenで作ったバッファからは、透明色を指定したうえでコピーすることはできないのでしょうか。
できないのであれば、ドーナツを描く時点で、透明色で上書き塗りつぶし、といったことができたら助かるのですが...
こちらはライブラリの作者に聞くべきでしょうか。

もう一点の件につきましては、ドーナツを一つにしても変化はありませんでした。
強制的に(0,0)に書かれてしまっている感じがします。

アバター
みけCAT
記事: 6734
登録日時: 13年前
住所: 千葉県
連絡を取る:

Re: ドーナツ型の円を複数描きたい

#6

投稿記事 by みけCAT » 8年前

タンタル さんが書きました:問題点を2点あげましたが、よくよく考えてみますと実質解決しなければならない問題は一つで、
・MakeScreenで作ったバッファ上のデータを、どのように黒だけ透過色にしたうえでコピーしてくるか
なのかもしれないです。
実験はしていませんが、MakeScreenの第三引数をFALSE (アルファチャンネルをつけない) にしてみてください。
うまく行けば黒(#000000)を透過色として認識するようになるかもしれません。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

タンタル

Re: ドーナツ型の円を複数描きたい

#7

投稿記事 by タンタル » 8年前

みけCATさん、ご返信ありがとうございます。
結論から申し上げますと、うまくいきませんでした。

SetDrawValidAlphaChannelGraphCreateFlagをいじったり、SetDrawBlendModeを変更したり、SetTransColorを使用したりしましたが、どれもうまくいきませんでした。
なにか見落としをしているのでしょうか...


余談ですが、いろいろ調べていく中で、
makescreenの透過
http://dixq.net/forum/viewtopic.php?f=3&t=14328
というトピックを見つけました。
状況が似ているような気がするので使わせていただきたかったのですが、結局どうすればよいのかよくわかりませんでした。

SetDrawBlendMode(DX_BLENDGRAPHTYPE_NORMAL,0);//内側部分を黒で上書き
DrawCircle((*it)->getPosition().x + GAME_WINDOW_OFFSET_X, (*it)->getPosition().y + GAME_WINDOW_OFFSET_Y, (*it)->getTailR(), GetColor(0, 0, 0));

SetDrawBlendMode(DX_BLENDMODE_SUB,0);//内側部分を黒で上書き
DrawCircle((*it)->getPosition().x + GAME_WINDOW_OFFSET_X, (*it)->getPosition().y + GAME_WINDOW_OFFSET_Y, (*it)->getTailR(), GetColor(0, 0, 0));
にするという意味ではなかったのでしょうか。

閉鎖

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