Showing posts with label Level Editor. Show all posts
Showing posts with label Level Editor. Show all posts

Friday, October 1, 2010

Side Scrolling Fun IV: Enemies, Mortality and Backgrounds

For the next small step in the side-scroller engine, I wanted to tidy the look up just a bit, add drone-type enemies, and have it so the player could die. For tidying it up, I first added a parallax background which consists of a layer of sprites and a depth into the screen. The larger the depth, the slower it scrolls, so a depth of 1 would scroll faster (twice as fast) than a layer with a depth of 2m and a depth of infinity would be stationary. This was a cheap attempt at a pseudo 3-D (circa 1982) feel. The background itself could be made in a level editor, or loaded as a random array of background elements upon start-up. For now the only objects are clouds placed at random, at two separate depths.

Another "look and feel" kind of effect was to have a clear-cut beginning and end to the level. You notice in the old Super Mario Bros. series (and most side-scrollers) the screen follows Mario unless he's at the beginning or end (or top or bottom) of the level at which the screen stops moving and Mario move with respect to the screen. To accomplish this, I just checked if the current screen would be more left than the leftmost tile or more right than the rightmost tile. If so, then the screen was fixed at the extreme point, i.e.

double screenX = 0;

if(xCX)

{

screenX = CX;

}

else if(x>levelMaxX-CX)

{

screenX = levelMaxX-CX;

}

else screenX = x;


... and similarly for y. Also, to make things more efficient I only computed collisions, drew tiles, and processed enemy behavior if they were visible. Since each of these elements are sub-classes of and abstract "Square Object" class, or Squob, this is really simple. At each iteration get all squobs within a half screen width distance from the player and update and draw those objects alone. Right now the speed-up in unnoticeable but for larger levels with more advanced processing, this could become significant.

Next step was getting enemies on the screen. This was done by making a generic Enemy class which extends Squob. No opponent in the game is directly from this class, but each individual enemy extends these properties. Then I just created an array of enemies and updated the array on each game iteration. Each enemy has a sprite manager which handles its animation and a function called iterate() which defines its behavior. Right now, the "behavior" is just to walk in a straight line and turn around if its next step will bring it over a ledge or if it bumps into another enemy or a wall. Whether or not a collision occurs is passed to the enemy from the main program.

The two prototype monsters are the "grunt":

and the "peon":
which basically do the same thing now: walk back and forth, and hope to bump into "smiley":
... who is not currently smiling.

In order to conveniently add the array of enemy monsters to the game in just the right place. I modified the level editor to allow for monster placement, as well as player start point. The level file now contains player start coords, enemy positions, and tiles:


clicking on the picture will give you the zipped source code.

To make it so the player could die, I just check for special cases in the collision detection. For example if the player collides with a spike, he dies. If the player collides with an enemy from below or the side, he dies, but if he collides from above, the enemy dies. Here the player dying means that his 'lives' get reduced by one, and he's warped to the beginning of the level. Now, nothing happens if he runs out of lives he just has a negative amount of lives. The philosophical implications are mind boggling!

Here is a screen-shot of the program in action. Click on the pic to try the game. One problem is that the loading time is brutal. At first I thought that it was the server but after writing a simple test program which loads a single image and text file from the server I noticed that this was not the case, as the test program ran instantly. Upon closer inspection I think it's just that I was being stupid. When the level is loaded it loads each tile as an image from a URL which is ridiculous. For next iteration of the program I'll just load each item once (via a LoadManager?) and store these images as global type files.



In the next programming run, the goal is to make a polished, 2 level game that doesn't make any sense. The game will have sounds, cut-scenes, intro, game-over screens, 1-up, nicer graphics, level bosses. In addition I'll try to debug all the little problems like slow loading times. This all needs to happen before the final stage of game design - that is; a story, characters, and lots of levels and variety.

Thursday, September 9, 2010

Side Scrolling Fun II: The Level Editor

In the very basic side-scroller engine that I started, I needed obstacles for the character (or circle) to walk on. This was done by manually typing in the coordinates and dimensions of the obstacles directly in the code. This is ridiculous and should be done with a level-editor type program, so I decided to take a stab at one. I decided to try to learn the nice-looking Java Swing layout editor. To simplify things such as file i/o, I made a stand-alone program instead of an Applet. At first, learning Swing was a huge mistake since I spent hours trying to make things work. After a while I learned the basics: the main window is a JFrame, which contains a number of JPanels which can be addressed individually. The frame can have a menu, a toolbar, and a drawing area, among other things.

The main program, which contains a menu, a toolbar and a drawing area (MapPanel which extends JPanel) is MainFrame (extends JFrame.) This contains all the event listeners and handles the "save" and "open" operations. The MapPanel is a grid of characters, each of which determine a block of a given size on the map.

The map may be saved into a text file consisting of a header telling the size of the map etc, followed by a list of coordinates of block types sorted by x.

A typical file is: (level1.txt)

200,50,636
0,0,b
0,1,b
0,2,b
1,17,b
1,18,b
2,1,r
2,13,g
...

You can open saved files. The open function first check for a logical header and then attempts to read the blocks into an Array of type "MapPoint" which is just a container for data of form (int x,int y, char type). If anything goes wrong with any of the points, the map loader jumps ship and returns false. Only if every point makes sense and the number of points is consistent with the header file does the map get loaded on screen and the method returns true.


The final time consuming part was making the program behave like a normal program. For example, if the user has already saved the file and chosen a file location, a new file dialog menu shouldn't pop up when he saves again, it should just save - something I never really thought about. Also, if the user saves then exits, he shouldn't be asked to save again, but if a save is needed, a polite program would ask of he wants to save first. To this end, boolean values for were created to denote whether a filename has been selected yet and whether a save is required.

Other challenges were making the functional part of the program convenient to use. It would be very annoying to have to draw the map by clicking each block individually. To circumvent this, a click-drag feature was implemented by checking whether the user is holding the mouse down. Also, it is essential to clear mistakenly placed blocks and to know what type of block is currently selected. I found that the best way to show this was to have an outline of the current block type hover along with the mouse cursor. Finally, for the "big picture," the user can toggle a mini map on and off by pressing m. The end result looks like this:


This now allows me to continue along with the side-scroller engine and test it out on a few simple maps. The next iteration of this program (if it comes to be) will extend the functionality of the UI by adding features like "undo" and remembering the current file directory so the user doesn't have to constantly navigate there.

The program+source code can be found zipped here, or straight out the gate here.

Thanks to Java Swing, the end results doesn't look too bad and almost resembles a real program that one might find on the internet.