Android:移动bmp留下痕迹(Surface View和Canvas)

时间:2016-01-11 22:35:32

标签: java android sprite android-canvas surfaceview

我试图为Android应用程序制作精灵动画,但我遇到了一个小问题。我正在使用我在现有布局上添加的surfaceView。在这个surfaceView上,我想动画几个精灵,这样他们就会沿着一条路走。

所以这就是我现在面临的结果:enter image description here

行走的精灵正在留下痕迹。所以我决定谷歌这个问题,显然我必须首先清除画布然后再画上它 这是我之前的onDraw方法:

public void onDraw(Canvas canvas) {
    update();
    int srcX = currentFrame * width;
    int srcY = directionX * height;
    Rect src = new Rect(srcX, srcY, srcX + width, srcY + height);
    Rect dst = new Rect(x, y, x + width, y + height);
    canvas.drawBitmap(bmp, src, dst, null);

}

这是

之后的onDraw方法
public void onDraw(Canvas canvas) {
    canvas.drawRGB(0, 0, 0);
    update();
    int srcX = currentFrame * width;
    int srcY = directionX * height;
    Rect src = new Rect(srcX, srcY, srcX + width, srcY + height);
    Rect dst = new Rect(x, y, x + width, y + height);
    canvas.drawBitmap(bmp, src, dst, null);

}

所以我现在有了这个结果

enter image description here

这很棒,因为它不会留下任何痕迹,但我无法看到下面的布局。无论如何,我可以充分利用这两个世界吗?我认为清除画布会起作用,但显然无法按预期工作。

我会在下面发布我的代码

SurfaceView:

public class MonsterView extends SurfaceView {

private Bitmap monsterImg;
private SurfaceHolder holder;
private MonsterThread mainThread;
private Sprite monsterSprite;
private int x;
private int xSpeed = 1;

public MonsterView(Context context) {
    super(context);
    this.mainThread = new MonsterThread(this);
    this.x = 0;


    holder = getHolder();
    holder.setFormat(PixelFormat.TRANSPARENT);

    holder.addCallback(new SurfaceHolder.Callback() {

        @Override
        public void surfaceCreated(SurfaceHolder holder) {
            mainThread.setRunning(true);
            mainThread.start();
        }

        @Override
        public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {

        }

        @Override
        public void surfaceDestroyed(SurfaceHolder holder) {
            boolean retry = true;
            mainThread.setRunning(false);
            while (retry) {
                try {
                    mainThread.join();
                    retry = false;
                } catch (InterruptedException e) {
                }
            }

        }
    });
    setZOrderOnTop(true);
    monsterImg = BitmapFactory.decodeResource(getResources(), R.drawable.fire);
    monsterSprite = new Sprite(this,monsterImg);
}

@Override
public void onDraw(Canvas canvas) {
    if (x == getWidth() - monsterImg.getWidth()) {
        xSpeed = -1;
    }
    if (x == 0) {
        xSpeed = 1;
    }
    x = x + xSpeed;
    monsterSprite.onDraw(canvas);
}

线程:

public class MonsterThread extends Thread {
private MonsterView monsterSurface;
private boolean running;
static final long FPS = 35;

public MonsterThread(MonsterView monsterSurface){
    this.monsterSurface = monsterSurface;
    this.running = false;
}

@Override
public void run() {
    long ticksPS = 1000 / FPS;
    long startTime;
    long sleepTime;

    while(running){
        Canvas c = null;
        startTime = System.currentTimeMillis();
        try{
            c = monsterSurface.getHolder().lockCanvas();
            synchronized (monsterSurface.getHolder()){

                monsterSurface.onDraw(c);
            }
        } finally {
            if( c!= null){
                monsterSurface.getHolder().unlockCanvasAndPost(c);

            }
        }
        sleepTime = ticksPS-(System.currentTimeMillis() - startTime);
        try {
            if(sleepTime > 0)
                sleep(sleepTime);
            else
                sleep(10);
        } catch (Exception e){}
    }
}

public MonsterView getMonsterSurface() {
    return monsterSurface;
}

public void setMonsterSurface(MonsterView monsterSurface) {
    this.monsterSurface = monsterSurface;
}

public boolean isRunning() {
    return running;
}

public void setRunning(boolean running) {
    this.running = running;
}

精灵:

public class Sprite {
private static final int BMP_ROWS = 4;
private static final int BMP_COLUMNS = 3;
private int x = 0;
private int y = 0;
private int xSpeed = 5;
private MonsterView monsterView;
private Bitmap bmp;
private int currentFrame = 0;
private int width;
private int height;

private int directionX;

public Sprite(MonsterView monsterView, Bitmap bmp) {
    this.monsterView = monsterView;
    this.bmp=bmp;
    this.width = bmp.getWidth() / BMP_COLUMNS;
    this.height = bmp.getHeight() / BMP_ROWS;
    this.directionX = 2;
}

private void update() {
    if (x > monsterView.getWidth() - width - xSpeed) {
        xSpeed = -5;
        directionX = 1;
    }
    if (x + xSpeed < 0) {
        xSpeed = 5;
        directionX = 2;
    }
    x = x + xSpeed;
    currentFrame = ++currentFrame % BMP_COLUMNS;
    Log.d("test", ""+currentFrame);
}

public void onDraw(Canvas canvas) {
    update();
    int srcX = currentFrame * width;
    int srcY = directionX * height;
    Rect src = new Rect(srcX, srcY, srcX + width, srcY + height);
    Rect dst = new Rect(x, y, x + width, y + height);
    canvas.drawBitmap(bmp, src, dst, null);

}

3 个答案:

答案 0 :(得分:3)

您正在使用setZOrderOnTop(),它将SurfaceView的Surface部分放在一个层之上。 (默认情况下,它是一个单独的图层,低于其他所有图层。)当您使用canvas.drawRGB(0, 0, 0)清除它时,您将整个图层设置为不透明的黑色,这将遮盖其下方的视图层。

如果您使用canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR)将其清除为透明黑色,则应获得所需的结果。

FWIW,如果您只是在Surface上绘图,则不应覆盖onDraw()。 View层次结构调用onDraw()方法在SurfaceView的View部分上绘制。如果某些东西设法使SurfaceView的视图无效,则会调用onDraw(),并且最终会在视图图层上显示一个字符精灵。 (根据您的布局,这可能不可见。)只需为方法指定一个不同的名称。

答案 1 :(得分:2)

有许多方法可以解决这个问题,但一般来说,这样做的方法是保持背景图层(只是另一个图像)和精灵图层。而不是清除,在每一帧你将你的背景blit(复制)到表面(擦除所有东西),然后你blit你的精灵。

答案 2 :(得分:0)

因此,在绘制精灵之前,您必须首先将背景位图绘制到曲面上。现在你正在绘制黑色,覆盖你的背景布局。

或者你可以使用Paint使用paint.setColor将canvas.drawRect转换为Color.Transparent。