Skip to main content
Tweeted twitter.com/#!/StackGameDev/status/587673529061093377
tag, make code example a bit shorter
Source Link
congusbongus
  • 14.9k
  • 58
  • 89

C++: Game State Logic other than Implementing game state without switch statementstatements everywhere?

Currently all my games use a very simplistic game state "engine" that is just auses switch statementstatements everywhere. It's very messy, violates DRY horribly, and does not scale very well.

enum STATE {
    LOADING,
    TITLE,
    LEVEL_ONE,
    LEVEL_TWO,
    LEVEL_THREE,
    LEVEL_FOUR,
    LEVEL_FIVE,
    LEVEL_SIX,
   // LEVEL_SEVEN,...
    WIN,
    GAME_OVER,
    CREDITS,
}GAME_STATE;


void Input() {
    keyboard->Update();

    //Check if the user wants to quit, if so, jump out.
    if(keyboard->KeyDown(KEY_ESC)) quit = true;
    if(quit) return;..

    switch(GAME_STATE) {
        case LOADING:
            break;
        case TITLE:
            if(keyboard->isKeyPressed())
                NEXT_LEVEL = true;
            break;
        case LEVEL_ONE:
        case LEVEL_TWO:
        case LEVEL_THREE:
        case LEVEL_FOUR:
        case LEVEL_FIVE:
        case LEVEL_SIX:

        case LEVEL_SEVEN:

            if(keyboard->KeyPress(KEY_PAUSE))// return;...
            InputCommon();
            break;
        case WIN:
        case GAME_OVER:
            if(keyboard->KeyDown(KEY_ENTER))
                GAME_STATE = CREDITS;
            break;
        case CREDITS:
            if(keyboard->isKeyPressed())
                quit = true;
            break;
    }
}

void Processing(int dead) {

    //Do nothing if user wants to quit.
    if(quit) return;

    if(keyboard->KeyPress(KEY_PAUSE)) return;

    deathTimer = dead;

    if(NEXT_LEVEL) {
        createFood();
        LoadLevel();
   // }...

    switch(GAME_STATE) {
        case LOADING:
            break;
        case TITLE:
            break;
        case LEVEL_ONE:
        case LEVEL_TWO:
        case LEVEL_THREE:
        case LEVEL_FOUR:
        case LEVEL_FIVE:
        case LEVEL_SIX:
        case// LEVEL_SEVEN:...
            ProcessLevel();
            if(GAME_STATE == LEVEL_SEVEN) {
                showWalls = true;
                sh->Index(BLEVELSEVEN)->SetAlpha(0);
                clear_bitmap(FOG_OF_WAR->GetImage());
                rectfill(FOG_OF_WAR->GetImage(), 0, 0, 226, _gw->GetHeight(), TRANSPARENT);
                rectfill(FOG_OF_WAR->GetImage(), 798, 0, _gw->GetWidth(), _gw->GetHeight(), TRANSPARENT);
                for(int i = 0; i < MAX_PLAYERS; i++) {
                    circlefill(FOG_OF_WAR->GetImage(), player[i]->GetX() + player[i]->GetSprite()->GetCenterX(), player[i]->GetY() + player[i]->GetSprite()->GetCenterY(), 90, TRANSPARENT);
               // }...
            }
            break;
        case WIN:
            break;
        case GAME_OVER:
            break;
        case CREDITS:
            break;
    }
}

void Render() {
    //Do nothing if the user wants to quit.
    if(quit) return;

    //Start render process.
    _gw->StartRender();.

    switch(GAME_STATE) {
        case LOADING:
            break;
        case TITLE:
            sh->Draw(_gw->GetBackBuffer(), sh->Index(0));
            break;
        case LEVEL_ONE:
        case LEVEL_TWO:
        case LEVEL_THREE:
        case LEVEL_FOUR:
        case LEVEL_FIVE:
        case LEVEL_SIX:
        case LEVEL_SEVEN:

            //BACKGROUND
            RenderLevel();

            //OBJECTS
            //PILLS
            for(int i = 0; i < MAX_PILLS; i++) {
                if(pills[i]->IsAlive()) sh->Draw(_gw->GetBackBuffer(), pills[i]->GetSprite());
            }
            //FOOD
            for(int i = 0; i < MAX_FOOD; i ++) {
                if(food[i]->IsAlive()) sh->Draw(_gw->GetBackBuffer(), food[i]->GetSprite());
                if(hasFood[i] == true) sh->Draw(_gw->GetBackBuffer(), dynamic_cast<AnimatedSprite*>(food[i]->GetSprite())->GetFrames()[i], 800, 100 + (i * 32), WHITE, 0, 255);
            }
            if(showWalls) {
                //WALLS
                for(int i = 0; i < MAX_WALLS; i++) {
                    rectfill(_gw->GetBackBuffer(), walls[i]->GetX(), walls[i]->GetY(), walls[i]->GetX() + walls[i]->GetWidth(), walls[i]->GetY() + walls[i]->GetHeight(), walls[i]->GetColor());
                }
                for(int i = 0; i < MAX_HIDDEN; i++) {
                    rectfill(_gw->GetBackBuffer(), hidden[i]->GetX(), hidden[i]->GetY(), hidden[i]->GetX() + hidden[i]->GetWidth(), hidden[i]->GetY() + hidden[i]->GetHeight(), hidden[i]->GetColor());
                }
            }
            if(showWaypoints) {
                for(int i = 0; i < MAX_WAYPOINTS; i ++) {
                    rectfill(_gw->GetBackBuffer(), waypoints[i]->GetX(), waypoints[i]->GetY(), waypoints[i]->GetX() + 7,waypoints[i]->GetY() + 7, BLACK);
                }
            }
            //Copy area for teleports
            copyTeleports();

            for(int i = 0; i < MAX_PLAYERS; i++) {
                if(player[i]->IsAlive()) {
                    switch(player[i]->GetFacing()) {
                        case Actor::RIGHT:
                            sh->Draw(_gw->GetBackBuffer(), player[i]->GetSprite());
                            break;
                        case Actor::LEFT:
                            sh->Draw(_gw->GetBackBuffer(), player[i]->GetSprite());
                            break;
                        case Actor::UP:
                            sh->Draw(_gw->GetBackBuffer(), player[i]->GetSprite());
                            break;
                        case Actor::DOWN:
                            sh->Draw(_gw->GetBackBuffer(), player[i]->GetSprite());
                            break;
                    }
                } else {
                    sh->Draw(_gw->GetBackBuffer(), player[i]->GetSprite());
                }
            }
            //ENEMIES
            for(int i = 0; i < MAX_ENEMIES; i++) {
                if(enemies[i]->IsAlive()) {
                    switch(enemies[i]->GetFacing()) {
                        case Actor::RIGHT:
                            sh->Draw(_gw->GetBackBuffer(), enemies[i]->GetSprite());
                            break;
                        case Actor::LEFT:
                            sh->DrawFlip(_gw->GetBackBuffer(), enemies[i]->GetSprite(), SpriteHandler::VERTICAL);
                            break;
                        case Actor::UP:
                            enemies[i]->GetSprite()->SetRotation(-90.0f);
                            sh->DrawRotate(_gw->GetBackBuffer(), enemies[i]->GetSprite());
                            break;
                        case Actor::DOWN:
                            enemies[i]->GetSprite()->SetRotation(90.0f);
                            sh->DrawRotateFlip(_gw->GetBackBuffer(), enemies[i]->GetSprite(), SpriteHandler::HORIZONTAL);
                            break;
                    }
                }
            }
            for(int i = 0; i < MAX_PUPS; i ++) {
                if(powerups[i]->IsAlive()) sh->Draw(_gw->GetBackBuffer(), powerups[i]->GetSprite());
            }

            //MOVED FOOD TO BEFORE TELEPORT COPY SO FOOD DOESN'T GET COVERED.

            for(int i = 0; i < MAX_PLAYERS; i++) {
                drawUI(i);
            }

            //Draw area for teleports.
            drawTeleports();
            
            //Draw fog of war for level seven.
            if(GAME_STATE == LEVEL_SEVEN) {
                sh->Draw(_gw->GetBackBuffer(), FOG_OF_WAR);
            }

            //Show level number
            textprintf_ex(_gw->GetBackBuffer(), UI_font->GetFont(), 20, 0, WHITE, -1, "LEVEL %d", GAME_STATE - 1);

            //Show PAUSE.
            if(keyboard->KeyPress(KEY_PAUSE)) {
                textout_ex(_gw->GetBackBuffer(), UI_font->GetFont(), "PAUSED", (_gw->GetWidth() / 2) - (UI_font->GetLength("PAUSED") / 2), (_gw->GetHeight() / 2) - (UI_font->GetHeight() / 2), WHITE, -1);
            }..
            break;
        case WIN:
            sh->Draw(_gw->GetBackBuffer(), sh->Index(3));
            break;
        case GAME_OVER:
            sh->Draw(_gw->GetBackBuffer(), sh->Index(1));
            break;
        case CREDITS:
            sh->Draw(_gw->GetBackBuffer(), sh->Index(2));
            break;
    }

    //End render process, display to screen.
    _gw->EndRender();

}

C++: Game State Logic other than switch statement?

Currently all my games use a very simplistic game state "engine" that is just a switch statement. It's very messy, violates DRY horribly, and does not scale very well.

enum STATE {
    LOADING,
    TITLE,
    LEVEL_ONE,
    LEVEL_TWO,
    LEVEL_THREE,
    LEVEL_FOUR,
    LEVEL_FIVE,
    LEVEL_SIX,
    LEVEL_SEVEN,
    WIN,
    GAME_OVER,
    CREDITS,
}GAME_STATE;


void Input() {
    keyboard->Update();

    //Check if the user wants to quit, if so, jump out.
    if(keyboard->KeyDown(KEY_ESC)) quit = true;
    if(quit) return;

    switch(GAME_STATE) {
        case LOADING:
            break;
        case TITLE:
            if(keyboard->isKeyPressed())
                NEXT_LEVEL = true;
            break;
        case LEVEL_ONE:
        case LEVEL_TWO:
        case LEVEL_THREE:
        case LEVEL_FOUR:
        case LEVEL_FIVE:
        case LEVEL_SIX:

        case LEVEL_SEVEN:

            if(keyboard->KeyPress(KEY_PAUSE)) return;
            InputCommon();
            break;
        case WIN:
        case GAME_OVER:
            if(keyboard->KeyDown(KEY_ENTER))
                GAME_STATE = CREDITS;
            break;
        case CREDITS:
            if(keyboard->isKeyPressed())
                quit = true;
            break;
    }
}

void Processing(int dead) {

    //Do nothing if user wants to quit.
    if(quit) return;

    if(keyboard->KeyPress(KEY_PAUSE)) return;

    deathTimer = dead;

    if(NEXT_LEVEL) {
        createFood();
        LoadLevel();
    }

    switch(GAME_STATE) {
        case LOADING:
            break;
        case TITLE:
            break;
        case LEVEL_ONE:
        case LEVEL_TWO:
        case LEVEL_THREE:
        case LEVEL_FOUR:
        case LEVEL_FIVE:
        case LEVEL_SIX:
        case LEVEL_SEVEN:
            ProcessLevel();
            if(GAME_STATE == LEVEL_SEVEN) {
                showWalls = true;
                sh->Index(BLEVELSEVEN)->SetAlpha(0);
                clear_bitmap(FOG_OF_WAR->GetImage());
                rectfill(FOG_OF_WAR->GetImage(), 0, 0, 226, _gw->GetHeight(), TRANSPARENT);
                rectfill(FOG_OF_WAR->GetImage(), 798, 0, _gw->GetWidth(), _gw->GetHeight(), TRANSPARENT);
                for(int i = 0; i < MAX_PLAYERS; i++) {
                    circlefill(FOG_OF_WAR->GetImage(), player[i]->GetX() + player[i]->GetSprite()->GetCenterX(), player[i]->GetY() + player[i]->GetSprite()->GetCenterY(), 90, TRANSPARENT);
                }
            }
            break;
        case WIN:
            break;
        case GAME_OVER:
            break;
        case CREDITS:
            break;
    }
}

void Render() {
    //Do nothing if the user wants to quit.
    if(quit) return;

    //Start render process.
    _gw->StartRender();

    switch(GAME_STATE) {
        case LOADING:
            break;
        case TITLE:
            sh->Draw(_gw->GetBackBuffer(), sh->Index(0));
            break;
        case LEVEL_ONE:
        case LEVEL_TWO:
        case LEVEL_THREE:
        case LEVEL_FOUR:
        case LEVEL_FIVE:
        case LEVEL_SIX:
        case LEVEL_SEVEN:

            //BACKGROUND
            RenderLevel();

            //OBJECTS
            //PILLS
            for(int i = 0; i < MAX_PILLS; i++) {
                if(pills[i]->IsAlive()) sh->Draw(_gw->GetBackBuffer(), pills[i]->GetSprite());
            }
            //FOOD
            for(int i = 0; i < MAX_FOOD; i ++) {
                if(food[i]->IsAlive()) sh->Draw(_gw->GetBackBuffer(), food[i]->GetSprite());
                if(hasFood[i] == true) sh->Draw(_gw->GetBackBuffer(), dynamic_cast<AnimatedSprite*>(food[i]->GetSprite())->GetFrames()[i], 800, 100 + (i * 32), WHITE, 0, 255);
            }
            if(showWalls) {
                //WALLS
                for(int i = 0; i < MAX_WALLS; i++) {
                    rectfill(_gw->GetBackBuffer(), walls[i]->GetX(), walls[i]->GetY(), walls[i]->GetX() + walls[i]->GetWidth(), walls[i]->GetY() + walls[i]->GetHeight(), walls[i]->GetColor());
                }
                for(int i = 0; i < MAX_HIDDEN; i++) {
                    rectfill(_gw->GetBackBuffer(), hidden[i]->GetX(), hidden[i]->GetY(), hidden[i]->GetX() + hidden[i]->GetWidth(), hidden[i]->GetY() + hidden[i]->GetHeight(), hidden[i]->GetColor());
                }
            }
            if(showWaypoints) {
                for(int i = 0; i < MAX_WAYPOINTS; i ++) {
                    rectfill(_gw->GetBackBuffer(), waypoints[i]->GetX(), waypoints[i]->GetY(), waypoints[i]->GetX() + 7,waypoints[i]->GetY() + 7, BLACK);
                }
            }
            //Copy area for teleports
            copyTeleports();

            for(int i = 0; i < MAX_PLAYERS; i++) {
                if(player[i]->IsAlive()) {
                    switch(player[i]->GetFacing()) {
                        case Actor::RIGHT:
                            sh->Draw(_gw->GetBackBuffer(), player[i]->GetSprite());
                            break;
                        case Actor::LEFT:
                            sh->Draw(_gw->GetBackBuffer(), player[i]->GetSprite());
                            break;
                        case Actor::UP:
                            sh->Draw(_gw->GetBackBuffer(), player[i]->GetSprite());
                            break;
                        case Actor::DOWN:
                            sh->Draw(_gw->GetBackBuffer(), player[i]->GetSprite());
                            break;
                    }
                } else {
                    sh->Draw(_gw->GetBackBuffer(), player[i]->GetSprite());
                }
            }
            //ENEMIES
            for(int i = 0; i < MAX_ENEMIES; i++) {
                if(enemies[i]->IsAlive()) {
                    switch(enemies[i]->GetFacing()) {
                        case Actor::RIGHT:
                            sh->Draw(_gw->GetBackBuffer(), enemies[i]->GetSprite());
                            break;
                        case Actor::LEFT:
                            sh->DrawFlip(_gw->GetBackBuffer(), enemies[i]->GetSprite(), SpriteHandler::VERTICAL);
                            break;
                        case Actor::UP:
                            enemies[i]->GetSprite()->SetRotation(-90.0f);
                            sh->DrawRotate(_gw->GetBackBuffer(), enemies[i]->GetSprite());
                            break;
                        case Actor::DOWN:
                            enemies[i]->GetSprite()->SetRotation(90.0f);
                            sh->DrawRotateFlip(_gw->GetBackBuffer(), enemies[i]->GetSprite(), SpriteHandler::HORIZONTAL);
                            break;
                    }
                }
            }
            for(int i = 0; i < MAX_PUPS; i ++) {
                if(powerups[i]->IsAlive()) sh->Draw(_gw->GetBackBuffer(), powerups[i]->GetSprite());
            }

            //MOVED FOOD TO BEFORE TELEPORT COPY SO FOOD DOESN'T GET COVERED.

            for(int i = 0; i < MAX_PLAYERS; i++) {
                drawUI(i);
            }

            //Draw area for teleports.
            drawTeleports();
            
            //Draw fog of war for level seven.
            if(GAME_STATE == LEVEL_SEVEN) {
                sh->Draw(_gw->GetBackBuffer(), FOG_OF_WAR);
            }

            //Show level number
            textprintf_ex(_gw->GetBackBuffer(), UI_font->GetFont(), 20, 0, WHITE, -1, "LEVEL %d", GAME_STATE - 1);

            //Show PAUSE.
            if(keyboard->KeyPress(KEY_PAUSE)) {
                textout_ex(_gw->GetBackBuffer(), UI_font->GetFont(), "PAUSED", (_gw->GetWidth() / 2) - (UI_font->GetLength("PAUSED") / 2), (_gw->GetHeight() / 2) - (UI_font->GetHeight() / 2), WHITE, -1);
            }
            break;
        case WIN:
            sh->Draw(_gw->GetBackBuffer(), sh->Index(3));
            break;
        case GAME_OVER:
            sh->Draw(_gw->GetBackBuffer(), sh->Index(1));
            break;
        case CREDITS:
            sh->Draw(_gw->GetBackBuffer(), sh->Index(2));
            break;
    }

    //End render process, display to screen.
    _gw->EndRender();

}

Implementing game state without switch statements everywhere?

Currently all my games use a very simplistic game state "engine" that uses switch statements everywhere. It's very messy, violates DRY horribly, and does not scale very well.

enum STATE {
    LOADING,
    TITLE,
    LEVEL_ONE,
    LEVEL_TWO,
    // ...
    WIN,
    GAME_OVER,
    CREDITS,
}GAME_STATE;


void Input() {
    // ...

    switch(GAME_STATE) {
        case LOADING:
            break;
        case TITLE:
            break;
        case LEVEL_ONE:
        case LEVEL_TWO:
        // ...
            InputCommon();
            break;
        case WIN:
        case GAME_OVER:
            if(keyboard->KeyDown(KEY_ENTER))
                GAME_STATE = CREDITS;
            break;
        case CREDITS:
            if(keyboard->isKeyPressed())
                quit = true;
            break;
    }
}

void Processing(int dead) {

    // ...

    switch(GAME_STATE) {
        case LOADING:
            break;
        case TITLE:
            break;
        case LEVEL_ONE:
        case LEVEL_TWO:
        // ...
            ProcessLevel();
            if(GAME_STATE == LEVEL_SEVEN) {
                // ...
            }
            break;
        case WIN:
            break;
        case GAME_OVER:
            break;
        case CREDITS:
            break;
    }
}

void Render() {
    // ...

    switch(GAME_STATE) {
        case LOADING:
            break;
        case TITLE:
            sh->Draw(_gw->GetBackBuffer(), sh->Index(0));
            break;
        case LEVEL_ONE:
        case LEVEL_TWO:
        // ...

            // ...
            break;
        case WIN:
            sh->Draw(_gw->GetBackBuffer(), sh->Index(3));
            break;
        case GAME_OVER:
            sh->Draw(_gw->GetBackBuffer(), sh->Index(1));
            break;
        case CREDITS:
            sh->Draw(_gw->GetBackBuffer(), sh->Index(2));
            break;
    }

    //End render process, display to screen.
    _gw->EndRender();

}
Source Link
Casey
  • 2.1k
  • 2
  • 18
  • 26

C++: Game State Logic other than switch statement?

Executive summary

Are there any good tutorials on Game State FSMs, particularly OOP/OOD-based and not switch-statement-based?

Summary

Is there a practical process for creating a game state engine other than using a switch statement, preferably with examples? Wikipedia's event-driven FSM article only shows a switch statement and the article on FSMs is strictly theory-based with no practical examples.

Background

Currently all my games use a very simplistic game state "engine" that is just a switch statement. It's very messy, violates DRY horribly, and does not scale very well.

Each state is treated as a level and must be checked at all three points throughout the game loop, i.e. Input, Processing, and Render. If a level or screen is added it must be added to all the switch statements.

Practical example of recreation of pac-man for educational purposes (seriously, this was a school project a few years ago):

enum STATE {
    LOADING,
    TITLE,
    LEVEL_ONE,
    LEVEL_TWO,
    LEVEL_THREE,
    LEVEL_FOUR,
    LEVEL_FIVE,
    LEVEL_SIX,
    LEVEL_SEVEN,
    WIN,
    GAME_OVER,
    CREDITS,
}GAME_STATE;


void Input() {
    keyboard->Update();

    //Check if the user wants to quit, if so, jump out.
    if(keyboard->KeyDown(KEY_ESC)) quit = true;
    if(quit) return;

    switch(GAME_STATE) {
        case LOADING:
            break;
        case TITLE:
            if(keyboard->isKeyPressed())
                NEXT_LEVEL = true;
            break;
        case LEVEL_ONE:
        case LEVEL_TWO:
        case LEVEL_THREE:
        case LEVEL_FOUR:
        case LEVEL_FIVE:
        case LEVEL_SIX:

        case LEVEL_SEVEN:

            if(keyboard->KeyPress(KEY_PAUSE)) return;
            InputCommon();
            break;
        case WIN:
        case GAME_OVER:
            if(keyboard->KeyDown(KEY_ENTER))
                GAME_STATE = CREDITS;
            break;
        case CREDITS:
            if(keyboard->isKeyPressed())
                quit = true;
            break;
    }
}

void Processing(int dead) {

    //Do nothing if user wants to quit.
    if(quit) return;

    if(keyboard->KeyPress(KEY_PAUSE)) return;

    deathTimer = dead;

    if(NEXT_LEVEL) {
        createFood();
        LoadLevel();
    }

    switch(GAME_STATE) {
        case LOADING:
            break;
        case TITLE:
            break;
        case LEVEL_ONE:
        case LEVEL_TWO:
        case LEVEL_THREE:
        case LEVEL_FOUR:
        case LEVEL_FIVE:
        case LEVEL_SIX:
        case LEVEL_SEVEN:
            ProcessLevel();
            if(GAME_STATE == LEVEL_SEVEN) {
                showWalls = true;
                sh->Index(BLEVELSEVEN)->SetAlpha(0);
                clear_bitmap(FOG_OF_WAR->GetImage());
                rectfill(FOG_OF_WAR->GetImage(), 0, 0, 226, _gw->GetHeight(), TRANSPARENT);
                rectfill(FOG_OF_WAR->GetImage(), 798, 0, _gw->GetWidth(), _gw->GetHeight(), TRANSPARENT);
                for(int i = 0; i < MAX_PLAYERS; i++) {
                    circlefill(FOG_OF_WAR->GetImage(), player[i]->GetX() + player[i]->GetSprite()->GetCenterX(), player[i]->GetY() + player[i]->GetSprite()->GetCenterY(), 90, TRANSPARENT);
                }
            }
            break;
        case WIN:
            break;
        case GAME_OVER:
            break;
        case CREDITS:
            break;
    }
}

void Render() {
    //Do nothing if the user wants to quit.
    if(quit) return;

    //Start render process.
    _gw->StartRender();

    switch(GAME_STATE) {
        case LOADING:
            break;
        case TITLE:
            sh->Draw(_gw->GetBackBuffer(), sh->Index(0));
            break;
        case LEVEL_ONE:
        case LEVEL_TWO:
        case LEVEL_THREE:
        case LEVEL_FOUR:
        case LEVEL_FIVE:
        case LEVEL_SIX:
        case LEVEL_SEVEN:

            //BACKGROUND
            RenderLevel();

            //OBJECTS
            //PILLS
            for(int i = 0; i < MAX_PILLS; i++) {
                if(pills[i]->IsAlive()) sh->Draw(_gw->GetBackBuffer(), pills[i]->GetSprite());
            }
            //FOOD
            for(int i = 0; i < MAX_FOOD; i ++) {
                if(food[i]->IsAlive()) sh->Draw(_gw->GetBackBuffer(), food[i]->GetSprite());
                if(hasFood[i] == true) sh->Draw(_gw->GetBackBuffer(), dynamic_cast<AnimatedSprite*>(food[i]->GetSprite())->GetFrames()[i], 800, 100 + (i * 32), WHITE, 0, 255);
            }
            if(showWalls) {
                //WALLS
                for(int i = 0; i < MAX_WALLS; i++) {
                    rectfill(_gw->GetBackBuffer(), walls[i]->GetX(), walls[i]->GetY(), walls[i]->GetX() + walls[i]->GetWidth(), walls[i]->GetY() + walls[i]->GetHeight(), walls[i]->GetColor());
                }
                for(int i = 0; i < MAX_HIDDEN; i++) {
                    rectfill(_gw->GetBackBuffer(), hidden[i]->GetX(), hidden[i]->GetY(), hidden[i]->GetX() + hidden[i]->GetWidth(), hidden[i]->GetY() + hidden[i]->GetHeight(), hidden[i]->GetColor());
                }
            }
            if(showWaypoints) {
                for(int i = 0; i < MAX_WAYPOINTS; i ++) {
                    rectfill(_gw->GetBackBuffer(), waypoints[i]->GetX(), waypoints[i]->GetY(), waypoints[i]->GetX() + 7,waypoints[i]->GetY() + 7, BLACK);
                }
            }
            //Copy area for teleports
            copyTeleports();

            for(int i = 0; i < MAX_PLAYERS; i++) {
                if(player[i]->IsAlive()) {
                    switch(player[i]->GetFacing()) {
                        case Actor::RIGHT:
                            sh->Draw(_gw->GetBackBuffer(), player[i]->GetSprite());
                            break;
                        case Actor::LEFT:
                            sh->Draw(_gw->GetBackBuffer(), player[i]->GetSprite());
                            break;
                        case Actor::UP:
                            sh->Draw(_gw->GetBackBuffer(), player[i]->GetSprite());
                            break;
                        case Actor::DOWN:
                            sh->Draw(_gw->GetBackBuffer(), player[i]->GetSprite());
                            break;
                    }
                } else {
                    sh->Draw(_gw->GetBackBuffer(), player[i]->GetSprite());
                }
            }
            //ENEMIES
            for(int i = 0; i < MAX_ENEMIES; i++) {
                if(enemies[i]->IsAlive()) {
                    switch(enemies[i]->GetFacing()) {
                        case Actor::RIGHT:
                            sh->Draw(_gw->GetBackBuffer(), enemies[i]->GetSprite());
                            break;
                        case Actor::LEFT:
                            sh->DrawFlip(_gw->GetBackBuffer(), enemies[i]->GetSprite(), SpriteHandler::VERTICAL);
                            break;
                        case Actor::UP:
                            enemies[i]->GetSprite()->SetRotation(-90.0f);
                            sh->DrawRotate(_gw->GetBackBuffer(), enemies[i]->GetSprite());
                            break;
                        case Actor::DOWN:
                            enemies[i]->GetSprite()->SetRotation(90.0f);
                            sh->DrawRotateFlip(_gw->GetBackBuffer(), enemies[i]->GetSprite(), SpriteHandler::HORIZONTAL);
                            break;
                    }
                }
            }
            for(int i = 0; i < MAX_PUPS; i ++) {
                if(powerups[i]->IsAlive()) sh->Draw(_gw->GetBackBuffer(), powerups[i]->GetSprite());
            }

            //MOVED FOOD TO BEFORE TELEPORT COPY SO FOOD DOESN'T GET COVERED.

            for(int i = 0; i < MAX_PLAYERS; i++) {
                drawUI(i);
            }

            //Draw area for teleports.
            drawTeleports();
            
            //Draw fog of war for level seven.
            if(GAME_STATE == LEVEL_SEVEN) {
                sh->Draw(_gw->GetBackBuffer(), FOG_OF_WAR);
            }

            //Show level number
            textprintf_ex(_gw->GetBackBuffer(), UI_font->GetFont(), 20, 0, WHITE, -1, "LEVEL %d", GAME_STATE - 1);

            //Show PAUSE.
            if(keyboard->KeyPress(KEY_PAUSE)) {
                textout_ex(_gw->GetBackBuffer(), UI_font->GetFont(), "PAUSED", (_gw->GetWidth() / 2) - (UI_font->GetLength("PAUSED") / 2), (_gw->GetHeight() / 2) - (UI_font->GetHeight() / 2), WHITE, -1);
            }
            break;
        case WIN:
            sh->Draw(_gw->GetBackBuffer(), sh->Index(3));
            break;
        case GAME_OVER:
            sh->Draw(_gw->GetBackBuffer(), sh->Index(1));
            break;
        case CREDITS:
            sh->Draw(_gw->GetBackBuffer(), sh->Index(2));
            break;
    }

    //End render process, display to screen.
    _gw->EndRender();

}