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
};
第二个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函数就是描述向右压缩的过程啊
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的量现在返回去看那个框图就明白啦!
加入有一行数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那几个字模,我不想再操作一次逆字模过程还原了,大概就这样了。其余代码大同小异也是上述分析的类似。好了明天开始画瓢,想到啥继续来补充