0
\$\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\$
  • \$\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\$ – TomTsagk Sep 12 '19 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 '19 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\$ – TomTsagk Sep 12 '19 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 '19 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 '19 at 17:18

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.