Create dropping ball - android

When the play button is pressed to start the game(activity), I'd like to create the instance of a ball falling from the top of the screen (the ball will hit something later). I'm not sure how to go about it. Can anyone assist?
What I'm working with so far:
public class GameActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Turn title off
requestWindowFeature(Window.FEATURE_NO_TITLE);
// set Game to fullscreen
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
View ballView = new BallView(this);
setContentView(ballView);
// ballView.setBackgroundColor(Color.TRANSPARENT);
}
}
and
public class BallView extends View {
// Ball attributes
private float ballRadius = 30;
private float ballX = 50;
private float ballY = 50;
private RectF ballBounds;
private Paint ballColor;
// For game elements
private int score = 0;
public BallView(Context context){
super(context);
// Initialize game elements
ballBounds = new RectF();
ballColor = new Paint();
this.setFocusableInTouchMode(true);
}
public void onDraw(Canvas canvas){
// Draw ball
ballBounds.set(ballX - ballRadius, ballY - ballRadius, ballX + ballRadius, ballY + ballRadius);
ballColor.setColor(Color.RED);
canvas.drawOval(ballBounds, ballColor);
}
}

From the description of your intent, you should probably use OpenGL or a framework like libgdx which has physics and collision detection built in.
But to answer you question, you try this quick example:
import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.view.View;
import android.view.ViewTreeObserver;
public class BallView extends View{
// Ball attributes
private float ballRadius = 30;
private float ballX = 50;
private float ballY = 50;
private float ballSpeed = 10.0f;
private RectF ballBounds;
private Paint ballColor;
boolean doBallAnimation = false;
// For game elements
private int score = 0;
ValueAnimator animator = ValueAnimator.ofFloat(0, 1);
long startTime, prevTime; // Used to track elapsed time for animations and fps
public BallView(Context context){
super(context);
// Initialize game elements
ballBounds = new RectF();
ballColor = new Paint();
this.setFocusableInTouchMode(true);
getViewTreeObserver().addOnGlobalLayoutListener(
new ViewTreeObserver.OnGlobalLayoutListener(){
#Override
public void onGlobalLayout(){
getViewTreeObserver().removeOnGlobalLayoutListener(this);
ballY = 0;
ballX = (getWidth()- ballRadius) / 2.0f;
doBallAnimation = true;
animator.start();
}
}
);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener(){
#Override
public void onAnimationUpdate(ValueAnimator arg0){
long nowTime = System.currentTimeMillis();
float secs = (float)(nowTime - prevTime) / 1000f;
prevTime = nowTime;
if((ballY + ballSpeed) > (getHeight() - (ballRadius)))
{
animator.cancel();
return;
}
ballY += ballSpeed;
// Force a redraw to see the ball in its new position
invalidate();
}
});
animator.setRepeatCount(ValueAnimator.INFINITE);
animator.setDuration(3000);
}
public void onDraw(Canvas canvas){
// Draw ball
if(doBallAnimation)
{
ballBounds.set(ballX - ballRadius, ballY - ballRadius, ballX + ballRadius, ballY + ballRadius);
ballColor.setColor(Color.RED);
canvas.drawOval(ballBounds, ballColor);
}
}
}

Related

Android SweepGradient and Drawing Lines in a circular pattern

I am trying to achieve this circular progress bar with gradient intervals UI effect
Currently I have been able to achieve this.
The code for my current implementation is below.
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.ColorFilter;
import android.graphics.LinearGradient;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Shader;
import android.graphics.SweepGradient;
import android.graphics.drawable.AnimationDrawable;
import android.support.annotation.IntRange;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
public class CBPDrawable extends AnimationDrawable {
Paint paint = new Paint();
RectF clip = new RectF();
LinearGradient shader;
Path path;
private static final int MAX = 360;
int dots = 75;
int dotRadius = 20;
RectF dotRect;
Context mContext;
public CBPDrawable(Context context){
mContext = context;
}
Shader gradient;
private int mTickOffset = 0;
private int mTickLength = 15;
private int mArcRadius = 10;
double slope, startTickX, startTickY, endTickX, endTickY, midTickX, midTickY, thetaInRadians;
double radiusOffset = mArcRadius + mTickOffset;
#Override
protected void onBoundsChange(Rect bounds) {
super.onBoundsChange(bounds);
path = new Path();
dotRect = new RectF(0, 0, dotRadius, dotRadius);
/*
for (int i = 0; i < dots; ++i) {
start();
path.addRoundRect(dotRect, dotRadius, dotRadius, Path.Direction.CCW);
stop();
}
*/
for (int i = 360; i >= 0; i -= 5) {
thetaInRadians = Math.toRadians(360 - i);
slope = Math.tan(thetaInRadians);
startTickX = (radiusOffset * Math.cos(thetaInRadians));
startTickY = slope * startTickX;
endTickX = startTickX + ((mTickLength) * Math.cos(thetaInRadians));
endTickY = slope * endTickX;
RectF r = new RectF();
r.set((float) startTickX, (float) startTickY, (float) endTickX, (float) endTickY);
path.addRoundRect(r, (int)radiusOffset, (int)radiusOffset, Path.Direction.CCW);
}
}
#Override
public void draw(#NonNull Canvas canvas) {
Rect b = getBounds();
final int width = canvas.getWidth();
final int height = canvas.getHeight();
final int squareSide = Math.min(width, height);
canvas.translate(width / 2f, height / 2f); // moving to the center of the View
canvas.rotate(270);
final float outerRadius = squareSide / 2f;
final float innerRadius = outerRadius - dotRadius;
final float angleFactor = 360f / 72;
int[] colors = new int[]{Color.BLUE, Color.RED};
float[] positions = new float[]{0,0.4f};
gradient = new SweepGradient(outerRadius / 2f, outerRadius / 2f,colors,null);
for (int i = 0; i < 72; ++i) {
canvas.save(); // creating a "checkpoint"
canvas.rotate(angleFactor * i);
canvas.translate(innerRadius, 0); //moving to the edge of the big circle
clip.set(b);
paint.setColor(Color.GRAY);
if(angleFactor * i <= 200){
paint.setShader(gradient);
}else{
paint.setShader(null);
}
//canvas.clipRect(clip, Region.Op.REPLACE);
canvas.drawPath(path, paint);
canvas.restore(); //restoring a "checkpoint"
//stop();
}
}
#Override
public void setAlpha(#IntRange(from = 0, to = 255) int i) {
}
#Override
public void setColorFilter(#Nullable ColorFilter colorFilter) {
}
#Override
public int getOpacity() {
return PixelFormat.OPAQUE;
}
}
As can be seen from the 2 images, I am unable to get the intervals correctly as a rectangle or line.
And, the gradient does not show, in spite of using a SweepGradient.
How should I go about achieving the desired effect?
Thanks.

How to make a square shape generate in an Android app instead of a circle

I am working on a android launcher that shows the 1st 4 app icons in a grid view however I'm trying to display the folder as a square shape it's showing up as a circle shape...
heres my code:
package appname.launcher.util;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.ColorFilter;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Rect;
import android.graphics.Region;
import android.graphics.drawable.Drawable;
import android.view.View;
import Appname.launcher.activity.Home;
public class GroupIconDrawable extends Drawable{
private int outlinepad;
Bitmap[] icons;
public int iconSize;
Paint paint;
Paint paint2;
Paint paint4;
private int iconSizeDiv2;
private int padding;
private float scaleFactor = 1;
private boolean needAnimate,needAnimatScale;
public View v;
private float sx = 1;
private float sy = 1 ;
public GroupIconDrawable(Bitmap[] icons,int size){
init(icons,size);
}
private void init(Bitmap[] icons,int size){
this.icons = icons;
this.iconSize = size;
iconSizeDiv2 = Math.round(iconSize / 2f);
padding = iconSize /25;
this.paint = new Paint();
paint.setColor(Color.WHITE);
paint.setAlpha(200);
paint.setAntiAlias(true);
this.paint4 = new Paint();
paint4.setColor(Color.WHITE);
paint4.setAntiAlias(true);
paint4.setFlags(Paint.ANTI_ALIAS_FLAG);
paint4.setStyle(Paint.Style.STROKE);
outlinepad = Tools.convertDpToPixel(2, Home.desktop.getContext());
paint4.setStrokeWidth(outlinepad);
this.paint2 = new Paint();
paint2.setAntiAlias(true);
paint2.setFilterBitmap(true);
}
public GroupIconDrawable(Bitmap[] icons,int size,View v){
init(icons,size);
this.v =v;
}
public void popUp(){
sy = 1;
sx = 1;
needAnimate = true;
needAnimatScale = true;
invalidateSelf();
}
public void popBack(){
needAnimate = false;
needAnimatScale = false;
invalidateSelf();
}
#Override
public void draw(Canvas canvas) {
canvas.save();
if (needAnimatScale){
scaleFactor = Tools.clampFloat(scaleFactor-0.09f,0.5f,1f);
}else {
scaleFactor = Tools.clampFloat(scaleFactor+0.09f,0.5f,1f);
}
if (v == null)
canvas.scale(scaleFactor,scaleFactor,iconSize/2,iconSize/2);
else
canvas.scale(scaleFactor,scaleFactor,iconSize/2,v.getHeight() / 2);
if (v!= null)
canvas.translate(0,v.getHeight()/2-iconSize/2);
Path clipp = new Path();
clipp.addCircle(iconSize / 2,iconSize / 2,iconSize / 2-outlinepad, Path.Direction.CW);
canvas.clipPath(clipp, Region.Op.REPLACE);
canvas.drawBitmap(icons[0],null,new Rect(padding,padding, iconSizeDiv2-padding, iconSizeDiv2-padding),paint2);
canvas.drawBitmap(icons[1],null,new Rect(iconSizeDiv2+padding,padding,iconSize-padding, iconSizeDiv2-padding),paint2);
canvas.drawBitmap(icons[2],null,new Rect(padding, iconSizeDiv2+padding, iconSizeDiv2-padding,iconSize-padding),paint2);
canvas.drawBitmap(icons[3],null,new Rect(iconSizeDiv2+padding, iconSizeDiv2+padding,iconSize-padding,iconSize-padding),paint2);
canvas.clipRect(0,0,iconSize,iconSize, Region.Op.REPLACE);
canvas.restore();
if (needAnimate){
paint2.setAlpha(Tools.clampInt(paint2.getAlpha()-25,0,255));
invalidateSelf();
}else if (paint2.getAlpha() != 255){
paint2.setAlpha(Tools.clampInt(paint2.getAlpha()+25,0,255));
invalidateSelf();
}
}
#Override
public void setAlpha(int i) {}
#Override
public void setColorFilter(ColorFilter colorFilter) {}
#Override
public int getOpacity() {return 0;}
}
I think its because of the > clipp.addCircle(iconSize / 2,iconSize /
2,iconSize / 2-outlinepad,> Path.Direction.CW); code but i'm not sure
how would I make it a square instead of a circle?
change your clipp Path usage from addCircle to be addRect(float left, float top, float right, float bottom, Path.Direction dir)

Android uber ping request animation or component

Can any one suggest me how to do circle animation and progress button like Uber driver pickup request in Android. If you can provide some code that will be good.
You can refer to this.
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.os.Handler;
import android.util.AttributeSet;
import android.view.View;
import com.circularseekbar.R;
public class CircularProgressBar extends View {
private Context mContext;
private Paint circleColor, innerColor, circleRing;
private int angle = 0, startAngle = 270, barWidth = 50, maxProgress = 100;
private int width, height, progress=1, tmpProgress=1, progressPercent;
private float innerRadius, outerRadius, adjustmentFactor=100;//The radius of the inner circle
private float cx, cy; //The circle's center X, Y coordinate
private float left, right, top, bottom, startPointX, startPointY, markPointX, markPointY;
private float dx, dy;//The X and Y coordinate for the top left corner of the marking drawable
private Bitmap progressMark, progressMarkPressed;
private RectF rect = new RectF();
{
circleColor = new Paint();
innerColor = new Paint();
circleRing = new Paint();
circleColor.setColor(Color.parseColor("#ff33b5e5")); // Set default
// progress
// color to holo
// blue.
innerColor.setColor(Color.BLACK); // Set default background color to
// black
circleRing.setColor(Color.GRAY);// Set default background color to Gray
circleColor.setAntiAlias(true);
innerColor.setAntiAlias(true);
circleRing.setAntiAlias(true);
circleColor.setStrokeWidth(25);
innerColor.setStrokeWidth(15);
circleRing.setStrokeWidth(10);
circleColor.setStyle(Paint.Style.FILL);
}
public CircularProgressBar(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
mContext = context;
}
public CircularProgressBar(Context context, AttributeSet attrs) {
super(context, attrs);
mContext = context;
}
public CircularProgressBar(Context context) {
super(context);
mContext = context;
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
width = getWidth(); // Get View Width
height = getHeight();// Get View Height
int size = (width > height) ? height : width; // Choose the smaller
// between width and
// height to make a
// square
cx = width / 2; // Center X for circle
cy = height / 2; // Center Y for circle
outerRadius = size / 2; // Radius of the outer circle
innerRadius = outerRadius - barWidth; // Radius of the inner circle
left = cx - outerRadius; // Calculate left bound of our rect
right = cx + outerRadius;// Calculate right bound of our rect
top = cy - outerRadius;// Calculate top bound of our rect
bottom = cy + outerRadius;// Calculate bottom bound of our rect
startPointX = cx; // 12 O'clock X coordinate
startPointY = cy - outerRadius;// 12 O'clock Y coordinate
markPointX = startPointX;// Initial locatino of the marker X coordinate
markPointY = startPointY;// Initial locatino of the marker Y coordinate
rect.set(left, top, right, bottom); // assign size to rect
}
#Override
public void onDraw(Canvas canvas) {
canvas.drawCircle(cx, cy, outerRadius, circleRing);
canvas.drawArc(rect, startAngle, angle, true, circleColor);
canvas.drawCircle(cx, cy, innerRadius, innerColor);
super.onDraw(canvas);
}
public int getAngle() {
return angle;
}
public void setAngle(int angle) {
//System.out.println("Angel "+angle);
this.angle = angle;
float donePercent = (((float) this.angle) / 360) * 100;
float progress = (donePercent / 100) * getMaxProgress();
setProgressPercent(Math.round(donePercent));
setProgress(Math.round(progress));
}
public int getBarWidth() {
return barWidth;
}
public void setBarWidth(int barWidth) {
this.barWidth = barWidth;
}
public int getMaxProgress() {
return maxProgress;
}
public void setMaxProgress(int maxProgress) {
this.maxProgress = maxProgress;
}
public int getProgress() {
return progress;
}
public void setProgress(int progress) {
if (this.progress != progress) {
this.progress = progress;
int newPercent = (this.progress * 100) / this.maxProgress;
int newAngle = (newPercent * 360) / 100;
this.setAngle(newAngle);
this.setProgressPercent(newPercent);
}
}
long mAnimStartTime;
Handler mHandler = new Handler();
Runnable mTick = new Runnable() {
public void run() {
invalidate();
update();
mHandler.postDelayed(this, 100); // 20ms == 60fps
}
};
public void update(){
if(IS_ACTIVE){
setProgress(tmpProgress);
if(tmpProgress>maxProgress){
stopAnimation();
}
tmpProgress++;
}
}
boolean IS_ACTIVE=false;
public void startAnimation() {
IS_ACTIVE=true;
tmpProgress=1;
mHandler.removeCallbacks(mTick);
mHandler.post(mTick);
}
public void stopAnimation() {
IS_ACTIVE=false;
progress=1;
mHandler.removeCallbacks(mTick);
}
public int getProgressPercent() {
return progressPercent;
}
public void setProgressPercent(int progressPercent) {
this.progressPercent = progressPercent;
}
public void setRingBackgroundColor(int color) {
circleRing.setColor(color);
}
public void setBackGroundColor(int color) {
innerColor.setColor(color);
}
public void setProgressColor(int color) {
circleColor.setColor(color);
}
public float getAdjustmentFactor() {
return adjustmentFactor;
}
public void setAdjustmentFactor(float adjustmentFactor) {
this.adjustmentFactor = adjustmentFactor;
}
}

Get a ball to roll around inside another circle

I'm trying to get a ball to bounce and roll around inside another ball, ultimately based on the accelerometer. There are countless tutorials out there to detect circle collisions and such, and they are indeed marginally helpful. Unfortunately, none that I have found deal with circle-inside-of-a-circle collision only circles bouncing around in a rectangle view.
Several helpful URLs are, where I got most of this code:
http://xiangchen.wordpress.com/2011/12/17/an-android-accelerometer-example/
circle-circle collision
..but again, this isn't quite what I'm after.
I want to get a circle to bounce and roll around inside of another circle. Then, after that, I will want the inner ball to roll down the inside of the outer circle at the right time as the velocity lessens, not simply bounce to the bottom. Am I articulating that clearly? And finally, the bounce angle will need to be adjusted I'm sure so I will ultimately need to figure out how to do that as well.
My code is a mess because I've tried so many things, so in particular, the commented block isn't even close to what it needs to be I don't think. It is just my latest attempt.
Anyone know a little something about this and willing to give me a hand? I would appreciate it.
Edit: This guy is very close to what I'm after, but I am having trouble making sense of it and converting the selected answer into Java. Help? https://gamedev.stackexchange.com/questions/29650/circle-inside-circle-collision
import android.app.Activity;
import android.content.Context;
import android.content.pm.ActivityInfo;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Point;
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.util.DisplayMetrics;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
public class Main extends Activity implements SensorEventListener {
private SensorManager mSensorManager;
private Sensor mAccelerometer;
private ShapeView mShapeView;
private int mWidthScreen;
private int mHeightScreen;
private final float FACTOR_FRICTION = 0.2f; // 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
private static final float OUTERSTROKE = 5;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
mSensorManager = (SensorManager)getSystemService(SENSOR_SERVICE);
mAccelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
DisplayMetrics displaymetrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(displaymetrics);
mWidthScreen = displaymetrics.widthPixels;
mHeightScreen = displaymetrics.heightPixels;
mShapeView = new ShapeView(this);
mShapeView.initOvalCenter((int) (mWidthScreen * 0.6), (int) (mHeightScreen * 0.6));
setContentView(mShapeView);
}
#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
public void onAccuracyChanged(Sensor sensor, int accuracy) {
}
#Override
protected void onResume() {
super.onResume();
// start sensor sensing
mSensorManager.registerListener(this, mAccelerometer, SensorManager.SENSOR_DELAY_NORMAL);
}
#Override
protected void onPause() {
super.onPause();
// stop sensor sensing
mSensorManager.unregisterListener(this);
}
// the view that renders the ball
private class ShapeView extends SurfaceView implements SurfaceHolder.Callback {
private final int BALLRADIUS = 100;
private final float FACTOR_BOUNCEBACK = 0.15f;
private final int OUTERRADIUS = 300;
private Point ballCenter = new Point();
private RectF mRectF;
private final Paint mPaint;
private ShapeThread mThread;
private float mVx;
private float mVy;
private final Paint outerPaint;
private RectF outerBounds;
private Point outerCenter;
private final double outerDiagonal;
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);
mPaint.setAntiAlias(true);
outerPaint= new Paint();
outerPaint.setColor(0xFFFFFFFF);
outerPaint.setAlpha(255);
outerPaint.setStrokeWidth(OUTERSTROKE);
outerPaint.setStyle(Paint.Style.STROKE);
outerPaint.setAntiAlias(true);
mRectF = new RectF();
outerDiagonal= Math.pow(BALLRADIUS - OUTERRADIUS, 2);
}
public void initOvalCenter(int x, int y) {
mShapeView.setOvalCenter(x, y);
outerCenter= new Point(x, y);
outerBounds = new RectF(x - OUTERRADIUS, y - OUTERRADIUS, x + OUTERRADIUS, y + OUTERRADIUS);
}
public boolean setOvalCenter(int x, int y) {
ballCenter.set(x, y);
return true;
}
public boolean updateOvalCenter() {
/*-------
* This is where the trouble is, currently. How do I "snap" the inner circle back into the
* outer circle? Or even better, how do I keep it from crossing the line to bring with?
*/
mVx -= mAx * mDeltaT;
mVy += mAy * mDeltaT;
Point newBallCenter = new Point();
newBallCenter.x = ballCenter.x + (int) (mDeltaT * (mVx + 0.5 * mAx * mDeltaT));
newBallCenter.y = ballCenter.y + (int) (mDeltaT * (mVy + 0.5 * mAy * mDeltaT));
double distance = Math.sqrt(Math.pow(newBallCenter.x - outerCenter.x, 2) + Math.pow(newBallCenter.y - outerCenter.y, 2));
if(distance >= OUTERRADIUS - BALLRADIUS) {
mVx = -mVx * FACTOR_BOUNCEBACK;
mVy = -mVy * FACTOR_BOUNCEBACK;
newBallCenter.x = ballCenter.x + (int) (mDeltaT * (mVx + 0.5 * mAx * mDeltaT));
newBallCenter.y = ballCenter.y + (int) (mDeltaT * (mVy + 0.5 * mAy * mDeltaT));
}
ballCenter.x = newBallCenter.x;
ballCenter.y = newBallCenter.y;
return true;
}
protected void doDraw(Canvas canvas) {
if (mRectF != null && canvas != null) {
mRectF.set(ballCenter.x - BALLRADIUS, ballCenter.y - BALLRADIUS, ballCenter.x + BALLRADIUS, ballCenter.y + BALLRADIUS);
canvas.drawColor(0XFF000000);
canvas.drawOval(mRectF, mPaint);
canvas.drawOval(outerBounds, outerPaint);
}
}
#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 ignored) { }
}
}
}
class ShapeThread extends Thread {
private final 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;
}
#Override
public void run() {
Canvas c;
while (mRun) {
mShapeView.updateOvalCenter();
c = null;
try {
c = mSurfaceHolder.lockCanvas(null);
synchronized (mSurfaceHolder) {
mShapeView.doDraw(c);
}
} finally {
if (c != null) {
mSurfaceHolder.unlockCanvasAndPost(c);
}
}
}
}
}
}
I thought i would answer this to at least help you even if it doesnt answer your question completely.
Below is your code with changes to a few things
i fixed your issue with snapping the inner circle back when a collision occurs.
Basically you need to move the inner circle back by one frame once a collision has occured. i think you tried doing this however you were resetting these values just before the collision check. I also added a little check to the velocity to say if it was less than 0.5 then just move the inner circle to the last frame without a bounce to get rid of the judering bouncing effect when it is trying to settle.
package com.test.circleincircle;
import android.app.Activity;
import android.content.Context;
import android.content.pm.ActivityInfo;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Point;
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.util.DisplayMetrics;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
public class Main extends Activity implements SensorEventListener {
private SensorManager mSensorManager;
private Sensor mAccelerometer;
private ShapeView mShapeView;
private int mWidthScreen;
private int mHeightScreen;
private final float FACTOR_FRICTION = 0.2f; // 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
private int previousInnerX, previousInnerY;
private static final float OUTERSTROKE = 5;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
mSensorManager = (SensorManager)getSystemService(SENSOR_SERVICE);
mAccelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
DisplayMetrics displaymetrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(displaymetrics);
mWidthScreen = displaymetrics.widthPixels;
mHeightScreen = displaymetrics.heightPixels;
mShapeView = new ShapeView(this);
mShapeView.initOvalCenter((int) (mWidthScreen * 0.6), (int) (mHeightScreen * 0.6));
setContentView(mShapeView);
}
#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
public void onAccuracyChanged(Sensor sensor, int accuracy) {
}
#Override
protected void onResume() {
super.onResume();
// start sensor sensing
mSensorManager.registerListener(this, mAccelerometer, SensorManager.SENSOR_DELAY_NORMAL);
}
#Override
protected void onPause() {
super.onPause();
// stop sensor sensing
mSensorManager.unregisterListener(this);
}
// the view that renders the ball
private class ShapeView extends SurfaceView implements SurfaceHolder.Callback {
private final int BALLRADIUS = 100;
private final float FACTOR_BOUNCEBACK = 0.45f;
private final int OUTERRADIUS = 300;
private Point ballCenter = new Point();
private RectF mRectF;
private final Paint mPaint;
private ShapeThread mThread;
private float mVx;
private float mVy;
private final Paint outerPaint;
private RectF outerBounds;
private Point outerCenter;
private final double outerDiagonal;
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);
mPaint.setAntiAlias(true);
outerPaint= new Paint();
outerPaint.setColor(0xFFFFFFFF);
outerPaint.setAlpha(255);
outerPaint.setStrokeWidth(OUTERSTROKE);
outerPaint.setStyle(Paint.Style.STROKE);
outerPaint.setAntiAlias(true);
mRectF = new RectF();
outerDiagonal= Math.pow(BALLRADIUS - OUTERRADIUS, 2);
}
public void initOvalCenter(int x, int y) {
mShapeView.setOvalCenter(x, y);
outerCenter= new Point(x, y);
outerBounds = new RectF(x - OUTERRADIUS, y - OUTERRADIUS, x + OUTERRADIUS, y + OUTERRADIUS);
}
public boolean setOvalCenter(int x, int y) {
ballCenter.set(x, y);
return true;
}
public boolean updateOvalCenter() {
Point newBallCenter = new Point();
newBallCenter.x = ballCenter.x + (int) (mDeltaT * (mVx + 0.5 * mAx * mDeltaT));
newBallCenter.y = ballCenter.y + (int) (mDeltaT * (mVy + 0.5 * mAy * mDeltaT));
double distance = Math.sqrt(Math.pow(newBallCenter.x - outerCenter.x, 2) + Math.pow(newBallCenter.y - outerCenter.y, 2));
if(distance >= OUTERRADIUS - BALLRADIUS) {
mVx = -mVx * FACTOR_BOUNCEBACK;
mVy = -mVy * FACTOR_BOUNCEBACK;
if(Math.abs(mVx) > 0.5)
{
newBallCenter.x = previousInnerX + (int) (mDeltaT * (mVx + 0.5 * mAx * mDeltaT));
newBallCenter.y = previousInnerY + (int) (mDeltaT * (mVy + 0.5 * mAy * mDeltaT));
}
else
{
newBallCenter.x = previousInnerX;
newBallCenter.y = previousInnerY;
}
}
else
{
mVx -= mAx * mDeltaT;
mVy += mAy * mDeltaT;
}
previousInnerX = ballCenter.x;
previousInnerY = ballCenter.y;
ballCenter.x = newBallCenter.x;
ballCenter.y = newBallCenter.y;
return true;
}
protected void doDraw(Canvas canvas) {
if (mRectF != null && canvas != null) {
mRectF.set(ballCenter.x - BALLRADIUS, ballCenter.y - BALLRADIUS, ballCenter.x + BALLRADIUS, ballCenter.y + BALLRADIUS);
canvas.drawColor(0XFF000000);
canvas.drawOval(mRectF, mPaint);
canvas.drawOval(outerBounds, outerPaint);
}
}
#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 ignored) { }
}
}
}
class ShapeThread extends Thread {
private final 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;
}
#Override
public void run() {
Canvas c;
while (mRun) {
mShapeView.updateOvalCenter();
c = null;
try {
c = mSurfaceHolder.lockCanvas(null);
synchronized (mSurfaceHolder) {
mShapeView.doDraw(c);
}
} finally {
if (c != null) {
mSurfaceHolder.unlockCanvasAndPost(c);
}
}
}
}
}
}
Adding in the smooth movement of the iner circle rolling within the outer one while also bouncing will be a lot more difficult to implement. The correct way would be to have the inner circle rotating and following the instructions from the question you reference.
Maybe you can ask a seperate question for that part after you are happy with the bouncing.
If anything this may just help you along your journey and hopefully you will be able to add to this.

adding button onto a view programatically

If I want to add a button in this class so that I can call the onclicklistener, how should I do it?i have also provided the activity class onto which i am adding this view.
activity:
import android.app.Activity;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
import android.widget.Button;
import android.widget.RelativeLayout;
import android.content.Context;
public class NewGame extends Activity {
View view;
Context context;
RelativeLayout layout;
GameView gameview;
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
gameview=new GameView(this);
setContentView(gameview);
//layout = (RelativeLayout) findViewById(R.id.relative_layout);
//layout.addView(gameview);
}
}
view:
public class GameView extends View {
Path circle;
Paint cPaint;
Paint tPaint;
String z;
int i = 65, strt, arc, leftx, topy, rightx, bottomy, maxx, maxy;
boolean flag1, flag2, flag3;
double n1, n2;
int n, n3 = 180,n4,n5 = 90;
float f1 = 180, f2 = 90;
Button b1;
Random r = new Random();
RectF oval;
public GameView(Context context) {
super(context);
leftx = 0;
topy = 60;
rightx = 150;
bottomy = 120;
z = String.valueOf(Character.toChars(i));
cPaint = new Paint();
cPaint.setColor(Color.RED);
strt = 45;
arc = 315;
n1 = Math.random() * 600;
Log.d("random", z);
if (flag2 == false)
new DrawThread(this);
// cPaint.setStrokeWidth(2);
tPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
tPaint.setStyle(Paint.Style.FILL_AND_STROKE);
tPaint.setColor(Color.BLACK);
float scale = getResources().getDisplayMetrics().scaledDensity;
tPaint.setTextSize(20 * scale);
}
public void onSizeChanged(int w,int h,int oldh,int oldw) {
maxx = oldw;
maxy = oldh;
}
//#Override
protected void onDraw(Canvas canvas) {
// Drawing commands go here
oval = new RectF(leftx,topy,rightx,bottomy);
canvas.drawArc(oval, strt, arc, true, cPaint);
while (i < 90) {
canvas.drawText(String.valueOf(Character.toChars(i)),f1,f2, tPaint);
break;
}
}
}
You can do it like this:
Button bt = new Button(this);
bt.setText("A Button");
bt.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT));
linerLayout.addView(bt);
And then you can do this
bt.setOnClickListener(new View.OnClickListener() {
//TO DO
}
I hope that this can help you.
first of all in order to allow to your custom view to have an addView(View v) method it must extend ViewGroup instead of View; then you can use this code
b1=new Button(context);
b1.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT,LayoutParams.WRAP_CONTENT ));
b1.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
}
});
this.addView(b1);

Categories

Resources