gamebuino制作的小游戏之2048代码分析 loop部分

 if(gb.update()) {
    DrawBoard();
    for( int x = 0; x < 16; x++ ) {
      Board2048Old[x] = Board2048[x];
    }

gb.update

返回true并以固定频率(默认每秒20次)更新所有内容(显示、声音、电池监视器等)。boolean:如果从上一帧开始的时间足够长(每秒20帧=每帧50毫秒),则为真。

while(1){
  if(gb.update()){
    //your game here
  }
}

下面来看一看DrawBoard函数

void DrawBoard() {
  ResetDisplay();       //复位显示参见上一篇博客
  for( int y = 0; y < 4; y++ ) {
    for( int x = 0; x < 4; x++ ) {
      gb.display.drawBitmap(x * 13, y * 12, TileSprites[Board2048[y * 4 + x]]);
    }
  }
}

 

int Board2048[16];
const byte *TileSprites[] = {
Tile_0,Tile_2,Tile_4,Tile_8,Tile_16,Tile_32,Tile_64,Tile_128,Tile_256,Tile_512,Tile_1024,Tile_2048,Tile_4096,Tile_8192,Tile_16384,Tile_32768,Tile_65536,Tile_131072
};

TileSprites[]里是0-131072的24*24的二进制字模库(2048居然可以玩到131072,我的乱点巅峰也就在1024),Board2048长为16的数组,用一个双重循环依次打印1-131072  16个位图


 bool ButtonPressed = false;
    if(gb.buttons.pressed(BTN_LEFT)) {
      ButtonPressed = true;
      RotateClockwise();
      RotateClockwise();
      MoveRight(true);
      RotateClockwise();
      RotateClockwise();
    }

gb.buttons.pressed

用于知道给定按钮何时按下的函数

gb.buttons.pressed(button);
  • button (byte):按键标识符可选参数BTN_A, BTN_B, BTN_C, BTN_UP, BTN_RIGHT, BTN_DOWN, BTN_LEFT
  • boolean: 返回布尔值如果按键按下为true

下面看一看RotateClockwise()函数,额暂时看不懂(RotArray里的好像是4*4矩阵里的第一列、第二列这样子)

void RotateClockwise() {
  for( int x = 0; x < 16; x++ ) {
    TempBoard[x] = Board2048[x];
  }
  for( int x = 0; x < 16; x++ ) {
    Board2048[x] = TempBoard[RotArray[x]];
  }
}
int TempBoard[16];
int RotArray[] = {
12,8,4,0,
13,9,5,1,
14,10,6,2,
15,11,7,3
};

gamebuino制作的小游戏之2048代码分析 loop部分_第1张图片

第二个for语句大概就是执行这个变化....暂时不太懂啥意思没事继续往下,总能参透

再看一下MoveRight()函数

void MoveRight(bool Animate) {
  CompressRight();
  for( int x = 0; x < 16; x += 4 ) {
    for( int y = 3; y >= 1; y-- ) {
      if(Board2048[x + y] == Board2048[x + y - 1] && Board2048[x + y] != 0) {
        Board2048[x + y] += 1;
        long MergeScore = 1L;
        for( int z = 0; z < Board2048[x + y]; z++ ) {
          MergeScore *= 2;
        }
        if (Animate) gameState.score += MergeScore;
        Board2048[x + y - 1] = 0;
      }
    }
  }
  if (Animate) {
    if (gameState.score > gameState.highscore) gameState.highscore = gameState.score;
  }
  CompressRight();
}


void CompressRight() {
  for( int x = 0; x < 16; x += 4 ) {
    int FarthestTile = 4;
    for( int y = 0; y < 4; y++ ) {
      if(Board2048[x + y] == 0) FarthestTile = y;
    }
    for( int y = 3; y >= 0; y-- ) {
      if(Board2048[x + y] && y < FarthestTile && FarthestTile < 4) {
        Board2048[x + FarthestTile] = Board2048[x + y];
        Board2048[x + y] = 0;
        FarthestTile -= 1;
      }
    }
  }
}

FarthestTile字面最深的瓷砖...最里面的那个小方格?步长为4的for循环实现一行一行扫描,如果Board2048[n]==0,将FartheTile的值设为对应的列值,这个FarthestTile的值应该是这一行最靠右边的Board2048[n]==0的列值。再观察下一个for循环if里的内容描述的应该是这一行找到的FarthestTile左边的非零值,然后将我们这行的FarthestTile对应的小方块和这个非零值小方块值做一个互换。脑子不够画图来凑,下图是四种情况下变化,观察图相信大家现在都明白了原来CompressRight函数就是描述向右压缩的过程啊

gamebuino制作的小游戏之2048代码分析 loop部分_第2张图片

ok,下面继续回到MoveRight函数,从每行最右侧开始检测左侧相邻元素是否等值,如果两个元素相等,则将右侧的值加1,设置一个变量MergeScore为2^Board2048,然后将这次合并的分数加到总分里,并将左侧的值改为0,并判断更新最高分。

可以将MoveRight函数理解为向右压缩合并相同行相同元素,并根据合并类型更新分数。


if(gb.buttons.pressed(BTN_RIGHT)) {
      ButtonPressed = true;
      MoveRight(true);
    }
 if(gb.buttons.pressed(BTN_LEFT)) {
      ButtonPressed = true;
      RotateClockwise();
      RotateClockwise();
      MoveRight(true);
      RotateClockwise();
      RotateClockwise();
    }

等等刚刚那个函数是左键,这个函数是右键,但是MoveRight(true)实现的是向右压缩的动作,看来RotateClockwise();是对矩阵进行了旋转的功能,减少了再写出MoveLeft,MoveUp,MoveDown的量现在返回去看那个框图就明白啦!

gamebuino制作的小游戏之2048代码分析 loop部分_第3张图片

加入有一行数2,2,4,0我要实现MoveLeft向左压缩0,4,0,0其实也就等价于0,4,2,2MoveRight操作以后0,0,4,0再次翻转。所以我们可以知道为什么有4次RotateClockwise();MoveDown好MoveUp同理构造,这里就不展开啦


    PopupMessage();
    int y = 0;
    bool WinBox = false;
    int TilesOnBoard = 0;
    for( int x = 0; x < 16; x++ ) {
      if (Board2048[x]) TilesOnBoard++;
      if (Board2048Old[x] == Board2048[x]) y++;
      if (Board2048[x] == 11 && gameState.winstate == false) {
        gameState.winstate = true;
        WinBox = true;
      }
    }
   if (y != 16) {
      SpawnTile(true);
    } else if (ButtonPressed) {
      gb.sound.playCancel();
    }
    if (TilesOnBoard == 15 && y != 16) {
      for( int x = 0; x < 16; x++ ) {
        TempBoard2[x] = Board2048[x];
      }

​
void PopupMessage() {
  int MaxTile = Board2048[0];
  for( int x; x < 16; x++ ) {
    if (MaxTile < Board2048[x]) {
      MaxTile = Board2048[x];
    }
  }
  for( int x; x < 16; x++ ) {
    if (MaxTile == Board2048Old[x]) MaxTile = 0;
  }
  if (MaxTile >= 3) {
    gb.popup((const __FlashStringHelper*)pgm_read_word(&newTileStrings[MaxTile-3]),40);
  }
}​

const char msg8[] PROGMEM = "8! Good!";
const char msg16[] PROGMEM = "16! Great!";
const char msg32[] PROGMEM = "32! Awesome!";
const char msg64[] PROGMEM = "64! Sweet!";
const char msg128[] PROGMEM = "128! Cool!";
const char msg256[] PROGMEM = "256! Keep it up!";
const char msg512[] PROGMEM = "512! Almost there!";
const char msg1024[] PROGMEM = "1024! One more!";
const char msg2048[] PROGMEM = "2048! You win!";
const char msg4096[] PROGMEM = "4096! Step it up!";
const char msg8192[] PROGMEM = "8192! You're good!";
const char msg16384[] PROGMEM = "16384! Keep playing!";
const char msg32768[] PROGMEM = "32768! Unbelievable!";
const char msg65536[] PROGMEM = "65536! Woohoo!";
const char msg131072[] PROGMEM = "131072! INSANE!!!";

const char* const newTileStrings[] PROGMEM = {msg8, msg16, msg32, msg64, msg128, msg256, msg512, msg1024, msg2048, msg4096, msg8192, msg16384, msg32768, msg65536, msg131072};


void SpawnTile(bool makeSound) {
  int RandTile;
  do {
    RandTile = random(16);
  } while(Board2048[RandTile] != 0);
  
  for( int x = 0; x < 3; x++ ) {
    DrawBoard();
    if (x == 0) gb.display.drawBitmap(RandTile % 4 * 13, RandTile / 4 * 12, NewTile_1);
    if (x == 1) gb.display.drawBitmap(RandTile % 4 * 13, RandTile / 4 * 12, NewTile_2);
    if (x == 2) gb.display.drawBitmap(RandTile % 4 * 13, RandTile / 4 * 12, NewTile_3);
    while(gb.update() == false) {}
  }
  if (makeSound) gb.sound.playOK();
  if(random(10)) {
    Board2048[RandTile] = 1;
  } else {
    Board2048[RandTile] = 2;
  }
}

看PopupMessage()第一个for循环找出16个小方块里的最大值,啊我想我现在知道了Board2048Old[x]这个数组存的是我up、down、left、right操作之前的状态信息,Board2048[x]是在这些操作后更新的状态信息,每次新的矩阵信息和旧的进行对比如果最大值变更,而且合成的数字>=8那么就会gb.popup预先设定好的msg

TilesOnBoard顾名思义,用循环检测16个方格里的值非0的tiles,看到这里....我才明白原来Board2048[x]里放的是2^n的n才对!而不是2,4,8这样的值.........Orz哭泣我就说为什么之前合并成功以后是 Board2048[x + y] += 1;原来如此。所以 Board2048[x ] = 11以后就更新gameState.winstate = true;因为2^11=2048你已经赢啦

接下来我们看看 SpawnTile()好了,每次按按键的时候响一下。Newtile_1那几个字模,我不想再操作一次逆字模过程还原了,大概就这样了。其余代码大同小异也是上述分析的类似。好了明天开始画瓢,想到啥继续来补充


 

你可能感兴趣的:(gamebuino制作的小游戏之2048代码分析 loop部分)