|
Development thoughts
2002 08 17
I've gone through the not-so-easy task of documenting the engine! Doxygen
gave me a pile of html's; also I've drawn some UML (the rest is still
todo).
The engine seems to be nearly completed. There are some missing things, but
we could keep adding them for ages - there's always something missing :)
So, I'm marking it as "Release Candidate 1".
2002 08 13
Time to merge my (NeARAZ) and ReJ's code... We couldn't easily agree on
some things, so we tried all the combinations :) It's clear that his
entity renderer is better; but we're still in doubt about his vs. mine entity
system...
2002 08 12
Almost accidentaly I've written a game! It's an extended version of the "Rail
game", this time with peaceful and angry gods also :) See it in development
files.
The system of entities and user interaction is now the "indirect one"
(see somewhere below). It has proved to be faster and fairly comfortable
to use.
Shuffled the source files layout, the game classes, etc. Started writing
source comments, tried Doxygen - it works :)
2002 08 10
Game idea: Babel tower game (by Aiste). There are different
colored people running round on the map. Colors represent the language they
speak. You select rectangles (or circles, etc.) of them to combine them
into one. If among the selected ones are 70% (or 80%, 90%, etc.) of the
same color, then you succeed and they turn into a big "unit" (or man) of the
major color. If you fail, something bad happens. The task is to combine
some not-so-small amount of single colored people to finally build the
tower.
Two cases for interaction with entities:
- The traditional one. There's a world space partition into sectors
(simple case may be ok: fixed 2D grid). Each entity knows the sector it
belongs to, and each sector knows the entities it contains. This approach
is simple to understand and implement, and suites well for (nearly) all
kinds of problems (collision, proximity queries, selecting entities,
etc.).
- The indirect one. Again, there are sectors. The difference is:
the sectors know nothing about the entities, and the entities do not
track the sectors they belong to. The sectors are just containers for
some data that is used for entities interaction. Consider a case of
ray-entity intersection: each sector has a ray (or hasn't). At first we
write a ray into the sectors it crosses (and don't write into the other
ones). Then each entity computes the sector it is in, checks whether the
sector contains a ray, and if so, checks itself against collision with
ray.
The second approach is slightly harder to understand, and it moves all logic
into the entity. But is has some advantages: no need to track entities-sectors
relations. I've written a "Rail Game" using both approaches, and the second
one turned out to be faster (50k entities, AthlonXP 1500+, 256 MB DDR RAM,
GeForce2GTS: 46 vs. 50 FPS).
2002 08 08
ReJ was trying various ways (and hacks also :)) to speed up the rendering.
At first I did the rendering as such:
- Lock whole dynamic VB with DISCARD flag (size of VB is 16k vertices).
- Fill it with sprites.
- Unlock.
- Draw.
- Repeat until no sprites left.
ReJ optimized off some branches (no sprites left? whole VB filled?) and
"split" filling of VB into portions (fills smaller portions with NOOVERWRITE).
This is (AFAIK) the current scheme.
Also we noted a couple of interesting things: filling the VB, but leaving
some parts untouched (like texture coordinates in NOOVERWRITE portion) does not
speed up things at all. Knowing we're RAM limited, it's kind of strange. Maybe
it's some of AGP specifics?
CPUs and FPUs nowadays are too hard to understand. We have 5 vector3-scalar
multiplications in one sprite. Commenting out the first one speeds up
calculations by 50%. Commenting out the just the last 4 (leaving the first one)
speeds also by 50%. Commenting out one of the last 4 does not speed up things,
and occasionally slows them down. Also: inserting redundant code (that isn't
executed at all) sometimes speeds up things. "The pipelines and superscalar
things are roots of all evil" - the conclusion :)
I (NeARAZ) have coded up a "Rail Game". See it in development files. For that
game there's a division of playing space into sectors, each entity knows the
sector it belongs to, and sectors manage pointers to entities they contain.
With this structure, I'm able to find intersection of some ray and entities
(and also do collision, proximity queries, etc. etc. - not done yet).
2002 08 05
Dilemma: should we try to hide the engine from the programmer, or should we
expose it? Exposure is good for such a project, but we fear that the
programmers would dig into the engine instead of writing games :)
Just to check: physics for each entity can now hold it on the terrain all the
time, let it fly or let it fall with gravity. I've spotted no difference
in speed. So: we're pretty ok with branches in the code. We're not ok with
RAM :)
So, what I would do:
- There's common physics code for all entities, using bit flags in entity
structure for various physics parameters. Just like everyone did some
years ago.
- Each entity has a pointer to current "decider" (or null). Decider gets
called not too often (or: quite rarely). Deciders could be possibly shared
by entities; they would have interface like
virtual void decideFor(
SEntity& e ) const; The game does like this: creates a decider of
it's will, sets it for some needed entities, sets it's calling period, and
voila! The ability to report something can be left to the decider (like:
some entity reached the destination!). It's game's responsibility to
delete/destruct the decider (afterall, the game is the one who creates
them). So, generally the decider is the AI for an entity.
Game setup scenario:
- Create, say, 7 entities, set "bad guy" decider for them. Have pointers
to the entities (or deciders) in "bad guys" array. Bad guys run in
circles around the map, inflicting damage ("dropping" it onto the grid
beneath them). One can also implement collision detection & response
between bad guys...
- Create, say, 50k entities, set "good wandering guy" decider for them
(that randomizes the velocity every now & then, possibly turning away
from the bad guys; and accepts damage from the underlying grid).
- In result we get a game with many guys wandering around, and a few bad
guys running and killing good guys. Interesting game, isn't it?
A dilemma to resolve: should we have (stochastic) collision detection? Or
will the "underlying grid" system be enough? In the latter case: should the
sectors know which entities they contain now (and so for the entities)? The
knowledge introduces some overhead, on the other hand, it has it's own
advantages...
2002 08 04
Checked out IndieGameJam sourcecode. It was similar to what we would do -
pool of entities, single big texture, space subdivided into sectors, etc.
What we haven't thought of is the idea of game updates affecting only a
subset of entities (thus bypassing the main bottleneck - RAM throughput).
It seems to be a good solution.
On the other hand, I was a bit suprised. They use plain C nearly everywhere,
using "// don't modify this! " for encapsulation, callbacks and
other good old C stuff. While I don't generally agree with ReJ's code also -
it's OOP too much (relatively). What I think we can allow is: we're
pretty ok with C++, but don't really need the inheritance or polymorphism for
the game entities. Let's remember old times...
The vision I see now is:
- The entity is a fixed size data structure, with some space reserved for
game needs. Method update() handles a single guy (updates it's position,
checks terrain altitude, etc.) and should not be modified by game in most cases.
- Game logic is happening either in Entity::gameUpdate() for some of the
entities (equiv. of ai_timer in IndieGameJam), collision managers or
Game::internalUpdate().
- Collision is stochastic (only a subset of sectors gets evaluated each
update).
The whole design very resembles the original IndieGameJam... Well, not too much
of a surprise, anyway :)
Specially for ProNinja: maybe we'll have a collision detection! (as it was
said, stochastic only).
Code, code, code... The codind is not as fast as it used to be 2-3 years ago.
I think a lot more (what's the better way? how it will integrate into the
whole thing? etc.). Is it good or bad?
2002 08 03
With 100k entities you very quickly reach system RAM throughput limit. CPU
limit comes the next, and GPU the last. 100k sprites == 400k vertices, that's
"a breeze for GeForce" (needs to be read in female voice), as said in one old
nVidia demo movie.
But even the CPU limit is not so high: if we process every entity at 10Hz rate,
and let us "burn" something like 500MHz (leaving other for rendering, driver,
Windows, etc.) - that's 500 cloks per entity. Kind of low...
Something has to be done. Process entities in groups? Cache something (like
colidees, paths, etc.) by location? Or have 10k entities... or 5k...
older ones
Some game ideas:
- University game (by ReJ). There are "good" students (those
that pay for the studies) and "bad" - the ones that don't have to pay. The
task is to keep as much of the good ones as possible, or convert bad ones into
good ones. But you must also leave some bad ones (but the ones who have the
highest marks) untouched. Also the periodic floods (yearly) of students, the
army and more stuff can be introduced.
- Politics game (by Aiste). You are a politician, and can
promise some things to the people. First you must gather some audience to
promise to, and then select the thing. Some people that don't like the thing
die immediately, the ones around them run in panic, and the others stay as
your supporters. With network, it can be a fight between more politicians.
- Runnin' troops (by NeARAZ). You drag short strokes on a
terrain, and there appears a bunch of troops and start running in the direction
of a stroke. While running, it destroys everything in it's way, digs the terrain,
etc. One bunch destroys the enemy bunch if it runs into it's side. Errmm...
and something else.
- Mosquito game (the idea came out naturally, while camping).
Hordes of moquitos attack people, people defend by smoke, sprays,
pshychological attacks :) and so on.
|