12
\$\begingroup\$

I am developing a 2D shmup (i.e. Aero Fighters) and I was wondering what are the various ways to store a level. Assuming that enemies are defined in their own xml file, how would you define when an enemy spawns in the level?

Would it be based on time? Updates? Distance?

Currently I do this based on "level time" (the amount of time the level is running - pausing doesn't update the time). Here is an example (the serialization was done by XNA):

<?xml version="1.0" encoding="utf-8"?>
<XnaContent xmlns:level="pekalicious.xanor.XanorContentShared.content.level">
  <Asset Type="level:Level">
    <Enemies>
      <Enemy>
        <EnemyType>data/enemies/smallenemy</EnemyType>
        <SpawnTime>PT0S</SpawnTime>
        <NumberOfSpawns>60</NumberOfSpawns>
        <SpawnOffset>PT0.2S</SpawnOffset>
      </Enemy>
      <Enemy>
        <EnemyType>data/enemies/secondenemy</EnemyType>
        <SpawnTime>PT0S</SpawnTime>
        <NumberOfSpawns>10</NumberOfSpawns>
        <SpawnOffset>PT0.5S</SpawnOffset>
      </Enemy>
      <Enemy>
        <EnemyType>data/enemies/secondenemy</EnemyType>
        <SpawnTime>PT20S</SpawnTime>
        <NumberOfSpawns>10</NumberOfSpawns>
        <SpawnOffset>PT0.5S</SpawnOffset>
      </Enemy>
      <Enemy>
        <EnemyType>data/enemies/boss1</EnemyType>
        <SpawnTime>PT30S</SpawnTime>
        <NumberOfSpawns>1</NumberOfSpawns>
        <SpawnOffset>PT0S</SpawnOffset>
      </Enemy>
    </Enemies>
  </Asset>
</XnaContent>

Each Enemy element is basically a wave of specific enemy types. The type is defined in EnemyType while SpawnTime is the "level time" this wave should appear. NumberOfSpawns and SpawnOffset is the number of enemies that will show up and the time it takes between each spawn respectively.

This could be a good idea or there could be better ones out there. I'm not sure. I would like to see some opinions and ideas.

I have two problems with this: spawning an enemy correctly and creating a level editor. The level editor thing is an entirely different problem (which I will probably post in the future :P).

As for spawning correctly, the problem lies in the fact that I have a variable update time and so I need to make sure I don't miss an enemy spawn because the spawn offset is too small, or because the update took a little more time. I kinda fixed it for the most part, but it seems to me that the problem is with how I store the level.

So, any ideas? Comments?

Thank you in advance.

\$\endgroup\$

3 Answers 3

4
\$\begingroup\$

One way to do this would be to base the spawn not on time but on horizontal distance traveled (assuming sidescrolling). You can store your enemy waves in a queue with a trigger distance; when your player's distance traveled is greater than the trigger distance of the object at the front of the queue, pop it from the queue and spawn it.

This solution would lend itself more to integration with a graphical level editor than a time-based solution. It'd make it much easier to match up specific points along your scrolling background with when the enemies spawn.

\$\endgroup\$
1
  • 4
    \$\begingroup\$ And as a bonus if you change the scrolling speed, either globally, or for a section of the level, it will keep later enemies in their correct spawn positions, because if it were time based, enemies would spawn at in correct spots. \$\endgroup\$ Commented Mar 3, 2011 at 20:14
2
\$\begingroup\$

I suggest you study the code of PowerManga as a reference. They have two kind of levels: side-scrolling (tyrian-like) levels where things are positioned at a specific distance from level start and other things are randomly generated, and "still" levels (à la galaga) where one wave is parsed only after the previous one has finished its pattern.

Wave patterns can of course efficiently be planned by successive bezier curves (wikipedia page has a neat animation to explain that).

If I can afford a final comment, I'd completely drop XML here in favour of something more expressive, easier to maintain and more useful in game programming such as a LUA script.

HTH.

\$\endgroup\$
2
  • \$\begingroup\$ I already use bezier curves to store enemy movements (which is also serialized in xml). I'm mainly using XML because both .NET and XNA have built-in support for serialization/deserialization. LUA script sounds good but it will require more work. However, I always planned on using it, so after I finish some basic engine, I'll definitely look into it. Finallt, rhe idea of spawning a wave after a previous one sounds interesting. \$\endgroup\$
    – pek
    Commented Mar 3, 2011 at 22:31
  • 2
    \$\begingroup\$ XML is fine, as long as it's generated by a tool, and not hand-edited. Whilst scripting languages may be useful for special-cases (e.g. bosses), that's a completely separate problem to defining standard attack patterns, isn't it? \$\endgroup\$
    – bluescrn
    Commented Mar 3, 2011 at 22:44
0
\$\begingroup\$

Consider procedurally generating enemies. I know it's quite different from the answer you want, and it indirectly solves the problem completely.

If I were to do this, I would assign each enemy unit a "points" value of how difficult it is, then assign levels some number of points -- 100 points are worth a hundred 1 point enemies, or one 100-point enemy, or anything in-between.

You would probably need to constrain this a bit so that you don't get a 100-point boss on the first level, or that you have some minimum number of enemies, and you probably want to periodically poll the list of enemies left and pull the next one on-screen.

You could take it a step further by having formations: collections of positions and points, eg. seven one-point enemies in a single line (row or column), or a five-point flanked by two 3-points.

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .