Android Canvas动画似乎口吃(不平滑)

时间:2015-11-24 18:03:59

标签: java android animation canvas

我正在制作一个应用程序,其中球从屏幕顶部落到屏幕底部,用户必须触摸某个区域才能使球消失。但是,当球落下时,它们会随着屏幕下降而断断续续。以下是该项目的完整代码:

public class GameActivity extends Activity implements View.OnTouchListener {

    MyBringBack ourSurfaceView;
    Paint p;
    float x, y, secondX, secondY;
    int firstRun;
    Bitmap green, red, blue, purple, white;
    int currentColor;
    ArrayList<Ball> balls = new ArrayList<>();
    Paint buttonPaint;
    Boolean thingFirstRun;
    int score;
    Model model;
    int cHeight, cWidth;
    int nextBallSpeed;
    int totalBalls;
    int countBalls;

    int buttonState = 0;
    public final static int BUTTON_NONE = 0;
    public final static int BUTTON_LEFT = 1;
    public final static int BUTTON_RIGHT = 2;
    public final static int BUTTON_BOTH = 3;

    class Ball {
        public Ball(int x, int y, int s, int color, Bitmap b) {
            xCord = x;
            yCord = y;
            speed = s;
            this.color = color;
            passedLineYet = false;
            bitmap = b;
        }

        public int xCord;
        public int yCord;
        public int speed;
        public int color;
        public boolean passedLineYet;
        public Bitmap bitmap;
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        red = BitmapFactory.decodeResource(getResources(), R.drawable.redcircle);
        blue = BitmapFactory.decodeResource(getResources(), R.drawable.bluecircle);
        green = BitmapFactory.decodeResource(getResources(), R.drawable.greencircle);
        purple = BitmapFactory.decodeResource(getResources(), R.drawable.purplecircle);
        white = BitmapFactory.decodeResource(getResources(), R.drawable.white);

        secondX = secondY = -1;

        cHeight = 0;
        cWidth = 0;

        countBalls = 0;

        nextBallSpeed = 60;

        p = new Paint();
        p.setColor(Color.WHITE);
        p.setTextSize(200);


        ourSurfaceView = new MyBringBack(this);
        ourSurfaceView.setOnTouchListener(this);

        setContentView(ourSurfaceView);

        model = new Model();

        score = 0;
        (new Thread(model)).start();


        thingFirstRun = false;
        currentColor = Color.GREEN;

        buttonPaint = new Paint();
        buttonPaint.setColor(currentColor);
        buttonPaint.setStrokeWidth(10);
        buttonPaint.setStyle(Paint.Style.FILL);

        firstRun = 0;

    }


    public boolean correctColor(Ball b) {
        if (currentColor == b.color) {
            return true;
        }

        return false;
    }


    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        return true;
    }

    @Override
    protected void onPause() {
        super.onPause();
        ourSurfaceView.pause();
    }

    @Override
    protected void onResume() {
        super.onResume();
        ourSurfaceView.resume();
    }

    @Override
    public boolean onTouch(View v, MotionEvent event) {
        try {


            switch (event.getAction() & MotionEvent.ACTION_MASK) {

                case MotionEvent.ACTION_DOWN:
                case MotionEvent.ACTION_POINTER_DOWN:

                    float xEvent = event.getX(event.getPointerId(event.getActionIndex()));
                    float yEvent = event.getY(event.getPointerId(event.getActionIndex()));

                    if (yEvent > cHeight / 4 * 3) {
                        if (xEvent < cWidth / 2) {
                            buttonState |= BUTTON_LEFT;
                        }
                        if (xEvent > cWidth / 2) {
                            buttonState |= BUTTON_RIGHT;
                        }
                    }
                    break;
                case MotionEvent.ACTION_POINTER_UP:
                case MotionEvent.ACTION_UP:

                    try {
                        xEvent = event.getX(event.getPointerId(event.getActionIndex()));
                        yEvent = event.getY(event.getPointerId(event.getActionIndex()));
                    } catch (Exception e) {
                        xEvent = event.getX();
                        yEvent = event.getY();
                    }

                    if (yEvent > cHeight / 4 * 3) {
                        if (xEvent < cWidth / 2) {
                            buttonState &= ~BUTTON_LEFT;
                        }
                        if (xEvent > cWidth / 2) {
                            buttonState &= ~BUTTON_RIGHT;
                        }
                    }

                    break;
            }
            switch (buttonState) {
                case BUTTON_LEFT:
                    currentColor = Color.RED;
                    break;
                case BUTTON_RIGHT:
                    currentColor = Color.BLUE;
                    break;
                case BUTTON_BOTH:
                    currentColor = Color.MAGENTA;
                    break;
                case BUTTON_NONE:
                    currentColor = Color.GREEN;
                    break;
            }
            buttonPaint.setColor(currentColor);

            Log.v("BUTTON STATE", buttonState + "");
            Log.v("BUTTON COLOR", currentColor + "");

            return true;
        } catch (Exception e) {

        }
        return true;
    }

    public class Model extends Thread implements Runnable {

        @Override
        public void run() {
            while (true) {
                try {
                    Thread.sleep(1000 / 240);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                if (countBalls % nextBallSpeed == 0) {
                    int temp = (int) (Math.random() * 4);
                    if (temp == 0) {
                        balls.add(new Ball((int) (Math.random() * (cWidth - red.getWidth())), 0 - red.getHeight(), cHeight / 800, Color.RED, red));
                    } else if (temp == 1) {
                        balls.add(new Ball((int) (Math.random() * (cWidth - red.getWidth())), 0 - green.getHeight(), cHeight / 800, Color.GREEN, green));
                    } else if (temp == 2) {
                        balls.add(new Ball((int) (Math.random() * (cWidth - blue.getWidth())), 0 - blue.getHeight(), cHeight / 800, Color.BLUE, blue));
                    } else if (temp == 3) {
                        balls.add(new Ball((int) (Math.random() * (cWidth - purple.getWidth())), 0 - purple.getHeight(), cHeight / 800, Color.MAGENTA, purple));
                    }
                    totalBalls++;

                }

                if (totalBalls < 10) {
                    nextBallSpeed = 30;
                } else if (totalBalls < 30) {
                    nextBallSpeed = 25;
                } else if (totalBalls < 50) {
                    nextBallSpeed = 20;
                } else if (totalBalls < 80) {
                    nextBallSpeed = 15;
                } else if (totalBalls < 150) {
                    nextBallSpeed = 10;
                } else {
                    nextBallSpeed = 5;
                }

                for (int i = 0; i < balls.size(); i++) {
                    int h = cHeight;
                    balls.get(i).yCord += balls.get(i).speed;
                }
                for (int i = 0; i < balls.size(); i++) {
                    try {
                        if (balls.get(i).yCord + green.getHeight() > ((double) cHeight * .75) && !balls.get(i).passedLineYet) {
                            balls.get(i).passedLineYet = true;
                            boolean b = correctColor(balls.get(i));
                            if (b) {
                                balls.remove(i);
                                score++;
                            }
                            if (!b) {

                            }
                        } else if (balls.get(i).yCord > cHeight) {
                            balls.remove(i);
                            score -= 5;
                        }
                    } catch (Exception ignored) {

                    }
                }
                countBalls++;
            }
        }

        public boolean correctColor(Ball b) {
            if (currentColor == b.color) {
                return true;
            }

            return false;
        }
    }


    public class MyBringBack extends SurfaceView implements Runnable {

        SurfaceHolder ourHolder;
        Thread ourThread = null;
        boolean isRunning = false;


        public MyBringBack(Context context) {
            super(context);
            ourHolder = getHolder();
        }


        public void pause() {
            isRunning = false;
            while (true) {
                try {
                    ourThread.join();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                break;
            }
            ourThread = null;
        }

        public void resume() {
            isRunning = true;
            ourThread = new Thread(this);
            ourThread.start();
        }


        @Override
        public void run() {
            while (isRunning) {
                try {
                    Thread.sleep(1000 / 240);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                if (!ourHolder.getSurface().isValid()) {
                    continue;
                }
                //NE
                Bitmap tempCanvasBitmap = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888);
                Canvas tempCanvas = new Canvas();
                tempCanvas.setBitmap(tempCanvasBitmap);
                //NEND

                //Canvas canvas = ourHolder.lockCanvas();
                tempCanvas.drawColor(Color.BLACK);

                if (firstRun == 0) {
                    cHeight = tempCanvas.getHeight();
                    cWidth = tempCanvas.getWidth();
                    red = getResizedBitmap(red, tempCanvas.getWidth() / 12, tempCanvas.getWidth() / 12);
                    green = getResizedBitmap(green, tempCanvas.getWidth() / 12, tempCanvas.getWidth() / 12);
                    blue = getResizedBitmap(blue, tempCanvas.getWidth() / 12, tempCanvas.getWidth() / 12);
                    purple = getResizedBitmap(purple, tempCanvas.getWidth() / 12, tempCanvas.getWidth() / 12);
                    white = getResizedBitmap(white, cHeight / 4 * 3, cWidth / 20);
                    firstRun = 1;
                    totalBalls = 0;
                }

                //canvas.drawBitmap(white, );
                tempCanvas.drawRect(0, tempCanvas.getHeight() * 3 / 4, tempCanvas.getWidth(), tempCanvas.getHeight(), buttonPaint);
                for (int i = 0; i < balls.size(); i++) {
                    try {
                        tempCanvas.drawBitmap(balls.get(i).bitmap, balls.get(i).xCord, balls.get(i).yCord, null);
                    } catch (Exception ignored) {

                    }
                }

                Rect r = new Rect();
                p.getTextBounds(score + "", 0, (score + "").length(), r);
                tempCanvas.drawText(score + "", cWidth - r.width() - 20, r.height() + 20, p);


                Canvas canvas = ourHolder.lockCanvas();
                canvas.drawBitmap(tempCanvasBitmap, 0, 0, p);
                ourHolder.unlockCanvasAndPost(canvas);

            }
        }
    }

    public static Bitmap getResizedBitmap(Bitmap bm, int newHeight, int newWidth) {
        int width = bm.getWidth();
        int height = bm.getHeight();
        float scaleWidth = ((float) newWidth) / width;
        float scaleHeight = ((float) newHeight) / height;
        // create a matrix for the manipulation
        Matrix matrix = new Matrix();
        // resize the bit map
        matrix.postScale(scaleWidth, scaleHeight);
        // recreate the new Bitmap
        Bitmap resizedBitmap = Bitmap.createBitmap(bm, 0, 0, width, height, matrix, false);
        return resizedBitmap;
    }

}

我以前创建过动画,但没有使用Runnable(onDraw()方法中的所有代码)。也许问题就在于此。

有谁知道为什么会出现这种口吃?

1 个答案:

答案 0 :(得分:1)

使用此: 添加类成员字段,替换run(),并添加primeCanvas()方法。

   boolean isPrimed = false;
   Canvas canvas;

    @Override
    public void run() {
        while(isRunning) {
            if (!ourHolder.getSurface().isValid())
                continue;

            canvas = ourHolder.lockCanvas();

            if(!isPrimed)
                primeCanvas();

            canvas.drawColor(Color.BLACK);
            canvas.drawRect(0, canvas.getHeight() * 3 / 4, canvas.getWidth(), canvas.getHeight(), buttonPaint);

            for(int i = 0; i < balls.size(); i ++)
                    canvas.drawBitmap(balls.get(i).bitmap, balls.get(i).xCord, balls.get(i).yCord, null);

            Rect r = new Rect();
            p.getTextBounds(score + "", 0, (score + "").length(), r);
            canvas.drawText(score + "", cWidth - r.width() - 20, r.height() + 20, p);

            ourHolder.unlockCanvasAndPost(canvas);
        }
    }

    private void primeCanvas() {
        cHeight = canvas.getHeight();
        cWidth = canvas.getWidth();
        red = getResizedBitmap(red, canvas.getWidth()/12, canvas.getWidth()/12);
        green = getResizedBitmap(green, canvas.getWidth()/12, canvas.getWidth()/12);
        blue  = getResizedBitmap(blue, canvas.getWidth()/12, canvas.getWidth()/12);
        purple = getResizedBitmap(purple, canvas.getWidth()/12, canvas.getWidth()/12);
        white = getResizedBitmap(white, cHeight / 4 * 3, cWidth / 20);
        firstRun = 1;
        totalBalls = 0;
    }