#include #include #include #include using namespace sf; using namespace std; constexpr int WIDTH = 800; constexpr int HEIGHT = 600; constexpr int GRID_SIZE = 40; constexpr int GRID_WIDTH = WIDTH / GRID_SIZE; constexpr int GRID_HEIGHT = HEIGHT / GRID_SIZE; constexpr int SPRITE_SIZE = GRID_SIZE; struct SnakeSegment { int x, y; }; class NumericSprite { private: Texture texture; Sprite sprite; public: NumericSprite() { texture.create(SPRITE_SIZE, SPRITE_SIZE); sprite.setTexture(texture); } void createFromPattern(const array, 5>& pattern, Color color) { Image img; img.create(SPRITE_SIZE, SPRITE_SIZE, Color::Transparent); int scale = SPRITE_SIZE / 5; for (int y = 0; y < 5; y++) { for (int x = 0; x < 5; x++) { if (pattern[y][x] == 1) { for (int sy = 0; sy < scale; sy++) { for (int sx = 0; sx < scale; sx++) { img.setPixel(x * scale + sx, y * scale + sy, color); } } } } } texture.update(img); } const Sprite& getSprite() const { return sprite; } void setPosition(float x, float y) { sprite.setPosition(x, y); } }; class Game { private: RenderWindow window; vector snake; Vector2f fruit; Vector2f direction; bool isMoving; Clock clock; float speed; int score; Font font; Text scoreText; // Numeric sprites NumericSprite snakeHeadSprite; NumericSprite snakeBodySprite; NumericSprite fruitSprite; // Grid vertex array VertexArray grid; // Patterns const array, 5> HEAD_PATTERN = {{ {1, 1, 1, 1, 1}, {1, 1, 1, 1, 1}, {1, 1, 1, 1, 1}, {1, 1, 1, 1, 1}, {1, 1, 1, 1, 1} }}; const array, 5> BODY_PATTERN = {{ {1, 1, 1, 1, 1}, {1, 1, 1, 1, 1}, {1, 1, 1, 1, 1}, {1, 1, 1, 1, 1}, {1, 1, 1, 1, 1} }}; // Apple-like pattern const array, 5> FRUIT_PATTERN = {{ {0, 1, 1, 1, 0}, {1, 1, 1, 1, 1}, {1, 1, 1, 1, 1}, {1, 1, 1, 1, 1}, {0, 1, 1, 1, 0} }}; public: Game() : window(VideoMode(WIDTH, HEIGHT), "SFML CPPSNEK V1.2"), direction(1, 0), isMoving(false), speed(0.1f), score(0), grid(Lines) { window.setFramerateLimit(60); // Initialize snake snake.push_back({GRID_WIDTH / 2, GRID_HEIGHT / 2}); snake.push_back({GRID_WIDTH / 2 - 1, GRID_HEIGHT / 2}); snake.push_back({GRID_WIDTH / 2 - 2, GRID_HEIGHT / 2}); // Create sprites snakeHeadSprite.createFromPattern(HEAD_PATTERN, Color(200, 200, 0)); // Yellow head snakeBodySprite.createFromPattern(BODY_PATTERN, Color(0, 200, 0)); // Green body fruitSprite.createFromPattern(FRUIT_PATTERN, Color(200, 0, 0)); // Red apple // Create grid createGrid(); spawnFruit(); // Setup font if (!font.loadFromFile("/usr/share/fonts/gnu-free/FreeSans.ttf")) { font.loadFromFile("/usr/share/fonts/liberation/LiberationSans-Regular.ttf"); } scoreText.setFont(font); scoreText.setCharacterSize(24); scoreText.setFillColor(Color::White); scoreText.setPosition(10, 10); updateScoreText(); } void createGrid() { // Vertical lines for (int x = 0; x <= WIDTH; x += GRID_SIZE) { grid.append(Vertex(Vector2f(x, 0), Color(50, 50, 50))); grid.append(Vertex(Vector2f(x, HEIGHT), Color(50, 50, 50))); } // Horizontal lines for (int y = 0; y <= HEIGHT; y += GRID_SIZE) { grid.append(Vertex(Vector2f(0, y), Color(50, 50, 50))); grid.append(Vertex(Vector2f(WIDTH, y), Color(50, 50, 50))); } } void spawnFruit() { static random_device rd; static mt19937 gen(rd()); uniform_int_distribution<> distX(0, GRID_WIDTH - 1); uniform_int_distribution<> distY(0, GRID_HEIGHT - 1); fruit.x = distX(gen); fruit.y = distY(gen); for (const auto& segment : snake) { if (segment.x == fruit.x && segment.y == fruit.y) { spawnFruit(); return; } } } void updateScoreText() { scoreText.setString("Score: " + to_string(score)); } void handleInput() { if (Keyboard::isKeyPressed(Keyboard::Left) && direction.x == 0) { direction = Vector2f(-1, 0); isMoving = true; } else if (Keyboard::isKeyPressed(Keyboard::Right) && direction.x == 0) { direction = Vector2f(1, 0); isMoving = true; } else if (Keyboard::isKeyPressed(Keyboard::Up) && direction.y == 0) { direction = Vector2f(0, -1); isMoving = true; } else if (Keyboard::isKeyPressed(Keyboard::Down) && direction.y == 0) { direction = Vector2f(0, 1); isMoving = true; } } void update() { if (clock.getElapsedTime().asSeconds() < speed || !isMoving) return; clock.restart(); SnakeSegment newHead = {snake[0].x + direction.x, snake[0].y + direction.y}; if (newHead.x < 0 || newHead.x >= GRID_WIDTH || newHead.y < 0 || newHead.y >= GRID_HEIGHT) { reset(); return; } for (size_t i = 1; i < snake.size(); i++) { if (newHead.x == snake[i].x && newHead.y == snake[i].y) { reset(); return; } } if (newHead.x == fruit.x && newHead.y == fruit.y) { snake.insert(snake.begin(), newHead); spawnFruit(); score += 10; updateScoreText(); if (score % 50 == 0 && speed > 0.05f) { speed -= 0.01f; } } else { snake.insert(snake.begin(), newHead); snake.pop_back(); } } void reset() { snake.clear(); snake.push_back({GRID_WIDTH / 2, GRID_HEIGHT / 2}); snake.push_back({GRID_WIDTH / 2 - 1, GRID_HEIGHT / 2}); snake.push_back({GRID_WIDTH / 2 - 2, GRID_HEIGHT / 2}); direction = Vector2f(1, 0); isMoving = false; speed = 0.1f; score = 0; updateScoreText(); spawnFruit(); } void render() { window.clear(Color(30, 30, 30)); // Dark gray background // Draw grid first window.draw(grid); // Draw snake for (size_t i = 0; i < snake.size(); i++) { if (i == 0) { snakeHeadSprite.setPosition(snake[i].x * GRID_SIZE, snake[i].y * GRID_SIZE); window.draw(snakeHeadSprite.getSprite()); } else { snakeBodySprite.setPosition(snake[i].x * GRID_SIZE, snake[i].y * GRID_SIZE); window.draw(snakeBodySprite.getSprite()); } } // Draw fruit (apple) fruitSprite.setPosition(fruit.x * GRID_SIZE, fruit.y * GRID_SIZE); window.draw(fruitSprite.getSprite()); // Draw score window.draw(scoreText); window.display(); } void run() { while (window.isOpen()) { Event event; while (window.pollEvent(event)) { if (event.type == Event::Closed) window.close(); } handleInput(); update(); render(); } } }; int main() { Game game; game.run(); return 0; }