//敵が階段にいてそこに右から入ると重なることがある(毎回ではない)
#include "ELECTROLIB.h"
#include "CAVEDATA.h"
#define CHAR_X (128/2-8/2)// キャラクター画面表示位置(ピクセル)
#define CHAR_Y (64/2-8/2)
#define CLEAR_FLOOR 30 // 30F到達でクリア
#define WATE_FLM 3 // 1歩移動する毎に移動待ちするフレーム数
uint8_t moveDelay=0; // 移動待ち用カウンタ
uint8_t nowAtk =0; // キャラクター攻撃中カウンタ
uint8_t cmp =0; // キャラクター向き
uint8_t mapX; // キャラクター位置(マップの座標:ピクセル座標)
uint8_t mapY;
uint8_t nowStageNo; // 現在のステージ番号
uint8_t nowHp; // HP
uint8_t statusFloor; // 状態管理用(0:通常 1:階段上だが何も起きない 2:階段上メッセージ表示でY選択中 3:階段上メッセージ表示でN選択中
uint8_t lastBtnAState = HIGH;// ボタンの前の状態 (HIGH:押されていない)
// 指定したタイル座標にキャラクターを移動させる(マップの表示位置(mapX, mapY)を更新して表現する)
// tx, ty: 移動先のタイル座標 (X, Y)(移動先の壁判定は行わない)
void jump(uint8_t tx, uint8_t ty) {
//指定タイル座標の左上隅ピクセル座標を計算し、キャラクター位置とする
mapX = tx * ONETIME_STEP;
mapY = ty * ONETIME_STEP;
}
// セットアップ関数
void setup(){
TinyOLED_init(); // OLED初期化
TINYJOYPAD_INIT(); // ジョイパッド初期化
nowHp=99;
nowGame=GAME_STAGE;
}
void handleInit(){
TILES_W = 17; // 初期マップサイズ(最大値)を設定
TILES_H = 11; // 初期マップサイズ(最大値)を設定
// ボタン押下までマップは全て壁
for(uint8_t y=0; y<TILES_H; y++){
for(uint8_t x=0; x<TILES_W; x++)sramTileMap[y][x] = 1; // 全て壁
}
cmp = 0; // 初期向き
nowStageNo=1; // 初期階層
nowHp=5; // 初期HP
makeNumData(nowHp, &hpDisp);
nowGame=GAME_STAGE;
statusFloor=0;
}
// Cave生成関数
void handleGoCave() {
// 迷路生成とキャラクター位置初期化
randomSeed(micros());
// 階層に応じて迷路サイズを決定
uint8_t sizeStep = nowStageNo / 5; // 5階層ごとにサイズアップ(20階層でMAX)
TILES_W = min(8, 4 + sizeStep) * 2 + 1; //TILES_W = random(4, 9)*2+1;
TILES_H = min(5, 2 + sizeStep) * 2 + 1; //TILES_H = random(2, 6)*2+1;
for(uint8_t y=0; y<TILES_H; y++){
for(uint8_t x=0; x<TILES_W; x++){ sramTileMap[y][x] = 1;}
}
dig(1,1);
// 階層に応じて壁をランダムで減らす(外周壁は除く)
uint8_t wallsToRemove = min(2 + (nowStageNo/5)*3, 14);
/* 上記計算は以下if文と同じ結果になる(上記の方がスケッチサイズが小さい)
uint8_t wallsToRemove = 2;
if (nowStageNo >= 5) wallsToRemove = 5;
if (nowStageNo >= 10)wallsToRemove = 8;
if (nowStageNo >= 15)wallsToRemove = 11;
if (nowStageNo >= 20)wallsToRemove = 14;
*/
for (uint8_t i = 0; i < wallsToRemove; i++) {
uint8_t rand_tx, rand_ty;
do {rand_tx = random(1, TILES_W - 1);
rand_ty = random(1, TILES_H - 1);
} while (sramTileMap[rand_ty][rand_tx] != TILE_WALL ||
(sramTileMap[rand_ty-1][rand_tx]==TILE_WALL && sramTileMap[rand_ty+1][rand_tx]==TILE_WALL &&
sramTileMap[rand_ty][rand_tx-1]==TILE_WALL && sramTileMap[rand_ty][rand_tx+1]==TILE_WALL) );
sramTileMap[rand_ty][rand_tx] = TILE_ROAD;
}
// ランダムでkeyを配置、特定階層にITEMを配置
uint8_t rand_tx, rand_ty;
do { rand_tx = random(TILES_W);
rand_ty = random(TILES_H);
} while(sramTileMap[rand_ty][rand_tx]!=0);
sramTileMap[rand_ty][rand_tx] = TILE_KEY;
//これだと難易度が高すぎる
//if (nowStageNo % 5 == 0) {
if ((nowStageNo<23 && nowStageNo%5==0)||(nowStageNo>=23 && (nowStageNo-23)%3==0)) {
do { rand_tx = random(TILES_W);
rand_ty = random(TILES_H);
} while(sramTileMap[rand_ty][rand_tx]!=0);
sramTileMap[rand_ty][rand_tx] = TILE_ITMBOX;
}
// ランダムな通路の場所を探してジャンプ
do { rand_tx = random(TILES_W);
rand_ty = random(TILES_H);
} while(sramTileMap[rand_ty][rand_tx]!=0);
jump(rand_tx, rand_ty);
uint8_t maxEnm = min(sizeStep + 1, MAX_ENEMIES);//敵の数
for(int i=maxEnm; i<MAX_ENEMIES; i++) {
enemies[i].isAlive = false;// 出現させない敵はfalseにする
}
// 敵の初期位置は1.壁でないこと 2.プレイヤーから3以上離れていること 3.すでに配置済みの他の敵と重ならないこと
for(uint8_t i = 0; i < maxEnm; i++) {
uint8_t enemyX, enemyY; bool isOverlap;
do {isOverlap=false;
enemyX =random(TILES_W);
enemyY =random(TILES_H);
for(uint8_t j=0; j<i; j++){
if(sramTileMap[enemyY][enemyX]==TILE_ENM1+(j*10)){ isOverlap=true; break; }// 配置済敵チェック
}
} while (isOverlap || sramTileMap[enemyY][enemyX]!=TILE_ROAD ||
(abs((int16_t)enemyX-(int16_t)rand_tx)<3 && abs((int16_t)enemyY-(int16_t)rand_ty)<3) );
sramTileMap[enemyY][enemyX]=TILE_ENM1+ (i*10); // 敵のIDをマップに設定
enemies[i].isAlive = true;
enemies[i].type = i;
}
nowGame = GAME_CAVE;
}
// 鍵、階段などのタイルイベント処理
void handleTileEvt() {
if (moveDelay==0 && nowAtk==0) {
uint8_t currentTileType = sramTileMap[mapY/ONETIME_STEP][mapX/ONETIME_STEP];
// 階段以外の場所に移動した場合、statusFloorをTILE_ROADに戻す
if (currentTileType != TILE_STAIRS && statusFloor != TILE_ROAD) {
statusFloor = TILE_ROAD;
}
switch (currentTileType) {
case TILE_KEY: { // 鍵
sramTileMap[mapY/ONETIME_STEP][mapX/ONETIME_STEP] = TILE_ROAD;
uint8_t rand_tx, rand_ty;
do {rand_tx = random(TILES_W);
rand_ty = random(TILES_H);
} while (sramTileMap[rand_ty][rand_tx] != TILE_ROAD ||
(abs((int16_t)rand_tx - (int16_t)mapX/ONETIME_STEP) < 3 &&
abs((int16_t)rand_ty - (int16_t)mapY/ONETIME_STEP) < 3)); //最低3マス乖離
sramTileMap[rand_ty][rand_tx] = TILE_STAIRS;
break;
}
case TILE_STAIRS: { // 階段
if (statusFloor == TILE_ROAD) statusFloor = TILE_KEY;
break;
}
case TILE_ITMBOX: { // アイテム
Sound(200, 20);
sramTileMap[mapY/ONETIME_STEP][mapX/ONETIME_STEP] = TILE_ROAD;
nowHp=5; makeNumData(nowHp, &hpDisp);
break;
}
}
}
}
// 階段上メッセージ処理
void handleStai() {
//statusFloorは状態管理用(0:通常 1:階段上だが何も起きない 2:階段上メッセージ表示でY選択中 3:階段上メッセージ表示でN選択中
switch(statusFloor) {
case 2: if (TINYJOYPAD_RIGHT) statusFloor=3; break;
case 3: if (TINYJOYPAD_LEFT) statusFloor=2; break;
}
if (BUTTON_DOWN) {DEBOUNCE(BUTTON_DOWN) { if (lastBtnAState == HIGH) {
switch(statusFloor) {
case 2: statusFloor=0; nowStageNo+=1; cnt=0; nowGame=GAME_STAGE; break;
case 3: statusFloor=1; break;
}
}}}
}
// マップから特定のタイル位置を検索する
bool findTile(uint8_t targetTile, uint8_t* outX, uint8_t* outY) {
for (uint8_t y = 0; y < TILES_H; y++) {
for (uint8_t x = 0; x < TILES_W; x++) {
if ((sramTileMap[y][x] / 10 * 10) == targetTile) {
*outX = x; *outY = y; return true;
}
}
}
return false;
}
// キャラクターの向きに応じたオフセットを計算
void getCharacterOffset(uint8_t direc, int8_t* offsetX, int8_t* offsetY, int8_t value) {
*offsetX = (direc == 2) ? -value : ((direc == 3) ? value : 0);
*offsetY = (direc == 0) ? value : ((direc == 1) ? -value : 0);
}
//上記は以下switch文と同じ結果になる(上記の方がスケッチサイズが小さい)
// *offsetX = 0; *offsetY = 0;
// switch(direc) { case 0: *offsetY = value; break;
// case 1: *offsetY = -value; break;
// case 2: *offsetX = -value; break;
// case 3: *offsetX = value; break; }
// 敵の種類(damageEnemy用)
enum EnemyType { CRAB=1, ALIEN=2, UFO=3, UFO4=4, CRAB_MINI=5 };
// ダメージ後の変化を定義する配列(damageEnemy用)
const uint8_t enmChange[] = {
0, // 0: 未使用
CRAB_MINI, // 1: CRAB -> CRAB_MINI
0, // 2: 未使用
CRAB, // 3: UFO -> CRAB
CRAB_MINI, // 4: UFO4 -> CRAB_MINI
0 // 5: 未使用
};
// 敵へのダメージ処理
void damageEnemy() {
int8_t atkTileX = mapX / ONETIME_STEP; // 攻撃範囲のタイル座標を計算
int8_t atkTileY = mapY / ONETIME_STEP;
int8_t offsetX, offsetY;
getCharacterOffset(cmp, &offsetX, &offsetY, 1);
atkTileX += offsetX; atkTileY += offsetY;
if (atkTileX>=0 && atkTileX<TILES_W && atkTileY>=0 && atkTileY<TILES_H) {
uint8_t tileVal = sramTileMap[atkTileY][atkTileX];
if (tileVal>=TILE_ENM1 && tileVal<=MAX_ENEMIES*10){
Sound(150, 20);
uint8_t enmIndex=(tileVal-TILE_ENM1)/10;
uint8_t nextType = enmChange[enemies[enmIndex].type];
if ( nextType!=0){enemies[enmIndex].type = nextType;
} else { enemies[enmIndex].isAlive= false;
sramTileMap[atkTileY][atkTileX]=tileVal%10;
}
/* 上記計算は以下switch文と同じ結果になる(上記の方がスケッチサイズが小さい)
switch (enemies[enmIndex].type) {
case 1: // type:crab(1)の場合type:crabMini(5)に変更
enemies[enmIndex].type = 5; break;
case 3: // type:UFO(3)の場合type:crab(1)に変更
enemies[enmIndex].type = 1; break;
case 4: // type:UFO(4)の場合
enemies[enmIndex].type = 5; break;
default:
enemies[enmIndex].isAlive = false;
sramTileMap[atkTileY][atkTileX]=tileVal%10; break;
}
*/
}
}
}
// 敵移動のヘルパー関数
bool moveEnm(uint8_t i, int8_t enmX, int8_t enmY, int8_t dx, int8_t dy) {
uint8_t nextEnmX = enmX + dx;
uint8_t nextEnmY = enmY + dy;
uint8_t nextTile = sramTileMap[nextEnmY][nextEnmX];
// 移動先のタイルが壁でなく、敵がおらず、プレイヤーもいないかチェック
if ((nextTile % 10) != TILE_WALL && (nextTile / 10 * 10) < TILE_ENM1 &&
(nextEnmX != (int16_t)mapX / ONETIME_STEP || nextEnmY != (int16_t)mapY / ONETIME_STEP)) {
// 移動元タイルから敵を削除し、背景を復元
sramTileMap[enmY][enmX] = sramTileMap[enmY][enmX] % 10;
// 移動先タイルに敵を配置し、背景を保持
sramTileMap[nextEnmY][nextEnmX] = TILE_ENM1 + (i * 10) + (nextTile % 10);
return true;
}
return false;
}
// 敵行動処理
void actEnemy() {
for (uint8_t i = 0; i < MAX_ENEMIES; i++) {
if (enemies[i].isAlive) {
// 敵が攻撃中の場合は何もしない
if (enemies[i].nowEnmAtk>0) {
continue;
}
// 敵の位置をマップ上で見つける
int8_t enmX = -1, enmY = -1;
if(findTile(TILE_ENM1+(i*10),(uint8_t*)&enmX,(uint8_t*)&enmY)){
// プレイヤーと敵の相対座標
int8_t diffX = (int16_t)mapX / ONETIME_STEP - enmX;
int8_t diffY = (int16_t)mapY / ONETIME_STEP - enmY;
// プレイヤーが隣接しているかチェック
if ((abs(diffX) <= 1 && diffY == 0) || (abs(diffY) <= 1 && diffX == 0)) {
enemies[i].nowEnmAtk=7; // 敵攻撃開始
continue; // 次の敵へ
}
int8_t dx = 0, dy = 0;
if (enemies[i].type==2||enemies[i].type==3){ // type:alien(2)||type:UFO(3)の場合ランダム行動
uint8_t dir = random(4);// ランダムな方向を1つ決め、その後4方向全てを試行
for (uint8_t j = 0; j < 4; j++) {
int8_t current_dir = (dir + j) % 4;
dx = (current_dir == 3) ? 1 : ((current_dir == 2) ? -1 : 0);
dy = (current_dir == 0) ? 1 : ((current_dir == 1) ? -1 : 0);
if (moveEnm(i, enmX, enmY, dx, dy)) break;
}
/*
int8_t dirs[4][2] = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}};
uint8_t dirIndices[4] = {0, 1, 2, 3};
for(uint8_t j = 3; j > 0; --j) {
uint8_t k = random(j + 1);// 方向をランダムにシャッフル
uint8_t temp = dirIndices[j];
dirIndices[j] = dirIndices[k];
dirIndices[k] = temp;
}
for (uint8_t j = 0; j < 4; j++) {// シャッフルされた方向で移動を試行
int8_t dx = dirs[dirIndices[j]][0];
int8_t dy = dirs[dirIndices[j]][1];
if (moveEnm(i, enmX, enmY, dx, dy)) break;
}
*/
} else {
// プレイヤーに近づくように方向を決定
if (abs(diffX)>abs(diffY)){dx=(diffX > 0) ? 1 : -1;
} else { dy=(diffY > 0) ? 1 : -1;
}
// 1回目の移動を試行
if (!moveEnm(i, enmX, enmY, dx, dy)) {
// 失敗時、もう一方の軸で試行
dx = (dx == 0) ? ((diffX > 0) ? 1 : -1) : 0;
dy = (dy == 0) ? ((diffY > 0) ? 1 : -1) : 0;
moveEnm(i, enmX, enmY, dx, dy);
}
}
}
}
}
}
void loop(){
while(1){
cnt=(cnt>=100?0:cnt+1);
uint8_t nowBtnAState=digitalRead(1); // ボタン状態
// ゲームの状態によって処理を分岐
makeNumData(nowStageNo, &stageDisp);
switch(nowGame) {
case GAME_STAGE:{
#define WATE_GAMEOVER 50 //GameOver画面でのWait用
if(cnt>=WATE_GAMEOVER)cnt=WATE_GAMEOVER;
if(BUTTON_DOWN){DEBOUNCE(BUTTON_DOWN){if(lastBtnAState==HIGH) {
if(nowHp==0||nowStageNo==CLEAR_FLOOR){ //GameOver||Ending(WATE_GAMEOVERの時間が経過しないとボタンは反応しない、経過後はgameTitleへ)
if(cnt==WATE_GAMEOVER){nowHp=99;nowStageNo=1;}
} else if(nowHp==99){ //GameTitle
handleInit();
} else { //GameStage
handleGoCave();
}
}}}
break;}
case GAME_CAVE: {
bool isEnmAttacking = false;
for (uint8_t i = 0; i < MAX_ENEMIES; i++) {
if(enemies[i].isAlive && enemies[i].nowEnmAtk>0) {
isEnmAttacking = true;
enemies[i].nowEnmAtk--;
if(enemies[i].nowEnmAtk==1){
nowHp--;makeNumData(nowHp, &hpDisp);
Sound(50, 20);
if(nowHp==0){
nowGame=GAME_STAGE; cnt=0; return;
}//GameOver
}
}
}
if (moveDelay> 0) moveDelay--; // 待ち時間中はデクリメント
if (nowAtk > 0) nowAtk--; // 待ち時間中はデクリメント
if (nowAtk ==2) damageEnemy();// 攻撃モーション後半で敵にダメージ
if (moveDelay==1||nowAtk==1) actEnemy(); // 待ち時間終了間際に敵行動
if (moveDelay==0 && nowAtk==0 && !isEnmAttacking) {
handleTileEvt(); // 移動完了時イベントチェック
if (statusFloor==2 || statusFloor==3){
handleStai(); //statusFloorは状態管理用(0:通常 1:階段上立 2:階段上Y選択中 3:階段上N選択中
} else {
uint8_t inputCmp = 5;
if( TINYJOYPAD_RIGHT){ cmp=3; inputCmp=cmp; }
else if(TINYJOYPAD_LEFT) { cmp=2; inputCmp=cmp; }
else if(TINYJOYPAD_DOWN) { cmp=0; inputCmp=cmp; }
else if(TINYJOYPAD_UP) { cmp=1; inputCmp=cmp; }
else if(BUTTON_DOWN){DEBOUNCE(BUTTON_DOWN){if(lastBtnAState==HIGH){
nowAtk = 7;
}}}
if (inputCmp != 5) { // 入力があった場合移動
int8_t dx=0, dy=0;
if( inputCmp == 0) dy = 1; // DOWN //ここはswitchにするとサイズが増える!
else if(inputCmp == 1) dy = -1; // UP //三項演算子にしてもサイズは変わらない!
else if(inputCmp == 2) dx = -1; // LEFT //よってこのままで!
else if(inputCmp == 3) dx = 1; // RIGHT
uint8_t nextX = mapX + dx * ONETIME_STEP;
uint8_t nextY = mapY + dy * ONETIME_STEP;
if (isMovePossible(nextX, nextY)){
mapX=nextX; mapY=nextY; moveDelay=WATE_FLM; // 移動したら待ち時間セット
}
}
}
}
break;
}
}
tinyDraw(); // 画面描画
// ボタン状態を保存
lastBtnAState = nowBtnAState; // ボタン状態更新
}
}
// 敵描画用計算用ヘルパー関数
void calcEnmDraw(int16_t mapX_screen_origin, int16_t mapY_screen_origin, int16_t* enmScreenX, int16_t* enmScreenY, int8_t* enmOffsetX, int8_t* enmOffsetY) {
for (uint8_t i = 0; i < MAX_ENEMIES; i++) {
enmScreenX[i] = -1; // 初期化
if (enemies[i].isAlive) {
int8_t enmX = -1, enmY = -1;
if (findTile(TILE_ENM1+(i*10),(uint8_t*)&enmX,(uint8_t*)&enmY)) {
// 敵の位置から画面上の座標を計算
enmScreenX[i] = (enmX * ONETIME_STEP) - mapX_screen_origin;
enmScreenY[i] = (enmY * ONETIME_STEP) - mapY_screen_origin;
// プレイヤーと敵の相対座標を計算
int16_t diffX = (int16_t)mapX / ONETIME_STEP - enmX;
int16_t diffY = (int16_t)mapY / ONETIME_STEP - enmY;
// プレイヤーのいる方向にオフセットを調整
enmOffsetX[i] = (abs(diffX) > abs(diffY)) ? ((diffX > 0) ? 6 : -6) : 0;
enmOffsetY[i] = (abs(diffX) > abs(diffY)) ? 0 : ((diffY > 0) ? 6 : -6);
}
}
}
}
// 画面描画関数
void tinyDraw(void){
uint8_t yPage; // ページ番号
uint8_t xPix; // 画面X座標
// ゲームの状態によって描画内容を分岐
switch(nowGame) {
case GAME_STAGE: {
// 数値表示構造体の表示範囲を設定
stageDisp.xStart=SCREEN_WIDTH/2; stageDisp.xEnd=SCREEN_WIDTH/2+8;
for(yPage=0;yPage<8;yPage++){ ssd1306_selectPage(yPage);
for(xPix=0;xPix<128;xPix++){
uint8_t displayByte=0x00;
if(yPage==3){
if(nowStageNo==CLEAR_FLOOR){ //Ending
displayByte|=SPEED_BLITZ(SCREEN_WIDTH/2-4, 0, xPix, 0, 6, miniYN); // Fin(8Pix)
} else if(nowHp==0){
displayByte|=SPEED_BLITZ(SCREEN_WIDTH/2-4, 0, xPix, 0, 3, miniYN); // DIE(8Pix)
} else if(nowHp==99){
displayByte|=SPEED_BLITZ(SCREEN_WIDTH/2-12,0, xPix, 0, 0, miniTitle);// Title(24Pix)
} else {
displayByte|=SPEED_BLITZ(SCREEN_WIDTH/2-8, 0, xPix, 0, 5, miniYN); // Fl.00(16pix)
displayByte|=getByteNum(xPix, &stageDisp); // ステージ番号
}
}
i2c_write(displayByte);
}
}
break;
}
case GAME_CAVE: {
// 数値表示構造体の表示範囲を設定
uint8_t startTire=SCREEN_WIDTH-16;
stageDisp.xStart= SCREEN_WIDTH- 7; // ステージ番号の開始X座標
stageDisp.xEnd = SCREEN_WIDTH; // ステージ番号の終了X座標
hpDisp.xStart= stageDisp.xStart;
hpDisp.xEnd = stageDisp.xEnd;
int16_t mapX_screen_origin=mapX-CHAR_X; // 画面左端マップX
int16_t mapY_screen_origin=mapY-CHAR_Y; // 画面上端マップY
// moveDelayに応じて描画位置をずらす処理
if (moveDelay >= 2) {
mapX_screen_origin += (cmp == 2) ? 4 : ((cmp == 3) ? -4 : 0);
mapY_screen_origin += (cmp == 0) ? -4 : ((cmp == 1) ? 4 : 0);
// 上記計算は以下if文と同じ結果になる(上記の方がスケッチサイズが小さい)
// if (cmp == 0) mapY_screen_origin -= 4; // DOWN
// else if (cmp == 1) mapY_screen_origin += 4; // UP
// else if (cmp == 2) mapX_screen_origin += 4; // LEFT
// else if (cmp == 3) mapX_screen_origin -= 4; // RIGHT
}
// 敵描画用の事前計算
int16_t enmScreenX[MAX_ENEMIES];
int16_t enmScreenY[MAX_ENEMIES];
int8_t enmOffsetX[MAX_ENEMIES];
int8_t enmOffsetY[MAX_ENEMIES];
calcEnmDraw(mapX_screen_origin, mapY_screen_origin, enmScreenX, enmScreenY, enmOffsetX, enmOffsetY);
for(yPage=0;yPage<8;yPage++){ // ページループ
ssd1306_selectPage(yPage); // ページ選択
for(xPix=0;xPix<128;xPix++){ // 画面Xループ
uint8_t displayByte=0x00; // 描画データバイト
if (yPage==0 && xPix>=startTire && xPix<=stageDisp.xEnd) {
displayByte|=SPEED_BLITZ(startTire+1, 0, xPix, 0, 5, miniYN); // Fl.00
displayByte|=getByteNum(xPix, &stageDisp);
} else
if (yPage==7 && xPix>=startTire && xPix<=hpDisp.xEnd) {
displayByte|=SPEED_BLITZ(startTire+1, 0, xPix, 0, 2, miniYN); //HP
displayByte|=getByteNum(xPix, &hpDisp);
} else
if ((yPage==6||yPage==7)&&(statusFloor==2||statusFloor==3)) {
if (yPage==7){
displayByte|=SPEED_BLITZ(52-8, 0, xPix, 0, 4, miniYN); //GO
displayByte|=SPEED_BLITZ(52+2, 0, xPix, 0, 1, miniTitle);
displayByte|=SPEED_BLITZ(80, 0, xPix, 0, statusFloor-2, miniYN);
}
} else { // タイル描画生成
displayByte |= makeTile(yPage, xPix, mapX_screen_origin, mapY_screen_origin);
// プレイヤー描画
const uint8_t *currentCharSprite = MyCh[cmp][(cnt/CNTCYCLE)%2];
if(nowAtk>1) { // 攻撃時はキャラクターを前に出す
int8_t offsetX, offsetY;
getCharacterOffset(cmp, &offsetX, &offsetY, 4);
displayByte|=blitzSprite(CHAR_X+offsetX, CHAR_Y+offsetY, xPix, yPage, 0, (const uint8_t*)MyAtk[cmp]);
} else {
displayByte|=blitzSprite(CHAR_X, CHAR_Y, xPix, yPage, 0, (const uint8_t*)MyCh[cmp][(cnt/CNTCYCLE)%2]);
}
// 敵描画
for (uint8_t i = 0; i < MAX_ENEMIES; i++) {
if(enemies[i].isAlive && enemies[i].nowEnmAtk > 2 && enemies[i].nowEnmAtk < 5) {
if(enmScreenX[i]!=-1) displayByte |= blitzSprite(enmScreenX[i] + enmOffsetX[i], enmScreenY[i] + enmOffsetY[i], xPix, yPage, 0, (const uint8_t*)OneEnm);
}
}
}
i2c_write(displayByte);
}
}
break; // スコープ終了
}
}
i2c_stop(); // 描画終了
}