2010-07-06 6 views
0

Hey tout, cela est tout à fait un problème compliqué pour moi que j'ai essayé de trouver pendant un certain temps maintenant. Même expliquer c'est un peu difficile pour moi mais je vais essayer.problème étrange avec Android exemple Serpent modifié

J'utilise une version vidées de l'échantillon Android Serpent. À peu près, j'utilise la classe verbile de TileView et j'essaie seulement d'afficher quelques carreaux sur l'écran. Au lieu de la classe SnakeView, j'utilise une classe GameView dans laquelle je n'ai inclus que le code que je pensais nécessaire pour afficher une tuile sur l'écran. Voici la classe

public class GameView extends TileView { 

    /** 
    * Labels for the drawables that will be loaded into the TileView class 
    */ 
    private static final int RED_STAR = 1; 
    private static final int YELLOW_STAR = 2; 
    private static final int GREEN_STAR = 3; 

    /** 
    * mMoveDelay: number of milliseconds between animations. 
    */ 
    private long mMoveDelay = 600; 
    /** 
    * mLastMove: tracks the absolute time when the last animation happened. 
    */ 
    private long mLastMove; 

    /** 
    * Create a simple handler that we can use to cause animation to happen. We 
    * set ourselves as a target and we can use the sleep() 
    * function to cause an update/invalidate to occur at a later date. 
    */ 
    private RefreshHandler mRedrawHandler = new RefreshHandler(); 

    class RefreshHandler extends Handler { 

     @Override 
     public void handleMessage(Message msg) { 
      GameView.this.update(); 
      GameView.this.invalidate(); 
     } 

     public void sleep(long delayMillis) { 
      this.removeMessages(0); 
      sendMessageDelayed(obtainMessage(0), delayMillis); 
     } 
    }; 

    /** 
    * Constructs a GameView based on inflation from XML 
    * 
    * @param context 
    * @param attrs 
    */ 
    public GameView(Context context, AttributeSet attrs) { 
     super(context, attrs); 
     initGameView(); 
    } 

    public GameView(Context context, AttributeSet attrs, int defStyle) { 
     super(context, attrs, defStyle); 
     initGameView(); 
    } 

    private void initGameView() { 
     setFocusable(true); 

     Resources r = this.getContext().getResources(); 

     resetTiles(4); 
     loadTile(RED_STAR, r.getDrawable(R.drawable.redstar)); 
     loadTile(YELLOW_STAR, r.getDrawable(R.drawable.yellowstar)); 
     loadTile(GREEN_STAR, r.getDrawable(R.drawable.greenstar)); 

    } 

    public void initNewGame() {  
     // set the move delay. This tells the update method how often it should 
     // refresh the screen. 
     mMoveDelay = 600; 

     update(); 
    } 

    public void update() { 
     long now = System.currentTimeMillis(); 

     if (now - mLastMove > mMoveDelay) { 
      // clear any tiles on the screen 
      clearTiles(); 

      updateWalls(); 

      // draws the tiles storred in mCellularArray 
      //updateCellularArray(); 

      mLastMove = now; 
     } 
     mRedrawHandler.sleep(mMoveDelay); 

    } 

    private void updateWalls() { 
     for (int x = 0; x < mXTileCount; x++) { 
      setTile(GREEN_STAR, x, 0); 
      setTile(GREEN_STAR, x, mYTileCount - 1); 
     } 
     for (int y = 1; y < mYTileCount - 1; y++) { 
      setTile(GREEN_STAR, 0, y); 
      setTile(GREEN_STAR, mXTileCount - 1, y); 
     } 
    } 

    private void updateCellularArray() { 
     setTile(YELLOW_STAR, 6, 7); 
    } 
} 

Maintenant, ce qui se passe est que lorsque la méthode updateWalls() est appelée, les tuiles sont placées dans la vue et vient comme ça:

alt text

Maintenant, quand Je décommenter la méthode updateCellularArray() et commenter le updateWalls() la force du programme se ferme et lève une exception NullPointerException. Après un débogage, j'ai compris que lorsque la méthode de tableau updateCellular est appelée, le tableau mTileGrid de la classe TileView n'est pas initialisé, mais c'est quand updateWalls() est appelé. Je suis complètement déconcerté de savoir pourquoi cela se produit. Ce n'est pas grave si je remplace la boucle for avec un simple setTile(GREEN_STAR, 3, 3); il ferme toujours la force.

Voici la classe TileView J'utilise (encore une fois c'est le même dans l'échantillon serpent qui est livré avec le SDK Android):

/** 
* TileView: a View-variant designed for handling arrays of "icons" or other 
* drawables. 
* 
*/ 
public class TileView extends View { 

    /** 
    * Parameters controlling the size of the tiles and their range within view. 
    * Width/Height are in pixels, and Drawables will be scaled to fit to these 
    * dimensions. X/Y Tile Counts are the number of tiles that will be drawn. 
    */ 

    protected static int mTileSize; 

    protected static int mXTileCount; 
    protected static int mYTileCount; 

    private static int mXOffset; 
    private static int mYOffset; 


    /** 
    * A hash that maps integer handles specified by the subclasser to the 
    * drawable that will be used for that reference 
    */ 
    private Bitmap[] mTileArray; 

    /** 
    * A two-dimensional array of integers in which the number represents the 
    * index of the tile that should be drawn at that locations 
    */ 
    private int[][] mTileGrid; 

    private final Paint mPaint = new Paint(); 

    public TileView(Context context, AttributeSet attrs, int defStyle) { 
     super(context, attrs, defStyle); 

     TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.TileView); 

     mTileSize = a.getInt(R.styleable.TileView_tileSize, 12); 

     a.recycle(); 
    } 

    public TileView(Context context, AttributeSet attrs) { 
     super(context, attrs); 

     TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.TileView); 

     mTileSize = a.getInt(R.styleable.TileView_tileSize, 12); 

     a.recycle(); 
    } 



    /** 
    * Rests the internal array of Bitmaps used for drawing tiles, and 
    * sets the maximum index of tiles to be inserted 
    * 
    * @param tilecount 
    */ 

    public void resetTiles(int tilecount) { 
    mTileArray = new Bitmap[tilecount]; 
    } 


    @Override 
    protected void onSizeChanged(int w, int h, int oldw, int oldh) { 
     mXTileCount = (int) Math.floor(w/mTileSize); 
     mYTileCount = (int) Math.floor(h/mTileSize); 

     mXOffset = ((w - (mTileSize * mXTileCount))/2); 
     mYOffset = ((h - (mTileSize * mYTileCount))/2); 

     Log.d("Tomek", "TileGrid array dimensions are: " + mXTileCount + "," + mYTileCount); 
     mTileGrid = new int[mXTileCount][mYTileCount]; 
     clearTiles(); 
    } 

    /** 
    * Function to set the specified Drawable as the tile for a particular 
    * integer key. 
    * 
    * @param key 
    * @param tile 
    */ 
    public void loadTile(int key, Drawable tile) { 
     Bitmap bitmap = Bitmap.createBitmap(mTileSize, mTileSize, Bitmap.Config.ARGB_8888); 
     Canvas canvas = new Canvas(bitmap); 
     tile.setBounds(0, 0, mTileSize, mTileSize); 
     tile.draw(canvas); 

     mTileArray[key] = bitmap; 
    } 

    /** 
    * Resets all tiles to 0 (empty) 
    * 
    */ 
    public void clearTiles() { 
     for (int x = 0; x < mXTileCount; x++) { 
      for (int y = 0; y < mYTileCount; y++) { 
       setTile(0, x, y); 
      } 
     } 
    } 

    /** 
    * Used to indicate that a particular tile (set with loadTile and referenced 
    * by an integer) should be drawn at the given x/y coordinates during the 
    * next invalidate/draw cycle. 
    * 
    * @param tileindex 
    * @param x 
    * @param y 
    */ 
    public void setTile(int tileindex, int x, int y) { 
    //Log.d("Tomek", "Attempting to set tile: " + x + "," + y); 
    //Log.d("Tomek", "The current value at " + x + "," + y + " is " + mTileGrid[x][y]); 
    //Log.d("Tomek", "It will be changed to " + tileindex); 
     mTileGrid[x][y] = tileindex; 
    } 


    @Override 
    public void onDraw(Canvas canvas) { 
     super.onDraw(canvas); 
     for (int x = 0; x < mXTileCount; x += 1) { 
      for (int y = 0; y < mYTileCount; y += 1) { 
       if (mTileGrid[x][y] > 0) { 
        canvas.drawBitmap(mTileArray[mTileGrid[x][y]], 
         mXOffset + x * mTileSize, 
         mYOffset + y * mTileSize, 
         mPaint); 
       } 
      } 
     } 

    } 

} 

Désolé pour l'affichage tout ce code. Toute aide serait grandement appréciée.

Merci beaucoup,

Tomek

EDIT: simplifié Gameview classe

EDIT 2: D'accord après avoir modifié la méthode updateCellularArray() à ce qui suit:

private void updateCellularArray() { 
    for (int x = 0; x < mXTileCount; x++) { 
     setTile(GREEN_STAR, 12, 12); 
    } 
} 

Il a finalement placé la tuile où je le voulais ... alt text http://img188.imageshack.us/img188/1148/device2z.png

Je commence à me demander si cela a quelque chose à voir avec RefreshHandler. Éventuellement lorsque la méthode Sleep de RedrawHandler est appelée dans la méthode de mise à jour de la classe GameView. Je ne suis pas tout à fait sûr comment cela fonctionne donc je vais essayer de jouer avec et voir ce que je peux arriver.

Répondre

1

J'ai oublié de instancier la variable mLastMove. La modification de la déclaration à:

private long mLastMove = System.currentTimeMillis(); 

a permis de résoudre le problème.

Il semble également que la méthode utilisée avec le RefreshHandler, bien intelligent, est obsolète? Constaté que avec ce post:

http://www.mail-archive.com/[email protected]/msg07352.html

Tomek