adonthell-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Adonthell-devel] Flaws in the current map implementation


From: Kai Sterker
Subject: [Adonthell-devel] Flaws in the current map implementation
Date: Tue, 1 Apr 2008 17:20:02 +0900

Doing the collision work only got me a glimpse into the map
implementation as a whole. Since then, while working on saving/loading
maps, I have got a better idea how everything fits together and am
finding some flaws that should probably be corrected now.


First, of all here's a picture of the fundamental parts the map
consists of (objects and characters ... later we'll throw items into
the mix too):

  frames --> animations --> sprites \ / objects
                   |           |     X
                 shapes --> models  / \ characters
                                          /
                                    position /

Basically, an object consists of a sprite and a model. A character has
additional location (and velocity) information. That means, each
character instance has a distinct state. This is different for
objects, where one instance usually exists at different locations of
the map (and only the map knows about those locations). This is quite
efficient, but it also has severe restrictions:

All instances of a certain objects will have the same state, i.e. they
will display the same animation. That may be okay for most objects,
but there are some exceptions:

* Doors or chests that can be opened/closed, light sources that could
be lit/dimmed, etc. ... . All those need to be individual objects
whose state needs to be changed without affecting any other instance.

* In a similar manner, it will not be possible to use a sprite to
group multiple variations of essentially the same object. Say a
bookshelf with or without books or other items, a tree with or without
leaves, with snow on it or with the wind moving its twigs. (Whether we
want to use this sort of grouping remains a different issue)

I haven't yet found any good solution for this issue, though. I don't
want to lose the efficiency of the current implementation that works
well for the biggest part of stuff we'll have on the map. One thought
is to maybe implement those objects as items or to introduce a
different kind of map object. The general theme seems to be that those
objects can be interacted with (doors, push-buttons, ...), whereas the
current type of object is meant for static scenery only.



Then there is another issue. The original (and IMHO quite nice) idea
of Alex had been to divide objects into their graphical and internal
representation. Hence we have sprites and models, as can be seen
above. All the map needs to work are the models, so we have the chance
to load the whole game world and simulate what is going on without
using much memory (whether we can actually have a lot of NPC/creature
schedules running simultaneously is again a different matter, of
course). Then, for those areas visible in a map view, we also load the
graphics to actually display that area to the user. Great stuff, but I
am not so sure if the implementation is all that great. It uses
multiple inheritance, which can be a bit of a problem at times ... for
example I couldn't get the overloaded draw methods of
character_with_gfx/object_with_gfx to resolve correctly when only
having a placeable_gfx, so the rendering code needs some ugly kludges
right now:

  switch ((*it).obj->type ())
  {
    case world::CHARACTER:
      ((world::character_with_gfx *) (*it).obj)->draw (pos_x, pos_y,
&da, target);
      break;
    case world::OBJECT:
      ((world::object_with_gfx *) (*it).obj)->draw (pos_x, pos_y, &da, target);
      break;
  }

That's not OOP at all! And means more work once we add in items, for
example. Instead, the following should work:

  ((world::placeable_gfx *) (*it).obj)->draw (pos_x, pos_y, &da, target);


Also, the part where it all comes together (area::thing_manager) does
not easily mix objects with and without gfx and its not really
possible to load the gfx of an object once it becomes required by a
map view (or unload it again later).

So all that screams for a bit of a redesign. Maybe something subtle is
enough to get rid of these issues; I only recently started thinking
more about all this.

A first idea would be to have draw methods in all objects, not just
those with gfx. Those without gfx could just render wireframes of
their model (something that's right now implemented as a draw_border
method in objects with gfx.) That should help get rid of the switch
statement required so far.


There's not much of an idea about how to load/unload gfx at runtime
though. I only see a couple possible implementations I do not like
much :-).

* Only have one type of object, and just don't load the sprite unless
requested. But that means a lot of ifs and elses inside that object.
Not nice.

* Replace the pure object with its gfx counterpart (and vice versa).
But that requires copying (or reloading) of the model (and in case of
characters) location data. Not efficient.

This seems to indicate that it's no good idea to let the gfx object
inherit from the non-gfx object (as in the current implementation). A
proposal that comes to my mind would be to work with a delegate, where
a map object (a placeable) has a renderer component that does the
drawing. For objects without gfx, we could have a default, static
renderer that gets the model from the object and draws the wireframe.
No allocations/deallocations of that non-gfx renderer, and no
ifs/elses either. For objects with gfx, we could do the same and have
one class that gets the sprite from placeable, looks it up in the
animation cache and draws it. More efficient seems to be to have
individual instances that hold on to the sprite instead, though. Only
few allocations/deallocations vs. numerous cache lookups every frame.
The map view could handle setting the proper renderers as objects come
into or go out of view.

Another idea could be to have a default empty renderer, that only
waits for the first call to its draw method to instantiate the real
render which loads the sprite and draws it. The cleanup would still
have to be done by the mapview though (at least I can't think of
anything else right now). For special cases (debugging, map editor) we
could use special renderers that draw the wireframe or other helpful
indicators. (Basically, it has to be possible to specify the renderer
class that will get instantiated.)

This should get rid of most (if not all) the multiple inheritance and
seems a way to untangle the current mess between objects with and
without gfx.

Kai




reply via email to

[Prev in Thread] Current Thread [Next in Thread]