Side-scroller

From OLPC
Jump to: navigation, search

OLPC Side-Scroller Engine

The side-scroller engine allows for easy level creation, image-swapping, and enemy customization. None of these require any skill in programming, but does require Python (version 2.4 and above recommended) and pygame (version 1.7 recommended) to be installed. Directions to installing python and pygame can be found elsewhere on the OLPC Wiki - Links to be posted here later.

Tutorial

I suggest playing the game first, so you can get an idea what I mean by "tile" and "player image" and a few other terms. To do so, run play.py or at the terminal:

python ~/path_name_here/play.py

This should start the game assuming you have Python 2.4 or above and pygame 1.7 or above.

For a Level Creation Tutorial, visit here. (Link to be added).

To easily swap tile images, simply replace the images with your own (keeping the image name the same). Or, read more under Variables -> char_image_index.

For further customization, after a few games, open up play.py in your favorite text editor or Integrated Development Enviornment. The other file, side_scroller.py is the nitty-gritty code that, while you can change, it's not wholeheartedly recommended unless you know the programming language Python. Then read the Variable section found below while having play.py open next to you.

Tile Types

Any of the following tile-attributes can be assigned to any of the four sides of a square. That is, a tile could kill a player when the player jumps from below and act as a stable platform when the player lands from above.

0. Player can pass through, causes no effect.
1. Player cannot pass through, acts like a solid wall.
2. Player can pass through and pick up, adds one to the item-count = "coin" count. 100 coins will increase the player's life by one.
3. Player can destroy tile but will bounce back.
4. Tile kills player upon collision.
5. Teleport tile - Ends the current level and teleports the player to a totally new level. Can also be used as a "key" to end the level.
6. Flip block -> Flips the whole screen upside down.
7. Warp tile -> Will change the level list to an entirely new one. Can be used to Warp the player ahead by several levels. See Variable section for details.

Enemy Types

Enemies are just like tiles in that they have 4 directions, and any of them can be any of the following: (0-4 are the same as above)

0. Player can pass through, causes no effect.
1. Player cannot pass through, acts like a solid wall.
2. Player can pass through and pick up, adds one to the item-count = "coin" count. 100 coins will increase the player's life by one.
3. Player can destroy enemy but will bounce back.
4. Enemy will kill player upon collision.

Then the 5th type is labeled 15, to distinguish itself from the tile-specific keys.
15. Invincibility Power up (See section below, number 1)
16. Alter-image Powerup (See section below, number 2)
17. Falling type -> Will cause gravity of the enemy to be half of the player's gravity. This can be used to create blocks that fall upon the enemies touch.
18. Jumping Powerup (See section below, number 3)
19. Flying Powerup (See section below, number 4)

Player Power-ups

Powerups are essentially enemies (of type 15, 16, 18, or 19). Four different power-ups are available to the player currently:
1. Invincibility Powerup. This causes the player to gain temporary invincibility (from enemies, not from tiles like spikes).
2. Alter-image Powerup. This causes the players image to change (optional).
3. Jumping Powerup. This causes the players image to change (optional) and for the player to be able to jump higher.
4. Flying Powerup. This causes the players image to change (optional) and for the player to be able to fly.


Variables

You will see the following variables under the words "def main():"
screen_width -> This variable determines how wide you want the screen to be, in number of tiles.
screen_height -> This variable determines how tall you want the screen to be, in number of tiles.
tile_size -> This variable determines both how wide and how tall you want a single tile to be, in number of pixels.

I suggest 25 tiles by 19 tiles, with a tile size of 32 pixels. If you experience extreme slowdown at these settings, you could try lowering the width or height of your levels.

player_lives -> The number of lives you want the player to have initially.
player_coins -> The number of collectible items (they don't have to be coins) you want the player to have initially.
player_can_go_backward -> You can set this to either True or False, depending on whether you want the player to revisit screens he or she has been to previously. If you do not understand, try setting it to False and playing the game again, and after moving forward one screen, you will find the player cannot move to the previous screen.
complex_enemy_collision -> This creates more checks for horizontal collision detection. It is recommended you keep it off as it may cause some slowdown, unless you are experiencing collision detection problems with enemies (and if, after turning it on, you are still having issues, please email me, see bottom for details).
game_title -> What will appear at the top of the screen upon playing your game. Please remember to keep the quotes, or else python will give you errors!
player_image_list -> This list contains four filenames, each with quotes and seperated by commas. These four images correspond to the image the player will take on upon receiving one of the power ups. Respectively, they are [normal image, alter-image powerup image, higher-jumping powerup image, flying powerup image].

level_list -> This is the list of files in the level-format (described in "level creation" section below). The player will go through these stages in order unless the player hits a warp or teleport tile/enemy. It is highly recommended the format of each level be a plain document text (.txt) file. The name of the file is also the name of the level; you do not have to enter in .txt as part of the name of the file, it will check automatically for both filename and filename.txt.

image_list -> A list of all the images used by the game (except for player images). The very next list refers to this list to assign enemies and tiles to images.


char_image_index -> Connects level characters ('=', '+', 'A', for example), with the corresponding image. For example:


A:(0,(1,3)) means that A's image is in the first image of the image_list (the previous variable). But where in the first image is it? That is to say, this side-scrolling engine allows for multiple enemy or tile-images to be on a single large "sheet" of images. That is what the (1,3) is for: it tells the program that the top left corner of A's image can be found 1 tile-size left and three tile-sizes down from the top left of the first image in the image_list. How big is A's image? Well, it is 1 tile-size wide and 1 tile-size tall.

Advanced: Enemies bigger than 1 tile-size by 1 tile-size: If you say A:(-9,(0,0)), then the program interprets A's image to be the entire 10th image on the list. Disclaimer: Large enemies have been play-tested fairly rigorously, but may still experience errors in collision.


rect_type -> Connects level characters and their interaction with the player upon player-collision. There are four directions- (player coming from above, player coming from the right, player coming from below, player coming from the left). Each number describes the action the player will cause upon collision. These numbers may later allow "keywords" to simplify things for unexperienced developers in a future release.

After the four directions, if the tiles have type 2 or 3 in them, then there is a fifth element to describe what the tile will turn into.

Key:

   0 - player can pass through, causes no effect
   1 - player cannot pass through
   2 - player can pass through and pick up, adds one to the item-count = "coin"
   3 - player can destroy but will bounce back
   4 - kills player
   

Tile only (i.e. non-enemy level characters):

   5 - teleport tile - if there is a stage name at the end of the type (i.e. (1,1,5,1,' ', "bonus"),
it adds that level to the level list and teleports player 6 - flip block -> flips the whole screen upside down 7 - warp tile -> will change level list to whatever is after the type (i.e. (3,3,11,3,' ', ["bonus", "1-1"])
will skip player right to bonus, then 1-1, then the game is over.

Enemy/powerup only:

   15 - invincibility - gives the play invincibility for 3.3 seconds.
   16 - change player image power-up - this is power_up 1, changes player image to the 2nd image on the player_image_list
   17 - falling type -> will cause enemy's gravity to be half of the player's gravity
   18 - power up 2, allows player to jump slight higher, changes to 3rd image on the player_image_list
   19 - power up 3, allows player to fly, changes to 4th image on the player_image_list
   

Examples:

' ' : (0,0,0,0) = the standard "background" tile, nothing player does will cause it to change.
'+' : (1,1,3,1,' ') = the standard "brick" tile, which can be broken from below, but will not be broken in any other direction. Upon destruction it becomes the standard "background" tile (see above).
'C' : (8,8,8,8) = An enemy that will begin to fall faster when you land on it. (used for basically allowing platforms that fall when you land on them).
'D' : (4,4,3,4) = An enemy that can only be destroyed from below and will kill the player any other direction. If it was a tile, it would have a character after the last 4 (i.e. '^' : (4,4,3,4,'+') to turn it into the standard block).

My suggestion is to start a nearly blank level and add in different tiles or enemies to get a better idea of what each one will do.


enemy_behavior -> two keywords here, first what type of enemy (or powerup)-movement, second whether the enemy splits in half or not.

There are 6 enemy/powerup movement types currently. You may use the number or any of the keywords.

   1, "standard", "walkie", "cliffwalker", "willfall","walker1", "walker-1"  -> enemy walks back and forth, will walk off a cliff
2, "turnaround", "nofall", "wontfall", "walker2", "walker-2" -> enemy will walk back and forth,
and will turn around at the edge of a cliff
3, "jumpy", "jumper", "hopper" -> enemy will jump whenever possible, but may fall off cliffs
4, "flappy", "flyer-1", "flyer1" -> flies at a pretty much constant level or height range,
will turn around when it hits something
5, "zoomer", "flubber", "flyer-2", "flyer2" -> this movement is like flubber
- enemy will zoom up until it hits ceiling,
zoom down until it hits floor; it's sort of like type 6/flyer 3 (see below) but faster
6, "floater", "bobber", "flyer-3", "flyer3" -> this flyer is like a combination of
flubber and flappy, will sort of go upward,
but in a very flappy-way, slowly gaining/losing height.


enemy_stats -> Four numbers for enemy (running speed, jump velocity, falling velocity, enemy's gravity). Each one is in terms of tiles.

There are also the following keywords (remember they must have quotes around them to be recognized):

   average, avg, mid, normal  = "regular" speed/gravity as defined by my debugging.
fast, high = 'larger' value than "normal"
slow, low = 'lower' value than "normal"
stop, none = 0

You can use the numbers instead (usually in the range of -2 to 2... anything with a velocity greater than 2 would be moving over 2 tiles a frame, which is very fast), if you want a more specific designation. My suggestion is to start with keyword values and move on when you feel comfortable or if a real need arises.

player_stats -> (initial x position, initial y position, jump velocity, jump boost, maximum falling speed, max running speed)

All are in terms of tile-sizes. The initial x and y positions will be the same for each stage. Jump velocity is the number of tiles per frame the player will initially go up. Gravity will then slow the player down (or theoretically cause the player to speed up if you set the gravity to a negative number). Jump boost is the speed boost the player gets by holding down the up button even after the player initially jumps, allowing the player to reach variable heights. Maximum falling speed is to simulate terminal velocities due to air/drag. Max running speed is more or less running speed, but the player actually does have a *little* bit of acceleration when he runs forward. It's very small, however (0.3). I may allow the user to change this in the future.

player_gravity -> The gravity for the player, in tiles per frame per frame (or frame-squared). I personally find 0.17 to feel just about right.

screen_scroller_percent -> When player is this percent of the screen, the screen will scroll forward.

FAQ, or What I imagine to be Frequently Asked Questions

Q. Why aren't my keywords working?
A. Right now keywords are case-sensitive. Make sure all letters are lowercase... but that's actually something I will likely change for next release if it's an issue.

Q. What is the easiest way I can add to this project/have fun with this?
A. The easiest (and perhaps most fun) things to do would be to create your own levels, and also doing tile-swap outs. An easy way to make your tile images replace the default is to simply rename your images to the name of the old images. If you are willing to put in a little bit of time into learning the engine, you may find it's pretty customizable even without any programming knowledge.

Q. The engine is slow!
A. I'm hoping I don't get this one very often. Last I heard, it runs well on the XO (the OLPC's laptop). If I get complaints, obviously I will do my best to speed it up. My suggestions, however, are as follows: Make sure that complex enemy collision is off, don't put too many enemies on the screen at one time, don't have enemies that split in half, use walker1 type enemies instead of walker2 (turnaround), and choose enemy images that are exactly 1 tilesize by 1 tilesize to reduce the amount of refreshing. Lowering horizontal and vertical values (default is 25 by 19) will also help. But please also email me, so I can get a sense of whether this engine needs further optimization (or optimisation for those who prefer).

Q. Could you design keywords for the player stats or tile-types?
A. May very well be done if anyone actually asks or feels a need for it.

Q. Why do I have to put quotes around everything?
A. That way the engine knows that you are sending a word (like "flubber") and not a variable name (for example, flubber = 100).

Q. Why does 0 = the first image, 1 = the second image, etc?
A. This is a programming convention, it may be changed in later releases depending on who uses the program and what those users demand.

Q. Why does the screen "scroll" forward by an integer number of tiles, rather than by a single pixel at a time?
A. This was done because the XO is not very good at redrawing the whole screen at once (or so I am told). Therefore, the tile system was implemented to (hopefully) reduce the number of times a section of the screen would have to be redrawn. Moving forward one pixel at a time would not allow this optimization to be implemented in a feasible manner.

Q. How can I make sure the end of the screen doesn't cause the player to go to the next level?
A. Add a vertical column of impassable-tiles at the end (i.e. bricks). This will force the player to find whatever teleport item or tile you have in the level.

Q. How many lines of code is your program?
A. Hovers right around 1000, but I don't have a lot of whitespace. Many of these lines have been written and rewritten, but improvements are always possible! If you have the gut for it, please contribute to and extend this engine!

Q. Your documentation is lacking/not human-readable!
A. Sorry, please feel free to add to it, as I will try to do over time. :D




This page and the side-scroller engine were created by Patrick DeJarnette in conjunction with Google's Summer of Code 2007. Feel free to email me at pepboy@uchicago.edu or AIM screen-name pepboy013.