gpt4 book ai didi

android - 让一个球在另一个圆圈内滚动

转载 作者:行者123 更新时间:2023-11-29 00:17:57 25 4
gpt4 key购买 nike

我试图让一个球在另一个球内弹跳并滚动,最终基于加速度计。有无数的教程可以检测圆圈碰撞等,它们确实有点帮助。不幸的是,我发现没有一个能处理圆内圆碰撞,只有圆在矩形 View 中弹跳。

几个有用的 URL 是我获得大部分代码的地方: http://xiangchen.wordpress.com/2011/12/17/an-android-accelerometer-example/ circle-circle collision

..但同样,这不是我想要的。

我想让一个圆圈在另一个圆圈内弹跳和滚动。然后,在那之后,我会希望内球随着速度的降低在正确的时间从外圈的内侧滚下,而不是简单地弹回底部。我表达清楚了吗?最后,弹跳角度需要调整,我敢肯定,所以我最终也需要弄清楚如何做到这一点。

我的代码一团糟,因为我尝试了很多东西,所以特别是,注释 block 甚至不接近它需要的东西,我不认为。这只是我最近的尝试。

有人对此有所了解并愿意帮助我吗?我将不胜感激。

编辑:这个人非常接近我所追求的,但我无法理解它并将所选答案转换为 Java。帮助? 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);
}
}
}
}
}
}

最佳答案

我想我会回答这个至少对你有帮助,即使它不能完全回答你的问题。

下面是你的代码,做了一些改动

我解决了您在发生碰撞时将内圆折回的问题。基本上,一旦发生碰撞,您需要将内圈向后移动一帧。我想你试过这样做但是你在碰撞检查之前重置了这些值。我还对速度添加了一点检查,如果它小于 0.5,则只需将内圈移动到最后一帧而不反弹,以消除它试图稳定时的抖动反弹效果。

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

添加内圆在外圆内滚动同时弹跳的平滑运动将更难实现。正确的方法是让内圈旋转并按照您引用的问题中的说明进行操作。

也许您可以在对弹跳感到满意之后针对该部分提出一个单独的问题。

如果有的话,这可能只会对您的旅程有所帮助,希望您能够对此有所补充。

关于android - 让一个球在另一个圆圈内滚动,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25187739/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com