Files
cppsnek/main.cpp
rattatwinko 239c1a2230 update
2025-05-08 18:00:40 +02:00

280 lines
7.6 KiB
C++

#include <SFML/Graphics.hpp>
#include <vector>
#include <random>
#include <array>
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<array<int, 5>, 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<SnakeSegment> 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<array<int, 5>, 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<array<int, 5>, 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<array<int, 5>, 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;
}