1
votes

I am getting astrange effect with invalidate(Rect).

I use an onDraw method on a canvas. In the simplest case, I have a background and a sprite.

On the first pass through onDraw, I draw the background and use invalidate(Rect) (a rect which covers the whole playfield) and in the same pass, I draw a sprite and (because the code is the same for all passes) I do an invalidate(Rect) for the Rect the sprite was in.

After the first pass, the playfield is correct. The whole background is in place, with the sprite superimposed.

On the next and subsequent passes through onDraw, I draw the "dirty" bit of the background the sprite was on, and do an invalidate(Rect) on that, together with the sprite and its new "dirty" rectangle, and another invalidate(Rect) for the sprite.

After this pass and all subsequent passes, I only see the sprite. It's as though the canvas had been cleared.

Is it not allowed to do multiple invalidate(Rect)s in one pass? Is this the problem? Have I come up against some problem with asynchronicity?

Here is the onDraw() code. It works fine, but slowly, if I do a full screen invalidate() at the end of onDraw() instead. It's also scaling all the images. All the images and screen positions are based on a 640x480 playfield, and scaled to the size of the current android device. All that works fine until I try to optimise the screen drawing by using invalidate(Rect).

    @Override
    protected void onDraw(Canvas canvas) 
{
    int ii;

    // Draw the background scene
    // Restore all the bits of the backcloth that got 
    // trampled on by any sprites or the cursor 
    // On the first pass the whole playfield dirty rectangle is in place in mask
    paint.reset();
    mask.collapse();
    ArrayList <Rect> usedSet = mask.getUsedRectSet();
    for (ii = 0; ii < usedSet.size(); ii++)
    {
        Rect src = rescaleRect(usedSet.get(ii));
        Rect dst = displaceRect(src);
        canvas.drawBitmap(backcloth, src, dst, paint);
        invalidate(dst);
    }
    // Leave used Rect set clear for next set of sprites
    mask.ClearUsedRectSet();

    //
    // draw Sprites
    //   screen scaling and
    //   displacement is done here.
    //
    ArrayList <Sprite> slist = jadedata.getCurrentSprites();
    //Sort sprites into ascending order of priority
    //      This is a sinking sort. On first pass, the highest
    //      priority sprite arrives at the bottom. On second,
    //      the next highest arrives at second bottom, etc.
    //      Sprites of the same priority remain in their
    //      original sequence with respect to each other.
    for (ii = 0; ii< slist.size()-1; ii++)
    {
        int sw=0;
        for (int jj = 0; jj < (slist.size()-ii-1); jj++)
        {
            Sprite spare1 = slist.get(jj);
            Sprite spare2 = slist.get(jj+1);
            if (spare1.getPriority() > spare2.getPriority())
            {
                slist.set(jj+1, spare1);
                slist.set(jj, spare2);
                sw=1;
            }
        }
        if (sw==0) break;  // exit if slist is already in sequence
    }

    for (ii = 0; ii< slist.size(); ii++) 
    {
        Point p = new Point();
        Point e = new Point();
        Rect o = new Rect();
        Sprite sprite = (Sprite)slist.get(ii);
        // Zero-priority sprites do not get drawn
        if (sprite.getPriority() == 0) continue;
        p = sprite.getPosition();
        e = sprite.getExtent();
        // make a rect for usedRects
        Rect r = new Rect(0, 0, e.x-1, e.y-1);
        Rect src = new Rect(r);
        // move it to the model playfield position
        r.offset(p.x-e.x/2, p.y-e.y/2);
        // make an overlap rect so we can apply it to the source image
        o = overlapRect(r, 0, 0, iWidth, iHeight);
        // trim r for the used rectangles
        r = trimRect(r, 0, 0, iWidth, iHeight);
        // add it to used Rectangles
        mask.addNewRect(r);
        // draw the sprite image
        Rect d = rescaleRect(usedSet.get(ii));
        Rect dst = displaceRect(d);
        Bitmap spriteim = sprite.getCurrentImage();
        src.top += o.top;
        src.left += o.left;
        src.bottom -= o.bottom;
        src.right -= o.right;
        canvas.drawBitmap(spriteim, src, dst, paint);
        invalidate(dst);
    }
1

1 Answers

0
votes

not sure what you are doing since you didn't provide code , so i will just give a general tip:

for the passes after the first pass , use the invalidate only on the rectangle that is dirty , and in the onDraw method , draw everything that needs to be drawn , but only inside the dirty rectangle.