Monday, March 21, 2011

AndEngine from Scratch (I)

What's AndEngine

AndEngine is a 2d Engine OpenGL for the Android platform.
There is the AndEngine Core Terminology taken directly from the AndEngine forums.
  • BaseGameActivity: The BaseGameActivity is the root of a game, that contains an Engine and manages to create a SurfaceView the contents of the Engine will be drawn into. There is always exactly one Engine for one BaseGameActivity. You can proceed from one BaseGameActivity to another using common Android mechanisms.
  • Engine: The Engine make the game proceed in small discrete steps of time. The Engine manages to synchronize a periodic drawing and updating of the Scene, which contains all the content that your game is currently handling actively. There usually is one Scene per Engine, except for the SplitScreenEngines.
  • IResolutionPolicy: An implementation of the IResolutionPolicy interface is part of the EngineOptions. It tells AndEngine how to deal with the different screen-sizes of different devices. I.e. RatioResolutionPolicy will maximize the SurfaceView to the limiting size of the screen, while keeping a specific ratio. That means objects won't be distorted while the SurfaceView has the maximum size possible.
  • Camera: A Camera defines the rectangle of the scene that is drawn on the screen, as not the whole scene is visible all the time. Usually there is one Camera per Scene, except for the SplitScreenEngines. There are subclasses that allow zooming and smooth position changes of the Camera.
  • Scene: The Scene class is the root container for all objects to be drawn on the screen. A Scene has a specific amount of Layers, which themselves can contain a (fixed or dynamic) amount of Entities. There are subclasses, like the CameraScene/HUD/MenuScene that are drawing themselves to the same position of the Scene no matter where the camera is positioned to.
  • Entity: An Entitiy is an object that can be drawn, like Sprites, Rectangles, Text or Lines. An Entity has a position/rotation/scale/color/etc...
  • Texture: A Texture is a 'image' in the memory of the graphics chip. On Android the width and height of a Texture has to be a power of 2. Therefore AndEngine assembles a Texture from a couple of ITextureSources, so the space can be used better.
  • ITextureSource: An implmentation of the ITextureSource-interface like AssetTextureSource manages to load an image onto a specific position in the Texture.
  • TextureRegion: A TextureRegion defines a rectangle on the Texture. A TextureRegion is used by Sprites to let the system know what part of the big Texture the Sprite is showing.
  • PhysicsConnector: A PhysicsConnector manages to update the AndEngine-Shapes (like Rectangles/Sprites/etc...) when their physics representations "bodies" change. Once using Physics (and a PhysicsConnector) with an AndEngine-Shape you'd disable the Physics calculated by AndEngine itself, by calling setUpdatePhysics(false) to the Shape. Changes made to the AndEngine-Shape are not reflected in the Physics - you have to call the methods on the Body object you have used to create the PhysicsConnector.

Getting AndEngine


To get Andengine, you can download sources from http://www.andengine.org or you can download a jar file. I'm using the jar file option.

First download this file and keep it in your computer.

Eclipse project Creation


Start new Project with File -> New Project.



Next, Finish.. Now we create a lib folder under the root directory of our project.



Now drag the jar file previously downloaded to the lib folder in Eclipse. It looks like this..


Now Right Button on the andengine.jar file and Build Path -> Add to Build Path.



Now the go to Main.java file and change Activity to BaseGameActivity. delete the default constructor, organize imports, and implement the BaseGameActivity methods. Now it should look like this code below.


Main.java
  1. package com.pruebas.andengine;
  2.  
  3. import org.anddev.andengine.engine.Engine;
  4. import org.anddev.andengine.entity.scene.Scene;
  5. import org.anddev.andengine.ui.activity.BaseGameActivity;
  6. import android.os.Bundle;
  7.  
  8. public class Main extends BaseGameActivity {
  9. @Override
  10. public void onLoadComplete() {
  11. // TODO Auto-generated method stub
  12.  
  13. }
  14.  
  15. @Override
  16. public Engine onLoadEngine() {
  17. // TODO Auto-generated method stub
  18. return null;
  19. }
  20.  
  21. @Override
  22. public void onLoadResources() {
  23. // TODO Auto-generated method stub
  24.  
  25. }
  26.  
  27. @Override
  28. public Scene onLoadScene() {
  29. // TODO Auto-generated method stub
  30. return null;
  31. }
  32. }
Parsed in 0.072 seconds at 8.45 KB/s, using GeSHi 1.0.8.10

Now let's change a little the file to make it clear.


Main.java
  1. import org.anddev.andengine.engine.Engine;
  2. import org.anddev.andengine.entity.scene.Scene;
  3. import org.anddev.andengine.ui.activity.BaseGameActivity;
  4.  
  5. public class Main extends BaseGameActivity {
  6. // ===========================================================
  7. // Constants
  8. // ===========================================================
  9.  
  10. // ===========================================================
  11. // Fields
  12. // ===========================================================
  13.  
  14. // ===========================================================
  15. // Constructors
  16. // ===========================================================
  17.  
  18. // ===========================================================
  19. // Getter & Setter
  20. // ===========================================================
  21.  
  22. // ===========================================================
  23. // Methods for/from SuperClass/Interfaces
  24. // ===========================================================
  25.  
  26. @Override
  27. public void onLoadComplete() {
  28. // TODO Auto-generated method stub
  29.  
  30. }
  31.  
  32. @Override
  33. public Engine onLoadEngine() {
  34. // TODO Auto-generated method stub
  35. return null;
  36. }
  37.  
  38. @Override
  39. public void onLoadResources() {
  40. // TODO Auto-generated method stub
  41.  
  42. }
  43.  
  44. @Override
  45. public Scene onLoadScene() {
  46. // TODO Auto-generated method stub
  47. return null;
  48. }
  49.  
  50. // ===========================================================
  51. // Methods
  52. // ===========================================================
  53.  
  54. // ===========================================================
  55. // Inner and Anonymous Classes
  56. // =========================================================== 
  57. }
  58.  
Parsed in 0.092 seconds at 17.27 KB/s, using GeSHi 1.0.8.10

Let's Start


Now we need a camera object to the proper view of the game. Let's create variables to define the screen resolution we are going to work for and a TAG variable for debugging purposes.

  1. // ===========================================================
  2. // Constants
  3. // ===========================================================
  4. static final int CAMERA_WIDTH = 480;
  5. static final int CAMERA_HEIGHT = 320;
  6.  
  7. private static final String TAG = "AndEngineTest";
  8.  
  9. // ===========================================================
  10. // Fields
  11. // ===========================================================
  12.  
  13. private ZoomCamera mCamera;
Parsed in 0.076 seconds at 5.72 KB/s, using GeSHi 1.0.8.10

Now let's write some code on the on the onLoadEngine() method.


  1. public Engine onLoadEngine() {
  2. this.mCamera = new ZoomCamera(0, 0, CAMERA_WIDTH, CAMERA_HEIGHT);
  3. return new Engine(new EngineOptions(true, ScreenOrientation.LANDSCAPE, new RatioResolutionPolicy(CAMERA_WIDTH, CAMERA_HEIGHT), this.mCamera));
  4. }
Parsed in 0.084 seconds at 2.84 KB/s, using GeSHi 1.0.8.10

We have a camera object now. Let's implement the method onLoadScene() and put some background color.

  1. @Override
  2. public Scene onLoadScene() {
  3. this.mEngine.registerUpdateHandler(new FPSLogger());
  4.  
  5. final Scene scene = new Scene(1);
  6. scene.setBackground(new ColorBackground(0, 0, 0.8784f));
  7.  
  8. return scene;
  9. }
Parsed in 0.076 seconds at 2.66 KB/s, using GeSHi 1.0.8.10

After organize imports and some organization...

  1. import org.anddev.andengine.engine.Engine;
  2. import org.anddev.andengine.engine.camera.ZoomCamera;
  3. import org.anddev.andengine.engine.options.EngineOptions;
  4. import org.anddev.andengine.engine.options.EngineOptions.ScreenOrientation;
  5. import org.anddev.andengine.engine.options.resolutionpolicy.RatioResolutionPolicy;
  6. import org.anddev.andengine.entity.scene.Scene;
  7. import org.anddev.andengine.entity.scene.background.ColorBackground;
  8. import org.anddev.andengine.entity.util.FPSLogger;
  9. import org.anddev.andengine.ui.activity.BaseGameActivity;
  10.  
  11. public class Main extends BaseGameActivity {
  12. // ===========================================================
  13. // Constants
  14. // ===========================================================
  15. static final int CAMERA_WIDTH = 480;
  16. static final int CAMERA_HEIGHT = 320;
  17.  
  18. private static final String TAG = "AndEngineTest";
  19.  
  20.  
  21. // ===========================================================
  22. // Fields
  23. // ===========================================================
  24.  
  25. private ZoomCamera mCamera;
  26.  
  27. // ===========================================================
  28. // Constructors
  29. // ===========================================================
  30.  
  31. // ===========================================================
  32. // Getter & Setter
  33. // ===========================================================
  34.  
  35. // ===========================================================
  36. // Methods for/from SuperClass/Interfaces
  37. // ===========================================================
  38.  
  39. @Override
  40. public void onLoadComplete() {
  41. // TODO Auto-generated method stub
  42.  
  43. }
  44.  
  45. @Override
  46. public Engine onLoadEngine() {
  47. this.mCamera = new ZoomCamera(0, 0, CAMERA_WIDTH, CAMERA_HEIGHT);
  48. return new Engine(new EngineOptions(true, ScreenOrientation.LANDSCAPE, new RatioResolutionPolicy(CAMERA_WIDTH, CAMERA_HEIGHT), this.mCamera));
  49. }
  50.  
  51. @Override
  52. public void onLoadResources() {
  53. // TODO Auto-generated method stub
  54.  
  55. }
  56.  
  57. @Override
  58. public Scene onLoadScene() {
  59. this.mEngine.registerUpdateHandler(new FPSLogger());
  60.  
  61. final Scene scene = new Scene(1);
  62. scene.setBackground(new ColorBackground(0, 0, 0.8784f));
  63.  
  64. return scene;
  65. }
  66.  
  67. // ===========================================================
  68. // Methods
  69. // ===========================================================
  70.  
  71. // ===========================================================
  72. // Inner and Anonymous Classes
  73. // =========================================================== 
  74. }
Parsed in 0.093 seconds at 26.05 KB/s, using GeSHi 1.0.8.10


Let's start the application to see a Background color. In the Top menu "Run" Configurations




Apply -> Run and now we see in the terminal our first AndEngine application.


This is the end of the first lesson in the series. In the second tutorial, we are gonna paint some objects in the screen, and implement scrolling with TouchEvents.

Source Code


To get the source code: svn checkout http://ch-soccer.googlecode.com/svn/trunk/ tutorial-read-only -r 3



Index

15 comments:

  1. eclipse throwing error
    [2011-03-31 00:55:17 - AndEngineTest] Error generating final archive: Found duplicate file for APK: AndroidManifest.xml
    Origin 1: C:\workspace\AndEngineTest\bin\resources.ap_
    Origin 2: C:\workspace\AndEngineTest\lib\andengine.jar

    ReplyDelete
  2. jar file includes another androidmanifest.xml files

    ReplyDelete
  3. I'm uploading my andengine.jar to mediafire to ensure we are all using the same .jar.

    The link is -> http://www.mediafire.com/?sz7xjjohbk3vo6o

    ReplyDelete
  4. Hey, thanks for the detailed examples.
    It seems that your donate button is broken. Could you check if it's ok? I'd love to donate couple of bucks for your efforts.
    Do email me when you have fixed the button, so I wont forget :)

    ReplyDelete
  5. Getting error

    Error generating final archive: Found duplicate file for APK: AndroidManifest.xml

    ReplyDelete
  6. I'm seeing a deprecation error around line 61 for:

    final Scene scene = new Scene(1);

    See http://www.andengine.org/forums/post17531.html for some relevant advice

    ReplyDelete
  7. I just used Scene() for the deprecated error.

    ReplyDelete
  8. This comment has been removed by the author.

    ReplyDelete
  9. public Engine onLoadEngine()
    {
    this.mCamera = new ZoomCamera(0,0, CAMERA_WIDTH, CAMERA_HEIGHT);
    return new Engine(new EngineOptions(true, ScreenOrientation.LANDSCAPE, new RatioResolutionPolicy(CAMERA_WIDTH, CAMERA_HEIGHT), this.mCamera));
    }

    Here, the error is
    "The constructor Engine(EngineOptions) is undefined"

    ReplyDelete
  10. asdasd make sure you have imported the Engine. Add this line under your last import statement :)

    import org.anddev.andengine.engine.Engine;

    ReplyDelete
  11. This comment has been removed by the author.

    ReplyDelete
  12. I'm getting a java.lang.RuntimeException: Unable to instantiate activity ComponentInfo
    Any ideas what i've done wrong?

    ReplyDelete
    Replies
    1. Problem solved.
      Just had to change the name of the folder from lib to libs :)

      Delete
  13. It's great to see a blog of this quality. I learned a lot of new things and I'm looking forward to see more like this. Thank you.
    website design

    ReplyDelete