ゲームプログラマになる前に覚えておきたい技術
http://www.shuwasystem.co.jp/support/7980html/2118.html
サンプルプログラムの荷物君(NimotsuKunBox)をワンダースワンで動かしてみます。
http://www.geocities.jp/parallel_computer_inc/nimotsu2.zip
nimotsu2.c
#include "wwwlib.h" #include <string.h> typedef int bool; typedef int Object; #define true 1 #define false 0 unsigned short nimotsu_chr[] = { 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x00AA,0x0055,0x00AA,0x0055,0x00AA,0x0055,0x00AA,0x0055, /* 1 */ 0xAA00,0x5500,0xAA00,0x5500,0xAA00,0x5500,0xAA00,0x5500,0xAAAA,0x5555,0xAAAA,0x5555,0xAAAA,0x5555,0xAAAA,0x5555, /* 3 */ 0xAA55,0x55AA,0xAA55,0x55AA,0xAA55,0x55AA,0xAA55,0x55AA,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF, /* 5 */ }; u16 game[224]; //#壁 _空間 .ゴール oブロック p人 const char gStageData[][63] = { "\ ########\n\ # .. p #\n\ # oo #\n\ # #\n\ ########\n\ \n\ \n", "\ ##### \n\ . # \n\ # o o # \n\ # op# # \n\ # # # \n\ #.###. \n\ ### ### \n" }; #define gStageWidth 8 #define gStageHeight 7 enum OBJ { OBJ_SPACE, OBJ_WALL, OBJ_GOAL, OBJ_BLOCK, OBJ_BLOCK_ON_GOAL, OBJ_MAN, OBJ_MAN_ON_GOAL, OBJ_UNKNOWN, }; Object state[56]; /* 関数プロトタイプ */ void initialize( Object* state, char* stageData ); void draw( Object* state, int w, int h ); void update( Object* state, u16 input, int w, int h ); bool checkClear( Object* state, int w, int h ); int main(){ int stage; wwc_set_color_mode(COLOR_MODE_4COLOR); wwc_palette_set_color(0, 0, 0x0000); /* black */ wwc_palette_set_color(0, 1, 0x000f); /* blue */ wwc_palette_set_color(0, 2, 0x0f00); /* red */ wwc_palette_set_color(0, 3, 0x0fff); /* white */ font_set_colordata(1, 6, nimotsu_chr); display_control(DCM_SCR2); for (stage=0; stage<2; stage++) { initialize( state, gStageData[stage] ); /* ステージ初期化 */ /* メインループ */ while ( true ){ /* まず描画 */ sys_wait(7); draw( state, gStageWidth, gStageHeight ); /* クリアチェック */ if ( checkClear(state, gStageWidth, gStageHeight ) ){ break; /* クリアチェック */ } /* 更新 */ update( state, key_press_check(), gStageWidth, gStageHeight ); } } return 0; } /* ---------------------以下関数定義------------------------------------------ */ void initialize( Object* state, char* stageData ){ const char* d = stageData; /* 読み込みポインタ */ int x = 0; int y = 0; while ( *d != '\0' ){ /* NULL文字でない間 */ Object t; /* 特に意味はないが使う回数が多い変数に私は良くtを使う。temporaryの略。たぶんよくない習慣だが、無駄に長い名前にして読みにくいのも困り物だろう。 */ switch ( *d ){ case '#': t = OBJ_WALL; break; case ' ': t = OBJ_SPACE; break; case 'o': t = OBJ_BLOCK; break; case 'O': t = OBJ_BLOCK_ON_GOAL; break; case '.': t = OBJ_GOAL; break; case 'p': t = OBJ_MAN; break; case 'P': t = OBJ_MAN_ON_GOAL; break; case '\n': x = 0; ++y; t = OBJ_UNKNOWN; break; /* 改行処理 */ default: t = OBJ_UNKNOWN; break; } ++d; if ( t != OBJ_UNKNOWN ){ /* 知らない文字なら無視するのでこのif文がある */ state[ y * gStageWidth + x ] = t; /* 書き込み */ ++x; } } } void draw(Object* state, int width, int height ){ int x, y; /* char font[] = {' ', '#', '.', 'o', 'O', 'p', 'P'}; */ u16 font[] = {1, 4, 2, 3, 5, 6, 6}; /* Object列挙の順 */ for ( y = 0; y < height; ++y ){ for (x=0; x < width; ++x ){ Object o = state[ y * width + x ]; game[x * 2 + 0 + (y * 2 + 0) * gStageWidth * 2] = font[ o ]; game[x * 2 + 1 + (y * 2 + 0) * gStageWidth * 2] = font[ o ]; game[x * 2 + 0 + (y * 2 + 1) * gStageWidth * 2] = font[ o ]; game[x * 2 + 1 + (y * 2 + 1) * gStageWidth * 2] = font[ o ]; } } screen_set_char(SCREEN2, 0, 0, 16, 14, game); } /* 第一引数はほかの関数ではstateとしているが、あまりに頻繁に使うので 短いsで済ませている。w,hもそれぞれwidth,heightである。 */ void update( Object* s, u16 input, int w, int h ){ /* 移動差分に変換(dはdifferenceでもdeltaでもお好きな方の略だと思って欲しい) */ int dx = 0; int dy = 0; int i = -1; int x, y, tx, ty, p, tp, tx2, ty2, tp2; switch ( input ){ case KEY_LEFT1: dx = -1; break; case KEY_RIGHT1: dx = 1; break; case KEY_UP1: dy = -1; break; case KEY_DOWN1: dy = 1; break; } /* 人座標を検索 */ for ( i = 0; i < w * h; ++i ){ if ( s[ i ] == OBJ_MAN || s[ i ] == OBJ_MAN_ON_GOAL ){ break; } } x = i % w; /* xは幅で割ったあまり */ y = i / w; /* yは幅で割った商 */ /* 移動後座標(tに意味はない。ごめんなさい) */ tx = x + dx; ty = y + dy; /* 座標の最大最小チェック。外れていれば不許可 */ if ( tx < 0 || ty < 0 || tx >= w || ty >= h ){ return; } /* A.その方向が空白またはゴール。人が移動。 */ p = y*w + x; /* 人位置 */ tp = ty*w + tx; /* ターゲット位置(TargetPosition) */ if ( s[ tp ] == OBJ_SPACE || s[ tp ] == OBJ_GOAL ){ s[ tp ] = ( s[ tp ] == OBJ_GOAL ) ? OBJ_MAN_ON_GOAL : OBJ_MAN; /* ゴールならゴール上の人に */ s[ p ] = ( s[ p ] == OBJ_MAN_ON_GOAL ) ? OBJ_GOAL : OBJ_SPACE; /* もともとゴール上ならゴールに */ /* B.その方向が箱。その方向の次のマスが空白またはゴールであれば移動。 */ }else if ( s[ tp ] == OBJ_BLOCK || s[ tp ] == OBJ_BLOCK_ON_GOAL ){ /* 2マス先が範囲内かチェック */ tx2 = tx + dx; ty2 = ty + dy; if ( tx2 < 0 || ty2 < 0 || tx2 >= w || ty2 >= h ){ /* 押せない */ return; } tp2 = ( ty + dy )*w + ( tx + dx ); /* 2マス先 */ if ( s[ tp2 ] == OBJ_SPACE || s[ tp2 ] == OBJ_GOAL ){ /* 順次入れ替え */ s[ tp2 ] = ( s[ tp2 ] == OBJ_GOAL ) ? OBJ_BLOCK_ON_GOAL : OBJ_BLOCK; s[ tp ] = ( s[ tp ] == OBJ_BLOCK_ON_GOAL ) ? OBJ_MAN_ON_GOAL : OBJ_MAN; s[ p ] = ( s[ p ] == OBJ_MAN_ON_GOAL ) ? OBJ_GOAL : OBJ_SPACE; } } } /* ブロックのみがなければクリアしている。 */ bool checkClear(Object* s, int width, int height ){ int i; for (i = 0; i < width*height; ++i ){ if ( s[ i ] == OBJ_BLOCK ){ return false; } } return true; }