Question

I am unable to create more circles which follows its own path with drawCircle .

I have used the code below which creates another circle but follows the path along the lines of 1st circle but not independent .How do I move both circles independent of each other?

I have added

    c.drawCircle(ballX-100, ballY-100, 50, ballPaintyellow);

How do I make the above circle independent from the 1st circle?. I really appreciate any help.Thanks in Advance.

BouncingBallActivity.java

 package com.stuffthathappens.games;

    import static android.hardware.SensorManager.DATA_X;
    import static android.hardware.SensorManager.DATA_Y;
    import static android.hardware.SensorManager.SENSOR_ACCELEROMETER;
    import static android.hardware.SensorManager.SENSOR_DELAY_GAME;

    import java.util.concurrent.TimeUnit;

    import android.app.Activity;
    import android.graphics.Canvas;
    import android.graphics.Color;
    import android.graphics.Paint;
    import android.hardware.SensorListener;
    import android.hardware.SensorManager;
    import android.os.Bundle;
    import android.os.Vibrator;
    import android.view.SurfaceHolder;
    import android.view.SurfaceView;
    import android.view.SurfaceHolder.Callback;

    /**
     * This activity shows a ball that bounces around. The phone's 
     * accelerometer acts as gravity on the ball. When the ball hits
     * the edge, it bounces back and triggers the phone vibrator.
     */
    @SuppressWarnings("deprecation")
    public class BouncingBallActivity extends Activity implements Callback, SensorListener {
        private static final int BALL_RADIUS =20;
        private SurfaceView surface;
        private SurfaceHolder holder;
        private final BouncingBallModel model = new BouncingBallModel(BALL_RADIUS);
        private GameLoop gameLoop;
        private Paint backgroundPaint;
        private Paint ballPaint;
        private SensorManager sensorMgr;
        private long lastSensorUpdate = -1;


        private Paint ballPaintyellow;

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

            setContentView(R.layout.bouncing_ball);

            surface = (SurfaceView) findViewById(R.id.bouncing_ball_surface);
            holder = surface.getHolder();
            surface.getHolder().addCallback(this);

            backgroundPaint = new Paint();
            backgroundPaint.setColor(Color.WHITE);

            ballPaint = new Paint();
            ballPaint.setColor(Color.BLUE);
            ballPaint.setAntiAlias(true);

            ballPaintyellow = new Paint();
            ballPaintyellow.setColor(Color.YELLOW);
            ballPaintyellow.setAntiAlias(true);
        }

        @Override
        protected void onPause() {
            super.onPause();

            model.setVibrator(null);

            sensorMgr.unregisterListener(this, SENSOR_ACCELEROMETER);
            sensorMgr = null;

            model.setAccel(0, 0);
        }

        @Override
        protected void onResume() {
            super.onResume();

            sensorMgr = (SensorManager) getSystemService(SENSOR_SERVICE);
            boolean accelSupported = sensorMgr.registerListener(this, 
                    SENSOR_ACCELEROMETER,
                    SENSOR_DELAY_GAME);

            if (!accelSupported) {
                // on accelerometer on this device
                sensorMgr.unregisterListener(this, SENSOR_ACCELEROMETER);
                // TODO show an error
            }

            // NOTE 1: you cannot get system services before onCreate()
            // NOTE 2: AndroidManifest.xml must contain this line:
            // <uses-permission android:name="android.permission.VIBRATE"/>
            Vibrator vibrator = (Vibrator) getSystemService(Activity.VIBRATOR_SERVICE);
            model.setVibrator(vibrator);
        }

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

            model.setSize(width, height);
        }

        public void surfaceCreated(SurfaceHolder holder) {
            gameLoop = new GameLoop();
            gameLoop.start();
        }

        private void draw() {
            // thread safety - the SurfaceView could go away while we are drawing

            Canvas c = null;
            try {
                // NOTE: in the LunarLander they don't have any synchronization here,
                // so I guess this is OK. It will return null if the holder is not ready
                c = holder.lockCanvas();

                // this needs to synchronize on something
                if (c != null) {
                    doDraw(c);
                }
            } finally {
                if (c != null) {
                    holder.unlockCanvasAndPost(c);
                }
            }
        }

        private void doDraw(Canvas c) {
            int width = c.getWidth();
            int height = c.getHeight();
            c.drawRect(0, 0, width, height, backgroundPaint);

            float ballX, ballY;
            synchronized (model.LOCK) {
                ballX = model.ballPixelX;
                ballY = model.ballPixelY;

            }
            c.drawCircle(ballX, ballY, BALL_RADIUS, ballPaint);


            c.drawCircle(ballX-100, ballY-100, 50, ballPaintyellow);
        }

        public void surfaceDestroyed(SurfaceHolder holder) {
            try {
                model.setSize(0,0);
                gameLoop.safeStop();
            } finally {
                gameLoop = null;
            }
        }

        private class GameLoop extends Thread {
            private volatile boolean running = true;

            public void run() {
                while (running) {
                    try {
                        //  don't like this hardcoding
                        TimeUnit.MILLISECONDS.sleep(5);

                        draw();
                        model.updatePhysics();

                    } catch (InterruptedException ie) {
                        running = false;
                    }
                }
            }

            public void safeStop() {
                running = false;
                interrupt();
            }
        }

        public void onAccuracyChanged(int sensor, int accuracy) {       
        }

        public void onSensorChanged(int sensor, float[] values) {
            if (sensor == SENSOR_ACCELEROMETER) {
                long curTime = System.currentTimeMillis();
                // only allow one update every 50ms, otherwise updates
                // come way too fast
                if (lastSensorUpdate == -1 || (curTime - lastSensorUpdate) > 50) {
                    lastSensorUpdate = curTime;

                    model.setAccel(values[DATA_X], values[DATA_Y]);
                }
            }
        }
    }

Bouncingballmodel.java

package com.stuffthathappens.games;

import java.util.concurrent.atomic.AtomicReference;

import android.os.Vibrator;

/**
 * This data model tracks the width and height of the playing field along 
 * with the current position of a ball. 
 */
public class BouncingBallModel {
    // the ball speed is meters / second. When we draw to the screen,
    // 1 pixel represents 1 meter. That ends up too slow, so multiply
    // by this number. Bigger numbers speeds things up.
    private final float pixelsPerMeter = 10;

    private final int ballRadius;

    // these are public, so make sure you synchronize on LOCK 
    // when reading these. I made them public since you need to
    // get both X and Y in pairs, and this is more efficient than
    // getter methods. With two getters, you'd still need to 
    // synchronize.
    public float ballPixelX, ballPixelY;

    private int pixelWidth, pixelHeight;

    // values are in meters/second
    private float velocityX, velocityY;

    // typical values range from -10...10, but could be higher or lower if
    // the user moves the phone rapidly
    private float accelX, accelY;

    /**
     * When the ball hits an edge, multiply the velocity by the rebound.
     * A value of 1.0 means the ball bounces with 100% efficiency. Lower
     * numbers simulate balls that don't bounce very much.
     */
    private static final float rebound = 0.8f;

    // if the ball bounces and the velocity is less than this constant,
    // stop bouncing.
    private static final float STOP_BOUNCING_VELOCITY = 2f;

    private volatile long lastTimeMs = -1;

    public final Object LOCK = new Object();

    private AtomicReference<Vibrator> vibratorRef =
        new AtomicReference<Vibrator>();

    public BouncingBallModel(int ballRadius) {
        this.ballRadius = ballRadius;
    }

    public void setAccel(float ax, float ay) {
        synchronized (LOCK) {
            this.accelX = ax;
            this.accelY = ay;
        }
    }

    public void setSize(int width, int height) {
        synchronized (LOCK) {
            this.pixelWidth = width;
            this.pixelHeight = height;
        }
    }

    public int getBallRadius() {
        return ballRadius;
    }

    /**
     * Call this to move the ball to a particular location on the screen. This
     * resets the velocity to zero, but the acceleration doesn't change so
     * the ball should start falling shortly.
     */
    public void moveBall(int ballX, int ballY) {
        synchronized (LOCK) {
            this.ballPixelX = ballX;
            this.ballPixelY = ballY;
            velocityX = 0;
            velocityY = 0;
        }
    }

    public void updatePhysics() {
        // copy everything to local vars (hence the 'l' prefix)
        float lWidth, lHeight, lBallX, lBallY, lAx, lAy, lVx, lVy;
        synchronized (LOCK) {
            lWidth = pixelWidth;
            lHeight = pixelHeight;
            lBallX = ballPixelX;
            lBallY = ballPixelY;
            lVx = velocityX;            
            lVy = velocityY;
            lAx = accelX;
            lAy = -accelY;
        }


        if (lWidth <= 0 || lHeight <= 0) {
            // invalid width and height, nothing to do until the GUI comes up
            return;
        }


        long curTime = System.currentTimeMillis();
        if (lastTimeMs < 0) {
            lastTimeMs = curTime;
            return;
        }

        long elapsedMs = curTime - lastTimeMs;
        lastTimeMs = curTime;

        // update the velocity
        // (divide by 1000 to convert ms to seconds)
        // end result is meters / second
        lVx += ((elapsedMs * lAx) / 1000) * pixelsPerMeter;
        lVy += ((elapsedMs * lAy) / 1000) * pixelsPerMeter;

        // update the position
        // (velocity is meters/sec, so divide by 1000 again)
        lBallX += ((lVx * elapsedMs) / 1000) * pixelsPerMeter;
        lBallY += ((lVy * elapsedMs) / 1000) * pixelsPerMeter;

        boolean bouncedX = false;
        boolean bouncedY = false;

        if (lBallY - ballRadius < 0) {
            lBallY = ballRadius;
            lVy = -lVy * rebound;
            bouncedY = true;
        } else if (lBallY + ballRadius > lHeight) {
            lBallY = lHeight - ballRadius;
            lVy = -lVy * rebound;
            bouncedY = true;
        }
        if (bouncedY && Math.abs(lVy) < STOP_BOUNCING_VELOCITY) {
            lVy = 0;  
            bouncedY = false;
        }

        if (lBallX - ballRadius < 0) {
            lBallX = ballRadius;
            lVx = -lVx * rebound;
            bouncedX = true;
        } else if (lBallX + ballRadius > lWidth) {
            lBallX = lWidth - ballRadius;
            lVx = -lVx * rebound;
            bouncedX = true;
        }
        if (bouncedX && Math.abs(lVx) < STOP_BOUNCING_VELOCITY) {
            lVx = 0;
            bouncedX = false;
        }


        // safely copy local vars back to object fields
        synchronized (LOCK) {
            ballPixelX = lBallX;
            ballPixelY = lBallY;

            velocityX = lVx;
            velocityY = lVy;
        }

        if (bouncedX || bouncedY) {
            Vibrator v = vibratorRef.get();
            if (v != null) {
                v.vibrate(20L);
            }
        }
    }

    public void setVibrator(Vibrator v) {
        vibratorRef.set(v);
    }
}
Was it helpful?

Solution

Which view you are using has nothing to do with it .... At the moment you have only one BouncingBallModel

private final BouncingBallModel model = new BouncingBallModel(BALL_RADIUS);

This is the one you see when you draw something. Now if you want to draw multiple balls, you will need many BouncingBallModel. So either create a BouncingBallModel model2 or make it dynamic using an array.

Then iterate over the array and draw each ball.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top