2D tutorial

Tutorials concerning the OpenGL® ES cross-platform API for full-function 2D and 3D graphics on the Google-Android platform.

2D tutorial

Postby MrSnowflake » Sun Oct 12, 2008 5:42 pm

Hi guys,

I've made a simple 2D Game template. I created it so I could easilly create new games without doing a lot of redundant stuff. The code is fairly simple and not really suitable for big games (ie. the GameThread should probably be in a seperate file, the snowflake should actually be in a Sprite class, ...). But you get the idea for simple games.

It's based upon the LunarLander example in the SDK, but I remove all unnescessairy stuff, so you are left with an (almost) empty framework.
Attachments
GameTemplate.zip
GameTemple: Android 2D game template.
(18.09 KiB) Downloaded 13949 times
User avatar
MrSnowflake
Moderator
Moderator
 
Posts: 1439
Joined: Sat Feb 16, 2008 3:11 pm
Location: Flanders, Belgium

Top

Postby ninor » Sun Oct 12, 2008 7:16 pm

Thanks MrSnowFlake!

Mental note: I *must* develop a little game when I have some spare time
Image AndDev: Your Android Development Community / Tutorials | Here's my Basic ToolKit
User avatar
ninor
Moderator
Moderator
 
Posts: 180
Joined: Thu Aug 14, 2008 6:30 pm
Location: Barcelona, Spain

Postby Danuubz » Thu Oct 30, 2008 10:11 pm

I've got a litte code sample for 2D animating on a simple UI extending View (wich is a little bit different from the SurfaceView approach, more like J2SE).

Red box is moving from one edge to the other. You can stop (and restart) him by pressing DPAD_CENTER.

Syntax: [ Download ] [ Hide ]
Using java Syntax Highlighting
  1. // author: Robert Kanzamar
  2.  
  3. package de.testing;
  4.  
  5.  
  6.  
  7. import android.app.Activity;
  8.  
  9. import android.os.Bundle;
  10.  
  11. import android.view.*;
  12.  
  13. import android.graphics.*;
  14.  
  15. import android.content.*;
  16.  
  17.  
  18.  
  19. public class Testing extends Activity
  20.  
  21. {      
  22.  
  23.         public static final int DIRECTION_RIGHT = 0, DIRECTION_LEFT = 1;
  24.  
  25.        
  26.  
  27.         private Panel main;
  28.  
  29.         private Bitmap scratch;
  30.  
  31.         private Canvas offscreen;
  32.  
  33.        
  34.  
  35.         public boolean start = true;
  36.  
  37.         private volatile boolean running = true;
  38.  
  39.         private int direction = DIRECTION_RIGHT;
  40.  
  41.        
  42.  
  43.         private int box = 10;
  44.  
  45.        
  46.  
  47.     @Override
  48.  
  49.     public void onCreate(Bundle savedInstanceState)
  50.  
  51.     {
  52.  
  53.         super.onCreate(savedInstanceState);  
  54.  
  55.        
  56.  
  57.         setOffscreenBitmap();
  58.  
  59.        
  60.  
  61.         main = new Panel(this);        
  62.  
  63.         setContentView(main,new ViewGroup.LayoutParams(320,480));
  64.  
  65.        
  66.  
  67.         (new Thread(new AnimationLoop())).start();
  68.  
  69.     }
  70.  
  71.    
  72.  
  73.     private void setOffscreenBitmap()
  74.  
  75.     {
  76.  
  77.          scratch = Bitmap.createBitmap(30,30,Bitmap.Config.ARGB_8888);
  78.  
  79.          offscreen = new Canvas();
  80.  
  81.          offscreen.setBitmap(scratch);
  82.  
  83.          offscreen.drawColor(Color.RED);
  84.  
  85.     }
  86.  
  87.    
  88.  
  89.     private synchronized void updatePhysics()
  90.  
  91.     {
  92.  
  93.         if(box < 10)
  94.  
  95.         {
  96.  
  97.                 direction = DIRECTION_RIGHT;
  98.  
  99.         }
  100.  
  101.         else if(box > 250)
  102.  
  103.         {
  104.  
  105.                 direction = DIRECTION_LEFT;
  106.  
  107.         }
  108.  
  109.        
  110.  
  111.         if(direction == DIRECTION_RIGHT)
  112.  
  113.         {
  114.  
  115.                 box += 10;
  116.  
  117.         }
  118.  
  119.         else
  120.  
  121.         {
  122.  
  123.                 box -= 10;
  124.  
  125.         }
  126.  
  127.     }
  128.  
  129.    
  130.  
  131.     private synchronized void doDraw(Canvas canvas, Paint paint)
  132.  
  133.     {
  134.  
  135.         if(start)
  136.  
  137.                 {
  138.  
  139.                         canvas.drawColor(Color.BLACK);
  140.  
  141.                         canvas.drawBitmap(scratch,10,10,paint);
  142.  
  143.                         start = false;
  144.  
  145.                 }
  146.  
  147.                 else
  148.  
  149.                 {              
  150.  
  151.                 canvas.save();
  152.  
  153.                 canvas.clipRect(box,8,box+32,40);              
  154.  
  155.                 canvas.drawColor(Color.RED);
  156.  
  157.                 // canvas.drawBitmap(scratch,box,10,paint);
  158.  
  159.                 canvas.restore();              
  160.  
  161.                 }
  162.  
  163.     }
  164.  
  165.    
  166.  
  167.     @Override
  168.  
  169.     public boolean onKeyDown(int keyCode, KeyEvent event)
  170.  
  171.     {
  172.  
  173.         if(keyCode == KeyEvent.KEYCODE_DPAD_CENTER)
  174.  
  175.         {
  176.  
  177.                 if(running)
  178.  
  179.                 {
  180.  
  181.                         running = false;
  182.  
  183.                 }
  184.  
  185.                 else
  186.  
  187.                 {
  188.  
  189.                         running = true;
  190.  
  191.                 }
  192.  
  193.         }
  194.  
  195.         else if (keyCode == KeyEvent.KEYCODE_DPAD_DOWN)
  196.  
  197.         {
  198.  
  199.                 finish();
  200.  
  201.         }
  202.  
  203.        
  204.  
  205.         return true;
  206.  
  207.     }
  208.  
  209.    
  210.  
  211.     class Panel extends View
  212.  
  213.     {
  214.  
  215.         Paint paint;
  216.  
  217.        
  218.  
  219.         public Panel(Context context)
  220.  
  221.         {
  222.  
  223.                 super(context);
  224.  
  225.                 paint = new Paint();
  226.  
  227.         }
  228.  
  229.        
  230.  
  231.         @Override
  232.  
  233.         protected void onDraw(Canvas canvas)
  234.  
  235.         {
  236.  
  237.                 doDraw(canvas,paint);
  238.  
  239.         }
  240.  
  241.     }
  242.  
  243.    
  244.  
  245.     class AnimationLoop implements Runnable
  246.  
  247.     {
  248.  
  249.         public void run()
  250.  
  251.         {
  252.  
  253.                 while(true)
  254.  
  255.                 {
  256.  
  257.                         while(running)
  258.  
  259.                         {                                      
  260.  
  261.                                 try
  262.  
  263.                                 {
  264.  
  265.                                         Thread.sleep(30);
  266.  
  267.                                 }
  268.  
  269.                                 catch(InterruptedException ex) {}
  270.  
  271.                                
  272.  
  273.                                 updatePhysics();
  274.  
  275.                                 main.postInvalidate();
  276.  
  277.                         }
  278.  
  279.                 }
  280.  
  281.         }
  282.  
  283.     }    
  284.  
  285. }
Parsed in 0.044 seconds, using GeSHi 1.0.8.4
User avatar
Danuubz
Experienced Developer
Experienced Developer
 
Posts: 78
Joined: Wed Dec 19, 2007 10:44 pm
Location: Germany

Postby timcharper » Sat Nov 29, 2008 11:16 am

Is the view the best place to handle physics and game logic?
timcharper
Freshman
Freshman
 
Posts: 2
Joined: Sat Nov 29, 2008 5:25 am
Location: Utah

Postby Danuubz » Sat Nov 29, 2008 11:53 am

Actually, in this example, the view only handles drawings. Which is the best depends on what you want to do.
User avatar
Danuubz
Experienced Developer
Experienced Developer
 
Posts: 78
Joined: Wed Dec 19, 2007 10:44 pm
Location: Germany

Postby Croccy22 » Wed Dec 03, 2008 5:01 pm

Hi guys,

Can someone give me a piece of sample code that does the following:

I see in the code above where it places your png on the screen. Thats fine.

What I want to do is have a png that is 150 pixels wide and 50 pixels high. This png will acually be three frames of animation each that are 50x50 pixels.

What I want to do is copy a 50x50 part of that image and place it on the screen. So I can then have one image which contains several frames of animation.

If someone could just give me a piece of sample code just to do this, a couple of lines will do.

Thanks, Matt.
Croccy22
Developer
Developer
 
Posts: 31
Joined: Wed Dec 03, 2008 3:15 pm

Top

Postby MrSnowflake » Wed Dec 03, 2008 7:03 pm

You can use Canvas.drawBitmap() with the source rectangle being: (0, 0),(0, 50), (50, 50), (50,0) and then move it: (50, 0),(50, 50), (100, 50), (100,50).
Coordinates might be off, but you should ge the point (i guess).
User avatar
MrSnowflake
Moderator
Moderator
 
Posts: 1439
Joined: Sat Feb 16, 2008 3:11 pm
Location: Flanders, Belgium

Postby Croccy22 » Wed Dec 03, 2008 11:59 pm

Ok thanks for that. I've actually developed quie a few things for mobile phones before (do a google search for smartanoid) but I used to program on Windows Mobile, so now i'm just trying to work out the syntax for commands I need to use.

Just uploaded an app to the markey place (XmasCard, under apps/demos). I know it is really naff but it was just a test to see how everything tied together and how fast stuff would run. It consists of three alpha layers and 50 alpha sprites on screen at same time. Takes a while to load but I guess that is down to the size of the png files as they weren't very optomized.

Anyone else noticed the comments/ratings on market place are REALLY abusive, I know that they are mostly a bunch of low lifes who don' understand what android is about but I hope google sort it out soon!

Cheers, Matt.
Croccy22
Developer
Developer
 
Posts: 31
Joined: Wed Dec 03, 2008 3:15 pm

Postby Croccy22 » Thu Dec 04, 2008 9:17 pm

Can anyone give me an example of how I could incorporate reading of the accelerometer from within this template?

I have tried the example on this site but I guess they have updated how it works as the tutorial code doesn't seem to work anymore. There is a demo game that uses it but I have tried to 'borrow' the bits of code I need but although I got it to read the values it never seemed to update them.

If someone could give us a hand with this it would be much appreciated, I'll carry on trying myself and will post if I get it working.

Thanks, Matt.
Croccy22
Developer
Developer
 
Posts: 31
Joined: Wed Dec 03, 2008 3:15 pm

Postby MrSnowflake » Thu Dec 04, 2008 9:40 pm

There's an example in de samples dir of the SDK and the docs should also help you as there is not a lot to do.
User avatar
MrSnowflake
Moderator
Moderator
 
Posts: 1439
Joined: Sat Feb 16, 2008 3:11 pm
Location: Flanders, Belgium

Postby Croccy22 » Thu Dec 04, 2008 9:52 pm

Ok cheers,

I'm sure everything is there in my code but it's just not recieving the updates by the look of it. I'm new to java so still trying to get my head around the overall structure as I come from C++.

I'll take alook at the sdk.

Matt.
Croccy22
Developer
Developer
 
Posts: 31
Joined: Wed Dec 03, 2008 3:15 pm

Postby MrSnowflake » Thu Dec 04, 2008 10:27 pm

Do you have a G1?
User avatar
MrSnowflake
Moderator
Moderator
 
Posts: 1439
Joined: Sat Feb 16, 2008 3:11 pm
Location: Flanders, Belgium

Postby Croccy22 » Thu Dec 04, 2008 10:51 pm

Ok, just done it. And yes it was me being a class a muppet!!

For anyone else here is the code. It's the GameTemplate project but just displays the x,y,z of the accelerometer. People can chop and change as they wish.

Matt.

GameTemplate
Syntax: [ Download ] [ Hide ]
Using java Syntax Highlighting
  1.  
  2. package eu.MrSnowflake.android.gametemplate;
  3.  
  4.  
  5.  
  6. import android.app.Activity;
  7.  
  8. import android.hardware.SensorManager;
  9.  
  10. import android.os.Bundle;
  11.  
  12. import android.util.Log;
  13.  
  14. import android.view.Menu;
  15.  
  16. import android.view.MenuItem;
  17.  
  18. import android.view.Window;
  19.  
  20. import eu.MrSnowflake.android.gametemplate.GameView.GameThread;
  21.  
  22.  
  23.  
  24. public class GameTemplate extends Activity {
  25.  
  26.     private static final int MENU_PAUSE = Menu.FIRST;
  27.  
  28.     private static final int MENU_RESUME = Menu.FIRST + 1;
  29.  
  30.     private static final int MENU_START = Menu.FIRST + 2;
  31.  
  32.     private static final int MENU_STOP = Menu.FIRST + 3;
  33.  
  34.  
  35.  
  36.     private SensorManager mSensorManager;
  37.  
  38.    
  39.  
  40.     /** A handle to the thread that's actually running the animation. */
  41.  
  42.     private GameThread mGameThread;
  43.  
  44.  
  45.  
  46.     /** A handle to the View in which the game is running. */
  47.  
  48.     private GameView mGameView;
  49.  
  50.  
  51.  
  52.     /**
  53.  
  54.      * Invoked during init to give the Activity a chance to set up its Menu.
  55.  
  56.      *
  57.  
  58.      * @param menu the Menu to which entries may be added
  59.  
  60.      * @return true
  61.  
  62.      */
  63.  
  64.     @Override
  65.  
  66.     public boolean onCreateOptionsMenu(Menu menu) {
  67.  
  68.         super.onCreateOptionsMenu(menu);
  69.  
  70.  
  71.  
  72.         menu.add(0, MENU_START, 0, R.string.menu_start);
  73.  
  74.         menu.add(0, MENU_STOP, 0, R.string.menu_stop);
  75.  
  76.         menu.add(0, MENU_PAUSE, 0, R.string.menu_pause);
  77.  
  78.         menu.add(0, MENU_RESUME, 0, R.string.menu_resume);
  79.  
  80.  
  81.  
  82.         return true;
  83.  
  84.     }
  85.  
  86.  
  87.  
  88.     /**
  89.  
  90.      * Invoked when the user selects an item from the Menu.
  91.  
  92.      *
  93.  
  94.      * @param item the Menu entry which was selected
  95.  
  96.      * @return true if the Menu item was legit (and we consumed it), false
  97.  
  98.      *         otherwise
  99.  
  100.      */
  101.  
  102.     @Override
  103.  
  104.     public boolean onOptionsItemSelected(MenuItem item) {
  105.  
  106.         switch (item.getItemId()) {
  107.  
  108.             case MENU_START:
  109.  
  110.                 mGameThread.doStart();
  111.  
  112.                 return true;
  113.  
  114.             case MENU_STOP:
  115.  
  116.                 mGameThread.setState(GameThread.STATE_LOSE);
  117.  
  118.                 return true;
  119.  
  120.             case MENU_PAUSE:
  121.  
  122.                 mGameThread.pause();
  123.  
  124.                 return true;
  125.  
  126.             case MENU_RESUME:
  127.  
  128.                 mGameThread.unpause();
  129.  
  130.                 return true;
  131.  
  132.         }
  133.  
  134.  
  135.  
  136.         return false;
  137.  
  138.     }
  139.  
  140.  
  141.  
  142.     /**
  143.  
  144.      * Invoked when the Activity is created.
  145.  
  146.      *
  147.  
  148.      * @param savedInstanceState a Bundle containing state saved from a previous
  149.  
  150.      *        execution, or null if this is a new execution
  151.  
  152.      */
  153.  
  154.     @Override
  155.  
  156.     protected void onCreate(Bundle savedInstanceState) {
  157.  
  158.         super.onCreate(savedInstanceState);
  159.  
  160.  
  161.  
  162.         // turn off the window's title bar
  163.  
  164.         requestWindowFeature(Window.FEATURE_NO_TITLE);
  165.  
  166.  
  167.  
  168.         // tell system to use the layout defined in our XML file
  169.  
  170.         setContentView(R.layout.main);
  171.  
  172.  
  173.  
  174.         // get handles to the LunarView from XML, and its LunarThread
  175.  
  176.         mGameView = (GameView) findViewById(R.id.game);
  177.  
  178.         mGameThread = mGameView.getThread();
  179.  
  180.  
  181.  
  182.         // set up a new game
  183.  
  184.         mGameThread.setState(GameThread.STATE_READY);
  185.  
  186.         Log.w(this.getClass().getName(), "SIS is null");
  187.  
  188.        
  189.  
  190.         mSensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
  191.  
  192.         mSensorManager.registerListener(mGameThread, SensorManager.SENSOR_ACCELEROMETER);
  193.  
  194.  
  195.  
  196.     }
  197.  
  198.  
  199.  
  200.     /**
  201.  
  202.      * Invoked when the Activity loses user focus.
  203.  
  204.      */
  205.  
  206.     @Override
  207.  
  208.     protected void onPause() {
  209.  
  210.         super.onPause();
  211.  
  212.         mGameView.getThread().pause(); // pause game when Activity pauses
  213.  
  214.     }
  215.  
  216. }
  217.  
  218.  
Parsed in 0.043 seconds, using GeSHi 1.0.8.4


GameThread
Syntax: [ Download ] [ Hide ]
Using java Syntax Highlighting
  1.  
  2. package eu.MrSnowflake.android.gametemplate;
  3.  
  4.  
  5.  
  6. import android.content.Context;
  7.  
  8. import android.graphics.Bitmap;
  9.  
  10. import android.graphics.BitmapFactory;
  11.  
  12. import android.graphics.Canvas;
  13.  
  14. import android.graphics.Paint;
  15.  
  16. import android.hardware.SensorListener;
  17.  
  18. import android.hardware.SensorManager;
  19.  
  20. import android.os.Bundle;
  21.  
  22. import android.os.Handler;
  23.  
  24. import android.os.Message;
  25.  
  26. import android.util.AttributeSet;
  27.  
  28. import android.util.Log;
  29.  
  30. import android.view.KeyEvent;
  31.  
  32. import android.view.SurfaceHolder;
  33.  
  34. import android.view.SurfaceView;
  35.  
  36. import android.view.View;
  37.  
  38. import android.widget.TextView;
  39.  
  40.  
  41.  
  42. /**
  43.  
  44.  * View that draws, takes keystrokes, etc. for a simple LunarLander game.
  45.  
  46.  *
  47.  
  48.  * Has a mode which RUNNING, PAUSED, etc. Has a x, y, dx, dy, ... capturing the
  49.  
  50.  * current ship physics. All x/y etc. are measured with (0,0) at the lower left.
  51.  
  52.  * updatePhysics() advances the physics based on realtime. draw() renders the
  53.  
  54.  * ship, and does an invalidate() to prompt another draw() as soon as possible
  55.  
  56.  * by the system.
  57.  
  58.  */
  59.  
  60. class GameView extends SurfaceView implements SurfaceHolder.Callback {
  61.  
  62.         class GameThread extends Thread implements SensorListener{
  63.  
  64.         /*
  65.  
  66.          * State-tracking constants
  67.  
  68.          */
  69.  
  70.         public static final int STATE_LOSE = 1;
  71.  
  72.         public static final int STATE_PAUSE = 2;
  73.  
  74.         public static final int STATE_READY = 3;
  75.  
  76.         public static final int STATE_RUNNING = 4;
  77.  
  78.         public static final int STATE_WIN = 5;
  79.  
  80.        
  81.  
  82.         private float x;
  83.  
  84.         private float y;
  85.  
  86.        
  87.  
  88.         private static final int SPEED = 100;
  89.  
  90.         private boolean dRight;
  91.  
  92.         private boolean dLeft;
  93.  
  94.         private boolean dUp;
  95.  
  96.         private boolean dDown;
  97.  
  98.        
  99.  
  100.         private int mCanvasWidth;
  101.  
  102.         private int mCanvasHeight;
  103.  
  104.  
  105.  
  106.         private long mLastTime;
  107.  
  108.         private Bitmap mSnowflake;
  109.  
  110.        
  111.  
  112.        
  113.  
  114.         float sensorx;
  115.  
  116.         float sensory;
  117.  
  118.         float sensorz;
  119.  
  120.        
  121.  
  122.         public void onSensorChanged(int sensor, float[] values) {
  123.  
  124.             sensorx = values[0];
  125.  
  126.             sensory = values[1];
  127.  
  128.             sensorz = values[2];
  129.  
  130.         }
  131.  
  132.        
  133.  
  134.         public void onAccuracyChanged(int sensor, int accuracy) {
  135.  
  136.             // TODO Auto-generated method stub      
  137.  
  138.         }
  139.  
  140.        
  141.  
  142.          /** Message handler used by thread to post stuff back to the GameView */
  143.  
  144.         private Handler mHandler;
  145.  
  146.  
  147.  
  148.          /** The state of the game. One of READY, RUNNING, PAUSE, LOSE, or WIN */
  149.  
  150.         private int mMode;
  151.  
  152.         /** Indicate whether the surface has been created & is ready to draw */
  153.  
  154.         private boolean mRun = false;
  155.  
  156.         /** Handle to the surface manager object we interact with */
  157.  
  158.         private SurfaceHolder mSurfaceHolder;
  159.  
  160.  
  161.  
  162.         public GameThread(SurfaceHolder surfaceHolder, Context context,
  163.  
  164.                 Handler handler) {
  165.  
  166.             // get handles to some important objects
  167.  
  168.             mSurfaceHolder = surfaceHolder;
  169.  
  170.             mHandler = handler;
  171.  
  172.             mContext = context;
  173.  
  174.                
  175.  
  176.             x = 10;
  177.  
  178.             y = 10;
  179.  
  180.            
  181.  
  182.                 mSnowflake = BitmapFactory.decodeResource(mContext.getResources(), R.drawable.snowflake);
  183.  
  184.                
  185.  
  186.         }
  187.  
  188.  
  189.  
  190.         /**
  191.  
  192.          * Starts the game, setting parameters for the current difficulty.
  193.  
  194.          */
  195.  
  196.         public void doStart() {
  197.  
  198.             synchronized (mSurfaceHolder) {
  199.  
  200.                 // Initialize game here!
  201.  
  202.                
  203.  
  204.                 x = 10;
  205.  
  206.                 y = 10;
  207.  
  208.                
  209.  
  210.                 mLastTime = System.currentTimeMillis() + 100;
  211.  
  212.                 setState(STATE_RUNNING);
  213.  
  214.             }
  215.  
  216.         }
  217.  
  218.  
  219.  
  220.         /**
  221.  
  222.          * Pauses the physics update & animation.
  223.  
  224.          */
  225.  
  226.         public void pause() {
  227.  
  228.             synchronized (mSurfaceHolder) {
  229.  
  230.                 if (mMode == STATE_RUNNING)
  231.  
  232.                         setState(STATE_PAUSE);
  233.  
  234.             }
  235.  
  236.         }      
  237.  
  238.         @Override
  239.  
  240.         public void run() {
  241.  
  242.             while (mRun) {
  243.  
  244.                 Canvas c = null;
  245.  
  246.                 try {
  247.  
  248.                     c = mSurfaceHolder.lockCanvas(null);
  249.  
  250.                     synchronized (mSurfaceHolder) {
  251.  
  252.                         if (mMode == STATE_RUNNING)
  253.  
  254.                                 updateGame();
  255.  
  256.                         doDraw(c);
  257.  
  258.                     }
  259.  
  260.                 } finally {
  261.  
  262.                     // do this in a finally so that if an exception is thrown
  263.  
  264.                     // during the above, we don't leave the Surface in an
  265.  
  266.                     // inconsistent state
  267.  
  268.                     if (c != null) {
  269.  
  270.                         mSurfaceHolder.unlockCanvasAndPost(c);
  271.  
  272.                     }
  273.  
  274.                 }
  275.  
  276.             }
  277.  
  278.         }
  279.  
  280.  
  281.  
  282.         /**
  283.  
  284.          * Used to signal the thread whether it should be running or not.
  285.  
  286.          * Passing true allows the thread to run; passing false will shut it
  287.  
  288.          * down if it's already running. Calling start() after this was most
  289.  
  290.          * recently called with false will result in an immediate shutdown.
  291.  
  292.          *
  293.  
  294.          * @param b true to run, false to shut down
  295.  
  296.          */
  297.  
  298.         public void setRunning(boolean b) {
  299.  
  300.             mRun = b;
  301.  
  302.         }
  303.  
  304.  
  305.  
  306.         /**
  307.  
  308.          * Sets the game mode. That is, whether we are running, paused, in the
  309.  
  310.          * failure state, in the victory state, etc.
  311.  
  312.          *
  313.  
  314.          * @see #setState(int, CharSequence)
  315.  
  316.          * @param mode one of the STATE_* constants
  317.  
  318.          */
  319.  
  320.         public void setState(int mode) {
  321.  
  322.             synchronized (mSurfaceHolder) {
  323.  
  324.                 setState(mode, null);
  325.  
  326.             }
  327.  
  328.         }
  329.  
  330.  
  331.  
  332.         /**
  333.  
  334.          * Sets the game mode. That is, whether we are running, paused, in the
  335.  
  336.          * failure state, in the victory state, etc.
  337.  
  338.          *
  339.  
  340.          * @param mode one of the STATE_* constants
  341.  
  342.          * @param message string to add to screen or null
  343.  
  344.          */
  345.  
  346.         public void setState(int mode, CharSequence message) {
  347.  
  348.             synchronized (mSurfaceHolder) {
  349.  
  350.                 mMode = mode;
  351.  
  352.             }
  353.  
  354.         }
  355.  
  356.  
  357.  
  358.         /* Callback invoked when the surface dimensions change. */
  359.  
  360.         public void setSurfaceSize(int width, int height) {
  361.  
  362.             // synchronized to make sure these all change atomically
  363.  
  364.             synchronized (mSurfaceHolder) {
  365.  
  366.                 mCanvasWidth = width;
  367.  
  368.                 mCanvasHeight = height;
  369.  
  370.             }
  371.  
  372.         }
  373.  
  374.  
  375.  
  376.         /**
  377.  
  378.          * Resumes from a pause.
  379.  
  380.          */
  381.  
  382.         public void unpause() {
  383.  
  384.             // Move the real time clock up to now
  385.  
  386.             synchronized (mSurfaceHolder) {
  387.  
  388.                 mLastTime = System.currentTimeMillis() + 100;
  389.  
  390.             }
  391.  
  392.             setState(STATE_RUNNING);
  393.  
  394.         }
  395.  
  396.  
  397.  
  398.         /**
  399.  
  400.          * Handles a key-down event.
  401.  
  402.          *
  403.  
  404.          * @param keyCode the key that was pressed
  405.  
  406.          * @param msg the original event object
  407.  
  408.          * @return true
  409.  
  410.          */
  411.  
  412.         boolean doKeyDown(int keyCode, KeyEvent msg) {
  413.  
  414.                 boolean handled = false;
  415.  
  416.             synchronized (mSurfaceHolder) {
  417.  
  418.                 if (keyCode == KeyEvent.KEYCODE_DPAD_RIGHT){
  419.  
  420.                         dRight = true;
  421.  
  422.                         handled = true;
  423.  
  424.                 }
  425.  
  426.                 if (keyCode == KeyEvent.KEYCODE_DPAD_LEFT){
  427.  
  428.                         dLeft = true;
  429.  
  430.                         handled = true;
  431.  
  432.                 }
  433.  
  434.                 if (keyCode == KeyEvent.KEYCODE_DPAD_UP){
  435.  
  436.                         dUp = true;
  437.  
  438.                         handled = true;
  439.  
  440.                 }
  441.  
  442.                 if (keyCode == KeyEvent.KEYCODE_DPAD_DOWN){
  443.  
  444.                         dDown = true;
  445.  
  446.                         handled = true;
  447.  
  448.                 }
  449.  
  450.                 return handled;
  451.  
  452.             }
  453.  
  454.         }
  455.  
  456.  
  457.  
  458.         /**
  459.  
  460.          * Handles a key-up event.
  461.  
  462.          *
  463.  
  464.          * @param keyCode the key that was pressed
  465.  
  466.          * @param msg the original event object
  467.  
  468.          * @return true if the key was handled and consumed, or else false
  469.  
  470.          */
  471.  
  472.         boolean doKeyUp(int keyCode, KeyEvent msg) {
  473.  
  474.                 boolean handled = false;
  475.  
  476.             synchronized (mSurfaceHolder) {
  477.  
  478.                 if (keyCode == KeyEvent.KEYCODE_DPAD_RIGHT){
  479.  
  480.                         dRight = false;
  481.  
  482.                         handled = true;
  483.  
  484.                 }
  485.  
  486.                 if (keyCode == KeyEvent.KEYCODE_DPAD_LEFT){
  487.  
  488.                         dLeft = false;
  489.  
  490.                         handled = true;
  491.  
  492.                 }
  493.  
  494.                 if (keyCode == KeyEvent.KEYCODE_DPAD_UP){
  495.  
  496.                         dUp = false;
  497.  
  498.                         handled = true;
  499.  
  500.                 }
  501.  
  502.                 if (keyCode == KeyEvent.KEYCODE_DPAD_DOWN){
  503.  
  504.                         dDown = false;
  505.  
  506.                         handled = true;
  507.  
  508.                 }
  509.  
  510.                 return handled;
  511.  
  512.             }
  513.  
  514.         }
  515.  
  516.  
  517.  
  518.         /**
  519.  
  520.          * Draws the ship, fuel/speed bars, and background to the provided
  521.  
  522.          * Canvas.
  523.  
  524.          */
  525.  
  526.         private void doDraw(Canvas canvas) {
  527.  
  528.                 // empty canvas
  529.  
  530.                 canvas.drawARGB(255, 128, 128, 128);
  531.  
  532.                
  533.  
  534.                 canvas.drawBitmap(mSnowflake, x, y, new Paint());
  535.  
  536.                 canvas.drawText(Float.toString(sensorx), 20, 100, new Paint());
  537.  
  538.                 canvas.drawText(Float.toString(sensory), 20, 150, new Paint());
  539.  
  540.                 canvas.drawText(Float.toString(sensorz), 20, 200, new Paint());
  541.  
  542.         }
  543.  
  544.  
  545.  
  546.         /**
  547.  
  548.          * Updates the game.
  549.  
  550.          */
  551.  
  552.         private void updateGame() {
  553.  
  554.                 //// <DoNotRemove>
  555.  
  556.             long now = System.currentTimeMillis();
  557.  
  558.             // Do nothing if mLastTime is in the future.
  559.  
  560.             // This allows the game-start to delay the start of the physics
  561.  
  562.             // by 100ms or whatever.
  563.  
  564.             if (mLastTime > now)
  565.  
  566.                 return;
  567.  
  568.             double elapsed = (now - mLastTime) / 1000.0;
  569.  
  570.             mLastTime = now;
  571.  
  572.             //// </DoNotRemove>
  573.  
  574.            
  575.  
  576.             /*
  577.  
  578.              * Why use mLastTime, now and elapsed?
  579.  
  580.              * Well, because the frame rate isn't always constant, it could happen your normal frame rate is 25fps
  581.  
  582.              * then your char will walk at a steady pace, but when your frame rate drops to say 12fps, without elapsed
  583.  
  584.              * your character will only walk half as fast as at the 25fps frame rate. Elapsed lets you manage the slowdowns
  585.  
  586.              * and speedups!
  587.  
  588.              */
  589.  
  590.  
  591.  
  592.             if (dUp)
  593.  
  594.                 y -= elapsed * SPEED;
  595.  
  596.             if (dDown)
  597.  
  598.                 y += elapsed * SPEED;
  599.  
  600.             if (y < 0)
  601.  
  602.                 y = 0;
  603.  
  604.             else if (y >= mCanvasHeight - mSnowflake.getHeight())
  605.  
  606.                 y = mCanvasHeight - mSnowflake.getHeight();
  607.  
  608.             if (dLeft)
  609.  
  610.                 x -= elapsed * SPEED;
  611.  
  612.             if (dRight)
  613.  
  614.                 x += elapsed * SPEED;
  615.  
  616.             if (x < 0)
  617.  
  618.                 x = 0;
  619.  
  620.             else if (x >= mCanvasWidth - mSnowflake.getWidth())
  621.  
  622.                 x = mCanvasWidth - mSnowflake.getWidth();
  623.  
  624.         }
  625.  
  626.     }
  627.  
  628.  
  629.  
  630.     /** Handle to the application context, used to e.g. fetch Drawables. */
  631.  
  632.     private Context mContext;
  633.  
  634.  
  635.  
  636.     /** The thread that actually draws the animation */
  637.  
  638.     private GameThread thread;
  639.  
  640.  
  641.  
  642.     public GameView(Context context, AttributeSet attrs) {
  643.  
  644.         super(context, attrs);
  645.  
  646.  
  647.  
  648.         // register our interest in hearing about changes to our surface
  649.  
  650.         SurfaceHolder holder = getHolder();
  651.  
  652.         holder.addCallback(this);
  653.  
  654.  
  655.  
  656.         // create thread only; it's started in surfaceCreated()
  657.  
  658.         thread = new GameThread(holder, context, new Handler() {
  659.  
  660.             @Override
  661.  
  662.             public void handleMessage(Message m) {
  663.  
  664.                 // Use for pushing back messages.
  665.  
  666.             }
  667.  
  668.         });
  669.  
  670.  
  671.  
  672.         setFocusable(true); // make sure we get key events
  673.  
  674.     }
  675.  
  676.  
  677.  
  678.     /**
  679.  
  680.      * Fetches the animation thread corresponding to this LunarView.
  681.  
  682.      *
  683.  
  684.      * @return the animation thread
  685.  
  686.      */
  687.  
  688.     public GameThread getThread() {
  689.  
  690.         return thread;
  691.  
  692.     }
  693.  
  694.  
  695.  
  696.     /**
  697.  
  698.      * Standard override to get key-press events.
  699.  
  700.      */
  701.  
  702.     @Override
  703.  
  704.     public boolean onKeyDown(int keyCode, KeyEvent msg) {
  705.  
  706.         return thread.doKeyDown(keyCode, msg);
  707.  
  708.     }
  709.  
  710.  
  711.  
  712.     /**
  713.  
  714.      * Standard override for key-up. We actually care about these, so we can
  715.  
  716.      * turn off the engine or stop rotating.
  717.  
  718.      */
  719.  
  720.     @Override
  721.  
  722.     public boolean onKeyUp(int keyCode, KeyEvent msg) {
  723.  
  724.         return thread.doKeyUp(keyCode, msg);
  725.  
  726.     }
  727.  
  728.  
  729.  
  730.     /**
  731.  
  732.      * Standard window-focus override. Notice focus lost so we can pause on
  733.  
  734.      * focus lost. e.g. user switches to take a call.
  735.  
  736.      */
  737.  
  738.     @Override
  739.  
  740.     public void onWindowFocusChanged(boolean hasWindowFocus) {
  741.  
  742.         if (!hasWindowFocus)
  743.  
  744.                 thread.pause();
  745.  
  746.     }
  747.  
  748.  
  749.  
  750.     /* Callback invoked when the surface dimensions change. */
  751.  
  752.     public void surfaceChanged(SurfaceHolder holder, int format, int width,
  753.  
  754.             int height) {
  755.  
  756.         thread.setSurfaceSize(width, height);
  757.  
  758.     }
  759.  
  760.  
  761.  
  762.     /*
  763.  
  764.      * Callback invoked when the Surface has been created and is ready to be
  765.  
  766.      * used.
  767.  
  768.      */
  769.  
  770.     public void surfaceCreated(SurfaceHolder holder) {
  771.  
  772.         // start the thread here so that we don't busy-wait in run()
  773.  
  774.         // waiting for the surface to be created
  775.  
  776.         thread.setRunning(true);
  777.  
  778.         thread.start();
  779.  
  780.     }
  781.  
  782.  
  783.  
  784.     /*
  785.  
  786.      * Callback invoked when the Surface has been destroyed and must no longer
  787.  
  788.      * be touched. WARNING: after this method returns, the Surface/Canvas must
  789.  
  790.      * never be touched again!
  791.  
  792.      */
  793.  
  794.     public void surfaceDestroyed(SurfaceHolder holder) {
  795.  
  796.         // we have to tell thread to shut down & wait for it to finish, or else
  797.  
  798.         // it might touch the Surface after we return and explode
  799.  
  800.         boolean retry = true;
  801.  
  802.         thread.setRunning(false);
  803.  
  804.         while (retry) {
  805.  
  806.             try {
  807.  
  808.                 thread.join();
  809.  
  810.                 retry = false;
  811.  
  812.             } catch (InterruptedException e) {
  813.  
  814.             }
  815.  
  816.         }
  817.  
  818.     }
  819.  
  820. }
  821.  
  822.  
Parsed in 0.079 seconds, using GeSHi 1.0.8.4
Croccy22
Developer
Developer
 
Posts: 31
Joined: Wed Dec 03, 2008 3:15 pm

Postby chefgon » Tue Dec 23, 2008 12:07 am

I tried throwing several PNGs on the screen and it works pretty well, when it loads. But after loading it up once and then exiting and loading again, I always get "Force Close" errors for the next two or three times I try to load it until it will work again, and then sometimes it doesn't load quite right.

Any idea what's going on? Is there something in here that isn't suitable for a large number of sprites? I've noticed that there's no logic to prevent it from restarting every time it loses focus (or the keyboard opens), is it possible I'm leaking memory somewhere? I just find it weird that it always works the first time but gets unreliable after that.
chefgon
Junior Developer
Junior Developer
 
Posts: 17
Joined: Fri Oct 31, 2008 8:26 pm

Postby Danuubz » Tue Dec 23, 2008 9:27 am

How do you exit the application?

It sounds like you press 'HOME' button or maybe 'Back'. I would use System.exit(0) for this.
Sticky Note Cork&Orc [Android Market] : http://www.youtube.com/watch?v=ewWaquAwZQY
User avatar
Danuubz
Experienced Developer
Experienced Developer
 
Posts: 78
Joined: Wed Dec 19, 2007 10:44 pm
Location: Germany

Top
Next

Return to Android 2D/3D Graphics - OpenGL Tutorials

Who is online

Users browsing this forum: No registered users and 2 guests