Back to posts Edit this post
Copy content

13 Oct 09:13

#include "platform.h" #include "xil_printf.h" #include "displayport.h" #include "vtc.h" #include "tpg.h" #include "xparameters.h" #include <stdint.h> #include "xil_types.h" #include "xil_io.h" extern char inbyte(void); // ========================================================================= // KONFIGURACJA EKRANU (Dostosuj do rozdzielczości ustawionej w VTC / TPG) // ========================================================================= #define SCREEN_WIDTH 1280 #define SCREEN_HEIGHT 720 #define BLOCK_SIZE 32 // Rozmiar jednego kafelka gry w pikselach (np. 32x32) // Zdefiniuj wskaźnik na bufor ramki w DDR (sprawdź adres w pliku displayport.c / xparameters.h) // Często jest to domyślny adres przypisany do modułu VDMA lub DisplayPort Subsystem #define DISPLAY_FRAME_ADDR 0x10000000 volatile u32* frame_buffer = (volatile u32*)DISPLAY_FRAME_ADDR; // Wymiary planszy gry w kafelkach #define BOARD_WIDTH (SCREEN_WIDTH / BLOCK_SIZE) // np. 40 kafelków #define BOARD_HEIGHT (SCREEN_HEIGHT / BLOCK_SIZE) // np. 22 kafelki #define MAX_SNAKE_LEN 200 typedef enum { UP, DOWN, LEFT, RIGHT } Direction; typedef struct { int16_t x; int16_t y; } Point; // Konwersja Hue na standardowy format 32-bitowy XRGB (0x00RRGGBB) u32 hsv_to_xrgb(u16 hue, u8 value) { if (hue >= 360) hue = hue % 360; 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)r << 16) | ((u32)g << 8) | b; } // Funkcja rysująca fizyczny kwadrat (kafelek) bezpośrednio w pamięci ekranu void draw_tile(int16_t tile_x, int16_t tile_y, u32 color_xrgb) { // Obliczanie początkowych współrzędnych pikseli na ekranie int16_t start_x = tile_x * BLOCK_SIZE; int16_t start_y = tile_y * BLOCK_SIZE; // Rysowanie klocka o wymiarach BLOCK_SIZE x BLOCK_SIZE for (int16_t y = 0; y < BLOCK_SIZE; y++) { for (int16_t x = 0; x < BLOCK_SIZE; x++) { u32 pixel_index = (start_y + y) * SCREEN_WIDTH + (start_x + x); frame_buffer[pixel_index] = color_xrgb; } } } 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--- SNAKE DIRECT FRAMEBUFFER RENDERER ---\r\n"); displayport_init(); displayport_setup_interrupts(); vtc_init(); tpg_init(); // Definiowanie kolorów u32 COLOR_BG = hsv_to_xrgb(200, 15); // Ciemne tło (przyciemniony niebieski) u32 COLOR_SNAKE = hsv_to_xrgb(120, 100); // Zielony wąż u32 COLOR_APPLE = hsv_to_xrgb(0, 100); // Czerwone jabłko // Wyczyszczenie całego ekranu na kolor tła przed startem for (u32 i = 0; i < SCREEN_WIDTH * SCREEN_HEIGHT; i++) { frame_buffer[i] = COLOR_BG; } // Stan gry Point snake[MAX_SNAKE_LEN]; u8 snake_len = 3; Direction dir = RIGHT; Point apple = {12, 7}; Point tail_end = {0, 0}; u8 game_over = 0; u32 score = 0; u32 rand_counter = 0; // Pozycja początkowa snake[0].x = 10; snake[0].y = 7; snake[1].x = 9; snake[1].y = 7; snake[2].x = 8; snake[2].y = 7; // Narysowanie obiektów początkowych for(int i = 0; i < snake_len; i++) { draw_tile(snake[i].x, snake[i].y, COLOR_SNAKE); } draw_tile(apple.x, apple.y, COLOR_APPLE); while (1) { rand_counter++; // 1. STEROWANIE UART (Wpisz klawisz 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; case 0x42: if (dir != UP) dir = DOWN; break; case 0x43: if (dir != LEFT) dir = RIGHT; break; case 0x44: if (dir != RIGHT) dir = LEFT; break; } } } if (game_over) { xil_printf("\rPrzegrana! Czyszczenie ekranu i restart..."); // Czyszczenie ekranu kafelkami for(int16_t x = 0; x < BOARD_WIDTH; x++) { for(int16_t y = 0; y < BOARD_HEIGHT; y++) { draw_tile(x, y, COLOR_BG); } } // Reset parametrów 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 = (rand_counter % (BOARD_WIDTH - 2)) + 1; apple.y = (rand_counter / 3 % (BOARD_HEIGHT - 2)) + 1; score = 0; game_over = 0; // Ponowne rysowanie obiektów for(int i = 0; i < snake_len; i++) { draw_tile(snake[i].x, snake[i].y, COLOR_SNAKE); } draw_tile(apple.x, apple.y, COLOR_APPLE); continue; } // Zapamiętanie końca ogona do zgaszenia tail_end = snake[snake_len - 1]; // 2. LOGIKA RUCHU for (int i = snake_len - 1; i > 0; i--) { snake[i] = snake[i - 1]; } 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 I OGONEM if (snake[0].x < 0 || snake[0].x >= BOARD_WIDTH || snake[0].y < 0 || snake[0].y >= BOARD_HEIGHT) { game_over = 1; continue; } 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. LOGIKA JABŁKA if (snake[0].x == apple.x && snake[0].y == apple.y) { score += 10; if (snake_len < MAX_SNAKE_LEN) { snake_len++; } apple.x = (rand_counter % (BOARD_WIDTH - 2)) + 1; apple.y = (rand_counter / 3 % (BOARD_HEIGHT - 2)) + 1; draw_tile(apple.x, apple.y, COLOR_APPLE); } else { // Nadpisanie starego ogona kolorem tła ekranu draw_tile(tail_end.x, tail_end.y, COLOR_BG); } // 5. RENDEROWANIE GŁOWY WĘŻA NA EKRANIE draw_tile(snake[0].x, snake[0].y, COLOR_SNAKE); xil_printf("\rScore: %d | Glowa: [%d,%d]", score, snake[0].x, snake[0].y); simple_delay(2500000); } cleanup_platform(); return 0; }

No files