1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-26 08:47:34 +00:00

Snake: Use a queue for the movement inputs.

This makes it a lot less finicky to make rapid moves like staircasing and
sudden turns.
This commit is contained in:
Andreas Kling 2019-04-20 03:44:01 +02:00
parent e24e486714
commit b41e95b578
3 changed files with 43 additions and 20 deletions

View file

@ -39,6 +39,9 @@ public:
const T& at(int index) const { return m_elements[(m_head + index) % Capacity]; } const T& at(int index) const { return m_elements[(m_head + index) % Capacity]; }
const T& first() const { return at(0); }
const T& last() const { return at(size() - 1); }
class ConstIterator { class ConstIterator {
public: public:
bool operator!=(const ConstIterator& other) { return m_index != other.m_index; } bool operator!=(const ConstIterator& other) { return m_index != other.m_index; }

View file

@ -56,11 +56,13 @@ void SnakeGame::timer_event(CTimerEvent&)
if (m_tail.size() > m_length) if (m_tail.size() > m_length)
m_tail.take_last(); m_tail.take_last();
m_head.row += m_vertical_velocity; if (!m_velocity_queue.is_empty())
m_head.column += m_horizontal_velocity; m_velocity = m_velocity_queue.dequeue();
m_last_vertical_velocity = m_vertical_velocity; m_head.row += m_velocity.vertical;
m_last_horizontal_velocity = m_horizontal_velocity; m_head.column += m_velocity.horizontal;
m_last_velocity = m_velocity;
if (m_head.row >= m_rows) if (m_head.row >= m_rows)
m_head.row = 0; m_head.row = 0;
@ -90,31 +92,27 @@ void SnakeGame::keydown_event(GKeyEvent& event)
switch (event.key()) { switch (event.key()) {
case KeyCode::Key_A: case KeyCode::Key_A:
case KeyCode::Key_Left: case KeyCode::Key_Left:
if (m_last_horizontal_velocity == 1) if (last_velocity().horizontal == 1)
break; break;
m_vertical_velocity = 0; queue_velocity(0, -1);
m_horizontal_velocity = -1;
break; break;
case KeyCode::Key_D: case KeyCode::Key_D:
case KeyCode::Key_Right: case KeyCode::Key_Right:
if (m_last_horizontal_velocity == -1) if (last_velocity().horizontal == -1)
break; break;
m_vertical_velocity = 0; queue_velocity(0, 1);
m_horizontal_velocity = 1;
break; break;
case KeyCode::Key_W: case KeyCode::Key_W:
case KeyCode::Key_Up: case KeyCode::Key_Up:
if (m_last_vertical_velocity == 1) if (last_velocity().vertical == 1)
break; break;
m_vertical_velocity = -1; queue_velocity(-1, 0);
m_horizontal_velocity = 0;
break; break;
case KeyCode::Key_S: case KeyCode::Key_S:
case KeyCode::Key_Down: case KeyCode::Key_Down:
if (m_last_vertical_velocity == -1) if (last_velocity().vertical == -1)
break; break;
m_vertical_velocity = 1; queue_velocity(1, 0);
m_horizontal_velocity = 0;
break; break;
default: default:
break; break;
@ -149,3 +147,18 @@ void SnakeGame::game_over()
{ {
reset(); reset();
} }
void SnakeGame::queue_velocity(int v, int h)
{
if (last_velocity().vertical == v && last_velocity().horizontal == h)
return;
m_velocity_queue.enqueue({ v, h });
}
const SnakeGame::Velocity& SnakeGame::last_velocity() const
{
if (!m_velocity_queue.is_empty())
return m_velocity_queue.last();
return m_last_velocity;
}

View file

@ -1,6 +1,7 @@
#pragma once #pragma once
#include <LibGUI/GWidget.h> #include <LibGUI/GWidget.h>
#include <AK/CircularQueue.h>
class SnakeGame : public GWidget { class SnakeGame : public GWidget {
public: public:
@ -24,18 +25,24 @@ private:
} }
}; };
struct Velocity {
int vertical { 0 };
int horizontal { 0 };
};
void game_over(); void game_over();
void spawn_fruit(); void spawn_fruit();
bool is_available(const Coordinate&); bool is_available(const Coordinate&);
void queue_velocity(int v, int h);
const Velocity& last_velocity() const;
int m_rows { 20 }; int m_rows { 20 };
int m_columns { 20 }; int m_columns { 20 };
int m_horizontal_velocity { 1 }; Velocity m_velocity { 0, 1 };
int m_vertical_velocity { 0 }; Velocity m_last_velocity { 0, 1 };
int m_last_horizontal_velocity { 1 }; CircularQueue<Velocity, 10> m_velocity_queue;
int m_last_vertical_velocity { 0 };
Coordinate m_head; Coordinate m_head;
Vector<Coordinate> m_tail; Vector<Coordinate> m_tail;