Yet, is this approach really necessary for coffee-break roguelikes?
Generally, they stick to the KISS principle, so they're less
vulnerable to the pitfalls of an overly ambitious top-down design.
There's also the danger of a preconceived design that ends up being
less than fun when implemented, but you could just stick to what works
in other roguelikes, in stead of introducing wild ideas that need
playtesting.
In fact, this would seem like a fun way to design a roguelike: you
play lots of different roguelikes, write down what you like, and then
go sit at the drawing board, and think about how to piece everything
together. After a few months, you can start programming with a
purpose, in stead of just toying around with the technology, until
you're satisfied with the result.
I think the working skeleton should be based on the
actual game design so you could minimize the work
required. Adding "meat" becomes harder dedending on
the complexity of the game and how good (=generic) the
engine is.
When I look at the source code of roguelike projects
I can see they are not engine-based but "a working
skeleton" which is then extended and becomes really
hard to maintain. In the case of 7DRL you probably
don't need an engine, but anything more complex than
that and you wish you had made an engine that allows
quick and clean adding of new content.
But then writing an engine seems to be really hard
and time consuming process, so I guess that's why most
people don't want to go that way.
I think after you make a couple of games (especially if you try to
keep the source code clean) you kind of end up with a de-facto engine
- you start a new game and take useful chunks of your old code (in my
case it also involved translating my old c code to java, but it's
basically still the same code) whenever you need something you've
already done in the past.
Before you know it you have a code repository that you can cobble-up a
new game from quite easily.
The genericness of that code emerges after you've rewritten the same
algorithm for 3 different games - because you start separating the
bits that are game dependent so that you don't have to do a ton of
copy-pasting.
The important thing is to not be lazy and actively search for these
generalizable parts of the code and refactor them to their optimal
shape.
-Ido.
This is true if you always make only 7DRL roguelikes,
but in my opinion skeletons like that fail in large
scale roguelikes or they become really big (this is
the case with all major roguelikes except ADOM, because
we haven't seen the source code, but I would guess it's
also very messy). So, having a skeleton from previous
game doesn't mean you have a good game engine.
> So, having a skeleton from previous
> game doesn't mean you have a good game engine.
But would you say you need to code the engine before even designing
the game? If so, doesn't the engine already tilt the design in a
certain direction?
Maybe- I have never made a really big game before.
But it seems to me that a big game is just a small game with a ton
more features in it rather than something that is qualitatively
different.
If you are being a lazy coder and aren't constantly refactoring your
code and looking for things that can be done better than you'll end up
with a mess anyway.
-Ido.
Isn't one of the main ideas behind coffeebreaks to try something wild
and different though? If you're just making a mini-Nethack... well,
why not just play Nethack? And even a mini-Nethack would require huge
changes (easier interface for a start - you shouldn't take longer
learning the key commands than it takes to play the game). I think
coffeebreaks need to have a very different style of gameplay than
traditional large roguelikes, and they're an excellent way of testing
out something revolutionary.
> In fact, this would seem like a fun way to design a roguelike: you
> play lots of different roguelikes, write down what you like, and then
> go sit at the drawing board, and think about how to piece everything
> together. After a few months, you can start programming with a
> purpose, in stead of just toying around with the technology, until
> you're satisfied with the result.
Months? Geez... The very simplicity of coffeebreaks means that you
should be able to churn something out quickly enough. Getting out a
very basic version of your game gets you some quick feedback, and this
is vital for motivation, good ideas and testing. Personally I'd
suggest it's *more* important for coffeebreaks to start from a
skeleton and add meat, mostly because that meat section is much
shorter than for large projects. A large project may depend on the
meatier elements to give the game its true enjoyment, and so a
skeleton release may not do it justice. A small project should be fun
from the very basic skeleton release, and if you don't test straight
away if your idea is fun or not then you could be wasting a lot of
time on erroneous design.
Another factor is that time constraints may mean you spend months
doing the design and then find no time to code. I got Gruesome out
the door at a very early stage, and have unfortunately had no time to
work on it since. But in the past couple of months I have had a lot
of good suggestions and encouragement, so when I do get some free time
(hopefully around Easter) I'll be able to work on it much more
effectively.
I'm generally wary of any idea of designing things long before ever
testing those designs. They may be good ideas, or may result in good
ideas, but they could just as well be useless. Any attempt to build
upon untested foundations will usually end in disaster, and it'll take
longer in the end to correct all the faulty design. Of course for
more experienced programmers with multiple projects completed this may
not be such a difficulty.
--
Darren Grey
On one hand (top-down first), you avoid some potentially crippling
mistakes (as I have done myself) where you have to rewrite massive
chunks of code for an idea you didn't plan on from the beginning, or
an idea you didn't truly think out completely. There's a lot to be
said for avoiding a costly mistake with pre-emptive planning. It also
tends to give you direction, and focus your efforts.
On the other hand (bottom-up), you tend to code an engine a little
more flexibly, (hopefully) anticipating possible features before they
have truly been finalized in your mind. You may find that an idea
doesn't work, is not feasible or easily coded or is simply not
fun..and you haven't wasted anything in doing so. Bottom-up gives you
a nice base where you can easily adjust your plan due to issues you
had no way of foreseeing. That being said, you may spend too much time
making compromises in the pursuit of generality and reusability, when
you really should just hard code the damn thing and move on.
At the end of the day, probably 95% of the code you see out there is a
compromise anyways. I dunno...maybe there are some really great
programmers who conceptualize the end-product from the beginning and
it's fairly smooth from start to finish. My limited experience has
seemed to indicate that you need to have some idea of what you want,
but try to generalize at least a little. Otherwise, you code yourself
into a corner.
I'm curious to see how people respond, and it would make an
interesting mini-study at least. Anyone care to post how they
programmed their rogue, and what that rogue is?? Maybe we could see a
trend in their designs that shows the advantages and disadvantages of
each approach.
> Months? Geez... The very simplicity of coffeebreaks means that you
> should be able to churn something out quickly enough. Getting out a
> very basic version of your game gets you some quick feedback, and this
> is vital for motivation, good ideas and testing. Personally I'd
> suggest it's *more* important for coffeebreaks to start from a
> skeleton and add meat, mostly because that meat section is much
> shorter than for large projects. A large project may depend on the
> meatier elements to give the game its true enjoyment, and so a
> skeleton release may not do it justice. A small project should be fun
> from the very basic skeleton release, and if you don't test straight
> away if your idea is fun or not then you could be wasting a lot of
> time on erroneous design.
The point of a coffee-break roguelike is that it should be playable in
short spurts, and complete games should not be very long or require you
to remember much between plays.
All this is utterly orthogonal to any coding considerations.
You seem to have some notion that 'coffee-break' refers to the
programmer's time. It doesn't. It refers to the player's.
- Gerry Quinn
--
Lair of the Demon Ape (a coffee-break roguelike)
<http://indigo.ie/~gerryq/lair/lair.htm>
> [...] I think
> coffeebreaks need to have a very different style of gameplay than
> traditional large roguelikes, and they're an excellent way of testing
> out something revolutionary.
I think 7DRL's are best suited to implement experimental features,
because the time restraints force you to stick to a proof of concept
anyway. Coffee-break roguelikes are just roguelikes that can be played
during your coffee break - obvious, I know, but that's what it comes
down to. In fact, I think that in retrospect, the original Rogue could
be called a coffee-break roguelike. Of course, Rogue was pretty
revolutionary, but that's not the point. ;-)
Also, non-revolutionary roguelikes need not be mini-Nethacks. You can
create a roguelike just by recombining tried and tested features from
other roguelikes, and yet end up with something that exceeds the sum
of its parts - i.e. something more than just a Nethack clone.
Arguably, POWDER is an example of a roguelike that does not introduce
anything revolutionary, but is still a valuable addition to the
roguelike scene.
> The very simplicity of coffeebreaks means that you
> should be able to churn something out quickly enough. Getting out a
> very basic version of your game gets you some quick feedback, and this
> is vital for motivation, good ideas and testing.
So I should quickly slap together a roguelike that is a dime in a
dozen, and then let other people's ideas guide my further design?
Well, that is an extreme version of a community-driven endeavor. :-)
> I'm generally wary of any idea of designing things long before ever
> testing those designs. They may be good ideas, or may result in good
> ideas, but they could just as well be useless.
The flipside of this is that you need ideas before they can be tested,
and coming up with good ideas takes time. Of course, they need to be
implemented at some point, but as long as you follow the KISS
principle, you should not be deterred for too long if you decide to
think things through in advance. Well, that's what I would expect. But
since this is my first project, so I'll have to trust you guys, I
guess. :-P
<snip>
> I'm curious to see how people respond, and it would make an
> interesting mini-study at least. Anyone care to post how they
> programmed their rogue, and what that rogue is??
I think most people's answers to this would be, in the first instance,
"badly"
;-)
> Maybe we could see a
> trend in their designs that shows the advantages and disadvantages of
> each approach.
The original Kharne was bottom-up. It never got finished because it
was all bottom up. The rewrite is significally more top-down, although
I fear bottom-up coding is starting to interfere.
Best,
P.
> The flipside of this is that you need ideas before they can be tested,
> and coming up with good ideas takes time. Of course, they need to be
> implemented at some point, but as long as you follow the KISS
> principle, you should not be deterred for too long if you decide to
> think things through in advance. Well, that's what I would expect. But
> since this is my first project, so I'll have to trust you guys, I
> guess. :-P
Eh, well don't take any single person's opinions as anything more than
what they are. Lots of people code differently, and different
projects require different approaches. There's no one right answer to
top-down vs bottom-up, and as Brigand said the best approach is often
a compromise of the two. Personally I like to use a general rule of
thumb of not having more lines of design than I have lines of code,
except for scrap notes at the start (and obviously ideas in the
head). I also think it's best to have things in a playable state from
an early stage and to always keep it in a playable state, even if
you're not releasing it. For your first project I'd say planning too
much ahead is definitely a bad idea, since you're bound to make lots
of mistakes and the important thing is to learn from them before start
making big plans.
--
Darren Grey
Right now, I'm focusing a bit more on bottom-up design. The second
incarnation of UR is little more than a bare engine (in fact, Umbra
Engine is an almost complete UR source code - I just stripped it from
the sound, the title screen and some images). I have ideas I'd love to
put in the code, sure, but they change and evolve constantly. I'll let
them ripen. In the meantime, I find it easier to develop the framework
that will later hold all these great features I have in mind.
Mingos
> Personally I like to use a general rule of
> thumb of not having more lines of design than I have lines of code [...]
Well, I only have "@ walking around in the dungeon, bumping into
walls" at the moment. :-)
http://img165.imageshack.us/img165/7809/atmoving.png
This is around 75-100 lines of code in Python + PyGame. I guess that
would do for my first design draft.
The danger is trying to code all your monumental features (top down?)
from be beginning. Adding multiple features without debugging each one
thoroughly means generating faults will virtually always require
figuring out which block of code, out of many, actually generated it.
If you are trying to, say, write an engine that supports hundreds of
features, but none of them have been tested, you are up a debugging
shit creek when you start using that code. Most of those features will
be broken, and multiple components may be contributing to a single
fault--a debugging nightmare.
Instead, you really want to create a bare-bones frame and
incrementally add features (bottom up?) and try to test them out very
carefully before you add new ones. You really want your game to be
playable at the end of every small feature. The top-down effort can
still be very valuable in determining how you add features and how you
structure your code--it is definitely not wasted effort. But you will
find that your expectations will often change as you develop new
ideas, realize certain components will be harder than you think, and
just as time passes.
Hmm. If I understand correctly, I can have a lengthy design document,
as long as I only implement byte-sized portions of it before
playtesting?
Yeah. And possibly the expectation that you will change your mind on
half of that document before you get done with it ;)
If I understand correctly, you can write lengthy design documents
using the top-down approach, but when you get to coding, you'll have
to start from the most basic things and test them step by step
anyway :D
I think the core of the problem is that top-down is the end user's
perspective, while bottom-up is the developer's perspective. When you
see a car, you're rarely interested in all the technical details, what
you value most is its looks, comfort, economy and reliability, perhaps
also the brand. This is top-down. But the assembly line can't use the
same perspective: first create the "looks, comfort, economy and
reliability", since they all depend on the little pieces you add one
by one to build the car. Same applies for roguelikes or any other
game. Nothing stops you from having your "lengthy design documents",
but if you focus them on the "top" specifications (feature X,
possibility to do Y, spell Z...) without taking in account the
"bottom" ones (keyboard input, display, world storage... every little
piece that's part of the engine), you probably won't manage to
implement any of it anyway.
Mingos
I am not sure agree. (Of course, I may be biased by being a non-coding
designer.) Many specific details should be left for later, but some
fundamental design decisions should be settled before doing (much) coding.
For example:
* Do you want line of sight? If so, which metric? (Brent Ross once
experimented with the max(|p.x-q.x|,|p.y-q.y|) metric, which leads to
square sight area, for reasons I do understand by now.)
* Do want healing by waiting, or in any other form?
* I think it helps to spend some time thinking on the interface before
implementing, say, any spellcasting.
But I definitely second that there is no point in writing documents about
spells and branches and monsters before having a game. It is just that if
you do "write generic small roguelike" as the first step, you may have
inadvertently accepted a bunch of staples.
David
> A top-down effort is fine for design, I think, but its not good for
> development.
I dunno. I think I'm in the "make one to throw away" camp here.
The first effort should be top-down, because if you're paying
attention, that will teach you what and where some of the problems
are. There's nothing like standing outside a locked door to help
you remember that your keys are still on your dresser, and there's
nothing like trying to code a new feature into the middle of naive
movement code to make you realize you've left yourself no way to,
eg, reschedule an actor's future turn or interrupt its current
action. If you have a feature in your plan that requires that
capability, then you have identified a scheduling requirement
that you didn't fully realize before you started.
But once you have a good idea of the problems and requirements?
You go back and either build a better design from the outset, or
do bottom-up refactoring. If you've modularized well, you can
usually refactor. If you haven't, or if you just like the old-
fashioned hardcore "start over from scratch" approach because you
have decided to use a different language or just find it more
satisfying to be hardcore, then you can at least start over
from scratch with better knowledge about the problem space.
> The danger is trying to code all your monumental features (top down?)
> from be beginning. Adding multiple features without debugging each one
> thoroughly means generating faults will virtually always require
> figuring out which block of code, out of many, actually generated it.
Aside from trying to code features at least once for your own
edification so you know what facilities you need, it's a far, far
better thing to make an abstracted simple core with a highly
generic interface for other code to use. That other code - the
actual features of your game - doesn't have to be written and
part of the core, but you should definitely know exactly how it
will interact with the core. When you refactor the core you will
probably need to write all of your "features" over again anyway.
For example, your core engine may take "actions" off a schedule and
execute them (which will alter the state of the game and sometimes
put more actions into the schedule) for as long as the game lasts,
then clean up. The actual code of the "actions" is part of your game,
but apart from a few very generic universal actions doesn't need to
be part of the core. Having written the core you know how an
"action" interacts with the rest of the code you should be able to
implement the features of your game by defining an appropriate set
of "actions." The core provides a set of interfaces to things like
the map, the monsters, the magic items, and the scheduler that
"actions" can use. You may need to expand these interfaces later,
but you should be able to do so in a way that doesn't invalidate
existing content. The code of the actions themselves is game
content, not core.
> If you are trying to, say, write an engine that supports hundreds of
> features, but none of them have been tested, you are up a debugging
> shit creek when you start using that code. Most of those features will
> be broken, and multiple components may be contributing to a single
> fault--a debugging nightmare.
Yeah. The features you write in a topdown style will go away when
you start to refactor bottom-up. You need to separate them from
your infrastructure code and add them back one at a time, rewritten
to be compatible with new infrastructure. Write the engine to be
an engine that other code has well-defined ways of interacting with,
then write/debug the other code (or "content").
Bear
Yeah, I'd mostly agree with this. No better way to learn that to screw
up :)
It does take a certain amount of emotional fortitude to get through
it, though. The rewards are better when you do it feature-by-feature.
But I do think, in practice, you will probably have to redo your code
completely at some point as your design mistakes start to accumulate.
At least... I've never been able to avoid it!
I think the other bit was about at least programming the interfaces to
your features, even if you don't add the features until later. Also a
great idea if you can keep on top of everything you will need from the
start. Although I think its a good bit easier during a recode than
during the initial design. Yea?
Of course not. In fact you should create the engine specific
to the game design, because how would you otherwise know what
features are needed? I think game design is much more important
(like anything else) in large scale roguelikes. The comments I
read tell me that people are only talking about small scale
projects and in those it doesn't really matter that much what
kind of approach you are using to create the game.
One important thing to remember is that the design itself can
be too complex to implement (at least for beginners) and can
make some people think that design first is a bad thing.
It's obvious that you need to know what you are planning to do.
If you don't know then you could as well try to code that @
walking on screen and continue slowly from there.
I'm in the apparent minority who is with you on this. Well, mostly. "A
few months" seems like an awfully long time to spend planning a
roguelike, but "a few days" seems pretty reasonable to me.
I have a roguelike under development that is at the moment completely
playable and pretty fun to play. I'm told one of my friends basically
plays it all day at work, for whatever that's worth. It's got a pretty
cool feature-set too, I think... colored dynamic light sources, good
algorithms for monster scent-following, attacking, wandering and
intelligently fleeing (i.e. not straight into the nearest corner),
some interesting items and varied monster types, and a level
generation algorithm I'm really proud of -- no long and twisty
passages, completely passable levels, subterranean lakes of water and
lava, chasms, surface features like funguses, piles of bones and
different kinds of splattered blood from combat, etc. It's certainly
no Nethack in terms of complexity, but it is starting to look like
what I envisioned, and I'm very happy with it so far. It's also the
first roguelike I've ever built, and I built it absolutely from
scratch (though with the benefit of having examined the Rogue source
code in years past, and reading on RogueBasin how various algorithms
worked in qualitative terms -- no copy/pasting).
My method was to work on features I was interested in working on for
as long as I was interested in working on them. Coding this thing
isn't a job; it's for my own enjoyment, and I want the process to be
enjoyable. So I spent literally two to three months just playing with
level generation, before I even implemented any items, creatures or
the player. You'd start the program up, it would generate a level, and
then it would quit. I would admire the level, generate five or ten
more, and then decide what I wanted to do differently and spend a few
hours doing it.
I spent a couple of hours implementing the player, movement, and a
single monster type with a single behavior (run straight at the player
until one is dead), and then spent another week or so playing with
colored lighting. Torches on the walls, glowing fungus and lava, and
an implicit "miner's light" that the player carries with him, which
gradually decreases in radius as he gets deeper into the dungeon. Each
gets dimmer toward the edge of its radius and can have flickering
color and radius. For a square to be visible, it must be both in the
line of sight and lit.
Anyway, I'm starting to ramble, but my point is that I spent tons of
time implementing features I enjoyed implementing and ignored features
I didn't feel like dealing with at the moment. At one point, I had a
game with gorgeous levels and beautiful dynamic lighting but no items
and only a single kind of monster. But at that point, the motivation
materialized to implement those since it is pleasurable to watch your
new features interact with a world that you're proud of.
So yeah. I say plan out the stuff that's exciting for as long as you
like, and then dive into the coding. Don't treat it like a job, and
only work on a feature when you want to work on that feature. I'm
happy with the results I've gotten from that method.
Is that really top-down? The way I see it, deciding on whether or not
to use Chebyshev distances for FOV (or any other type, for that
matter) is something you have to do prior to coding, thus part of the
bottom-up approach (although it's clearly visible from the top-down
perspective as well in this particular case). Plus, in this case, it
is strongly linked to the game mechanics itself. Chebyshev distances
assume that diagonal movement is possible and its walking cost is the
same as in case of orthogonal movement. Manhattan is diamond-shaped.
If you decide to use it, it's not just because it looks cool or
uncool, but simply because it assumes diagonal movement is disallowed.
A fine example of this logic might be Slash's 1kBRL LUCK!, which
disallows diagonal movement and thus uses Manhattan distances to
calculate FOV; I doubt Slash's primary idea was to use Manhattan
distances from the beginning, but rather a logical step after deciding
against allowing diagonal movement. The anti-example would be ADoM. It
uses Chebyshev distances for movement, but not for FOV (for the
curious: it uses a sum of Chebyshev and Manhattan shifted right by one
bit, resulting in an octagonal FOV: [max(|p.x-q.x|,|p.y-q.y|)+|p.x-q.x|
+|p.y-q.y|]>>1), resulting in the ability to see further (game-wise)
in orthogonal directions than in diagonal. This is a top-down
decision. Thomas Biskup valued more the visual aspect than the
underlying mechanics.
Ultimately, we might agree that pure top-down or bottom-up approach is
quite impossible and you'll be forced to mix the two at some step. For
instance, if you plan to use a specific feature, you'll be likely to
direct your coding towards the possibility of implementing it later,
thus we can't affirm that the top-down approach has no influence on
coding. Still, the end user won't be aware of how you resolve a
specific pointer issue or how you decide to structure your map. He'll
just see the final appearance of the game, which is a purely top-
bottom approach (or rather just "top", hehe).
> * Do want healing by waiting, or in any other form?
> * I think it helps to spend some time thinking on the interface before
> implementing, say, any spellcasting.
Technically, you're right. You have to know what you want to implement
before actually implementing it. The problem is, the top-down approach
tends to desribe the exterior appearance, while bottom-up is rather
about the underlying mechanics. Your examples appear to be somewhere
in between :).
Look at these examples (I think they're right):
A1 (top-down): I want a "lightning bolt" spell. It should be a yellow
straight line from the PC to the target, dealing X damage to an
opponent.
A2 (bottom-up): The "lightning bolt" spell will use a visual effect
based on Bresenham algo, drawing a straight line from the caster to
the target. Each map cell, although containing a character, will have
to be forced to display a yellow asterisk. After the visual effect is
over, the bolt's trajectory is redrawn again, using previous
characters and colours. The effect will be draining X mana points from
the caster and Y health points from the target. How long will the
visual effect last? How do I display it without putting too much
burden on the CPU? What will be taken into account when calculating
the damage (metal objects worn/wielded by the target, resistances, and
so on).
B1 (top-down): I want the caves to be blob-like, with "tentacles"
spreading from the centre of the map outwards, with no large open
spaces to improve gameplay.
B2 (bottom-up): I should use cellular automata/Perlin noise/CA erosion/
fractional Brownian motion+Dijkstra/whatever to create such a cavern.
How do I come up with the necessary calculations? What's the correct
threshold to use when determining wall/floor placement based on, say,
noise values? Experiments and trial and error will be necessary to
achieve a visually appealing and proper gameplay guaranteeing map.
We may argue endlessly here and try to prove that one or the other
approach should have more weight when making a game than the other,
but in the end, everything needs to be programmed, right? Programming
is the most bottom-up part of the process. In other words, an
architect may design a house, but the builders won't be able to start
the construction from the roof anyway. The thing is knowing what is
our project's roadmap and don't design in advance elements that will
need to be coded last. Ideas are prone to evolve. The code at the very
core of the game isn't that flexible and is getting even less so as
the project gets more complex.
Note that I'm not trying to prove that the top-bottom approach is bad.
It's not and in many cases it helps or even is plainly necessary. I
also have many ideas written down, heck, I even have an entire
background story and some intro narration recordings made in a
professional recording studio! But these are simply waiting for their
turn to be implemented. My point is that one should limit the top-down
approach to a sensible minimum, focusing rather on making the game
work and putting more effort in the challenges that need to be tackled
immediately instead.
Mingos
> I think the other bit was about at least programming the interfaces to
> your features, even if you don't add the features until later. Also a
> great idea if you can keep on top of everything you will need from the
> start. Although I think its a good bit easier during a recode than
> during the initial design. Yea?
Yah. Not the *user* interface for the features, but the *APIs*
that will be available for your use when you start writing
features.
In OO terms, the core can be just an "engine" that calls generic
functions on "actions." Some of these generic functions will
always be inherited from the base "action" class (like how to
schedule, unschedule, reschedule, store pending actions, etc)
and those are legitimately part of your engine. The function
that's game content is the "DO_ME" method, and that will vary
from one action to the next. Those, you fill in as you write
content or "add features" to the game.
To make your life easier in writing those methods, you'll need
to define a bunch of API's for the other objects in the game;
the Map, the Schedule, the Actors, etc. and know how those fit
together. The individual "DO_ME" methods will call those API's
to do most of their actual work.
Bear