セーブ・ロード機能を使う
セーブスロットごとに距離を保存し、またスロットに対応した読み込みを行います。
- 2022-06-30
- 公開
コード
res_image.res
- TILESET mark "mark.png" NONE ALL
main.c
- #include <genesis.h>
- #include "res_image.h"
- static void JoyInit();
- static void JoyEvent(u16 joy, u16 changed, u16 state);
- static void saveRecorrido(u8 state, u16 recorrido);
- static u16 loadRecorrido(u8 state);
- enum E_LinePosition {
- RECORRIDO,
- SAVE_SLOT,
- LOAD_SLOT,
- };
- typedef struct {
- u16 current; // 押下しているキー
- u16 trigger; // 押し始めたキー
- u16 off; // 離したキー
- } S_JoyState;
- S_JoyState JoyState;
- int main(u16 hard) {
- JoyInit();
- // 各部テキストの描画
- u16 posX = 13;
- u16 posY = 11;
- VDP_drawText("< 0 >", posX, posY - 1);
- VDP_drawText("SAVE < 0 >", posX, posY + 1);
- VDP_drawText("LOAD < 0 >", posX, posY + 3);
- VDP_drawText(":SELECT A:RUN", posX, posY + 6);
- // マーク類の描画
- VDP_loadTileSet(&mark, TILE_USERINDEX, DMA);
- // NOTE: TILE_ATTR_FULL(PAL0, FALSE, FALSE, FALSE, index) == index
- VDP_fillTileMapRect(BG_A, TILE_USERINDEX, posX, posY, 11, 1); // 下線
- VDP_setTileMapXY(BG_A, TILE_USERINDEX + 1, posX - 2, posY + 6); // 上矢印
- VDP_setTileMapXY(BG_A, TILE_USERINDEX + 2, posX - 1, posY + 6); // 下矢印
- // 各部位の変数
- char blankLine[] = " ";
- u8 lineNum = 0;
- u16 recorrido = 0;
- u8 saveSlot = 0;
- u8 loadSlot = 0;
- // メインループ
- u16 counter = 0;
- while (TRUE) {
- SYS_doVBlankProcess();
- // 動作のウェイト
- if (counter++ & 3) {
- continue;
- }
- // 現在のライン位置
- u8 currentLinePos = lineNum % 3;
- // キー操作による各処理
- if (JoyState.trigger & BUTTON_UP) {
- lineNum--;
- }
- if (JoyState.trigger & BUTTON_DOWN) {
- lineNum++;
- }
- if (JoyState.trigger & BUTTON_LEFT) {
- switch (currentLinePos) {
- case RECORRIDO:
- recorrido--;
- break;
- case SAVE_SLOT:
- saveSlot--;
- break;
- case LOAD_SLOT:
- loadSlot--;
- break;
- }
- }
- if (JoyState.trigger & BUTTON_RIGHT) {
- switch (currentLinePos) {
- case RECORRIDO:
- recorrido++;
- break;
- case SAVE_SLOT:
- saveSlot++;
- break;
- case LOAD_SLOT:
- loadSlot++;
- break;
- }
- }
- if (JoyState.trigger & BUTTON_A) {
- switch (currentLinePos) {
- case SAVE_SLOT:
- saveRecorrido(saveSlot & 3, recorrido);
- break;
- case LOAD_SLOT:
- recorrido = loadRecorrido(loadSlot & 3);
- break;
- }
- }
- // 描画刷新
- // 下線
- VDP_drawText(blankLine, posX, posY + currentLinePos*2);
- VDP_fillTileMapRect(BG_A, TILE_USERINDEX, posX, posY + (lineNum%3)*2, 11, 1);
- // 距離
- char strRecorrido[6];
- sprintf(strRecorrido, "%5d", recorrido);
- VDP_drawText(strRecorrido, posX + 3, posY - 1);
- // セーブスロット
- char strSlot[2];
- intToStr(saveSlot & 3, strSlot, 1);
- VDP_drawText(strSlot, posX + 8, posY + 1);
- // ロードスロット
- intToStr(loadSlot & 3, strSlot, 1);
- VDP_drawText(strSlot, posX + 8, posY + 3);
- }
- return 0;
- }
- /**
- * コントローラの初期化
- */
- static void JoyInit() {
- memset(&JoyState, 0, sizeof(S_JoyState));
- JOY_setEventHandler(JoyEvent);
- }
- /**
- * 1Pコントローラの状態を設定する
- * @param joy 変更のあったコントローラ
- * @param changed 変更のあったボタン
- * @param state 押されているボタン
- */
- static void JoyEvent(u16 joy, u16 changed, u16 state) {
- if (joy != JOY_1) {
- return;
- }
- // 押し始めたボタン
- JoyState.trigger = state & changed;
- // 離したボタン
- JoyState.off = changed & ~state;
- // 押しているボタン
- JoyState.current = state;
- }
- /**
- * 距離を保存する
- * @param slot セーブスロット
- * @param recorrido 距離
- */
- static void saveRecorrido(u8 slot, u16 recorrido) {
- // SRAMを読み書き可能にする
- SRAM_enable();
- // 距離をSRAMに書き込む
- // NOTE: SRAM_writeXXの第1引数のoffsetは1増えるごとにSRAMを8bit進む
- // つまりSRAM_writeWordの次に書き込むならoffsetを2、
- // SRAM_writeLongの次に書き込むならoffsetを4進めないと、
- // 前に保存した値の一部を上書きしてしまう
- // 例: wordサイズのデータを保存した後、offsetを1だけ進めて
- // 次のwordサイズのデータを保存した場合
- // |------> offset: +1
- // |- 保存したかった場所 -|
- // xxxxxxxx yyyyyyyy yyyyyyyy 00000000
- // |-- 保存した場所 --|
- // 前の値(xxxxxxxx xxxxxxxx)の後半を上書きしてしまっている
- SRAM_writeWord(slot * 2, recorrido);
- // SRAMを読み込み専用にする
- SRAM_enableRO();
- }
- /**
- * 保存された距離を読み込んで返す
- * @param slot セーブスロット
- * @return u16 距離
- */
- static u16 loadRecorrido(u8 slot) {
- // NOTE: SRAM_readXXの引数offsetは1増えるごとにSRAMを8bit進む
- // wordサイズで保存された値の次の値を読み込むならoffsetを2、
- // longサイズで保存された値の次の値を読み込むならoffsetを4進めないと、
- // 前の値の一部を読み込んでしまう
- // 例: wordサイズのデータを読み込んだ後、offsetを1だけ進めて
- // 次のwordサイズのデータを読み込んだ場合
- // |------> offset: +1
- // |- 読み込みたい値 -|
- // xxxxxxxx xxxxxxxx yyyyyyyy yyyyyyyy
- // |--- 読み込む値 ---|
- // 前の値の後半+欲しい値の前半を読み込んでしまっている
- return SRAM_readWord(slot * 2);
- }
実行結果
上記コードをSGDK1.70でコンパイルし
Gens v2.14 Souvenirで実行したスクリーンショット
解説
コード内にも書いてありますが、SRAM_readXXやSRAM_writeXXの第1引数offsetは1増減することで、保存もしくは読み込むデータのサイズ(byte, word, long)に関わらずSRAM領域を8bit移動します。
保存するデータのbit長とその範囲を間違えると、既存の保存データを壊したり、おかしなデータを読み込むことになるため注意が必要です。
なお、offsetの最大値は511のようです。つまり512 * 8bit = 4096bit
のデータを保存できます。
範囲を超えた場合、offsetが0の位置に戻り、値を上書きしていきます。