13 Oct 09:10
#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"
extern char inbyte(void);
#define BOARD_WIDTH 20
#define BOARD_HEIGHT 15
#define MAX_SNAKE_LEN 100
// Typy obiektów renderowanych na monitorze
#define OBJ_CLEAR 0 // Puste pole / tło
#define OBJ_SNAKE 1 // Segment węża
#define OBJ_APPLE 2 // Jabłko
typedef enum { UP, DOWN, LEFT, RIGHT } Direction;
typedef struct {
int8_t x;
int8_t y;
} Point;
// Funkcja pakująca współrzędne, typ obiektu i kolor Hue w jeden rejestr 32-bitowy
// Bit 31-28: Typ obiektu (0=czyszczenie, 1=wąż, 2=jabłko)
// Bit 27-20: Współrzędna X (0-255)
// Bit 19-12: Współrzędna Y (0-255)
// Bit 11-0 : Wartość Hue (0-360)
void draw_object(u8 obj_type, u8 x, u8 y, u16 hue) {
u32 packed_data = ((u32)(obj_type & 0x0F) << 28) |
((u32)x << 20) |
((u32)y << 12) |
(hue & 0x0FFF);
MYIP_mWriteReg(XPAR_MYIP_0_BASEADDR, MYIP_S00_AXI_SLV_REG0_OFFSET, packed_data);
}
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 MONITOR RENDERER ---\r\n");
displayport_init();
displayport_setup_interrupts();
vtc_init();
tpg_init();
// Definiowanie kolorów w Hue (0-360)
u16 HUE_SNAKE = 120; // Zielony wąż
u16 HUE_APPLE = 0; // Czerwone jabłko
// Stan gry
Point snake[MAX_SNAKE_LEN];
u8 snake_len = 3;
Direction dir = RIGHT;
Point apple = {12, 7};
Point tail_end = {0, 0}; // Przechowuje stary ogon do wyczyszczenia z monitora
u8 game_over = 0;
u32 score = 0;
u32 rand_counter = 0;
// Pozycja startowa
snake[0].x = 10; snake[0].y = 7;
snake[1].x = 9; snake[1].y = 7;
snake[2].x = 8; snake[2].y = 7;
// Wyrysowanie początkowego stanu na monitorze
for(int i = 0; i < snake_len; i++) {
draw_object(OBJ_SNAKE, snake[i].x, snake[i].y, HUE_SNAKE);
}
draw_object(OBJ_APPLE, apple.x, apple.y, HUE_APPLE);
while (1) {
rand_counter++;
// 1. OBSŁUGA STEROWANIA UART
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("\rGAME OVER! Resetowanie planszy...");
// Czyszczenie całego ekranu monitora (kafelek po kafelku)
for(u8 x = 0; x < BOARD_WIDTH; x++) {
for(u8 y = 0; y < BOARD_HEIGHT; y++) {
draw_object(OBJ_CLEAR, x, y, 0);
}
}
// Reset zmiennych
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;
// Ponowne narysowanie stanu startowego
for(int i = 0; i < snake_len; i++) {
draw_object(OBJ_SNAKE, snake[i].x, snake[i].y, HUE_SNAKE);
}
draw_object(OBJ_APPLE, apple.x, apple.y, HUE_APPLE);
continue;
}
// Zapamiętanie ostatniego segmentu ogona przed ruchem (żeby go potem zgasić)
tail_end = snake[snake_len - 1];
// 2. LOGIKA RUCHU WĘŻA
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
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. ZJADANIE JABŁKA
if (snake[0].x == apple.x && snake[0].y == apple.y) {
score += 10;
if (snake_len < MAX_SNAKE_LEN) {
snake_len++;
}
// Nowa pozycja jabłka
apple.x = (rand_counter % (BOARD_WIDTH - 2)) + 1;
apple.y = (rand_counter / 3 % (BOARD_HEIGHT - 2)) + 1;
// Narysowanie nowego jabłka na monitorze
draw_object(OBJ_APPLE, apple.x, apple.y, HUE_APPLE);
} else {
// Jeśli nie zjadł jabłka, stary ogon musi zniknąć z monitora
draw_object(OBJ_CLEAR, tail_end.x, tail_end.y, 0);
}
// 5. AKTUALIZACJA MONITORA
// Rysujemy tylko nową pozycję głowy (reszta ciała podąża za nią, a ogon czyścimy wyżej)
draw_object(OBJ_SNAKE, snake[0].x, snake[0].y, HUE_SNAKE);
xil_printf("\rScore: %d | Snake Head: [%d,%d]", score, snake[0].x, snake[0].y);
simple_delay(2000000);
}
cleanup_platform();
return 0;
}