Implementacja dotykowej wersji „Snake” na STM32F4DISCOVERY
Ekran wstępnie podzielony został na dwie części (połówkę górną wraz belką nagłówkową i połówkę dolną). Pozycja lewa górna odpowiada współrzędnym x=0 i y=0, gdzie x to krawędź pozioma, a y to krawędź pionowa.
Dla połówki górnej pozycje dla x<y to pole czerwone (ruch w lewo), pozycje xmax–x<y to pole zielone (ruch w prawo), a pozostałe pozycje to pole niebieskie (ruch do góry). Analogicznie jest dla połówki dolnej: x<ymax–y to pole czerwone (ruch w lewo), xmax–x<ymax–y to pole zielone (ruch w prawo), a pozostałe pozycje to pole czarne (ruch do dołu). |
Na podstawie wyznaczonego kierunku ruchu następuje wyznaczenie nowej pozycji głowy węża, przy czym jeśli nowa pozycja dotyka krawędzi ekranu następuje zakończenie gry (listing 4).
List. 4.
switch (direction) { case left: if (MOVE_MARGIN >= g_snake[0].x) ret_val = RET_GAME_OVER; g_snake[0].x -= SNAKE_STEP; break; case right: if((DISP_HOR_RESOLUTION - MOVE_MARGIN) <= g_snake[0].x) ret_val = RET_GAME_OVER; g_snake[0].x += SNAKE_STEP; break; case up: if ((MOVE_MARGIN + HEADER_SIZE) >= g_snake[0].y) ret_val = RET_GAME_OVER; g_snake[0].y -= SNAKE_STEP; break; case down: if ((DISP_VER_RESOLUTION - MOVE_MARGIN) <= g_snake[0].y) ret_val = RET_GAME_OVER; g_snake[0].y += SNAKE_STEP; break; }
Współrzędne poszczególnych elementów węża umieszczone są w tablicy, a jego ruch polega na narysowaniu głowy na nowej pozycji i usunięciu ostatniego fragmentu ogona z jednoczesnym przesunięciem wszystkich pozycji w tablicy współrzędnych (listing 5).
List. 5.
// remove last part of snake LCD_SetTextColor(BACKGROUND_COLOR); LCD_DrawFullRectFill(g_snake[partsCount-1].x - 5, g_snake[partsCount-1].y - 5, 11, 11, true); for (part = partsCount-1; part > 0; part--) { g_snake[part].x = g_snake[part-1].x; g_snake[part].y = g_snake[part-1].y; } // print head on new position LCD_SetColors(SNAKE_COLOR_BODY, SNAKE_COLOR_HEAD); LCD_DrawFullCircle(g_snake[0].x, g_snake[0].y, 5); LCD_DrawFullCircleFill(g_snake[1].x, g_snake[1].y, 5, true);
Jeśli nowa pozycja głowy węża pokrywa się z pozycją celu, to następuje narysowanie nowej pozycji celu, zwiększenie liczby punktów, wzrost węża oraz przyspieszenie jego ruchu. Zwiększenie prędkości węża następuje co określoną (SPEED_INCREASE_STEPS_CNT) liczbę punktów (listing 6).
List. 6.
if ( (target.x == g_snake[0].x) &&(target.y == g_snake[0].y) ) { target.new = true; g_points++; snakeGrow(); if (0 == --speedIncreaseCnt) { speedIncreaseCnt = SPEED_INCREASE_STEPS_CNT; g_snakeSpeed -= g_snakeSpeed>>2; if (SPEED_LIMIT > g_snakeSpeed) g_snakeSpeed = SPEED_LIMIT; } }
Nowa pozycja celu powinna być wyznaczana w losowy sposób. Mikrokontrolery z rodziny STM32F4 mają wbudowany sprzętowy generator liczb losowych. Jednak w tym przypadku stopień losowości nie musi być wysoki i dlatego w tym celu wykorzystany został licznik zegarowy. Moment „trafienia” celu raczej nie będzie się powtarzał, dzięki czemu uzyskamy wystarczającą pseudolosowość. Po wyznaczeniu nowego punktu trzeba sprawdzić, czy jego pozycja jest poprawna i jeśli wszystko się zgadza można narysować „jabłko” w nowych współrzędnych (listing 7).
List. 7.
if (target.new) { target.x = (getSysTick()%TARGET_X_RATIO + 1) * 10 + 5; target.y = (getSysTick()%TARGET_Y_RATIO + 1) * 10 + 5 + HEADER_SIZE; for (part = 0; part < g_snakeSize; part++) { if ((target.x == g_snake[part].x) && (target.y == g_snake[part].y)) { // target cannot be on the snake, generate the new one return true; } } LCD_SetColors(TARGET_COLOR, BACKGROUND_COLOR); LCD_DrawFullCircleFill(target.x, target.y, 3, true); target.new = false; }
Prezentowany projekt w minimalnym stopniu wykorzystuje możliwości zestawu STM32F4DISCOVERY. Wykorzystując elementy peryferyjne dostępne na płytce zestawu (jak akcelerometr), można urozmaicić grę o dodatkowy sposób sterowania za pomocą ruchu (przechyłu) płytki. Idąc dalej, czujnik dźwięku z wbudowanym mikrofonem można wykorzystać do głosowego sterowania wężem dodając prosty moduł rozpoznawania mowy. Wbudowany przetwornik audio można wykorzystać do urozmaicenia gry dźwiękami.