Android 弹跳球使用 Canvas

Android Bouncing Ball using Canvas

这是我目前在 MainActivity.java 中的内容。

public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    MyBall ball = new MyBall(this);
    setContentView(ball);
    }
 }

这是我的 canvas class

public class MyBall extends View {
    Bitmap myBall;
    int gap = 10;
    String direction = "down";
    float xPos = 0;
    float yPos = 0;

public MyBall(Context context) {
    super(context);
    myBall = BitmapFactory.decodeResource(getResources(), R.drawable.ball3);

 }
protected void onDraw(Canvas canvas){
    super.onDraw(canvas);
    canvas.drawColor(Color.WHITE);


    canvas.drawBitmap(myBall, xPos, yPos, null);
    invalidate();
 }
}

我想从左上移动到右中,左中,右下然后循环回来。当我将方向更改为横向时,我也遇到了问题,因为 canvas 的宽度发生了变化,之后一切都毁了。

[编辑]

 protected void onDraw(Canvas canvas){
    super.onDraw(canvas);
    canvas.drawColor(Color.WHITE);
    if(direction.equals("down"))
    {
            if(yPos < canvas.getHeight()/2 - myBall.getWidth()){
                xPos+=gap;
                yPos+=gap;
            }
        else {
                direction = "up";
                Log.d("direction", xPos + "help");
            }

    }
    if(direction.equals("up")){
        if (xPos >  myBall.getWidth()) {
            xPos-=gap;
            yPos+=gap;
        }

    }

    canvas.drawBitmap(myBall, xPos, yPos, null);
    invalidate();
}

这就是我卡住的地方。球往左中偏了,但是当方向改成横屏的时候球往下不往上了。

球Class

为了让它正常工作而不至于让你的代码变得令人作呕和混乱,你需要为你的 Ball 定义一个好的 class,这也增加了灵活性,如果你曾经想在 canvas 或其他任何地方添加额外的球。如您所见,我们拥有球实例的所有相关信息,包括方向和颜色,然后我们需要根据自定义 View 做的就是告诉球移动,然后绘制 oval 它包含 paint.

public class Ball{
    public int[] direction = new int[]{1,1}; //direction modifier (-1,1)
    public int x,y,size;
    public int speed = 10;
    public Paint paint;
    public RectF oval;

    public Ball(int x, int y, int size, int color){
        this.x = x;
        this.y = y;
        this.size = size;
        this.paint = new Paint();
        this.paint.setColor(color);
    }

    public void move(Canvas canvas) {
        this.x += speed*direction[0];
        this.y += speed*direction[1];
        this.oval = new RectF(x-size/2,y-size/2,x+size/2,y+size/2);

        //Do we need to bounce next time?
        Rect bounds = new Rect();
        this.oval.roundOut(bounds); ///store our int bounds

        //This is what you're looking for ▼
        if(!canvas.getClipBounds().contains(bounds)){
            if(this.x-size<0 || this.x+size > canvas.getWidth()){
                direction[0] = direction[0]*-1;
            }
            if(this.y-size<0 || this.y+size > canvas.getHeight()){
                direction[1] = direction[1]*-1;
            }
        }
    }
}

我们如何计算方向?

当我们与边界碰撞时,您可能对我们如何计算感到困惑。有几种方法可以解决这个问题,但在我们的例子中,我们正在检查包围我们球的矩形是否仍然包含在 canvas 中。 如果不是,这意味着我们已经以某种方式逃脱了 canvas 的边界,如果我们已经超过了 X 轴的限制,我们将检查需要修改哪个方向或低于零,我们将方向乘以 -1,改变修饰符。同样适用于 Y 轴

自定义视图

前面的class可以包含在单独的文件中,也可以包含在自定义View中class,这取决于您和您的编码方式,但是对于Custom View,我们只是需要处理图纸:

public class BouncingBallInside extends View {
    private List<Ball> balls = new ArrayList<>();

    public BouncingBallInside(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }
    public BouncingBallInside(Context context) {
        super(context);
        init();
    }
    private void init(){
        //Add a new ball to the view
        balls.add(new Ball(50,50,100,Color.RED));
    }
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        //Draw the balls
        for(Ball ball : balls){
            //Move first
            ball.move(canvas);
            //Draw them
            canvas.drawOval(ball.oval,ball.paint);
        }
        invalidate(); // See note
    }
}

备注

你真的应该使用 Handler 和设定的时间间隔来制作动画。但对于简单的情况,这应该足够了。

除了 Jaun Cortes 之外,还通过引入数组

在(速度、大小、x 和 y 坐标)中添加了一些随机性
public class BouncingBallInside extends View {
    private Ball[] balls = new Ball[10];

/*even new Ball can be added as variable e.g. ballcount passed as new Ball[ballcount] */

    public BouncingBallInside(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }
    public BouncingBallInside(Context context) {
        super(context);
        init();
    }
    private void init(){
        //Add a new ball to the view
        for (int i =0; i <10 ; i++) {
        balls[i] = (new Ball(i*2,i*5,i*3,i*3 , Color.RED));
//        balls.add(new Ball(i*4,i*3,i*2, i*3,Color.GREEN));
        }
    }
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        //Draw the balls

        for (int i =0; i <10 ; i++) {
            balls[i].move(canvas);
            //Draw them
            canvas.drawOval(balls[i].oval,balls[i].paint);
        }
        invalidate(); // See note
    }
}

接下来是球class

    public Ball(int x, int y, int s,int size, int color){
        this.x = x;
        this.y = y;
        this.size = size;
        this.paint = new Paint();
        this.paint.setColor(color);
        this.speed =s;
    }

    public void move(Canvas canvas) {
        this.x += speed*direction[0];
        this.y += speed*direction[1];
        this.oval = new RectF(x-size/2,y-size/2,x+size/2,y+size/2);

        //Do we need to bounce next time?
        Rect bounds = new Rect();
        this.oval.roundOut(bounds); ///store our int bounds

        //This is what you're looking for ▼
        if(!canvas.getClipBounds().contains(bounds)){
            if(this.x-size<0 || this.x+size > canvas.getWidth()){
                direction[0] = direction[0]*-1;
            }
            if(this.y-size<0 || this.y+size > canvas.getHeight()){
                direction[1] = direction[1]*-1;
            }
        }
    }
}

和 Main activity class 如下:

public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        final BouncingBallInside bouncingballi = new BouncingBallInside(this);
        setContentView(bouncingballi);

    }

}