Created
January 2, 2021 01:19
-
-
Save aoirint/d6bd55c0f4f02582ae7c4069b6486e4c to your computer and use it in GitHub Desktop.
サルベージ版(開発途中)。「board Orange:mbed評価用ベースボード」用。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "mbed.h" | |
#include "TextLCD.h" | |
/** | |
<since>2016</since> | |
<authorList> | |
<author><admission>平成26年度</admission><name>aoirint</name></author> | |
<author><admission>平成28年度</admission><name>T.F</name></author> | |
</authorList> | |
*/ | |
struct GameStatus | |
{ | |
int interval; | |
int intervalCount; | |
int playerX; | |
int playerY; | |
char* map_l1; | |
char* map_l2; | |
char* specialText; | |
int mode; | |
}; | |
Ticker ticker; // タイマー割り込みオブジェクト | |
GameStatus status; // ゲーム状態 | |
DigitalIn swFlip(p5); // フリップスイッチの入力状態 | |
int prevSwFlip; // 直前Tickのフリップスイッチの入力状態 チャタリング対策 | |
TextLCD lcd(p24, p26, p27, p28, p29, p30); // LCDのオブジェクト | |
const int EVENT_DEATH = -1; // ゲームオーバー | |
const int EVENT_NONE = 0; // 何もしない | |
const int EVENT_CLEAR = 1; // クリア | |
const int LCD_WIDTH = 16; // LCDの横---横の文字数 | |
const int LCD_HEIGHT = 2; // LCDの縦---行数 | |
const int MODE_TITLE = 0; // タイトル画面(Tap to START) | |
const int MODE_LIVING = 1; // ゲーム中 | |
const int MODE_DIED = 2; // 死んでる | |
const int MODE_CLEARED = 3; // クリアした | |
void init() // 初期化 | |
{ | |
GameStatus newStatus; | |
newStatus.interval = 10; | |
newStatus.intervalCount = -5; // ここの初期値をマイナスにすればマップが動き始めるまで時間ができる(ディレイ)。ただし(interval-intervalCount)がディレイなので注意。-5なら15 -> 1.5秒。 | |
newStatus.playerX = newStatus.playerY = 0; | |
// TODO: マップ | |
newStatus.map_l1 = " ## ## ## G"; | |
newStatus.map_l2 = " ## ## ## G"; | |
newStatus.specialText = "Tap to START"; | |
newStatus.mode = MODE_TITLE; | |
status = newStatus; | |
} | |
char* getLine(int lineNum) // 指定行のマップ文字列を返す | |
{ | |
if (lineNum == 0) return status.map_l1; // 1行目 | |
return status.map_l2; // 0でないなら2行目として扱う | |
} | |
// TODO: マップ末端で表示がおかしい。Gだけだから大した問題はないが、違和感あり | |
char* subLine(int lineNum, int offsetX, int length) // 指定行のマップの部分文字列を返す | |
{ | |
char* line = getLine(lineNum); | |
int lineLen; | |
for (lineLen=0; line[lineLen]!=NULL; lineLen++); // 行の長さを取る | |
char* buffer = new char[length +1]; | |
int i; | |
for (i=0; i<length; i++) // ほしい文字数分繰り返す | |
{ | |
int idx = offsetX +i; // 対応するインデックスはここ | |
if (lineLen <= idx) break; // 行の文字数を超えている | |
buffer[i] = line[idx]; // 文字を取得 | |
} | |
buffer[length] = '\0'; // 最後にNULL文字つける -> 不要かも? | |
return buffer; | |
} | |
char getTileAt(int x, int y) | |
{ | |
char* line = getLine(y); | |
return line[x]; | |
} | |
int getEventAt(int x, int y) // 衝突を判定、処理番号を返す | |
{ | |
char tile = getTileAt(x, y); | |
if (tile == '#') return EVENT_DEATH; // 障害物 | |
else if (tile == 'G') return EVENT_CLEAR; // クリア | |
return EVENT_NONE; // なにもしない | |
} | |
void doEventAt(int x, int y) // | |
{ | |
// もしアイテム類を追加するなら、二重に取得できないように消すか、二次元ブール値なんかのフラグが必要か | |
int eventId = getEventAt(x, y); // 何があるか調べる | |
switch (eventId) | |
{ | |
case EVENT_NONE: break; // 何もない | |
case EVENT_DEATH: // ゲームオーバー | |
status.specialText = "YOU DIED"; | |
status.mode = MODE_DIED; | |
break; | |
case EVENT_CLEAR: // クリア | |
status.specialText = "CLEARED!"; | |
status.mode = MODE_CLEARED; | |
break; | |
default: break; | |
} | |
} | |
void playerFlip() // プレイヤーのy座標を上下反転 | |
{ | |
status.playerY = status.playerY == 0 ? 1 : 0; | |
doEventAt(status.playerX, status.playerY); | |
} | |
void updateControl() | |
{ | |
if (swFlip != prevSwFlip && swFlip) // チャタリング対策 | |
{ | |
if (status.mode == MODE_LIVING) playerFlip(); | |
else if (status.mode == MODE_TITLE) | |
{ | |
status.mode = MODE_LIVING; // 開始 | |
status.specialText = NULL; | |
} | |
else if (status.mode == MODE_DIED || status.mode == MODE_CLEARED) | |
{ | |
init(); // 死んでるときタップしたら初期化 | |
} | |
} | |
prevSwFlip = swFlip; // チャタリング対策 | |
} | |
void paint() | |
{ | |
lcd.cls(); // LCD描画のクリア | |
if (status.specialText != NULL) // 特別なテキスト | |
{ | |
lcd.locate(0,0); | |
lcd.printf(status.specialText); // TODO: 再描画防止策は? | |
return ; | |
} | |
int y; | |
for (y=0; y<LCD_HEIGHT; y++) // 1行目、2行目... | |
{ | |
lcd.locate(0, y); // ここに描画する | |
char* playerSight = subLine(y, status.playerX, LCD_WIDTH); // プレイヤーの視界 | |
lcd.printf(playerSight); // LCDに描画 | |
delete playerSight; // 明示的にリリース | |
} | |
lcd.locate(0, status.playerY); | |
lcd.printf("@"); | |
} | |
void onTick() | |
{ | |
status.playerX ++; | |
doEventAt(status.playerX, status.playerY); | |
} | |
void loop() | |
{ | |
if (status.mode != MODE_DIED) | |
{ | |
status.intervalCount++; | |
if (status.interval < status.intervalCount) // 周期よりカウントが大きければ更新 | |
{ | |
onTick(); // 更新 | |
status.intervalCount = 0; // カウントをリセット | |
} | |
} | |
updateControl(); | |
paint(); | |
} | |
int main() | |
{ | |
init(); // 初期化 | |
ticker.attach_us(&loop, 1000 *100); // 100ミリ秒ごとに割り込み | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment