【问题标题】:Android Bouncing Ball using Canvas使用 Canvas 的 Android 弹跳球
【发布时间】:2016-05-08 09:47:45
【问题描述】:

这是我目前在 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();
}

这是我卡住的地方。球向左中间移动,但当方向变为横向时,球向下而不向上。

【问题讨论】:

  • 不要在onDraw() 中调用invalidate。为您的动画帧使用其他来源。
  • @tynn 你到底是什么意思?我是新手,所以我使用了 invalidate 以便再次调用 ondraw 方法,以便更新图像。
  • 这就是我的意思。不要在onDraw() 中这样做。使用计时器或类似的东西进行更新。或者看看View Animation

标签: android bitmap android-canvas drawable


【解决方案1】:

球类

为了让这个工作不至于发疯和让你的代码变得令人恶心和混乱,你需要为你的Ball 定义一个好的类,如果你想添加额外的球到帆布什么的。如您所见,我们拥有球实例的所有相关信息,包括方向和颜色,然后我们需要从自定义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;
            }
        }
    }
}

我们如何计算方向?

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

自定义视图

上一个类可以包含在单独的文件中,也可以包含在自定义 View 类中,这取决于您和您的编码方式,但是对于自定义 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 和设置的间隔来制作动画。但是对于一个简单的情况,这应该就足够了。

【讨论】:

  • 好吧,这对我来说有点太多了,我想我必须阅读你的代码一段时间才能理解它。但我试过了,它奏效了,所以这几乎解决了我的问题。谢谢这个人!
  • 阅读它,测试它,你最终会理解它。祝你好运!
【解决方案2】:

除了 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
    }
}

接下来是球类

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

    }

}

【讨论】:

    猜你喜欢
    • 2014-06-18
    • 1970-01-01
    • 2013-05-23
    • 1970-01-01
    • 2012-10-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多