Roguelike Aoc – part 24

In the twenty-fourth lesson of a roguelike game tutorial a decoupling of display and logic happened. That was something that I was planning for some time (Locations in my Level instance were specifically created for that). Let’s get into it.

Starting with the Player

Again we have a situation where my previous job was right. I already have created playerDraw function. Its only job is to draw a player at the provided coordinates. What I’ve decided to do (and in the monsters drawing functions it will be the same), I’ve made the parameter to this function just a variable, not a pointer.

Second place where we have to make a change is mvprintw call in the playerMove in the canGoToPosition IF statement:

    
  if (canGoToPosition(possibleY, possibleX)) {
        // THIS STATEMENT MUST GO!
        mvprintw(level->user->currentLocation->position.y, level->user->currentLocation->position.x,
               level->user->currentLocation->displaySign);

Redrawing monsters

Ok, up until now the monsters were a tough one. There is a lot of logic involved there – first with positioning the monsters in a level and then with moving them around. The author did a nice thing – just removed all the drawing functions from monster.c file. That bold tactics actually is great! What is more – my equivalent of setStartingPosition for monsters actually does not contain any drawing logic so no changes has to be done here.

Same as author I’ve added drawMonster function, although I’ve made the parameter as variable – we just read the value. Maybe it’s not how’s supposed to be in C, but I prefer passing value of the variable instead of pointer that is supposed to be constant. The intent is even more clear – I only want to get the data, not even thinking about modifying it:

void drawMonster(Monster monster)
{
     if(monster.alive == TRUE) {
            mvprintw(monster.currentLocation->position.y, monster.currentLocation->position.x, monster.displaySign);
    }
}  

To be more consistent I’ve moved the function drawMonsters from the level.c file to the monster.c where it belongs. The function right now looks like this:

void drawMonsters(Level *level) {
    for(int i = 0; i < level->numberOfMonsters; i++) {     
        drawMonster(*level->monsters[i]);
    }
}

Drawing the whole level

In level.c in the same way as author I’ve added drawLevel function which looks like this:

void drawLevel(Level *level)
{
    int x, y;

    // printing locations
    for (y = 0; y < MAX_HEIGHT; y++) {
        for (x = 0; x < MAX_WIDTH; x++) {
            mvprintw(y, x, level->locations[y][x].displaySign);
        }
    }

    drawMonsters(level);
    playerDraw(*level->user);
}

As You can see I’ve used already existing drawMonsters function (instead of a loop). Due to the fact that my displaySign property is a pointer, I did not have to change drawing to the mvaddch function.

Making it all work together

As You recall in a previous lesson I did not implement the menu as there was no way to do that using PDCurses. Therefore, also the separate game loop was not created. In order to make everything work as expected I’ve modified my main.c loop. Before it looked like this:

    screenSetup();
    Level *level = createLevel(DEFAULT_LEVEL_NUMBER, NUMBER_OF_ROOMS, NUMBER_OF_MONSTERS);
    
    // Initial drawing when we enter the game
    printGameHub(level);
    playerDraw(level->user);
    
    /* Main game loop */
    char keyPressed;
    while((keyPressed = getch()) != 'q') {
        handleInput(keyPressed, level);
        moveMonsters(level);
        printGameHub(level);
        playerDraw(level->user);  // We redraw the player position after redrawing everything else
    }

To incorporate all the changes we’ve made the new version is this:

    screenSetup();
    Level *level = createLevel(DEFAULT_LEVEL_NUMBER, NUMBER_OF_ROOMS, NUMBER_OF_MONSTERS);
    
    /* Main game loop */
    char keyPressed = ' ';
    while(keyPressed != 'q') {
        handleInput(keyPressed, level);
        moveMonsters(level);
    
        printGameHub(level);
        drawLevel(level);
        keyPressed = getch();
    }

Viola! We have a working level redrawing solution! It feels good 😉

Code

Here is the direct link to the GitHub repo.

You Might Also Like

Leave a Reply

Back to top