Scrolling Level Selector

  ... tutorials on how to use AndEngine.

Scrolling Level Selector

Postby avergottini » Tue Sep 27, 2011 1:43 am

Hello!

I wanted to implement a level selector in my game( https://market.android.com/details?id=com.pickle.mazzter), and could not find any examples, so I've created a simple vertical scrolling example.

It creates a box for each level.
Depending on the levels completed, it disables the ability to click those levels and grays them out.

To keep it as clean as possible, it uses rectangles and text, but it can be easily changed to use sprites and a background, to make it prettier, but I guess that depends on what kind of game you are doing.

Let me know what you think or if you have any questions!

a little screenshot:
screenshot.png
screenshot.png (4.51 KiB) Viewed 7509 times


Source code:
Syntax: [ Download ] [ Hide ]
Using java Syntax Highlighting
  1.  
  2. public class MenuScrollerActivity extends BaseGameActivity implements IScrollDetectorListener, IOnSceneTouchListener, IClickDetectorListener {
  3.        
  4.         // ===========================================================
  5.         // Constants
  6.         // ===========================================================
  7.         protected static int CAMERA_WIDTH = 720;
  8.         protected static int CAMERA_HEIGHT = 480;
  9.  
  10.         protected static int FONT_SIZE = 24;
  11.  
  12.         protected static int LEVELS = 30;
  13.         protected static int LEVEL_COLUMNS_PER_SCREEN = 4;
  14.         protected static int LEVEL_ROWS_PER_SCREEN = 3;
  15.         protected static int LEVEL_PADDING = 50;
  16.  
  17.         // ===========================================================
  18.         // Fields
  19.         // ===========================================================
  20.         private Scene mScene;
  21.         private Camera mCamera;
  22.         protected PhysicsWorld mPhysicsWorld;
  23.  
  24.         private Font mDroidFont;
  25.  
  26.         private BitmapTextureAtlas mDroidFontTexture;
  27.  
  28.         // Scrolling
  29.         private SurfaceScrollDetector mScrollDetector;
  30.         private ClickDetector mClickDetector;
  31.  
  32.         private float mMinY = 0;
  33.         private float mMaxY = 0;
  34.         private float mCurrentY = 0;
  35.         private int iLevelClicked = -1;
  36.        
  37.         //This value will be loaded from whatever method used to store data.
  38.         private int mMaxLevelReached = 7;
  39.  
  40.         // ===========================================================
  41.         // Constructors
  42.         // ===========================================================
  43.  
  44.         // ===========================================================
  45.         // Getter & Setter
  46.         // ===========================================================
  47.  
  48.         // ===========================================================
  49.         // Methods for/from SuperClass/Interfaces
  50.         // ===========================================================
  51.  
  52.         @Override
  53.         public void onLoadResources() {
  54.                 // Paths
  55.                 FontFactory.setAssetBasePath("font/");
  56.  
  57.                 // Font
  58.                 this.mDroidFontTexture = new BitmapTextureAtlas(256, 256);
  59.                 this.mDroidFont = FontFactory.createFromAsset(this.mDroidFontTexture, this, "Droid.ttf", FONT_SIZE, true, Color.BLACK);
  60.                 this.mEngine.getTextureManager().loadTextures(this.mDroidFontTexture);
  61.                 this.mEngine.getFontManager().loadFonts(this.mDroidFont);
  62.  
  63.         }
  64.  
  65.         @Override
  66.         public Engine onLoadEngine() {
  67.                 this.mCamera = new Camera(0, 0, CAMERA_WIDTH, CAMERA_HEIGHT);
  68.  
  69.                 final EngineOptions engineOptions = new EngineOptions(true, ScreenOrientation.LANDSCAPE, new FillResolutionPolicy(), this.mCamera);
  70.                 engineOptions.getTouchOptions().setRunOnUpdateThread(true);
  71.  
  72.                 final Engine engine = new Engine(engineOptions);
  73.                 return engine;
  74.         }
  75.  
  76.         @Override
  77.         public Scene onLoadScene() {
  78.                 this.mEngine.registerUpdateHandler(new FPSLogger());
  79.  
  80.                 this.mScene = new Scene();
  81.                 this.mScene.setBackground(new ColorBackground(0.9f, 0.9f, 0.9f));
  82.                
  83.                 this.mScrollDetector = new SurfaceScrollDetector(this);
  84.                 this.mClickDetector = new ClickDetector(this);
  85.  
  86.                 this.mScene.setOnSceneTouchListener(this);
  87.                 this.mScene.setTouchAreaBindingEnabled(true);
  88.                 this.mScene.setOnSceneTouchListenerBindingEnabled(true);
  89.  
  90.                 CreateLevelBoxes();
  91.  
  92.                 return this.mScene;
  93.  
  94.         }
  95.  
  96.         @Override
  97.         public boolean onSceneTouchEvent(final Scene pScene, final TouchEvent pSceneTouchEvent) {
  98.                 this.mClickDetector.onTouchEvent(pSceneTouchEvent);
  99.                 this.mScrollDetector.onTouchEvent(pSceneTouchEvent);
  100.                 return true;
  101.         }
  102.  
  103.         @Override
  104.         public void onScroll(final ScrollDetector pScollDetector, final TouchEvent pTouchEvent, final float pDistanceX, final float pDistanceY) {
  105.  
  106.                 if ( ((mCurrentY - pDistanceY) < mMinY) || ((mCurrentY - pDistanceY) > mMaxY) )
  107.                         return;
  108.  
  109.                 this.mCamera.offsetCenter(0, -pDistanceY);
  110.  
  111.                 mCurrentY -= pDistanceY;
  112.  
  113.         }
  114.  
  115.         @Override
  116.         public void onClick(ClickDetector pClickDetector, TouchEvent pTouchEvent) {
  117.                 loadLevel(iLevelClicked);
  118.         };
  119.  
  120.         // ===========================================================
  121.         // Methods
  122.         // ===========================================================
  123.  
  124.         private void CreateLevelBoxes() {
  125.  
  126.                 // calculate the amount of required columns for the level count
  127.                 int totalRows = (LEVELS / LEVEL_COLUMNS_PER_SCREEN) + 1;
  128.  
  129.                 // Calculate space between each level square
  130.                 int spaceBetweenRows = (CAMERA_HEIGHT / LEVEL_ROWS_PER_SCREEN) - LEVEL_PADDING;
  131.                 int spaceBetweenColumns = (CAMERA_WIDTH / LEVEL_COLUMNS_PER_SCREEN) - LEVEL_PADDING;
  132.  
  133.                
  134.                 //Current Level Counter
  135.                 int iLevel = 1;
  136.                
  137.                 //Create the Level selectors, one row at a time.
  138.                 int boxX = LEVEL_PADDING, boxY = LEVEL_PADDING;
  139.                 for (int y = 0; y < totalRows; y++) {
  140.                         for (int x = 0; x < LEVEL_COLUMNS_PER_SCREEN; x++) {
  141.  
  142.                                 //On Touch, save the clicked level in case it's a click and not a scroll.
  143.                                 final int levelToLoad = iLevel;
  144.                                
  145.                                 // Create the rectangle. If the level selected
  146.                                 // has not been unlocked yet, don't allow loading.
  147.                                 Rectangle box = new Rectangle(boxX, boxY, 50, 50) {
  148.                                         @Override
  149.                                         public boolean onAreaTouched(final TouchEvent pSceneTouchEvent, final float pTouchAreaLocalX, final float pTouchAreaLocalY) {
  150.                                                 if (levelToLoad >= mMaxLevelReached)
  151.                                                         iLevelClicked = -1;
  152.                                                 else
  153.                                                         iLevelClicked = levelToLoad;
  154.                                                 return false;
  155.                                         }
  156.                                 };
  157.  
  158.                                 if (iLevel >= mMaxLevelReached)
  159.                                         box.setColor(0, 0, 0.9f);
  160.                                 else
  161.                                         box.setColor(0, 0.9f,0f);
  162.                                 box.setAlpha(0.5f);
  163.  
  164.                                 this.mScene.attachChild(box);
  165.                                
  166.                                 //Center for different font size
  167.                                 if (iLevel < 10) {
  168.                                         this.mScene.attachChild(new Text(boxX + 18, boxY + 15, this.mDroidFont, String.valueOf(iLevel)));
  169.                                 }
  170.                                 else {
  171.                                         this.mScene.attachChild(new Text(boxX + 10, boxY + 15, this.mDroidFont, String.valueOf(iLevel)));
  172.                                 }
  173.                                
  174.                                
  175.                                 this.mScene.registerTouchArea(box);
  176.  
  177.                                 iLevel++;
  178.                                 boxX += spaceBetweenColumns + LEVEL_PADDING;
  179.  
  180.                                 if (iLevel > LEVELS)
  181.                                         break;
  182.                         }
  183.  
  184.                         if (iLevel > LEVELS)
  185.                                 break;
  186.  
  187.                         boxY += spaceBetweenRows + LEVEL_PADDING;
  188.                         boxX = 50;
  189.                 }
  190.  
  191.                 //Set the max scroll possible, so it does not go over the boundaries.
  192.                 mMaxY = boxY - CAMERA_HEIGHT + 200;
  193.         }
  194.  
  195.         @Override
  196.         public void onLoadComplete() {
  197.  
  198.         }
  199.  
  200.         //Here is where you call the level load.
  201.         private void loadLevel(final int iLevel) {
  202.                 if (iLevel != -1) {
  203.                         runOnUiThread(new Runnable() {
  204.                                 @Override
  205.                                 public void run() {
  206.                                         Toast.makeText(MenuScrollerActivity.this, "Loads Level " + String.valueOf(iLevel), Toast.LENGTH_SHORT).show();
  207.                                         iLevelClicked = -1;
  208.                                 }
  209.                         });
  210.                 }
  211.         }
  212. }
  213.  
Parsed in 0.055 seconds, using GeSHi 1.0.8.4



Thanks!
avergottini
 
Posts: 18
Joined: Wed Aug 03, 2011 10:35 pm

Re: Scrolling Level Selector

Postby avergottini » Tue Sep 27, 2011 11:34 pm

Here's a Screenshot of the level selector integrated on the game:
level.png
level.png (112.03 KiB) Viewed 7473 times
avergottini
 
Posts: 18
Joined: Wed Aug 03, 2011 10:35 pm

Re: Scrolling Level Selector

Postby pep_dj » Wed Sep 28, 2011 11:34 am

Thanks for sharing!
Image
pep_dj
 
Posts: 170
Joined: Fri Nov 12, 2010 9:05 pm

Re: Scrolling Level Selector

Postby drjava72 » Mon Oct 03, 2011 11:14 am

avergottini wrote:Here's a Screenshot of the level selector integrated on the game:
level.png


It is really nice but would you please upload your project in which you just switched scenes !!! I just want to see how to switch from one scene to another scene.

Thanks very much.
Best Regards,
drJava72
drjava72
 
Posts: 287
Joined: Fri Apr 29, 2011 8:03 am

Re: Scrolling Level Selector

Postby Mathew » Sun Oct 09, 2011 11:44 am

drjava72 wrote:
avergottini wrote:Here's a Screenshot of the level selector integrated on the game:
level.png


It is really nice but would you please upload your project in which you just switched scenes !!! I just want to see how to switch from one scene to another scene.

Thanks very much.


Indeed, would be really helpful!
User avatar
Mathew
 
Posts: 1073
Joined: Sun Jul 31, 2011 2:49 pm
Location: Tarnów, Poland

Re: Scrolling Level Selector

Postby avergottini » Mon Oct 10, 2011 6:53 pm

I switch screens in the function loadLevel.
Right now it just shows a toast, but there what I do is load the selected maze from file to the maze scene.
(I use one scene for all levels, that I just rewrite).
This is the code in the procedure:

LoadMaze(mScene, iLevelSelected);
mEngine.setScene(mScene);

And I have another scene for the level select, which I switch to when you hit a green or red circle.

Please let me know if you need a full working code sample.

Thanks!
Agustin.
avergottini
 
Posts: 18
Joined: Wed Aug 03, 2011 10:35 pm

Re: Scrolling Level Selector

Postby avergottini » Mon Oct 10, 2011 11:10 pm

Just added a new post on this forum, with the source code to my game that uses the level selector:
tutorials/mazzter-game-full-source-code-t5323.html

Thanks!
avergottini
 
Posts: 18
Joined: Wed Aug 03, 2011 10:35 pm

Re: Scrolling Level Selector

Postby Coder_For_Life22 » Wed May 23, 2012 9:03 pm

I am using this for two scenes but for some reason when i go back to the first scene the camera is out of position.

Has anyone else experienced this issue?
User avatar
Coder_For_Life22
 
Posts: 1036
Joined: Wed Nov 09, 2011 5:37 pm

Re: Scrolling Level Selector

Postby SumitDasGames » Thu Aug 08, 2013 10:28 pm

Coder_For_Life22 wrote:I am using this for two scenes but for some reason when i go back to the first scene the camera is out of position.

Has anyone else experienced this issue?


Set the camera center to screen_width/2 (screen center) before returning back to the previous scene
Powerplay Hockey Lite [FREE] - https://play.google.com/store/apps/details?id=com.maxrockzz.powerplayhockey.lite

^^ Please Rate my First game ^^
SumitDasGames
 
Posts: 6
Joined: Mon Jul 29, 2013 11:53 pm

Re: Scrolling Level Selector

Postby descuer » Sat Nov 16, 2013 4:05 pm

Hi all, and thanks to the author for sharing!!

I'm using GLES2 version now, and I've updated your code so it now works with GLES2 branch, Here's the modified code:

Syntax: [ Download ] [ Hide ]
Using java Syntax Highlighting
  1. import org.andengine.engine.Engine;
  2. import org.andengine.engine.camera.Camera;
  3. import org.andengine.engine.options.EngineOptions;
  4. import org.andengine.engine.options.ScreenOrientation;
  5. import org.andengine.engine.options.resolutionpolicy.FillResolutionPolicy;
  6. import org.andengine.entity.primitive.Rectangle;
  7. import org.andengine.entity.scene.IOnSceneTouchListener;
  8. import org.andengine.entity.scene.Scene;
  9. import org.andengine.entity.text.Text;
  10. import org.andengine.entity.util.FPSLogger;
  11. import org.andengine.extension.physics.box2d.PhysicsWorld;
  12. import org.andengine.input.touch.TouchEvent;
  13. import org.andengine.input.touch.detector.ClickDetector;
  14. import org.andengine.input.touch.detector.ClickDetector.IClickDetectorListener;
  15. import org.andengine.input.touch.detector.ScrollDetector;
  16. import org.andengine.input.touch.detector.ScrollDetector.IScrollDetectorListener;
  17. import org.andengine.input.touch.detector.SurfaceScrollDetector;
  18. import org.andengine.opengl.font.Font;
  19. import org.andengine.opengl.font.FontFactory;
  20. import org.andengine.opengl.texture.Texture;
  21. import org.andengine.opengl.texture.TextureOptions;
  22. import org.andengine.opengl.texture.atlas.bitmap.BitmapTextureAtlas;
  23. import org.andengine.ui.activity.SimpleBaseGameActivity;
  24.  
  25. import android.graphics.Color;
  26. import android.widget.Toast;
  27.  
  28. public class MenuScrollerActivity extends SimpleBaseGameActivity implements IScrollDetectorListener, IOnSceneTouchListener, IClickDetectorListener {
  29.        
  30.         // ===========================================================
  31.         // Constants
  32.         // ===========================================================
  33.         protected static int CAMERA_WIDTH = 720;
  34.         protected static int CAMERA_HEIGHT = 480;
  35.  
  36.         protected static int FONT_SIZE = 24;
  37.  
  38.         protected static int LEVELS = 30;
  39.         protected static int LEVEL_COLUMNS_PER_SCREEN = 4;
  40.         protected static int LEVEL_ROWS_PER_SCREEN = 3;
  41.         protected static int LEVEL_PADDING = 50;
  42.  
  43.         // ===========================================================
  44.         // Fields
  45.         // ===========================================================
  46.         private Scene mScene;
  47.         private Camera mCamera;
  48.         protected PhysicsWorld mPhysicsWorld;
  49.  
  50.         private Font mDroidFont;
  51.  
  52.         private Texture mDroidFontTexture;
  53.  
  54.         // Scrolling
  55.         private SurfaceScrollDetector mScrollDetector;
  56.         private ClickDetector mClickDetector;
  57.  
  58.         private float mMinY = 0;
  59.         private float mMaxY = 0;
  60.         private float mCurrentY = 0;
  61.         private int iLevelClicked = -1;
  62.        
  63.         //This value will be loaded from whatever method used to store data.
  64.         private int mMaxLevelReached = 7;
  65.  
  66.         // ===========================================================
  67.         // Constructors
  68.         // ===========================================================
  69.  
  70.         // ===========================================================
  71.         // Getter & Setter
  72.         // ===========================================================
  73.  
  74.         // ===========================================================
  75.         // Methods for/from SuperClass/Interfaces
  76.         // ===========================================================
  77.  
  78.         @Override
  79.                 protected void onCreateResources() {
  80.                 // Paths
  81.                 FontFactory.setAssetBasePath("font/");
  82.  
  83.                 // Font
  84.                
  85.                         this.mDroidFontTexture = new BitmapTextureAtlas(this.getTextureManager(),512, 512, TextureOptions.BILINEAR_PREMULTIPLYALPHA);          
  86.  
  87.                         this.mDroidFont = FontFactory.createFromAsset(this.getFontManager(), mDroidFontTexture, this.getAssets(), "lcd-bold.TTF", 26, true, Color.WHITE);
  88.                         this.mDroidFont.load();                                
  89.        
  90.                 this.mEngine.getTextureManager().loadTexture(mDroidFontTexture);
  91.                 this.mEngine.getFontManager().loadFonts(this.mDroidFont);
  92.  
  93.         }
  94.  
  95.         @Override
  96.                 protected Scene onCreateScene() {
  97.             this.mEngine.registerUpdateHandler(new FPSLogger());
  98.            
  99.             this.mScene = new Scene();
  100.        //     this.mScene.setBackground(new ColorBackground(0.9f, 0.9f, 0.9f));
  101.            
  102.             this.mScrollDetector = new SurfaceScrollDetector(this);
  103.             this.mClickDetector = new ClickDetector(this);
  104.  
  105.             this.mScene.setOnSceneTouchListener(this);
  106.             this.mScene.setTouchAreaBindingOnActionDownEnabled(true);
  107.             this.mScene.setTouchAreaBindingOnActionMoveEnabled(true);            
  108.             this.mScene.setOnSceneTouchListenerBindingOnActionDownEnabled(true);
  109.  
  110.             CreateLevelBoxes();
  111.  
  112.             return this.mScene;
  113.         }
  114.  
  115.  
  116.         @Override
  117.         public boolean onSceneTouchEvent(final Scene pScene, final TouchEvent pSceneTouchEvent) {
  118.                 this.mClickDetector.onTouchEvent(pSceneTouchEvent);
  119.                 this.mScrollDetector.onTouchEvent(pSceneTouchEvent);
  120.                 return true;
  121.         }
  122.  
  123.  
  124.  
  125.  
  126.         // ===========================================================
  127.         // Methods
  128.         // ===========================================================
  129.  
  130.         private void CreateLevelBoxes() {
  131.  
  132.                 // calculate the amount of required columns for the level count
  133.                 int totalRows = (LEVELS / LEVEL_COLUMNS_PER_SCREEN) + 1;
  134.  
  135.                 // Calculate space between each level square
  136.                 int spaceBetweenRows = (CAMERA_HEIGHT / LEVEL_ROWS_PER_SCREEN) - LEVEL_PADDING;
  137.                 int spaceBetweenColumns = (CAMERA_WIDTH / LEVEL_COLUMNS_PER_SCREEN) - LEVEL_PADDING;
  138.  
  139.                
  140.                 //Current Level Counter
  141.                 int iLevel = 1;
  142.                
  143.                 //Create the Level selectors, one row at a time.
  144.                 int boxX = LEVEL_PADDING, boxY = LEVEL_PADDING;
  145.                 for (int y = 0; y < totalRows; y++) {
  146.                         for (int x = 0; x < LEVEL_COLUMNS_PER_SCREEN; x++) {
  147.  
  148.                                 //On Touch, save the clicked level in case it's a click and not a scroll.
  149.                                 final int levelToLoad = iLevel;
  150.                                
  151.                                 // Create the rectangle. If the level selected
  152.                                 // has not been unlocked yet, don't allow loading.
  153.                                 Rectangle box = new Rectangle(boxX, boxY, 50, 50, this.getVertexBufferObjectManager()) {
  154.                                         @Override
  155.                                         public boolean onAreaTouched(final TouchEvent pSceneTouchEvent, final float pTouchAreaLocalX, final float pTouchAreaLocalY) {
  156.                                                 if (levelToLoad >= mMaxLevelReached)
  157.                                                         iLevelClicked = -1;
  158.                                                 else
  159.                                                         iLevelClicked = levelToLoad;
  160.                                                 return false;
  161.                                         }
  162.                                 };
  163.  
  164.                                 if (iLevel >= mMaxLevelReached)
  165.                                         box.setColor(0, 0, 0.9f);
  166.                                 else
  167.                                         box.setColor(0, 0.9f,0f);
  168.                                 box.setAlpha(0.5f);
  169.  
  170.                                 this.mScene.attachChild(box);
  171.                                
  172.                                 //Center for different font size
  173.                                 if (iLevel < 10) {
  174.                                         this.mScene.attachChild(new Text(boxX + 18, boxY + 15, this.mDroidFont, String.valueOf(iLevel), this.getVertexBufferObjectManager()));
  175.                                 }
  176.                                 else {
  177.                                         this.mScene.attachChild(new Text(boxX + 10, boxY + 15, this.mDroidFont, String.valueOf(iLevel), this.getVertexBufferObjectManager()));
  178.                                 }
  179.                                
  180.                                
  181.                                 this.mScene.registerTouchArea(box);
  182.  
  183.                                 iLevel++;
  184.                                 boxX += spaceBetweenColumns + LEVEL_PADDING;
  185.  
  186.                                 if (iLevel > LEVELS)
  187.                                         break;
  188.                         }
  189.  
  190.                         if (iLevel > LEVELS)
  191.                                 break;
  192.  
  193.                         boxY += spaceBetweenRows + LEVEL_PADDING;
  194.                         boxX = 50;
  195.                 }
  196.  
  197.                 //Set the max scroll possible, so it does not go over the boundaries.
  198.                 mMaxY = boxY - CAMERA_HEIGHT + 200;
  199.         }
  200.  
  201.  
  202.  
  203.         //Here is where you call the level load.
  204.         private void loadLevel(final int iLevel) {
  205.                 if (iLevel != -1) {
  206.                         runOnUiThread(new Runnable() {
  207.                                 @Override
  208.                                 public void run() {
  209.                                         Toast.makeText(MenuScrollerActivity.this, "Loads Level " + String.valueOf(iLevel), Toast.LENGTH_SHORT).show();
  210.                                         iLevelClicked = -1;
  211.                                 }
  212.                         });
  213.                 }
  214.         }
  215.  
  216.  
  217.  
  218.                 @Override
  219.                 public void onClick(ClickDetector pClickDetector, int pPointerID,
  220.                                 float pSceneX, float pSceneY) {
  221.                         // TODO Auto-generated method stub
  222.                         loadLevel(iLevelClicked);
  223.                        
  224.                 }
  225.  
  226.                 @Override
  227.                 public void onScrollStarted(ScrollDetector pScollDetector,
  228.                                 int pPointerID, float pDistanceX, float pDistanceY) {
  229.                         // TODO Auto-generated method stub
  230.                        
  231.                 }
  232.  
  233.                 @Override
  234.                 public void onScroll(ScrollDetector pScollDetector, int pPointerID,
  235.                                 float pDistanceX, float pDistanceY) {
  236.                         // TODO Auto-generated method stub
  237.             if ( ((mCurrentY - pDistanceY) < mMinY) || ((mCurrentY - pDistanceY) > mMaxY) )
  238.                 return;
  239.  
  240.         this.mCamera.offsetCenter(0, -pDistanceY);
  241.  
  242.         mCurrentY -= pDistanceY;                       
  243.                 }
  244.  
  245.                 @Override
  246.                 public void onScrollFinished(ScrollDetector pScollDetector,
  247.                                 int pPointerID, float pDistanceX, float pDistanceY) {
  248.                         // TODO Auto-generated method stub
  249.                        
  250.                 }
  251.  
  252.                 @Override
  253.                 public EngineOptions onCreateEngineOptions() {
  254.             this.mCamera = new Camera(0, 0, CAMERA_WIDTH, CAMERA_HEIGHT);
  255.            
  256.             final EngineOptions engineOptions = new EngineOptions(true, ScreenOrientation.LANDSCAPE_FIXED, new FillResolutionPolicy(), this.mCamera);
  257.            
  258.                         return engineOptions;
  259.                 }
  260.  
  261.  
  262.  
  263.  
  264. }
  265.  
Parsed in 0.077 seconds, using GeSHi 1.0.8.4
descuer
 
Posts: 12
Joined: Wed Nov 09, 2011 4:13 pm


Return to Tutorials

Who is online

Users browsing this forum: Google [Bot] and 21 guests