「さめがめ」の落ちるアニメーション処理について

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

「さめがめ」の落ちるアニメーション処理について

#1

投稿記事 by ツナマヨ » 7年前

パズルゲーム制作を独学で勉強しており、「さめがめ」もどきを作っております。

「さめがめ」とはご存知の方が多いかと思いますが、
選択したパネルの周囲に同じ色があった場合のみ消せるパズルゲームです。
1つずつでは消せません。

消した際に自分の下にパネルがなければ落下し、左の列が空いていたら詰めます。
参考サイトを元にコーディングをしてみたのですが、アニメーションの部分で詰まってしまいました。
(現在、参考サイトを見ながら落下アニメーション以外の実装は出来ました。)

アニメーションは落下しているのを表現したく、縦が優先、縦で落ちれなくなったら横をつめるみたいな感じで実装したいです。
現在の物だと直接配列の値を変えてしまっているので、もしかすると大々的な改修が必要かもしれません。

開発環境はMac、Xcodeです。
少し変わっておりましてWindowsの環境が御座いません。
その為、OpenGLを使って実装しております。

参考サイト http://www40.atwiki.jp/spellbound/pages/1066.html

ソースが見づらくて恐縮なのですが、添付させて頂きます。
修正のアドバイスを頂けないでしょうか。

コード:

----------------------------------------------------------------------

// パネルタッチ用
class MENU{
public:
	int Px, Py;
    int Width, Height;
	float SizeX, SizeY;
	bool TouchCheck( void );
	void Init( int Px, int Py, int width, int height, float Sx, float Sy );
};

bool MENU::TouchCheck( void ){
	
    int x = System.touchPos.x;
    int y = System.touchPos.y;
    
	int sx = ( this->Width * this->SizeX) / 2;
	int sy = ( this->Height * this->SizeY) / 2;
	
	if(x < this->Px+sx && x > this->Px-sx &&
	   y < this->Py+sy && y > this->Py-sy ){
		return true;
	}else{
		return false;
	}
	
}

void MENU::Init( int Px, int Py, int width, int height, float Sx, float Sy ){
	this->Px = Px;
	this->Py = Py;
    this->Width = width;
    this->Height = height;
	this->SizeX = Sx;
	this->SizeY = Sy;
}

----------------------------------------------------------------------

#define PANEL_SIZE 64
#define PANEL_WIDTH_MAX 10
#define PANEL_HEIGHT_MAX 10
#define PANEL_TYPE 3
#define DROP_SPEED 0

typedef struct{
    int TouchX;
    int TouchY;
}OBJECT_GAME;

// パネルクラス
class PANEL : public MENU{
public:
    int Type;
    int TargetX, TargetY;
    void Delete( void );
};

void PANEL::Delete( void ){
    this->Type = 0;
}

static PANEL Panel[PANEL_HEIGHT_MAX][PANEL_WIDTH_MAX];
static OBJECT_GAME Obj;

/********************  ********************/

// 削除
void DeletePanel( int x, int y, int color ){
    
    // 配列外ならリターン
	if (x < 0 || PANEL_WIDTH_MAX  <= x ||
		y < 0 || PANEL_HEIGHT_MAX <= y) return;
    
    // 消えていたら
    if( Panel[y][x].Type == 0 ) return;
    if( Panel[y][x].Type != color ) return;
    
    // 消す
    Panel[y][x].Delete();
    
    // 再帰
    DeletePanel( x-1, y, color );
    DeletePanel( x+1, y, color );
    DeletePanel( x, y-1, color );
    DeletePanel( x, y+1, color );
    
}

// 詰める処理
void DropPanel( void ){
    
    // 縦の判定
    for(int j=0; j<PANEL_WIDTH_MAX; j++){
        for(int i=PANEL_HEIGHT_MAX-1; i>=0; i--){
            
            // 隙間があった
            if( Panel[i][j].Type == 0 ){
                for(int yy=i-1; yy>=0; yy--){
                    if( yy >= 0 ){
                        if( Panel[yy][j].Type != 0 ){
                            Panel[i][j].Type = Panel[yy][j].Type;
                            Panel[yy][j].Type = 0;
                            Panel[i][j].Py = i*PANEL_SIZE;
                            //Panel[i][j].TargetY = i*PANEL_SIZE;
                            //Panel[yy][j].TargetY = i*PANEL_SIZE;;
                            break;
                        }
                    }
                }
            }
        }
    }
    
    // 横方向
    int underY = PANEL_HEIGHT_MAX-1;
    
    for (int x=0; x<PANEL_WIDTH_MAX; x++){
        if( Panel[underY][x].Type == 0 ){
            for (int xx=x+1; xx<PANEL_WIDTH_MAX; xx++){
                if( Panel[underY][xx].Type != 0 ){
                    for(int yy=PANEL_HEIGHT_MAX-1; yy>=0; yy--){
                        if( Panel[yy][xx].Type == 0 ) break;
                        Panel[yy][x].Type = Panel[yy][xx].Type;
                        Panel[yy][xx].Type = 0;
                        Panel[yy][x].Px = x*PANEL_SIZE;
                        //Panel[yy][x].TargetX = x * PANEL_SIZE;
                    }
                    break;
                }
            }
        }
    }

}

// カラーチェック
bool CheckType( int x, int y, int color ){
	bool check = false;
    
	if (0 <= x - 1 && Panel[y][x-1].Type != 0 && Panel[y][x-1].Type == color) check = true;
    else if (x + 1 < PANEL_WIDTH_MAX && Panel[y][x + 1].Type != 0 && Panel[y][x + 1].Type == color) check = true;
    else if (0 <= y - 1 && Panel[y-1][x].Type != 0 && Panel[y-1][x].Type == color) check = true;
    else if (y + 1 < PANEL_HEIGHT_MAX && Panel[y+1][x].Type != 0 && Panel[y+1][x].Type == color) check = true;
                    
    return check;
}

// クリア判定
bool CheckEnd( void ){
    for(int i=0; i<PANEL_HEIGHT_MAX; i++){
        for(int j=0; j<PANEL_WIDTH_MAX; j++){
			if (Panel[i][j].Type == 0) continue;
			if (CheckType( j, i, Panel[i][j].Type )) return false; // 周りに同じ色が一つでもあったら
		}
	}
	return true;
}


static void Init(){
    
    // パネルの初期化
    for(int i=0; i<PANEL_HEIGHT_MAX; i++){
        for(int j=0; j<PANEL_WIDTH_MAX; j++){
            Panel[i][j].Init( j*PANEL_SIZE, i*PANEL_SIZE, PANEL_SIZE, PANEL_SIZE, 1.0f, 1.0f );
            //Panel[i][j].Init( j*PANEL_SIZE-PANEL_SIZE/2, i*PANEL_SIZE-PANEL_SIZE/2, PANEL_SIZE, PANEL_SIZE, 1.0f, 1.0f );
            Panel[i][j].Type = rand()%PANEL_TYPE+1;
            Panel[i][j].TargetX = Panel[i][j].Px;
            Panel[i][j].TargetY = Panel[i][j].Py;
        }
    }
    
    Obj.TouchX = -1;
    Obj.TouchY = -1;
}

static void Loop(){
    
    Obj.TouchX = -1;
    Obj.TouchY = -1;
    
    if( System.touch.trgFlag ){
        
        for(int i=0; i<PANEL_HEIGHT_MAX; i++){
            for(int j=0; j<PANEL_WIDTH_MAX; j++){
                if( Panel[i][j].TouchCheck() ){
                    Obj.TouchX = j;
                    Obj.TouchY = i;
                    break;
                }
            }
        }
        NSLog( @"%d%d", Obj.TouchX, Obj.TouchY );
        //タッチされたら
        if( Obj.TouchX != -1 && Obj.TouchY != -1 ){
            // 隣同士で同じ色があったら消す
            
            if( CheckType( Obj.TouchX , Obj.TouchY, Panel[Obj.TouchY][Obj.TouchX].Type ) )
                DeletePanel( Obj.TouchX , Obj.TouchY, Panel[Obj.TouchY][Obj.TouchX].Type );
        }
    }
    
    // 詰める
    DropPanel();
    
    // 目標値へ移動
    for(int i=0; i<PANEL_HEIGHT_MAX; i++){
        for(int j=0; j<PANEL_WIDTH_MAX; j++){
            //Panel[i][j].Px -= DROP_SPEED;
            //Panel[i][j].Py += DROP_SPEED;
            //if( Panel[i][j].Px <= Panel[i][j].TargetX ) Panel[i][j].Px = Panel[i][j].TargetX;
            //if( Panel[i][j].Py >= Panel[i][j].TargetY ) Panel[i][j].Py = Panel[i][j].TargetY;
        }
    }
    
    NSLog( @"%d", CheckEnd() );
    
}

static void Draw(){
    
    // パネルの描画
    for(int i=0; i<PANEL_HEIGHT_MAX; i++){
        for(int j=0; j<PANEL_WIDTH_MAX; j++){
            if( Panel[i][j].Type == 1 ) DrawBox( Panel[i][j].Px, Panel[i][j].Py, Panel[i][j].Px+PANEL_SIZE, Panel[i][j].Py+PANEL_SIZE, 0xff0000, 255 );
            else if( Panel[i][j].Type == 2 ) DrawBox( Panel[i][j].Px, Panel[i][j].Py, Panel[i][j].Px+PANEL_SIZE, Panel[i][j].Py+PANEL_SIZE, 0x00ff00, 255 );
            else if( Panel[i][j].Type == 3 ) DrawBox( Panel[i][j].Px, Panel[i][j].Py, Panel[i][j].Px+PANEL_SIZE, Panel[i][j].Py+PANEL_SIZE, 0x0000ff, 255 );
        }
    }
}

アバター
h2so5
副管理人
記事: 2212
登録日時: 9年前
住所: 東京
連絡を取る:

Re: 「さめがめ」の落ちるアニメーション処理について

#2

投稿記事 by h2so5 » 7年前

ロジック部分と表示部分を分けるのが適切だと思います。

つまり、パズルのロジックの部分は今のままにして表示するための処理を分離します。
ロジックの部分では一瞬でブロックが落ちるけれど、表示部分で遅延させて落ちるように見せます。

状態の同期を取るために落ちている間はロジック部分のでユーザーの操作を受け付けないようにします。

ツナマヨ

Re: 「さめがめ」の落ちるアニメーション処理について

#3

投稿記事 by ツナマヨ » 7年前

ご回答ありがとうございます。
現在のロジックでも行けるのですね!

なるほど・・・。遅延させて落とすことがちょっとわからないのですが、
値を一瞬で変えるのに出来るものなのでしょうか?
ココらへんの実装ができそうにないです・・・。

ホヅミ
記事: 110
登録日時: 9年前

Re: 「さめがめ」の落ちるアニメーション処理について

#4

投稿記事 by ホヅミ » 7年前

アニメーションだけならばDXライブラリ本家のサンプル
4.マップスクロール基本
http://homepage2.nifty.com/natupaji/DxL ... am.html#N4
が参考になるのではないでしょうか?

ツナマヨ

Re: 「さめがめ」の落ちるアニメーション処理について

#5

投稿記事 by ツナマヨ » 7年前

皆様色々とありがとうございます。
ソースを見てなんとなくは理解できているのですが、ソースにすることができません。
アニメーションしているように見せるため、座標系のみ別個に管理することはわかりました。

現在だと Panel[j].Type == 1のように配列を見て表示しているのが問題かと思います。
こちらを修正するためにMove用の状態を管理する変数などを
用意してみたのですが、実装が出来そうに御座いません・・・。

サンプルでは1キャラに対してマップ全体が動く感じかと思うのですが、
今回のパズルゲームだと自分より下のブロックがないか、左詰めの時に落ちる感じです。

何度も質問してしまい申し訳ございません。

コード:

static void Draw(){
    
    // パネルの描画
    for(int i=0; i<PANEL_HEIGHT_MAX; i++){
        for(int j=0; j<PANEL_WIDTH_MAX; j++){
            if( Panel[i][j].Type == 1 ) DrawBox( Panel[i][j].Px, Panel[i][j].Py, Panel[i][j].Px+PANEL_SIZE, Panel[i][j].Py+PANEL_SIZE, 0xff0000, 255 );
            else if( Panel[i][j].Type == 2 ) DrawBox( Panel[i][j].Px, Panel[i][j].Py, Panel[i][j].Px+PANEL_SIZE, Panel[i][j].Py+PANEL_SIZE, 0x00ff00, 255 );
            else if( Panel[i][j].Type == 3 ) DrawBox( Panel[i][j].Px, Panel[i][j].Py, Panel[i][j].Px+PANEL_SIZE, Panel[i][j].Py+PANEL_SIZE, 0x0000ff, 255 );
        }
    }
}

ツナマヨ

Re: 「さめがめ」の落ちるアニメーション処理について

#6

投稿記事 by ツナマヨ » 7年前

何度もすみません。
現在のソースを添付させて頂きます。
現在のソースでは落ちませんが、コメントアウトを外すと動かせたりするようになりました。
さめがめは決まって左下に向かって進むため、TagetX,TagetYまでは
進んで欲しいみたいなプログラムで書いてみたのですが上手く動かすことができませんでした。

質問がかりで申し訳ないです。

コード:



#define PANEL_SIZE 64
#define PANEL_WIDTH_MAX 10
#define PANEL_HEIGHT_MAX 10
#define PANEL_TYPE 3
#define DROP_SPEED 0

extern SYSTEM System;
extern GLOBAL Global;

typedef struct{
    int TouchX;
    int TouchY;
}OBJECT_GAME;

// パネルクラス
class PANEL : public MENU{
public:
    int Type;
    
    int TargetX, TargetY;
    int AnmType;
    int Move;
    /*
    int MoveX, MoveY ;
    int MoveCounter ;
    */
    void Delete( void );
    
};

void PANEL::Delete( void ){
    this->Type = 0;
    this->AnmType = 0;
}

static PANEL Panel[PANEL_HEIGHT_MAX][PANEL_WIDTH_MAX];
static OBJECT_GAME Obj;

/********************  ********************/

// 削除
void DeletePanel( int x, int y, int color ){
    
    // 配列外ならリターン
	if (x < 0 || PANEL_WIDTH_MAX  <= x ||
		y < 0 || PANEL_HEIGHT_MAX <= y) return;
    
    // 消えていたら
    if( Panel[y][x].Type == 0 ) return;
    if( Panel[y][x].Type != color ) return;
    
    // 消す
    Panel[y][x].Delete();
    
    // 再帰
    DeletePanel( x-1, y, color );
    DeletePanel( x+1, y, color );
    DeletePanel( x, y-1, color );
    DeletePanel( x, y+1, color );
    
}

// 詰める処理
void DropPanel( void ){
    
    // 縦の判定
    for(int j=0; j<PANEL_WIDTH_MAX; j++){
        for(int i=PANEL_HEIGHT_MAX-1; i>=0; i--){
            
            // 隙間があった
            if( Panel[i][j].Type == 0 ){
                for(int yy=i-1; yy>=0; yy--){
                    if( yy >= 0 ){
                        if( Panel[yy][j].Type != 0 ){
                            Panel[i][j].Type = Panel[yy][j].Type;
                            Panel[yy][j].Move = 1;
                            Panel[yy][j].Type = 0;
                            //Panel[i][j].Py = i*PANEL_SIZE;
                            Panel[yy][j].TargetY = i*PANEL_SIZE;
                            //Panel[yy][j].TargetY = i*PANEL_SIZE;;
                            break;
                        }
                    }
                }
            }
        }
    }
    
    // 横方向
    int underY = PANEL_HEIGHT_MAX-1;
    
    for (int x=0; x<PANEL_WIDTH_MAX; x++){
        if( Panel[underY][x].Type == 0 ){
            for (int xx=x+1; xx<PANEL_WIDTH_MAX; xx++){
                if( Panel[underY][xx].Type != 0 ){
                    for(int yy=PANEL_HEIGHT_MAX-1; yy>=0; yy--){
                        if( Panel[yy][xx].Type == 0 ) break;
                        Panel[yy][x].Type = Panel[yy][xx].Type;
                        Panel[yy][xx].Move = 1;
                        Panel[yy][xx].Type = 0;
                        //Panel[yy][x].Px = x*PANEL_SIZE;
                        Panel[yy][xx].TargetX = x * PANEL_SIZE;
                    }
                    break;
                }
            }
        }
    }
    
    // 移動処理
    /* 32を動かすことが出来る
    for(int i=0; i<PANEL_HEIGHT_MAX; i++){
        for(int j=0; j<PANEL_WIDTH_MAX; j++){
            if( Panel[i][j].Move == 1 ){
                Panel[i][j].Py += 2;
                Panel[i][j].MoveCounter++;
                if( Panel[i][j].MoveCounter >= PANEL_SIZE/2 ){
                    Panel[i][j].MoveCounter = 0;
                    Panel[i][j].Move = 0;
                }
            }
        }
    }
     */
}

// カラーチェック
bool CheckType( int x, int y, int color ){
	bool check = false;
    
	if (0 <= x - 1 && Panel[y][x-1].Type != 0 && Panel[y][x-1].Type == color) check = true;
    else if (x + 1 < PANEL_WIDTH_MAX && Panel[y][x + 1].Type != 0 && Panel[y][x + 1].Type == color) check = true;
    else if (0 <= y - 1 && Panel[y-1][x].Type != 0 && Panel[y-1][x].Type == color) check = true;
    else if (y + 1 < PANEL_HEIGHT_MAX && Panel[y+1][x].Type != 0 && Panel[y+1][x].Type == color) check = true;
                    
    return check;
}

// クリア判定
bool CheckEnd( void ){
    for(int i=0; i<PANEL_HEIGHT_MAX; i++){
        for(int j=0; j<PANEL_WIDTH_MAX; j++){
			if (Panel[i][j].Type == 0) continue;
			if (CheckType( j, i, Panel[i][j].Type )) return false; // 周りに同じ色が一つでもあったら
		}
	}
	return true;
}


static void Init(){
    
    // パネルの初期化
    for(int i=0; i<PANEL_HEIGHT_MAX; i++){
        for(int j=0; j<PANEL_WIDTH_MAX; j++){
            Panel[i][j].Init( j*PANEL_SIZE, i*PANEL_SIZE, PANEL_SIZE, PANEL_SIZE, 1.0f, 1.0f );
            //Panel[i][j].Init( j*PANEL_SIZE-PANEL_SIZE/2, i*PANEL_SIZE-PANEL_SIZE/2, PANEL_SIZE, PANEL_SIZE, 1.0f, 1.0f );
            Panel[i][j].Type = rand()%PANEL_TYPE+1;
            Panel[i][j].AnmType = Panel[i][j].Type;
            Panel[i][j].Px = j*PANEL_SIZE;
            Panel[i][j].Py = i*PANEL_SIZE;
            Panel[i][j].TargetX = Panel[i][j].Px;
            Panel[i][j].TargetY = Panel[i][j].Py;
        }
    }
    
    Obj.TouchX = -1;
    Obj.TouchY = -1;
}

static void Loop(){
    
    Obj.TouchX = -1;
    Obj.TouchY = -1;
    
    if( System.touch.trgFlag ){
        
        for(int i=0; i<PANEL_HEIGHT_MAX; i++){
            for(int j=0; j<PANEL_WIDTH_MAX; j++){
                
                Panel[i][j].Move = 0;
                
                if( Panel[i][j].TouchCheck() ){
                    Obj.TouchX = j;
                    Obj.TouchY = i;
                    break;
                }
            }
        }
        NSLog( @"%d%d", Obj.TouchX, Obj.TouchY );
        //タッチされたら
        if( Obj.TouchX != -1 && Obj.TouchY != -1 ){
            // 隣同士で同じ色があったら消す
            
            if( CheckType( Obj.TouchX , Obj.TouchY, Panel[Obj.TouchY][Obj.TouchX].Type ) )
                DeletePanel( Obj.TouchX , Obj.TouchY, Panel[Obj.TouchY][Obj.TouchX].Type );
        }
    }
    
    // 詰める
    DropPanel();
    
    // 目標値へ移動
    for(int i=0; i<PANEL_HEIGHT_MAX; i++){
        for(int j=0; j<PANEL_WIDTH_MAX; j++){
            if( Panel[i][j].Move == 1 ){
                Panel[i][j].Py += DROP_SPEED;
                if( Panel[i][j].Py >= Panel[i][j].TargetY ){
                    Panel[i][j].Py = Panel[i][j].TargetY;
                    Panel[i][j].Px -= DROP_SPEED;
                    if( Panel[i][j].Px <= Panel[i][j].TargetX ) {
                        Panel[i][j].Px = Panel[i][j].TargetX;                        
                        Panel[i][j].Move = 0;
                    }
                }
            }
        }
    }
    
    NSLog( @"%d", CheckEnd() );
    
}

static void Draw(){
    
    // パネルの描画
    for(int i=0; i<PANEL_HEIGHT_MAX; i++){
        for(int j=0; j<PANEL_WIDTH_MAX; j++){
            if( Panel[i][j].AnmType == 1 ) DrawBox( Panel[i][j].Px, Panel[i][j].Py, Panel[i][j].Px+PANEL_SIZE, Panel[i][j].Py+PANEL_SIZE, 0xff0000, 255 );
            else if( Panel[i][j].AnmType == 2 ) DrawBox( Panel[i][j].Px, Panel[i][j].Py, Panel[i][j].Px+PANEL_SIZE, Panel[i][j].Py+PANEL_SIZE, 0x00ff00, 255 );
            else if( Panel[i][j].AnmType == 3 ) DrawBox( Panel[i][j].Px, Panel[i][j].Py, Panel[i][j].Px+PANEL_SIZE, Panel[i][j].Py+PANEL_SIZE, 0x0000ff, 255 );
            /*
            if( Panel[i][j].Type == 1 ) DrawBox( Panel[i][j].Px, Panel[i][j].Py, Panel[i][j].Px+PANEL_SIZE, Panel[i][j].Py+PANEL_SIZE, 0xff0000, 255 );
            else if( Panel[i][j].Type == 2 ) DrawBox( Panel[i][j].Px, Panel[i][j].Py, Panel[i][j].Px+PANEL_SIZE, Panel[i][j].Py+PANEL_SIZE, 0x00ff00, 255 );
            else if( Panel[i][j].Type == 3 ) DrawBox( Panel[i][j].Px, Panel[i][j].Py, Panel[i][j].Px+PANEL_SIZE, Panel[i][j].Py+PANEL_SIZE, 0x0000ff, 255 );
             */
        }
    }
}


ツナマヨ

Re: 「さめがめ」の落ちるアニメーション処理について

#7

投稿記事 by ツナマヨ » 7年前

何度もすみません。
この土日を使って色々と試してみたのですが、
やはり落ちるアニメーションをさせることができません。

動くようには出来たのですが、違う場所に行ってしまったりと
正常にはなりませんでした。

サンプルの方も拝見し作成してみたのですが、期待通りの動きにはなってくれませんでした。

ISLe
記事: 2646
登録日時: 9年前
連絡を取る:

Re: 「さめがめ」の落ちるアニメーション処理について

#8

投稿記事 by ISLe » 7年前

ちょっと前のスレでDXライブラリを使ったコードですが。
パズルゲームに自然なアニメーションを付けたい

ズルズル落ちるようになってますけど、アニメーションカウンタを独立させて、落ち幅が異なっても同じ時間で落下するのが本当です。

ツナマヨ

Re: 「さめがめ」の落ちるアニメーション処理について

#9

投稿記事 by ツナマヨ » 7年前

ご連絡が遅くなりました。
なるほど!!!!!アレンジして出来ました。

このような発想ができなかったので、本当に助かりました。
この度は長い間お世話になりました。

閉鎖

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