■ふう、秋もお休み中ですう。現実世界はキビシーからひと働やっぱ休まんとイカんです。わあ冬休み楽しみ♪
そりゃともかくsegalagaそろそろテストROMとしての職責(?)をはたさなくなってきたんで、過去にダウングレード。
これは何が言いたいかというと、「セガャラガ」は256x240モード。つまり32カラムモードのテストだった訳です。んが320x240モード、
つまり40カラムモードのテストROMが欲しい。そこで、VDPコマンドの12番つまり(0x0c)を発行して、40カラムモードにしてみたのです。
(註:反転機能をまだ考慮してないからハグッタよーな迷路画面は、迷路の幅が256ドットだからワカルでしょう。タブン)
んでソース。
/* utils.c*/
static void init_vdp(void)
{
ushort *pw;
register uchar *pb;
pw = (ushort *) VDP_CNTL;
/* Lifted the struct from gens 2.12 .*/
/* 0 UINT8 Set1; */ *pw = 0x8014; /* reg. 80 - Enable HBL */
/* 1 UINT8 Set2; */ *pw = 0x8174; /* reg. 81 - Enable VBL */
/* 2 UINT8 Pat_ScrA_Adr; */ *pw = 0x8238; /* reg. 82 - Plane A =E000 */
/* 3 UINT8 Pat_Win_Adr; */ *pw = 0x8338; /* reg. 83 - " " */
/* 4 UINT8 Pat_ScrB_Adr; */ *pw = 0x8406; /* reg. 84 - Plane B =C000 */
/* 5 UINT8 Spr_Att_Adr; */ *pw = 0x857F; /* reg. 85 - sprite table begins at $FE00 */
/* 6 UINT8 Reg6; */ *pw = 0x8600;
/* 7 UINT8 BG_Color; */ *pw = 0x8700; /* background color */
/* 8 UINT8 Reg8; */ *pw = 0x8800;
/* 9 UINT8 Reg9; */ *pw = 0x8900;
/*10 0x0a UINT8 H_Int; */ *pw = 0x8a08; /* generate a HLI every 8 lines */
/*11 0x0b UINT8 Set3; */ *pw = 0x8b00;
/*12 0x0c UINT8 Set4; */ *pw = 0x8c01; /*40 cell*/
// ---- si--
// s shadow/highlight 0:off 1:on
// i interlace 0:off 1:on
// ?
// c H_Cell s__c 0__0:32 cell
// c H_Cell s__c 0__1:40 cell
// c H_Cell s__c 1__0:40 cell??(どうもこうなるらしい)
// c H_Cell s__c 1__1:40 cell
/*13 0x0d UINT8 H_Scr_Adr; */ *pw = 0x8d08;
/*14 0x0e UINT8 Reg14; */ *pw = 0x8e00;
/*15 0x0f UINT8 Auto_Inc; */ *pw = 0x8f02;
/*16 0x10 UINT8 Scr_Size; */ *pw = 0x9000;
/*17 0x11 UINT8 Win_H_Pos; */
/*18 0x12 UINT8 Win_V_Pos; */
<以下略>
どっかでみたよーなそーすだなあ?ってsegadriveからのコピペですね!もっと言っちまえばGens2.12からのコピペ。
VDPコマンドはどおやって使うのかとゆーと、こーやって使うのです。(これでワカンナイならのーみそタン使ってないカモネ)
えっと、しょうがないな。マジメ(?)に解説すると、「頭(MSB)はビット立てるつまりxxx|=0x8000;だにゃ」そんでとにかく、
「VDPレジスタ番号」、「VDPレジスタに入れる引数」。になる訳。例えば0x0cレジスタに0xffを入れたかったら、*pw=(0x8000)|(0x0c<<8)|(0xff);に、
なる訳ですね。(註:「pw」はshortのポインタで「0x00c00004」番地を指してる。「0x00c00004」番地はVDPのコントロールポート)
とにかく、「*pw = 0x8c01; /*40 cell*/」にしてみた、「セガャラガ」とは、「そこだけが違う」(現状、あとは同じもの)。
んだが、OBJが表示されねー。何でOBJ出ないんだろと、少し調べる必要がある訳です。
ちなみに、256で(仮想画面の)パターンがミラーになってるのは、現状そーゆーモードになってるからで、モード変えれば(仮想画面のサイズ)
簡単に直るのです。マダやってないケド、えっと確かVDPコマンドの16番(0x10)だったよな。
つまり「/*16 0x10 UINT8 Scr_Size; */ *pw = 0x9000;」を変えないと...。
(2006-09/03、04:44)
とゆー訳でやってみる。「*pw = 0x9000;」を「*pw = 0x9001;」にしたダケ。
それにしても、OBJはどおやって出すんだーうぉーwwん。
(2006-09/03、07:00)
PSP実機に転送し、segadriveA33でチェック。なんとOBJ出る。
ちなみにpicodriveはOBJでない。Gens32がOBJ出ないし、やっぱここは「OBJ出ないのが正常動作」なんではあるまいか?
役に立つ(?)なあ。
(2006-09/03、07:30)
CHR反転機能は、OBJと同じで簡単だった。んだけどOBJまだ出し方わからんつ!
pspDGEN170でもOBJが出る事ハケーン。HazeMD0.05a00は出ない。Genecystも出ない。Genecystスゴwwww。あの時代にもう
ソコまで解析済みでしたか。恐れ入ります。それにしても、ううう、お、OBJが出ないなんて、とってもツインビ~じゃなかったナンセンス。
そおいや昔Censerのメガドラデモdisった奴がどっかにあったなあ。あれは確か40カラムモードだった気がする。データーばっかで、
プログラム小さかったよなあ。(今からDLして)disるのも(昔の)探すのもめんどいなあ。
(2006-09/03、13:33)
■やっとOBJ出たあ。
原因はVRAM配置。OBJ表示がどうのこうのとゆー簡単に予想できるようなものではなかった。
要するにVRAMのメモリ配置がバッティングしてた。
#if 0
/* [NG] */
#define VRAM_CHRDEF 0x0000
#define VRAM_PLB 0xc000
#define VRAM_PLA 0xe000
#define VRAM_PLW 0xe000
#define VRAM_OBJLST 0xfe00
#endif
/* [OK] */
#define VRAM_CHRDEF 0x0000
#define VRAM_PLB 0xc000
#define VRAM_PLA 0xe000
#define VRAM_PLW 0xe000
#define VRAM_OBJLST 0xf000
って最後しか違わんな。何でそーなるのかは、ヨクワカラン。40カラムモードの場合は0xfe00からではダメなのかも?わかんね。
んで、ソースにゃ続きがある。今までは「設定」。「設定」は「反映」しないとさ。んで、
<略>
/* scrollabase *//* 2 UINT8 Pat_ScrA_Adr; */ *pw = ((0x8200)|(VRAM_PLA>>10));
/* windowbase *//* 3 UINT8 Pat_Win_Adr; */ *pw = ((0x8300)|(VRAM_PLW>>10));
/* scrollbbase *//* 4 UINT8 Pat_ScrB_Adr; */ *pw = ((0x8400)|(VRAM_PLB>>13));
/* spritebase *//* 5 UINT8 Spr_Att_Adr; */ *pw = ((0x8500)|(VRAM_OBJLST>>9));
<略>
こうやって「反映させる」そうしないと「意味不明」になっちゃうから念の為。
さてと、ここでちと問題。16x16OBJはCHR画面(2画面)の背後に出てる。本来手前に出て欲しいなあ。
それから「8x8の上下反転OBJ」画面では「青い丸(註:セガャラガで敵の爆弾?だったOBJ)」だ。
これは何故か、CHR画面(2画面)より手前に表示されてる。
迷路の一部の白い線が欠けてる(隠れてる)のは、手前に表示されてるからだ。
(2006-09/04、11:00)
■半透明ですう。
(実機でも確認[picodrive])
(2006-09/05、07:33)
メガドラのOBJ座標がワカランと、しょーがない。自分のOBJ位置に(CHRで)「A」を描いてみた。
なんか生まれて始めてプログラムを組んだ頃の気分。初心忘るるべからず。
///////////
xy(
(((sprite[0].xAxis-(16*8))&0xfff8)>>3),
(((sprite[0].yAxis-(16*8))&0xfff8)>>3)
);
*vpw= COLOR_BANK0 | 'A';
//////////
(註:xy(xxx,yyy);は「(X,Y)座標→VRAM座標」変換&設定マクロ。画面モードが違うので、セガャラガのものとは違う)
なーる程。X,Y共「128ドット」ずれてる訳ね。それで、セガャラガの仮想値は変なんだ~。納得。
(註:つまりOBJ座標128,128が画面の上左隅の座標。(普通は0,0)。
だから下右隅は(128+320,128+240)==(448,368)って事。)
(2006-09/05、14:44)
■
なんとかでっちあげられそーな気がするが、気のせいかもしんない。とくにOBJのプライオリティーがヨクワカラン。
なーんか無理やりやると、出来るんだけど、(プログラムが)すごくタコになりそう。もっと簡単な方法ないのかなあ?
一応VRAM直アクセスはあきらめて、仮想VRAM方式にした。んで、「自分の走行ルーチンだけ」ちと作った。こんなん。
static short add_vv_now;/*実はunsigned charで十分*/
static void pac_calc_add_vv_now(void)/* 自分の進める量を決める。 */
{
add_vv_now=0x20;/*ここは固定小数点。ROUNDによって(量が)違う。*/
}
static void pac_get_chr_nowkey(void)/* nowkeyの方向のCHRを調べる。 */
{
pacvx = tbl16[TBL_JSTY+(nowkey)];
pacvy = tbl16[TBL_JSTX+(nowkey)];
bg_dat=(vmap
[((((pac_y)>>3) + pacvy )&0x1f)]
[((((pac_x)>>3) + pacvx )&0x1f)]
);
}
#define CHR_MONSTER_DOOR 0x14
static void move_pac(void)/*自分移動*/
{
short getkey;
/* 入力から方向のみ取り出す。 */
getkey=(sys_key & 0x0f);
/* 4方向に制限 */
getkey = tbl16[TBL_INVER+(getkey)];/*他の目的でどうせ要るテーブルを利用*/
getkey = tbl16[TBL_INVER+(getkey)];
/* ぴったりチェック */
if(
(0==(pac_x&0x07))&& // Y: x000?
(0==(pac_y&0x07)) // X: x000?
){
if(getkey==0)
{
nowkey=oldkey; /* 押されなかったら、止まらなくする。 */
}else{
nowkey=getkey;
}
pac_get_chr_nowkey();
if((CHR_MONSTER_DOOR-1)<bg_dat)/* 自分にとっての壁? */
{
nowkey=oldkey;/* 古い方向でもう一度調べる。 */
pac_get_chr_nowkey();
if((CHR_MONSTER_DOOR-1)<bg_dat)/* 自分にとっての壁? */
{
nowkey=0;/* (「現在目指す方向」と「古い方向」の)両方壁なら止まる。 */
}
}
}
/* 移動 */
pacvx = tbl16[TBL_JSTY+(nowkey)];
pacvy = tbl16[TBL_JSTX+(nowkey)];
pac_calc_add_vv_now();
{
short add_vv;
add_vv=add_vv_now;
do{
pac_x += pacvx;
pac_y += pacvy;
add_vv -=0x10;
}while(add_vv<0x10);
}
pac_x &= 0xff;
pac_y &= 0xff;
/* ここまで仮想座標、ここで実座標に変換 */
obj[OBJ_PAC].x = (128+(8*4)-8+4 )+pac_x;
obj[OBJ_PAC].y = (128-(8*2)-8+4 )+pac_y;
oldkey=nowkey;
}
なんか納得いかないが、めんどいからイイヤ。
(2006-09/06、21:21)
■地味にモンスターの移動ルーチンとか作る。こんなん。
static void move_monster(void){
short monss;
short now_monster;
short now_monster_obj;
if(0<max_ijike_time_counter)
{
max_ijike_time_counter--;
if(1==max_ijike_time_counter) priority_normal_mode();
}
monss=1;
do
{
MONSTER_STATUS *mon;
short mon_now_muki;
/* モンスターの種類 0:aka 1:pin 2:aos 3:guz */
now_monster=monss+monss+((sys_c_count&(1+1))?(1):(0));
now_monster_obj=OBJ_AKABEI_EYE+now_monster+now_monster;
mon=&monster[now_monster];
/* ターゲット(追いかけ先)を決める */
if(0==(sys_h_count&(8))){
/* 散りモードの場合 */
mon->tgt_x=mon->SU_X;
mon->tgt_y=mon->SU_Y;
}else{
/* 追いかけモードの場合 */
/*単純に追いかける*/
mon->tgt_x=pac_x;
mon->tgt_y=pac_y;
switch(now_monster){
// case AKABEI: break;
case PINKEY: //3x8==24dots先読み.
mon->tgt_x += tbl16[TBL_PSHY+(nowkey)];
mon->tgt_y += tbl16[TBL_PSHX+(nowkey)];
break;
case AOSUKE: // 距離が近いなら点対称の位置を目指す。
{
short wwx;
short wwy;
wwx=(pac_x-monster[AKABEI].wx);
wwy=(pac_y-monster[AKABEI].wy);
if(wwx<128) mon->tgt_x += wwx;
if(wwy<128) mon->tgt_y += wwy;
}
break;
case GUZUTA: //3x8==24dots後ろ。(註:ワカンナイでっす)
mon->tgt_x -= tbl16[TBL_PSHY+(nowkey)];
mon->tgt_y -= tbl16[TBL_PSHX+(nowkey)];
break;
}
#ifdef DEBUG_KAKUNIN
/* 仮想座標→実座標に変換 */
obj[now_monster_obj ].x = V2R_X(mon->tgt_x);
obj[now_monster_obj ].y = V2R_Y(mon->tgt_y);
#endif
}
mon_now_muki=mon->old_muki;
/* ぴったりチェック */
if(
(0==(mon->wx&0x07))&& // Y: x000?
(0==(mon->wy&0x07)) // X: x000?
){
//
// X [7] | [6] / ;
// X 111 | 110 / ;
// X | / [2] ;
// 011 X | / 010 ;
// [3] X U / ;
//----------L + R--------->x++ ;
// / D X ;
// 001 / | X 000 ;
// [1] / | X [0] ;
// / 101 V 100 X ;
// / [5] y++ [4] X ;
// ----------->X //表示アドレスオフセット量
// 上
//条件1:Xが負なら左右を逆にする。 | 1
//条件2:Yが負なら上下を逆にする。 | 左4 + 8右
//条件3:|Y|>|X|ならXとYをいれかえる。 V 2
// 厚みビット1684 Y 下
// 検索順序1 2 3 4 条件321 //モンスター検索テーブル(アルゴリズム)
//
short stbl[8*4]={
/*[0]*/ MUKI_R,MUKI_D,MUKI_U,MUKI_L, /* 検索順序:R->D->U->L */
/*[1]*/ MUKI_L,MUKI_D,MUKI_U,MUKI_R,
/*[2]*/ MUKI_R,MUKI_U,MUKI_D,MUKI_L,
/*[3]*/ MUKI_L,MUKI_U,MUKI_D,MUKI_R,
/*[4]*/ MUKI_D,MUKI_R,MUKI_L,MUKI_U,
/*[5]*/ MUKI_D,MUKI_L,MUKI_R,MUKI_U,
/*[6]*/ MUKI_U,MUKI_R,MUKI_L,MUKI_D,
/*[7]*/ MUKI_U,MUKI_L,MUKI_R,MUKI_D,
};
short serch_offs;
/* 検索順序を決める。 */
serch_offs=0; /* 検索条件を消す。 */
if((mon->tgt_x)<(mon->wx))/*自分よりターゲットXが負方向なら、*/
{ /* swap(tgt.x,mon->wx); */
serch_offs |=(4);/* 4==(2^(0+2))「厚みビット4」 */
}
if((mon->tgt_y)<(mon->wy))/*自分よりターゲットYが負方向なら、*/
{ /* swap(tgt.x,mon->wx); */
serch_offs |=(8);/* 8==(2^(1+2))「厚みビット8」 */
}
if(
((0==(serch_offs&(4)))?((mon->tgt_x)-(mon->wx)):((mon->wx)-(mon->tgt_x)))
<
((0==(serch_offs&(8)))?((mon->tgt_y)-(mon->wy)):((mon->wy)-(mon->tgt_y)))
)/*abs|Y|>abs|X|なら、*/
{
serch_offs |=(16);/* 16==(2^(2+2))「厚みビット16」 */
}
#define aaa
//#undef aaa
#ifdef aaa
/* 方向のCHRを調べる。 */
#define MON_GET_CHR \
{{\
short tmpvx;\
short tmpvy;\
tmpvx = tbl16[TBL_JSTY+(mon_now_muki)];\
tmpvy = tbl16[TBL_JSTX+(mon_now_muki)];\
bg_dat=(vmap \
[((((mon->wy)>>3) + tmpvy )&0x1f)]\
[((((mon->wx)>>3) + tmpvx )&0x1f)]\
);\
}}
#define VS_MON_KABE ((CHR_HENNA_ESA-1)<bg_dat)||/* モンスターにとっての壁? */
#else
#define MON_GET_CHR
#define VS_MON_KABE
#endif
/* 再帰(リエントラント)にすれば、すっきりするかも(?)。 */
mon_now_muki=stbl[serch_offs+0];
MON_GET_CHR;
if( VS_MON_KABE
(mon->old_muki==tbl16[TBL_INVER+(mon_now_muki)])
){
mon_now_muki=stbl[serch_offs+1];
MON_GET_CHR;
if( VS_MON_KABE
(mon->old_muki==tbl16[TBL_INVER+(mon_now_muki)])
){
mon_now_muki=stbl[serch_offs+2];
MON_GET_CHR;
if( VS_MON_KABE
(mon->old_muki==tbl16[TBL_INVER+(mon_now_muki)])
){
mon_now_muki=stbl[serch_offs+3];
MON_GET_CHR;
if( VS_MON_KABE
(mon->old_muki==tbl16[TBL_INVER+(mon_now_muki)])
){
mon_now_muki=mon->old_muki;
}
}
}
}
}
/* 移動(とりあえず1ドット) */
mon->wx += tbl16[TBL_JSTY+(mon_now_muki)];
mon->wy += tbl16[TBL_JSTX+(mon_now_muki)];
/* 移動(とりあえずもう1ドット) */
mon->wx += tbl16[TBL_JSTY+(mon_now_muki)];
mon->wy += tbl16[TBL_JSTX+(mon_now_muki)];
/**/
mon->wx &=0xff;
mon->wy &=0xff;
mon->old_muki=mon_now_muki;
/* ここまで仮想座標、ここで実座標に変換 */
#ifndef DEBUG_KAKUNIN
obj[now_monster_obj ].x = /* MONSTER EYE */
#endif
obj[now_monster_obj+1].x = V2R_X(mon->wx);
#ifndef DEBUG_KAKUNIN
obj[now_monster_obj ].y = /* MONSTER EYE */
#endif
obj[now_monster_obj+1].y = V2R_Y(mon->wy);
}
while(monss--);
}
static void pac_get_chr(short keykey)/* 方向のCHRを調べる。 */
{
pacvx = tbl16[TBL_JSTY+(keykey)];
pacvy = tbl16[TBL_JSTX+(keykey)];
bg_dat=(vmap
[((((pac_y)>>3) + pacvy )&0x1f)]
[((((pac_x)>>3) + pacvx )&0x1f)]
);
}
static short pac_walk;/* need static */
static void move_pac(void)/*自分移動*/
{
short getkey;
/* 入力から方向のみ取り出す。 */
getkey=(sys_key & 0x0f);
/* 4方向に制限 */
getkey = tbl16[TBL_INVER+(getkey)]; /*他の目的でどうせ要るテーブルを利用*/
getkey = tbl16[TBL_INVER+(getkey)];
/* ぴったりチェック */
if(
(0==(pac_x&0x07))&& // Y: x000?
(0==(pac_y&0x07)) // X: x000?
){
if(getkey==0)
{
nowkey=oldkey; /* 押されなかったら、止まらなくする。 */
}else{
nowkey=getkey;
}
pac_get_chr(nowkey);
if((CHR_MONSTER_DOOR-1)<bg_dat)/* 自分にとっての壁? */
{
nowkey=oldkey;/* 古い方向でもう一度調べる。 */
pac_get_chr(nowkey);
if((CHR_MONSTER_DOOR-1)<bg_dat)/* 自分にとっての壁? */
{
nowkey=0;/* (「現在目指す方向」と「古い方向」の)両方壁なら止まる。 */
}
}
/* お食事 */
pac_get_chr(0);
switch(bg_dat){
// case CHR_FRUIT_A: /* フルーツ#1*/
// case CHR_FRUIT_B: /* フルーツ#2*/
case CHR_POWER_ESA: /* パワーエサ power food.*/
max_ijike_time_counter=64*11;//1面の場合
/* 向き反転 */
monster[AKABEI].old_muki=tbl16[TBL_INVER+(monster[AKABEI].old_muki)];
monster[PINKEY].old_muki=tbl16[TBL_INVER+(monster[PINKEY].old_muki)];
monster[AOSUKE].old_muki=tbl16[TBL_INVER+(monster[AOSUKE].old_muki)];
monster[GUZUTA].old_muki=tbl16[TBL_INVER+(monster[GUZUTA].old_muki)];
/**/
priority_ijike_mode();
score1up+=(5-1);/*50pts*/
case CHR_HENNA_ESA: /* 変なエサ*/
case CHR_NORMAL_ESA: /* 普通のエサ dots.*/
score1up+=1;/*10pts*/
xy_plb(
(((pac_x+8*4 )&0xfff8)>>3),
(((pac_y-8*2 )&0xfff8)>>3)
);
*vpw= 0;
vmap[((((pac_y)>>3) + pacvy )&0x1f)]
[((((pac_x)>>3) + pacvx )&0x1f)]=((CHR_HENNA_ESA==bg_dat)?(CHR_HENNA_KABE):(0));
pac_walk-=0x10;/* 喰って遅い*/
break;
}
}
/* 移動 */
pacvx = tbl16[TBL_JSTY+(nowkey)];
pacvy = tbl16[TBL_JSTX+(nowkey)];
/* 自分の進める量を決める。 */
pac_walk+=0x10; /* +1 歩 */
if(nowkey!=oldkey){ pac_walk+=0x20; /* +2 歩 */ } /* 曲がった瞬間(now<>old)は、速い(?)。*/
{
while(pac_walk<0x20){
pac_walk -=0x10;
pac_x += pacvx;
pac_y += pacvy;
}
}
/**/
pac_x &= 0xff;
pac_y &= 0xff;
oldkey=nowkey;
/* ここまで仮想座標、ここで実座標に変換 */
obj[OBJ_PAC].x = V2R_X(pac_x);
obj[OBJ_PAC].y = V2R_Y(pac_y);
}
int main(void)/*メイン*/
{
init_system(); /* system初期化 */
init_coin(); /* game_data初期化 */
init_round(); /* ラウンド開始前の初期化部分のみ */
//test sound
sound_effect(2); play_sample((ulong)SOUND, SOUND_LENGTH);
/* ゲームループ*/
while(1) /* LOOP FOREVER */
{
/* ポーズボタン調べる。*/
if(BUTTON_S==(sys_key&0xf0)){ pause_mode=1; } /* ポーズモードへ移行。*/
if(pause_mode){ pause_main(); }
else{
/* ゲーム中(ポーズ中でない)*/
if(0==(sys_c_count&1)){
move_pac(); /* 自機処理*/
}else{
move_monster(); /* モンスター処理*/
}
show_score_value(score1up); /* スコア表示*/
}
/* VSYNC処理(VSYNC内でパッド読み込む)*/
flash_1up(); /* '1UP'とパワーエサ点滅。その他OBJアニメ。 */
show_objects(); /* スプライト(OBJ)表示*/
/* sound_main();*/
wait_vsync();
}
return 0;/* ダミー。*/
}
あとさ、OBJの優先順位の問題もあるし。
やっぱモンスターが動くと、ゲームっぽくなるなあ。
(2006-09/08、14:30)