使用Canvas的Android Bouncing Ball

时间:2016-05-08 09:47:46

标签: android bitmap android-canvas drawable

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

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

这是我的画布类

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

我希望从左上角,中间右侧,中间左侧,右下方移动,然后再循环回来。当我将方向更改为横向时,我也遇到了问题,因为画布的宽度发生了变化,之后一切都被破坏了。

[编辑]

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

这就是我被困住的地方。球向中间左侧移动,但是当方向改变为横向时,球会下降并且不会上升。

2 个答案:

答案 0 :(得分:1)

球类

为了让这个工作变得有效而不会让你的代码变得令人厌恶和混乱,你需要为你的Ball定义一个好的课程,如果你想添加额外的球,这也增加了灵活性到画布或其他什么。正如您所看到的,我们拥有球实例的所有相关信息,包括方向和颜色,然后我们需要从我们的自定义View做的就是告诉球移动,并绘制{{ 1}}它包含oval

paint

我们如何计算方向?

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

自定义视图

上一个类可以包含在一个单独的文件中,也可以包含在自定义View类中,这取决于您和您的编码方式,但对于自定义视图,我们只需要处理绘图:

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

注意

你真的应该使用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 } } 和设定的间隔来设置动画。但对于一个简单的案例,这应该足够了。

答案 1 :(得分:0)

除了Jaun Cortes之外,还通过引入Arrays在(速度,大小,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
    }
}

然后是球类

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

和主要活动类别如下:

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

    }

}