PCエンジンのプログラミング(その3)Spriteを動かす

nicotakuya.hatenablog.com
前回の続きです。「HuC」を使って、PCエンジンのプログラミングをやってみたいと思います。
前回は変換ツールがPCXファイルしか対応してない&使いにくいというところで終わっていましたが、ついに変換ツールを自作してみました。
こちらで公開中です。

sites.google.com
このツールを使うと、BMPファイルから画像/パレットデータを抽出することができます。

f:id:nicotakuya:20201129020851p:plain
自作のスプライトエディタで画像をバイナリ化する

ツールの実行画面です。
ここでは例として、16x16ピクセルx64個のキャラクター画像を描いてみました。キャラクター1個あたりのデータ量は64ワードなので、64個で4096ワードのVRAMを消費します。

f:id:nicotakuya:20201129022034p:plain
メニューを拡大

変換時のメニューです。
binary 16colorのボタンがPCエンジン用です。
変換後、「pattern.bin」(パターン)と「palette.bin」(パレット)という2つのバイナリファイルが出力されます。
最初は「const char pattern[]={ データ、、、」みたく、テキストで出力したかったのですが、インクルードするとhucで謎のエラーが出てしまうので、バイナリにしました。

動作確認用のプログラムを作ってみました。以下の通りです。

/* sprite move by takuya matsubara*/
#include "huc.h"
#incbin(pattern,"pattern.bin");
#incbin(palette,"palette.bin");

#define CHRADDR   0x6F00
#define SPMAX 64

main()
{
    int num;
    char newx,newy;
    char x[SPMAX],y[SPMAX],x1[SPMAX],y1[SPMAX];

    load_vram(CHRADDR,pattern,64*64);
    init_satb();
    for(num=0; num<SPMAX; num++){
        spr_set(num);
        spr_pattern(CHRADDR+(64*num));
        spr_ctrl(SIZE_MAS|FLIP_MAS, SZ_16x16|NO_FLIP);
        spr_pal(0);
        spr_pri(1);
        x[num]=16+(num % 14)*16;
        y[num]=16+(num / 14)*16;
        x1[num]=(num % 7);
        y1[num]=(num % 5);
        if((x1[num]==0)&&(y1[num]==0))y1[num]=1;
    }
    vsync(1);
    set_sprpal(0, palette);

    while(1){
         vsync(1);
         for(num=0; num<SPMAX; num++){
             spr_set(num);
             newx = x[num]+x1[num];
             newy = y[num]+y1[num];
             if((newx<=8)||(newx>=248)) x1[num] *= -1;
             if((newy<=8)||(newy>=232)) y1[num] *= -1;
             spr_x(newx);
             spr_y(newy);
             x[num]=newx;
             y[num]=newy;
         }
         satb_update();
    }
}

パターン/パレットデータは「#incbin」マクロで組み込みます。
load_vram関数でVRAMに転送します。
パターンの転送先は適切なアドレスがよくわかりませんが、0x6F00番地にしてみました。0x7EFF番地までデータが格納されます。
これで、「#incspr」や「#incpal」を使わず、PCXファイルが不要になりました。
このソースをビルドして、ROMイメージ(pceファイル)を生成します。

f:id:nicotakuya:20201129020957p:plain
PCエンジンエミュレータの実行結果

PCエンジンエミュレータで実行した結果がこちらです。
64個のスプライトが画面をバウンドします。
エミュのせいかもしれませんが、全然処理落ちしてません。実機だとどうなるのか気になります。

続き
nicotakuya.hatenablog.com

PCエンジンのプログラミング(その2)Spriteのデータ構造

nicotakuya.hatenablog.com

前回の続きです。

前回は開発環境の「HuC」を導入して、サンプルプログラムを動かすところまでやってみました。

f:id:nicotakuya:20201127121618p:plain

「PONG」に付属するボールの画像

使ってみて気が付きましたが、画像の読み込みに対応しているファイル形式が「PCX」のみで、どうにも使いにくいです。

PCXファイルというのは、こんな感じの画像ファイルです。DOSの時代には良く使われていたみたいですが、今となってはマイナーなファイル形式だと思います。PCXファイルはirfanviewで開けましたが、Photoshopでは開けませんでした。

なので、PCXファイル以外に対応する変換ツールを自作する必要が出てきました。

 

f:id:nicotakuya:20201127121329p:plain

画像/パレットデータをダンプする

まず、HuCで「#inc~」マクロでPCXファイルを取り込んだ時にどんな感じにデータ化されるのかを調べます。ドキュメントを見てもよくわからないので、上記のようなプログラムを自作しました。「BALL.PCX」はサンプルのPONGに付属する画像ファイルです。

 

f:id:nicotakuya:20201127121438p:plain

PCエンジンエミュレータでの実行結果

hucとpceasでビルドして、PCエンジンエミュレータで実行すると、こういう画面が表示されます。画面上半分が画像データ、画面下半分がパレットデータです。

これだけだと、意味不明な16進数の羅列ですが、、、

 

f:id:nicotakuya:20201127121519p:plain

画像/パレットデータの構造

 いろいろ試行錯誤しながらデータを再構築してみました。マクロの出力は次のようなフォーマットだと思われます。

「#incspr」

・スプライト用は1枚あたり16x16ピクセル。他にも32x16、16x32ピクセルも選択可。

・1枚あたり4bit=16色。透明色を除くと実質15色。

・1枚あたりのパターンはint型(16bit)×64要素=64ワード。1要素は2値16ピクセルで考える。

・16要素で1プレーン。全4プレーン。下位ビットから順番にデータを格納。

 

「#incpal」

・1パレット16色。int型(16bit)×16要素=16ワード。カラーインデックス0番から格納。

・1要素あたりは9bit(bit8~6=緑、bit5~3=赤、bit0~2=青)

・8諧調x8諧調x8諧調=512色。

・0番のカラーは透明色。

 

これで画像/パレットデータの構造がわかりましたので、次は変換ツールを自作してみたいと思います。

nicotakuya.hatenablog.com

日経ソフトウエア2021年1月号

f:id:nicotakuya:20201124033335j:plain

日経ソフトウエア2021年1月号

 

2020年11月24日発売の「日経ソフトウエア2021年1月号」で「ファミコンで動くゲームを作ろう」という特集記事を書かせて頂きました。

f:id:nicotakuya:20201124033006p:plain

掲載プログラム(ファミコン用)

今回が第2回目です。ファミコンのライブラリが完成して、十字ボタンの入力ができたというところで終わっています。

次回、第3回目では実際にゲームを作ります。

 

PCエンジンのプログラミング(その1)開発環境の導入

突然ですが、PCエンジン用のプログラムを自作してみたいと思います。関連する知識が全くない状態からのスタートです。

まず最初にCC65が開発に使えるのでは、と思っていたのですが、CC65のドキュメントを読んでも使い方が良くわかりません、、、。付属のドキュメントには「Some useful resources on PCE coding:」というリンクを貼られていたのですが、その中の一つがこちら。

www.zeograd.com

「HuC」というPCエンジン用のCコンパイラがありました。これを使ってみます。CC65とは無関係ですね。開発は2005年で終わっています。バージョンが一杯ありますが、「huc-3.21-win.zip」をダウンロードしてみました。windows版ですが、DOS版との違いがわかりません。

 

f:id:nicotakuya:20201120225123p:plain

HuCを展開する

ZIPファイルを展開して、「huc-3.21-win」フォルダをCドライブの最上位ディレクトリに置いてみました。これでインストールは完了です。

binフォルダ内のEXEファイルは実行しようとすると「WindowsによってPCが保護されました」と出てしまうので、事前に解除しないといけません。

どうプログラムしたらいいのか、よくわからないので、docフォルダのドキュメントを読むと、「PONGが参考になる」という感じの一文を発見。そこで検索すると、次のページがヒットしました。

www.magicengine.com

こっちのHuC(huc_dos_142.zip)はタイムスタンプが2000年で、バージョンが5年ほど古いです。DEMOSフォルダにサンプルプログラムとして「PONG」と「SCROLL」が付属しています。これらのソースだけ頂くことにします。ソースの中に拡張子が「PCX」というファイルありますが、これはBG&スプライト用の画像ファイルです。

 

f:id:nicotakuya:20201120224512p:plain

ビルド用バッチファイル

ビルド用のバッチファイルを作ります。「PCE_INCLUDE」はHuCに指定するヘッダファイルのパスです。

「SRCFILE」はコンパイルしたいソースのファイル名。出力するROMイメージのファイル名と兼用です。

「huc」はCコンパイラ。「pceas」はアセンブラです。hucはCをアセンブラに変換するだけなので、pceasを使ってアセンブルを行います。

f:id:nicotakuya:20201209185526p:plain

バッチファイル

、、、と思ったのですが、hucからpceasを呼び出すのが正しかったようなので、上記のように修正しました。pceasを実行する記述を無くして、binまでのパスを設定しています。この場合、pceasの実行中にpauseのメッセージが表示されてしまうので、nulでメッセージを消しています。もしエラーが出ないならpauseは不要です。

バッチファイルを実行すると、PONGをリビルドします。そのままだとファイルが見つからないというエラーが出るので、ソースをちょっと直します。

#include "../huc.h"

#include "huc.h"

こんな感じです。

あと、PCXファイルが見つからないというエラーが2件出るので、ファイル名を直します。

「RACKETLE.PCX」→「RACKETLEFT.PCX

「RACKETRI.PCX」→「RACKETRIGHT.PCX

こんな感じです。逆にソースのファイル名を直してもいいです。

うまくビルドできたら、ROMイメージの「PONG.PCE」が生成されます。

 

f:id:nicotakuya:20201120224601p:plain

サンプルのPONGをリビルド

PONG.PCEをPCエンジンエミュレータで実行した様子。

なぜかスコア表示がおかしくなってしまいました。原因は不明です。そのうち直したいと思います。

 

f:id:nicotakuya:20201120224756p:plain

サンプルのscrollをリビルド

先ほどのバッチファイルを修正して、「SCROLL」もリビルドして、実行してみました。こっちは問題なく動きました。

現時点ではエミュレータで動かしていますが、そのうちPCエンジンの実機でも動かしてみたいです。

 

(追記2020/11/29)

PONGのスコア表示がおかしくなる問題ですが、「load_sprites」を使わないで「load_vram」に変更すると直りました。

f:id:nicotakuya:20201129033627p:plain

load_vramに変更する

こんな感じに修正します。

load_vramの書式は(VRAMアドレス ,int型配列変数 ,転送ワード数)です。

#incsprの変換後のソースを見ると、画像データの合間になぜか「dw.0」が追加されていて、これがデータの頭出しの誤差を作ってしまってました。load_spritesを使うと誤差を含んだままVRAMに転送してしまうのですが、load_vramなら誤差を取り除いて転送することができます。

あと、#incspr関連の記述はソースの最後に配置されていますが、これだとコンパイル時に変数の未定義エラーが出てしまいます。いままでエラーが出なかったのが不思議ですが、、、。#incspr関連はmain関数より上に配置しましょう。

f:id:nicotakuya:20201129010530p:plain

スコアが正しく表示されるようになりました

正常にスコアが表示している様子です。

 

続き

nicotakuya.hatenablog.com

PCエンジン用のカードを自作する(設計編)

前回の続きです。

nicotakuya.hatenablog.com

ここから歩いていける距離に駿河屋があるので、ちょっと覗いてみたのですが、PCエンジン系のソフトは高いですね。ボンバーマンが600円というのが最低価格でした。ブックオフは950円均一でしたが、数が少ないです。市販のPCエンジンのゲームはPS3WiiUアーカイブで遊ぶのが正解な気がします。

今度はPCエンジンのカードを自作してみたいと思います。

 

f:id:nicotakuya:20201117142610j:plain

1.27mmピッチ?

目コピーで基板を作ります。さすがに肉眼で見るには辛いサイズなので、スキャナを使ってみました。上の写真はスキャナの画像です。

ピンの端から端までの距離は47mmくらい。全38ピンなので、37で割ると、、、

47/37 = 1.27027027027027。

たぶん、1.27mmピッチだと思います。間違ってたらすみません。

 

f:id:nicotakuya:20201117142724p:plain

とりあえず結線してみる

CADに入力中の様子。

カード自体のサイズは54×85mmとしました。厚さは2.5mmくらいですね。1.5mmで作ってから、1mmのプラ板を足したらいいのかなと思っています。

 

f:id:nicotakuya:20201117142756p:plain

結線を修正。まだ未完成

結線を調節中。まだ未完成です。

フラッシュメモリの容量は4Mビットです。「R-TYPE」の容量の2倍ですが、少ないかもしれません。開発環境はHuCというのを使ったらC言語で作れるみたいです。

資料不足です。ピン配置が間違っている可能性があるので、もう少し調べないといけません。

CD(Card Detect)はカード検出用の端子ですね。GNDに接続するのではないかと予想しています。これから直します。

HSM(High Speed Mode)は処理速度を伝える端子ですが、信号の向きはどっちでしょうか。検索した感じだと、論理はHigh=ハイスピードらしいです。

CS(Chip Select)に相当する端子が無かったので、A19をCEに接続してみました。

D0~7は海外仕様とでビットの並びが逆だそうです。これは書き込み時に反転すれば、対応できるということですね。

あと、書き込み装置も作らないといけないのですが、コネクタの入手が難しいです。

f:id:nicotakuya:20201118024134p:plain

さらに修正

 

f:id:nicotakuya:20201119122819p:plain

D7-D0の並びを反転

(11/19追記)D7~D0の並びが逆だったような気がするので、反転してみました。エッジ経由で書き込んだらデータに変換はないので、反転する意味はないのですが、気分の問題です。