3 months and a few refactorings later, V is nicely moving along.
Pieces and models are beginning to fit together and I am adding new
functionality all the time. I am headed toward a goal of a simple
alpha release with user sign-up, avatar creation, movement, fighting
wandering monsters, level advancement, and items. I so far have the
movement, fighting, and levelling programmed on the back-end. Let's
see how I got there and how I set up the infrastructure.
Unlike previous V implementations, I developed django-V from the
bottom up. I started by designing the models. I started with the same
map models that I have been using all along. One class for each map
type, a class for the map region, and a class for each map cell that
holds the type for its x,y location. I even had old SQL import
statements so that I could define a starting map to work with. This
was a good introduction to django models since I was making something
I was familiar with in a language and framework that I was not
familiar with.
Next, I designed and implemented the main class structure: Mappable.
Mappable is the superclass for all models that can appear on the map,
including Avatars (the player's character), Monsters, NPCs, Items, and
Buildings. It encapsulates location storage, placement and movement
methods, and the Abilities system (more on that later). Making the
model was easy, but extending it was harder. When I started, I had to
do some hacking to make inheritence work in django. The fields and
models were inherited correctly, but the objects Manager did not work
correctly, so every subclass had to specify it explicitly. Recently, I
upgraded to latest development release, and the single-table
inheritence fixed all of the necessary hacks.
There are two branches off of Mappable, Thing and GameCharacter. Thing
splits into SmallThing (anything an Avatar can hold, like items and
equipment) and BigThing (cannot be held, but still placed on the map,
like buildings and signs and fountains). GameCharacter includes all
living beings. It first splits into NPCs (can't fight) and Fighter.
Fighter then splits into Avatar and Monster. While this may seem like
a complicated inheritence structure, it reduces A LOT of coding (don't
have to specify xLocation and yLocation for everything) and makes it
easy to add new types.
The Mappable structure also aids in coding the interface. The
interface works by getting a list of all of the Mappable objects in
the same location as the player's Avatar. The template then lists
through these objects and displays them. The display interface is all
the same (a 'name' property), so if I create a new Mappable model, I
do not have to rewrite any view or template code in order to display
it. The only problem is actions.
An Avatar can attack a Monster, but can only talk to an NPC and pick
up an Item. I needed a standardized way to represent the abilities
that could be performed on a Mappable. I also needed a way to specify
which actions an Avatar could perform, which could change depending on
the Avatar's type (only magic users can Cast Spell), level (so that
you gain abilities as you level up), and equipment. The goal was to
easily create a list of abilities for each Mappable object that is an
intersection of the actions that can be performed on the Mappble, and
the abilities that the Avatar can currently perform. And so, I created
the Ability system.
The Ability system both standardizes abilities and the methods that
perform them. Abilities are definied by a standardized name. Each
Mappable subclass defines a list of Abilities which can be performed
on the object. This also includes superclasses (any subclass of
Fighter automatically can have Attack performed on it). Also, a method
in the Avatar class retrieves all Abilities which the Avatar can
currently perform. The execution of the Ability is standardized as
well. There is a standard naming convention for Ability methods that
depend on whether the Mappable is either performing the Ability or is
the target of the Ability and when the method is executing. The
interface calls a single method which dynamically builds the method
names and calls them indirectly. This way, a Mappable can define a
brand new Ability and implement it without changing code in any other
model.
I liked my Mappable and Ability structure, but I wasn't sure if it
would work. I next moved out of the back-end, and began doing some
interface programming. I built the map template and started loading
data from the database. For AJAX-y stuff, I included the JQuery
javascript library.
When the user clicks a new location, in the
background JQuery requests a url based on the direction the Avatar is
moving, a view in django handles the movement and loads the new map
template, then sends the HTML back to JQuery which it loads into a
<div>. The list of Mappables, and their list of Abilities, is included
in the template. When the user clicks on a Mappable, the Abilities
appear below it, and when a user clicks on an Abilitiy, JQuery sends
the data in a background POST request. Django performs the Ability,
and sends back the new map HTML. Ahh... progress.
Relieved that my system worked, and that I hadn't just wasted several
weeks of my life on this thing(again), I moved back to the models
where I didn't have to worry about things like layout and colors. My
first Ability implemented was Message. This allows Avatars to send
messages to one another, and allows the system to send messages to the
Avatar. To test, I wrote unit test cases and eventually got fixtures
to work. After that, I moved on to Attack. I decided on fighting
statistics (perhaps more on that in another post) and programmed the
initial fighting system. It's a simple system with a simple formula
that may need to be tweeked, but it works for now. Finally, if you can
kill monsters and gain xp, you need to be able to level up, so that it
is what I am working on right now.
On the side (which would make it a side-project to a side-project) I
am also writing a project management system to control what tasks need
to be accomplished. With this project I am learning a lot about the
django admin interface which I plan to use heavily in the future (way
more on that in a way later post).
Up next is to finish the levelling system, including stat progression,
and unit test it. Then it's on to items (which I finally have figured
out how I'm going to do) and Avatar creation.
Thursday, May 29, 2008
Subscribe to:
Post Comments (Atom)
No comments:
Post a Comment