見出し画像

X68000 V-DISPの効果がすごい

 前回のV-DISP (V-Sync)を組み込んだフリッカーレスのブロック崩しのリストです。
 ぜひ、以前のものと比較してみてください。こんなにも印象が変わるのですね。

/* フリッカーレス */
#include <iocslib.h>

/* X68000の16ビットカラーコード定義 */
#define COLOR_BLACK   0x0000
#define COLOR_WHITE   0xffff
#define COLOR_BLUE    0x003f
#define COLOR_RED     0x07c1
#define COLOR_GREEN   0xf801
#define COLOR_YELLOW  0xffc1
#define COLOR_CYAN    0xf83f
#define COLOR_MAGENTA 0x07ff

/* ブロックの配置設定 */
#define BLOCK_ROWS 5
#define BLOCK_COLS 12

int main(void) {
    int old_mode;
    struct FILLPTR pad;
    struct FILLPTR ball;
    struct FILLPTR wall;
    struct FILLPTR blk;
    
    /* パドルの変数宣言 */
    int pad_width;
    int pad_height;
    int pad_x;
    int pad_y;
    int speed;
    int prev_pad_x;

    /* ボールの変数宣言 */
    int ball_size;
    int ball_x;
    int ball_y;
    int ball_vx;
    int ball_vy;
    int prev_ball_x;
    int prev_ball_y;

    /* ブロック管理の変数宣言 */
    int blocks[BLOCK_ROWS][BLOCK_COLS];
    int block_width;
    int block_height;
    int gap_x;
    int gap_y;
    int start_x;
    int start_y;
    int row;
    int col;

    /* V-SYNC同期(ハードウェア直接監視)用のポインタと、スタック退避用の変数 */
    volatile unsigned char *gpip;
    int ssp; /* スーパーバイザ移行時のスタック退避用 */

    /* 1. 現在の画面モードを保存 */
    old_mode = CRTMOD(-1);

    /* スーパーバイザモード(特権モード)へ移行します */
    /* これにより、システムI/O領域 $e88001 への直接読み取りが許可されます */
    ssp = B_SUPER(0);

    /* 画面初期化 (17: グラフィック16色 / 解像度 512x512) */
    CRTMOD(17);
    G_CLR_ON();
    
    /* WINDOWの解像度を設定 */
    WINDOW(0, 0, 511, 511);

    /* カラーパレット登録 */
    GPALET(0, COLOR_BLACK);
    GPALET(1, COLOR_WHITE);
    GPALET(2, COLOR_BLUE);
    GPALET(3, COLOR_RED);
    GPALET(4, COLOR_GREEN);
    GPALET(5, COLOR_YELLOW);
    GPALET(6, COLOR_CYAN);
    GPALET(7, COLOR_MAGENTA);

    /* ハードウェアレジスタのアドレス設定 */
    gpip = (volatile unsigned char *)0xe88001;

    /* 外壁の描画(青) */
    wall.x1 = 0; wall.y1 = 0; wall.x2 = 9; wall.y2 = 430; wall.color = 2;
    FILL(&wall);
    wall.x1 = 502; wall.y1 = 0; wall.x2 = 511; wall.y2 = 430; wall.color = 2;
    FILL(&wall);
    wall.x1 = 0; wall.y1 = 0; wall.x2 = 511; wall.y2 = 19; wall.color = 2;
    FILL(&wall);

    /* ブロック群の初期化と描画 */
    block_width = 39;
    block_height = 16;
    gap_x = 2;
    gap_y = 4;
    start_x = 11;
    start_y = 50;

    for (row = 0; row < BLOCK_ROWS; row++) {
        for (col = 0; col < BLOCK_COLS; col++) {
            blocks[row][col] = 1;

            blk.x1 = start_x + col * (block_width + gap_x);
            blk.y1 = start_y + row * (block_height + gap_y);
            blk.x2 = blk.x1 + block_width - 1;
            blk.y2 = blk.y1 + block_height - 1;
            blk.color = 3 + row;
            FILL(&blk);
        }
    }

    /* パドルの初期設定 */
    pad_width = 60;
    pad_height = 12;
    pad_x = (512 - pad_width) / 2;
    pad_y = 410;
    speed = 8;
    prev_pad_x = pad_x;

    /* パドルの初期描画 */
    pad.x1 = pad_x; pad.y1 = pad_y; pad.x2 = pad_x + pad_width - 1; pad.y2 = pad_y + pad_height - 1; pad.color = 1;
    FILL(&pad);

    /* ボールの初期設定 */
    ball_size = 8;
    ball_x = 256;
    ball_y = 200;
    ball_vx = 4;
    ball_vy = 4;
    prev_ball_x = ball_x;
    prev_ball_y = ball_y;

    /* ゲームのメインループ */
    while (1) {
        int is_moved;
        int new_x;
        int b_hit;
        int next_ball_x;
        int next_ball_y;

        /* ESCキーで終了 */
        if ((BITSNS(0) & 2) != 0) {
            break;
        }

        /* --- 計算フェーズ --- */
        prev_pad_x = pad_x;
        prev_ball_x = ball_x;
        prev_ball_y = ball_y;

        /* パドルの移動先計算 */
        is_moved = 0;
        new_x = pad_x;

        if ((BITSNS(7) & 8) != 0) {
            new_x = pad_x - speed;
            if (new_x < 10) { new_x = 10; }
            is_moved = 1;
        }
        if ((BITSNS(7) & 32) != 0) {
            new_x = pad_x + speed;
            if (new_x > 502 - pad_width) { new_x = 502 - pad_width; }
            is_moved = 1;
        }
        pad_x = new_x;

        /* ボールの移動先を予測 */
        next_ball_x = ball_x + ball_vx;
        next_ball_y = ball_y + ball_vy;

        /* 壁との衝突 */
        if (next_ball_x < 10) {
            next_ball_x = 10;
            ball_vx = -ball_vx;
        } else if (next_ball_x > 502 - ball_size) {
            next_ball_x = 502 - ball_size;
            ball_vx = -ball_vx;
        }

        if (next_ball_y < 20) {
            next_ball_y = 20;
            ball_vy = -ball_vy;
        }

        /* パドルとの衝突 */
        if (ball_vy > 0) {
            if (next_ball_y + ball_size >= pad_y && next_ball_y <= pad_y + pad_height) {
                if (next_ball_x + ball_size >= pad_x && next_ball_x <= pad_x + pad_width) {
                    next_ball_y = pad_y - ball_size;
                    ball_vy = -ball_vy;
                }
            }
        }

        /* ブロックとの衝突 */
        b_hit = 0;
        for (row = 0; row < BLOCK_ROWS && b_hit == 0; row++) {
            for (col = 0; col < BLOCK_COLS; col++) {
                if (blocks[row][col] == 1) {
                    int blx1 = start_x + col * (block_width + gap_x);
                    int bly1 = start_y + row * (block_height + gap_y);
                    int blx2 = blx1 + block_width - 1;
                    int bly2 = bly1 + block_height - 1;

                    if (next_ball_x <= blx2 && next_ball_x + ball_size - 1 >= blx1 &&
                        next_ball_y <= bly2 && next_ball_y + ball_size - 1 >= bly1) {
                        
                        blocks[row][col] = 0;

                        blk.x1 = blx1; blk.y1 = bly1; blk.x2 = blx2; blk.y2 = bly2; blk.color = 0;
                        FILL(&blk);

                        ball_vy = -ball_vy;
                        b_hit = 1;
                        break;
                    }
                }
            }
        }

        /* ミス判定 */
        if (next_ball_y > 430) {
            next_ball_x = 256;
            next_ball_y = 200;
            ball_vx = 4;
            ball_vy = 4;
        }

        ball_x = next_ball_x;
        ball_y = next_ball_y;

        /* --- 同期フェーズ (V-SYNC) --- */
        while ((*gpip & 0x10) == 0) ;
        while ((*gpip & 0x10) != 0) ;

        /* --- 描画フェーズ (V-Blank中に一気に行う) --- */
        if (pad_x != prev_pad_x) {
            pad.x1 = prev_pad_x; pad.y1 = pad_y; pad.x2 = prev_pad_x + pad_width - 1; pad.y2 = pad_y + pad_height - 1; pad.color = 0;
            FILL(&pad);

            pad.x1 = pad_x; pad.y1 = pad_y; pad.x2 = pad_x + pad_width - 1; pad.y2 = pad_y + pad_height - 1; pad.color = 1;
            FILL(&pad);
        }

        ball.x1 = prev_ball_x; ball.y1 = prev_ball_y; ball.x2 = prev_ball_x + ball_size - 1; ball.y2 = prev_ball_y + ball_size - 1; ball.color = 0;
        FILL(&ball);

        ball.x1 = ball_x; ball.y1 = ball_y; ball.x2 = ball_x + ball_size - 1; ball.y2 = ball_y + ball_size - 1; ball.color = 1;
        FILL(&ball);
    }

    /* 画面モードを元に戻す */
    CRTMOD(old_mode);

    /* ユーザーモード(通常の安全なモード)に戻してプログラムを終了します */
    B_SUPER(ssp);

    return 0;
}

このまま、XCでコンパイルすれば動作します。
cc /Y block.c


エミュレータ上での動作

今回は、右を空けています。
いろいろな情報を表示できるようにです。
それでは、ヌルヌル動くようになったゲームをお楽しみください。

2026.8.8

いいなと思ったら応援しよう!