Absolutely LOST in making Snake

As a diversion from my regular learning, I was making a game of Snake using NCurses. However, my Snake class below is completely not working and I have ABSOLUTELY NO IDEA what is wrong. Could any of you give a hint as to what the errors are, since I am absolutely stuck. Irrelevant code is hidden here, since I have a lot

Here is the structure of my code:

There is a class SnakeGame, in which the user in main only calls game.runLoop. SnakeGame has its own appropriate members, such as the class Snake, which is not working. Additionally, SnakeGame has a WINDOW inside, which the game will be played in:

SnakeGame.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#ifndef SNAKEGAME_HPP
#define SNAKEGAME_HPP

#include <ncurses.h>
#include "Snake.hpp"

class SnakeGame
{
    WINDOW * gameWindow; //Represents what Snake will be played inside
    bool isRunning;
    Snake snake;
    //Window limits initialized in constructor
    //End window limits
    //Basic Functions
    void initGame();
    void readInput();
    void updateGame();
    void gameOver();
    //End basic functions
public:
    SnakeGame();
    void runLoop();
    ~SnakeGame();
};

#endif 


SnakeGame.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
#include <ncurses.h>
#include <unistd.h>
#include <string>
#include "SnakeGame.hpp"
#include "Snake.hpp"

SnakeGame::SnakeGame()
{
    initscr(); //Initalizes curses mode
    cbreak(); //Disallows special functions to interrupt game
    keypad(gameWindow, true); //Allows reading of arrow keys
    noecho();
}

void SnakeGame::initGame()
{
    //Shows title text
    int gameStartKey = getch();
    refresh();
    gameWindow = newwin(30, 100, 0, 0);
    box(gameWindow, 0, 0);
    wrefresh(gameWindow);
}

void SnakeGame::readInput()
{
    int nextKey = wgetch(gameWindow);
    switch(nextKey)
    {
    case KEY_BACKSPACE:
        isRunning = false;
        break;
    case KEY_LEFT:
        snake.setDirection(Direction::LEFT);
        break;
    case KEY_RIGHT:
        snake.setDirection(Direction::RIGHT);
        break;
    case KEY_UP:
        snake.setDirection(Direction::UP);
        break;
    case KEY_DOWN:
        snake.setDirection(Direction::DOWN);
        break;
    }
}

void SnakeGame::updateGame()
{
    snake.moveForward();
    snake.draw(gameWindow);
    wrefresh(gameWindow);
}

void SnakeGame::gameOver()
{
    wborder(gameWindow, ' ', ' ', ' ',' ',' ',' ',' ',' ');
    wrefresh(gameWindow);
    delwin(gameWindow);
    //Does countdown at end in stdscr
}

void SnakeGame::runLoop()
{
    isRunning = true;
    initGame();
    while (isRunning)
    {
        readInput();
        updateGame();
        //wrefresh(gameWindow);
    }
    gameOver();
}

SnakeGame::~SnakeGame()
{
    endwin(); //Ends curses modes. Makes use of RAII to guarantee endwin() is called
}


Snake.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#ifndef SNAKE_HPP
#define SNAKE_HPP

#include <ncurses.h>
#include "Utilities.hpp"
#include <vector>

class Snake
{
    std::vector<Coord> bodyLocations;
    Coord previousTailLocation;
    Direction currentDirection;
public:
    Snake();
    inline void setDirection(Direction dir) { currentDirection = dir; };
    void moveForward();
    void increaseSize();
    void draw(WINDOW * win);
};
#endif 


Below is the main code which is driving me crazy:

Snake.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
#include <ncurses.h>
#include "Snake.hpp"
#include "Utilities.hpp"
#include <vector>

Snake::Snake()
{
    Coord tail{49, 15};
    Coord head{50, 15};
    bodyLocations.push_back(tail);
    bodyLocations.push_back(head);
    previousTailLocation = tail;
    currentDirection = Direction::RIGHT;
}

void Snake::moveForward()
{
    previousTailLocation = bodyLocations[0];
    Coord currentHeadLocation = bodyLocations[bodyLocations.size() - 1];
    for (int i = 0; i < bodyLocations.size() - 2; ++i)
    {
        bodyLocations[i] = bodyLocations[i + 1];
    }
    switch(currentDirection)
    {
    case Direction::UP:
        --currentHeadLocation.y;
        break;
    case Direction::DOWN:
        ++currentHeadLocation.y;
        break;
    case Direction::LEFT:
        --currentHeadLocation.x;
        break;
    case Direction::RIGHT:
        ++currentHeadLocation.x;
        break;
    }
}

void Snake::increaseSize()
{}

void Snake::draw(WINDOW * win)
{
    for (int i = 0; i < bodyLocations.size(); ++i)
    {
        mvwprintw(win, bodyLocations[i].y, bodyLocations[i].x, "o");
    }
    wrefresh(win);
}


I would have expected this to work, but I have really no idea why it is not. The only thing this does is place 2 characters in the center of the window, and not let me do anything with them. In fact, when I press backspace, nothing happens and I have to use Ctrl-C to exit the app from the command line. Coord here represents a simple struct with two public members x and y. Here are the command line arguments I am using:

 
g++ -o snake main.cpp SnakeGame.cpp Snake.cpp -std=c++11 -lncurses
Last edited on
Changes made to the currentHeadLocation variable will not affect the head coordinates in the bodyLocations vector.

You either have to copy it to the vector at the end of the function ...
 
bodyLocations.back() = currentHeadLocation;
... or you could change it to a reference so that the changes are reflected in the vector immediately.
 
Coord& currentHeadLocation = bodyLocations.back();
Last edited on
Thank you, you are a genius. I can't believe I didn't realize that mistake!
Topic archived. No new replies allowed.