0
\$\begingroup\$

I'm trying to make a simple snake game in C and OpenGL, and I have this at the moment, which runs almost perfectly:

#include "glad/glad.h"
#include <GLFW/glfw3.h>

#include "stb/stb_image.h"

#include <stdio.h>
#include <time.h>
#include <stdlib.h>

#include "cglm/cglm.h"
#include "cglm/call.h"

#include "apple.h"
#include "snake.h"

struct Snake snake;
snakeDir dir;

void initSnake() {
    dir = Up; //Initilize direction

    snake.speed = 15;
    snake.size = 1;

    snake.body[0].x = -1.0f;
    snake.body[0].y = -1.0f;

    snake.head = snake.body[0];

    snake.ticks = 0;
}

static void _drawSnake() {

    snake.ticks++;

    if (glfwGetKey(window.self, GLFW_KEY_UP) == GLFW_PRESS && dir != Down)
        dir = Up;
    if (glfwGetKey(window.self, GLFW_KEY_DOWN) == GLFW_PRESS && dir != Up)
        dir = Down;
    if (glfwGetKey(window.self, GLFW_KEY_LEFT) == GLFW_PRESS && dir != Right)
        dir = Left;
    if (glfwGetKey(window.self, GLFW_KEY_RIGHT) == GLFW_PRESS && dir != Left)
        dir = Right;


    if (snake.ticks == snake.speed) {
        // Move the snake's head in the direction specified by the dir variable
        switch(dir) {
            case Up:
                snake.head.y -= 2.0f;
                break;
            case Down:
                snake.head.y += 2.0f;
                break;
            case Left:
                snake.head.x -= 2.0f;
                break;
            case Right:
                snake.head.x += 2.0f;
                break;
        }

        // Move the snake's body
        for (int i = snake.size - 1; i > 0; i--) {
            snake.body[i] = snake.body[i-1];
        }

        snake.body[0] = snake.head;
        
        // Reset ticks
        snake.ticks = 0;
    }

    // Check if the snake eats an apple
    if (snake.head.x == apple.x && snake.head.y == apple.y) {
        // Generate a new apple
        int rx = (rand() % (10 + 1 + 8) - 8);
        int ry = (rand() % (10 + 1 + 8) - 8);
        float ax = (rx + rx % 2) - 1.0f;
        float ay = (ry + ry % 2) - 1.0f;

        apple.x = ax;
        apple.y = ay;

        snake.size++;
    }

    // Check if the snake hits its own body
    for (int i = 1; i < snake.size; i++) {
        if (snake.head.x == snake.body[i].x && snake.head.y == snake.body[i].y) {
            terminateWindow();
        }
    }
}

void renderSnake(struct Shader shader) {

    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, snake.texture);

    useShader(shader);

    glBindVertexArray(snake.VAO);

    for (int i = 0; i < snake.size; i++) {
        glm_mat4_identity(camera.model); //Reset matrix
        glm_rotate(camera.model, glm_rad(90.0f), (vec3) {1.0f, 0.0f, 0.0f});
        glm_scale(camera.model, (vec3) {0.1, 0.1, 0.05}); //Construct second matrix
        glm_translate(camera.model, (vec3) {snake.body[i].x, snake.body[i].y, -21.0f});
        setShaderMat4(shader, "model", camera.model);

        glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_INT, 0);
    }

    _drawSnake();
}

The only problem is that whenever the snake collects an apple, it looks like the head of the snake or something flashes in the middle of the screen for a second then disappears. I tried tracking this bug down but I can't figure out what it's coming from. This is what it looks like: enter image description here

Does anyone know what bug in my code is causing this? It's really quite annoying and any help is greatly appriciated!

\$\endgroup\$

1 Answer 1

3
\$\begingroup\$

When your "snake eats apple" code block is executed, you increment the snake snake size, but it doesn't look like you're initializing the location for the new snake segment. The flash looks like it's always in the center of your game area. So my intuition is that most recently added block of the snake is appearing at the origin by default, but that this error then gets corrected when the movement code executes because it moves the head & the positions "trickle down" until finally the most recent snake block gets put in the correct location.

If I'm following your code correctly, you can fix this adding an initialization step after growing the snake size:

snake.size++;
if(snake.size > 1)
{
   int last = snake.size - 1;
   snake.body[last] = snake.body[last-1];
}
\$\endgroup\$
2
  • \$\begingroup\$ Hey, this is so close! It works when the snake.body is 2 segments or greater, but if it's only 1 segment (like at the beginning), last-1 is trying to access snake.body[-1] which causes a segfault. Do you have any fix for this? \$\endgroup\$ Commented Mar 31, 2023 at 12:56
  • \$\begingroup\$ I added a guard against that - sorry that I didn't catch that. \$\endgroup\$ Commented Mar 31, 2023 at 21:09

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.