ライン

PIC32MXワンチップテレビゲーム −パックマン編−

ライン

2013年2月4日

 PICによるカラーテキストビデオ出力実験を応用して、わずか200円のPICマイコンでテレビに映して遊べるパックマンを作成しました。ハードウェアは、28ピンDIPタイプのPIC32MXワンチップの非常にシンプルな回路で、映像信号生成と効果音、そしてゲームそのものの処理を行っています。ソースコードも公開しましたので、PICマイコンでのテレビゲーム製作の参考にしてください。

高解像度グラフィック版はこちら

ゲーム画面

ハードウェア

 PIC32MX版のカラービデオ出力実験の回路に、ゲーム操作用のボタンと、1チャンネルの音声出力を追加しただけのものです。今回もこれまで通りPIC32MX120F032Bを使用しましたが、USB機能を搭載したPIC32MX220F032Bでも動作するように設計しました。
 発信子には必ず3.579545MHzの水晶を使ってください。セラミック発信子ではカラー映像信号の精度は出せません。ボタンはタクトスイッチを6個使いました。今回のゲームで実際に使っているのは5個だけで、1個は今後の応用への予備です。片方の端子を単純にグランドに接続し、もう片方はPICのデジタル入力ポートに接続して、内部設定でプルアップをしています。
 電源は3.3V想定ですが、アルカリ乾電池2本でも正常に動作しています。VCAPピンに接続のコンデンサは、10μFの積層セラミックです。また、ICSP端子は必要に応じて付けて下さい。
 音声出力はテレビの音声入力端子に接続します。RB13ピンから出力していますが、周辺機能ピン割り当てで出力コンペアOC4を割り当ており、OC4のトグルモードで方形波の周期設定を変更しながら、効果音を鳴らしています。

回路図

基板写真

 私は写真のように、95×72mmのユニバーサル基板上で製作しましたが、ブレッドボードでも十分に作れるでしょう。電源は乾電池とACアダプタをスイッチで切り替えて使えるようにしました。また電源確認用にLEDを1つ付けました。

プリント基板

(2013.11.4追記)
 私の記事を見て、NASUさんがプリント基板を起こしてくれました。とてもきれいで感激です。ここで頒布もあるようですので、1枚買ってみられてはいかがでしょうか。

ソフトウェア

 (2015.11.21)今後のシステム対応のため、設定変更を行いました。

ソースファイルのダウンロード

 全てのソースコードと、念のためにHEXファイルを掲載しておきます。プロジェクトに全てのソースファイル、インクルードファイルを追加して、ビルドしてください。MPLAB XC32 v1.31またはC32 v2.02で動作確認しています。XC32 v1.33以降には対応していません。
 ビルドに際して、オプションで最適化の設定をしないと、フラッシュメモリの容量に収まりません。MPLAB IDEの場合、メニューの「Project」-「Build Options」-「Project」で、図のように「MPLAB PIC32 C Compiler」-「Categories」-「Optimization」の「Optimization Level」を1またはそれ以上に設定してください。フリー版だとビルド時に警告が出て、利用できないようなメッセージが出ますが、実際にはLevel1は利用可能なようです。

ビルドオプション設定

 MPLAB X IDEの場合、「File」-「Project Properties」-「xc32-gcc」で右図のように設定してください。

ビルドオプション設定
MPLAB X IDEの場合(クリックで拡大)

 各ファイルは以下の機能となっています。
・colortext32.c
 カラーテキスト表示システム。詳細はこちらのページを参照ください。
・colortext32.h
 上記システムのインクルードファイル。
・pacfont.c
 カラーテキスト表示システムで使用するフォントパターン。256個のキャラクターを定義しています。
・pacman.c
 main関数を含む、ゲーム本体。
・pacman.h
 パックマンプログラムの定数や構造体などを定義したインクルードファイル。

ゲームについて

 ビデオ端子、音声端子を接続して、電源オンするとタイトル画面が表示されます。STARTボタンで音楽と共にゲームが始まります。
 ゲームそのものは説明不要だと思います。1980年代に流行したパックマンです。ただし、キャラクターベースですので、動きもキャラクター単位で大まかです。「こんなのパックマンじゃない!」と怒られそうなので、何かよい名前はないかと悩んだ末に「PIC-MAN」としました。。。
 そのほか、アーケード版との大きな違いは、通路の形です。解像度が縦にキャラクター27行ではどうしても再現できません。どうやらファミコン版と同じのようです。
 とはいえ、多くのサイトや動画を参考に、なるべくオリジナルに似せて作りました。キャラクターの動きや効果音、フルーツの出現はもちろん、お楽しみのコーヒーブレイクもあります!
 面が進むとだんだん動きが速くなってきます。イジケ時間も短かったり、イジケなかったりします。有名なパターンが通用するのかどうか、私にはよくわかりませんが、結構夢中になって遊べます。
 ハイスコアはフラッシュメモリの最後のページに書き込みをしますので、電源を切っても残ります。

タイトル画面

プレイ画面

コーヒーブレイク画面

プログラムの解説

 簡単に今回のプログラムの解説をします。カラーテキスト表示システムや、カラーグラフィック表示システムを使ったプログラム製作のノウハウやテクニックを書いておきますので、ぜひ参考にしてください。

映像表示について

 ゲーム本体プログラム部分では、カラーテキスト表示システムはあまり意識する必要はありません。init_composite()関数を呼び出すことで全てが初期化され、TVRAM配列にキャラクターコードとカラーコードを書き込んでいけば、Timer2割り込みで勝手に表示されます。しかし、アクションゲームのようなリアルタイム性を求められるプログラムでは、多少意識する必要があります。
 映像信号生成側では、タイマー割り込みを用いて、必要なタイミングで映像信号と同期信号を生成、出力しています。したがって、ゲーム処理側は、空いた時間で処理を行う必要があります。映像信号の各ラインごとにも空き時間がありますが、大きな空きは映像下端(252ライン)まで出力したあと、次の映像の上端(37ライン)表示開始までの間です。この期間は同期信号とカラーバースト信号のみ生成すればよく、ほとんどのCPU時間を信号生成以外の処理に使えます。また、表示も終了しているので、画像の消去や書き換えを行っても、映像が乱れる心配がありません。
 映像信号側では、映像下端の最後の処理を終えたあと、グローバル変数「drawcount」を1増加させます。この変化をチェックすることで、ゲーム処理側は、表示内容の更新やキャラクターの移動などの処理開始のタイミングを図ることができます。このタイミングは、正確に60分の1秒ごとにやってきます。このため、この方法を用いたプログラムは、60分の1秒を基本単位とした処理に向いています。

信号生成とゲーム処理の関係図

 ちなみに、今回のパックマンプログラムの実際の処理を観測すると、映像下端出力後の最初の1ライン目(253ライン)で全てのゲーム処理が終わっていて、あとはずっとCPUをアイドルにして、映像処理の割り込み待ちをしている状況になっています。表示がキャラクターベースで非常に簡単なことと、ゲーム自体も単純ということでしょうか。ゲーム製作の参考情報として、感覚的に知っておくとよいでしょう。

ゲームについて

 パックマンのゲーム作成について説明をすることは、今回の本題ではありません。上記の通り、60分の1秒ごとに表示、消去、移動チェック、捕獲チェックなどを行っています。キャラクターベースでの表示座標となっているので、動きはかなり大まかです。各面ごとのパックマンやモンスターの動きの速さは、60分の何秒ごとに1キャラクター座標動かすかを配列で定義しています。面が進むにつれ、動きが速くなるようにしていますが、オリジナルと見比べてチューニングしたわけではないので、パックマンマニアの方には不満かもしれませんが、ご容赦ください。
 ゲームプログラム自体はそれほど複雑なものでもないので、コメントも参照すれば、簡単に理解できると思います。
 パックマンのプログラムの一番の醍醐味とも言える、各モンスターの動きについてはKonyaさんの開発ブログを大いに参考にさせていただきました。PIC24Fシリーズに128×128ドットの液晶を接続して、数多くのゲームを製作されています。オールアセンブラーというのも、なかなか真似できないことです。

効果音について

 今回、効果音に少し凝ってみました。出力コンペア4のトグルモードで方形波の周期を変えることで、音程の調整を行いますが、これでは複数の音を同時に鳴らすことができません。オリジナルのパックマンではモンスターの状態ごとに、常時サイレンのような音が鳴っており、そのほかに、パックマンがえさを食べる音やフルーツを食べたときの音などが重なっています。出力コンペアを2チャンネル使えれば簡単なのですが、PIC32MX1xx/2xxシリーズでは、出力コンペアのタイムベースにはTimer2とTimer3しか使えません。Timer2は映像信号出力に使用しているので、音声に使えるのはTimer3だけとなり、2チャンネル音声は実現しませんでした。出力コンペア自体は5チャンネルもあり、タイマーもTimer5まであるのに、残念なところです。
 残念がっていても仕方がないので、同時発音はあきらめて、時分割することにしました。これもやはり60分の1秒単位です。60分の1秒ごとにsound()という関数を呼び出して、そこで全ての効果音を共通的に処理しています。この関数では、Timer3の周期設定レジスタPR3の値を変更していくのですが、基本はモンスターの音、ただしえさを食べたときなどの60分の数秒間については、えさを食べた音を優先で鳴らすようにしています。ちょっと微妙な感じですが、このくらいで許してください。

最後に

 今回は、カラーテキスト表示システムを使って、キャラクターベースのパックマンを作成しましたが、同じハードウェアで160×100ドット、8色のカラーグラフィックシステムにも使えます。1つハードウェアを作っておけば、プログラムの書き換えだけで様々な応用ができますので、1つ作ってみられてはいかがでしょうか。そして、応用プログラムもぜひ作ってみてください。驚くほど簡単にできますよ。
 最後に、YouTubeにアップした動画を掲載しておきますので、ぜひ一度ご視聴してください。

ご意見、ご質問、メッセージなどありましたらこちらの掲示板にお願いします。

Copyright (C) KenKen All Rights Reserved.