2
\$\begingroup\$

I've been working in my free time on a vertical shooter similar to Xenon 2 Megablast. It's a tribute of sorts to the game that destroyed a considerable part of my childhood.

I've got the basic stuff in place - weapons, enemies, collision detection and a scrolling background. Now, I want to design the levels.

I want to create some kind of an engine which can render a level based on some kind of (say) textual description so that I can easily create levels. Are there any articles or links to how platformer/vertical shooter levels can be stored as files and loaded by the game engine? I'm not looking for completely solutions but ideas and starting points so that I can try to do it myself.

Specifically, how would you store the level of a platformer game like Prince of Persia or a shooter like Xenon 2?

\$\endgroup\$
3
  • 1
    \$\begingroup\$ I'm not sure what exactly you are looking for. Are you interested in the aesthetic design aspects, in the gameplay aspects (how to place objects for interesting gameplay), do you need help with the technical implementation (how to store and load the level design) or do you need a map editor? \$\endgroup\$
    – Philipp
    Commented Jun 11, 2013 at 7:29
  • \$\begingroup\$ Technical implementation. Thanks for your comment that clarifies all the aspects of this. \$\endgroup\$ Commented Jun 11, 2013 at 13:04
  • 1
    \$\begingroup\$ Tetrad - Nothing since I haven't a clue how to start. Like I've already mentioned in my question, I've got everything except the level background/design/engine working and I don't know where to start. \$\endgroup\$ Commented Jun 11, 2013 at 16:02

2 Answers 2

5
\$\begingroup\$

I don't know if you can find any valuable resources or articles about the topic, but I think that the idea of the textual description is good. Personally, I have some experience with vertical-scroller shmups, and I have always followed this approach.

Roughly speaking, you can have a series of text files (or other kind of file...); each file corresponds to a level of your game. Every row of a file contains the essential informations that you need for generating the enemies (or other objects, such as background elements - like planets, stars,...). These informations, obviously, vary accordingly with your specific game but, in general, they could be:

  • The spawn time: this is the time that you have to wait between a "row" and another. Basically, you control the frequency of spawning, with this "parameter";

  • The enemy type: this could be an index, or a string, that represents the specific enemy type. As an example, if you have 20 types of enemies in your game, this can be a numerical index, from 1 to 20, that represents the type of object to be instantiated: a particular function in your code will bind the index with the specific asset of the enemy. As I said, you could also use the string that represents the asset's name in your project: It will just be a unique identifier for the object to be instantiated.

  • The x and y coordinates that define the spawn point (y-coordinate could be avoided, and defined as a constant, if all the enemies come from the top of the screen).

So, your txt file can be structured in a similar fashion:

4.0 little_enemy_1 200 150
0.0 little enemy_1 240 150
0.0 little_enemy_1 280 150
3.5 mothership 140 170

In Unity (sorry, but I'm familiar with that...) these lines correspond to:

yield WaitForSeconds(4);
Instantiate (little_enemy_1, Vector3.Position(200, 150, 0), Quaternion.identity); 
Instantiate (little_enemy_1, Vector3.Position(240, 150, 0), Quaternion.identity); 
Instantiate (little_enemy_1, Vector3.Position(280, 150, 0), Quaternion.identity); 
yield WaitForSeconds(3.5);
Instantiate (mothership, Vector3.Position(140, 170, 0), Quaternion.identity); 

If you're not familiar with Unity, those lines say: "wait 4 seconds, generate 3 little enemies in a row, wait 3.5 seconds, and generate a mothership (all in the proper coordinates)". In my example I have not considered the particular rotation of the objects that have to be spawned, but, obviously, you can also add that.

I know that it was just a quick tip, but I hope that it could represent a good starting point for you, as you asked. Any feedback will be appreciated, of course.

\$\endgroup\$
0
\$\begingroup\$

Similar to @Goblin's answer here, I am using a random endless wave generator for my game, which is an HTML5 side-scrolling space shooter. The code below is plain Javascript. I am not posting the entire code here. Some functions are left out for your implementation. I just wanted to depict the logic.

var shipTypes = ['warbird','crosswing','raider','drone','tinydrone'];
var levelTimer = 0; // This variable increments by 1 per frame
var wave = {};
var screenHeight = canvas.innerHeight; // Dont bother about this step
function generateNextWave () {

    var numberOfShips = getRandomNumberBetween(1,5); // This function is to pick a integer between the two numbers (inclusive)
    wave = {};

    var len = shipTypes.length - 1,ships = [];
    for(i=0;i<numberOfShips;i++) {
      var pickAShipType = shipTypes[getRandomNumberBetween(0,len-1)];
      ships.push(createShip(pickAShipType)); // Assume I have a function to create a ship according to its type
    }
    wave[levelTimer + getRandomNumberBetween(100,200)] = ships;

}


function gameLoop() {

    .... 

    // check if there is a wave this time
    if(wave[levelTimer]) {

      // add the ships to the list of ships on screen
      addShipsToScreen(wave[levelTimer]);

      // now generate the next wave
      generateNextWave();

    }

   ....
   levelTimer+=1;

}

Every frame in our game loop we check for wave[levelTimer] to see if its empty. If its not we add all the ships in that wave to the game. Please let me know if you need more clarification.

\$\endgroup\$
12
  • \$\begingroup\$ wave[leveltimer] wouldn't that be a huge array for a long level? Why not have a leveltimer[step] that holds the timing information: you would then check if the framecount = leveltimer[currentstep].framenumber, and if so; increments the step by 1. \$\endgroup\$
    – Felsir
    Commented Jul 14, 2016 at 11:48
  • \$\begingroup\$ wave = {}; I am clearing the object each time I invoke generateNextWave () so that it will have only the next wave. \$\endgroup\$ Commented Jul 14, 2016 at 12:22
  • \$\begingroup\$ @Felsir, why overcomplicate things with your leveltimer approach? I have edited my answer above. Added the game loop. Please have a look. \$\endgroup\$ Commented Jul 14, 2016 at 12:23
  • \$\begingroup\$ The biggest difference is, I would only store the 'events' in the array instead of creating a large array. If a level should last a minute, your array would be of size 60 frames * 60 minutes, while it could be as small as just the number of enemies spawned. \$\endgroup\$
    – Felsir
    Commented Jul 14, 2016 at 17:21
  • \$\begingroup\$ @Felsir, you are still not understanding my code. Please have a look again. The wave object will have only one member at any time. The generate function empties the wave before generating a fresh list of ships. And for your information wave is not an array. It is a javascript object. \$\endgroup\$ Commented Jul 14, 2016 at 17:25

You must log in to answer this question.

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