I made an object-oriented maze game. It compiles but I can't move the character around in the maze. Please help me out, thank you.

Person.h file:

#include <windows.h>
#include <process.h>
#pragma once
class Person
{
    private:
        int m_X;
        int m_Y;

    public:
        WORD Color;

        Person();
        ~Person();

        void DrawASCIICharacter(int x, int y, unsigned char ch, WORD CharAttribute, CHAR_INFO *pScreen, int ScreenWidth, int ScreenHeight);
        void DrawPerson(CHAR_INFO *pScreen, int ScreenWidth, int ScreenHeight);

        void SetX(int x);
        void SetY(int y);

        int GetX() const {return m_X;}
        int GetY() const {return m_Y;}
};`

Person.cpp file:

    #include "Person.h"


    Person::Person()
    {
        m_X = 1;
        m_Y = 1;
        Color = FOREGROUND_INTENSITY | FOREGROUND_GREEN | FOREGROUND_BLUE | BACKGROUND_BLUE | BACKGROUND_INTENSITY;
    }


    Person::~Person()
    {
    }

    void Person::DrawASCIICharacter(int x, int y, unsigned char ch, WORD CharAttribute, CHAR_INFO *pScreen, int ScreenWidth, int ScreenHeight)
    {
        if (x < 0) return;
        if (y < 0 ) return;
        if (x >= ScreenWidth) return;
        if (y >= ScreenHeight) return;

        pScreen[y*ScreenWidth + x].Char.AsciiChar = ch;
        pScreen[y*ScreenWidth + x].Attributes = CharAttribute;
    }

    void Person::DrawPerson(CHAR_INFO *pScreen, int ScreenWidth, int ScreenHeight)
    {

        DrawASCIICharacter(m_X, m_Y, 2, Color, pScreen, ScreenWidth, ScreenHeight);

    }

    void Person::SetX(int x)
    {
        m_X = x;
        x = 1;
    }
    void Person::SetY(int y)
    {
        m_Y = y;
        y = 1;
    }

Map.h file:

#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <windows.h>
#include <process.h>
#include <cstdlib>
#include <ctime>
using namespace std;
#pragma once
class Map
{
    private:
        int m_mazeWidth;
        int m_mazeHeight;
        //int m_mazeArray[45*20];

    public:
        WORD mazeColor;
        WORD endColor;
        WORD keyColor;
        WORD doorColor;
        WORD backgroundColor;
        WORD winColor;

        Map();
        ~Map();

        bool CanPlayerEnterSpace(int x, int y);
        void DrawASCIICharacter(int x, int y, unsigned char ch, WORD CharAttribute, CHAR_INFO *pScreen, int ScreenWidth, int ScreenHeight);
        void DrawMaze1234(CHAR_INFO *pScreen, int ScreenWidth, int ScreenHeight);
        void ClearScreen(WORD CharAttribute, CHAR_INFO *pScreen, int ScreenWidth, int ScreenHeight);


};

Map.cpp file:

#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <process.h>
#include <cstdlib>
#include <ctime>
#include "Map.h"
#include "Person.h"
Map::Map()
{
    m_mazeWidth;
    m_mazeHeight;

    mazeColor = FOREGROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_BLUE | BACKGROUND_INTENSITY;
    endColor = FOREGROUND_INTENSITY | FOREGROUND_GREEN | FOREGROUND_GREEN | BACKGROUND_INTENSITY;
    keyColor = FOREGROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_GREEN | BACKGROUND_INTENSITY;
    doorColor = FOREGROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_RED | BACKGROUND_INTENSITY;
    backgroundColor = 0;
    winColor = BACKGROUND_BLUE | BACKGROUND_INTENSITY;

}


Map::~Map()
{
}
void Map::DrawASCIICharacter(int x, int y, unsigned char ch, WORD CharAttribute, CHAR_INFO *pScreen, int ScreenWidth, int ScreenHeight)
{

    if (x < 0) return;
    if (y < 0 ) return;
    if (x >= ScreenWidth) return;
    if (y >= ScreenHeight) return;

    pScreen[y*ScreenWidth + x].Char.AsciiChar = ch;
    pScreen[y*ScreenWidth + x].Attributes = CharAttribute;}


void Map::DrawMaze1234(CHAR_INFO *pScreen, int ScreenWidth, int ScreenHeight)
{
    int mazeArray[45*20] =
    {
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  
    1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 
    1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
    1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 
    1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1,
    1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 4, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1,
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1,
    1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1,
    1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1,
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1,
    1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1,
    1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 4, 0, 1, 0, 0, 1,
    1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1,
    1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1,
    1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1,
    1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1,
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
    1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 5, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
    3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
    };
    int mazeHeight = 45;
    int mazeWidth = 20;
    //int mazeArray[45*20];
    int r, c;
    for (r = 0; r < mazeHeight; r++)
    {
        for (c=0; c < mazeWidth; c++)
        {
            switch (mazeArray[r*mazeWidth + c])
            {
                case 1: DrawASCIICharacter(c, r, 219, mazeColor, pScreen, 20, 45); break;
                case 2: DrawASCIICharacter(c, r, 212, mazeColor, pScreen, 20, 45); break;
                case 3: DrawASCIICharacter(c, r, '*', endColor, pScreen, 20, 45); break;
                case 4: DrawASCIICharacter(c, r, 'K', keyColor, pScreen, 20, 45); break;
                case 5: DrawASCIICharacter(c, r, 68, doorColor, pScreen, 20, 45); break;

            }

        }
    }


}
bool Map::CanPlayerEnterSpace(int x, int y)
{
    int mazeArray[45*20];
    int mazeWidth = 20;
    int keys = 0;
    if (mazeArray[y*mazeWidth + x] == 1) return false;

    if (mazeArray[y*mazeWidth + x] == 5)
    {
        if (keys == 0) return false;
        else
        {
            keys--;
            mazeArray[y*mazeWidth + x] = 0;
            return true;
        }
    }


    return true;


}
void Map::ClearScreen(WORD CharAttribute, CHAR_INFO *pScreen, int ScreenWidth, int ScreenHeight)
{
    int r, c;
    for (r = 0; r < ScreenHeight; r++)
    {
        for (c = 0; c < ScreenWidth; c++)
        {
            pScreen[r*ScreenWidth + c].Char.AsciiChar = ' ';
            pScreen[r*ScreenWidth + c].Attributes = CharAttribute;
        }
    }
}

main.cpp file:

#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <process.h>
#include <cstdlib>
#include <ctime>
#include "Person.h"
#include "Map.h"
using namespace std;

//Constant Global Variables
const int WIDTH = 45;
const int HEIGHT = 30;
const WORD BACKGROUND_COLOR = 0;
const WORD BACKGROUND_COLOR_WIN = BACKGROUND_BLUE | BACKGROUND_INTENSITY;
const WORD PERSON_COLOR = FOREGROUND_INTENSITY | FOREGROUND_GREEN | FOREGROUND_BLUE | BACKGROUND_COLOR;
const WORD END_COLOR = FOREGROUND_INTENSITY | FOREGROUND_GREEN | FOREGROUND_GREEN | BACKGROUND_COLOR;
const WORD KEY_COLOR = FOREGROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_GREEN | BACKGROUND_COLOR;
const WORD DOOR_COLOR = FOREGROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_RED | BACKGROUND_COLOR;
const WORD WALL_COLOR = FOREGROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
const WORD MAZE_COLOR = FOREGROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_BLUE | BACKGROUND_COLOR;

CHAR_INFO SCREEN_BUFFER[HEIGHT * WIDTH];
COORD BUFFER_SIZE = {WIDTH, HEIGHT};
COORD CHARACTER_POSITION = {0,0};
SMALL_RECT WINDOW_SIZE = {0, 0, WIDTH-1, HEIGHT-1};

//Function Prototypes
unsigned int __stdcall UpdateScreenThread(void *pThreadData);

//Global Variables
HANDLE g_hWin;   // Handle to the Standard Output
HANDLE g_hInput; // Handle to the Standard Input
bool g_ISRUNNING = true;

bool isGameDone = false;
int keys = 0;

Map maze;
Person person;

int main()
{

    //person.DrawPerson(SCREEN_BUFFER, WIDTH, HEIGHT);
    //maze.DrawMaze1234(SCREEN_BUFFER, WIDTH, HEIGHT);

    DWORD numEvents, numEventsRead = 0;  // number of Events that have happened
    INPUT_RECORD inputEvent;             // Event from the input (or windows)

    //------------------------------------------
    // Setup the windows console
    //------------------------------------------
    unsigned int seed = time(0);
    srand(seed);
    // get the handles to the standard windows
    g_hWin = GetStdHandle(STD_OUTPUT_HANDLE);
    g_hInput = GetStdHandle(STD_INPUT_HANDLE);

    // Set the title of the window
    SetConsoleTitle(TEXT("The Labyrinth"));

    // Set the console window size
    SetConsoleWindowInfo(g_hWin, TRUE, &WINDOW_SIZE);

    // Set the buffer size
    SetConsoleScreenBufferSize(g_hWin, BUFFER_SIZE);

    maze.ClearScreen(BACKGROUND_COLOR, SCREEN_BUFFER, WIDTH, HEIGHT);


    //------------------------------------------
    // This starts a thread that draws the screen
    //  ever 50 milliseconds
    //------------------------------------------
    unsigned int threadID = 0;
    _beginthreadex(NULL, 0, UpdateScreenThread, NULL, 0, &threadID);


    //------------------------------------------
    // This is the main Loop
    //------------------------------------------
    while (g_ISRUNNING)
    {
        // Check the events
        GetNumberOfConsoleInputEvents(g_hInput, &numEvents);

        if (numEvents)
        {
            ReadConsoleInputA(g_hInput, &inputEvent, 1, &numEventsRead);

            if (numEventsRead)
            {
                // An event has been read in

                // Check the event type: was it a key?
                switch (inputEvent.EventType)
                {
                    case KEY_EVENT:
                        if (inputEvent.Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE)
                        {
                            g_ISRUNNING = false;
                        }

                        if (inputEvent.Event.KeyEvent.wVirtualKeyCode == VK_DOWN)
                        {
                            int p = person.GetY();
                            if (maze.CanPlayerEnterSpace(person.GetX(), person.GetY() + 1))
                                p++;
                        }
                        if (inputEvent.Event.KeyEvent.wVirtualKeyCode == VK_UP)
                        {
                            int p = person.GetY();
                            if (maze.CanPlayerEnterSpace(person.GetX(), person.GetY() - 1))
                                p--;
                        }
                        if (inputEvent.Event.KeyEvent.wVirtualKeyCode == VK_LEFT)
                        {
                            int p = person.GetX();
                            if (maze.CanPlayerEnterSpace(person.GetX() - 1, person.GetY()))
                                p--;
                        }
                        if (inputEvent.Event.KeyEvent.wVirtualKeyCode == VK_RIGHT)
                        {
                            int p = person.GetX();
                            if (maze.CanPlayerEnterSpace(person.GetX() + 1, person.GetY()))
                                p++;
                        }
                        break;


                }
            } 
        } 

        //------------------------------------------
        // You Game code that you want to run "fast" goes here
        //------------------------------------------
    /*if(maze.DrawMaze1234(SCREEN_BUFFER, WIDTH, HEIGHT)
    {
        if (person.DrawPerson(SCREEN_BUFFER, WIDTH, HEIGHT) == 3)
        {
            isGameDone = true;
        }


        if(person.DrawPerson(SCREEN_BUFFER, WIDTH, HEIGHT) == 4)
        {
            keys++;
            mazeArray[g_personY*mazeWidth + g_personX] = 0;
        }
    }*/

    } //while


    return 0;
}

unsigned int __stdcall UpdateScreenThread(void *pThreadData)
{

    while(g_ISRUNNING)
    {
        // call out timer update function
      //  TimerUpdate();
        if (isGameDone)
        {
            // Update the Screen
            maze.ClearScreen(BACKGROUND_BLUE | BACKGROUND_INTENSITY, SCREEN_BUFFER, WIDTH, HEIGHT);
            maze.DrawASCIICharacter(17, 9, 'Y', PERSON_COLOR, SCREEN_BUFFER, WIDTH, HEIGHT);
            maze.DrawASCIICharacter(18, 9, 'o', PERSON_COLOR, SCREEN_BUFFER, WIDTH, HEIGHT);
            maze.DrawASCIICharacter(19, 9, 'u', PERSON_COLOR, SCREEN_BUFFER, WIDTH, HEIGHT);
            maze.DrawASCIICharacter(20, 9, ' ', PERSON_COLOR, SCREEN_BUFFER, WIDTH, HEIGHT);
            maze.DrawASCIICharacter(21, 9, 'W', PERSON_COLOR, SCREEN_BUFFER, WIDTH, HEIGHT);
            maze.DrawASCIICharacter(22, 9, 'i', PERSON_COLOR, SCREEN_BUFFER, WIDTH, HEIGHT);
            maze.DrawASCIICharacter(23, 9, 'n', PERSON_COLOR, SCREEN_BUFFER, WIDTH, HEIGHT);
            maze.DrawASCIICharacter(24, 9, '!', PERSON_COLOR, SCREEN_BUFFER, WIDTH, HEIGHT);
        }
        else
        {
            // Update the Screen
            maze.ClearScreen(BACKGROUND_COLOR, SCREEN_BUFFER, WIDTH, HEIGHT);
            maze.DrawMaze1234(SCREEN_BUFFER, WIDTH, HEIGHT);
            person.DrawPerson(SCREEN_BUFFER, WIDTH, HEIGHT);



        }

        // WriteConsoleOutputA is WriteConsoleOutput ASCII
        WriteConsoleOutputA(g_hWin, SCREEN_BUFFER, BUFFER_SIZE, CHARACTER_POSITION, &WINDOW_SIZE);

        // Wait 50 milli-seconds
        Sleep(50);
    }

    return 0;
}

This is what it looks like but notice how the Keys and Doors look weird (highlighted). And my character(the blue guy) won't move.

f9ad6b3e6951e21e2df95209a04b94ea

You need to use your setX and setY functions to set the new positions, as so:

                    if (inputEvent.Event.KeyEvent.wVirtualKeyCode == VK_DOWN)
                    {
                        if (maze.CanPlayerEnterSpace(person.GetX(), person.GetY() + 1))
                            person.SetY(person.GetY() + 1);
                    }
                    if (inputEvent.Event.KeyEvent.wVirtualKeyCode == VK_UP)
                    {
                        if (maze.CanPlayerEnterSpace(person.GetX(), person.GetY() - 1))
                            person.SetY(person.GetY() - 1);
                    }
                    if (inputEvent.Event.KeyEvent.wVirtualKeyCode == VK_LEFT)
                    {
                        if (maze.CanPlayerEnterSpace(person.GetX() - 1, person.GetY()))
                            person.SetX(person.GetX() - 1);
                    }
                    if (inputEvent.Event.KeyEvent.wVirtualKeyCode == VK_RIGHT)
                    {
                        if (maze.CanPlayerEnterSpace(person.GetX() + 1, person.GetY()))
                            person.SetX(person.GetX() + 1);
                    }
                    break;

The way you had it before, as this:

                        int p = person.GetY();
                        if (maze.CanPlayerEnterSpace(person.GetX(), person.GetY() + 1))
                            p++;

didn't work because the variable p is not referring to the y coordinate in the person object, it is a separate variable, so, when you do p++;, all you are doing is incrementing the p variable, it does nothing to the y coordinate of the person object.

have you tried updating the persons x/y? at the moment all you're doing is checking the next position but not updating to it so on the next loop through when you're checking the next position its going to be the same as the previous position resulting in no movement. simply putting person.setY(person.getY() + 1), person .setY(person.getY() - 1) and person.setX(person.getX() + 1), person.setX(person.getX() - 1) instead of p++ or p-- in there corrisponding if statements should update the persons position so on the next loop through you will be testing the new position and drawing the new position.

i think, just a novice myself.

Edited 3 Years Ago by A Haunted Army

By weird, what exactly do you mean? The backgrounds on both appear to be gray, is that what you are referring to?

If I were you, I would reconsider my design, and specifically, I would want to have some sort of parent GameObject class which the other elements could inherit the common code and constants from. As it is, you are reproducing several constants and the entire DrawASCIICharacter() method, which is something OOP design should help you avoid.

Actually, I would make DrawASCIICharacter() a standalone function, anyway, as it is useful even without reference to any specific object. The following header files should do nicely:

screen.h:

class Screen 
{
private:
    WORD* buffer;
    int width, height;
    int curr_x, curr_y;

public:
    Screen(int w, int h) width(w), height(h)
    {
        return;
    }

    int getWidth()  { return width; };
    int getHeight() { return height; };
    int getX() { return curr_x; };
    int getY() { return curr_y; };        
}

game.h:

#pragma once
#include <windows.h>
#include <process.h>
#include "screen.h"

//Constant Global Variables
const int WIDTH = 45;
const int HEIGHT = 30;

const WORD BACKGROUND_COLOR = 0;
const WORD BACKGROUND_COLOR_WIN = BACKGROUND_BLUE | BACKGROUND_INTENSITY;
const WORD PERSON_COLOR = FOREGROUND_INTENSITY | FOREGROUND_GREEN | FOREGROUND_BLUE | BACKGROUND_COLOR;
const WORD END_COLOR = FOREGROUND_INTENSITY | FOREGROUND_GREEN | FOREGROUND_GREEN | BACKGROUND_COLOR;
const WORD KEY_COLOR = FOREGROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_GREEN | BACKGROUND_COLOR;
const WORD DOOR_COLOR = FOREGROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_RED | BACKGROUND_COLOR;
const WORD WALL_COLOR = FOREGROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
const WORD MAZE_COLOR = FOREGROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_BLUE | BACKGROUND_COLOR;

const CHAR_INFO SCREEN_BUFFER[HEIGHT * WIDTH];
const COORD BUFFER_SIZE = {WIDTH, HEIGHT};
const COORD CHARACTER_POSITION = {0,0};
const SMALL_RECT WINDOW_SIZE = {0, 0, WIDTH-1, HEIGHT-1};

//Function Prototypes
unsigned int __stdcall UpdateScreenThread(void *pThreadData);
void DrawASCIICharacter(int x, int y, unsigned char ch, WORD CharAttribute, Screen& port);


//Global Variables
extern HANDLE g_hWin;   // Handle to the Standard Output
extern HANDLE g_hInput; // Handle to the Standard Input
extern bool g_ISRUNNING = true;

Edited 3 Years Ago by Schol-R-LEA

Oh wow, thanks! I only did person.SetX(1) or person.SetY(1) before. Makes much more sense now. What am I doing wrong with my CanPlayerEnterSpace() function? The player can go through walls so theres probably something I'm missing from the CanPlayerEnterSpace() in the Map.cpp file.

bool Map::CanPlayerEnterSpace(int x, int y)
{
int mazeArray[45*20];
int mazeWidth = 20;
int keys = 0;
if (mazeArray[y*mazeWidth + x] == 1) return false;
if (mazeArray[y*mazeWidth + x] == 5)
{
if (keys == 0) return false;
else
{
keys--;
mazeArray[y*mazeWidth + x] = 0;
return true;
}
}
return true;
}

this function wil always return true because you're creating a local variable of the maze which is un-intialzed so every element is going to contain scrap memory. you are using this varibale to decide whether or not the player can move through it, but, because each element in the map contains scrap memory it will always return true since nothing in the maze will be an object.

what you should do is store the map in the class object itself and either use a construtor, setter function or load-from-file function set up the maze. this maze array in your map object can also be used for displaying images.

as a note, its worth looking at std::vector instead of using raw arrays because its a dynamic array container so you could re-use the map class in the future for different size maps instead of being restrained to a fixed size map.

Edited 3 Years Ago by A Haunted Army

I tried adding the maze array into the CanPlayerEnterSpace function but then my blue ascii character isn't able to move again.

Edited 3 Years Ago by TheNewbie1234

Schol-R-LEA, I added the screen.h and game.h into my program but after compiling it, nothing changed at all. There's still that gray background behind the keys, doors, and the green asterick.

That's just what A Haunted Army means, I think. By hard-wiring the maze into the code, it makes it difficult to change or reuse the code; it would make more sense to use a either a dynamic array or a std::vector< std::vector<char> > to hold the map data, and read the data itself in from a file. Using a vector of vectors would have the advantage that it would automatically track the dimensions of the map for you.

Edited 3 Years Ago by Schol-R-LEA

Ugh, sorry, I didn't explain things very well; I had been in a bit of a rush earlier, and had to finish up before I could explain what I was suggesting.

The idea here is that you would use the header declarations as given here to begin re-writing part of you existing code, to eliminate some redundancies and smooth out the handling of the screen. The Screen class is a represntation of the screen itself; a Screen object holds not only the screen buffer, but the dimensions of the screen, and the current cursor position on the screen. This would actually be only the beginning of the class; in fact, I've changed my mind about DrawASCIICharacter() again, I now think you should make it a method of class Screen. You would use a separate method, let's call it gotoxy() for simplicity's sake, and you would use that to re-position the cursor before calling This let's you separate the

#pragma once

#include <exception>
#include <windows.h>


class ScreenCoordinatesOutOfBoundsException: public exception
{
private:
    unsigned int coordinate;

    ScreenCoordinatesOutOfBoundsException(unsigned int coord): coordinate(coord) {return;};

    virtual const int what() const throw()
    {
        return coordinate;
    }
};

class Screen 
{
private:
    CHAR_INFO* buffer;
    unsigned int width, height;
    unsigned int curr_x, curr_y;

public:
    Screen(unsigned int w, unsigned int h) width(w), height(h)
    {
        buffer = new CHAR_INFO[w][h];
    }

    ~Screen()
    {
        delete buffer;
    }

    unsigned int getWidth()  { return width; };
    unsigned int getHeight() { return height; };
    unsigned int getX() { return curr_x; };
    unsigned int getY() { return curr_y; };

    void gotoxy(int x, int y) throw (ScreenCoordinatesOutOfBoundsException);

    void drawASCIICharacter(unsigned char ch, WORD CharAttribute);
    void drawString(usigned char* str, WORD CharAttribute);
}

Screen.cpp

#include <exception>
#include <windows.h>
#include "screen.h"

void Screen::gotoxy(int x, int y) throw (ScreenCoordinatesOutOfBoundsException)
{
    if (x >= width) 
    {
        throw ScreenCoordinatesOutOfBoundsException(x);
    }
    else if (y >= height) 
    {
        throw ScreenCoordinatesOutOfBoundsException(y);
    }
    else
    {
        curr_x = x;
        curr_y = y; 
    }
}


void Screen::DrawASCIICharacter(unsigned char ch, WORD CharAttribute)
{
    buffer[(curr_y * width) + curr_x].Char.AsciiChar = ch;
    buffer[(curr_y * width) + curr_x].Attributes = CharAttribute;
}


void drawString(usigned char* str, WORD CharAttribute)
{
    int i = 0;
    unsigned char *ch = str;

    while(ch != '\000') 
    {
        this->drawASCIICharacter(ch, CharAttribute);
        ch++;
    }
}

Edited 3 Years Ago by Schol-R-LEA

i think the reason the blue character won't move again is because you're moving the it pixel by pixel but the map is stored as chars, so when you move one pixel you're moving to the next object in the maze. to get the location in the array you want to divide persons poistionX by the width of the objects and Y by the height of the objects.

say the objects are 10x10, pixel position X100 Y100 isn't X10 Y10 in the array, it will still be X100 Y100 so you would be accessing objects that are 10 elements ahead of where the person is in the map. if we divide the pixel position by the width and height of the objects stored in the array then pixel position X100 / 10, Y100 / 10 will give us position X10 Y10 in the array so you we're knowing accesing to correct position in the array.

if you store the maze array in the class itself as you currently have it commented out you will no longer need to re-create it in each function where you need it. all you will need is some manner of initializing the array which is trivial.

The output is pretty much the same as what I've already had. It was a good idea though.

it works in my map class perfectly...

what i mean is

bool Map::CanPlayerEnterSpace(int x, int y)
{
    //calculate the position in the array
    int PosY = std::floor(Y / this->GridHeight);
    int PosX = std::floor(X / this->GridWidth);

    //if there is a collision return false
    if (this->mazeArray[PosY * this->mazeWidth + PosX] == 1) return false;

    //if colliding with a tree adjust how many left
    if (mazeArray[PosY * this->mazeWidth + PosX] == 5){
        if (this->keys == 0) return false;
        else{
            this->keys--;
            this->mazeArray[PosY * this->mazeWidth + PosX] = 0;
        }
    }

    //return truet to allow movement
    return true;
}

GridWidth and GridHeight would be defined how ever you want, they just contain dimensions of the blocks in the array, when you try and access array elements without calculating the position in the array you're trying to access elements ahead of the player actually is. when you do calculate the position you're accessing the location of the player at the correct position in the array.

to search through an array you have to iterate by +1 each time, if the objects stored in the array are 10x10 then it will take 10 pixels before you reach the next object in the array, so it would take +10 visually to move by 1 in the array, if you don't divide by the dimensions of the obejcts then +1 visually will be moving +1 in the array which is ahead of where the player would be located in the map, so visually 10y 10x without calculating will be accessing object 100y 100x visually in the array. with calculating the position visually 10y 10x divided by objects dimensions will be accessing 10y 10x visuall in the array.

assuming the objects are 10x10, 10x 10y in the array would be stored as 1x 1y, 100x 100y would be stored as 10x 10y and soo on...

Edited 3 Years Ago by A Haunted Army

What is the "floor" in this case?

 int PosY = std::floor(Y / this->GridHeight);
 int PosX = std::floor(X / this->GridWidth);

How does it work perfectly for you, I'm getting errors. Are you using private members of the class?

in my own game project it works fine, sorry should have been more clear. yea they should be members of your class because it allows you to re-define them in the future making the code re-usable and that code was meant to be more of an example....

I was also able (after a horrible amount of effort for such a small project) to get it working entirely. It was a completely re-written versions, with hardly anything resembling the original code, however.

This article has been dead for over six months. Start a new discussion instead.