簡體   English   中英

Android:移動bmp留下痕跡(Surface View和Canvas)

[英]Android : moving bmp leaving a trail ( Surface View and Canvas )

我正在嘗試為Android應用程序的精靈設置動畫,但是遇到一個小問題。 我正在一個SurfaceView上繪制,該視圖添加到已經存在的布局之上。 在這個surfaceView上,我想為幾個精靈設置動畫,以便它們沿着路徑行走。

所以這就是我現在面臨的結果: 在此處輸入圖片說明

行走的精靈正在留下痕跡。 所以我決定用谷歌搜索這個問題,顯然我必須在畫上畫布之前先清除它。
這是我之前的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);

}

所以我現在有了這個

在此處輸入圖片說明

這很棒,因為它不再留下任何痕跡,但我看不到下面的布局。 無論如何,我能同時獲得兩全其美嗎? 我認為清理畫布會起作用,但顯然不能按預期工作。

我將在下面發布我的代碼

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);

}

您正在使用setZOrderOnTop() ,它會將SurfaceView的Surface部分放在其他所有圖層之上。 (默認情況下,它是其他所有之下的單獨層。)使用canvas.drawRGB(0, 0, 0) )清除它時, canvas.drawRGB(0, 0, 0)整個層設置為不透明黑色,這將使下面的View層模糊。

相反,如果使用canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR)其清除為透明黑色,則應該獲得所需的結果。

FWIW,如果僅在Surface上繪制,則不應覆蓋onDraw() View層次結構調用onDraw()方法以在SurfaceView的View部分上進行繪制。 如果某種方法使SurfaceView的View無效,則將調用onDraw() ,最后在View層上顯示一個字符精靈。 (根據您的布局,這可能不可見。)只需為該方法指定其他名稱即可。

有多種方法可以解決此問題,但是通常,通過維護背景層(僅是另一幅圖像)和子畫面層來實現此目的。 無需清除,而是在每一幀上將背景變亮(復制)到表面上(這會擦除所有內容),然后使精靈變亮。

因此,在繪制精靈之前,您必須先在背景上繪制背景位圖。 現在,您正在繪制黑色,這覆蓋了您的背景布局。

或者,您也可以使用Paint.setColor設置為Color.Transparent的Paint來進行canvas.drawRect。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM