gamebuino制作的小游戏之2048代码分析 loop部分
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那幾個字模,我不想再操作一次逆字模過程還原了,大概就這樣了。其余代碼大同小異也是上述分析的類似。好了明天開始畫瓢,想到啥繼續來補充
?
總結
以上是生活随笔為你收集整理的gamebuino制作的小游戏之2048代码分析 loop部分的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 51之按键控制开关
- 下一篇: 小乌龟使用教程(最简单版本)