1
\$\begingroup\$

I've been trying to make my own implementation of Snake clone using Allegro 5 / C. Unfortunetaly I can't find a good method to align x & y position of snake to grid. I'm looking for some good examples that can solve my problem, preferably in C / C++.

#include <stdio.h>
#include <allegro5/allegro.h>
#include <allegro5/allegro_primitives.h>

#define FPS 60.0f
#define CELL_SIZE 20

typedef struct position
{
    int x, y;
} Position;

typedef struct snake
{
    float x, y;
    float animationTime;
    Position animationOrigin, animationDestination;
} Snake;

Position direction;
static const float snakeSpeed = 30;
static const float speed = 300;

void UpdateSnake(Snake *snake, float timeStep);
float Lerp(float a, float b, float f);

int main(void)
{
    ALLEGRO_DISPLAY *display; 
    ALLEGRO_TIMER *timer;
    ALLEGRO_EVENT_QUEUE *eventQueue;

    if (!al_init() || !(display = al_create_display(800, 600)))
        exit(EXIT_FAILURE);
    if (!al_install_keyboard() || !al_init_primitives_addon())
        exit(EXIT_FAILURE);
    if (!(timer = al_create_timer(1.0 / FPS)))
        exit(EXIT_FAILURE);

    eventQueue = al_create_event_queue();
    al_register_event_source(eventQueue, al_get_keyboard_event_source());
    al_register_event_source(eventQueue, al_get_timer_event_source(timer));
    al_register_event_source(eventQueue, al_get_display_event_source(display));
    al_start_timer(timer);

    float currentTime = 0.0f, lastFrameTime = 0.0f, timeStep = 0.0f;
    bool gameOver = false;
    bool draw = true;
    bool keys[5] = { false };
    enum Keys { DOWN, UP, LEFT, RIGHT, ESCAPE };
    Snake snake = (Snake) { 400.0f, 300.0f, 0.0f, (Position) { 400, 300 }, (Position) { 400, 300 } };

    while (!gameOver)
    {
        ALLEGRO_EVENT events;
        al_wait_for_event(eventQueue, &events);

        switch (events.type)
        {
            case ALLEGRO_EVENT_TIMER:
            {
                draw = true;

                currentTime = (float)al_get_time();
                timeStep = currentTime - lastFrameTime;
                lastFrameTime = currentTime;

                if (keys[UP] && direction.y != 1)
                    direction = (Position) { 0, -1 };

                else if (keys[DOWN] && direction.y != -1)
                    direction = (Position) { 0, 1 };

                else if (keys[LEFT] && direction.x != 1)
                    direction = (Position) { -1, 0 };

                else if (keys[RIGHT] && direction.x != -1)
                    direction = (Position) { 1, 0 };

                if (keys[ESCAPE])
                    gameOver = true;

                UpdateSnake(&snake, timeStep);

                break;
            }

            case ALLEGRO_EVENT_KEY_DOWN:
            {
                switch (events.keyboard.keycode)
                {
                    case ALLEGRO_KEY_W:
                        keys[UP] = true;
                        break;

                    case ALLEGRO_KEY_S:
                        keys[DOWN] = true;
                        break;

                    case ALLEGRO_KEY_A:
                        keys[LEFT] = true;
                        break;

                    case ALLEGRO_KEY_D:
                        keys[RIGHT] = true;
                        break;

                    case ALLEGRO_KEY_ESCAPE:
                        keys[ESCAPE] = true;
                        break;
                }

                break;
            }

            case ALLEGRO_EVENT_KEY_UP:
            {
                switch (events.keyboard.keycode)
                {
                    case ALLEGRO_KEY_W:
                        keys[UP] = false;
                        break;

                    case ALLEGRO_KEY_S:
                        keys[DOWN] = false;
                        break;

                    case ALLEGRO_KEY_A:
                        keys[LEFT] = false;
                        break;

                    case ALLEGRO_KEY_D:
                        keys[RIGHT] = false;
                        break;

                    case ALLEGRO_KEY_ESCAPE:
                        keys[ESCAPE] = false;
                        break;
                }

                break;
            }

            case ALLEGRO_EVENT_DISPLAY_CLOSE:
                gameOver = true;
                break;
        }

        if (draw && al_is_event_queue_empty(eventQueue))
        {
            draw = false;

            al_draw_filled_rectangle(snake.x, snake.y, snake.x + CELL_SIZE, snake.y + CELL_SIZE, al_map_rgb(0, 0, 0));

            al_flip_display();
            al_clear_to_color(al_map_rgb(255, 255, 255));
        }
    }

    al_destroy_display(display);
    al_destroy_timer(timer);
    al_destroy_event_queue(eventQueue);
}

void UpdateSnake(Snake *snake, float timeStep)
{
    if (1)
    {
        snake->x += (speed * timeStep * direction.x);
        snake->y += (speed * timeStep * direction.y);
    }

    if (0)
    {
        if (snake->animationTime == 0.0f)
        {
            snake->animationOrigin.x = ((int)snake->x / CELL_SIZE) * CELL_SIZE;
            snake->animationOrigin.y = ((int)snake->y / CELL_SIZE) * CELL_SIZE;
        }

        snake->animationTime += timeStep;
        float f = snake->animationTime * snakeSpeed;

        if (f >= 1.0f)
        {
            snake->animationTime = 0.0f;
            f = 1.0f;
        }

        if (direction.x == 1) //RIGHT
        {
            snake->animationDestination.x = snake->animationOrigin.x + CELL_SIZE;
            snake->animationDestination.y = snake->animationOrigin.y;
        }

        if (direction.x == -1) //LEFT
        {
            snake->animationDestination.x = snake->animationOrigin.x - CELL_SIZE;
            snake->animationDestination.y = snake->animationOrigin.y;
        }

        if (direction.y == -1) //UP
        {
            snake->animationDestination.x = snake->animationOrigin.x;
            snake->animationDestination.y = snake->animationOrigin.y - CELL_SIZE;
        }

        if (direction.y == 1) //DOWN
        {
            snake->animationDestination.x = snake->animationOrigin.x;
            snake->animationDestination.y = snake->animationOrigin.y + CELL_SIZE;
        }

        snake->x = Lerp(snake->animationOrigin.x, snake->animationDestination.x, f);
        snake->y = Lerp(snake->animationOrigin.y, snake->animationDestination.y, f);
    }
}

float Lerp(float a, float b, float f)
{
    return a + f * (b - a);
}
\$\endgroup\$
10
  • \$\begingroup\$ I'm not sure if I understand the question. What is stopping you giving to the snake the position of one of the tiles of your grid? Can you show us how your grid is implemented? \$\endgroup\$ Sep 12, 2019 at 15:48
  • \$\begingroup\$ I don't know what do you mean by "how my grid is implemented" but I updated my question. \$\endgroup\$
    – wixy0
    Sep 12, 2019 at 15:59
  • \$\begingroup\$ Could you explain what this function is intended to do ? From what I understand it is given two values x and y, makes some calculations, and returns a new position based on them. Are x and y the coordinates of the snake? And is the snake getting the new position from the returned value of this function? \$\endgroup\$ Sep 12, 2019 at 16:07
  • \$\begingroup\$ Ah, sorry I forgot to add, yes, returned Position is based on snake position and snake position is based speed, delta time and direction so it moves freely on the screen (isn't aligned at all). Moreover, I didn't implement grid, I'm asking how to do it. \$\endgroup\$
    – wixy0
    Sep 12, 2019 at 16:15
  • \$\begingroup\$ This looks similar to your previous question. Can you clarify in what way the answer you accepted there falls short of meeting your needs, or what specific help you need putting it into practice? \$\endgroup\$
    – DMGregory
    Sep 12, 2019 at 17:18

0

You must log in to answer this question.

Browse other questions tagged .