android 弹回球

发布于 2024-12-25 09:56:30 字数 7833 浏览 1 评论 0原文

我以使用 SensorManager 的加速器为例,其中画布(球)根据设备加速器的旋转来更新其位置。这是图像:

在此处输入图像描述

如图所示,有一个球和一条线。球的位置经常更新,而线的位置是静态的。

我想让球在触及线时反弹回来。我从三天开始就尝试过,但不明白我该怎么做。

这是我的代码:

public class ballsensor extends Activity implements SensorEventListener {

    // sensor-related
    private SensorManager mSensorManager;
    private Sensor mAccelerometer;

    // animated view
    private ShapeView mShapeView;

    // screen size
    private int mWidthScreen;
    private int mHeightScreen;

    // motion parameters
    private final float FACTOR_FRICTION = 0.5f; // imaginary friction on the
                                                // screen
    private final float GRAVITY = 9.8f; // acceleration of gravity
    private float mAx; // acceleration along x axis
    private float mAy; // acceleration along y axis
    private final float mDeltaT = 0.5f; // imaginary time interval between each
                                        // acceleration updates

    // timer
    private Timer mTimer;
    private Handler mHandler;
    private boolean isTimerStarted = false;
    private long mStart;

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

        // set the screen always portait
        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);

        // initializing sensors
        mSensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
        mAccelerometer = mSensorManager
                .getDefaultSensor(Sensor.TYPE_ACCELEROMETER);

        // obtain screen width and height
        Display display = ((WindowManager) this
                .getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
        mWidthScreen = display.getWidth();
        mHeightScreen = display.getHeight() - 35;

        // initializing the view that renders the ball
        mShapeView = new ShapeView(this);
        mShapeView.setOvalCenter((int) (mWidthScreen * 0.6),
                (int) (mHeightScreen * 0.6));

        setContentView(mShapeView);

    }

    @Override
    public void onAccuracyChanged(Sensor sensor, int accuracy) {

    }

    @Override
    public void onSensorChanged(SensorEvent event) {
        // obtain the three accelerations from sensors
        mAx = event.values[0];
        mAy = event.values[1];

        float mAz = event.values[2];

        // taking into account the frictions
        mAx = Math.signum(mAx) * Math.abs(mAx)
                * (1 - FACTOR_FRICTION * Math.abs(mAz) / GRAVITY);
        mAy = Math.signum(mAy) * Math.abs(mAy)
                * (1 - FACTOR_FRICTION * Math.abs(mAz) / GRAVITY);
    }

    @Override
    protected void onResume() {
        super.onResume();
        // start sensor sensing
        mSensorManager.registerListener(this, mAccelerometer,
                SensorManager.SENSOR_DELAY_NORMAL);

    }

    @Override
    protected void onPause() {
        super.onPause();
        // stop senser sensing
        mSensorManager.unregisterListener(this);
    }

    // the view that renders the ball
    private class ShapeView extends SurfaceView implements
            SurfaceHolder.Callback {

        private final int RADIUS = 30;
        private final float FACTOR_BOUNCEBACK = 0.50f;

        private int mXCenter;
        private int mYCenter;
        private RectF mRectF;
        private final Paint mPaint;
        private ShapeThread mThread;

        private float mVx;
        private float mVy;

        public ShapeView(Context context) {
            super(context);

            getHolder().addCallback(this);
            mThread = new ShapeThread(getHolder(), this);
            setFocusable(true);

            mPaint = new Paint();
            mPaint.setColor(0xFFFFFFFF);
            mPaint.setAlpha(192);
            mPaint.setStyle(Paint.Style.FILL_AND_STROKE);
            mPaint.setAntiAlias(true);

            mRectF = new RectF();
        }

        // set the position of the ball
        public boolean setOvalCenter(int x, int y) {
            mXCenter = x;
            mYCenter = y;
            return true;
        }

        // calculate and update the ball's position
        public boolean updateOvalCenter() {
            mVx -= mAx * mDeltaT;
            mVy += mAy * mDeltaT;

            System.out.println("mVx is ::" + mVx);
            System.out.println("mVy is ::" + mVy);

            mXCenter += (int) (mDeltaT * (mVx + 0.6 * mAx * mDeltaT));
            mYCenter += (int) (mDeltaT * (mVy + 0.6 * mAy * mDeltaT));

            if (mXCenter < RADIUS) {
                mXCenter = RADIUS;
                mVx = -mVx * FACTOR_BOUNCEBACK;
            }

            if (mYCenter < RADIUS) {
                mYCenter = RADIUS;
                mVy = -mVy * FACTOR_BOUNCEBACK;
            }
            if (mXCenter > mWidthScreen - RADIUS) {
                mXCenter = mWidthScreen - RADIUS;
                mVx = -mVx * FACTOR_BOUNCEBACK;
            }

            if (mYCenter > mHeightScreen - 2 * RADIUS) {
                mYCenter = mHeightScreen - 2 * RADIUS;
                mVy = -mVy * FACTOR_BOUNCEBACK;
            }

            return true;
        }

        // update the canvas.
        @Override
        protected void onDraw(Canvas canvas) {
            if (mRectF != null) {
                mRectF.set(mXCenter - RADIUS, mYCenter - RADIUS, mXCenter
                        + RADIUS, mYCenter + RADIUS);
                canvas.drawColor(0XFF000000);
                // canvas.drawOval(mRectF, mPaint);

                Bitmap kangoo = BitmapFactory.decodeResource(getResources(),
                        R.drawable.stripe1);

                Bitmap ball = BitmapFactory.decodeResource(getResources(),
                        R.drawable.blackwhiteball);

                canvas.drawBitmap(ball, mXCenter - RADIUS, mYCenter - RADIUS,
                        mPaint);
                canvas.drawBitmap(kangoo, 130, 10, null);

            }
        }

        @Override
        public void surfaceChanged(SurfaceHolder holder, int format, int width,
                int height) {
        }

        @Override
        public void surfaceCreated(SurfaceHolder holder) {
            mThread.setRunning(true);
            mThread.start();
        }

        @Override
        public void surfaceDestroyed(SurfaceHolder holder) {
            boolean retry = true;
            mThread.setRunning(false);
            while (retry) {
                try {
                    mThread.join();
                    retry = false;
                } catch (InterruptedException e) {

                }
            }
        }
    }

    class ShapeThread extends Thread {
        private SurfaceHolder mSurfaceHolder;
        private ShapeView mShapeView;
        private boolean mRun = false;

        public ShapeThread(SurfaceHolder surfaceHolder, ShapeView shapeView) {
            mSurfaceHolder = surfaceHolder;
            mShapeView = shapeView;
        }

        public void setRunning(boolean run) {
            mRun = run;
        }

        public SurfaceHolder getSurfaceHolder() {
            return mSurfaceHolder;
        }

        @Override
        public void run() {
            Canvas c;
            while (mRun) {
                mShapeView.updateOvalCenter();
                c = null;
                try {
                    c = mSurfaceHolder.lockCanvas(null);
                    synchronized (mSurfaceHolder) {
                        mShapeView.onDraw(c);
                    }
                } finally {
                    if (c != null) {
                        mSurfaceHolder.unlockCanvasAndPost(c);
                    }
                }
            }
        }
    }
}

I have take Example of Accelerator with SensorManager, in which canvas(ball) are get update its position as per device Accelerator are rotated. Here is image :

enter image description here

As shown in the image there is a ball and one line. The ball's position is frequently updated, while the line's position is static.

I would like to have the ball bounce back when it touches the line. I have tried since from 3 day, but don't understand how I can do this.

here is my code:

public class ballsensor extends Activity implements SensorEventListener {

    // sensor-related
    private SensorManager mSensorManager;
    private Sensor mAccelerometer;

    // animated view
    private ShapeView mShapeView;

    // screen size
    private int mWidthScreen;
    private int mHeightScreen;

    // motion parameters
    private final float FACTOR_FRICTION = 0.5f; // imaginary friction on the
                                                // screen
    private final float GRAVITY = 9.8f; // acceleration of gravity
    private float mAx; // acceleration along x axis
    private float mAy; // acceleration along y axis
    private final float mDeltaT = 0.5f; // imaginary time interval between each
                                        // acceleration updates

    // timer
    private Timer mTimer;
    private Handler mHandler;
    private boolean isTimerStarted = false;
    private long mStart;

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

        // set the screen always portait
        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);

        // initializing sensors
        mSensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
        mAccelerometer = mSensorManager
                .getDefaultSensor(Sensor.TYPE_ACCELEROMETER);

        // obtain screen width and height
        Display display = ((WindowManager) this
                .getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
        mWidthScreen = display.getWidth();
        mHeightScreen = display.getHeight() - 35;

        // initializing the view that renders the ball
        mShapeView = new ShapeView(this);
        mShapeView.setOvalCenter((int) (mWidthScreen * 0.6),
                (int) (mHeightScreen * 0.6));

        setContentView(mShapeView);

    }

    @Override
    public void onAccuracyChanged(Sensor sensor, int accuracy) {

    }

    @Override
    public void onSensorChanged(SensorEvent event) {
        // obtain the three accelerations from sensors
        mAx = event.values[0];
        mAy = event.values[1];

        float mAz = event.values[2];

        // taking into account the frictions
        mAx = Math.signum(mAx) * Math.abs(mAx)
                * (1 - FACTOR_FRICTION * Math.abs(mAz) / GRAVITY);
        mAy = Math.signum(mAy) * Math.abs(mAy)
                * (1 - FACTOR_FRICTION * Math.abs(mAz) / GRAVITY);
    }

    @Override
    protected void onResume() {
        super.onResume();
        // start sensor sensing
        mSensorManager.registerListener(this, mAccelerometer,
                SensorManager.SENSOR_DELAY_NORMAL);

    }

    @Override
    protected void onPause() {
        super.onPause();
        // stop senser sensing
        mSensorManager.unregisterListener(this);
    }

    // the view that renders the ball
    private class ShapeView extends SurfaceView implements
            SurfaceHolder.Callback {

        private final int RADIUS = 30;
        private final float FACTOR_BOUNCEBACK = 0.50f;

        private int mXCenter;
        private int mYCenter;
        private RectF mRectF;
        private final Paint mPaint;
        private ShapeThread mThread;

        private float mVx;
        private float mVy;

        public ShapeView(Context context) {
            super(context);

            getHolder().addCallback(this);
            mThread = new ShapeThread(getHolder(), this);
            setFocusable(true);

            mPaint = new Paint();
            mPaint.setColor(0xFFFFFFFF);
            mPaint.setAlpha(192);
            mPaint.setStyle(Paint.Style.FILL_AND_STROKE);
            mPaint.setAntiAlias(true);

            mRectF = new RectF();
        }

        // set the position of the ball
        public boolean setOvalCenter(int x, int y) {
            mXCenter = x;
            mYCenter = y;
            return true;
        }

        // calculate and update the ball's position
        public boolean updateOvalCenter() {
            mVx -= mAx * mDeltaT;
            mVy += mAy * mDeltaT;

            System.out.println("mVx is ::" + mVx);
            System.out.println("mVy is ::" + mVy);

            mXCenter += (int) (mDeltaT * (mVx + 0.6 * mAx * mDeltaT));
            mYCenter += (int) (mDeltaT * (mVy + 0.6 * mAy * mDeltaT));

            if (mXCenter < RADIUS) {
                mXCenter = RADIUS;
                mVx = -mVx * FACTOR_BOUNCEBACK;
            }

            if (mYCenter < RADIUS) {
                mYCenter = RADIUS;
                mVy = -mVy * FACTOR_BOUNCEBACK;
            }
            if (mXCenter > mWidthScreen - RADIUS) {
                mXCenter = mWidthScreen - RADIUS;
                mVx = -mVx * FACTOR_BOUNCEBACK;
            }

            if (mYCenter > mHeightScreen - 2 * RADIUS) {
                mYCenter = mHeightScreen - 2 * RADIUS;
                mVy = -mVy * FACTOR_BOUNCEBACK;
            }

            return true;
        }

        // update the canvas.
        @Override
        protected void onDraw(Canvas canvas) {
            if (mRectF != null) {
                mRectF.set(mXCenter - RADIUS, mYCenter - RADIUS, mXCenter
                        + RADIUS, mYCenter + RADIUS);
                canvas.drawColor(0XFF000000);
                // canvas.drawOval(mRectF, mPaint);

                Bitmap kangoo = BitmapFactory.decodeResource(getResources(),
                        R.drawable.stripe1);

                Bitmap ball = BitmapFactory.decodeResource(getResources(),
                        R.drawable.blackwhiteball);

                canvas.drawBitmap(ball, mXCenter - RADIUS, mYCenter - RADIUS,
                        mPaint);
                canvas.drawBitmap(kangoo, 130, 10, null);

            }
        }

        @Override
        public void surfaceChanged(SurfaceHolder holder, int format, int width,
                int height) {
        }

        @Override
        public void surfaceCreated(SurfaceHolder holder) {
            mThread.setRunning(true);
            mThread.start();
        }

        @Override
        public void surfaceDestroyed(SurfaceHolder holder) {
            boolean retry = true;
            mThread.setRunning(false);
            while (retry) {
                try {
                    mThread.join();
                    retry = false;
                } catch (InterruptedException e) {

                }
            }
        }
    }

    class ShapeThread extends Thread {
        private SurfaceHolder mSurfaceHolder;
        private ShapeView mShapeView;
        private boolean mRun = false;

        public ShapeThread(SurfaceHolder surfaceHolder, ShapeView shapeView) {
            mSurfaceHolder = surfaceHolder;
            mShapeView = shapeView;
        }

        public void setRunning(boolean run) {
            mRun = run;
        }

        public SurfaceHolder getSurfaceHolder() {
            return mSurfaceHolder;
        }

        @Override
        public void run() {
            Canvas c;
            while (mRun) {
                mShapeView.updateOvalCenter();
                c = null;
                try {
                    c = mSurfaceHolder.lockCanvas(null);
                    synchronized (mSurfaceHolder) {
                        mShapeView.onDraw(c);
                    }
                } finally {
                    if (c != null) {
                        mSurfaceHolder.unlockCanvasAndPost(c);
                    }
                }
            }
        }
    }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

祁梦 2025-01-01 09:56:30

不要尝试修复代码,而是通过开发具有两个组件的软件架构来进行设计级别的工作:物理模型和显示。关键是将问题的物理原理与显示分开。当与显示器分开时,物理建模变得更加容易。同样,显示也变得更加容易。有两个单独的包 - 一个用于物理,一个用于显示。

从问题的更简单版本开始,其中物理世界只有一个点和一条线。对直线反射的点进行建模。您有一些代码可以执行此操作。只需将其从当前代码中删除即可。确保物理效果符合您的预期,而无需担心显示。

为球设计一个类。球具有速度和位置属性。它有一种移动方法,可以根据一次单击的速度更新位置。 move 方法检查它是否与墙壁相互作用(碰撞),并根据您希望世界具有的物理特性更改速度。碰撞检测是通过询问墙壁是否存在来完成的。物理原理可能是入射角等于反射角,或者您可以在球上设置旋转属性来改变球的弹跳方式。关键是所有物理建模都是与显示分开完成的。同样,您为墙创建一个类。最初,墙是固定的,但您可以为其添加运动。好处是,如果您正确设计了球类,则更改墙壁以使其移动不会影响球类的设计。此外,这些物理变化都不会影响显示的方式。

制作一个显示器,可以将物理现象简单地转换为屏幕上的演示。

从那里您可以增加模型的复杂性。将点设为圆。重做物理原理,使其能够适应这种新的复杂性。显示不会有太大变化,但将它们分开。

我让我的 CS1 班做了同样问题的版本。两年前,我让他们做了一场乒乓球比赛。去年有一个版本的蜈蚣。下个学期他们将把“突破”作为一个项目。当他们将物理模型与显示器分开时,他们就能让它发挥作用。如果他们不这样做,事情通常会变得一团糟。

Rather than try to fix your code, work at the design level by developing a software architecture that has two components: physics model and display. The key is to separate the physics of the problem from the display. Modelling the physics becomes much easier when done separately from the display. Likewise the display also becomes easier. Have two separate packages - one for the physics and one for the display.

Start with a simpler version of the problem where the physics world just has a point and a line. Model the point reflecting off the line. You have some code that does this. Just rip it out of the current code. Make sure the physics does what you expect it to without worrying about the display.

Design a class for the ball. The ball has velocity and position properties. It has a move method that updates the position based on the velocity for one time click. The move method checks to see if it has interacted (collided) with the wall and changes the velocity according the physics you want your world to have. The collision detection is done by asking the wall were it is. The physics could be angle of incidence equals angle of reflection, or you could have a spin property on the ball that changes how the ball bounces. The key is that all of the physics modelling is done separately from the display. Similarly, you create a class for the wall. Initially the wall is fixed, but you could add movement to it. The nice thing is that if you've designed the ball class correctly changing the wall to make it move doesn't effect the design of the ball class. Also, none of these changes to the physics effect how the display is done.

Make a display that simply translates the physics into a presentation on the screen.

From there you can add complexity to your model. Make the point a circle. Redo the physics to make it work with this new complexity. The display won't change much, but keep them separate.

I have my CS1 class do versions of this same problem. Two years ago, I had them make a pong game. Last year a version of Centipede. This coming semester they'll have Breakout as a project. When they model the physics separately from the display, they get it working. When they don't, it is usually a muddled mess.

绝對不後悔。 2025-01-01 09:56:30

物理模型应在单独的线程中运行,并使用最佳可用时间分辨率进行位置更新。 (毫秒应该足够了)这就是我设计游戏循环的方式:

    lastFrameTime = System.currentTimeMillis();

    // as long as we run we move
    while (state == GameState.RUNNING) {
        currentFrame++;
        timeNow = System.currentTimeMillis();

        // sleep until this frame is scheduled
        long l = lastFrameTime + FRAME_DELAY - timeNow;
        updatePositions();
        redraw();       
        if (l > 0L) {
            try {
                Thread.sleep(l);
            }
            catch (Exception exception) {
            }
        } else {
            // something long kept us from updating, reset delays
            lastFrameTime = timeNow;
            l = FRAME_DELAY;
        }

        lastFrameTime = timeNow + l;
        // be polite, let others play
        Thread.yield();
    }

对于将处理事件和发送给 phyiscs 引擎的 hive 命令的 UI 任务,放弃线程的控制非常重要。

至于碰撞检测——这是非常简单的数学。你的线是垂直的,zou必须检查线和中心的x坐标差是否小于半径 - 然后反转速度的x分量

Physics modyle shall run in separate thread, and use best available time resolution for position updates. ( milliseconds should be enough ) This is how I design gameloop:

    lastFrameTime = System.currentTimeMillis();

    // as long as we run we move
    while (state == GameState.RUNNING) {
        currentFrame++;
        timeNow = System.currentTimeMillis();

        // sleep until this frame is scheduled
        long l = lastFrameTime + FRAME_DELAY - timeNow;
        updatePositions();
        redraw();       
        if (l > 0L) {
            try {
                Thread.sleep(l);
            }
            catch (Exception exception) {
            }
        } else {
            // something long kept us from updating, reset delays
            lastFrameTime = timeNow;
            l = FRAME_DELAY;
        }

        lastFrameTime = timeNow + l;
        // be polite, let others play
        Thread.yield();
    }

It is important to give up control of the thread, for UI tasks which will be processing events and hive commands to your phyiscs engine.

As for collision detection - it is pretty simple math. Your line is vertical, and zou must just check whether difference in x-coord of line and center is got less than radius - then reverse x-componen of velocity

深居我梦 2025-01-01 09:56:30

您可以使用 Rect.intersects(Rect, Rect) 来检测碰撞。使用位图宽度和高度来设置新的矩形。

这是一个肮脏的例子:

import java.util.Timer;

import android.app.Activity;
import android.content.Context;
import android.content.pm.ActivityInfo;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.RectF;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Bundle;
import android.os.Handler;
import android.view.Display;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.WindowManager;

public class ballsensor extends Activity implements SensorEventListener {

// sensor-related
private SensorManager mSensorManager;
private Sensor mAccelerometer;

// animated view
private ShapeView mShapeView;

// screen size
private int mWidthScreen;
private int mHeightScreen;

// motion parameters
private final float FACTOR_FRICTION = 0.5f; // imaginary friction on the
                                            // screen
private final float GRAVITY = 9.8f; // acceleration of gravity
private float mAx; // acceleration along x axis
private float mAy; // acceleration along y axis
private final float mDeltaT = 0.5f; // imaginary time interval between each
                                    // acceleration updates

// timer
private Timer mTimer;
private Handler mHandler;
private final boolean isTimerStarted = false;
private long mStart;

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

    // set the screen always portait
    setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);

    // initializing sensors
    mSensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
    mAccelerometer = mSensorManager
            .getDefaultSensor(Sensor.TYPE_ACCELEROMETER);

    // obtain screen width and height
    final Display display = ((WindowManager) this
            .getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
    mWidthScreen = display.getWidth();
    mHeightScreen = display.getHeight() - 35;

    // initializing the view that renders the ball
    mShapeView = new ShapeView(this);
    mShapeView.setOvalCenter((int) (mWidthScreen * 0.6),
            (int) (mHeightScreen * 0.6));

    setContentView(mShapeView);

}

@Override
public void onAccuracyChanged(final Sensor sensor, final int accuracy) {

}

@Override
public void onSensorChanged(final SensorEvent event) {
    // obtain the three accelerations from sensors
    mAx = event.values[0];
    mAy = event.values[1];

    final float mAz = event.values[2];

    // taking into account the frictions
    mAx = Math.signum(mAx) * Math.abs(mAx)
            * (1 - FACTOR_FRICTION * Math.abs(mAz) / GRAVITY);
    mAy = Math.signum(mAy) * Math.abs(mAy)
            * (1 - FACTOR_FRICTION * Math.abs(mAz) / GRAVITY);
}

@Override
protected void onResume() {
    super.onResume();
    // start sensor sensing
    mSensorManager.registerListener(this, mAccelerometer,
            SensorManager.SENSOR_DELAY_NORMAL);

}

@Override
protected void onPause() {
    super.onPause();
    // stop senser sensing
    mSensorManager.unregisterListener(this);
}

// the view that renders the ball
private class ShapeView extends SurfaceView implements
        SurfaceHolder.Callback {

    private final int RADIUS = 30;
    private final float FACTOR_BOUNCEBACK = 0.50f;

    private int mXCenter;
    private int mYCenter;
    private final RectF mRectF;
    private final Paint mPaint;
    private final ShapeThread mThread;

    private float mVx;
    private float mVy;
    private final Rect lineRect = new Rect();
    private final Rect ballRect = new Rect();

    public ShapeView(final Context context) {
        super(context);

        getHolder().addCallback(this);
        mThread = new ShapeThread(getHolder(), this);
        setFocusable(true);

        mPaint = new Paint();
        mPaint.setColor(0xFFFFFFFF);
        mPaint.setAlpha(192);
        mPaint.setStyle(Paint.Style.FILL_AND_STROKE);
        mPaint.setAntiAlias(true);

        mRectF = new RectF();
    }

    // set the position of the ball
    public boolean setOvalCenter(final int x, final int y) {
        mXCenter = x;
        mYCenter = y;
        return true;
    }

    // calculate and update the ball's position
    public boolean updateOvalCenter() {
        mVx -= mAx * mDeltaT;
        mVy += mAy * mDeltaT;

        System.out.println("mVx is ::" + mVx);
        System.out.println("mVy is ::" + mVy);

        mXCenter += (int) (mDeltaT * (mVx + 0.6 * mAx * mDeltaT));
        mYCenter += (int) (mDeltaT * (mVy + 0.6 * mAy * mDeltaT));

        if (mXCenter < RADIUS) {
            mXCenter = RADIUS;
            mVx = -mVx * FACTOR_BOUNCEBACK;
        }

        if (mYCenter < RADIUS) {
            mYCenter = RADIUS;
            mVy = -mVy * FACTOR_BOUNCEBACK;
        }
        if (mXCenter > mWidthScreen - RADIUS) {
            mXCenter = mWidthScreen - RADIUS;
            mVx = -mVx * FACTOR_BOUNCEBACK;
        }

        if (mYCenter > mHeightScreen - 2 * RADIUS) {
            mYCenter = mHeightScreen - 2 * RADIUS;
            mVy = -mVy * FACTOR_BOUNCEBACK;
        }

        if(Rect.intersects(lineRect, ballRect)){
            mVx = -mVx * FACTOR_BOUNCEBACK;
            mVy = -mVy * FACTOR_BOUNCEBACK;
             mXCenter += (int) (mDeltaT * (mVx + 0.6 * mAx * mDeltaT)) * 5;
             mYCenter += (int) (mDeltaT * (mVy + 0.6 * mAy * mDeltaT)) * 5;
        }

        return true;
    }

    // update the canvas.
    @Override
    protected void onDraw(final Canvas canvas) {
        if (mRectF != null) {
            mRectF.set(mXCenter - RADIUS, mYCenter - RADIUS, mXCenter
                    + RADIUS, mYCenter + RADIUS);
            canvas.drawColor(0XFF000000);
            // canvas.drawOval(mRectF, mPaint);

            final Bitmap kangoo = BitmapFactory.decodeResource(getResources(),
                    R.drawable.blankcard);
            lineRect.set(130, 10, 130 + kangoo.getWidth(), 10 + kangoo.getHeight());

            final Bitmap ball = BitmapFactory.decodeResource(getResources(),
                    R.drawable.blankcard);
            ballRect.set(mXCenter - RADIUS,  mYCenter - RADIUS, mXCenter - RADIUS + ball.getWidth(),  mYCenter - RADIUS + ball.getHeight());

            canvas.drawBitmap(ball, mXCenter - RADIUS, mYCenter - RADIUS,
                    mPaint);
            canvas.drawBitmap(kangoo, 130, 10, null);

        }
    }

    @Override
    public void surfaceChanged(final SurfaceHolder holder, final int format, final int width,
            final int height) {
    }

    @Override
    public void surfaceCreated(final SurfaceHolder holder) {
        mThread.setRunning(true);
        mThread.start();
    }

    @Override
    public void surfaceDestroyed(final SurfaceHolder holder) {
        boolean retry = true;
        mThread.setRunning(false);
        while (retry) {
            try {
                mThread.join();
                retry = false;
            } catch (final InterruptedException e) {

            }
        }
    }
}

class ShapeThread extends Thread {
    private final SurfaceHolder mSurfaceHolder;
    private final ShapeView mShapeView;
    private boolean mRun = false;

    public ShapeThread(final SurfaceHolder surfaceHolder, final ShapeView shapeView) {
        mSurfaceHolder = surfaceHolder;
        mShapeView = shapeView;
    }

    public void setRunning(final boolean run) {
        mRun = run;
    }

    public SurfaceHolder getSurfaceHolder() {
        return mSurfaceHolder;
    }

    @Override
    public void run() {
        Canvas c;
        while (mRun) {
            mShapeView.updateOvalCenter();
            c = null;
            try {
                c = mSurfaceHolder.lockCanvas(null);
                synchronized (mSurfaceHolder) {
                    mShapeView.onDraw(c);
                }
            } finally {
                if (c != null) {
                    mSurfaceHolder.unlockCanvasAndPost(c);
                }
            }
        }
    }
}
}

需要改进,但可能会让你走上正轨。

You can use Rect.intersects(Rect, Rect) to detect collisions. Use your bitmap width and height to set up the new Rects.

Here is a dirty example:

import java.util.Timer;

import android.app.Activity;
import android.content.Context;
import android.content.pm.ActivityInfo;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.RectF;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Bundle;
import android.os.Handler;
import android.view.Display;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.WindowManager;

public class ballsensor extends Activity implements SensorEventListener {

// sensor-related
private SensorManager mSensorManager;
private Sensor mAccelerometer;

// animated view
private ShapeView mShapeView;

// screen size
private int mWidthScreen;
private int mHeightScreen;

// motion parameters
private final float FACTOR_FRICTION = 0.5f; // imaginary friction on the
                                            // screen
private final float GRAVITY = 9.8f; // acceleration of gravity
private float mAx; // acceleration along x axis
private float mAy; // acceleration along y axis
private final float mDeltaT = 0.5f; // imaginary time interval between each
                                    // acceleration updates

// timer
private Timer mTimer;
private Handler mHandler;
private final boolean isTimerStarted = false;
private long mStart;

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

    // set the screen always portait
    setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);

    // initializing sensors
    mSensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
    mAccelerometer = mSensorManager
            .getDefaultSensor(Sensor.TYPE_ACCELEROMETER);

    // obtain screen width and height
    final Display display = ((WindowManager) this
            .getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
    mWidthScreen = display.getWidth();
    mHeightScreen = display.getHeight() - 35;

    // initializing the view that renders the ball
    mShapeView = new ShapeView(this);
    mShapeView.setOvalCenter((int) (mWidthScreen * 0.6),
            (int) (mHeightScreen * 0.6));

    setContentView(mShapeView);

}

@Override
public void onAccuracyChanged(final Sensor sensor, final int accuracy) {

}

@Override
public void onSensorChanged(final SensorEvent event) {
    // obtain the three accelerations from sensors
    mAx = event.values[0];
    mAy = event.values[1];

    final float mAz = event.values[2];

    // taking into account the frictions
    mAx = Math.signum(mAx) * Math.abs(mAx)
            * (1 - FACTOR_FRICTION * Math.abs(mAz) / GRAVITY);
    mAy = Math.signum(mAy) * Math.abs(mAy)
            * (1 - FACTOR_FRICTION * Math.abs(mAz) / GRAVITY);
}

@Override
protected void onResume() {
    super.onResume();
    // start sensor sensing
    mSensorManager.registerListener(this, mAccelerometer,
            SensorManager.SENSOR_DELAY_NORMAL);

}

@Override
protected void onPause() {
    super.onPause();
    // stop senser sensing
    mSensorManager.unregisterListener(this);
}

// the view that renders the ball
private class ShapeView extends SurfaceView implements
        SurfaceHolder.Callback {

    private final int RADIUS = 30;
    private final float FACTOR_BOUNCEBACK = 0.50f;

    private int mXCenter;
    private int mYCenter;
    private final RectF mRectF;
    private final Paint mPaint;
    private final ShapeThread mThread;

    private float mVx;
    private float mVy;
    private final Rect lineRect = new Rect();
    private final Rect ballRect = new Rect();

    public ShapeView(final Context context) {
        super(context);

        getHolder().addCallback(this);
        mThread = new ShapeThread(getHolder(), this);
        setFocusable(true);

        mPaint = new Paint();
        mPaint.setColor(0xFFFFFFFF);
        mPaint.setAlpha(192);
        mPaint.setStyle(Paint.Style.FILL_AND_STROKE);
        mPaint.setAntiAlias(true);

        mRectF = new RectF();
    }

    // set the position of the ball
    public boolean setOvalCenter(final int x, final int y) {
        mXCenter = x;
        mYCenter = y;
        return true;
    }

    // calculate and update the ball's position
    public boolean updateOvalCenter() {
        mVx -= mAx * mDeltaT;
        mVy += mAy * mDeltaT;

        System.out.println("mVx is ::" + mVx);
        System.out.println("mVy is ::" + mVy);

        mXCenter += (int) (mDeltaT * (mVx + 0.6 * mAx * mDeltaT));
        mYCenter += (int) (mDeltaT * (mVy + 0.6 * mAy * mDeltaT));

        if (mXCenter < RADIUS) {
            mXCenter = RADIUS;
            mVx = -mVx * FACTOR_BOUNCEBACK;
        }

        if (mYCenter < RADIUS) {
            mYCenter = RADIUS;
            mVy = -mVy * FACTOR_BOUNCEBACK;
        }
        if (mXCenter > mWidthScreen - RADIUS) {
            mXCenter = mWidthScreen - RADIUS;
            mVx = -mVx * FACTOR_BOUNCEBACK;
        }

        if (mYCenter > mHeightScreen - 2 * RADIUS) {
            mYCenter = mHeightScreen - 2 * RADIUS;
            mVy = -mVy * FACTOR_BOUNCEBACK;
        }

        if(Rect.intersects(lineRect, ballRect)){
            mVx = -mVx * FACTOR_BOUNCEBACK;
            mVy = -mVy * FACTOR_BOUNCEBACK;
             mXCenter += (int) (mDeltaT * (mVx + 0.6 * mAx * mDeltaT)) * 5;
             mYCenter += (int) (mDeltaT * (mVy + 0.6 * mAy * mDeltaT)) * 5;
        }

        return true;
    }

    // update the canvas.
    @Override
    protected void onDraw(final Canvas canvas) {
        if (mRectF != null) {
            mRectF.set(mXCenter - RADIUS, mYCenter - RADIUS, mXCenter
                    + RADIUS, mYCenter + RADIUS);
            canvas.drawColor(0XFF000000);
            // canvas.drawOval(mRectF, mPaint);

            final Bitmap kangoo = BitmapFactory.decodeResource(getResources(),
                    R.drawable.blankcard);
            lineRect.set(130, 10, 130 + kangoo.getWidth(), 10 + kangoo.getHeight());

            final Bitmap ball = BitmapFactory.decodeResource(getResources(),
                    R.drawable.blankcard);
            ballRect.set(mXCenter - RADIUS,  mYCenter - RADIUS, mXCenter - RADIUS + ball.getWidth(),  mYCenter - RADIUS + ball.getHeight());

            canvas.drawBitmap(ball, mXCenter - RADIUS, mYCenter - RADIUS,
                    mPaint);
            canvas.drawBitmap(kangoo, 130, 10, null);

        }
    }

    @Override
    public void surfaceChanged(final SurfaceHolder holder, final int format, final int width,
            final int height) {
    }

    @Override
    public void surfaceCreated(final SurfaceHolder holder) {
        mThread.setRunning(true);
        mThread.start();
    }

    @Override
    public void surfaceDestroyed(final SurfaceHolder holder) {
        boolean retry = true;
        mThread.setRunning(false);
        while (retry) {
            try {
                mThread.join();
                retry = false;
            } catch (final InterruptedException e) {

            }
        }
    }
}

class ShapeThread extends Thread {
    private final SurfaceHolder mSurfaceHolder;
    private final ShapeView mShapeView;
    private boolean mRun = false;

    public ShapeThread(final SurfaceHolder surfaceHolder, final ShapeView shapeView) {
        mSurfaceHolder = surfaceHolder;
        mShapeView = shapeView;
    }

    public void setRunning(final boolean run) {
        mRun = run;
    }

    public SurfaceHolder getSurfaceHolder() {
        return mSurfaceHolder;
    }

    @Override
    public void run() {
        Canvas c;
        while (mRun) {
            mShapeView.updateOvalCenter();
            c = null;
            try {
                c = mSurfaceHolder.lockCanvas(null);
                synchronized (mSurfaceHolder) {
                    mShapeView.onDraw(c);
                }
            } finally {
                if (c != null) {
                    mSurfaceHolder.unlockCanvasAndPost(c);
                }
            }
        }
    }
}
}

Needs improvement but might get you on the right track.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文