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);
}
x
andy
, makes some calculations, and returns a new position based on them. Arex
andy
the coordinates of the snake? And is the snake getting the new position from the returned value of this function? \$\endgroup\$