Archive for the ‘libtcod’ Tag

getting started with game development and Common Lisp

Things have been on a slow simmer here for a while. I kept up the small weekly ritual of my IF news report IFURLs, and read a fair bit, but I hadn’t been too satisfied with doing things with a computer, playing, or making games this summer. This is still sticking around some — playing IF on a computer at a desk is increasingly less appealing (making things like this more and more attractive) — but, and I don’t know if it’s the turn to Fall that’s stoking the fire, I’ve spent more time in the cave lately so to speak, and capped by a long session last night I sort of feel like I’m ‘back’.

The thing keeping me up last night was compiling Steel Bank Common Lisp for Windows. Mostly a straightforward job thanks to the fine folks working on sbcl and the msys/MinGW build environment, but if you ever need to do the same thing, just put the sbcl source directory in a path without spaces before you compile — trust me on this one.

The other wrinkle not really mentioned in the sbcl install docs is you’ll probably have to explicitly set the sbcl home variable if you don’t usually work as the Windows admin user, and then reboot your system for the path changes to take full effect.

What led me to compiling sbcl rather than using the slightly older Windows binary was a problem loading cl-tcod from within Emacs+SLIME using Quicklisp (a nicer alternative to the older asdf-install package loading library for the language Common Lisp).

If you’ve read stuff here before you may recognize the tcod initials — cl-tcod is a binding for the great roguelike library libtcod. Not only is libtcod a great roguelike library, but the community has grown so much that it now has bindings for many different languages. For a language aficionado like myself, that makes it a great handle to learn new languages that I’m interested in — which brings me full circle back to the title of this post, game development, and Lisp.

It may sound weird, but I feel like going to the land of Lisp is an inevitable part of my programming bildungsroman. It started back in May with some prompt or another, I don’t remember exactly what, which led to trying out Racket, a dialect of Scheme. Racket is quite nice, and I found Michele Simionato’s The Adventures of a Pythonista in Schemeland an excellent guide along the way.

But in the end, even though there is of course a Racket binding to libtcod, I felt there wasn’t enough support in terms of a game development environment with Racket. However it did look like there was a lot of activity on the other side of the fence so to speak, with Common Lisp, once I discovered the Lisp Games Wiki — and so I was lured over.

It seems like Lisp is a whirlpool — once I went for Common Lisp, diving into Emacs and SLIME followed soon after. The problem with something like this is the complexity just exploded. It’s nothing like first working with Python, where getting a development environment set up fast is relatively trivial. With the Lisp bindings to libtcod, I found myself really using msys for the first time, compiling the latest libtcod in svn, then compiling sbcl, working my way through the right choice of a package installer for Common Lisp, setting up SLIME, getting the package installer configured correctly, and on and on. Much of this friction comes from working in Windows, and I suppose I accept that willingly given the trade offs.

Then you have Lisp itself, and especially Common Lisp — a 40 something year old legacy and all the cruft that entails. Seriously, some of this stuff almost makes me cry working through it — the influence of Lisp on Python is obvious, and it’s a bloody trail hacked out of the Forest of Lisp! Good guides here have been Practical Common Lisp and Successful Lisp. The Common Lisp Cookbook is a good companion too.

Despite the complexities and the cruft, there’s something about Lisp that’s positively endearing — I can’t put my finger on it yet. It just feels worth it.

Of course I have a roguelike game idea I’m working on in Common Lisp, and I’ll record the progress of that here for anyone else who might learn from it.

So this is (again) the first step. To put all the links in one place, if you want to follow along:

Getting started with game development and Common Lisp

* msys/MinGW
* SBCL
* Emacs
* SLIME
* Quicklisp
* Lisp Games Wiki
* Practical Common Lisp
* Successful Lisp
* cl-tcod
* libtcod
* Common Lisp Cookbook

Bidden #8

I didn’t get back to Bidden until last Thursday (at least according to the commit log, I might have done a couple of things before then), but between Thursday and today I’ve:

* added levels and level switching
* added a datastore to make it easier to make new things after I’ve loaded everything in from level files
* added a basic animation system (X-com style with turn-based)
* tweaked the level generator a little to make it look nicer (to me)
* added a stairway driller to this generator
* along with the stairway added stair exits

For this level generator (the temple) the stairs work a little differently from a typical RL — there’s one stairway created (so far), and all the stairs are connected. When you walk over a stair you automatically descend/ascend, and are put in the middle of the staircase. At the top and bottom level you can’t go up or down anymore of course. I might change this to use an ascend/descend command, but I’m leaning toward not at the moment.

Ran into obvious but for a while insidious bug (aren’t they all) where the stair exit move event handlers were all firing, because I wasn’t modifying the event data packet properly…

I’m finding it’s very important to have a standard way of handling event data for each event handler. Better yet, I should standardize that somehow in something that takes care of that automatically. I don’t think I’m quite there yet though. With the pieces I have now there’s enough to hammer on to get things tight before I start to add much more.

Bidden 7DRL code review

While things are still fresh in my mind I want to review the somewhat bizarre code design I came up with during the 7DRL, if only to mark a way point to look back on as things change.

Here’s the code (Leo makes exporting this outline easy):

+ Code
	- TODO
	+ @thin bidden.py
		- << docstring >>
		- << import >>
		- << constants >>
		+ class Game
			- __init__
			- load
			- save
			- create_gid
			- register_gid
		+ class Event
			- __init__
			- broadcast
			- register_component
		+ class Control
			- __init__
			- action
			- switch_view
			- quit
		+ Controllers
			+ class Menu
				- __init__
				+ new_game
					- << make player >>
					- << make binding >>
					+ << load from .bid >>
						- << test >>
					- << put things in stage >>
			+ class Intro
				- __init__
			+ class Play
				- __init__
				- move
				- use_boon
				- wait
				- help
			+ class Coda
				- __init__
		+ class Component
			- __init__
			- __lt__
			- __gt__
		+ Components
			+ class Hunter
				- __init__
			+ class Container
				- __init__
			+ class Model
				- __init__
				- on_death
			+ class XY
				- __init__
				- on_move
			+ class Stage
				- __init__
				- create
			+ class Collision
				- __init__
				- on_move
			+ class Bump
				- __init__
				- on_move
			+ class Title
				- __init__
				- create
				- make
			+ class Hunted
				- __init__
				- on_death
			+ class Wounds
				- __init__
			+ Boons
				+ class Boon
					- __init__
				+ class Strike
					- __init__
					- on_boon
			+ AIs
				+ class AI
					- __init__
				+ class Zombie
					- __init__
					- decide
		+ class Prototype
			- __init__
		+ class UI
			- init
			+ class Pane
				- __init__
				- fade_in
			+ class Animation
				- __init__
			- input
			- view
			- menu_draw
			- intro_draw
			- play_draw
			- coda_draw
			- quit_draw
			- play_help_draw
		+ class Keyboard
			- __init__
			- check
		- << run game >>

Let’s look at the concise version:

+ @thin bidden.py
	- << docstring >>
	- << import >>
	- << constants >>
	+ class Game
	+ class Event
	+ class Control
	+ Controllers
	+ class Component
	+ Components
	+ class Prototype
	+ class UI
	+ class Keyboard
	- << run game >>

Going over things from the main loop:

    while not libtcod.console_is_window_closed() and not game.control == 'quit':
        keys.check()

        if game.control == 'play':
            for item in game.gids:
                thing = game.gids[item]
                for k in thing.__dict__:
                    c = thing.__dict__[k]
                    if isinstance(c, AI):
                        c.decide()
        ui.view()

The keys instance of Keyboard waits for a key press. If it gets an ‘x’ or the control key it waits for another key press. This is my somewhat hacked way to get key + direction key combinations. It checks if the key is in the configuration for the game, and sends a message (such as ‘up’ or ‘enter’) to the method UI.input.

That method passes along the input to the current game.control, including it in a dict and adding the enactor game ID (in the case of the player, 0). There’s a control basically for each state of the game (main menu, in-play, etcetera). I tried to make all arguments passed around in the form of a dictionary, using the same key names for like types of data.

Each control inherits an action method from the Control parent. This method checks the input message against an actions dictionary, and if the message is a key, it runs the corresponding value as a method on the control instance (for example, I had the ‘enter’ key mapped to a method to advance the state of the game arbitrarily, so I could restart the game without exiting/restarting the Python file). Individual control instances may map the same message to different methods of course.

This method gets the data in the dict described above. A good example is the move method (in the ‘play’ control instance, mapped to the ‘up/down/right/left’ message which is mapped to the arrow keys in the keys instance):

def move(self, data):
    self.directions = {
                        'up' : {'x':0, 'y':-1},
                        'down' : {'x':0, 'y':1},
                        'right' : {'x':1, 'y':0},
                        'left' : {'x':-1, 'y':0},
                        }

    data['event'] = 'on_move'
    data['outcome'] = 'continue'
    data.update(self.directions[data['input']])


    event.broadcast(data)

So this method basically adds data to the dictionary, and then sends it to the instance of Event.

Event , in the context of the 7DRL, probably was a big mistake…going into the week I had vague thoughts of trying out a message passing/broadcasting scheme for the first time, and this was the result. I spent a lot of time figuring this out.

The Event.broadcast method takes the data and sends it along to anything registered to listen for the event included, in this case ‘on_move’. So, when the player presses the up key, it’s not directly moving the player-character, but telling the game to announce that the player-character has the intention of moving…I know, I know.

To digress for a moment, each thing in the game is an instance of Prototype, which basically is a collection of Components. A component is a narrowly-defined piece of functionality, that registers itself with the event instance upon creation. For example, if the component has a method called on_move, the event instance will tell the component when an on_move event occurs.

There is a component called XY that holds the in-game position of a thing, and its on_move looks like this:

def on_move(self, data):
    if (data['enactor'] == self.gid) and (data['outcome'] == 'continue'):
        self.x += data['x']
        self.y += data['y'] 
    return data

When the player presses the arrow key and the event instance broadcasts ‘on_move’, the XY component of the player-character will take that data — if the ‘outcome’ is ‘continue’ — modify its x and y position, then pass the data along back to the broadcaster.

The reason for ‘outcome’, and passing the data back to the broadcaster, is that other components handle things like collision with walls and bumping into other things. They’ll have an on_move method, and it receives the data broadcast. For example, here is collision:

def on_move(self, data):
    enactor = game.gids[data['enactor']]
    dx = data['x']
    dy = data['y']
    xx = enactor.XY.x + dx
    yy = enactor.XY.y + dy 

    stage = game.gids[game.stage].Stage 

    if not stage.cells[yy][xx]['kind'] == 'floor':
        data['outcome'] = 'failure'
        return data

    return data

Now obviously the question came up — in which order is the event broadcast? In other words, if the XY of the player happened to get the event before collision, the player would move before the collision check even happened.

To make this work I gave each component a priority from 1 to 1000, with a default of 1000. The collision component’s priority is 100, and the XY priority is 1000. Then before event broadcasts, it sorts the list of components registered for the event. This is easy to do with Python by writing a method like so on the Component parent.

def __lt__(self, other):
    if self.priority < other.priority:
        return True
    else:
        return False

If the class defines __lt__, then calling sort() on a list of instances of that class will sort it appropriately.

That’s all there is to the event broadcasting, basically a chain of event filters that modify both the event data and game world data as the event propagates through the listening components. I suppose I’ll find out what problems this causes down the road!

NPC actions are basically the same, the only difference being in how they’re initiated. Going back to the game loop:

        if game.control == 'play':
            for item in game.gids:
                thing = game.gids[item]
                for k in thing.__dict__:
                    c = thing.__dict__[k]
                    if isinstance(c, AI):
                        c.decide()

This runs through each component, and if it’s an AI, it runs the decide method. This is all I have for decide at the moment (in the Zombie component):

def decide(self):
    choice = random.choice(self.actions)

    data = {'enactor' : self.gid, 'input' : choice}
    control = game.controllers[game.control]
    control.action(data)

Where its self.actions is just this list — [‘up’, ‘down’, ‘right’, ‘left’, ‘wait’].

This just gave me an idea for attaching AI components to the player…anyway.

After the player does their thing and the AI runs, the UI instance runs its view method, which looks like this:

def view(self):
    libtcod.console_clear(0)

    for item in self.views:
            func = getattr(self, game.control + item)
            func()

    libtcod.console_flush()

So, clear the console, and go through its list of views and run the function — for example, there’s one called ‘play_draw’, where ‘play’ is the game.control and the item is ‘_draw’.

Other conceivable ones might be ‘_log’ to capture the game state, or perhaps ‘_write’ to turn this into IF ;D. In any case, yet another example of severe over-engineering…

These methods are fairly straightforward…I did one weird thing where certain events could create ‘animations’, components that last for just one game loop and get added to the list of game objects to be drawn. That’s something I need to redo (I want to have multi-frame animations possible between each player turn). My current idea here is to make drawing a series of frames, where normally there’s just one frame as I have now in play_draw, but with the potential for adding frames to make the animations.

So that’s it. If I expand this I can see the component system getting really massive…on the other hand I don’t know that any game wouldn’t have a similar situation once you add a lot of stuff. I can derive children from component classes in some cases (for example with AI) so that might keep things more organized. I like the separation of input/views/logic. Right now the world state is woven into the game logic quite a bit, but I’m of mixed feelings of trying to make a hard separation between the two. In this application it may not be worth it.

Any comments or criticism is particularly welcome at this point, so feel free.

Bidden day #7

total time: 54 hours

Well it’s 10 AM, up all night, and it’s rather shocking given the time spent, but I didn’t finish. The still warm entrails are here:

http://sites.google.com/site/biddenrl

You’ll need Python 2.6 and Windows to play (I use the word play very loosely). Linux shouldn’t be that hard but I’m not sure if I have the correct DLLs in the zip — you’re welcome to check it out though to see (I did include some .so DLLs, so maybe that will work).

I got to the point where the player had a goal, but really no gameplay. I spent a lot of time messing around with programming and obscure code structures, where I should have ruthlessly simplified/hacked things to get the gameplay vision in place, since I had a very clear idea of where I wanted to go. On the other hand I’m definitely pleased to have spent so much focused time this week (more than twice what I’ve ever done for Pyweek or Ludum Dare). A lot of the time went to basic programming tasks, which will speed up with practice I think. In general I feel like I’ve crossed a hurdle of some kind in making stuff.

In any case, I’m still very into the Bidden idea, so I’ll continue working on it until it’s fully realized.

Bidden day #7 in progress

time so far: 44 hours

The RNG smiled on me this afternoon and I finished early at work, so got an extra few hours in this afternoon. About 12 hours left, and I’m still very far from a success I think. But the structure is almost completely there. Right now it’s 9 PM and:

* I have the house to myself
* I have a full can of tea
* soul on the radio
* nothing to do tomorrow

We’ll see what happens!

Bidden day #6

time so far: 38 hours

* the creature is corpse’d when you bump into it (decorpsed? corpsefied? ‘killed’ is a little strong given the state of the creature model at the moment).

* world creation occurs properly at game start.

* beginning of a goal.

* but I did spend 2/3 of the night on message passing and event filtering! I’m sure this will come in handy.

tomorrow:

* add more creatures

* add at least one character boon

* add everything else

Bidden day #5

time so far: 35 hours

For some reason I thought it was Thursday today. What luck!

Still avoiding gameplay by making intro and help screens. I’ve also been messing around too much with stuff like UI and game input structures. However tonight I’ve been getting more messy and loose, and progress is accelerating. The screens above are the basic outline of a single play through. All I have to do now is add everything else!

Bidden day #4

time so far: 30 hours

Yes it’s true…only three more days to go…still no goals, conflict, character advancement or content. But I made a lot of title screens!

Really I couldn’t resist. The above example is a kind of mash-up from messing around with ascii-paint, the wonderful tool by priomsrb. I did get some other things done — I’m on my way to a structure for a menu, state switching and so on. I have a feeling though that I’m avoiding some of the harder things by doing these things that are, really, not totally necessary to making a functional game. I think it’s OK in the end though, it’s kind of like a mid-term break, and it should add to the overall experience (assuming I have something playable to experience!).

Still with the goal of a playable run-through from start to finish — would like to get that done by tomorrow night. Then Friday is work all night to add things and release.

Bidden day #3

time so far: 26 hours

The mockup slowly wrenches its way toward a real game. Believe it or not, up to this point in my programming self-education I had never touched procedural map generation — always working with hardcoded maps while doing other things. Luckily libtcod makes all of this fairly painless. I can’t imagine doing all of this from the ground up as some entrants are doing!

The above is a simple binary-space partition, with the borders of the rooms walled in, and then tunnels dug from room to room (somewhat randomly). I’m quite relieved to have made this milestone actually, as I was worried it was going to be a major stumbling block. I think I’ll be able to produce a rougher ruin map, and a twisting labyrinth map, in similar fashion. Of course it’s an open question if I’ll have any content to fill those maps with!

Basic movement and collision is in of course, and along with that and the level generation a proper code structure for the map as well.

I spent a bit of time with generating a template for title creation — if you look in the header you’ll see a partial example of that. In the story of this world there are many groups and factions, forming in every which way, and I hope with the titles to add some of that flavor.

Wrangled more with the json saving and loading — found since everything is unicode in json I need to convert symbols to str before printing with libtcod. It’s turning into more of a cost than a benefit, but one of my goals with this project was to give json a go, and I’m certainly doing that!

My long weekend is over, and it’s back to the dayjob Tuesday-Friday. Hopefully I’ll have some extra free time during the day this week, otherwise I see some long evenings ahead. My goal now that I have the basic structures is to get a playable run from start to finish, even if this just means the bare minimum of content required.

Almost double the number of entries this year compared to last year by the way — incredible!

Bidden day #2

time so far: 16 hours

Not much more than another mockup, but I like this one better than having the big sidebar not really doing much. The descriptive style of the header in this one is a bit of an experiment.

Spent a lot of the day working on saving and loading, choosing json instead of the tried and true YAML. Went for a walk in the afternoon and realized that was probably going overboard. Do I even need save games? Probably not, though I want them. In any case it’s worked out now, so I’ll go with it.

Tightened up the design, eliminating the mountain and slum map generation parameters. Also realized I should have a power limiter of some kind for boons, so put in limited uses. As you complete tasks you get more uses; at the same time the chance of more dangerous enemies and traps increases. I don’t want this to be a difficulty scale per se, though — there still should be low power enemies you can just blow away later in the game.

addenda: I couldn’t resist a couple of more hours post-post. For some reason I’ve decided to try a publisher/subscriber for the first time with this game. I got the game components to register handlers with an event broadcaster, and now keypresses send an event to the broadcaster, which propagates them to the appropriate handlers.