13 Oct 09:07
#include "platform.h"
#include "xil_printf.h"
#include "displayport.h"
#include "vtc.h"
#include "tpg.h"
#include "xparameters.h"
#include "./../../../hw/sdt/drivers/myip_v1_0/src/myip.h"
#include <stdint.h>
#include "xil_types.h"
#include "xil_io.h"
// Deklaracja funkcji do odbierania pojedynczego bajtu z UART
extern char inbyte(void);
// Definicje stałych gry
#define BOARD_WIDTH 20
#define BOARD_HEIGHT 15
#define MAX_SNAKE_LEN 100
// Kierunki ruchu
typedef enum { UP, DOWN, LEFT, RIGHT } Direction;
// Struktura punktu na planszy
typedef struct {
int8_t x;
int8_t y;
} Point;
// Funkcja konwertująca Hue (0-360) oraz Jasność (0-100%) na format XRGB (0x00RRGGBB)
u32 hsv_to_xrgb(u16 hue, u8 value) {
if (hue >= 360) hue = hue % 360;
if (value > 100) value = 100;
u8 max_val = (value * 255) / 100;
if (max_val == 0) return 0x00000000;
u8 r = 0, g = 0, b = 0;
u32 sector = hue / 60;
u32 remainder = hue % 60;
u8 x_val = (max_val * remainder) / 60;
u8 inv_x_val = max_val - x_val;
switch (sector) {
case 0: r = max_val; g = x_val; b = 0; break;
case 1: r = inv_x_val; g = max_val; b = 0; break;
case 2: r = 0; g = max_val; b = x_val; break;
case 3: r = 0; g = inv_x_val; b = max_val; break;
case 4: r = x_val; g = 0; b = max_val; break;
case 5: r = max_val; g = 0; b = inv_x_val; break;
default: r = 0; g = 0; b = 0; break;
}
return ((u32)0x00 << 24) | ((u32)r << 16) | ((u32)g << 8) | b;
}
// Prosta funkcja opóźniająca (zastępuje sleep)
void simple_delay(u32 cycles) {
volatile u32 i;
for (i = 0; i < cycles; i++) {
__asm__("nop");
}
}
int main() {
init_platform();
xil_printf("\n\n\n\n\n--- SNAKE GAME IN HUE/RGB ---\r\n");
xil_printf("Sterowanie strzalkami na klawiaturze terminala!\r\n");
// Inicjalizacja potoku wideo
displayport_init();
displayport_setup_interrupts();
vtc_init();
tpg_init();
xil_printf("Video pipeline ready.\r\n");
// Kolory gry zdefiniowane w Hue
u32 color_snake = hsv_to_xrgb(120, 100); // Zielony wąż
u32 color_apple = hsv_to_xrgb(0, 100); // Czerwone jabłko
u32 color_dead = hsv_to_xrgb(280, 100); // Fioletowy (koniec gry)
// Stan gry
Point snake[MAX_SNAKE_LEN];
u8 snake_len = 3;
Direction dir = RIGHT;
Point apple = {12, 7};
u8 game_over = 0;
u32 score = 0;
// Pozycja startowa węża (środek planszy)
snake[0].x = 10; snake[0].y = 7; // Głowa
snake[1].x = 9; snake[1].y = 7;
snake[2].x = 8; snake[2].y = 7; // Ogon
// Pseudo-losowy licznik do generowania jabłek
u32 rand_counter = 0;
while (1) {
rand_counter++;
// --- 1. OBSŁUGA STEROWANIA (Nieblokujące sprawdzanie UART lub symulacja ruchu) ---
// Ponieważ inbyte() domyślnie blokuje procesor, w grach na mikrokontrolerach
// sterowanie opiera się na taktowaniu pętli z opóźnieniem.
// Aby zagrać, klikaj strzałki rytmicznie w terminalu.
char c = inbyte();
if (c == 0x1B) {
c = inbyte();
if (c == 0x5B) {
c = inbyte();
switch (c) {
case 0x41: if (dir != DOWN) dir = UP; break; // Góra
case 0x42: if (dir != UP) dir = DOWN; break; // Dół
case 0x43: if (dir != LEFT) dir = RIGHT; break; // Prawo
case 0x44: if (dir != RIGHT) dir = LEFT; break; // Lewo
}
}
}
if (game_over) {
MYIP_mWriteReg(XPAR_MYIP_0_BASEADDR, MYIP_S00_AXI_SLV_REG0_OFFSET, color_dead);
xil_printf("\rGAME OVER! Wynik: %d. Nacisnij dowolny klawisz, aby restartowac...", score);
inbyte(); // Czekaj na klawisz restartu
// Reset stanu gry
snake_len = 3;
dir = RIGHT;
snake[0].x = 10; snake[0].y = 7;
snake[1].x = 9; snake[1].y = 7;
snake[2].x = 8; snake[2].y = 7;
apple.x = 12; apple.y = 7;
score = 0;
game_over = 0;
xil_printf("\nNowa gra wystartowala!\n");
continue;
}
// --- 2. LOGIKA RUCHU ---
// Przesunięcie ogona węża
for (int i = snake_len - 1; i > 0; i--) {
snake[i] = snake[i - 1];
}
// Ruch głowy węża
switch (dir) {
case UP: snake[0].y--; break;
case DOWN: snake[0].y++; break;
case LEFT: snake[0].x--; break;
case RIGHT: snake[0].x++; break;
}
// --- 3. KOLIZJE ZE ŚCIANAMI ---
if (snake[0].x < 0 || snake[0].x >= BOARD_WIDTH || snake[0].y < 0 || snake[0].y >= BOARD_HEIGHT) {
game_over = 1;
}
// Kolizja z samym sobą
for (int i = 1; i < snake_len; i++) {
if (snake[0].x == snake[i].x && snake[0].y == snake[i].y) {
game_over = 1;
}
}
// --- 4. ZJADANIE JABŁKA ---
if (snake[0].x == apple.x && snake[0].y == apple.y) {
score += 10;
if (snake_len < MAX_SNAKE_LEN) {
snake_len++;
}
// Proste generowanie nowej pozycji jabłka na podstawie licznika cykli pętli
apple.x = (rand_counter % (BOARD_WIDTH - 2)) + 1;
apple.y = (rand_counter / 3 % (BOARD_HEIGHT - 2)) + 1;
}
// --- 5. RENDEROWANIE SYGNAŁU NA EKRAN ---
// Kod dynamicznie przełącza rejestr MYIP_REG0 w takt odświeżania gry.
// Kiedy wąż zbliża się do jabłka, rejestr błyska na czerwono; kiedy się porusza, koloruje ekran na zielono.
if (snake[0].x == apple.x || snake[0].y == apple.y) {
// Sygnalizacja bliskości jedzenia na ekranie wideo
MYIP_mWriteReg(XPAR_MYIP_0_BASEADDR, MYIP_S00_AXI_SLV_REG0_OFFSET, color_apple);
} else {
// Standardowy kolor życia węża przekazywany do potoku obrazu
MYIP_mWriteReg(XPAR_MYIP_0_BASEADDR, MYIP_S00_AXI_SLV_REG0_OFFSET, color_snake);
}
// Wydruk kontrolny stanu gry do konsoli szeregowej UART
xil_printf("\rGlowa: [%2d,%2d] | Jabłko: [%2d,%2d] | Wynik: %d ", snake[0].x, snake[0].y, apple.x, apple.y, score);
// Regulacja prędkości gry (ok. 5-10 klatek na sekundę w zależności od architektury procesora)
simple_delay(2000000);
}
cleanup_platform();
return 0;
}