[Prev] [Home] [Next]
2002/05
01日
本日から(実際は昨日から)バージョン0.3へ向けた作業を行う。
ちなみにバージョン0.3以降の道のりは以下の通り。
-0.3
プレイ中Aボタンでメニュー呼び出し。
メニューから、アンドゥ(1回だけ)、リトライ、タイトル画面へ戻る、が可能。
-0.4
無限回のアンドゥ可能(アンドゥはBボタン)
-0.5
プレイ中メニューからアンドゥ後のリドゥ可能。
複数レベル対応の仕組み。
-0.6
ファイルからのレベルデータ読み込み。
プレイ中メニューからレベルセレクト可能。
-0.7
トレースモード。
アバウト画面表示。
-0.8
プレイの手順を記録してファイルへ書き出し/読み込み。
-0.9
目標地点への自動移動を可能。
ヘルプ画面表示。
-1.0
設定ファイル対応。
グラフィック対応。
本日のメインはfgame.c。前回fsokoban.cから分割したフロークラス。
今後はここにレベルプレイのフロー機能を実装していく。
---ソース1−1(旧fgame.c)
/*******************************
SOKOBAN for DOS
fgame.c
Build:0001
Berse
(C)ThinkingRabbit
*******************************/
#include"level.h"
#define P_CLEAR 0
#define P_EXIT 1
#define P_RETRY 2
#define P_CHANGE_LEVEL 3
/*-------------- 20011214-Berse */
int FGplaygame()
{
int play,level, maxlevel;
struct leveldata ldata;
level = 1;
maxlevel = Lgetmaxlevel();
for(;;){
Lgetleveldata(level,&ldata);
Odispstatus(level, maxlevel, ldata.steplimit);
play = Pplaylevel(ldata);
if(play==P_CLEAR){
level++;
Oputstr(13,12,"+--------+");
Oputstr(13,13,"+ CLEAR! +");
Oputstr(13,14,"+--------+");
if(level > maxlevel){
Oputstr(13,10,"+--------+");
Oputstr(13,11,"+ ALL +");
Igetkey();
break;
}
Igetkey();
}else if(play==P_EXIT) break;
}
}
---
各規約に従わせるとともに以下の処理をサブルーチン化して機能を分割。
初期処理、実際のプレイ処理、クリア処理、オールクリア処理
ちなみに規約を1つ追加。
・格納値がコード表的な値が入る変数は末尾に大文字のCを付ける。
(それに伴い変数playをlevelresultCに変更)
また、画面表示に関してはデザイン層としてDoutputクラスを作成し、そこで対応させる事とした(doutput.c)。
後はlevelN、maxlevelN、levelresultCをクラス変数とし、また、オールクリア時の手順とメッセージを少々変更。
他のクラスも順次見直していくが、それに伴う変更も入ってくる予定。
---ソース1−2(新fgame.c)
/*******************************
SOKOBAN for DOS
fgame.c[FG]
Build:0002
Berse
(C)ThinkingRabbit
*******************************/
#include"level.h"
int P_CLEAR =0;
int P_EXIT =1;
int P_RETRY =2;
int P_CHANGE_LEVEL =3;
int levelN;
int maxlevelN;
int levelresultC;
/*-------------- 20020430-Berse */
void FGinit()
{
maxlevelN = Lgetmaxlevel();
levelN = 1;
}
/*-------------- 20020501-Berse */
int FGplaylevel()
{
int retC;
struct leveldata ldata;
Lgetleveldata(levelN,&ldata);
Odispstatus(levelN, maxlevelN, ldata.steplimit);
retC = Pplaylevel(ldata);
return retC;
}
/*-------------- 20020430-Berse */
void FGclear()
{
levelN++;
DOclear();
Igetkey();
}
/*-------------- 20020430-Berse */
void FGallclear()
{
DOallclear();
Igetkey();
}
/*-------------- 20020501-Berse */
void FGplaygame()
{
FGinit();
for(;;){
levelresultC = FGplaylevel();
if(levelresultC == P_CLEAR){
FGclear();
if(levelN > maxlevelN){
FGallclear();
return;
}
}else if(levelresultC == P_EXIT){
return;
}else{
; /* retry */
}
}
}
続いてdoutput.c。
ここは現在、DOclearとDOallclearのみ定義。
そのうち、output.cや他のところから、画面表示デザイン関係のものを持ってくる予定。
---ソース2(doutput.c)
/*******************************
SOKOBAN for DOS
doutput.c[DO]
Build:0001
Berse
(C)ThinkingRabbit
*******************************/
/*-------------- 20020430-Berse */
void DOclear()
{
Oputstr(13,12,"+--------+");
Oputstr(13,13,"+ CLEAR! +");
Oputstr(13,14,"+--------+");
}
/*-------------- 20020430-Berse */
void DOallclear()
{
Oputstr(13,12,"+--------+");
Oputstr(13,13,"+ ALL +");
Oputstr(13,14,"+ CLEAR! +");
Oputstr(13,15,"+--------+");
}
続いてsokoban.cのbuildを変更。
---ソース3−1(旧fsokoban.c)(一部)
/*-------------- 20020429-Berse */
FSinit()
{
fsokoban._VERSION = "0.2";
fsokoban.BUILD = 16;
Lsetlevelset();
}
---ソース3−1(新fsokoban.c)(一部)
/*-------------- 20020430-Berse */
FSinit()
{
fsokoban._VERSION = "0.2";
fsokoban.BUILD = 17;
Lsetlevelset();
}
という事で本日のコンパイル! オッケー。
実行! オッケー。
本日でのクラスの階層関係は次の通り。(変更なし)
フロー :Fsokoban.c / Fgame.c / MENU.C −プログラム制御
ロジック:PLAY.C / LEVELSET −データ処理部
デザイン:Doutput.c / OUTPUT.C / (INPUT.C) −入出力デザイン
部品 :(OUTPUT.C) / INPUT.C −汎用関数
環境依存:ENV.C −キーボード/画面/ファイルの制御
フロー層、ロジック層、デザイン層の関係を見直す必要があるな。
09日
本日はメニュー表示+整理の作業を行う。
まずはメニュー表示用にplay.cを変更する。
---ソース1−1(旧play.c)(一部)
/*-------------- 20011215-Berse */
int Pplaylevel(ldatawk)
struct leveldata ldatawk;
{
char key;
ldata = ldatawk;
Psetlevel();
Odisplevel(ldata);
key = KEY_NO;
for(;;){
key = Igetkey();
switch(key){
case KEY_U: Pmove(DIR_U);break;
case KEY_R: Pmove(DIR_R);break;
case KEY_D: Pmove(DIR_D);break;
case KEY_L: Pmove(DIR_L);break;
}
if(clear==1) break;
if((key==KEY_A)||(key==KEY_B)) break;
}
if(clear == 1) return(P_CLEAR);
if(key==KEY_A) return(P_RETRY);
if(key==KEY_B) return(P_EXIT);
}
今まではプレイ中にAボタン(KEY_A)が押された時にリトライ処理を行っていたが、今後はプレイメニューを呼び出して、その結果に応じて処理が変わる事となる。とりあえずプレイメニューを表示させて、今まで通りリトライ処理を行わせる事とする。
よって、P_RETRYコードを返す前に、Mplay()を呼び出す。
play.c自体の見直しは今後行う。
---ソース1−2(新play.c)(一部)
/*-------------- 20020504-Berse */
int Pplaylevel(ldatawk)
struct leveldata ldatawk;
{
char key;
ldata = ldatawk;
Psetlevel();
Odisplevel(ldata);
key = KEY_NO;
for(;;){
key = Igetkey();
switch(key){
case KEY_U: Pmove(DIR_U);break;
case KEY_R: Pmove(DIR_R);break;
case KEY_D: Pmove(DIR_D);break;
case KEY_L: Pmove(DIR_L);break;
}
if(clear==1) break;
if((key==KEY_A)||(key==KEY_B)) break;
}
if(clear == 1) return(P_CLEAR);
if(key==KEY_A){
Mplay();
return(P_RETRY);
}
if(key==KEY_B) return(P_EXIT);
}
---
続いて本日のメインのmenu.c。
大まかに以下の2つを行う。
・画面表示をdoutput.cにて行わせる。
・mtitleを別クラス(ftitle.c)へ分割
---ソース2(旧menu.c)
/*******************************
SOKOBAN for DOS
menu.c
Build:0003
Berse
(c) ThinkingRabbit
*******************************/
#include<stdio.h>
#include"input.h"
#define M_TITLE_START 0
#define M_TITLE_EXIT 1
/*-------------- 20011209-Berse */
int Mtitle(ver,bld)
char *ver;
int bld;
{
char key;
Oputstr(2, 2,"################################");
Oputstr(2, 3,"# #");
Oputstr(2, 4,"# ## # # # # ## # # # #");
Oputstr(2, 5,"# # # # # # # # # # # # ## # #");
Oputstr(2, 6,"# # # # ## # # ## ### #### #");
Oputstr(2, 7,"# # # # # # # # # # # # # ## #");
Oputstr(2, 8,"# ## # # # # ## # # # # #");
Oputstr(2, 9,"# #");
Oputstr(2,10,"# #");
Oputstr(2,11,"# # # # # #");
Oputstr(2,12,"# # # # ## #");
Oputstr(2,13,"# ### # # # #");
Oputstr(2,14,"# # # # #");
Oputstr(2,15,"# #");
Oputstr(2,16,"# ## # ## #");
Oputstr(2,17,"# # # # # # #");
Oputstr(2,18,"# # # # # # #");
Oputstr(2,19,"# # # # # # #");
Oputstr(2,20,"# ## # ## Ver.0.0 #");
Oputstr(2,21,"# Bld. #");
Oputstr(2,22,"# START: SPACE KEY #");
Oputstr(2,23,"# EXIT : ESC KEY #");
Oputstr(2,24,"# #");
Oputstr(2,25,"################################");
Oputstr(28,20,ver);
Oputnum(28,21,bld);
for(;;){
key = Igetkey();
if(key == KEY_A) return(M_TITLE_START);
if(key == KEY_B) return(M_TITLE_EXIT);
}
}
/*-------------- 20011213-Berse */
int Mplay()
{
char x,y,bx,by,item,ynow,key;
int i;
Oputstr(38,10,"+------------------+");
Oputstr(38,11,"| Undo |");
Oputstr(38,12,"| Redo |");
Oputstr(38,13,"| Auto Move |");
Oputstr(38,14,"| Trace-mode |");
Oputstr(38,15,"| Retry |");
Oputstr(38,16,"| Change Level |");
Oputstr(38,17,"| Back Title |");
Oputstr(38,18,"| continue Play |");
Oputstr(38,19,"+------------------+");
x=40;y=11;
item=8;
ynow=0;bx=x;by=y+1;
Oputmenucursor(x,y,bx,by);
key=KEY_NO;
while((key==KEY_A)||(key==KEY_B)){
key = Igetkey();
if((key==KEY_U)&&(ynow>0)){
by=y;y--;
Oputmenucursor(x,y,bx,by);
}
if((key==KEY_D)&&(ynow<(item-1))){
by=y;y++;
Oputmenucursor(x,y,bx,by);
}
}
for(i=0;i<(item+2);i++){
Oputstr(38,10+i," ");
}
if(key==KEY_A) return(ynow+1);
if(key==KEY_B) return(0);
}
---
doutput.cに画面表示関係を行わせる。
---ソース3(doutput.c)(一部)
/*-------------- 20020503-Berse */
void DOtitle(_ver, bld)
char *_ver;
int bld;
{
Oputstr(2, 2,"################################");
Oputstr(2, 3,"# #");
Oputstr(2, 4,"# ## # # # # ## # # # #");
Oputstr(2, 5,"# # # # # # # # # # # # ## # #");
Oputstr(2, 6,"# # # # ## # # ## ### #### #");
Oputstr(2, 7,"# # # # # # # # # # # # # ## #");
Oputstr(2, 8,"# ## # # # # ## # # # # #");
Oputstr(2, 9,"# #");
Oputstr(2,10,"# #");
Oputstr(2,11,"# # # # # #");
Oputstr(2,12,"# # # # ## #");
Oputstr(2,13,"# ### # # # #");
Oputstr(2,14,"# # # # #");
Oputstr(2,15,"# #");
Oputstr(2,16,"# ## # ## #");
Oputstr(2,17,"# # # # # # #");
Oputstr(2,18,"# # # # # # #");
Oputstr(2,19,"# # # # # # #");
Oputstr(2,20,"# ## # ## Ver.0.0 #");
Oputstr(2,21,"# Bld. #");
Oputstr(2,22,"# START: SPACE KEY #");
Oputstr(2,23,"# EXIT : ESC KEY #");
Oputstr(2,24,"# #");
Oputstr(2,25,"################################");
Oputstr(28,20,_ver);
Oputnum(28,21,bld);
}
/*-------------- 20020504-Berse */
void DOmenu()
{
Oputstr(38,10,"+------------------+");
Oputstr(38,11,"| Undo |");
Oputstr(38,12,"| Redo |");
Oputstr(38,13,"| Auto Move |");
Oputstr(38,14,"| Trace-mode |");
Oputstr(38,15,"| Retry |");
Oputstr(38,16,"| Change Level |");
Oputstr(38,17,"| Back Title |");
Oputstr(38,18,"| continue Play |");
Oputstr(38,19,"+------------------+");
}
/*-------------- 20020503-Berse */
void DOmenuhide(item)
char item;
{
int i;
for(i=0;i<(item+2);i++){
Oputstr(38,10+i," ");
}
}
/*-------------- 20020503-Berse */
void DOputmenucursor(x,y,bx,by)
char x, y, bx, by;
{
Oputmenucursor(x,y,bx,by);
}
続いてmenu.cの見直し。mtitleを別ファイル(ftitle.c)へ移動。
何でstdio.hなんかincludeしてたんだろう・・・。
---ソース4(menu.c)
/*******************************
SOKOBAN for DOS
menu.c
Build:0004/20020504
Berse
(c) ThinkingRabbit
*******************************/
/*-------------- 20020504-Berse */
#include"input.h"
/*-------------- 20020504-Berse */
int Mplay()
{
char x,y,bx,by,item,ynow,key;
int i;
DOmenu();
x=40;y=11;
item=8;
ynow=0;bx=x;by=y+1;
DOputmenucursor(x,y,bx,by);
key=KEY_NO;
while((key==KEY_A)||(key==KEY_B)){
key = Igetkey();
if((key==KEY_U)&&(ynow>0)){
by=y;y--;
DOputmenucursor(x,y,bx,by);
}
if((key==KEY_D)&&(ynow<(item-1))){
by=y;y++;
DOputmenucursor(x,y,bx,by);
}
}
DOmenuhide(item);
if(key==KEY_A) return(ynow+1);
if(key==KEY_B) return(0);
}
更に、分割したmtitleが入るftitle.c。
関数名はFTmenuに変更。
またfsokoban.cからFSmainloopも改名して移動(FTmainloop)。
ここからFGplaylevelを呼び出す事とする。
よってゲーム開始までのプログラムの流れは以下の様になる。
fsokoban.c(main)
↓
ftitle.c(FTmainloop)
↓
ftitle.c(FTmenu)
↓
fgame.c(FGplaygame)
↓
fgame.c(FGplaylevel)
↓
play.c(Pplaylevel)
うーむ、結構な階層数だ。多すぎる。
---ソース4(ftitle.c)
/*******************************
SOKOBAN for DOS
ftitle.c[FT]
Build:0001/20020504
Berse
(c) ThinkingRabbit
*******************************/
/*-------------- 20020504-Berse */
#include"input.h"
struct Ftitle_{
int M_TITLE_START;
int M_TITLE_EXIT;
int M_TITLE_ABOUT;
int M_TITLE_HELP;
} Ftitle;
/*-------------- 20020504-Berse */
FTinit()
{
Ftitle.M_TITLE_START = 0;
Ftitle.M_TITLE_EXIT = 1;
Ftitle.M_TITLE_ABOUT = 2;
Ftitle.M_TITLE_HELP = 3;
}
/*-------------- 20020504-Berse */
int FTmenu(_ver,bld)
char *_ver;
int bld;
{
char key;
DOtitle(_ver, bld);
for(;;){
key = Igetkey();
if(key == KEY_A) return(Ftitle.M_TITLE_START);
if(key == KEY_B) return(Ftitle.M_TITLE_EXIT);
}
}
/*-------------- 20020504-Berse */
FTmainloop(_ver, bld)
char *_ver;
int bld;
{
int menu;
for(;;){
menu = FTmenu(_ver, bld);
if(menu == Ftitle.M_TITLE_START){
FGplaygame();
}else{
break;
}
}
}
最後にfsokoban.c。FSmainloopをftitle.cにもっていったので随分小さくなった。
FSinit内にFTinitの呼び出しを追加。
メンバー定数の_VERSIONとBUILDは他からの呼び出しが今のところないので、structから外した。
---ソース5(fsokoban.c)
/*******************************
SOKOBAN for DOS
fsokoban.c[FS]
Ver. 0.2 Build:0018/20020504
Berse
(C)ThinkingRabbit
*******************************/
/*-------------- 20020504-Berse */
char *_VERSION;
int BUILD;
/*-------------- 20020504-Berse */
FSinit()
{
_VERSION = "0.2";
BUILD = 18;
Lsetlevelset();
FTinit();
}
/*-------------- 20020429-Berse */
main()
{
FSinit();
FTmainloop(_VERSION, BUILD);
}
さて、それでは本日のコンパイル! オッケー!
実行! ・・・あれ、メニューがすぐ消える。
あれ、Mplayのループの終了条件が逆だ・・・。
本日でのクラスの階層関係は次の通り。
フロー :Fsokoban.c / Fgame.c / Ftitle.c / MENU.C −プログラム制御
ロジック:PLAY.C / LEVELSET −データ処理部
デザイン:Doutput.c / OUTPUT.C / (INPUT.C) −入出力デザイン
部品 :(OUTPUT.C) / INPUT.C −汎用関数
環境依存:ENV.C −キーボード/画面/ファイルの制御
[Prev] [Home] [Next]