Devlog 2: Shaping the world and adding a Twist

Second week of development (and a few days extra) and the game is turning, twisting and morphing into new areas and directions!

So the world-generator is now up and running, as mentioned in the vlog, I LOVE creating level-generators. I could of course have grabbed the one from the original Space Grunts, or possibly from Heroes of Loot 2, but I wanted to create a new one from scratch, as I want the levels to feel different to both of those games. The whole idea behind it is that I want a very “clear” maze, so that’s why I went for the whole “same-size” rooms with corridors linking them.  Then I can just modify the rooms to look like any structure I want, but there’s always a “comfortable” feeling to the whole maze structure, and players should never feel lost.

My maze generation code now looks like this:

int i=maxRoomCount;
while (i>0)
{
    // find a visited room first
    while (roomX<0 || !roomInUse(roomX,roomY) || !roomHasRoomForExits(roomX,roomY))
    {
        if (roomX<0)
        {
            roomX = 1 + getMyRandomValue(World.maxRoomW - 2);
            roomY = 1 + getMyRandomValue(World.maxRoomH - 2);
        }
        else
        {
            roomX++;
            if (roomX>World.maxRoomW-1)
            {
                roomX=2;
                roomY++;
                if (roomY>World.maxRoomH-1)
                {
                    roomY=2;
                }
            }
        }
    }
    
    // pick a random (un-visited) direction
    done=false;
    itteration=8;
    
    roomDirection=getMyRandomValue(4);
    
    // first room? only give it one exit!
    if (firstRoom)
    {
        World.rooms[roomX+(roomY*World.maxRoomW)].limitedToOneExit=true;
        firstRoom=false;
    }

    
    while (!done && itteration>0)
    {
        switch (roomDirection)
        {
            case Globals.UP:
                if (roomY>0 && !roomInUse(roomX, roomY-1) && roomHasRoomForExits(roomX,roomY-1))
                {
                    World.rooms[roomX + (roomY * World.maxRoomW)].exitNorth=true;
                    World.rooms[roomX + ((roomY-1) * World.maxRoomW)].setUsed();
                    World.rooms[roomX + ((roomY-1) * World.maxRoomW)].exitSouth=true;
                    done = true;

                    roomY--;
                }
                
                break;

            case Globals.RIGHT:
                if (roomX<World.maxRoomW-1 && !roomInUse(roomX + 1, roomY) && roomHasRoomForExits(roomX+1,roomY))
                {
                    World.rooms[roomX + (roomY * World.maxRoomW)].exitEast=true;
                    World.rooms[roomX +1+ (roomY * World.maxRoomW)].setUsed();
                    World.rooms[roomX +1+ (roomY * World.maxRoomW)].exitWest=true;
                    done = true;
                    
                    roomX++;
                }
                
                break;

            case Globals.DOWN:
                if (roomY<World.maxRoomH-1 && !roomInUse(roomX , roomY+1) && roomHasRoomForExits(roomX,roomY+1))
                {
                    World.rooms[roomX + (roomY * World.maxRoomW)].exitSouth=true;
                    World.rooms[roomX + ((roomY+1) * World.maxRoomW)].setUsed();
                    World.rooms[roomX + ((roomY+1) * World.maxRoomW)].exitNorth=true;
                    done = true;
                    
                    roomY++;
                }
                
                break;

            case Globals.LEFT:
                if (roomX>0 && !roomInUse(roomX - 1, roomY) && roomHasRoomForExits(roomX-1,roomY))
                {
                    World.rooms[(roomX) + (roomY * World.maxRoomW)].exitWest=true;
                    World.rooms[(roomX-1) + (roomY * World.maxRoomW)].setUsed();
                    World.rooms[(roomX-1) + (roomY * World.maxRoomW)].exitEast=true;
                    done = true;
                    
                    roomX--;
                }
                break;
        }
        if (!done)
        {
            roomDirection=getMyRandomValue(4);
        }
        else
        {
            World.rooms[roomX+(roomY*World.maxRoomW)].generatedID=roomID;
            roomID++;
        }
        
        itteration--;
    }
    
    // make new room an end-room?
    // make sure we are at least >4 rooms away from the starting room.. so we have options to branch
    if (roomID>4)
    {
        if (getMyRandomValue(100)>75
                || (roomX==0 || roomY==0 || roomX==World.maxRoomW || roomY==World.maxRoomH)
                || (minDeadEnd>0 && roomID%3==0))

        {
            if (World.rooms[roomX + (roomY * World.maxRoomW)].countExits()==1)
            {
                // make it a true end-cap room
                World.rooms[roomX + (roomY * World.maxRoomW)].limitedToOneExit = true;
                World.rooms[roomX + (roomY * World.maxRoomW)].hasLockedDoor = true;
            }
            roomX = -1;
            roomY = -1;
            minDeadEnd--;
        }
    }
    
    i--;
    if (i<4 && minDeadEnd>0) i+=2;
}

It generates a pre-specified amount of rooms and also generates a pre-specified amount of “dead-ends”. If we haven’t reached the minimum required amount of “dead-end” rooms, then we generate a few rooms more.

Once all rooms are made, we then let the room generate itself by picking a random template fitting with the amount of exits/connections it has to other rooms, and PRESTO! we have a maze-generator.

CARDS!

Alright, let’s move on to the 2nd biggest thing..  because it’s hard to avoid:  the cards!  I’m still figuring out a bunch of stuff regarding these cards and how to integrate it into the gameplay. But I really love the concept of it, and I wanted to explore it. I never really played much card battle games, and I don’t pretend this will be a card-battle game, but it will be a rogue-like with a card-battle mechanism of sorts.

So most of my energy was put into making the interface work, coming up with card designs, and I’ve set it all up in such a way that the cards handle most of the action and stuff.  Which is funny, because it almost eliminates the need for all the turn-based game-states I mentioned in last weeks devlog !   All the action/interaction is now handled in the card-interface area.

The way I look at this card mechanism, is that your normal game-inventory is replaced with playing-cards. So every item you pick up, is actually a playing card for your deck.  I’m still thinking about adding an inventory screen to the game, and it would allow the player to move cards around, and setup your deck for a big fight by placing some heavy-weapon cards at the front of the deck just before you enter a boss room.

Anyway…

Bookmark the permalink.