My Roguelike (this one’s for the geeks)


As we’ve talked about previously, I love roguelikes. And I also love programming in python. Which is why it shouldn’t come as a huge surprise that I decided to try to make one. First I made a combat engine which allows special abilities, a relationships and conversation mechanic, and finally pathfinding. Then I scrapped the whole thing because it didn’t work. Later I tried again and came up with a better pathfinding system (read:it works). Later I plan to implement the combat engine from the last game but at the moment all I’ve got is people wondering around a town (yes that is what those rectangles are). For those of you who are interested in programming here is the source code so far. For those of you who are NOT interested in programming and just want to see the code in action download python, start IDLE (comes with python) and run this code in the window.

It has been a few weeks since I’ve looked at it so I’ll do my best to explain what’s going on in it (I’m a lousy commenter).

There are two class, the Game class which controls the game and the Character class which represents the character inside of the game.

The Game Class:
Right now all that this does is first setup the map, tell the characters when to update themselves (take a turn) and display the map when it’s told to.

The Character Class
This is where it’s at just now. The character class handles all the pathfinding. I must say that pathfinding had been the most difficult part of a game to program. Although unlike other areas (balancing and so forth) when it works you usually know that it’s working. What it does is identify where the character wants to get to. Then it looks at where the character is. If that isn’t where the character wants to get to the pathfinder looks at the spaces around it and runs a couple checks on them.

  1. Have I seen this space before? No? Keep going then, else stop and look at the next space in the cue.
  2. Is it possible to walk on this space? If it isn’t stop and look at the next space in the cue.
  3. Is this the space you’re looking for? What?? It isn’t? In that case we’ll just have to add every space around this one to the back of the cue and go onto the next one.

When you finally find the space that you’re looking for the pathfinder generates a list of the moves needed to get to that space which the characters will go through one at a time till it reaches that space and the whole thing starts over again.

This is just the first step in a (rather) large journey. If anybody want to help me make this feel free to chime in.

By now I should have learnt not to try to make predictions about what I’ll talk about in the future but one day I plan to post the game me and Gio made in the large school break as well as posting updates to this project as well as some talk about the direction that I want it to take in terms of game mechanics and philosephy.

#!/usr/bin/env python
import string
import collections

class Game():

    def __init__(self):
        self.make_map()
        self.characters = []

    def loop(self):
        while True:
            for character in self.characters:
                character.update()
            self.display_map()
            raw_input("Press Enter")

    def make_map(self):
        self.map = []
        for line in open('map.txt', 'rU'):
            temp = []
            for i in line.strip():
                temp.append(i)
            self.map.append(temp)

    def display_map(self):
        mapy = []
        for line in self.map:
            temp = []
            for i in line:
                temp.append(i)
            mapy.append(temp)

        if self.characters:
            for character in self.characters:
                mapy[character.position[1]][character.position[0]] = '@'
        for line in mapy:
            print ''.join(line)

class Character():

    def __init__(self, position = (1, 3), goals = None):
        self.position = position
        if goals == None:
            self.goals = [(8, 4), (23, 4), (10, 18)]
        else:
            self.goals = goals
        self.path = []

    def update(self):
        if len(self.path) == 0:
            self.path = self.pathfinder(self.goals[0])
            temp = self.goals.pop(0)
            self.goals.append(temp)
        self.move(self.path.pop(0))

    def pathfinder(self, goal):
        game.map[goal[1]][goal[0]] = '#'
        game.display_map()
        if self.position == goal:
            return True
        else:
            possible = collections.deque()
            for i in self.look_round(self.position):
                possible.append(i)

            seen = []

            while True:
                focus = possible.popleft()
                if (focus[0], focus[1]) in seen:
                    continue
                else:
                    seen.append((focus[0], focus[1]))

                if game.map[focus[1]][focus[0]] == 'x':
                    continue

                if (focus[0], focus[1]) == goal:
                    return focus[2]

                else:
                    for i in self.look_round(focus):
                        possible.append(i)

    def look_round(self, place):
        if len(place) == 2:
            place = (place[0], place[1], [])
        return ((place[0]-1, place[1], place[2] + ['west']),
               (place[0]+1, place[1], place[2] + ['east']),

               (place[0], place[1]+1, place[2] + ['south']),
               (place[0], place[1]-1, place[2] + ['north']),

               (place[0]-1, place[1]-1, place[2] + ['northwest']),
               (place[0]-1, place[1]+1, place[2] + ['southwest']),

               (place[0]+1, place[1]+1, place[2] + ['southeast']),
               (place[0]+1, place[1]-1, place[2] + ['northeast']))

    def move(self, direction):
        moves = {'north': self.move_north,
                 'south': self.move_south,

                 'east': self.move_east,
                 'west': self.move_west,

                 'northwest': self.move_northwest,
                 'northeast': self.move_northeast,

                 'southeast': self.move_southeast,
                 'southwest': self.move_southwest}
        place = moves[direction]()

    def move_west(self):
        self.position = (self.position[0]-1, self.position[1])
        return self.position

    def move_east(self):
        self.position = (self.position[0]+1, self.position[1])
        return self.position

    def move_south(self):
        self.position = (self.position[0], self.position[1]+1)
        return self.position

    def move_north(self):
        self.position = (self.position[0], self.position[1]-1)
        return self.position

    def move_southwest(self):
        self.position = (self.position[0]-1, self.position[1]+1)
        return self.position

    def move_northwest(self):
        self.position = (self.position[0]-1, self.position[1]-1)
        return self.position

    def move_southeast(self):
        self.position = (self.position[0]+1, self.position[1]+1)
        return self.position

    def move_northeast(self):
        self.position = (self.position[0]+1, self.position[1]-1)
        return self.position

game = Game()
game.characters.append(Character())
game.characters.append(Character((15, 12), [(23, 4), (8, 4), (10, 18)]))
game.display_map()
game.loop()
Advertisements

2 thoughts on “My Roguelike (this one’s for the geeks)

  1. Hey, awesome so far :D, specially having the motivation to actually do something…
    Seems good so far, although, at the end of the game is seems to crash a little…
    Also, if you wanna make the game really awesome, take a look at http://tldp.org/HOWTO/Bash-Prompt-HOWTO/c327.html which gives directions on how to colour the terminal or move the writer to a particular position. So,
    print “33[1;34m”
    makes it write in blue and
    print “33[2;2H” puts the cursor at line two column two, so you dont have to reprint the map every time.

    • That is extremely cool, thanks. I spent a little while a few weeks back experimenting with colour. It’d be good to not have to print the whole thing out every time because that’s where most of the speed is lost.

      And what crash? I didn’t notice any.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s