Wednesday 25 July 2012

Diabolical Editor

I noticed the other day that I had not mentioned much about the level editor that I use for Diabolical: The Shooter.  I've spent a lot of time adding features to it so I thought it worth describing.

The editor is used for shaping and colouring the terrain and for positioning the static models on to the map.  With hindsight I should have created a completely separate application but my original design was to be able to quickly play test any level I created so the Editor uses much of the same code as the game and is run from the game's main menu.

That works but there has been a lot of struggling to keep the game code tidy whilst also adding in the Editor methods.  This has resulted in a lot compiler directives of the type '#if EDITOR'.

To be able to use Windows menus I have had to do some messing about.  The WinForm menus are not fully supported in the XNA game loop.  I have an open source test project that shows how I have managed to get the menus to work with some limitations:

The top level menus and the drop downs have to be coded by hand but they can launch forms created with the Visual Studio GUI.  The menus work fine for the Editor used only by me but I would never use the WinForm menus in an XNA game.

Over time I have added stacks of features, too many to list but just a few are: texture terrain with up to four layers, adjust the height of the terrain with various helpers such as flatten, noise, slope etc.  use a round cursor, a rectangular cursor, add structures, waypoints, triggers, static particle and sound effects and so on...

The whole terrain is based on a height map using a regular grid.  This makes finding heights relatively quick.  The grid only has one value, the height at each corner.  The limitation of this is that it cannot do vertical faces only slopes.  For the vertical cliff faces seen in some of these screen shots I have created 3D models.

To position the cursor I project a line from the view and calculate where it intersects the terrain.  At first the cursor always followed the view but I found this difficult to see what I was doing so now the cursor stays still unless I hold down the Ctrl key.

I am not sure if my method for finding the point on the terrain to position the cursor is efficient but it is fine for this editor.  I step along the line projected from the view, testing the height at each point.  The step being just under one grid width to ensure every grid is tested.  As soon as the end point of the line goes underground I know that somewhere between the last step and this step it intersects with the ground.  I then back step in smaller and smaller segments to get a nearly accurate point of impact.  I only need to know which grid I'm in.

I use the top left corner of the grid in which the line intersects the terrain as the centre position of the cursor.  For some modes I offset this by half a grid in others I stay with the corner point.

I can size the terrain cursor using a simple popup form.  Whatever action I carry out is done for every point under the cursor.  The positions are all easily calculated using simple maths.

The terrain cursor and the many helper shapes I draw are just simple lines drawn in 3D space.  The cursor samples the terrain height at the ends of each line and sets the heights a fraction above the terrain.  This means the cursor follows the contours of the terrain.

There has been a lot of work over the years getting to this stage with many features I have not mentioned yet.  If I knew then what I know now I would probably use an existing editor and spend the time writing an importer rather than adding all these features to my editor.  Having said that, I've learnt a lot and I do enjoy knowing that I did all this.

To complete the picture, this is a list of all the features of the game engine:
  • Walk round a 3D world
  • - first person controls
  • - over the shoulder view of yourself (more fiddly than it sounds)
  • - resolution 1024x576 (for better performance on the Xbox 360)
  • - jump
  • - spectate
  • - two player split screen
  • Animated
  • - blend animations
  • - merge in arm movement to follow which way the player is looking
  • - hold attachments that move with whatever they are attached to
  • - shared animation files (and a way to get them in to the pipeline.)
  • Physics
  • - collide with characters and structures
  • - projectile impacts
  • - projectile trajectories (thrown grenades)
  • Terrain and game editor (development only)
  • - change heights
  • - change textures
  • Add and remove (only in the development editor):
  • - models
  • - triggers
  • - particle effects
  • - goals
  • - trigger goal success
  • - trigger add a new goal
  • - trigger spawn player
  • - trigger spawn non-players
  • - trigger particle effects
  • - waypoints for AI pathfinding
  • - spawnpoints
  • - weapon or equipment pickups
  • Lighting
  • - single shadow casting light
  • - three effect lights
  • - shadows (not a trivial task, many many months spent on this)
  • Full menu system
  • - select which map to play
  • - customise the player character with hats etc.
  • - load and save character choices
  • - change music and effect volumes
  • - in game pause menu, resume or exit
  • - display goals outstanding and completed
  • Combat system
  • - select weapons
  • - shoot weapons
  • - throw grenades
  • - melee (elbow bash while holding a gun)
  • - projectile trails
  • - impact damage decals (instanced)
  • - impact effects, debris and smoke
  • - explosions
  • - muzzle flash
  • - sound effects
  • - drop weapons
  • - pickup weapons
  • - pickup ammunition
  • Head Up Display (HUD)
  • - weapon sights
  • - sniper sights
  • - zoom in
  • - display ammo as used
  • - compass
  • - radar showing friend and enemy positions if close
  • Non-Player Artificial Intelligence (AI)
  • - pathfinding (A* using navigation rooms)
  • - select a target if in range
  • - shoot at a target
  • - move to better cover to shoot from
  • and I'm sure there's more...


Brandon said...

Really impressed with how fully-featured you've made this over time! The level editor I'm writing for my project is just now out of its infancy (just got static model placement added) but I'm curious: I started out editing a heightmap file, but changed over to just using the paint/sculpt method to modify vertex Y values directly. Do your levels still rely on an external heightmap object?

I'm looking into dynamically adding vertices if heights stretch too far between verts during the sculpting process, as well as changing the brush to paint all three values (not just Y) to be able to make concave/vertical surfaces. If/when I get it working I'd be happy to share some algorithms if you'd like.

Anyway, great stuff as always, thanks for sharing your project with everyone!

John C Brown said...

Like you, I now only use the vertices. I changed to this to slightly speed up level load time on the Xbox by not having to create a separate height array.

I deliberately keep mine as a uniform grid so that I can very rapidly calculate the exact position to get the height.

Collision calculation performance is more important to me than perfect looking terrain.

Thanks for the offer and comment.

If you think I may already have some code that will help, just ask.