「コントローラ確認・BG&スプライト出力」の編集履歴(バックアップ)一覧に戻る

コントローラ確認・BG&スプライト出力 - (2016/10/20 (木) 23:30:24) のソース

#contents()

*kihon.hの作成
メモ帳に以下の内容を書き、kihon.hという名前でcc65/includeに保存します。
#highlight(c){{{
/////////////////////////////////////////////////////////////////////////////////
// 2016.10.19 ver 0.15
// 煮るなり焼くなりお好きにどうぞ。
// -----------------------------------------------------------------------------
// cc65@wiki
// http://www34.atwiki.jp/cc65/
/////////////////////////////////////////////////////////////////////////////////
#define REGIST_PPU_CTRL1 (char*)0x2000
#define REGIST_PPU_CTRL2 (char*)0x2001
#define REGIST_PPU_STS   (char*)0x2002
#define REGIST_SPR_ADR   (char*)0x2003
#define REGIST_SPR_GRA   (char*)0x2004
#define REGIST_SCROLL    (char*)0x2005
#define REGIST_ADR       (char*)0x2006
#define REGIST_GRA       (char*)0x2007
#define REGIST_DMA       (char*)0x4014
#define JOYPAD           (char*)0x4016
#define BTN_A            0x80
#define BTN_B            0x40
#define BTN_SELECT       0x20
#define BTN_START        0x10
#define BTN_UP           0x08
#define BTN_DOWN         0x04
#define BTN_LEFT         0x02
#define BTN_RIGHT        0x01
#define GUN_TRIGGER      0x10
#define GUN_HIT          0x08
#define MIC_USE          0x04

unsigned char padinfo[2][2];
unsigned char padother;

//コントローラ確認
void CheckPad()
{
    unsigned char i,j,ret;
    *JOYPAD = 1;
    *JOYPAD = 0;
    padother= 0;
    for(i=0; i < 2; i++) {
        padinfo[i][1] = padinfo[i][0];
        padinfo[i][0]= 0;
        for(j=0; j < 8; j++) {
            ret = *(JOYPAD + i);
            padinfo[i][0] <<= 1;
            padinfo[i][0] += (ret & 0x01);
            padother |= (ret & 0x0F);
        }
    }
}

//ボタン押しっぱなし player:0=1P , 1=2P
char ButtonDown(unsigned char player,unsigned char btn)
{
    if(padinfo[player][0] & btn) {
        return 1;
    } else {
        return 0;
    }
}

//ボタン押す
char ButtonPush(unsigned char player,unsigned char btn)
{
    if((padinfo[player][0] & btn) && ! (padinfo[player][1] & btn)) {
        return 1;
    } else {
        return 0;
    }
}

//マイク・光線銃など
char ControlOther(unsigned char btn)
{
    if(padother & btn) {
        return 1;
    } else {
        return 0;
    }
}

// PPUコントロールレジスタの初期化
void InitPPU()
{
    *REGIST_PPU_CTRL1 = 0x00;
    *REGIST_PPU_CTRL2 = 0x00;
}

// PPUコントロールレジスタの設定
void SetPPU(unsigned char flag1,unsigned char flag2)
{
    *REGIST_PPU_CTRL1 = flag1;
    *REGIST_PPU_CTRL2 = flag2;
}

// スクロール設定
void SetScroll(unsigned char x, unsigned char y)
{
    *REGIST_SCROLL = x;
    *REGIST_SCROLL = y;
}

//背景設定(繰り返し)
void FillBackground(unsigned char address1, unsigned char address2, unsigned char val, unsigned char cnt)
{
    char i;

    *REGIST_ADR = address1;
    *REGIST_ADR = address2;
    for (i = 0; i < cnt; i++)
    {
        *REGIST_GRA = val;
    }
}

//背景設定
void SetBackground(unsigned char address1, unsigned char address2, unsigned char *bg, unsigned char cnt)
{
    char i;

    *REGIST_ADR = address1;
    *REGIST_ADR = address2;
    for (i = 0; i < cnt; i++)
    {
        *REGIST_GRA = *(bg + i);
    }
}

//座標から背景のアドレス計算
void GetBackgroundAddress(unsigned char screen, unsigned char x, unsigned char y, char *ret)
{
    unsigned int pos;

    switch (screen) {
    case 0:        //左下
        pos = 0x2000;
        break;
    case 1:        //右下
        pos = 0x2800;
        break;
    case 2:        //左上
        pos = 0x2400;
        break;
    case 3:        //右上
        pos = 0x2c00;
        break;
    }

    pos += y * 0x20 + x;
    *(ret + 0) = (pos & 0xff00) >> 8;
    *(ret + 1) =  pos & 0x00ff;
}

//属性設定(繰り返し)
void FillAttribute(unsigned char address1, unsigned char address2, unsigned char val, unsigned char cnt)
{
    FillBackground(address1,address2,val,cnt);
}

//属性設定
void SetAttribute(unsigned char address1, unsigned char address2, unsigned char *atr, unsigned char cnt)
{
    SetBackground(address1,address2,atr,cnt);
}

//パレット設定
void SetPalette(unsigned char *palette,unsigned char sprite)
{
    char i;

    *REGIST_ADR = 0x3f;
    if (sprite) {
        *REGIST_ADR = 0x10;
    } else {
        *REGIST_ADR = 0x00;
    }

    for (i = 0; i < 16; i++)
    {
        *REGIST_GRA = *(palette + i);
    }
}

//スプライト設定
void SetSprite(unsigned char first,unsigned char x,unsigned char y,unsigned char index,unsigned char flag)
{
    if (first) {
        *REGIST_SPR_ADR=0x00;
    }
    *REGIST_SPR_GRA=y;
    *REGIST_SPR_GRA=index;
    *REGIST_SPR_GRA=flag;
    *REGIST_SPR_GRA=x;
}

//DMA転送領域初期化
void InitDMA(unsigned char *address)
{
    int i;
    for(i=0; i < 256; i++) {
        *(address + i)=0;
    }
}

//DMA転送準備
void SetDMA(unsigned char *address,unsigned char first,unsigned char x,unsigned char y,unsigned char index,unsigned char flag)
{
    static unsigned char cnt;
    if (first) { cnt = 0; }
    *(address + cnt + 0)=y;
    *(address + cnt + 1)=index;
    *(address + cnt + 2)=flag;
    *(address + cnt + 3)=x;
    cnt+=4;
}

//DMA転送
void SendDMA(unsigned char address)
{
    *REGIST_DMA = address;
}

//VBlank待ち
void VBlank()
{
    while (! (*REGIST_PPU_STS & 0x80) );
}

//0爆弾待ち
void ZeroSprite()
{
    while (  (*REGIST_PPU_STS & 0x40) );
    while (! (*REGIST_PPU_STS & 0x40) );
}
}}}

*kihon.hの解説
-CheckPad:コントローラの確認。基本的に毎回呼び出す。
-ButtonDown:押されたボタンの確認。(押し続ける)
-ButtonPush:押されたボタンの確認。(押す→離す)
-ControlOther:マイク・光線銃の確認。
-InitPPU:PPUコントロールレジスタの初期化。
-SetPPU:PPUコントロールレジスタの設定。
--flag1:PPUコントロールレジスタ1の設定。
---bit7:VBlank時にNMIを実行
---bit6:PPUマスター/スレーブセレクト
---bit5:スプライトサイズ(0:8x8,1:8x16)
---bit4:BGパターンテーブルアドレス(0:$0000,1:$1000)
---bit3:スプライトパターンテーブルアドレス(0:$0000,1:$1000)
---bit2:PPUアドレスインクリメント(0:+1,1:+32)
---bit0,1:表示するネームテーブルアドレス番号(00:$2000・左下、01:$2400・左上、10:$2800・右下、11:$2C00・右上)
--flag2:PPUコントロールレジスタ2の設定。
---bit5-7:bit0=1のとき背景色/bit0=1のとき色強調&br()000:なし・001:緑・010:青・100:赤(それ以外の数字は不可)
---bit4:スプライト表示(0:非表示,1:表示)
---bit3:BG表示(0:非表示,1:表示)
---bit2:スプライトクリップ(0:画面の左8ドットを表示しない,1:クリップなし)
---bit1:BGクリップ(0:画面の左8ドットを表示しない,1:クリップなし)
---bit0:ディスプレイタイプ(0:カラー,1:モノクロ)
-SetScroll:背景のスクロール。
--x:横位置。
--y:縦位置。
-FillBackground:背景の設定(繰り返し)。
--address1:出力開始位置(上位2バイト)
--address2:出力開始位置(下位2バイト)
--val:出力内容(マスの番号)
--cnt:出力を繰り返す数
-SetBackground:背景の設定。
--address1:出力開始位置(上位2バイト)
--address2:出力開始位置(下位2バイト)
--*bg:出力内容のポインタ
--cnt:出力内容のバイト数
-GetBackgroundAddress:座標から背景のアドレスを算出。
--screen:画面(0:左下・初期画面,1:右下,2:左上,3:右上)
--x:横位置。
--y:縦位置。
--*ret:アドレスを格納する1バイト×2の配列
-SetPalette:パレットの設定。
--*palette:パレット内容のポインタ
--sprite:0:背景用パレット 1:スプライト用パレット
-FillAttribute:属性(背景4マス×4マス毎にどのパレットを使うか)の設定。(繰り返し)
--address1:出力先(上位2バイト)
--address2:出力先(下位2バイト)
--val:出力内容
--cnt:出力を繰り返す数
-SetAttribute:属性(背景4マス×4マス毎にどのパレットを使うか)の設定。
--address1:出力先(上位2バイト)
--address2:出力先(下位2バイト)
--*atr:出力内容のポインタ
--cnt:出力内容のバイト数
-SetSprite:スプライトの設定。
--first:1=1つ目のスプライト 0=2つ目以降
--x:横位置
--y:縦位置
--index:何コマ目の画像を表示するか
--flag:表示条件 
---7bit:上下反転
---6bit:左右反転
---5bit:背景よりも後ろに表示
---0,1bit:パレット番号
-SetDMA:DMA転送準備。(スプライト用領域の設定)
--*address:スプライト用領域の開始アドレス
--first:1=1つ目のスプライト 0=2つ目以降
--x,y,index,flag:SetSpriteと同内容。
-SendDMA:DMA転送
--address:スプライト用領域の開始アドレスの三桁目 0x1=0x0100
-VBlank:VBlank待ち処理。
-ZeroSprite:0爆弾待ち処理。
&color(red){※SetRegister・SetBackground・SetAttribute・SetPaletteは便宜上分けているだけで、やっている処理は同じです。}
&color(red){※FillBackgroundとFillAttributeも同様。}

*&spanid(ryuui){留意事項}
-SetBackgroundによる描画が間に合わない場合、背景がまだらに表示されます。
#highlight(c){{{
 VBlank()
 SetBackground(0x20,0x00,(char *)bg,32);
 SetScroll( 0, 0 );
}}}
-一時的に背景の描画を停止し、その間に描画することで回避できます。
#highlight(c){{{
 SetPPU(0x08,0x06);
 SetBackground(0x20,0x00,(char *)bg,32);
 SetScroll( 0, 0 );
 SetPPU(0x08,0x1e);
}}}
-描画する範囲を狭めることでも回避できます。
#highlight(c){{{
 VBlank();
 SetBackground(0x20,0x00,(char *)bg,10)
 SetScroll( 0, 0 );
 VBlank();
 SetBackground(0x20,0x0a,(char *)bg,10)
 SetScroll( 0, 0 );
 VBlank();
 SetBackground(0x20,0x14,(char *)bg,12)
 SetScroll( 0, 0 );
}}}
-SetBackgroundを呼び出さずにベタに処理を書くとより効果的です。&br()(#defineの使用は問題ありません。)
#highlight(c){{{
 *REGIST_ADR = 0x20;
 *REGIST_ADR = 0x00;
 *REGIST_GRA = 0;
 *REGIST_GRA = 1;
      :
      :
 *REGIST_GRA = 31;
}}}