ページ 11

DXライブラリを使用したゲームの時間制御について

Posted: 2011年10月24日(月) 17:28
by Loki
[/code]
オフトピック
http://detail.chiebukuro.yahoo.co.jp/qa ... 1273998357
こちらで質問させていただいたところ、こちらの方が良いということでしたので、質問させていただきます。
利用規約には相互リンクが必要、とのことですが、利用規約を読む前にYahoo!知恵袋の回答を解決済みにしてしまったために、相互リンクが出来ませんでした。
御無礼申し訳ありません。
さて、本題ですが、まずは、環境について書きます。
  • OS Windows 7 Home Premium(32 bit)
  • Compiler Microsoft Visual C++ 2010 Express
  • library DXライブラリ
環境は以上の通りです。
また、C言語のレベルに関しては、初心者レベルです。

具体的なソースコードは以下のようになります。
宣言部がやや怪しくなっていますが、知識不足です。

コード:

#include "DxLib.h"
#define ELEMENTS 6 //data.popの要素数
#define CROSS ELEMENTS-1 //×
#define BLOCK CROSS-1 //BLOCK
#define RAND BLOCK-2 //乱数に使う
//プロトタイプ宣言
typedef unsigned int natural;
typedef const int equable;
typedef struct{
	natural m[14][6],e[14][6];
}MASS;
int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nCmdShow);
static void UpdateKey(char *KeyStateBuf);
static int Fall(MASS &mass,bool flag,natural mNext[2],natural eNext[2],natural linkage[2]);
static int Link(MASS mass,int x,int y,int kind,MASS &checked,bool flag);
static void Delete(MASS &mass,int x,int y,int kind,bool flag);
static int PopJelly(natural level);
static int StoryMode(void);
static int FreeMode(void);
static int ConfigMode(void);
typedef struct{
	int image[6],pop[ELEMENTS],character[5],effect[4],music[1];
}DATA;
DATA data;
/*Music http://nochiko.websozai.jp/
~~~:(width,height)
スクリーン:640,480
ぷよ:38,38
ぷよが置けるエリア:228,456
余白:46,12
プレイヤーと敵の間:92

~~~:自分(x,y) 敵(x,y)
ぷよが置けるエリア:46,12 366,12
×の位置:122,12と160,12 442,12と480,120

~~~:補足
横のマス数 6
縦のマス数 12 (+1 {非表示})

_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
						【要注意】
Releaseする時には、pop-jellyフォルダを
ドキュメント/DxLib_VC/Toolにあるやつでdxaファイルにし、
D:\pop-jellyにコピーして、圧縮すること。
SetOutApplicationLogValidFlagをFALSEに設定すること。
_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
*/
int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nCmdShow){
	if(ChangeWindowMode(TRUE)==-1 || SetGraphMode(640,480,16)!=DX_CHANGESCREEN_OK || DxLib_Init()==-1)return -1;
	if(SetOutApplicationLogValidFlag(TRUE)==-1 || SetAlwaysRunFlag(TRUE)==-1 || SetDrawScreen(DX_SCREEN_BACK)==-1 || SetWindowText("ポップ ゼリー")==-1)goto last;
//宣言
	//画像全般
		data.image[0]=LoadGraph("./pop-jelly/Image/background/title.png"); //タイトル
		data.image[1]=LoadGraph("./pop-jelly/Image/background/background.png"); //ポップゼリー メイン背景
		data.image[2]=LoadGraph("./pop-jelly/Image/background/frame.png"); //ポップゼリー フレーム部分
		data.image[3]=LoadGraph("./pop-jelly/Image/message.png"); //メッセージ表示領域
		data.image[4]=LoadGraph("./pop-jelly/Image/select.png"); //選択ボタン
		data.image[5]=LoadGraph("./pop-jelly/Image/select_now.png"); //現在選択中のもの
	//ポップ画像
		data.pop[0]=0;
		data.pop[1]=LoadGraph("./pop-jelly/Image/pop/red.png"); //赤ポップ
		data.pop[2]=LoadGraph("./pop-jelly/Image/pop/blue.png"); //青ポップ
		data.pop[3]=LoadGraph("./pop-jelly/Image/pop/green.png"); //緑ポップ
//		data.pop[4]=LoadGraph("./pop-jelly/Image/pop/pink.png"); //ピンクポップ
		data.pop[4]=LoadGraph("./pop-jelly/Image/pop/block.png"); //ブロックポップ
		data.pop[5]=LoadGraph("./pop-jelly/Image/pop/cross.png"); //×
	//キャラクター画像
		data.character[0]=LoadGraph("./pop-jelly/Image/character/slime1.png"); //アースLv1
		data.character[1]=LoadGraph("./pop-jelly/Image/character/slime2.png"); //アースLv2
		data.character[2]=LoadGraph("./pop-jelly/Image/character/slime3.png"); //アースLv3
		data.character[3]=LoadGraph("./pop-jelly/Image/character/slime4.png"); //アースLv4
		data.character[4]=LoadGraph("./pop-jelly/Image/character/sun.png"); //サン
	//効果音
		data.effect[0]=LoadSoundMem("./pop-jelly/Music/message.ogg"); //次のメッセージへ移る時
		data.effect[1]=LoadSoundMem("./pop-jelly/Music/select.ogg"); //選択効果音
		data.effect[2]=LoadSoundMem("./pop-jelly/Music/enter.ogg"); //決定音
		data.effect[3]=LoadSoundMem("./pop-jelly/Music/story/vire.ogg"); //剣が当たる音
	//音楽
		data.music[0]=LoadSoundMem("./pop-jelly/Music/title.ogg"); //タイトル
	int flag=0;
	//此処にタイトル描写処理がありますが、省きます。
	flag=FreeMode();
	if(flag==1)goto title;
	last:
	DxLib_End();
	return 0;
}
static void UpdateKey(char *KeyStateBuf){
	char key[256];
	GetHitKeyStateAll(key);
	for(int i=0;i<256;i++){
		if(key[i]==0)KeyStateBuf[i]=0;
		else KeyStateBuf[i]++;
	}
}//完全実装 不具合なし
static int Fall(MASS &mass,bool flag,natural mNext[2],natural eNext[2],natural linkage[2]){
	int n=0;
	char string[2][3];
	sprintf_s(string[0],"%d",linkage[0]);
	sprintf_s(string[1],"%d",linkage[1]);
	if(flag) //自分
		for(int x=0;x<6;x++) //一番左から
			for(int y=13,i;y>=0;y--){ //一番下から
				if(mass.m[y][x]==0){ //空のマスなら
					for(i=y-1;i>=0 && (mass.m[i][x]==0 || mass.m[i][x]==CROSS);i--); //空のマスと、×は飛ばす
					if(i<0)break; //上にポップがない
					if(!n)n=1; //ループ用
					for(i=y;i>=0;i--)
						if(mass.m[i][x]!=CROSS)
							mass.m[i][x]=i>0 && mass.m[i-1][x]!=CROSS ? mass.m[i-1][x] : 0; //このマスをすぐ上のマスに。一番上か、上が×なら、空にする
					if(mass.m[2][2]==0)mass.m[2][2]=CROSS; //×の位置
					if(mass.m[2][3]==0)mass.m[2][3]=CROSS;
					if(mass.e[2][2]==0)mass.e[2][2]=CROSS;
					if(mass.e[2][3]==0)mass.e[2][3]=CROSS;
					for(int y=-64,i=0;y<=430;y+=38,i++){
						for(int x=46,j=0;x<=236;x+=38,j++)mass.m[i][j] && DrawGraph(x,y,data.pop[mass.m[i][j]],TRUE);
						for(int x=366,j=0;x<=556;x+=38,j++)mass.e[i][j] && DrawGraph(x,y,data.pop[mass.e[i][j]],TRUE);
					}
					DrawGraph(0,0,data.image[2],TRUE);		//枠(背景)
					DrawGraph(278,10,data.pop[mNext[0]],TRUE); //次のポップを表示(自分)
					DrawGraph(278,48,data.pop[mNext[1]],TRUE);
					DrawGraph(321,10,data.pop[eNext[0]],TRUE); //次のポップを表示(敵)
					DrawGraph(321,48,data.pop[eNext[1]],TRUE);
					linkage[0] && DrawString(278,400,string[0],0x000000); //連鎖数を表示(自分)
					linkage[1] && DrawString(321,400,string[1],0x000000); //連鎖数を表示(敵)
					if(!(ScreenFlip()==0 && ProcessMessage()==0 && ClearDrawScreen()==0))return 0;
					DrawGraph(0,0,data.image[1],TRUE);		//枠(メイン)
					Sleep(50);
					break;
				}
			}
	else //敵
		for(int x=0;x<6;x++)
			for(int y=13,i;y>=0;y--){
				if(mass.e[y][x]==0){
					for(i=y-1;i>=0 && (mass.e[i][x]==0 || mass.e[i][x]==CROSS);i--);
					if(i<0)break;
					if(!n)n=1;
					for(i=y;i>=0;i--)
						if(mass.e[i][x]!=CROSS)
							mass.e[i][x]=i>0 && mass.e[i-1][x]!=CROSS ? mass.e[i-1][x] : 0;
					if(mass.m[2][2]==0)mass.m[2][2]=CROSS;
					if(mass.m[2][3]==0)mass.m[2][3]=CROSS;
					if(mass.e[2][2]==0)mass.e[2][2]=CROSS;
					if(mass.e[2][3]==0)mass.e[2][3]=CROSS;
					for(int y=-64,i=0;y<=430;y+=38,i++){
						for(int x=46,j=0;x<=236;x+=38,j++)mass.m[i][j] && DrawGraph(x,y,data.pop[mass.m[i][j]],TRUE);
						for(int x=366,j=0;x<=556;x+=38,j++)mass.e[i][j] && DrawGraph(x,y,data.pop[mass.e[i][j]],TRUE);
					}
					DrawGraph(0,0,data.image[2],TRUE);
					DrawGraph(278,10,data.pop[mNext[0]],TRUE);
					DrawGraph(278,48,data.pop[mNext[1]],TRUE);
					DrawGraph(321,10,data.pop[eNext[0]],TRUE);
					DrawGraph(321,48,data.pop[eNext[1]],TRUE);
					linkage[0] && DrawString(278,400,string[0],0x000000);
					linkage[1] && DrawString(321,400,string[1],0x000000);
					if(!(ScreenFlip()==0 && ProcessMessage()==0 && ClearDrawScreen()==0))return 0;
					DrawGraph(0,0,data.image[1],TRUE);
					Sleep(35);
					break;
				}
			}
	return n;
}// この関数内では、Sleepが使われていて、(一応)時間制御をしています。
static int Link(MASS mass,int x,int y,int kind,MASS &checked,bool flag){
	int number=1;
	if(flag){
		if(checked.m[y][x]==1)return 0; //既にチェック済み
		checked.m[y][x]=1;
		if(mass.m[y][x]==0 || mass.m[y][x]==BLOCK || mass.m[y][x]==CROSS)return 0; //空かブロックポップか×
		if(y>2 && mass.m[y-1][x]==kind)number+=Link(mass,x,y-1,kind,checked,flag); //上
		if(x<5 && mass.m[y][x+1]==kind)number+=Link(mass,x+1,y,kind,checked,flag); //右
		if(x>0 && mass.m[y][x-1]==kind)number+=Link(mass,x-1,y,kind,checked,flag); //左
		if(y<13 && mass.m[y+1][x]==kind)number+=Link(mass,x,y+1,kind,checked,flag); //下
	}
	else{
		if(checked.e[y][x]==1)return 0; //既にチェック済み
		checked.e[y][x]=1;
		if(mass.e[y][x]==0 || mass.e[y][x]==BLOCK || mass.e[y][x]==CROSS)return 0; //空かブロックポップか×
		if(y>2 && mass.e[y-1][x]==kind)number+=Link(mass,x,y-1,kind,checked,flag); //上
		if(x<5 && mass.e[y][x+1]==kind)number+=Link(mass,x+1,y,kind,checked,flag); //右
		if(x>0 && mass.e[y][x-1]==kind)number+=Link(mass,x-1,y,kind,checked,flag); //左
		if(y<13 && mass.e[y+1][x]==kind)number+=Link(mass,x,y+1,kind,checked,flag); //下
	}
	return number; //結合数
}//微妙 ポップがくっついた時の画像変更 要実装
static void Delete(MASS &mass,int x,int y,int kind,bool flag){
	if(flag){
		if(mass.m[y][x]==kind){
			mass.m[y][x]=0; //消す
			if(y>2 && mass.m[y-1][x]==kind)Delete(mass,x,y-1,kind,flag); //上
			if(x<5 && mass.m[y][x+1]==kind)Delete(mass,x+1,y,kind,flag); //右
			if(x>0 && mass.m[y][x-1]==kind)Delete(mass,x-1,y,kind,flag); //左
			if(y<13 && mass.m[y+1][x]==kind)Delete(mass,x,y+1,kind,flag); //下
		}
	}
	else{
		if(mass.e[y][x]==kind){
			mass.e[y][x]=0; //消す
			if(y>2 && mass.e[y-1][x]==kind)Delete(mass,x,y-1,kind,flag); //上
			if(x<5 && mass.e[y][x+1]==kind)Delete(mass,x+1,y,kind,flag); //右
			if(x>0 && mass.e[y][x-1]==kind)Delete(mass,x-1,y,kind,flag); //左
			if(y<13 && mass.e[y+1][x]==kind)Delete(mass,x,y+1,kind,flag); //下
		}
	}
}
static int PopJelly(natural level=0){
//宣言
	int count[2]={60,60}; //ポップが床等に最初に付いてからの経過時間 再度離れた場合は、少し減らす(未実装) ついてから下を押すと増やす(未実装)
	natural time[2]={1,1}; //1/60秒に一回1増加。 1秒たつと、1に初期化。(自分,敵)
	natural process[2]={0,0}; //時間制御用変数 //未使用。。。。
	natural turn[2]={0,0}; //回転回数(自分,敵)
	natural linkage[2]={0,0}; //連鎖数(自分,敵)
	natural block={0,0}; //BLOCK ポップの数(自分,敵)
	bool chain[2]={false,false}; //連鎖フラグ(自分,敵)
	bool countflag[2]={false,false}; //カウントフラグ(自分,敵)
	char key[256]; //キー保存用
	natural mKind[2]={GetRand(RAND)+1,GetRand(RAND)+1}; //ポップの種類(上,下)(自分)
	natural eKind[2]={GetRand(RAND)+1,GetRand(RAND)+1}; //ポップの種類(上,下)(敵)
	natural mNext[2]={GetRand(RAND)+1,GetRand(RAND)+1}; //次のポップ(上,下)(自分)
	natural eNext[2]={GetRand(RAND)+1,GetRand(RAND)+1}; //次のポップ(上,下)(敵)
	POINT mPosition[2]={{2,0},{2,1}}; //ポップの場所(x,y)(自分)
	POINT ePosition[2]={{2,0},{2,1}}; //ポップの場所(x,y)(敵)
	const MASS copy={}; //チェック用変数の初期化コピー用
	MASS checked; //チェック用
	MASS mass={ //フィールド用
		{ //自分
			{0,0,0,0,0,0}, //この列に積んだら消す
			{3,1,0,0,1,1}, //とりあえず、まずは連鎖を組んでみたところから
			{3,3,3,2,1,3},
			{2,3,1,1,2,1},
			{3,1,2,2,1,3},
			{1,2,1,3,2,3},
			{2,1,3,2,1,3},
			{1,2,1,3,2,1},
			{1,2,1,3,2,1},
			{1,3,3,2,1,2},
			{3,1,2,3,2,2},
			{2,3,1,2,3,1},
			{2,3,1,2,3,1},
			{2,3,1,2,3,1}
		},
		{ //敵
			{0,0,0,0,0,0},
			{0,0,0,0,0,0},
			{0,0,0,0,0,0},
			{0,0,0,0,0,0},
			{0,0,0,0,0,0},
			{0,0,0,0,0,0},
			{0,0,0,0,0,0},
			{0,0,0,0,0,0},
			{0,0,0,0,0,0},
			{0,0,0,0,0,0},
			{0,0,0,0,0,0},
			{0,0,0,0,0,0},
			{0,0,0,0,0,0},
			{0,0,0,0,0,0}
		}
	};
	do{
		if(ProcessMessage()!=0)return 0;
		UpdateKey(key);
		DrawGraph(0,0,data.image[1],TRUE);		//枠(背景)
		natural my1=mPosition[0].y,mx1=mPosition[0].x,my2=mPosition[1].y,mx2=mPosition[1].x;
		natural ey1=ePosition[0].y,ex1=ePosition[0].x,ey2=ePosition[1].y,ex2=ePosition[1].x;
		if(count[0]==60){ //次のポップ(自分)
			while(Fall(mass,true,mNext,eNext,linkage)); //浮いているポップがなくなるまで落とす
			mass.m[0][0]=0; //14段目のポップは消す。
			mass.m[0][1]=0;
			mass.m[0][2]=0;
			mass.m[0][3]=0;
			mass.m[0][4]=0;
			mass.m[0][5]=0;
			Sleep(100);
			do{
				checked=copy;
				for(natural x=0;x<6;x++){ //一番左の
					for(natural y=13;y>1;y--){ //一番下から上から三番目迄
						natural temp=mass.m[y][x];
						if(temp && temp!=CROSS && temp!=BLOCK && Link(mass,x,y,temp,checked,true)>=4){ //空白、×、BLOCKでなく、4つ以上繋がっている
							Delete(mass,x,y,temp,1);
							if(!chain[0])chain[0]=true; //ポップが消えた
						}
					}
				}
				if(!chain[0])break; //ポップが消えなかったら終了
				linkage[0]++; //連鎖数を増やす
				chain[0]=false;
				checked=copy;
				while(Fall(mass,true,mNext,eNext,linkage)); //落とす & 描写
				for(natural x=0;x<6;x++){ //もう一回連鎖しそうかチェック
					for(natural y=13;y>1;y--){
						natural temp=mass.m[y][x];
						if(temp && temp!=CROSS && temp!=BLOCK && Link(mass,x,y,temp,checked,true)>=4)goto mOut; //空白、×、BLOCKでなく、4つ以上繋がっている場合は、ループを抜ける
					}
				}
				break; //連鎖できない場合は終了
mOut: //連鎖できる場合
				Sleep(850); //少し待ってから、もう一度
			}while(1);
			if((mass.m[2][2] && mass.m[2][2]!=CROSS) || (mass.m[2][3] && mass.m[2][3]!=CROSS)){ //×に積んだ
				DrawString(30,50,"Game Over!! 3秒後に戻ります。",0x000000);
				DrawGraph(0,0,data.image[2],TRUE);
				ScreenFlip();
				Sleep(3000);
				break;
			}
			time[0]=1;
			mKind[0]=mNext[0];
			mKind[1]=mNext[1];
			mNext[0]=GetRand(RAND)+1;
			mNext[1]=GetRand(RAND)+1;
			mPosition[0].x=2;
			mPosition[0].y=0;
			mPosition[1].x=2;
			mPosition[1].y=1;
			count[0]=0;
			countflag[0]=false;
			turn[0]=0;
		}
		else{
			if(mass.m[2][2]==0)mass.m[2][2]=CROSS; //×の位置
			if(mass.m[2][3]==0)mass.m[2][3]=CROSS;
			if(time[0]%60==0){
				if(my1!=13 && my2!=13){ //一秒ごとにポップを下へ移動(自分)
					if(turn[0]%2==0){
						if(!mass.m[my1+1][mx1] || !mass.m[my2+1][mx2] || mass.m[my1+1][mx1]==CROSS || mass.m[my2+1][mx2]==CROSS){
							mass.m[my1][mx1]=0;
							mass.m[my2][mx2]=0;
							mPosition[0].y=++my1;
							mPosition[1].y=++my2;
						}
					}
					else if((!mass.m[my1+1][mx1] || mass.m[my1+1][mx1]==CROSS) && (!mass.m[my2+1][mx2] || mass.m[my2+1][mx2]==CROSS)){
						mass.m[my1][mx1]=0;
						mass.m[my2][mx2]=0;
						mPosition[0].y=++my1;
						mPosition[1].y=++my2;
					}
				}
			}
			if(key[KEY_INPUT_RIGHT] && key[KEY_INPUT_RIGHT]%5==1 && mx1!=5 && mx2!=5){
				if(turn[0]%2==0){
					if((!mass.m[my1][mx1+1] || mass.m[my1][mx1+1]==CROSS) && (!mass.m[my2][mx2+1] || mass.m[my2][mx2+1]==CROSS)){
						mass.m[my1][mx1]=0;
						mass.m[my2][mx2]=0;
						mPosition[0].x=++mx1;
						mPosition[1].x=++mx2;
					}
				}
				else if(!mass.m[my1][mx1+1] || !mass.m[my2][mx2+1] || mass.m[my1][mx1+1]==CROSS || mass.m[my2][mx2+1]==CROSS){
					mass.m[my1][mx1]=0;
					mass.m[my2][mx2]=0;
					mPosition[0].x=++mx1;
					mPosition[1].x=++mx2;
				}
			}
			else if(key[KEY_INPUT_LEFT] && key[KEY_INPUT_LEFT]%5==1 && mx1 && mx2){
				if(turn[0]%2==0){
					if((!mass.m[my1][mx1-1] || mass.m[my1][mx1-1]==CROSS) && (!mass.m[my2][mx2-1] || mass.m[my2][mx2-1]==CROSS)){
						mass.m[my1][mx1]=0;
						mass.m[my2][mx2]=0;
						mPosition[0].x=--mx1;
						mPosition[1].x=--mx2;
					}
				}
				else if(!mass.m[my1][mx1-1] || !mass.m[my2][mx2-1] || mass.m[my1][mx1-1]==CROSS || mass.m[my2][mx2-1]==CROSS){
					mass.m[my1][mx1]=0;
					mass.m[my2][mx2]=0;
					mPosition[0].x=--mx1;
					mPosition[1].x=--mx2;
				}
			}
			else if(key[KEY_INPUT_DOWN] && key[KEY_INPUT_DOWN]%5==1 && my1!=13 && my2!=13){
				if(turn[0]%2==0){
					if(!mass.m[my1+1][mx1] || !mass.m[my2+1][mx2] || mass.m[my1+1][mx1]==CROSS || mass.m[my2+1][mx2]==CROSS){
						mass.m[my1][mx1]=0;
						mass.m[my2][mx2]=0;
						mPosition[0].y=++my1;
						mPosition[1].y=++my2;
					}
				}
				else if((!mass.m[my1+1][mx1] || mass.m[my1+1][mx1]==CROSS) && (!mass.m[my2+1][mx2] || mass.m[my2+1][mx2]==CROSS)){
					mass.m[my1][mx1]=0;
					mass.m[my2][mx2]=0;
					mPosition[0].y=++my1;
					mPosition[1].y=++my2;
				}
			}
			else if(key[KEY_INPUT_A]==1){ //回転判定(右回転)
				switch(turn[0]){
				case 0: // 縦 mPosition[0],[1] (1,2)
					if(mx2==5 || mass.m[my2][mx2+1] && mass.m[my2][mx2+1]!=CROSS){ //右がポップか壁で
						if(mx1 && (!mass.m[my2][mx2-1] || mass.m[my2][mx2-1]==CROSS)){ //左が空か×なら
							mass.m[my1][mx1]=0;
							mPosition[0].y=++my1;
							mPosition[1].x=--mx2;
						}
						else{ //どっちもポップ or 壁なら
							if(my2==13 || mass.m[my2+1][mx2]){ //下にポップか壁があるなら
								mPosition[0].y=++my1; //上のポップを下へ
								mPosition[1].y=--my2; //下のポップを上へ
							}
							else{
								mass.m[my1][mx1]=0;
								++my1;
								mPosition[0].y=++my1; //上のポップを二つ下へ
							}
							turn[0]++; //case 2まで飛ばす。
						}
					}
					else{ //右が空 もしくは ×
						mass.m[my1][mx1]=0;
						mPosition[0].x=++mx1;
						mPosition[0].y=++my1;
					}
					turn[0]++;
					break;
				case 1: // 横 mPosition[1],[0] (2,1)
					mass.m[my1][mx1]=0;
					if(my2==13 || mass.m[my2+1][mx2] && mass.m[my2+1][mx2]!=CROSS){ //左ポップの下がポップか壁なら
						mPosition[0].x=--mx1;
						mPosition[1].y=--my2;
					}
					else{ //左ポップの下が空 もしくは ×
						mPosition[0].x=--mx1;
						mPosition[0].y=++my1;
					}
					turn[0]++;
					break;
				case 2: // 縦 mPosition[1],[0] (2,1)
					if(!mx1 || mass.m[my1][mx1-1] && mass.m[my1][mx1-1]!=CROSS){ //左がポップか壁で
						if(mx1!=5 && (!mass.m[my1][mx1+1] || mass.m[my1][mx1+1]==CROSS)){ //右が空か×なら
							mass.m[my2][mx2]=0;
							mPosition[1].y=++my2;
							mPosition[1].x=++mx2;
							turn[0]=3;
						}
						else{ //どっちもポップ or 壁なら
							if(my1==13 || mass.m[my1+1][mx1]){ //下にポップか壁があるなら
								mPosition[1].y=++my2; //上のポップを下へ
								mPosition[0].y=--my1; //下のポップを上へ
							}
							else{
								mass.m[my1][mx1]=0;
								--my1;
								mPosition[0].y=--my1; //下のポップを二つ上へ
							}
							turn[0]=0;
						}
					}
					else{ //左が空 もしくは ×
						mass.m[my1][mx1]=0;
						mPosition[0].x=--mx1;
						mPosition[0].y=--my1;
						turn[0]=3;
					}
					break;
				default: // 横 mPosition[0],[1] (1,2)
					mass.m[my1][mx1]=0;
					mPosition[0].x=++mx1;
					mPosition[0].y=--my1;
					turn[0]=0;
				}
			}
			else if(key[KEY_INPUT_D]==1){ //回転判定(左回転)
				switch(turn[0]){
				case 0: // 縦 mPosition[0],[1] (1,2)
					if(mx1==0 || mass.m[my2][mx2-1] && mass.m[my2][mx2-1]!=CROSS){ //左がポップか壁で
						if(mx1!=5 && (!mass.m[my1][mx1+1] || mass.m[my1][mx1+1]==CROSS)){ //右が空か×なら
							mass.m[my1][mx1]=0;
							mPosition[0].y=++my1;
							mPosition[1].x=++mx2;
							turn[0]=3;
						}
						else{ //どっちもポップ or 壁なら
							if(my2==13 || mass.m[my2+1][mx2]){ //下にポップか壁があるなら
								mPosition[0].y=++my1; //上のポップを下へ
								mPosition[1].y=--my2; //下のポップを上へ
							}
							else{
								mass.m[my1][mx1]=0;
								++my1;
								mPosition[0].y=++my1; //上のポップを二つ下へ
							}
							turn[0]=2;
						}
					}
					else{ //左が空 もしくは ×
						mass.m[my1][mx1]=0;
						mPosition[0].x=--mx1;
						mPosition[0].y=++my1;
						turn[0]=3;
					}
					break;
				case 1: // 横 mPosition[1],[0] (2,1)
					mass.m[my1][mx1]=0;
					mPosition[0].x=--mx1;
					mPosition[0].y=--my1;
					turn[0]--;
					break;
				case 2: // 縦 mPosition[1],[0] (2,1)
					if(mx2==5 || mass.m[my2][mx2+1] && mass.m[my2][mx2+1]!=CROSS){ //右がポップか壁で
						if(mx1 && (!mass.m[my1][mx1-1] || mass.m[my1][mx1-1]==CROSS)){ //左が空か×なら
							mass.m[my2][mx2]=0;
							mPosition[1].y=++my2;
							mPosition[1].x=--mx2;
						}
						else{ //どっちもポップ or 壁なら
							if(my1==13 || mass.m[my1+1][mx1]){ //下にポップか壁があるなら
								mPosition[0].y=--my1; //上のポップを下へ
								mPosition[1].y=++my2; //下のポップを上へ
							}
							else{
								mass.m[my1][mx1]=0;
								--my1;
								mPosition[0].y=--my1; //下のポップを二つ上へ
							}
							turn[0]--; //case 0まで飛ばす。
						}
					}
					else{ //右が空 もしくは ×
						mass.m[my1][mx1]=0;
						mPosition[0].x=++mx1;
						mPosition[0].y=--my1;
					}
					turn[0]--;
					break;
				default: // 横 mPosition[0],[1] (1,2)
					mass.m[my1][mx1]=0;
					if(my2==13 || mass.m[my2+1][mx2] && mass.m[my2+1][mx2]!=CROSS){ //右ポップの下がポップか壁なら
						mPosition[0].x=++mx1;
						mPosition[1].y=--my2;
					}
					else{ //左ポップの下が空 もしくは ×
						mPosition[0].x=++mx1;
						mPosition[0].y=++my1;
					}
					turn[0]--;
				}
			}
			mass.m[my1][mx1]=mKind[0];
			mass.m[my2][mx2]=mKind[1];
		}
		if(count[1]==60){ //次のポップ(敵)
			while(Fall(mass,false,mNext,eNext,linkage));
			Sleep(100);
			do{
				checked=copy;
				for(natural x=0;x<6;x++){
					for(natural y=13;y>1;y--){
						natural temp=mass.e[y][x];
						if(temp && temp!=CROSS && temp!=BLOCK && Link(mass,x,y,temp,checked,false)>=4){
							Delete(mass,x,y,temp,false);
							if(!chain[1])chain[1]=true;
						}
					}
				}
				if(!chain[1])break;
				chain[1]=false;
				checked=copy;
				while(Fall(mass,false,mNext,eNext,linkage));
				for(natural x=0;x<6;x++){
					for(natural y=13;y>1;y--){
						natural temp=mass.e[y][x];
						if(temp && temp!=CROSS && temp!=BLOCK && Link(mass,x,y,temp,checked,false)>=4)goto eOut;
					}
				}
				break;
eOut:
				Sleep(800);
			}while(1);
//				if((mass.e[2][2] && mass.e[2][2]!=CROSS) || (mass.e[2][2] && mass.e[2][3]!=CROSS)){
//					DrawString(30,50,"Game Clear!! おめでとう。 3秒後に戻ります。",0x000000);
//					DrawGraph(0,0,background[1],TRUE);
//					ScreenFlip();
//					Sleep(3000);
//					break;
//				}
			time[1]=1;
			eKind[0]=eNext[0];
			eKind[1]=eNext[1];
			eNext[0]=GetRand(RAND)+1;
			eNext[1]=GetRand(RAND)+1;
			ePosition[0].x=2;
			ePosition[0].y=0;
			ePosition[1].x=2;
			ePosition[1].y=1;
			count[1]=0;
			countflag[1]=false;
			turn[1]=0;
		}
		else{
			if(mass.e[2][2]==0)mass.e[2][2]=CROSS;
			if(mass.e[2][3]==0)mass.e[2][3]=CROSS;
			if(time[1]%60==0){
				if(ey1!=13 && ey2!=13){ //一秒ごとにポップを下へ移動(敵)
					if(turn[1]%2==0){
						if(!mass.e[ey1+1][ex1] || !mass.e[ey2+1][ex2] || mass.e[ey1+1][ex1]==CROSS || mass.e[ey2+1][ex2]==CROSS){
							mass.e[ey1][ex1]=0;
							mass.e[ey2][ex2]=0;
							ePosition[0].y=++ey1;
							ePosition[1].y=++ey2;
						}
					}
					else if((!mass.e[ey1+1][ex1] || mass.e[ey1+1][ex1]==CROSS) && (!mass.e[ey2+1][ex2] || mass.e[ey2+1][ex2]==CROSS)){
						mass.e[ey1][ex1]=0;
						mass.e[ey2][ex2]=0;
						ePosition[0].y=++ey1;
						ePosition[1].y=++ey2;
					}
				}
			}
			mass.e[ey1][ex1]=eKind[0];
			mass.e[ey2][ex2]=eKind[1];
		}
		for(int y=-64,i=0;y<=430;y+=38,i++){ //ポップを描く
			for(int x=46,j=0;x<=236;x+=38,j++)mass.m[i][j] && DrawGraph(x,y,data.pop[mass.m[i][j]],TRUE);
			for(int x=366,j=0;x<=556;x+=38,j++)mass.e[i][j] && DrawGraph(x,y,data.pop[mass.e[i][j]],TRUE);
		}
		DrawGraph(0,0,data.image[2],TRUE); //枠(メイン)
		DrawGraph(278,10,data.pop[mNext[0]],TRUE); //次のポップを表示(自分)
		DrawGraph(278,48,data.pop[mNext[1]],TRUE);
		DrawGraph(321,10,data.pop[eNext[0]],TRUE); //次のポップを表示(敵)
		DrawGraph(321,48,data.pop[eNext[1]],TRUE);
		{ // もし時間管理を変数で管理して行う場合は、このwhileループを使うため、↓
			char string[2][3];
			if(linkage[0]){
				sprintf_s(string[0],"%d",linkage[0]);
				linkage[0] && DrawString(278,400,string[0],0x000000); //連鎖数を表示(自分)
				linkage[0]=0;
			}
			if(linkage[1]){
				sprintf_s(string[1],"%d",linkage[1]);
				linkage[1] && DrawString(321,400,string[1],0x000000); //連鎖数を表示(敵)
				linkage[1]=0;
			}
		}
		if(key[KEY_INPUT_ESCAPE]==1)return 0;
		else if(key[KEY_INPUT_RETURN]==1){
			int waitkey;
			DrawString(0,0,"一時停止",0xffffff);
			ScreenFlip();
			while(1){
				waitkey=WaitKey();
				if(waitkey==KEY_INPUT_RETURN)break;
				else if(waitkey==KEY_INPUT_SPACE)goto end;
			};
		}
		if(turn[0]%2==0)if(my1==13 || my2==13 || mass.m[my1+1][mx1] && mass.m[my1+1][mx1]!=CROSS && mass.m[my2+1][mx2] && mass.m[my2+1][mx2]!=CROSS)count[0]++;
		else if(my1==13 && my2==13 || (mass.m[my1+1][mx1] && mass.m[my1+1][mx1]!=CROSS) || (mass.m[my2+1][mx2] && mass.m[my2+1][mx2]!=CROSS))count[0]++;

		if(turn[1]%2==0)if(ey1==13 || ey2==13 || mass.e[ey1+1][ex1] && mass.e[ey1+1][ex1]!=CROSS && mass.e[ey2+1][ex2] && mass.e[ey2+1][ex2]!=CROSS)count[1]++;
		else if(ey1==13 && ey2==13 || (mass.e[ey1+1][ex1] && mass.e[ey1+1][ex1]!=CROSS) || (mass.e[ey2+1][ex2] && mass.e[ey2+1][ex2]!=CROSS))count[1]++;
		time[0]++;
		time[1]++;
		if(time[0]>60)time[0]=1;
		if(time[1]>60)time[1]=1;
	}while(ScreenFlip()==0 && ClearDrawScreen()==0);
	end:
	return 1;
}
static int StoryMode(void){
	return 1;
}
static int FreeMode(void){
	return PopJelly();
}
static int ConfigMode(void){
	return 1;
}
全体を表示すると更に膨大になってしまうため、(PopJelly関数と、その関数に関係のある関数以外は)ところどころ省いています。
質問は、
プレイヤーが連鎖中等のときに、敵の自由落下やその他の動作を動くようにしたい、というものです。
今はSleepで制御しているので、スレッド(?というんでしょうか;)全体を止めることになり、できません。
時間管理用のprocess変数を作って、試行錯誤してみたものの、何が分からないのかも分からなくなるぐらいパニックになってしまい、元に戻しました。。
一応、PopJelly関数にはprocess変数があります。
具体的にどの様に時間管理を実装しようとしたかといいますと、
  1. Sleepを使っている関数 全ての引数にnatural process[2]を追加。
  2. PopJelly関数 メイン描写を担当している whileループ末端にprocess[0]++とprocess[1]++を追加。 (オーバーフローしないようにする方法が分かりませんでした)
  3. 呼び出すときに、processを追加して、其々の関数内で時間をチェックするようにしました。
  4. が! しかし、ループ中にSleep関数があることが多いために、どうすればいいか全く見当がつかず、断念。
と、このようになっております。
具体的にどのようにしたらよいのか、ご教示宜しくお願いします。

後書き:
仕様は次の通りです。
  • タイトルがぷよぷよではなく、ポップ ゼリー
  • ぷよではなく、ポップ
  • おじゃまぷよではなく、ブロックポップ
  • 14段目のポップは連鎖直前に消されます。(ぷよぷよ フィーバー含む、それ以降の仕様?)
  • ブロックポップは連鎖中に相殺、そして、連鎖直後に14段目に配置されて、Fall関数を実行、それを繰り返して降ってきます。(※ 未実装)
  • (注意)このまま実行しても、画像が無いので真っ黒になります。
また、ゲームを作るのは、C言語では初めてです。

Re: DXライブラリを使用したゲームの時間制御について

Posted: 2011年10月24日(月) 19:33
by softya(ソフト屋)
とりあえず見ましたが、なんか制御が複雑なことになっています。
これを他の人が調整することは困難(たぶんご本人も)だと思います。

ここのサイトのメインの一つでありDXライブラリの講座「ゲームプログラミングの館」を例に説明させてもらいます。
「新・C言語 ~ゲームプログラミングの館~ [DXライブラリ]」
http://dixq.net/g/

まず問題は、ProcessMessage()!=やScreenFlip()0があちこちにあったりすることですね。
制御をすっきりするにはメインループはWinMainにひとつだけとすることが望ましいです。

まず、骨格は次のようになります。
「1.9章 ゲームプログラムの骨格の完成」
http://dixq.net/g/01_09.html
このWinMainのDrawGraph()と x = x + 2;の部分に関数を追加していくのが基本形です。

「d1章. メイン関数の書き方」 こんな感じです。
http://dixq.net/g/d_01.html

関数では、かならずWinMainに戻るようにしてSleep()やWaitKey()などは使いません。
じゃあ、どうするかというと今は待機中を示す待機時間のカウンタを用意します。

イメージとしての待機処理。

コード:

// 初期化
static int 待機中カウント = 0;

if( 待機中カウント > 0 ) {
	待機中カウント--;//カウントダウン
} else {
	
	本来の処理
	
	if( 待機が必要? ) {
		待機中カウント = 待機させたいフレーム数
	}
}
これを待機に必要な場所の数だけ用意します。

そのほか気になったこと。
・gotoは必要ないと思います。
・マジックナンバーが多い。マジックナンバーは本人にしか分からない謎の数値のことです。
const intやenumなど定数化するのが分かりやすくするコツです。
・同じような処理が多い。 → 関数化出来ると思います。
・処理と描画が混在している。 処理と描画を分けるとわかりやすくなります。
・PopJellyなど大きな関数がある。 → 機能別に関数に分けることでわかりやすくなります。

ここまで作って直すのは大変だと思いますが、継ぎ足しに継ぎ足しで収取が付かなくなっている印象です。
このソースコードは別保存して、関数の整理などをお勧めします。

Re: DXライブラリを使用したゲームの時間制御について

Posted: 2011年10月25日(火) 02:31
by Loki
softya(ソフト屋) さんが書きました: とりあえず見ましたが、なんか制御が複雑なことになっています。
これを他の人が調整することは困難(たぶんご本人も)だと思います。

まず問題は、ProcessMessage()!=やScreenFlip()0があちこちにあったりすることですね。
制御をすっきりするにはメインループはWinMainにひとつだけとすることが望ましいです。

そのほか気になったこと。
・gotoは必要ないと思います。
・マジックナンバーが多い。マジックナンバーは本人にしか分からない謎の数値のことです。
const intやenumなど定数化するのが分かりやすくするコツです。
・同じような処理が多い。 → 関数化出来ると思います。
・処理と描画が混在している。 処理と描画を分けるとわかりやすくなります。
・PopJellyなど大きな関数がある。 → 機能別に関数に分けることでわかりやすくなります。
ありがとうございます。
御指摘の通り、自分でも何が何だか分からない状態になっていました。
スクリーンに表示するのは、WinMainのみに変更しました。
goto文は無くして、其々適切な処理をしました。
マジックナンバーについては、コメントで説明を加えてみました。
同じような処理とは、具体的にどのようなところでしょうか?
WinMainで表示することによって、解決しました。

今のところは、少ししか直せてませんが、スッキリしてきました^^
アドバイスありがとうございます。
全体が修正出来次第、本題に取り掛かり、上手く行かなければ追記、完成したら、解決という形にしたいと思います。
宜しくお願いします。

Re: DXライブラリを使用したゲームの時間制御について

Posted: 2011年10月25日(火) 10:45
by softya(ソフト屋)
・マジックナンバーについては、コメントで説明を加えてみました。
出来るだけ名前をつけてください。つまり、int countやenumです。

・同じような処理とは、具体的にどのようなところでしょうか?

例えばですか? いっぱいあるんですが。
これと

コード:

   if(flag) //自分
        for(int x=0;x<6;x++) //一番左から
            for(int y=13,i;y>=0;y--){ //一番下から
                if(mass.m[y][x]==0){ //空のマスなら
                    for(i=y-1;i>=0 && (mass.m[i][x]==0 || mass.m[i][x]==CROSS);i--); //空のマスと、×は飛ばす
                    if(i<0)break; //上にポップがない
                    if(!n)n=1; //ループ用
                    for(i=y;i>=0;i--)
                        if(mass.m[i][x]!=CROSS)
                            mass.m[i][x]=i>0 && mass.m[i-1][x]!=CROSS ? mass.m[i-1][x] : 0; //このマスをすぐ上のマスに。一番上か、上が×なら、空にする
                    if(mass.m[2][2]==0)mass.m[2][2]=CROSS; //×の位置
                    if(mass.m[2][3]==0)mass.m[2][3]=CROSS;
                    if(mass.e[2][2]==0)mass.e[2][2]=CROSS;
                    if(mass.e[2][3]==0)mass.e[2][3]=CROSS;
                    for(int y=-64,i=0;y<=430;y+=38,i++){
                        for(int x=46,j=0;x<=236;x+=38,j++)mass.m[i][j] && DrawGraph(x,y,data.pop[mass.m[i][j]],TRUE);
                        for(int x=366,j=0;x<=556;x+=38,j++)mass.e[i][j] && DrawGraph(x,y,data.pop[mass.e[i][j]],TRUE);
                    }
                    DrawGraph(0,0,data.image[2],TRUE);      //枠(背景)
                    DrawGraph(278,10,data.pop[mNext[0]],TRUE); //次のポップを表示(自分)
                    DrawGraph(278,48,data.pop[mNext[1]],TRUE);
                    DrawGraph(321,10,data.pop[eNext[0]],TRUE); //次のポップを表示(敵)
                    DrawGraph(321,48,data.pop[eNext[1]],TRUE);
                    linkage[0] && DrawString(278,400,string[0],0x000000); //連鎖数を表示(自分)
                    linkage[1] && DrawString(321,400,string[1],0x000000); //連鎖数を表示(敵)
                    if(!(ScreenFlip()==0 && ProcessMessage()==0 && ClearDrawScreen()==0))return 0;
                    DrawGraph(0,0,data.image[1],TRUE);      //枠(メイン)
                    Sleep(50);
                    break;
                }
            }
これとか

コード:

        for(int x=0;x<6;x++)
            for(int y=13,i;y>=0;y--){
                if(mass.e[y][x]==0){
                    for(i=y-1;i>=0 && (mass.e[i][x]==0 || mass.e[i][x]==CROSS);i--);
                    if(i<0)break;
                    if(!n)n=1;
                    for(i=y;i>=0;i--)
                        if(mass.e[i][x]!=CROSS)
                            mass.e[i][x]=i>0 && mass.e[i-1][x]!=CROSS ? mass.e[i-1][x] : 0;
                    if(mass.m[2][2]==0)mass.m[2][2]=CROSS;
                    if(mass.m[2][3]==0)mass.m[2][3]=CROSS;
                    if(mass.e[2][2]==0)mass.e[2][2]=CROSS;
                    if(mass.e[2][3]==0)mass.e[2][3]=CROSS;
                    for(int y=-64,i=0;y<=430;y+=38,i++){
                        for(int x=46,j=0;x<=236;x+=38,j++)mass.m[i][j] && DrawGraph(x,y,data.pop[mass.m[i][j]],TRUE);
                        for(int x=366,j=0;x<=556;x+=38,j++)mass.e[i][j] && DrawGraph(x,y,data.pop[mass.e[i][j]],TRUE);
                    }
                    DrawGraph(0,0,data.image[2],TRUE);
                    DrawGraph(278,10,data.pop[mNext[0]],TRUE);
                    DrawGraph(278,48,data.pop[mNext[1]],TRUE);
                    DrawGraph(321,10,data.pop[eNext[0]],TRUE);
                    DrawGraph(321,48,data.pop[eNext[1]],TRUE);
                    linkage[0] && DrawString(278,400,string[0],0x000000);
                    linkage[1] && DrawString(321,400,string[1],0x000000);
                    if(!(ScreenFlip()==0 && ProcessMessage()==0 && ClearDrawScreen()==0))return 0;
                    DrawGraph(0,0,data.image[1],TRUE);
                    Sleep(35);
                    break;
                }
            }
凄く関数にまとめられそうです。

これとかもmass.mとmass.eの違いしかありませんので引数で工夫すれば関数にまとめられます。

コード:

    if(flag){
        if(checked.m[y][x]==1)return 0; //既にチェック済み
        checked.m[y][x]=1;
        if(mass.m[y][x]==0 || mass.m[y][x]==BLOCK || mass.m[y][x]==CROSS)return 0; //空かブロックポップか×
        if(y>2 && mass.m[y-1][x]==kind)number+=Link(mass,x,y-1,kind,checked,flag); //上
        if(x<5 && mass.m[y][x+1]==kind)number+=Link(mass,x+1,y,kind,checked,flag); //右
        if(x>0 && mass.m[y][x-1]==kind)number+=Link(mass,x-1,y,kind,checked,flag); //左
        if(y<13 && mass.m[y+1][x]==kind)number+=Link(mass,x,y+1,kind,checked,flag); //下
    }
    else{
        if(checked.e[y][x]==1)return 0; //既にチェック済み
        checked.e[y][x]=1;
        if(mass.e[y][x]==0 || mass.e[y][x]==BLOCK || mass.e[y][x]==CROSS)return 0; //空かブロックポップか×
        if(y>2 && mass.e[y-1][x]==kind)number+=Link(mass,x,y-1,kind,checked,flag); //上
        if(x<5 && mass.e[y][x+1]==kind)number+=Link(mass,x+1,y,kind,checked,flag); //右
        if(x>0 && mass.e[y][x-1]==kind)number+=Link(mass,x-1,y,kind,checked,flag); //左
        if(y<13 && mass.e[y+1][x]==kind)number+=Link(mass,x,y+1,kind,checked,flag); //下
    }

Re: DXライブラリを使用したゲームの時間制御について

Posted: 2011年11月14日(月) 01:32
by Loki
次のように実装してみる予定なのですが、毎回switch - case文を通っても、大丈夫なのでしょうか。
※イメージ
  • WinMain内は、宣言に重点を置きました。

コード:

enum{END=-1}manage;
enum{TITLE,STORY,FREE,CONFIG}mode;
static void StartScreen(void){
	natural mode=TITLE; //モード選択
	bool error=false; //エラー用
	char key[256]; //キー情報保存用
//各関数ごとの変数宣言
	//Title
		natural title_select=0;
		struct MENU title_menu[4]={ //メニュー
			{32,320,5,55,370,"ストーリー"},
			{184,320,4,210,370,"自由練習"},
			{338,320,4,355,370,"コンフィグ"},
			{492,320,4,540,370,"終了"}
		};
//宣言終了
	PlaySoundMem(data.music[0],DX_PLAYTYPE_LOOP); //音楽再生
	while(1){
		if(ScreenFlip()==END || ProcessMessage()==END || ClearDrawScreen()==END)break; //失敗したら終了
		UpdateKey(key);
		switch(mode){
		case TITLE:
			{
				count returnValue=Title(key,title_menu,title_select);
				if(returnValue==END)error=true;
				else if(returnValue){
					mode=returnValue;
				}
			}
			break;
		case STORY:
			if(Story(key)==END)error=true;
			break;
		case FREE:
			if(Free(key)==END)error=true;
			break;
		case CONFIG:
			if(Config(key)==END)error=true;
			break;
		default: //終了 または、例外
			error=true;
			break;
		}
		if(error)break;
	}
}
int WINAPI WinMain(~){
[tab=30]DxLib_Init();
[tab=30]画像等を、一気に宣言&読み込み
[tab=30]StartScreen();
[tab=30]DxLib_End();
[tab=30]return 0;
}
ところで、END は ERRORの方が適しているのでしょうか。
オフトピック
プレビューの際に、[ tab=nn ]が正常動作せずに、
[ tab=30:変な文字 ]となってしまいます。

Re: DXライブラリを使用したゲームの時間制御について

Posted: 2011年11月14日(月) 08:55
by softya(ソフト屋)
Loki さんが書きました:次のように実装してみる予定なのですが、毎回switch - case文を通っても、大丈夫なのでしょうか。
何の問題もありませんが、StartScreen関数内でStartScreenと言う関数目にふさわしくないことをするのは止めた方が良いでしょう。
このswitch - case文はWinMainにあったほうが良いと思います。
Loki さんが書きました:ところで、END は ERRORの方が適しているのでしょうか。
errorなのかendなのか兼用するのはやめたほうが良いと思います。
意味を明確にしてください。

Re: DXライブラリを使用したゲームの時間制御について

Posted: 2012年2月18日(土) 18:52
by Loki
オフトピック
なかなか時間が無くて、久しぶりに時間が取れたので、少し編集にとりかかりました。
http://mathoff.rosx.net/source.cpp
ソース全体は、こういう風になりました。
もともとERRORは定義されていましたが、書き換えて-1にしたんですが、いいんでしょうか。

今頃↓の意味がわかり、実行しようとしたのですが、どんなふうにすればいいのでしょうか。

コード:

static int 待機中カウント = 0;

if( 待機中カウント > 0 ) {
    待機中カウント--;//カウントダウン
} else {
    
    本来の処理
    
    if( 待機が必要? ) {
        待機中カウント = 待機させたいフレーム数
    }
}
つまり、こういうことですよね。

コード:

strict int count[2]={0,0}; //自分,敵
while(1){
	if(count[0]>0){ //自分が待機する
		count[0]--;
	}
	else{
		if(連鎖中?){
			連鎖
		}
		else{
			自分の処理
		}
	}
	if(count[1]>0){ //敵が待機する
		count[1]--;
	}
	else{
		if(連鎖中?){
			連鎖
		}
		else{
			敵の処理
		}
	}
}
毎回、Menu関数内のwhileで表示させているのですが、それだと上記のような待機処理を、どこに入れたらいいのか分かりません。
Story,Free,Configのようにいくつかのモードがあり、その中にもFreeの中でもAモード,Bモードのようにあり、StoryではStory中に戦闘とかがあります。

因みに、このまま実行してしまうと(フリーモードの場合)、WinMain→Menu→(Free→PopJelly)無限ループ
このように無限ループになってしまい、while一つでは、かなり厳しい状態です。
Menu→Free→PopJelly→Free→PopJellyのようなループはいいのですが、PopJelly関数を実行する度に変数が毎回初期化されます。
これもまた改善したいです。改善方法は分かるのですが、Menu関数内に変数が増えて行くばかりです。
本来(完成形)の実行順は、次のようになります。
WinMain→Menu→Free→ModeA→(PopJelly)ループ→敗北 or 勝利→Menu
大まかにはこんな感じです。

ぷよぷよって意外と難しいですね……
ゲームの中では簡単な方なはずなのですが。。
どの辺に時間制御を入れれば良いのか、教えてください。

Re: DXライブラリを使用したゲームの時間制御について

Posted: 2012年2月18日(土) 21:45
by softya(ソフト屋)
Loki さんが書きました:
オフトピック
なかなか時間が無くて、久しぶりに時間が取れたので、少し編集にとりかかりました。
http://mathoff.rosx.net/source.cpp
ソース全体は、こういう風になりました。
もともとERRORは定義されていましたが、書き換えて-1にしたんですが、いいんでしょうか。
DXライブラリのエラーは-1なのでERRORを変えるとマズイでしょうね。
これを質問されるということは何らかのベースにしているプログラムがあってご自分が理解されていない部分があると言うことでしょうか?
Loki さんが書きました: 今頃↓の意味がわかり、実行しようとしたのですが、どんなふうにすればいいのでしょうか。

コード:

static int 待機中カウント = 0;

if( 待機中カウント > 0 ) {
    待機中カウント--;//カウントダウン
} else {
    
    本来の処理
    
    if( 待機が必要? ) {
        待機中カウント = 待機させたいフレーム数
    }
}
つまり、こういうことですよね。

コード:

strict int count[2]={0,0}; //自分,敵
while(1){
	if(count[0]>0){ //自分が待機する
		count[0]--;
	}
	else{
		if(連鎖中?){
			連鎖
		}
		else{
			自分の処理
		}
	}
	if(count[1]>0){ //敵が待機する
		count[1]--;
	}
	else{
		if(連鎖中?){
			連鎖
		}
		else{
			敵の処理
		}
	}
}
毎回、Menu関数内のwhileで表示させているのですが、それだと上記のような待機処理を、どこに入れたらいいのか分かりません。
Story,Free,Configのようにいくつかのモードがあり、その中にもFreeの中でもAモード,Bモードのようにあり、StoryではStory中に戦闘とかがあります。
ProcessMessage()のwhileループをひとつにしないといけません。mainにあるwhileループだけにしましょう。
そうするためには待機処理は、上のような待機処理にするしか有りません。
各モードの振り分けもモードの変数を持てば今どの処理をするかは振り分けられます。
多段的に複数のモードがあれば、2段目、3段目用のモード変数をそれぞれ持ちます。
Loki さんが書きました: 因みに、このまま実行してしまうと(フリーモードの場合)、WinMain→Menu→(Free→PopJelly)無限ループ
このように無限ループになってしまい、while一つでは、かなり厳しい状態です。
Menu→Free→PopJelly→Free→PopJellyのようなループはいいのですが、PopJelly関数を実行する度に変数が毎回初期化されます。
これもまた改善したいです。改善方法は分かるのですが、Menu関数内に変数が増えて行くばかりです。
本来(完成形)の実行順は、次のようになります。
WinMain→Menu→Free→ModeA→(PopJelly)ループ→敗北 or 勝利→Menu
大まかにはこんな感じです。
プログラムの構造によりますが、staticな変数にするとか出来ませんか?
あるいは引数にするにしても構造体に纏めることで解決しませんか?

普通のゲームはwhile一つで回していますので、ちゃんと組めば問題なく動くようになります。
複雑なRPGやSLGでもmainのwhileループひとつで作りますので、そうしないと逆に色々な事で困ることになります。
現状がそういう状態だと思います。
Loki さんが書きました: ぷよぷよって意外と難しいですね……
ゲームの中では簡単な方なはずなのですが。。
どの辺に時間制御を入れれば良いのか、教えてください。
状態制御が色々とあるので簡単とは言えないと思いますね。
テトリスのほうが簡単です。

Re: DXライブラリを使用したゲームの時間制御について

Posted: 2012年2月19日(日) 15:28
by Loki
時間制御はどうにかなりそうです。
ありがとうございます。

しかし、
http://mathoff.rosx.net/source.cpp

コード:

const struct MASS popjelly_mass_copy={ //フィールド初期化用
	{ //自分
		{0,0,0,0,0,0}, //この列に積んだら消す
		{3,1,0,0,1,1},
		{3,3,3,2,1,3},
		{2,3,1,1,2,1},
		{3,1,2,2,1,3},
		{1,2,1,3,2,3},
		{2,1,3,2,1,3},
		{1,2,1,3,2,1},
		{1,2,1,3,2,1},
		{1,3,3,2,1,2},
		{3,1,2,3,2,2},
		{2,3,1,2,3,1},
		{2,3,1,2,3,1},
		{2,3,1,2,3,1}
	},
	{ //敵
		{0,0,0,0,0,0},
		{0,0,0,0,0,0},
		{0,0,0,0,0,0},
		{0,0,0,0,0,0},
		{0,0,0,0,0,0},
		{0,0,0,0,0,0},
		{0,0,0,0,0,0},
		{0,0,0,0,0,0},
		{0,0,0,0,0,0},
		{0,0,0,0,0,0},
		{0,0,0,0,0,0},
		{0,0,0,0,0,0},
		{0,0,0,0,0,0},
		{0,0,0,0,0,0}
	}
};
敵は最初から、空なので問題ないのですが、自分の場合連鎖の種を初期化させているのに、PopJelly関数を実行させると、

コード:

	{0,0,0,0,0,0}, //この列に積んだら消す
	{3,1,0,0,1,1},
	{3,3,3,2,1,3},
	{2,3,1,1,2,1},
が、

コード:

	{0,0,0,0,0,0}, //この列に積んだら消す
	{0,0,0,0,1,1},
	{0,0,0,2,1,3},
	{2,0,1,1,2,1},
ように変化してしまいます。
上二行は合っているかどうか分かりません。(データではなく、画像で判断しています。上二行は隠れるようになっているので)
どの関数をみても、間違いがあるようには思えず……
また、DXライブラリのGetRand関数は、毎回違うはずなのに、同じになってしまいます。

コード:

natural popjelly_mKind[2]={GetRand(RAND)+1,GetRand(RAND)+1}; //ポップの種類(上,下)(自分)
natural popjelly_eKind[2]={GetRand(RAND)+1,GetRand(RAND)+1}; //ポップの種類(上,下)(敵)
natural popjelly_mNext[2]={GetRand(RAND)+1,GetRand(RAND)+1}; //次のポップ(上,下)(自分)
natural popjelly_eNext[2]={GetRand(RAND)+1,GetRand(RAND)+1}; //次のポップ(上,下)(敵)
上記2つの点、御回答宜しくお願いします。

Re: DXライブラリを使用したゲームの時間制御について

Posted: 2012年2月19日(日) 15:40
by みけCAT
Loki さんが書きました:また、DXライブラリのGetRand関数は、毎回違うはずなのに、同じになってしまいます。

コード:

natural popjelly_mKind[2]={GetRand(RAND)+1,GetRand(RAND)+1}; //ポップの種類(上,下)(自分)
natural popjelly_eKind[2]={GetRand(RAND)+1,GetRand(RAND)+1}; //ポップの種類(上,下)(敵)
natural popjelly_mNext[2]={GetRand(RAND)+1,GetRand(RAND)+1}; //次のポップ(上,下)(自分)
natural popjelly_eNext[2]={GetRand(RAND)+1,GetRand(RAND)+1}; //次のポップ(上,下)(敵)
グローバル領域で初期化していて、DxLib_Init()より前に呼ばれている影響かもしれません。
自信はありませんが。

Re: DXライブラリを使用したゲームの時間制御について

Posted: 2012年2月19日(日) 16:10
by softya(ソフト屋)
ソースを見ても目視トレースが困難なプログラムなので実際に実行してみないと何処が悪いか皆目検討が付きません。
データをいただけないでしょうか。何処かで公開されているものなら元の方のURLを教えて下さい。

Re: DXライブラリを使用したゲームの時間制御について

Posted: 2012年2月19日(日) 18:54
by Loki
配布されているものではありません。

http://mathoff.rosx.net/upload/pop-jelly.zipです。
画像と音量に注意して下さい。
画像は、友達にかいて貰ったものです。
左右のボタンで選択、「自由練習」へと進んで下さい。
mPopJellyとePopJellyの間には、Sleep(500) (デバッグ用)が入っているので、少々重たくなります。
グローバル領域で初期化していて、DxLib_Init()より前に呼ばれている影響かもしれません。
分かりました。試してみます。

Re: DXライブラリを使用したゲームの時間制御について

Posted: 2012年2月19日(日) 19:33
by softya(ソフト屋)
試して見ましたが、言われているような変化が起きません。
------------------ mPopJelly後
0 0 0 0 0 0
1 1 0 0 1 1
2 2 0 2 1 3
2 3 1 1 2 1
3 1 2 2 1 3
1 2 1 3 2 3
2 1 3 2 1 3
1 2 1 3 2 1
1 2 1 3 2 1
1 3 3 2 1 2
3 1 2 3 2 2
2 3 1 2 3 1
2 3 1 2 3 1
2 3 1 2 3 1
表示方法は、次のテクニックを使ってプログラムを改造してあります。
「簡単RPG講座 番外編。 デバッグ入門 • C言語交流フォーラム ~ mixC++ ~」
http://dixq.net/forum/blog.php?u=114&b=982&c=2

改造したプログラム。

コード:

#include "DxLib.h"
#define ELEMENTS 6 //data.popの要素数
#define CROSS ELEMENTS-1 //×
#define BLOCK CROSS-1 //BLOCK
#define RAND BLOCK-2 //乱数に使う
#define WIDTH 6 //マスの数 横
#define HEIGHT 14 //マスの数 縦
#define isMusicOn 0 //デバッグ用 曲を流す1 or 流さない0
#define isEffectOn 0 //デバッグ用 効果音あり1 or なし0
#define LIMIT 60 //床についてから、どのくらい停止を許可するか
//プロトタイプ宣言
typedef unsigned short int natural;
typedef const short int invariant;
typedef short int count;
struct MASS {
	natural m[14][6], e[14][6];
};
struct MENU {
	invariant imgX, imgY;
	int handle;
	invariant nameX, nameY;
	const char name[128];
};
struct {
	int image[6], pop[ELEMENTS], character[5], effect[4], music[1];
} data;
struct popjelly_COORDINATE {
	natural x, y;
};
static void Menu( void );
static void UpdateKey( char *KeyStateBuf );
static count Title( char *key, MENU menu[4], natural &tselect );
static void DrawButtons_title( MENU menu[4] );
static void Message( const char name[], const char message[] );
static natural Fall( natural mass[HEIGHT][WIDTH] );
static natural Link( natural mass[HEIGHT][WIDTH], natural x, natural y, natural kind, natural checked[HEIGHT][WIDTH] );
static void Delete( natural mass[HEIGHT][WIDTH], natural x, natural y, natural kind );
static void init_popjelly( void );
static bool mPopJelly( popjelly_COORDINATE position[2], int &count, natural mass[HEIGHT][WIDTH], natural checked[HEIGHT][WIDTH], natural &process, char key[256] );
static bool ePopJelly( popjelly_COORDINATE position[2], int &count, natural mass[HEIGHT][WIDTH], natural checked[HEIGHT][WIDTH], natural &process );
static count PopJelly( char *key, natural level );
static count Story( char *key );
static count Free( char *key );
static count Config( char *key );
int popjelly_count[2] = {LIMIT, LIMIT}; //ポップが床等に最初に付いてからの経過時間 再度離れた場合は、少し減らす ついてから下を押すと増やす
natural popjelly_time[2] = {1, 1}; //1/60秒に一回1増加。 1秒たつと、1に初期化。(自分,敵)
natural popjelly_process[2] = {0, 0}; //時間制御用変数
natural popjelly_turn[2] = {0, 0}; //回転回数(自分,敵)
natural popjelly_linkage[2] = {0, 0}; //連鎖数(自分,敵)
natural popjelly_block[2] = {0, 0}; //BLOCK ポップの数(自分,敵)
bool popjelly_chain[2] = {false, false}; //連鎖フラグ(自分,敵)
bool popjelly_countflag[2] = {false, false}; //カウントフラグ(自分,敵)
char popjelly_key[256]; //キー保存用
natural popjelly_mKind[2] = {GetRand( RAND ) + 1, GetRand( RAND ) + 1}; //ポップの種類(上,下)(自分)
natural popjelly_eKind[2] = {GetRand( RAND ) + 1, GetRand( RAND ) + 1}; //ポップの種類(上,下)(敵)
natural popjelly_mNext[2] = {GetRand( RAND ) + 1, GetRand( RAND ) + 1}; //次のポップ(上,下)(自分)
natural popjelly_eNext[2] = {GetRand( RAND ) + 1, GetRand( RAND ) + 1}; //次のポップ(上,下)(敵)
struct popjelly_COORDINATE popjelly_mPosition[2] = {{2, 0}, {2, 1}}; //ポップの場所(x,y)(自分)
struct popjelly_COORDINATE popjelly_ePosition[2] = {{2, 0}, {2, 1}}; //ポップの場所(x,y)(敵)
const struct MASS popjelly_copy = {}; //チェック用の初期化用
struct MASS popjelly_checked; //チェック用
const struct MASS popjelly_mass_copy = { //フィールド初期化用
	{
		//自分
		{0, 0, 0, 0, 0, 0}, //この列に積んだら消す
		{3, 1, 0, 0, 1, 1},
		{3, 3, 3, 2, 1, 3},
		{2, 3, 1, 1, 2, 1},
		{3, 1, 2, 2, 1, 3},
		{1, 2, 1, 3, 2, 3},
		{2, 1, 3, 2, 1, 3},
		{1, 2, 1, 3, 2, 1},
		{1, 2, 1, 3, 2, 1},
		{1, 3, 3, 2, 1, 2},
		{3, 1, 2, 3, 2, 2},
		{2, 3, 1, 2, 3, 1},
		{2, 3, 1, 2, 3, 1},
		{2, 3, 1, 2, 3, 1}
	},
	{
		//敵
		{0, 0, 0, 0, 0, 0},
		{0, 0, 0, 0, 0, 0},
		{0, 0, 0, 0, 0, 0},
		{0, 0, 0, 0, 0, 0},
		{0, 0, 0, 0, 0, 0},
		{0, 0, 0, 0, 0, 0},
		{0, 0, 0, 0, 0, 0},
		{0, 0, 0, 0, 0, 0},
		{0, 0, 0, 0, 0, 0},
		{0, 0, 0, 0, 0, 0},
		{0, 0, 0, 0, 0, 0},
		{0, 0, 0, 0, 0, 0},
		{0, 0, 0, 0, 0, 0},
		{0, 0, 0, 0, 0, 0}
	}
};
struct MASS popjelly_mass = popjelly_mass_copy; //フィールド用
static enum {END = -1} manage;
enum {TITLE, STORY, FREE, CONFIG} mode;
/*Music htt-p://nochiko.websozai.jp/
~~~:(width,height)
スクリーン:640,480
ぷよ:38,38
ぷよが置けるエリア:228,456
余白:46,12
プレイヤーと敵の間:92

~~~:自分(x,y) 敵(x,y)
ぷよが置けるエリア:46,12 366,12
×の位置:122,12と160,12 442,12と480,120

~~~:補足
横のマス数 6
縦のマス数 13 (+1 {非表示})

_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
                        【要注意】
Releaseする時には、pop-jellyフォルダを
ドキュメント/DxLib_VC/Toolにあるやつでdxaファイルにし、
D:\pop-jellyにコピーして、圧縮すること。
SetOutApplicationLogValidFlagをFALSEに設定すること。
_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
*/
int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow )
{
    AllocConsole();
    freopen("CONOUT$", "w", stdout); //標準出力をコンソールにする
//  printf( "これでprintfが使えます\n" );   //←お試し用

	if( ChangeWindowMode( TRUE ) == END || SetGraphMode( 640, 480, 16 ) != DX_CHANGESCREEN_OK || DxLib_Init() == END )return END;
	if( SetOutApplicationLogValidFlag( TRUE ) == END || SetAlwaysRunFlag( TRUE ) == END || SetDrawScreen( DX_SCREEN_BACK ) == END || SetWindowText( "ポップ ゼリー" ) == END ) {
		DxLib_End();
		return 0;
	}
//宣言
	//画像全般
	data.image[0] = LoadGraph( "./pop-jelly/Image/background/title.png" ); //タイトル
	data.image[1] = LoadGraph( "./pop-jelly/Image/background/background.png" ); //ポップゼリー メイン背景
	data.image[2] = LoadGraph( "./pop-jelly/Image/background/frame.png" ); //ポップゼリー フレーム部分
	data.image[3] = LoadGraph( "./pop-jelly/Image/message.png" ); //メッセージ表示領域
	data.image[4] = LoadGraph( "./pop-jelly/Image/select.png" ); //選択ボタン
	data.image[5] = LoadGraph( "./pop-jelly/Image/select_now.png" ); //現在選択中のもの
	//ポップ画像
	data.pop[0] = 0;
	data.pop[1] = LoadGraph( "./pop-jelly/Image/pop/red.png" ); //赤ポップ
	data.pop[2] = LoadGraph( "./pop-jelly/Image/pop/blue.png" ); //青ポップ
	data.pop[3] = LoadGraph( "./pop-jelly/Image/pop/green.png" ); //緑ポップ
//		data.pop[4]=LoadGraph("./pop-jelly/Image/pop/pink.png"); //ピンクポップ
	data.pop[4] = LoadGraph( "./pop-jelly/Image/pop/block.png" ); //ブロックポップ
	data.pop[5] = LoadGraph( "./pop-jelly/Image/pop/cross.png" ); //×
	//キャラクター画像
	data.character[0] = LoadGraph( "./pop-jelly/Image/character/slime1.png" ); //アースLv1
	data.character[1] = LoadGraph( "./pop-jelly/Image/character/slime2.png" ); //アースLv2
	data.character[2] = LoadGraph( "./pop-jelly/Image/character/slime3.png" ); //アースLv3
	data.character[3] = LoadGraph( "./pop-jelly/Image/character/slime4.png" ); //アースLv4
	data.character[4] = LoadGraph( "./pop-jelly/Image/character/sun.png" ); //サン
	//効果音
	data.effect[0] = LoadSoundMem( "./pop-jelly/Music/message.ogg" ); //次のメッセージへ移る時
	data.effect[1] = LoadSoundMem( "./pop-jelly/Music/select.ogg" ); //選択効果音
	data.effect[2] = LoadSoundMem( "./pop-jelly/Music/enter.ogg" ); //決定音
	data.effect[3] = LoadSoundMem( "./pop-jelly/Music/story/vire.ogg" ); //剣が当たる音
	//音楽
	data.music[0] = LoadSoundMem( "./pop-jelly/Music/title.ogg" ); //タイトル
//宣言 終了
	Menu();
	DxLib_End();
	return 0;
}
static void Menu( void )
{
	natural mode = TITLE; //モード選択
	bool end = false; //終了用
	char key[256]; //キー情報保存用
//各関数ごとの変数宣言
	//Title
	natural title_select = 0;
	struct MENU title_menu[4] = { //メニュー
		{32, 320, 5, 55, 370, "ストーリー"},
		{184, 320, 4, 210, 370, "自由練習"},
		{338, 320, 4, 355, 370, "コンフィグ"},
		{492, 320, 4, 540, 370, "終了"}
	};
//宣言終了
#if isMusicOn
	PlaySoundMem( data.music[0], DX_PLAYTYPE_LOOP ); //音楽再生
#endif
	while( 1 ) {
		if( ScreenFlip() == END || ProcessMessage() == END || ClearDrawScreen() == END )break; //失敗したら終了
		UpdateKey( key );
		switch( mode ) {
		case TITLE: {
				count returnValue = Title( key, title_menu, title_select );
				if( returnValue == END )end = true;
				else if( returnValue ) {
					mode = returnValue;
				}
			}
			break;
		case STORY:
			if( Story( key ) == END )end = true;
			break;
		case FREE:
			if( Free( key ) == END )end = true;
			break;
		case CONFIG:
			if( Config( key ) == END )end = true;
			break;
		default: //終了 または、例外
			end = true;
			break;
		}
		if( end )break;
	}
}
static void UpdateKey( char *KeyStateBuf )
{
	char key[256];
	GetHitKeyStateAll( key );
	for( natural i = 0; i < 256; i++ ) {
		if( key[i] == 0 )KeyStateBuf[i] = 0;
		else KeyStateBuf[i]++;
	}
}//完全実装 不具合なし
static count Title( char *key, MENU menu[4], natural &tselect )
{
	DrawGraph( 0, 0, data.image[0], FALSE ); //背景描写
	int right = key[KEY_INPUT_RIGHT], left = key[KEY_INPUT_LEFT]; //キー取得
	if( key[KEY_INPUT_RETURN] == 1 ) { //Enterキー押した
#if isMusicOn
		StopSoundMem( data.music[0] ); //音楽を止める
#endif
#if isEffectOn
		PlaySoundMem( data.effect[2], DX_PLAYTYPE_BACK ); //キーを押した音
#endif
		DrawButtons_title( menu ); //ボタンの表示
		return tselect + 1; //選択したボタン+1を返して終了
	} else if( key[KEY_INPUT_ESCAPE] == 1 ) { //Escapeキーを押した
		DrawButtons_title( menu ); //ボタンの表示
		return END; //終了
	} else if( left == 1 || left > 35 && left % 5 == 0 ) { //左を押した
		if( left == 125 )key[KEY_INPUT_LEFT] = 34; //オーバーフロー対策用
		menu[tselect].handle = 4; //現在選択中の要素は選択中ではない画像に
		tselect = ( tselect + 3 ) % 4; //左を計算
		menu[tselect].handle = 5; //選択中になった要素は/を選択中の画像に
#if isEffectOn
		PlaySoundMem( data.effect[1], DX_PLAYTYPE_BACK ); //選択音
#endif
	} else if( right == 1 || right > 35 && right % 5 == 0 ) { //右を押した
		if( right == 125 )key[KEY_INPUT_RIGHT] = 34; //オーバーフロー対策用
		menu[tselect].handle = 4; //現在選択中の要素は選択中ではない画像に
		tselect = ( tselect + 1 ) % 4; //右を計算
		menu[tselect].handle = 5; //選択中になった要素を選択中の画像に
#if isEffectOn
		PlaySoundMem( data.effect[1], DX_PLAYTYPE_BACK ); //選択音
#endif
	}
	DrawButtons_title( menu ); //ボタンの表示
	return TITLE; //TITLE画面の表示を継続
}
static void DrawButtons_title( MENU menu[4] )
{
	DrawGraph( menu[0].imgX, menu[0].imgY, data.image[menu[0].handle], TRUE ); //ボタン画像
	DrawString( menu[0].nameX, menu[0].nameY, menu[0].name, GetColor( 255, 255, 255 ) ); //ボタン内容
	DrawGraph( menu[1].imgX, menu[1].imgY, data.image[menu[1].handle], TRUE ); //ボタン画像
	DrawString( menu[1].nameX, menu[1].nameY, menu[1].name, GetColor( 255, 255, 255 ) ); //ボタン内容
	DrawGraph( menu[2].imgX, menu[2].imgY, data.image[menu[2].handle], TRUE ); //ボタン画像
	DrawString( menu[2].nameX, menu[2].nameY, menu[2].name, GetColor( 255, 255, 255 ) ); //ボタン内容
	DrawGraph( menu[3].imgX, menu[3].imgY, data.image[menu[3].handle], TRUE ); //ボタン画像
	DrawString( menu[3].nameX, menu[3].nameY, menu[3].name, GetColor( 255, 255, 255 ) ); //ボタン内容
}
static void Message( const char name[], const char message[] )
{
	DrawGraph( 10, 340, data.image[3], TRUE );
	DrawString( 40, 375, name, 0xffffff );
	DrawString( 80, 400, message, 0xffffff );
}//不完全実装 画像適当文字適当
static natural Fall( natural mass[HEIGHT][WIDTH] )
{
	natural n = 0;
	for( natural x = 0; x < WIDTH; x++ ) //一番左から
		for( natural y = HEIGHT - 1; y > 0; y-- ) //一番下から(14段目を除く)
			if( mass[y][x] == 0 ) { //空のマスなら
				count i;
				for( i = y - 1; i >= 0 && ( mass[i][x] == 0 || mass[i][x] == CROSS ); i-- ); //空のマスと、×は飛ばす
				if( i < 0 )break; //上にポップがない
				n++; //ループ用
				for( i = y; i >= 0; i-- )mass[i][x] != CROSS && ( mass[i][x] = i ) > 0 && mass[i - 1][x] != CROSS ? mass[i - 1][x] : 0; //このマスをすぐ上のマスに。一番上か、上が×なら、空にする
				break;
			}
	return n;
}//完全実装済み 不具合なし?
static natural Link( natural mass[HEIGHT][WIDTH], natural x, natural y, natural kind, natural checked[HEIGHT][WIDTH] )
{
	natural chain = 1;
	if( checked[y][x] == 1 )return 0; //既にチェック済み
	checked[y][x] = 1;
	if( mass[y][x] == 0 || mass[y][x] == BLOCK || mass[y][x] == CROSS )return 0; //空かブロックポップか×
	if( y > 2 && mass[y - 1][x] == kind )chain += Link( mass, x, y - 1, kind, checked ); //上(見えない部分は除く)
	if( x < 5 && mass[y][x + 1] == kind )chain += Link( mass, x + 1, y, kind, checked ); //右
	if( x > 0 && mass[y][x - 1] == kind )chain += Link( mass, x - 1, y, kind, checked ); //左
	if( y < 13 && mass[y + 1][x] == kind )chain += Link( mass, x, y + 1, kind, checked ); //下
	return chain; //結合数
}//完成
static void Delete( natural mass[HEIGHT][WIDTH], natural x, natural y, natural kind )
{
	if( mass[y][x] == kind ) {
		mass[y][x] = 0; //消す
		if( y > 2 && mass[y - 1][x] == kind )Delete( mass, x, y - 1, kind ); //上(見えない部分は除く)
		if( x < 5 && mass[y][x + 1] == kind )Delete( mass, x + 1, y, kind ); //右
		if( x > 0 && mass[y][x - 1] == kind )Delete( mass, x - 1, y, kind ); //左
		if( y < 13 && mass[y + 1][x] == kind )Delete( mass, x, y + 1, kind ); //下
	}
}//完成
static void init_popjelly( void )
{
	for( int i = 0; i < 2; i++ ) {
		popjelly_count[i] = 60;
		popjelly_time[i] = 1;
		popjelly_process[i] = 0;
		popjelly_turn[i] = 0;
		popjelly_linkage[i] = 0;
		popjelly_block[i] = 0;
		popjelly_chain[i] = false;
		popjelly_countflag[i] = false;
		popjelly_mKind[i] = GetRand( RAND ) + 1;
		popjelly_eKind[i] = GetRand( RAND ) + 1;
		popjelly_mNext[i] = GetRand( RAND ) + 1;
		popjelly_mNext[i] = GetRand( RAND ) + 1;
		popjelly_mPosition[i].x = 2;
		popjelly_ePosition[i].x = 2;
	}
	popjelly_key[256];
	popjelly_mPosition[0].y = 0;
	popjelly_mPosition[1].y = 1;
	popjelly_ePosition[0].y = 0;
	popjelly_ePosition[1].y = 1;
	popjelly_mass = popjelly_mass_copy;
}
static bool mPopJelly( popjelly_COORDINATE position[2], int &count, natural mass[HEIGHT][WIDTH], natural checked[HEIGHT][WIDTH], natural &process, char key[256] ) //自分の処理
{
	natural y1 = position[0].y, x1 = position[0].x, y2 = position[1].y, x2 = position[1].x;
	bool isClear = false;
	if( count >= LIMIT ) { //床についてからLIMIT/60秒以上経ったら
		if( !Fall( mass ) ) { //ポップを落とした時、隙間が無ければ
			mass[0][0] = 0; //14段目のポップは消す。
			mass[0][1] = 0;
			mass[0][2] = 0;
			mass[0][3] = 0;
			mass[0][4] = 0;
			mass[0][5] = 0;
			//連鎖処理
			for( natural x = 0; x < WIDTH; x++ ) { //一番左の
				for( natural y = HEIGHT - 1; y > 1; y-- ) { //一番下から、上から三番目迄
					natural temp = mass[y][x];
					if( temp && temp != CROSS && temp != BLOCK && Link( mass, x, y, temp, checked ) >= 4 ) { //空白、×、BLOCKでなく、4つ以上繋がっている
						Delete( mass, x, y, temp ); //削除
						if( !popjelly_chain[0] )isClear = true; //ポップが消えた
					}
				}
			}
			if( isClear ) { //消えた
				popjelly_linkage[0]++; //連鎖数を増やす
				process += 10; // 1/60秒後に落とす
			} else { //消えなかった
				if( mass[2][2] != CROSS || mass[2][3] != CROSS ) { //×に積んだ
					DrawString( 30, 50, "Game Over!! 3秒後に戻ります。", 0x000000 );
					return true;
				}
				popjelly_time[0] = 1; // 1/60秒ごとに1増加。60になると、1に戻る
				popjelly_mKind[0] = popjelly_mNext[0]; //次のポップに。
				popjelly_mKind[1] = popjelly_mNext[1];
				popjelly_mNext[0] = GetRand( RAND ) + 1; //乱数で、種類を決める。
				popjelly_mNext[1] = GetRand( RAND ) + 1;
				position[0].x = 2; //場所 初期化
				position[0].y = 0;
				position[1].x = 2;
				position[1].y = 1;
				count = 0; //床についてからのカウントを0にする。
				popjelly_countflag[0] = false;
				popjelly_turn[0] = 0;
			}
		} else {
			process += 10; // 1/60秒後にまた落とす
		}
	} else { //通常の処理
		if( mass[2][2] == 0 )popjelly_mass.m[2][2] = CROSS; //×の位置
		if( mass[2][3] == 0 )popjelly_mass.m[2][3] = CROSS;
		if( popjelly_time[0] % 60 == 0 ) { // 一秒経過
			if( y1 != 13 && y2 != 13 ) { //一番下じゃないなら、ポップを下へ移動(自分)
				if( popjelly_turn[0] % 2 == 0 ) {
					if( !mass[y1 + 1][x1] || !mass[y2 + 1][x2] || mass[y1 + 1][x1] == CROSS || mass[y2 + 1][x2] == CROSS ) {
						mass[y1][x1] = 0;
						mass[y2][x2] = 0;
						position[0].y = ++y1;
						position[1].y = ++y2;
					}
				} else if( ( !mass[y1 + 1][x1] || mass[y1 + 1][x1] == CROSS ) && ( !mass[y2 + 1][x2] || mass[y2 + 1][x2] == CROSS ) ) {
					mass[y1][x1] = 0;
					mass[y2][x2] = 0;
					position[0].y = ++y1;
					position[1].y = ++y2;
				}
			}
		}
		if( key[KEY_INPUT_RIGHT] && key[KEY_INPUT_RIGHT] % 5 == 1 && x1 != 5 && x2 != 5 ) { //右端じゃない時に、右を押したとき
			if( popjelly_turn[0] % 2 == 0 ) {
				if( ( !mass[y1][x1 + 1] || mass[y1][x1 + 1] == CROSS ) && ( !mass[y2][x2 + 1] || mass[y2][x2 + 1] == CROSS ) ) {
					mass[y1][x1] = 0;
					mass[y2][x2] = 0;
					popjelly_mPosition[0].x = ++x1;
					popjelly_mPosition[1].x = ++x2;
				}
			} else if( !mass[y1][x1 + 1] || !mass[y2][x2 + 1] || mass[y1][x1 + 1] == CROSS || mass[y2][x2 + 1] == CROSS ) {
				mass[y1][x1] = 0;
				mass[y2][x2] = 0;
				popjelly_mPosition[0].x = ++x1;
				popjelly_mPosition[1].x = ++x2;
			}
		} else if( key[KEY_INPUT_LEFT] && key[KEY_INPUT_LEFT] % 5 == 1 && x1 && x2 ) { //左端じゃない時に、左を押したとき
			if( popjelly_turn[0] % 2 == 0 ) {
				if( ( !mass[y1][x1 - 1] || mass[y1][x1 - 1] == CROSS ) && ( !mass[y2][x2 - 1] || mass[y2][x2 - 1] == CROSS ) ) {
					mass[y1][x1] = 0;
					mass[y2][x2] = 0;
					popjelly_mPosition[0].x = --x1;
					popjelly_mPosition[1].x = --x2;
				}
			} else if( !mass[y1][x1 - 1] || !mass[y2][x2 - 1] || mass[y1][x1 - 1] == CROSS || mass[y2][x2 - 1] == CROSS ) {
				mass[y1][x1] = 0;
				mass[y2][x2] = 0;
				popjelly_mPosition[0].x = --x1;
				popjelly_mPosition[1].x = --x2;
			}
		} else if( key[KEY_INPUT_DOWN] && key[KEY_INPUT_DOWN] % 5 == 1 && y1 != 13 && y2 != 13 ) {
			if( popjelly_turn[0] % 2 == 0 ) {
				if( !mass[y1 + 1][x1] || !mass[y2 + 1][x2] || mass[y1 + 1][x1] == CROSS || mass[y2 + 1][x2] == CROSS ) {
					mass[y1][x1] = 0;
					mass[y2][x2] = 0;
					popjelly_mPosition[0].y = ++y1;
					popjelly_mPosition[1].y = ++y2;
				}
			} else if( ( !mass[y1 + 1][x1] || mass[y1 + 1][x1] == CROSS ) && ( !mass[y2 + 1][x2] || mass[y2 + 1][x2] == CROSS ) ) {
				mass[y1][x1] = 0;
				mass[y2][x2] = 0;
				popjelly_mPosition[0].y = ++y1;
				popjelly_mPosition[1].y = ++y2;
			}
		} else if( key[KEY_INPUT_A] == 1 ) { //回転判定(右回転)
			switch( popjelly_turn[0] ) {
			case 0: // 縦 popjelly_mPosition[0],[1] (1,2)
				if( x2 == 5 || mass[y2][x2 + 1] && mass[y2][x2 + 1] != CROSS ) { //右がポップか壁で
					if( x1 && ( !mass[y2][x2 - 1] || mass[y2][x2 - 1] == CROSS ) ) { //左が空か×なら
						mass[y1][x1] = 0;
						popjelly_mPosition[0].y = ++y1;
						popjelly_mPosition[1].x = --x2;
					} else { //どっちもポップ or 壁なら
						if( y2 == 13 || mass[y2 + 1][x2] ) { //下にポップか壁があるなら
							popjelly_mPosition[0].y = ++y1; //上のポップを下へ
							popjelly_mPosition[1].y = --y2; //下のポップを上へ
						} else {
							mass[y1][x1] = 0;
							++y1;
							popjelly_mPosition[0].y = ++y1; //上のポップを二つ下へ
						}
						popjelly_turn[0]++; //case 2まで飛ばす。
					}
				} else { //右が空 もしくは ×
					mass[y1][x1] = 0;
					popjelly_mPosition[0].x = ++x1;
					popjelly_mPosition[0].y = ++y1;
				}
				popjelly_turn[0]++;
				break;
			case 1: // 横 popjelly_mPosition[1],[0] (2,1)
				mass[y1][x1] = 0;
				if( y2 == 13 || mass[y2 + 1][x2] && mass[y2 + 1][x2] != CROSS ) { //左ポップの下がポップか壁なら
					popjelly_mPosition[0].x = --x1;
					popjelly_mPosition[1].y = --y2;
				} else { //左ポップの下が空 もしくは ×
					popjelly_mPosition[0].x = --x1;
					popjelly_mPosition[0].y = ++y1;
				}
				popjelly_turn[0]++;
				break;
			case 2: // 縦 popjelly_mPosition[1],[0] (2,1)
				if( !x1 || mass[y1][x1 - 1] && mass[y1][x1 - 1] != CROSS ) { //左がポップか壁で
					if( x1 != 5 && ( !mass[y1][x1 + 1] || mass[y1][x1 + 1] == CROSS ) ) { //右が空か×なら
						mass[y2][x2] = 0;
						popjelly_mPosition[1].y = ++y2;
						popjelly_mPosition[1].x = ++x2;
						popjelly_turn[0] = 3;
					} else { //どっちもポップ or 壁なら
						if( y1 == 13 || mass[y1 + 1][x1] ) { //下にポップか壁があるなら
							popjelly_mPosition[1].y = ++y2; //上のポップを下へ
							popjelly_mPosition[0].y = --y1; //下のポップを上へ
						} else {
							mass[y1][x1] = 0;
							--y1;
							popjelly_mPosition[0].y = --y1; //下のポップを二つ上へ
						}
						popjelly_turn[0] = 0;
					}
				} else { //左が空 もしくは ×
					mass[y1][x1] = 0;
					popjelly_mPosition[0].x = --x1;
					popjelly_mPosition[0].y = --y1;
					popjelly_turn[0] = 3;
				}
				break;
			default: // 横 popjelly_mPosition[0],[1] (1,2)
				mass[y1][x1] = 0;
				popjelly_mPosition[0].x = ++x1;
				popjelly_mPosition[0].y = --y1;
				popjelly_turn[0] = 0;
			}
		} else if( key[KEY_INPUT_D] == 1 ) { //回転判定(左回転)
			switch( popjelly_turn[0] ) {
			case 0: // 縦 popjelly_mPosition[0],[1] (1,2)
				if( x1 == 0 || mass[y2][x2 - 1] && mass[y2][x2 - 1] != CROSS ) { //左がポップか壁で
					if( x1 != 5 && ( !mass[y1][x1 + 1] || mass[y1][x1 + 1] == CROSS ) ) { //右が空か×なら
						mass[y1][x1] = 0;
						popjelly_mPosition[0].y = ++y1;
						popjelly_mPosition[1].x = ++x2;
						popjelly_turn[0] = 3;
					} else { //どっちもポップ or 壁なら
						if( y2 == 13 || mass[y2 + 1][x2] ) { //下にポップか壁があるなら
							popjelly_mPosition[0].y = ++y1; //上のポップを下へ
							popjelly_mPosition[1].y = --y2; //下のポップを上へ
						} else {
							mass[y1][x1] = 0;
							++y1;
							popjelly_mPosition[0].y = ++y1; //上のポップを二つ下へ
						}
						popjelly_turn[0] = 2;
					}
				} else { //左が空 もしくは ×
					mass[y1][x1] = 0;
					popjelly_mPosition[0].x = --x1;
					popjelly_mPosition[0].y = ++y1;
					popjelly_turn[0] = 3;
				}
				break;
			case 1: // 横 popjelly_mPosition[1],[0] (2,1)
				mass[y1][x1] = 0;
				popjelly_mPosition[0].x = --x1;
				popjelly_mPosition[0].y = --y1;
				popjelly_turn[0]--;
				break;
			case 2: // 縦 popjelly_mPosition[1],[0] (2,1)
				if( x2 == 5 || mass[y2][x2 + 1] && mass[y2][x2 + 1] != CROSS ) { //右がポップか壁で
					if( x1 && ( !mass[y1][x1 - 1] || mass[y1][x1 - 1] == CROSS ) ) { //左が空か×なら
						mass[y2][x2] = 0;
						popjelly_mPosition[1].y = ++y2;
						popjelly_mPosition[1].x = --x2;
					} else { //どっちもポップ or 壁なら
						if( y1 == 13 || mass[y1 + 1][x1] ) { //下にポップか壁があるなら
							popjelly_mPosition[0].y = --y1; //上のポップを下へ
							popjelly_mPosition[1].y = ++y2; //下のポップを上へ
						} else {
							mass[y1][x1] = 0;
							--y1;
							popjelly_mPosition[0].y = --y1; //下のポップを二つ上へ
						}
						popjelly_turn[0]--; //case 0まで飛ばす。
					}
				} else { //右が空 もしくは ×
					mass[y1][x1] = 0;
					popjelly_mPosition[0].x = ++x1;
					popjelly_mPosition[0].y = --y1;
				}
				popjelly_turn[0]--;
				break;
			default: // 横 popjelly_mPosition[0],[1] (1,2)
				mass[y1][x1] = 0;
				if( y2 == 13 || mass[y2 + 1][x2] && mass[y2 + 1][x2] != CROSS ) { //右ポップの下がポップか壁なら
					popjelly_mPosition[0].x = ++x1;
					popjelly_mPosition[1].y = --y2;
				} else { //左ポップの下が空 もしくは ×
					popjelly_mPosition[0].x = ++x1;
					popjelly_mPosition[0].y = ++y1;
				}
				popjelly_turn[0]--;
			}
		}
		mass[y1][x1] = popjelly_mKind[0];
		mass[y2][x2] = popjelly_mKind[1];
	}
	return false;
}
static bool ePopJelly( popjelly_COORDINATE position[2], int &count, natural mass[HEIGHT][WIDTH], natural checked[HEIGHT][WIDTH], natural &process ) //敵の処理
{
	natural y1 = position[0].y, x1 = position[0].x, y2 = position[1].y, x2 = position[1].x;
	bool isClear = false;
	if( count >= LIMIT ) { //床についてからLIMIT/60秒以上経ったら
		if( !Fall( mass ) ) { //ポップを落とした時、隙間が無ければ
			mass[0][0] = 0; //14段目のポップは消す。
			mass[0][1] = 0;
			mass[0][2] = 0;
			mass[0][3] = 0;
			mass[0][4] = 0;
			mass[0][5] = 0;
			//連鎖処理
			for( natural x = 0; x < WIDTH; x++ ) { //一番左の
				for( natural y = HEIGHT - 1; y > 1; y-- ) { //一番下から、上から三番目迄
					natural temp = mass[y][x];
					if( temp && temp != CROSS && temp != BLOCK && Link( mass, x, y, temp, checked ) >= 4 ) { //空白、×、BLOCKでなく、4つ以上繋がっている
						Delete( mass, x, y, temp ); //削除
						if( !popjelly_chain[1] )isClear = true; //ポップが消えた
					}
				}
			}
			if( isClear ) { //消えた
				popjelly_linkage[1]++; //連鎖数を増やす
				process += 10; // 1/60秒後に落とす
			} else { //消えなかった
				if( ( mass[2][2] && mass[2][2] != CROSS ) || ( mass[2][2] && mass[2][3] != CROSS ) ) { //×に積んだ
					DrawString( 30, 50, "ゲームクリア!おめでとう。", 0x000000 );
					return true;
				}
				popjelly_time[1] = 1; // 1/60秒ごとに1増加。60になると、1に戻る
				popjelly_eKind[0] = popjelly_eNext[0]; //次のポップに。
				popjelly_eKind[1] = popjelly_eNext[1];
				popjelly_eNext[0] = GetRand( RAND ) + 1; //乱数で、種類を決める。
				popjelly_eNext[1] = GetRand( RAND ) + 1;
				position[0].x = 2; //場所 初期化
				position[0].y = 0;
				position[1].x = 2;
				position[1].y = 1;
				count = 0; //床についてからのカウントを0にする。
				popjelly_countflag[1] = false;
				popjelly_turn[1] = 0;
			}
		} else {
			process += 10; // 1/6秒後にまた落とす
		}
	} else {
		if( mass[2][2] == 0 )mass[2][2] = CROSS;
		if( mass[2][3] == 0 )mass[2][3] = CROSS;
		if( popjelly_time[1] % 60 == 0 ) { //一秒ごとに
			if( y1 != 13 && y2 != 13 ) { //一番下じゃないなら、下へ移動(敵)
				if( popjelly_turn[1] % 2 == 0 ) {
					if( !mass[y1 + 1][x1] || !mass[y2 + 1][x2] || mass[y1 + 1][x1] == CROSS || mass[y2 + 1][x2] == CROSS ) {
						mass[y1][x1] = 0;
						mass[y2][x2] = 0;
						popjelly_ePosition[0].y = ++y1;
						popjelly_ePosition[1].y = ++y2;
					}
				} else if( ( !mass[y1 + 1][x1] || mass[y1 + 1][x1] == CROSS ) && ( !mass[y2 + 1][x2] || mass[y2 + 1][x2] == CROSS ) ) {
					mass[y1][x1] = 0;
					mass[y2][x2] = 0;
					popjelly_ePosition[0].y = ++y1;
					popjelly_ePosition[1].y = ++y2;
				}
			}
		}
		mass[y1][x1] = popjelly_eKind[0];
		mass[y2][x2] = popjelly_eKind[1];
	}
	return false;
}
static void printMass(char* title,natural mass[14][6])
{
	printf( "\n------------------ %s", title );
	for( int i=0 ; i<14 ; i++ ) {
		printf( "\n" );
		for( int j=0 ; j<6 ; j++ ) {
			printf( " %d" , mass[i][j] );
		}
	}
	natural m[14][6], e[14][6];
}

static count PopJelly( char *key, natural level )
{
	DrawGraph( 0, 0, data.image[1], TRUE ); //枠(背景)
	natural my1 = popjelly_mPosition[0].y, mx1 = popjelly_mPosition[0].x, my2 = popjelly_mPosition[1].y, mx2 = popjelly_mPosition[1].x;
	natural ey1 = popjelly_ePosition[0].y, ex1 = popjelly_ePosition[0].x, ey2 = popjelly_ePosition[1].y, ex2 = popjelly_ePosition[1].x;
	bool lose = false, win = false;
	
	
	printMass("mPopJelly前",popjelly_mass.m);
	if( popjelly_process[0] )popjelly_process[0]--;
	else lose = mPopJelly( popjelly_mPosition, popjelly_count[0], popjelly_mass.m, popjelly_checked.m, popjelly_process[0], key );
	printMass("mPopJelly後",popjelly_mass.m);
	
	Sleep( 1000 );
	
//	printMass("ePopJelly前",popjelly_mass.e);
	if( popjelly_process[1] )popjelly_process[1]--;
	else win = ePopJelly( popjelly_ePosition, popjelly_count[1], popjelly_mass.e, popjelly_checked.e, popjelly_process[1] );
//	printMass("ePopJelly後",popjelly_mass.e);
	
	for( int y = -64, i = 0; y <= 430; y += 38, i++ ) { //ポップを描く
		for( int x = 46, j = 0; x <= 236; x += 38, j++ )popjelly_mass.m[i][j] && DrawGraph( x, y, data.pop[popjelly_mass.m[i][j]], TRUE );
		for( int x = 366, j = 0; x <= 556; x += 38, j++ )popjelly_mass.e[i][j] && DrawGraph( x, y, data.pop[popjelly_mass.e[i][j]], TRUE );
	}
	DrawGraph( 0, 0, data.image[2], TRUE ); //枠(メイン)
	if( lose || win ) {
		ScreenFlip();
		Sleep( 3000 );
		return TITLE;
	}
	DrawGraph( 278, 10, data.pop[popjelly_mNext[0]], TRUE ); //次のポップを表示(自分)
	DrawGraph( 278, 48, data.pop[popjelly_mNext[1]], TRUE );
	DrawGraph( 321, 10, data.pop[popjelly_eNext[0]], TRUE ); //次のポップを表示(敵)
	DrawGraph( 321, 48, data.pop[popjelly_eNext[1]], TRUE );
	{
		char string[2][3];
		if( popjelly_linkage[0] ) {
			sprintf_s( string[0], "%d", popjelly_linkage[0] );
			popjelly_linkage[0] && DrawString( 278, 400, string[0], 0x000000 ); //連鎖数を表示(自分)
			popjelly_linkage[0] = 0;
		}
		if( popjelly_linkage[1] ) {
			sprintf_s( string[1], "%d", popjelly_linkage[1] );
			popjelly_linkage[1] && DrawString( 321, 400, string[1], 0x000000 ); //連鎖数を表示(敵)
			popjelly_linkage[1] = 0;
		}
	}
	if( key[KEY_INPUT_ESCAPE] == 1 )return 0;
	else if( key[KEY_INPUT_RETURN] == 1 ) {
		int waitkey;
		DrawString( 0, 0, "一時停止", 0xffffff );
		ScreenFlip();
		while( 1 ) {
			waitkey = WaitKey();
			if( waitkey == KEY_INPUT_RETURN )break;
			else if( waitkey == KEY_INPUT_SPACE )goto end;
		};
	}
	if( popjelly_turn[0] % 2 == 0 )if( my1 == 13 || my2 == 13 || popjelly_mass.m[my1 + 1][mx1] && popjelly_mass.m[my1 + 1][mx1] != CROSS && popjelly_mass.m[my2 + 1][mx2] && popjelly_mass.m[my2 + 1][mx2] != CROSS )popjelly_count[0]++;
		else if( my1 == 13 && my2 == 13 || ( popjelly_mass.m[my1 + 1][mx1] && popjelly_mass.m[my1 + 1][mx1] != CROSS ) || ( popjelly_mass.m[my2 + 1][mx2] && popjelly_mass.m[my2 + 1][mx2] != CROSS ) )popjelly_count[0]++;

	if( popjelly_turn[1] % 2 == 0 )if( ey1 == 13 || ey2 == 13 || popjelly_mass.e[ey1 + 1][ex1] && popjelly_mass.e[ey1 + 1][ex1] != CROSS && popjelly_mass.e[ey2 + 1][ex2] && popjelly_mass.e[ey2 + 1][ex2] != CROSS )popjelly_count[1]++;
		else if( ey1 == 13 && ey2 == 13 || ( popjelly_mass.e[ey1 + 1][ex1] && popjelly_mass.e[ey1 + 1][ex1] != CROSS ) || ( popjelly_mass.e[ey2 + 1][ex2] && popjelly_mass.e[ey2 + 1][ex2] != CROSS ) )popjelly_count[1]++;
	popjelly_time[0]++;
	popjelly_time[1]++;
	if( popjelly_time[0] > 60 )popjelly_time[0] = 1;
	if( popjelly_time[1] > 60 )popjelly_time[1] = 1;
end:
	return 1; //終了
}
static count Story( char *key )
{
	int level = 0, story = 0;
back:
	switch( level ) {
	case 0:
		while( 1 ) {
			if( !( ScreenFlip() == 0 && ProcessMessage() == 0 && ClearDrawScreen() == 0 ) )return 0;
			UpdateKey( key );
			DrawGraph( 70, 130, data.character[0], TRUE );
			DrawGraph( 400, 100, data.character[4], TRUE );
			switch( story ) {
			case 0:
				Message( "アース", "ここはどこだろう……?" );
				break;
			case 1:
				Message( "アース", "うわぁ! あれは何!?" );
				break;
			case 2:
				Message( "???", "スレア ヴァイア!" ); // サン(ラスボス)
				ScreenFlip();
#if isEffectOn
				PlaySoundMem( data.effect[3], DX_PLAYTYPE_NORMAL );
#endif
				story++;
				break;
			case 3:
				Message( "アース", "ふにゃぁー……" );
				break;
			default:
				Sleep( 2000 );
				level++;
				story = 0;
				goto back;
			}
			if( key[KEY_INPUT_ESCAPE] == 1 )return 0;
			else if( key[KEY_INPUT_RETURN] == 1 ) {
				PlaySoundMem( data.effect[0], DX_PLAYTYPE_BACK );
				story++;
			}
		}
	case 1:
		while( 1 ) {
			if( !( ScreenFlip() == 0 && ProcessMessage() == 0 && ClearDrawScreen() == 0 ) )return 0;
			UpdateKey( key );
			DrawGraph( 70, 130, data.character[0], TRUE );
			DrawGraph( 400, 100, data.character[1], TRUE );
			switch( story ) {
			case 0:
				Message( "アース", "何してたんだろう……?" );
				break;
			case 1:
				Message( "???", "な~めく~じく~じく~じ" );
				break;
			case 2:
				Message( "アース", "近寄らないで……!" );
				break;
			case 3:
				Message( "ベトン", "俺はベトンだ。。" );
				break;
			case 4:
				Message( "ベトン", "Let's スライミング!!" );
				break;
			case 5:
				Message( "アース", "しょうがないなぁ……" );
				break;
			default:
				Sleep( 2000 );
				if( PopJelly( key, 0 ) == 1 )level++;
				else return 0;
				story = 0;
				//goto back;
				return 1;
			}
			if( key[KEY_INPUT_ESCAPE] == 1 )return 0;
			else if( key[KEY_INPUT_RETURN] == 1 ) {
#if isEffectOn
				PlaySoundMem( data.effect[0], DX_PLAYTYPE_BACK );
#endif
				story++;
			}
		}
	default:
		break;
	}
	return 1;
}
static count Free( char *key )
{
	return PopJelly( key, 0 );
}
static count Config( char *key )
{
	return 1;
}

Re: DXライブラリを使用したゲームの時間制御について

Posted: 2012年2月20日(月) 18:14
by Loki
ありがとうございます。
そんなふうにして、動作確認ができるのですね!
原因が分かり、無事修正できました。
Fall関数に問題があったようです。
現在のソース:http://mathoff.rosx.net/upload/source.cpp
現在のプログラム:http://mathoff.rosx.net/upload/pop-jelly.zip

しかし、前々からずっと良く分からなくて悩んでいた問題があります。
画像
いま、このような状態なんですが、キーの左を押しっぱなしにして、自動的に一マス落ちるという処理のとき、
画像
このように、めり込んでしまいます。
しかも、たまにしか起きなくて、どの辺に原因があるのか全く分かりません。
左だけでなく、右に寄せるときにも起きます。
ただし、
A
A
の様な形で寄せても起きず、
AA
の様に、横向きのときだけ起きます。
Aボタンで右回転、Dボタンで左回転です。
また、先程試してみたところ、

コード:

 B
 B
A A
CAC
(空白を表示させる為)
Bが自分の手ですが、自動的に落ちる瞬間にAを押した場合も、

ABB
CAC

このようにめり込みます。(これを再現するのは至難の技で、スクリーンショットは無理でした)
上記二点から、自動で落ちる処理の部分に問題があると思ったのですが、

mPopJelly関数内

コード:

if(popjelly_time[0]>=FPS){ // FPS/60秒以上経過
	if(y1!=13 && y2!=13){ //一番下じゃないなら、ポップを下へ移動(自分)
		if(popjelly_turn[0]%2==0){
			if(!mass[y1+1][x1] || !mass[y2+1][x2] || mass[y1+1][x1]==CROSS || mass[y2+1][x2]==CROSS){
				mass[y1][x1]=0;
				mass[y2][x2]=0;
				position[0].y=++y1;
				position[1].y=++y2;
			}
		}
		else if((!mass[y1+1][x1] || mass[y1+1][x1]==CROSS) && (!mass[y2+1][x2] || mass[y2+1][x2]==CROSS)){
			mass[y1][x1]=0;
			mass[y2][x2]=0;
			position[0].y=++y1;
			position[1].y=++y2;
		}
	}
}
y1やy2は増やしていますし、その後のキーを押す処理でも、y1,y2は使っていますが、y1,y2の元となる、popjelly_mPositionの値は、左へ行けるかどうかの判断には使用していません。

Re: DXライブラリを使用したゲームの時間制御について

Posted: 2012年2月20日(月) 18:53
by softya(ソフト屋)
キーによる移動と自動降下の2ヶ所有るみたいですが、何か条件の書き方が違います。
これが共通化していないプログラムで起きやすい問題点です。どちらが正しいのでしょうか?
キーの方は (A or B) and (C or D)
自動降下は、A or C or B or D
こういう箇所を減らすために共通化を心がけましょう。多分、ソースコードに長さは2/3ぐらいになって、分かりやすさは数倍上がります。

コード:

		else if(key[KEY_INPUT_LEFT] && key[KEY_INPUT_LEFT]%5==1 && x1 && x2){ //左端じゃない時に、左を押したとき
			if(popjelly_turn[0]%2==0){
				if((!mass[y1][x1-1] || mass[y1][x1-1]==CROSS) && (!mass[y2][x2-1] || mass[y2][x2-1]==CROSS)){
					mass[y1][x1]=0;
					mass[y2][x2]=0;
					position[0].x=--x1;
					position[1].x=--x2;
				}
			}
			else if(!mass[y1][x1-1] || !mass[y2][x2-1] || mass[y1][x1-1]==CROSS || mass[y2][x2-1]==CROSS){
				mass[y1][x1]=0;
				mass[y2][x2]=0;
				position[0].x=--x1;
				position[1].x=--x2;
			}
		}

コード:

if(popjelly_time[0]>=FPS){ // FPS/60秒以上経過
    if(y1!=13 && y2!=13){ //一番下じゃないなら、ポップを下へ移動(自分)
        if(popjelly_turn[0]%2==0){
            if(!mass[y1+1][x1] || !mass[y2+1][x2] || mass[y1+1][x1]==CROSS || mass[y2+1][x2]==CROSS){
                mass[y1][x1]=0;
                mass[y2][x2]=0;
                position[0].y=++y1;
                position[1].y=++y2;
            }
        }
        else if((!mass[y1+1][x1] || mass[y1+1][x1]==CROSS) && (!mass[y2+1][x2] || mass[y2+1][x2]==CROSS)){
            mass[y1][x1]=0;
            mass[y2][x2]=0;
            position[0].y=++y1;
            position[1].y=++y2;
        }
    }
}

Re: DXライブラリを使用したゲームの時間制御について

Posted: 2012年2月20日(月) 20:05
by Loki

コード:

if(popjelly_turn[0]%2==0){
	if(!mass[y1+1][x1] || mass[y1+1][x1]==CROSS || !mass[y2+1][x2] || mass[y2+1][x2]==CROSS){
		mass[y1][x1]=0;
		mass[y2][x2]=0;
		position[0].y=++y1;
		position[1].y=++y2;
	}
}
else if((!mass[y1+1][x1] || mass[y1+1][x1]==CROSS) && (!mass[y2+1][x2] || mass[y2+1][x2]==CROSS)){
	mass[y1][x1]=0;
	mass[y2][x2]=0;
	position[0].y=++y1;
	position[1].y=++y2;
}
チェックする順番を一緒にするということでしょうか。

こうしてみたところで、一向に分かりません。

Re: DXライブラリを使用したゲームの時間制御について

Posted: 2012年2月20日(月) 20:28
by softya(ソフト屋)
すいません。順番が逆だったんですね。
逆だと場合により動作が違う気がするんですが、どうなのでしょうか?
CROSSの説明がなく意味が分かっていないので見当違いかも知れません。

[追記] とにかくソースコードを追いかけるのが非常に困難でして、バグの再現方法を確定しないと難しいです。
出来れば食い込んだことをチェックする機能を組み込んで、DebugBreak();でデバッガをブレークするか、食い込んだ場所とか状況の情報をprintfするなどの工夫が必要でしょう。

Re: DXライブラリを使用したゲームの時間制御について

Posted: 2012年2月20日(月) 20:49
by Loki
softya(ソフト屋) さんが書きました: CROSSの説明がなく意味が分かっていないので見当違いかも知れません。
ぷよぷよは御存じでしょうか。
×のところに積んだらゲームオーバーですが、CROSSはその × のことです。
0は空白、1は赤、2は青 みたいな感じになっていて、BLOCKはお邪魔ぷよで、CROSS は × です。
説明が足りず、すみません。
逆だと場合により動作が違う気がするんですが、どうなのでしょうか?
一応、手動で確認できる範囲は全て確認し、成功しています。(めり込み以外)
バグの再現方法を確定しないと難しい
出来れば食い込んだことをチェックする機能を組み込んで
分かりました。
もう少し調べてみます。

Re: DXライブラリを使用したゲームの時間制御について

Posted: 2012年2月21日(火) 00:50
by Loki
無事解決しました!
この変数を変更すると、表示も変わるだろう、などという先入観で、失敗していたようです。
長い間ありがとうございました。
ソースなどで、膨大になりましたので、これにて、このスレッドは終了させていただきます。
また、敵を作る際や、解決できない不具合など、意見をお聞きしたいときにはお世話になるかもしれませんが、宜しくお願いします。

Re: DXライブラリを使用したゲームの時間制御について

Posted: 2012年2月21日(火) 09:21
by softya(ソフト屋)
解決してよかったです。
ただ、ソースコードをもっと整理しないとバグを内包する危険と隣り合わせだと思いますよ。
あと、ここのフォーラムルールで解決した場合は直ったソースコードを掲載する事になっていますのでお願いします。
http://dixq.net/board/board.html

Re: DXライブラリを使用したゲームの時間制御について

Posted: 2012年2月21日(火) 17:40
by Loki
了解です。

修正したコードは、こちらです。(他の追加処理も混ざってしまっています。)
コメントは、複数行取っている場合は、消しています。

コード:

#include "DxLib.h"
#define ELEMENTS 7 //data.popの要素数
#define CROSS ELEMENTS-1 //× 積んだらゲームオーバー
#define BLOCK CROSS-1 //BLOCK
#define RAND BLOCK-2 //乱数に使う
#define WIDTH 6 //マスの数 横
#define HEIGHT 14 //マスの数 縦
#define isMusicOn 1 //デバッグ用 曲を流す1 or 流さない0
#define isEffectOn 1 //デバッグ用 効果音あり1 or なし0
#define LIMIT 100 //床についてから、どのくらい停止を許可するか
#define WaitBeforeDelete 39 //消える前に、どのくらい待つか
#define WaitAfterDelete 25 //消えた後に、どのくらい待つか
#define FallSpeed 5 //浮いたポップが落ちる速さ */60 に1マス落ちる
#define FPS 63 //現在のポップが */60 に1マス落ちる
#define StepForKey 5 //keyが、この値を超えたら、0に戻す (オーバーフロー対策) また、間隔にも該当
#define CountIfKeepDown 15 //下にポップがあるのに、[KEY_INPUT_DOWN] し続ける場合、どれくらいcount値を増やすか
typedef unsigned short int natural;
typedef const short int invariant;
typedef short int count;
struct MASS{
	natural m[14][6],e[14][6];
};
struct MENU{
	invariant imgX,imgY;
	int handle;
	invariant nameX,nameY;
	const char name[128];
};
struct{
	int image[6],pop[ELEMENTS],character[5],effect[4],music[1];
}data;
struct popjelly_COORDINATE{
	natural x,y;
};
static void Menu(void);
static void UpdateKey(char *KeyStateBuf);
static count Title(char *key,MENU menu[4],natural &tselect);
static void DrawButtons_title(MENU menu[4]);
static void Message(const char name[],const char message[]);
static bool Fall(natural mass[HEIGHT][WIDTH]);
static natural Link(natural mass[HEIGHT][WIDTH],natural x,natural y,natural kind,natural checked[HEIGHT][WIDTH]);
static void Delete(natural mass[HEIGHT][WIDTH],natural x,natural y,natural kind);
static void init_popjelly(void);
static bool mPopJelly(popjelly_COORDINATE position[2],int &count,natural mass[HEIGHT][WIDTH],natural checked[HEIGHT][WIDTH],natural &process,char key[256]);
static bool ePopJelly(popjelly_COORDINATE position[2],int &count,natural mass[HEIGHT][WIDTH],natural checked[HEIGHT][WIDTH],natural &process);
static void printMass(char* title,natural mass[14][6]);
static count PopJelly(char *key,natural level);
static count Story(char *key);
static count Free(char *key);
static count Config(char *key);
int popjelly_count[2]={LIMIT,LIMIT}; //ポップが床等に最初に付いてからの経過時間 再度離れた場合は、少し減らす ついてから下を押すと増やす
natural popjelly_time[2]={1,1}; //1/60秒に一回1増加。 FPS/60秒たつと、1に初期化。(自分,敵)
natural popjelly_process[2]={0,0}; //時間制御用変数
natural popjelly_turn[2]={0,0}; //回転回数(自分,敵)
natural popjelly_linkage[2]={0,0}; //連鎖数(自分,敵)
natural popjelly_block[2]={0,0}; //BLOCK ポップの数(自分,敵)
bool popjelly_isChain[2]={false,false}; //消えそうかどうか(自分,敵)
char popjelly_key[256]; //キー保存用
natural popjelly_mKind[2]; //ポップの種類(上,下)(自分)
natural popjelly_eKind[2];
natural popjelly_mNext[2]; //次のポップ(上,下)(自分)
natural popjelly_eNext[2];
struct popjelly_COORDINATE popjelly_mPosition[2]={{2,0},{2,1}}; //ポップの場所(x,y)(自分)
struct popjelly_COORDINATE popjelly_ePosition[2]={{2,0},{2,1}}; //ポップの場所(x,y)(敵)
const struct MASS popjelly_copy={}; //チェック用の初期化用
struct MASS popjelly_checked; //チェック用
const struct MASS popjelly_mass_copy={ //フィールド初期化用
	{ //自分
		{0,0,0,0,0,0}, //この列に積んだら消す
		{3,1,0,0,1,1},
		{3,3,3,2,1,3},
		{2,3,1,1,2,1},
		{3,1,2,2,1,3},
		{1,2,1,3,2,3},
		{2,1,3,2,1,3},
		{1,2,1,3,2,1},
		{1,2,1,3,2,1},
		{1,3,3,2,1,2},
		{3,1,2,3,2,2},
		{2,3,1,2,3,1},
		{2,3,1,2,3,1},
		{2,3,1,2,3,1}
	},
	{ //敵
		{0,0,0,0,0,0},
		{2,3,0,0,1,2},
		{3,3,2,2,2,2},
		{2,2,1,3,1,1},
		{1,1,3,2,2,1},
		{2,2,1,3,3,2},
		{3,1,3,2,1,1},
		{2,1,3,2,1,3},
		{2,2,1,3,2,1},
		{3,1,3,2,1,3},
		{3,2,1,3,2,3},
		{2,1,3,2,1,3},
		{3,2,1,3,2,1},
		{3,2,1,3,2,1}
	}
};
struct MASS popjelly_mass=popjelly_mass_copy; //フィールド用
static enum{END=-1}manage;
enum{TITLE,STORY,FREE,CONFIG}mode;
int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nCmdShow){
	if(ChangeWindowMode(TRUE)==END || SetGraphMode(640,480,16)!=DX_CHANGESCREEN_OK || DxLib_Init()==END)return END;
	if(SetOutApplicationLogValidFlag(FALSE)==END || SetAlwaysRunFlag(TRUE)==END || SetDrawScreen(DX_SCREEN_BACK)==END || SetWindowText("ポップ ゼリー")==END){
		DxLib_End();
		return 0;
	}
		data.image[0]=LoadGraph("./pop-jelly/Image/background/title.png"); //タイトル
		data.image[1]=LoadGraph("./pop-jelly/Image/background/background.png"); //ポップゼリー メイン背景
		data.image[2]=LoadGraph("./pop-jelly/Image/background/frame.png"); //ポップゼリー フレーム部分
		data.image[3]=LoadGraph("./pop-jelly/Image/message.png"); //メッセージ表示領域
		data.image[4]=LoadGraph("./pop-jelly/Image/select.png"); //選択ボタン
		data.image[5]=LoadGraph("./pop-jelly/Image/select_now.png"); //現在選択中のもの
		data.pop[0]=0;
		data.pop[1]=LoadGraph("./pop-jelly/Image/pop/red.png"); //赤ポップ
		data.pop[2]=LoadGraph("./pop-jelly/Image/pop/blue.png"); //青ポップ
		data.pop[3]=LoadGraph("./pop-jelly/Image/pop/green.png"); //緑ポップ
		data.pop[4]=LoadGraph("./pop-jelly/Image/pop/pink.png"); //ピンクポップ
		data.pop[5]=LoadGraph("./pop-jelly/Image/pop/block.png"); //ブロックポップ
		data.pop[6]=LoadGraph("./pop-jelly/Image/pop/cross.png"); //×
		data.character[0]=LoadGraph("./pop-jelly/Image/character/slime1.png"); //アースLv1
		data.character[1]=LoadGraph("./pop-jelly/Image/character/slime2.png"); //アースLv2
		data.character[2]=LoadGraph("./pop-jelly/Image/character/slime3.png"); //アースLv3
		data.character[3]=LoadGraph("./pop-jelly/Image/character/slime4.png"); //アースLv4
		data.character[4]=LoadGraph("./pop-jelly/Image/character/sun.png"); //サン
		data.effect[0]=LoadSoundMem("./pop-jelly/Music/message.ogg"); //次のメッセージへ移る時
		data.effect[1]=LoadSoundMem("./pop-jelly/Music/select.ogg"); //選択効果音
		data.effect[2]=LoadSoundMem("./pop-jelly/Music/enter.ogg"); //決定音
		data.effect[3]=LoadSoundMem("./pop-jelly/Music/story/vire.ogg"); //剣が当たる音
		data.music[0]=LoadSoundMem("./pop-jelly/Music/title.ogg"); //タイトル
		popjelly_mKind[0]=GetRand(RAND)+1;
		popjelly_mKind[1]=GetRand(RAND)+1;
		popjelly_eKind[0]=GetRand(RAND)+1;
		popjelly_eKind[1]=GetRand(RAND)+1;
		popjelly_mNext[0]=GetRand(RAND)+1;
		popjelly_mNext[1]=GetRand(RAND)+1;
		popjelly_eNext[0]=GetRand(RAND)+1;
		popjelly_eNext[1]=GetRand(RAND)+1;
	Menu();
	DxLib_End();
	return 0;
}
static void Menu(void){
	natural mode=TITLE; //モード選択
	bool end=false; //終了用
	char key[256]; //キー情報保存用
		natural title_select=0;
		struct MENU title_menu[4]={ //メニュー
			{32,320,5,55,370,"ストーリー"},
			{184,320,4,210,370,"自由練習"},
			{338,320,4,355,370,"コンフィグ"},
			{492,320,4,540,370,"終了"}
		};
#if isMusicOn
PlaySoundMem(data.music[0],DX_PLAYTYPE_LOOP); //音楽再生
#endif
	while(1){
		if(ScreenFlip()==END || ProcessMessage()==END || ClearDrawScreen()==END)break; //失敗したら終了
		UpdateKey(key);
		switch(mode){
		case TITLE:{
				count returnValue=Title(key,title_menu,title_select);
				if(returnValue==END)end=true;
				else if(returnValue){
					mode=returnValue;
				}
			}
			break;
		case STORY:
			if(Story(key)==END)end=true;
			break;
		case FREE:
			if(Free(key)==END)end=true;
			break;
		case CONFIG:
			if(Config(key)==END)end=true;
			break;
		default: //終了 または、例外
			end=true;
			break;
		}
		if(end)break;
	}
}
static void UpdateKey(char *KeyStateBuf){
	char key[256];
	GetHitKeyStateAll(key);
	for(natural i=0;i<256;i++){
		if(key[i]==0)KeyStateBuf[i]=0;
		else KeyStateBuf[i]++;
	}
}//完全実装 不具合なし
static count Title(char *key,MENU menu[4],natural &tselect){
	DrawGraph(0,0,data.image[0],FALSE); //背景描写
	int right=key[KEY_INPUT_RIGHT],left=key[KEY_INPUT_LEFT]; //キー取得
	if(key[KEY_INPUT_RETURN]==1){ //Enterキー押した
#if isMusicOn
		StopSoundMem(data.music[0]); //音楽を止める
#endif
#if isEffectOn
		PlaySoundMem(data.effect[2],DX_PLAYTYPE_BACK); //キーを押した音
#endif
		DrawButtons_title(menu); //ボタンの表示
		return tselect+1; //選択したボタン+1を返して終了
	}
	else if(key[KEY_INPUT_ESCAPE]==1){ //Escapeキーを押した
		DrawButtons_title(menu); //ボタンの表示
		return END; //終了
	}
	else if(left==1 || left>35 && left%5==0){ //左を押した
		if(left==125)key[KEY_INPUT_LEFT]=34; //オーバーフロー対策用
		menu[tselect].handle=4; //現在選択中の要素は選択中ではない画像に
		tselect=(tselect+3)%4; //左を計算
		menu[tselect].handle=5; //選択中になった要素は/を選択中の画像に
#if isEffectOn
		PlaySoundMem(data.effect[1],DX_PLAYTYPE_BACK); //選択音
#endif
	}
	else if(right==1 || right>35 && right%5==0){ //右を押した
		if(right==125)key[KEY_INPUT_RIGHT]=34; //オーバーフロー対策用
		menu[tselect].handle=4; //現在選択中の要素は選択中ではない画像に
		tselect=(tselect+1)%4; //右を計算
		menu[tselect].handle=5; //選択中になった要素を選択中の画像に
#if isEffectOn
		PlaySoundMem(data.effect[1],DX_PLAYTYPE_BACK); //選択音
#endif
	}
	DrawButtons_title(menu); //ボタンの表示
	return TITLE; //TITLE画面の表示を継続
}
static void DrawButtons_title(MENU menu[4]){
	DrawGraph(menu[0].imgX,menu[0].imgY,data.image[menu[0].handle],TRUE); //ボタン画像
	DrawString(menu[0].nameX,menu[0].nameY,menu[0].name,GetColor(255,255,255)); //ボタン内容
	DrawGraph(menu[1].imgX,menu[1].imgY,data.image[menu[1].handle],TRUE); //ボタン画像
	DrawString(menu[1].nameX,menu[1].nameY,menu[1].name,GetColor(255,255,255)); //ボタン内容
	DrawGraph(menu[2].imgX,menu[2].imgY,data.image[menu[2].handle],TRUE); //ボタン画像
	DrawString(menu[2].nameX,menu[2].nameY,menu[2].name,GetColor(255,255,255)); //ボタン内容
	DrawGraph(menu[3].imgX,menu[3].imgY,data.image[menu[3].handle],TRUE); //ボタン画像
	DrawString(menu[3].nameX,menu[3].nameY,menu[3].name,GetColor(255,255,255)); //ボタン内容
}
static void Message(const char name[],const char message[]){
	DrawGraph(10,340,data.image[3],TRUE);
	DrawString(40,375,name,0xffffff);
	DrawString(80,400,message,0xffffff);
}//不完全実装 画像適当文字適当
static bool Fall(natural mass[HEIGHT][WIDTH]){
	bool n=0;
	for(natural x=0;x<WIDTH;x++) //一番左から
		for(natural y=HEIGHT-1;y>0;y--) //一番下から(14段目を除く)
			if(mass[y][x]==0){ //空のマスなら
				count i;
				for(i=y-1;i>=0 && (mass[i][x]==0 || mass[i][x]==CROSS);i--); //空のマスと、×は飛ばす
				if(i<0)break; //上にポップがない
				if(!n)n=true; //落ちたかどうか
				for(i=y;i>=0;i--)
					if(mass[i][x]!=CROSS)
						mass[i][x]=(i>0 && mass[i-1][x]!=CROSS ? mass[i-1][x] : 0); //このマスをすぐ上のマスに。一番上か、上が×なら、空にする
				break;
			}
	return n;
}//完全実装済み 不具合なし?
static natural Link(natural mass[HEIGHT][WIDTH],natural x,natural y,natural kind,natural checked[HEIGHT][WIDTH]){
	natural chain=1;
	if(checked[y][x]==1)return 0; //既にチェック済み
	checked[y][x]=1;
	if(mass[y][x]==0 || mass[y][x]==BLOCK || mass[y][x]==CROSS)return 0; //空かブロックポップか×
	if(y>2 && mass[y-1][x]==kind)chain+=Link(mass,x,y-1,kind,checked); //上(見えない部分は除く)
	if(x<5 && mass[y][x+1]==kind)chain+=Link(mass,x+1,y,kind,checked); //右
	if(x>0 && mass[y][x-1]==kind)chain+=Link(mass,x-1,y,kind,checked); //左
	if(y<13 && mass[y+1][x]==kind)chain+=Link(mass,x,y+1,kind,checked); //下
	return chain; //結合数
}//完成
static void Delete(natural mass[HEIGHT][WIDTH],natural x,natural y,natural kind){
	if(mass[y][x]==kind){
		mass[y][x]=0; //消す
		if(y>2 && mass[y-1][x]==kind)Delete(mass,x,y-1,kind); //上(見えない部分は除く)
		if(x<5 && mass[y][x+1]==kind)Delete(mass,x+1,y,kind); //右
		if(x>0 && mass[y][x-1]==kind)Delete(mass,x-1,y,kind); //左
		if(y<13 && mass[y+1][x]==kind)Delete(mass,x,y+1,kind); //下
	}
}//完成
static void init_popjelly(void){
	for(count i=0;i<2;i++){
		popjelly_count[i]=LIMIT;
		popjelly_time[i]=1;
		popjelly_process[i]=0;
		popjelly_turn[i]=0;
		popjelly_linkage[i]=0;
		popjelly_block[i]=0;
		popjelly_isChain[i]=false;
		popjelly_mKind[i]=GetRand(RAND)+1;
		popjelly_eKind[i]=GetRand(RAND)+1;
		popjelly_mNext[i]=GetRand(RAND)+1;
		popjelly_mNext[i]=GetRand(RAND)+1;
		popjelly_mPosition[i].x=2;
		popjelly_ePosition[i].x=2;
	}
	for(count i=0;i<256;popjelly_key[i++]=0);
	popjelly_mPosition[0].y=0;
	popjelly_mPosition[1].y=1;
	popjelly_ePosition[0].y=0;
	popjelly_ePosition[1].y=1;
	popjelly_mass=popjelly_mass_copy;
}
static bool mPopJelly(popjelly_COORDINATE position[2],int &count,natural mass[HEIGHT][WIDTH],natural checked[HEIGHT][WIDTH],natural &process,char key[256]){ //自分の処理
	natural y1=position[0].y,x1=position[0].x,y2=position[1].y,x2=position[1].x;
	if(popjelly_isChain[0]){ //ポップが消える状態 連鎖処理
		popjelly_linkage[0]++; //連鎖数を増やす
		for(natural x=0;x<WIDTH;x++){ //一番左の
			for(natural y=HEIGHT-1;y>1;y--){ //一番下から、上から三番目迄
				natural temp=mass[y][x];
				if(temp && temp!=CROSS && temp!=BLOCK && Link(mass,x,y,temp,checked)>=4)Delete(mass,x,y,temp); //空白、×、BLOCKでなく、4つ以上繋がっているなら削除
			}
		}
		popjelly_isChain[0]=false; //削除完了
		process+=WaitAfterDelete;
	}
	else if(count>=LIMIT){ //床についてからLIMIT/60秒以上経ったら
		if(!Fall(mass)){ //ポップが落ちなかった
			mass[0][0]=0; //14段目のポップは消す。
			mass[0][1]=0;
			mass[0][2]=0;
			mass[0][3]=0;
			mass[0][4]=0;
			mass[0][5]=0;
			//連鎖確認処理
			for(natural x=0;x<WIDTH;x++){ //一番左の
				for(natural y=HEIGHT-1;y>1;y--){ //一番下から、上から三番目迄
					natural temp=mass[y][x];
					if(temp && temp!=CROSS && temp!=BLOCK && Link(mass,x,y,temp,checked)>=4){ //空白、×、BLOCKでなく、4つ以上繋がっている
						popjelly_isChain[0]=true; //ポップが消えた
						break;
					}
				}
				if(popjelly_isChain[0])break;
			}
			if(popjelly_isChain[0]){ //消える状態
				process+=WaitBeforeDelete; // 消す前に、WaitBeforeDelete/60秒待つ
			}
			else{ //消えなかった
				if(mass[2][2]!=CROSS || mass[2][3]!=CROSS){ //×に積んだ
					DrawString(30,50,"Game Over!! 3秒後に戻ります。",0x000000);
					return true;
				}
				popjelly_time[0]=1; // 1/60秒ごとに1増加。FPSになると、1に戻る
				popjelly_mKind[0]=popjelly_mNext[0]; //次のポップに。
				popjelly_mKind[1]=popjelly_mNext[1];
				popjelly_mNext[0]=GetRand(RAND)+1; //乱数で、種類を決める。
				popjelly_mNext[1]=GetRand(RAND)+1;
				position[0].x=2; //場所 初期化
				position[0].y=0;
				position[1].x=2;
				position[1].y=1;
				count=0; //床についてからのカウントを0にする。
				popjelly_isChain[0]=false;
				popjelly_turn[0]=0;
				popjelly_linkage[0]=0; //連鎖数 0
			}
		}
		else{
			process+=FallSpeed; // FallSpeed/60秒後にまた落とす
		}
	}
	else{ //通常の処理
		if(popjelly_time[0]>=FPS){ // FPS/60秒以上経過
			if(y1!=13 && y2!=13){ //一番下じゃないなら、ポップを下へ移動(自分)
				if(popjelly_turn[0]%2==0){
					if(!mass[y1+1][x1] || mass[y1+1][x1]==CROSS || !mass[y2+1][x2] || mass[y2+1][x2]==CROSS){
						mass[y1][x1]=0;
						mass[y2][x2]=0;
						position[0].y=++y1;
						position[1].y=++y2;
					}
				}
				else if((!mass[y1+1][x1] || mass[y1+1][x1]==CROSS) && (!mass[y2+1][x2] || mass[y2+1][x2]==CROSS)){
					mass[y1][x1]=0;
					mass[y2][x2]=0;
					position[0].y=++y1;
					position[1].y=++y2;
				}
			}
		}
		if(key[KEY_INPUT_RIGHT] && key[KEY_INPUT_RIGHT]%StepForKey==1 && x1!=5 && x2!=5){ //右端じゃない時に、右を押したとき
			if(popjelly_turn[0]%2==0){
				if((!mass[y1][x1+1] || mass[y1][x1+1]==CROSS) && (!mass[y2][x2+1] || mass[y2][x2+1]==CROSS)){
					mass[y1][x1]=0;
					mass[y2][x2]=0;
					position[0].x=++x1;
					position[1].x=++x2;
				}
			}
			else if(popjelly_turn[0]==1){ //2 1 の状態
				if(!mass[y1][x1+1] || mass[y1][x1+1]==CROSS){
					mass[y1][x1]=0;
					mass[y2][x2]=0;
					position[0].x=++x1;
					position[1].x=++x2;
				}
			}
			else if(!mass[y2][x2+1] || mass[y2][x2+1]==CROSS){ //1 2 の状態
				mass[y1][x1]=0;
				mass[y2][x2]=0;
				position[0].x=++x1;
				position[1].x=++x2;
			}
		}
		if(key[KEY_INPUT_LEFT] && key[KEY_INPUT_LEFT]%StepForKey==1 && x1 && x2){ //左端じゃない時に、左を押したとき
			if(popjelly_turn[0]%2==0){
				if((!mass[y1][x1-1] || mass[y1][x1-1]==CROSS) && (!mass[y2][x2-1] || mass[y2][x2-1]==CROSS)){
					mass[y1][x1]=0;
					mass[y2][x2]=0;
					position[0].x=--x1;
					position[1].x=--x2;
				}
			}
			else if(popjelly_turn[0]==1){ //2 1 の状態
				if(!mass[y2][x2-1] || mass[y2][x2-1]==CROSS){
					mass[y1][x1]=0;
					mass[y2][x2]=0;
					position[0].x=--x1;
					position[1].x=--x2;
				}
			}
			else if(!mass[y1][x1-1] || mass[y1][x1-1]==CROSS){ //1 2 の状態
				mass[y1][x1]=0;
				mass[y2][x2]=0;
				position[0].x=--x1;
				position[1].x=--x2;
			}
		}
		if(key[KEY_INPUT_DOWN] && key[KEY_INPUT_DOWN]%StepForKey==1 && y1!=13 && y2!=13){
			if(popjelly_turn[0]%2==0){
				if(!mass[y1+1][x1] || mass[y1+1][x1]==CROSS || !mass[y2+1][x2] || mass[y2+1][x2]==CROSS){
					mass[y1][x1]=0;
					mass[y2][x2]=0;
					position[0].y=++y1;
					position[1].y=++y2;
				}
				else count+=CountIfKeepDown; //下にポップがあるのに、[KEY_INPUT_DOWN]をする場合
			}
			else if((!mass[y1+1][x1] || mass[y1+1][x1]==CROSS) && (!mass[y2+1][x2] || mass[y2+1][x2]==CROSS)){
				mass[y1][x1]=0;
				mass[y2][x2]=0;
				position[0].y=++y1;
				position[1].y=++y2;
			}
			else count+=CountIfKeepDown; //下にポップがあるのに、[KEY_INPUT_DOWN]をする場合
		}
		if(key[KEY_INPUT_A]==1){ //回転判定(右回転)
			switch(popjelly_turn[0]){
			case 0: // 縦 position[0],[1] (1,2)
				if(x2==5 || mass[y2][x2+1] && mass[y2][x2+1]!=CROSS){ //右がポップか壁で
					if(x1 && (!mass[y2][x2-1] || mass[y2][x2-1]==CROSS)){ //左が空か×なら
						mass[y1][x1]=0;
						position[0].y=++y1;
						position[1].x=--x2;
					}
					else{ //どっちもポップ or 壁なら
						if(y2==13 || mass[y2+1][x2]){ //下にポップか壁があるなら
							position[0].y=++y1; //上のポップを下へ
							position[1].y=--y2; //下のポップを上へ
						}
						else{
							mass[y1][x1]=0;
							++y1;
							position[0].y=++y1; //上のポップを二つ下へ
						}
						popjelly_turn[0]++; //case 2まで飛ばす。
					}
				}
				else{ //右が空 もしくは ×
					mass[y1][x1]=0;
					position[0].x=++x1;
					position[0].y=++y1;
				}
				popjelly_turn[0]++;
				break;
			case 1: // 横 position[1],[0] (2,1)
				mass[y1][x1]=0;
				if(y2==13 || mass[y2+1][x2] && mass[y2+1][x2]!=CROSS){ //左ポップの下がポップか壁なら
					position[0].x=--x1;
					position[1].y=--y2;
				}
				else{ //左ポップの下が空 もしくは ×
					position[0].x=--x1;
					position[0].y=++y1;
				}
				popjelly_turn[0]++;
				break;
			case 2: // 縦 position[1],[0] (2,1)
				if(!x1 || mass[y1][x1-1] && mass[y1][x1-1]!=CROSS){ //左がポップか壁で
					if(x1!=5 && (!mass[y1][x1+1] || mass[y1][x1+1]==CROSS)){ //右が空か×なら
						mass[y2][x2]=0;
						position[1].y=++y2;
						position[1].x=++x2;
						popjelly_turn[0]=3;
					}
					else{ //どっちもポップ or 壁なら
						if(y1==13 || mass[y1+1][x1]){ //下にポップか壁があるなら
							position[1].y=++y2; //上のポップを下へ
							position[0].y=--y1; //下のポップを上へ
						}
						else{
							mass[y1][x1]=0;
							--y1;
							position[0].y=--y1; //下のポップを二つ上へ
						}
						popjelly_turn[0]=0;
					}
				}
				else{ //左が空 もしくは ×
					mass[y1][x1]=0;
					position[0].x=--x1;
					position[0].y=--y1;
					popjelly_turn[0]=3;
				}
				break;
			default: // 横 position[0],[1] (1,2)
				mass[y1][x1]=0;
				position[0].x=++x1;
				position[0].y=--y1;
				popjelly_turn[0]=0;
			}
		}
		if(key[KEY_INPUT_D]==1){ //回転判定(左回転)
			switch(popjelly_turn[0]){
			case 0: // 縦 position[0],[1] (1,2)
				if(x1==0 || mass[y2][x2-1] && mass[y2][x2-1]!=CROSS){ //左がポップか壁で
					if(x1!=5 && (!mass[y1][x1+1] || mass[y1][x1+1]==CROSS)){ //右が空か×なら
						mass[y1][x1]=0;
						position[0].y=++y1;
						position[1].x=++x2;
						popjelly_turn[0]=3;
					}
					else{ //どっちもポップ or 壁なら
						if(y2==13 || mass[y2+1][x2]){ //下にポップか壁があるなら
							position[0].y=++y1; //上のポップを下へ
							position[1].y=--y2; //下のポップを上へ
						}
						else{
							mass[y1][x1]=0;
							++y1;
							position[0].y=++y1; //上のポップを二つ下へ
						}
						popjelly_turn[0]=2;
					}
				}
				else{ //左が空 もしくは ×
					mass[y1][x1]=0;
					position[0].x=--x1;
					position[0].y=++y1;
					popjelly_turn[0]=3;
				}
				break;
			case 1: // 横 position[1],[0] (2,1)
				mass[y1][x1]=0;
				position[0].x=--x1;
				position[0].y=--y1;
				popjelly_turn[0]--;
				break;
			case 2: // 縦 position[1],[0] (2,1)
				if(x2==5 || mass[y2][x2+1] && mass[y2][x2+1]!=CROSS){ //右がポップか壁で
					if(x1 && (!mass[y1][x1-1] || mass[y1][x1-1]==CROSS)){ //左が空か×なら
						mass[y2][x2]=0;
						position[1].y=++y2;
						position[1].x=--x2;
					}
					else{ //どっちもポップ or 壁なら
						if(y1==13 || mass[y1+1][x1]){ //下にポップか壁があるなら
							position[0].y=--y1; //上のポップを下へ
							position[1].y=++y2; //下のポップを上へ
						}
						else{
							mass[y1][x1]=0;
							--y1;
							position[0].y=--y1; //下のポップを二つ上へ
						}
						popjelly_turn[0]--; //case 0まで飛ばす。
					}
				}
				else{ //右が空 もしくは ×
					mass[y1][x1]=0;
					position[0].x=++x1;
					position[0].y=--y1;
				}
				popjelly_turn[0]--;
				break;
			default: // 横 position[0],[1] (1,2)
				mass[y1][x1]=0;
				if(y2==13 || mass[y2+1][x2] && mass[y2+1][x2]!=CROSS){ //右ポップの下がポップか壁なら
					position[0].x=++x1;
					position[1].y=--y2;
				}
				else{ //左ポップの下が空 もしくは ×
					position[0].x=++x1;
					position[0].y=++y1;
				}
				popjelly_turn[0]--;
			}
		}
		mass[y1][x1]=popjelly_mKind[0];
		mass[y2][x2]=popjelly_mKind[1];
	}
	return false;
}
static bool ePopJelly(popjelly_COORDINATE position[2],int &count,natural mass[HEIGHT][WIDTH],natural checked[HEIGHT][WIDTH],natural &process){ //敵の処理
	natural y1=position[0].y,x1=position[0].x,y2=position[1].y,x2=position[1].x;
	if(popjelly_isChain[1]){ //ポップが消える状態 連鎖処理
		popjelly_linkage[1]++; //連鎖数を増やす
		for(natural x=0;x<WIDTH;x++){ //一番左の
			for(natural y=HEIGHT-1;y>1;y--){ //一番下から、上から三番目迄
				natural temp=mass[y][x];
				if(temp && temp!=CROSS && temp!=BLOCK && Link(mass,x,y,temp,checked)>=4)Delete(mass,x,y,temp); //空白、×、BLOCKでなく、4つ以上繋がっているなら削除
			}
		}
		popjelly_isChain[1]=false; //削除完了
		process+=WaitAfterDelete;
	}
	else if(count>=LIMIT){ //床についてからLIMIT/60秒以上経ったら
		if(!Fall(mass)){ //ポップが落ちなかった
			mass[0][0]=0; //14段目のポップは消す。
			mass[0][1]=0;
			mass[0][2]=0;
			mass[0][3]=0;
			mass[0][4]=0;
			mass[0][5]=0;
			//連鎖確認処理
			for(natural x=0;x<WIDTH;x++){ //一番左の
				for(natural y=HEIGHT-1;y>1;y--){ //一番下から、上から三番目迄
					natural temp=mass[y][x];
					if(temp && temp!=CROSS && temp!=BLOCK && Link(mass,x,y,temp,checked)>=4){ //空白、×、BLOCKでなく、4つ以上繋がっている
						popjelly_isChain[1]=true; //ポップが消えた
						break;
					}
				}
				if(popjelly_isChain[1])break;
			}
			if(popjelly_isChain[1]){ //消える状態
				process+=WaitBeforeDelete; // 消す前に、WaitBeforeDelete/60秒待つ
			}
			else{ //消えなかった
				if(mass[2][2]!=CROSS || mass[2][3]!=CROSS){ //×に積んだ
					DrawString(30,50,"ゲームクリア!おめでとう。",0x000000);
					return true;
				}
				popjelly_time[1]=1; // 1/60秒ごとに1増加。FPSになると、1に戻る
				popjelly_eKind[0]=popjelly_eNext[0]; //次のポップに。
				popjelly_eKind[1]=popjelly_eNext[1];
				popjelly_eNext[0]=GetRand(RAND)+1; //乱数で、種類を決める。
				popjelly_eNext[1]=GetRand(RAND)+1;
				position[0].x=2; //場所 初期化
				position[0].y=0;
				position[1].x=2;
				position[1].y=1;
				count=0; //床についてからのカウントを0にする。
				popjelly_isChain[1]=false;
				popjelly_turn[1]=0;
				popjelly_linkage[1]=0; //連鎖数 0
			}
		}
		else{
			process+=FallSpeed; // FallSpeed/60秒後にまた落とす
		}
	}
	else{
		if(mass[2][2]==0)mass[2][2]=CROSS;
		if(mass[2][3]==0)mass[2][3]=CROSS;
		if(popjelly_time[1]>=FPS){ // FPS/60秒以上経過
			if(y1!=13 && y2!=13){ // 一番下じゃないなら、下へ移動(敵)
				if(popjelly_turn[1]%2==0){
					if(!mass[y1+1][x1] || !mass[y2+1][x2] || mass[y1+1][x1]==CROSS || mass[y2+1][x2]==CROSS){
						mass[y1][x1]=0;
						mass[y2][x2]=0;
						position[0].y=++y1;
						position[1].y=++y2;
					}
				}
				else if((!mass[y1+1][x1] || mass[y1+1][x1]==CROSS) && (!mass[y2+1][x2] || mass[y2+1][x2]==CROSS)){
					mass[y1][x1]=0;
					mass[y2][x2]=0;
					position[0].y=++y1;
					position[1].y=++y2;
				}
			}
		}
		mass[y1][x1]=popjelly_eKind[0];
		mass[y2][x2]=popjelly_eKind[1];
	}
	return false;
}
static void printMass(char* title,natural mass[14][6]){
	printf("\n------------------ %s",title);
	for(count i=0;i<14;i++){
		printf("\n");
		for(count j=0;j<6;printf("%d",mass[i][j++]));
	}
}
static count PopJelly(char *key,natural level){
	if(key[KEY_INPUT_A]==127)key[KEY_INPUT_A]=126;
	if(key[KEY_INPUT_D]==127)key[KEY_INPUT_D]=126;
	if(key[KEY_INPUT_DOWN]==6)key[KEY_INPUT_DOWN]=0;
	if(key[KEY_INPUT_LEFT]==6)key[KEY_INPUT_LEFT]=0;
	if(key[KEY_INPUT_RIGHT]==6)key[KEY_INPUT_RIGHT]=0;
	DrawGraph(0,0,data.image[1],TRUE); //枠(背景)
	popjelly_checked=popjelly_copy; //初期化
	if(popjelly_mass.m[2][2]==0)popjelly_mass.m[2][2]=CROSS; //×の位置
	if(popjelly_mass.m[2][3]==0)popjelly_mass.m[2][3]=CROSS;
	if(popjelly_mass.e[2][2]==0)popjelly_mass.e[2][2]=CROSS; //×の位置
	if(popjelly_mass.e[2][3]==0)popjelly_mass.e[2][3]=CROSS;
	bool lose=false,win=false;
	if(popjelly_process[0])popjelly_process[0]--;
	else lose=mPopJelly(popjelly_mPosition,popjelly_count[0],popjelly_mass.m,popjelly_checked.m,popjelly_process[0],key);
	if(popjelly_process[1])popjelly_process[1]--;
	else win=ePopJelly(popjelly_ePosition,popjelly_count[1],popjelly_mass.e,popjelly_checked.e,popjelly_process[1]);
	natural my1=popjelly_mPosition[0].y,mx1=popjelly_mPosition[0].x,my2=popjelly_mPosition[1].y,mx2=popjelly_mPosition[1].x;
	natural ey1=popjelly_ePosition[0].y,ex1=popjelly_ePosition[0].x,ey2=popjelly_ePosition[1].y,ex2=popjelly_ePosition[1].x;
	for(int y=-64,i=0;y<=430;y+=38,i++){ //ポップを描く
		for(int x=46,j=0;x<=236;x+=38,j++)popjelly_mass.m[i][j] && DrawGraph(x,y,data.pop[popjelly_mass.m[i][j]],TRUE);
		for(int x=366,j=0;x<=556;x+=38,j++)popjelly_mass.e[i][j] && DrawGraph(x,y,data.pop[popjelly_mass.e[i][j]],TRUE);
	}
	DrawGraph(0,0,data.image[2],TRUE); //枠(メイン)
	if(lose||win){
		ScreenFlip();
		Sleep(1000);
		return END;
	}
	DrawGraph(278,10,data.pop[popjelly_mNext[0]],TRUE); //次のポップを表示(自分)
	DrawGraph(278,48,data.pop[popjelly_mNext[1]],TRUE);
	DrawGraph(321,10,data.pop[popjelly_eNext[0]],TRUE); //次のポップを表示(敵)
	DrawGraph(321,48,data.pop[popjelly_eNext[1]],TRUE);
	{
		char string[2][3];
		if(popjelly_linkage[0]){
			sprintf_s(string[0],"%d",popjelly_linkage[0]);
			popjelly_linkage[0] && DrawString(278,400,string[0],0x000000); //連鎖数を表示(自分)
		}
		if(popjelly_linkage[1]){
			sprintf_s(string[1],"%d",popjelly_linkage[1]);
			popjelly_linkage[1] && DrawString(321,400,string[1],0x000000); //連鎖数を表示(敵)
		}
	}
	if(key[KEY_INPUT_ESCAPE]==1)return END;
	else if(key[KEY_INPUT_RETURN]==1){
		int waitkey;
		DrawString(0,0,"一時停止",0xffffff);
		ScreenFlip();
		while(1){
			waitkey=WaitKey();
			if(waitkey==KEY_INPUT_RETURN)break;
			else if(waitkey==KEY_INPUT_SPACE)goto end;
		};
	}
	if(popjelly_turn[0]%2==0){
		if(my1==13 || my2==13 || popjelly_mass.m[my1+1][mx1] && popjelly_mass.m[my1+1][mx1]!=CROSS && popjelly_mass.m[my2+1][mx2] && popjelly_mass.m[my2+1][mx2]!=CROSS)popjelly_count[0]++;
	}
	else if(my1==13 && my2==13 || (popjelly_mass.m[my1+1][mx1] && popjelly_mass.m[my1+1][mx1]!=CROSS) || (popjelly_mass.m[my2+1][mx2] && popjelly_mass.m[my2+1][mx2]!=CROSS))popjelly_count[0]++;

	if(popjelly_turn[1]%2==0){
		if(ey1==13 || ey2==13 || popjelly_mass.e[ey1+1][ex1] && popjelly_mass.e[ey1+1][ex1]!=CROSS && popjelly_mass.e[ey2+1][ex2] && popjelly_mass.e[ey2+1][ex2]!=CROSS)popjelly_count[1]++;
	}
	else if(ey1==13 && ey2==13 || (popjelly_mass.e[ey1+1][ex1] && popjelly_mass.e[ey1+1][ex1]!=CROSS) || (popjelly_mass.e[ey2+1][ex2] && popjelly_mass.e[ey2+1][ex2]!=CROSS))popjelly_count[1]++;
	popjelly_time[0]++;
	popjelly_time[1]++;
	if(popjelly_time[0]>FPS)popjelly_time[0]=1;
	if(popjelly_time[1]>FPS)popjelly_time[1]=1;
	end:
	return 1; //終了
}
static count Story(char *key){
	int level=0,story=0;
	back:
	switch(level){
	case 0:
		while(1){
			if(!(ScreenFlip()==0 && ProcessMessage()==0 && ClearDrawScreen()==0))return 0;
			UpdateKey(key);
			DrawGraph(70,130,data.character[0],TRUE);
			DrawGraph(400,100,data.character[4],TRUE);
			switch(story){
			case 0:
				Message("アース","ここはどこだろう……?");
				break;
			case 1:
				Message("アース","うわぁ! あれは何!?");
				break;
			case 2:
				Message("???","スレア ヴァイア!"); // サン(ラスボス)
				ScreenFlip();
#if isEffectOn
				PlaySoundMem(data.effect[3],DX_PLAYTYPE_NORMAL);
#endif
				story++;
				break;
			case 3:
				Message("アース","ふにゃぁー……");
				break;
			default:
				Sleep(2000);
				level++;
				story=0;
				goto back;
			}
			if(key[KEY_INPUT_ESCAPE]==1)return 0;
			else if(key[KEY_INPUT_RETURN]==1){
				PlaySoundMem(data.effect[0],DX_PLAYTYPE_BACK);
				story++;
			}
		}
	case 1:
		while(1){
			if(!(ScreenFlip()==0 && ProcessMessage()==0 && ClearDrawScreen()==0))return 0;
			UpdateKey(key);
			DrawGraph(70,130,data.character[0],TRUE);
			DrawGraph(400,100,data.character[1],TRUE);
			switch(story){
			case 0:
				Message("アース","何してたんだろう……?");
				break;
			case 1:
				Message("???","な~めく~じく~じく~じ");
				break;
			case 2:
				Message("アース","近寄らないで……!");
				break;
			case 3:
				Message("ベトン","俺はベトンだ。。");
				break;
			case 4:
				Message("ベトン","Let's スライミング!!");
				break;
			case 5:
				Message("アース","しょうがないなぁ……");
				break;
			default:
				Sleep(2000);
				if(PopJelly(key,0)==1)level++;
				else return 0;
				story=0;
				//goto back;
				return 1;
			}
			if(key[KEY_INPUT_ESCAPE]==1)return 0;
			else if(key[KEY_INPUT_RETURN]==1){
#if isEffectOn
				PlaySoundMem(data.effect[0],DX_PLAYTYPE_BACK);
#endif
				story++;
			}
		}
	default:
		break;
	}
	return 1;
}
static count Free(char *key){
	return PopJelly(key,0);
}
static count Config(char *key){
	return 1;
}