ページ 11

パネポンの様な消える処理について

Posted: 2010年4月13日(火) 05:12
by 猫旅
http://www.play21.jp/board/formz.cgi?ac ... &rln=50511
で質問させて頂いた猫旅です。

現在パズルゲームを作っております。

選択した部分と周囲の3×3マスが反転し
3×3マスが同じパネルだったら消えるという処理までは実装できました。

パネルが消えた時に上にあるパネルが落ちる処理をしたいのですが
どの様に処理すればよいのかが見当がつきません・・・。

どうかご教授願えないでしょうか?

又、マップの出現でもう一つ下の配列を指定したいのですが
修正後にしてしまうと同じパネルしか出なくなり
2個ずれてしまいます。(配列が壊れてしまっている?)

修正前
// マップの出現
void PLAYER::MapBorn(){
for(int j=0; j<CEL_W; j++){
if(Map[CEL_H-2][j] == 0 && j != 0 && j != CEL_W-1) Map[CEL_H-2][j] = rand()%2+1;
}
}

修正後
// マップの出現
void PLAYER::MapBorn(){
for(int j=0; j<CEL_W; j++){
if(Map[CEL_H-1][j] == 0 && j != 0 && j != CEL_W-1) Map[CEL_H-1][j] = rand()%2+1;
}
}

Re:パネポンの様な消える処理について

Posted: 2010年4月13日(火) 08:10
by やっくん
>パネルが消えた時に上にあるパネルが落ちる処理をしたいのですが
パネルを入れ替えたときに下が空白なら落ちるようにしてますよね?
それと同じような処理で大丈夫かと思います。

>又、マップの出現でもう一つ下の配列を指定したいのですが
マップの出現とはプレイ中に下から新たに出てくるブロックを指すのでしょうか?
2個ズレるとは具体的にどこがどのようにズレるかわからないので、できれば詳しく教えてもらえませんか?

Re:パネポンの様な消える処理について

Posted: 2010年4月13日(火) 10:27
by バグ
以前作ったパズルゲームのずらし処理用の関数を載せます。
// フィールドの幅と高
#define Field_Width    10
#define Field_Height    20

// フィールド管理用の配列変数(0を空白とする)
int map[Field_Width][Field_Height];

// 1箇所でも動いたマスがあった場合はtrueを、そうでない場合はfalseを返す
bool drop_down(void)
{
    // 検査結果の格納用フラグ
    bool res = false;

    for (int x = 0; x < Field_Width; ++x)
    {
        for (int y = Field_Height - 1; y >= 1; --y)
        {
            // 現在検査中の位置が空白で、1つ上が空白ではない場合
            if (map[x][y] == 0 && map[x][y - 1] != 0)
            {
                // 検査中のマスを、1つ上のマスの情報で上書きする
                map[x][y] = map[x][y - 1];

                // 1つ上のマスは空白にする
                map[x][y - 1] = 0;

                // 動いた箇所があったので、検査結果フラグをtrueにする
                res = true;
            }
        }
    }

    return res;
}

Re:パネポンの様な消える処理について

Posted: 2010年4月13日(火) 13:01
by ookami
落ちる処理:
元のソースが分からないので全くの想像です。参考までに。
for(int y=0; y<CEL_H-1;y++){
for(int x=0; x<CEL_W ;x++){
if(Map[x][y]==0) swap(Map[x][y],Map[x][y+1]);
}}

Re:パネポンの様な消える処理について

Posted: 2010年4月13日(火) 14:07
by 猫旅
皆様、回答ありがとうございます。
本当に助かります。

>>やっくん様
その処理がわからない為質問させて頂きました。
説明が下手で申し訳ありません・・・。
又、ずれるのは添付した画像の様になってしまいます。

>>バグ様
為になるソースをありがとうございます。
ソースを見させていただいたのですが
判定は出来ますが落ちるような処理は出来なくないでしょうか?
パッと切り替わるのではなく落下するような処理にしたいです。

>>ookami様
そのような発想はありませんでした。
ありがとうございます。
ただやはり落下するように見せることが出来ない気がします。

やはりこのソースでは落下の様に見せることは出来ないのでしょうか?

Re:パネポンの様な消える処理について

Posted: 2010年4月13日(火) 14:56
by バグ
>>為になるソースをありがとうございます。
>>ソースを見させていただいたのですが
>>判定は出来ますが落ちるような処理は出来なくないでしょうか?
>>パッと切り替わるのではなく落下するような処理にしたいです。

よく読んでください。判定&1段だけ落とす処理を行っていますよ?(^_^;)
落ちているように見せたいならば、呼び出し元で下記のように記述すればOKです。
while (drop_down() == true)
{
    /* グラフィック描画とかWaitとか… */
}

Re:パネポンの様な消える処理について

Posted: 2010年4月13日(火) 16:14
by ookami
落下途中の描画が必要なんですね。想像ですいませんが以下。

struct fallingBlock {
int celX,celY,dy,type;
};

vector<fallingBlock> fallingBlockList;

---

for(int y=1; y<CEL_H;y++){
for(int x=0; x<CEL_W;x++){
if( Map[x][y]!=0 && Map[x][y-1]==0) { // 下が空白なら fallingBlockList に登録
fallingBlockList.push_back();
fallingBlock &fb=fallingBlockList[fallingBlockList.size()-1];
fb.celX=x;
fb.celY=y;
fb.dy=0;
fb.type=Map[x][y];
Map[x][y]=0;
}
}}

---

for(i=0;i<fallingBlockList.size();i++) {
fallingBlock &fb=fallingBlock;
fb.dy+=4;
if(fb.dy<32) {
draw(...);
} else {
Map[fb.celX][fb.celY-1]=fb.type;
fallingBlock.erase(i);
i--;
}
}
画像

Re:パネポンの様な消える処理について

Posted: 2010年4月13日(火) 19:50
by 猫旅
何度もご回答ありがとうございます。

>>バグ様
落下するような処理にしたいのですが
drop_down() == trueと書いてどの様に落下させるのでしょうか?
どこのパネルの座標をどのように弄ればよいのかがわかりません・・・。
考えてみたのですが本当にわからないんです・・・。


>>ookami様
ソースを試したのですが
struct fallingBlock {
int celX,celY,dy,type;
};

vector<fallingBlock> fallingBlockList;
と書くとエラーが帰ってきてしまいます。

使っているライブラリはDXライブラリなのですが
vector<fallingBlock>のような書き方はどう意味なのでしょうか・・・。
無知で申し訳ないです。

1>.\game_scene.cpp(231) : error C2143: 構文エラー : ';' が '<' の前にありません。
1>.\game_scene.cpp(231) : error C4430: 型指定子がありません - int と仮定しました。メモ: C++ は int を既定値としてサポートしていません

Re:パネポンの様な消える処理について

Posted: 2010年4月13日(火) 20:21
by バグ
>>落下するような処理にしたいのですが
>>drop_down() == trueと書いてどの様に落下させるのでしょうか?
>>どこのパネルの座標をどのように弄ればよいのかがわかりません・・・。
>>考えてみたのですが本当にわからないんです・・・。

ひょっとして、私が記述したものをそのまま使っています?
あれは、以前私が作ったゲーム用の関数なので、猫旅さんのゲーム用に書き換えないと駄目ですよ?

もし、そうでないと仮定して、順番に説明しますね。

drop_down関数はブロックを並び替えて、消去された箇所があった場合に消去処理を行った後に呼び出す関数です。処理内容は、空白の1つ上のマスにブロックが存在する場合に1段落下させ、フィールド上のどこかで落下移動があった場合にtrueを返すというものです。


1:パネルを入れ替えた

2:入れ替えた結果を描画する

3:入れ替えたことによって消える箇所はあるか?無い場合は1に戻る

4:パネルを消去する

5:消去された状態を描画する

6:落下するパネルはあるか?(※ここでdrop_down関数を呼ぶ)無い場合は2へ戻る(連鎖処理の為)

7:落下した状態を描画して6へ戻る


大まかな流れはこんな感じです。これを自分のゲームで動くようにプログラムを書いていけばいいと思いますよ。

Re:パネポンの様な消える処理について

Posted: 2010年4月13日(火) 21:09
by ookami
すいません、説明不足でした;; そのままコピペではたぶん動かないと思います。(#include<vector> して using namespace std; すればとりあえず進むかもしれませんが...)

>>50538 について補足します。とりあえず考え方だけ...
・下が空白のブロックがあったらMap配列からfallingBlockListへ移す。
・fallingBlockListにあるブロックは、毎フレームごとに 4 ピクセルずつ落下させる。
・(ブロックの大きさが32ピクセルだとして、)32ピクセルに達したら、fallingBlockListからMap配列へ戻す。

(補足)
vectorは...そうですね、可変長の配列と思っていただければ。コンパイラによっては使えないかも。
http://www.kumei.ne.jp/c_lang/cpp/cpp_64.htm

Re:パネポンの様な消える処理について

Posted: 2010年4月13日(火) 21:51
by 猫旅
皆様、本当に回答ありがとうございます。

>>バグ様
その6~7がわからないんです・・・。

6についてはどこのセルのパネルが消えたかの判定がわかりません。
提示して頂いたソースを改編するにもどの様に弄ればよいのかがわかりません。
※ソースについては完全に理解しております。

7については落下した状態を描画したいのですが
これが本当にわかりません・・・。

>>ookami様
ご丁寧にありがとうございます。
私のわからないことが出てきましたので少しソースを解析させて下さい。

Re:パネポンの様な消える処理について

Posted: 2010年4月13日(火) 22:22
by やっくん
横からすみません。
バグさんの6、7について私なりに述べさせてもらいます。

まず、どのようなときにパネルが落ちる処理が必要かという点に着目すると
・パネルを入れ替えたときに下が空白である場合
・パネルを入れ替え&パネルのせり上げによってパネルが3個揃って消滅する場合
大体この2通りかと思います。

なのでバグさんが書かれたソースのdrop_down関数を
・パネルを入れ替えた後。
・パネルが消滅した後。
この2つの処理の後に挟みこめばいいのではないでしょうか?

drop_down関数の後は描画処理を当然しますが、drop_down関数では配列を1度しか走査してないので落ちるブロックは1マス分しか落ちてません。
つまり、2マス以上落ちなきゃ行けないブロックはまだ1マスしか落ちて無いので完全に落ちきって無い状況です。
なので、全てのブロックが落ちないという状況(戻値がfalse)になるまでdrop_down関数をループさせれば良いかと思います。

Re:パネポンの様な消える処理について

Posted: 2010年4月13日(火) 22:32
by 猫旅
皆様、回答ありがとうございます。

私の説明が下手なせいで理解できにくくて申し訳ないです。

drop_down関数については本当に理解しております。
添付させて頂いた画像の様にパネルは一つではないんです。

提示頂いたdrop_down関数を使ってもどこのマップ座標を弄ればよいのか?
y座標をどの様にいじればよいのかがわからないのです。

現在、描画は下記の様に行っております。
//  マップの表示
    for(int i=0; i<CEL_H; i++){
        for(int j=0; j<CEL_W; j++){
            if(Play01.Map[j] == 1) DrawCenter( j*32+16, i*32+24-(int)Play01.UpCount , Handle.Paz01 , 0xff ) ;
            if(Play01.Map[j] == 2) DrawCenter( j*32+16, i*32+24-(int)Play01.UpCount , Handle.Paz02 , 0xff ) ;
        }    
    }

Re:パネポンの様な消える処理について

Posted: 2010年4月13日(火) 23:13
by やっくん
drop_down関数では配列の中身を弄っているのでマップの座標を弄る必要は無いと思います。

例えば、猫旅さんのソースコードで言うならば
Play01.Map[0][0] = 1 だったのを Play01.Map[0][0] = 2
に変えたりする処理をdrop_down関数では行っています。

パネルが目では移動しているように見えてもパネルの座標が変わったのでは無く、配列の中身が変わっただけではないでしょうか?
パネルの移動は描画処理であたかもパネルの座標が変わっているように見せかけてるだけだと思います。

間違っていたらすみません(´д・;

Re:パネポンの様な消える処理について

Posted: 2010年4月13日(火) 23:15
by やっくん
↑細かいですが訂正です。
 → で

Re:パネポンの様な消える処理について

Posted: 2010年4月13日(火) 23:53
by 猫旅
本当に何度も解凍して頂いて申し訳ないと思っております。
私が質問させて頂いているのはどのようにして落ちるように見せているのかということです・・・。

例えばなのですがパネルが32×32だとします。
これを下に何もなければ1フレームで4ドット落ちる処理をしたいんです。
drop_down関数はあくまで配列の値を変化させるだけで落ちるというより交換しているだけですよね?
それをdrop_down関数の戻り値を使って描画で行うということなのですが
どの様に行えばよいのかが見当がつかないと質問させて頂いているのです・・・。

>>例えば、猫旅さんのソースコードで言うならば
>>Play01.Map[0][0] = 1 だったのを Play01.Map[0][0] = 2
>>に変えたりする処理をdrop_down関数では行っています。
こんな処理はしていないですよね?
あくまでも配列の下が0なら上の値を落とす処理だけですよね?

>>パネルの移動は描画処理であたかもパネルの座標が変わっているように見せかけてるだけだと思います。
それは理解していると何度も申しております・・・。
座標が変わっているような処理がわからないと申しているのです。

例えば描画の時に
i*32+24-(int)Play01.UpCount
の値が変えなければなりませんよね?

でもdrop_down関数では何処が落ちるのか・・・。
又、1フレーム(処理が一瞬ですので)しか落ちませんよね?

>>パネルの移動は描画処理であたかもパネルの座標が変わっているように見せかけてるだけだと思います。
何度もお尋ねさせて頂いているのですがここがわからないのです・・・。

失礼な言い方でしたら本当に申し訳ないです・・・。
ただ本当にわからないので皆様にご教授いただきたいのです。

Re:パネポンの様な消える処理について

Posted: 2010年4月13日(火) 23:53
by conio
あぁー・・・Y座標に関しては構造体に入れてしまったほうが良さそうですね。
※ただし、クライアント座標ではなく、 「i*32からどれだけズレているか?」の値。


----------------------------------------------------------------------
struct PANEL{
int PanelType; //パネルの種類
int DifY; //Y座標の差分
};

PANEL Play01.Map[CEL_H][CEL_W];

// マップの表示
for(int i=0; i<CEL_H; i++){
for(int j=0; j<CEL_W; j++){
if(Play01.Map[j] == 1) DrawCenter( j*32+16, i*32+24-Play01Map[j].DifY , Handle.Paz01 , 0xff ) ;
if(Play01.Map[j] == 2) DrawCenter( j*32+16, i*32+24-Play01Map[j].DifY, Handle.Paz02 , 0xff ) ;
}
}
----------------------------------------------------------------------

この場合、例えばパネルが1段下がった時は、
(Play01.Map[0][2] → Play01.Map[1][2])

下がる前のDifYを0に戻し、2次元配列の値を書き換える必要があります。
-----------------------------------------------------------------
【1】Play01.Map[0][2].DifY = 0; //差分を元に戻す
【2】Play01.Map[1][2].PanelType = Play01.Map[0][2].PanelType; //落ちる前の位置のパネル情報を、落ちた先の配列に入れる
【3】Play01.Map[0][2].PanelType = 0; //落ちる前の配列の値を空白にする
-----------------------------------------------------------------
※下がった後のパネルの上(Play01.Map[0][2])は空白、空白はPanelType == 0とする。


これなら、どれか1つだけ下げたい場合は
----------------------------
Play01.Map[0][2].DifY -= 1;
----------------------------
みたいにすればよいですし、

全体を上昇させたい場合は、
----------------------------------------
for(int i=0; i<CEL_H; i++){
for(int j=0; j<CEL_W; j++){
Play01Map[j].DifY += 1;
}
}
----------------------------------------
とすれば良いと思います。



画像

Re:パネポンの様な消える処理について

Posted: 2010年4月14日(水) 00:04
by やっくん
ごめんなさい(^^;
私の理解力不足のようでした。
ようやく今、理解できました。

>>>例えば、猫旅さんのソースコードで言うならば
>>>Play01.Map[0][0] = 1 だったのを Play01.Map[0][0] = 2
>>>に変えたりする処理をdrop_down関数では行っています。
>こんな処理はしていないですよね?
>あくまでも配列の下が0なら上の値を落とす処理だけですよね?
こちらも謝ります。
仰るとおりで配列の中身を変えてると言いたかっただけです。

Re:パネポンの様な消える処理について

Posted: 2010年4月14日(水) 02:27
by 猫旅
本当にありがとうございます。
皆様のお陰で落ちるという動作は出来ました。
但し問題がありまして起動時に必ず落下します。

>>conio様
その方法を実装させて頂きました。
ありがとうございます。

>>やっくん様
こちらこそ強くいってしまい申し訳御座いません。
折角答えて頂いていたのに・・・。
本当に申し訳ないです。

やっくん様の理解力不足ではなく私の質問が理解しにくい文章すぎるのだと思います。

Re:パネポンの様な消える処理について

Posted: 2010年4月14日(水) 02:27
by 猫旅
画像を添付させて頂きます。

Re:パネポンの様な消える処理について

Posted: 2010年4月14日(水) 08:03
by バグ
あぁ、なるほど!
ようやく、質問の意図を理解できました(^_^;)
私だったら、パネルをクラス(もしくは構造体)化しますね。色、消去フラグ、フィールド座標(X、Y)、描画用オフセット座標(X、Y)…このくらいのデータをメンバで持っていれば大丈夫かな?
まず、消去箇所のチェックだけを行う関数を作り、その関数内で消去箇所の消去フラグをtrueにします。
それから、オフセット座標を少し下へずらして描画を繰り返し、1マス分動いたら、オフセット座標をクリアして、次のステップへ…といった感じかな?
この方法なら、消去時のエフェクトを掛けたい場合も管理が楽にできると思います。

Re:パネポンの様な消える処理について

Posted: 2010年4月14日(水) 08:10
by バグ
うわ、トンチンカンな書き込みをしてしまいましたm(_ _)m

前の書き込みで書いた『消去箇所』というのは『落下箇所』の誤りで、『消去フラグ』というのも『落下フラグ』の誤りです。

Re:パネポンの様な消える処理について

Posted: 2010年4月14日(水) 17:30
by 猫旅
回答ありがとうございます。
最初のソースを見て頂ければおわかりになるかと思うのですが
// パズル
/*
class PAZZULE{
    public:
        bool Flg;
        float Px,Py;    // 位置座標
        float Mx,My;    // 移動速度
        int Cx,Cy;        // セル
        int Status;        // 状態
};

PAZZULE Pazzule01[OBJ_MAX];
*/
そのように書いておりました。
配列にデータをもたないと消去が出来ないのでは?と思い
(実際に質問させて頂きましたが)
配列に変更した次第で御座います。

やはり配列では出来ないのでしょうか?
他の関数(添付したソース以外に)も配列用に作ってしまってあるので
修正が正直しんどいです・・・。
その為、このままで行おうかと思います。


添付させて頂いた画像ではパネルの隙間があいておりますが
起動した時のみそれぞれのパネルが32ドット落ちるだけで
落ち終わったら隙間もなくなります。
この原因を知りたいのですが何故なのでしょうか?

Re:パネポンの様な消える処理について

Posted: 2010年4月14日(水) 19:26
by バグ
構造体の配列でいいのでは?

Re:パネポンの様な消える処理について

Posted: 2010年4月15日(木) 06:40
by 猫旅
構造体を使うように修正しました。
但し反転処理が上手く出来ません。

パズルにはそれぞれ1~ナンバーがあり毎フレームそのナンバーを二次元配列に格納しております。
 ※この二次元配列なのですが反転処理縦横+2ずつ大きめにサイズを取ってあります。

そのナンバーを使って毎フレーム色々な処理をするような仕様に変更しました。


{0, 1,2,3, 4,5,6, 0},
{0, 7,8,9, 10,11,12, 0},

反転処理は選んだマスと周囲の3×3マスのナンバーの配列の
パターンが1なら2に2なら1に変更という処理にしようとしております。

しかし変な位置のマスが反転されてしまいます。
色々な部分を弄ってみたのですがやはり上手くいきません・・・。

どうかご教授願えないでしょうか?

Re:パネポンの様な消える処理について

Posted: 2010年4月15日(木) 13:53
by たいちう
傍観していましたが、パズル好きの私としては看過できない点がありすので、
指摘させていただきます。

× : PAZZULE
○ : PUZZLE

以上が看過できない点です。
以下は単なるアドバイスですので、無視してくれても結構です。

難航しているようですが、もっと仕様を簡単にして試しましょうよ。

・パネルは1つのみ。初期表示はこのパネルが宙に浮いている状態。
・パネルをクリックすると落下開始。
・底まで落ちたら止まる。以後は変化なし。

もしもクリック検出の処理が難しければ、起動後1秒経過したら
落下開始という仕様でもよい。
空中で静止 → 落下 → 底で静止 となれば結構です。

Re:パネポンの様な消える処理について

Posted: 2010年4月15日(木) 20:02
by 猫旅
>>たいちう様

落下のみの実装は出来ております。
しかし構造体でデータを持つようにしたため
反転処理がうまくいかないんです・・・。

選択した周囲9マスが反転するようにしたいのですが
現在のソースでは変な所が反転してしまいます。

Re:パネポンの様な消える処理について

Posted: 2010年4月15日(木) 20:42
by conio
上手く把握できてないかもしれませんが、
「カーソルを中心とした3×3の領域を反転させる」というのは
下記の様な感じで良いのではないでしょうか?
----------------------------------------------
for(int i = Cursol.Cy - 1; i < Cursol.Cy+2; i++){
for(int j = Cursol.Cx - 1; j < Cursol.Cx+2; j++){
if(Map[j] == 1) {
Map[j] = 2;
}else{
Map[j] = 1;
}
}
}
----------------------------------------------

Re:パネポンの様な消える処理について

Posted: 2010年4月15日(木) 20:49
by 猫旅
conio様

回答ありがとうございます。
最初はそれと似たような方法で実装しておりました・・・。
構造体を使わずに二次元配列のみでの反転は成功しております。

しかしパネルのデータを構造体で持った方が良いというアドバイスを頂いたので
そちらの方法でコーディングを組み直してしまいました。

Re:パネポンの様な消える処理について

Posted: 2010年4月15日(木) 21:21
by conio
------------------------------------------------------------------------------
・パネルの構造体を定義し、 その構造体の2次元配列を作る。
・カーソルの構造体を定義する。
・パネルの構造体と、カーソルの構造体をメンバに持つ PLAYER構造体を定義する。
------------------------------------------------------------------------------

大体 こんな感じで宜しいのでしょうか? (No:50674 から推測)
プレイヤーごとにPanel、Cursorの必要な情報を持つ、みたいな感じです。


で、おおまかなソースコードはこんな感じにしてはどうでしょう。
※何か意図を取り違えてたら指摘してください。
---------------------------------------------------------------
#define MAP_W 6
#define MAP_H 12

/*パネルの構造体*/
struct PANEL {
int type; //パネルの種類
int DifX; //差分X
int DifY; //差分Y
};

/*カーソルの構造体*/
struct CURSOR{
int Cx; //x座標
int Cy; //y座標
int Graphic; //カーソルの画像
};

/*プレイヤーの構造体*/
struct PLAYER{
PANEL Map[MAP_H][MAP_W];
CURSOR Cursor;
};

PLAYER player;

void Init(void){
//省略
}

/*PLAYER型を参照渡しで渡す。そしてメンバに持つMapを反転させる。*/
void Reverse(PLAYER& pr){
for(int i = pr.Cursor.Cy - 1; i < pr.Cursor.Cy+2; i++){
for(int j = pr.Cursor.Cx - 1; j < pr.Cursor.Cx+2; j++){
if(pr.Map[j].type == 1) {
pr.Map[j].type = 2;
}else{
pr.Map[j].type = 1;
}
}
}
}

//呼び方: Reverse(player); で呼ぶ。
---------------------------------------------------------------

【追記】
見ての通りコンパイルできる状態ではないので、誤字・脱字があるかもしれません。 画像

Re:パネポンの様な消える処理について

Posted: 2010年4月16日(金) 05:40
by 猫旅
申し訳ありません。
解決しておりませんが締めさせて頂きます。
回答して下さった方々ありがとうございます。