我正在创建一个弹跳球的项目。
我的项目唯一的问题是当两个球相互交叉时碰撞分辨率。碰撞检测很好,因为当两个球相交时它们会反弹然后它们会一次又一次地碰撞。当球与墙碰撞时正确弹跳但我不知道为什么当它们相互碰撞时会出现问题。
我尝试了各种代码,但仍然无法获得它。
我该怎么做?
你可以像我一样帮助这个链接。
Ball to Ball Collision - Detection and Handling
这是我的代码:
package com.example.bouncer;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Point;
import android.provider.SyncStateContract.Constants;
public class Ball {
private Point p; //Point p:Represents the x and y position of the Ball
private int c; //Represents the color of the Ball
private int r; //Represents the Radius of the Ball.
private int dx; //Integer dx:Represents the change in x position of ball
// Integer dy:Represents the change in y position of ball
private int dy;
private Paint paint; //Android Object holding the color for drawing on the canvas
public Ball(int x,int y,int col,int radius)
{
p=new Point(x,y);
c=col;
r=radius;
paint=new Paint();
dx=0;
dy=0;
}
public int getX()
{return p.x;
}
public int getY()
{
return p.y;
}
public int getRadius()
{return r;
}
public Paint getPaint()
{return paint;
}
public void setColor(int col)
{c=col;
}
public void goTo(int x,int y)
{p.x=x;
p.y=y;
}
public void setDX(int speed)
{dx=speed;
}
public void setDY(int speed)
{
dy=speed;
}
public void move()
{
p.x=p.x+dx;
p.y=p.y+dy;
}
public void bounce(Canvas canvas) //COLLISION DETECTION AND RESOLUTION WITH WALLS
{
move();
if(p.x>canvas.getWidth()|| p.x<0)
{
dx=dx * -1;
}
if(p.y>canvas.getWidth()|| p.y<0)
{
dy=dy * -1;
}
}
public void bounceoff(Ball b) //BALL TO BALL COLLSION DETECTION
{
float x = b.getX() - p.x;
float y = b.getY() - p.y;
float distanceSquared = x*x + y*y;
float radius = b.getRadius()+r;
float radiusSquared = radius*radius;
if (distanceSquared <= radiusSquared)
{
dx=dx * -1;
dy=dy * -1;
}
}
}
AnimationView.java
package com.example.bouncer;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.os.Handler;
import android.util.AttributeSet;
import android.view.View;
public class AnimationView extends View{
private final int FRAME_RATE=15;
private Paint paint;
private Handler h;
Ball myball;
Ball greenball;
Ball redball;
public AnimationView(Context context,AttributeSet attrs) {
super(context,attrs);
// TODO Auto-generated constructor stub
h=new Handler();
paint=new Paint();
paint.setColor(Color.BLUE);
myball=new Ball(100,100,Color.BLUE,50);
greenball=new Ball(200,200,Color.GREEN,50);
redball=new Ball(50,400,Color.RED,50);
myball.setDX(10);
myball.setDY(10);
greenball.setDX(-20);
greenball.setDY(-15);
redball.setDX(5);
redball.setDY(-5);
}
protected void onDraw(Canvas c)
{
myball.bounce(c);
greenball.bounce(c);
redball.bounce(c);
myball.bounceoff(myball);
greenball.bounceoff(greenball);
redball.bounceoff(redball);
c.drawCircle(myball.getX(), myball.getY(),myball.getRadius(), myball.getPaint());
c.drawCircle(greenball.getX(), greenball.getY(),greenball.getRadius(), greenball.getPaint());
c.drawCircle(redball.getX(), redball.getY(),redball.getRadius(), redball.getPaint());
h.postDelayed(r, FRAME_RATE);
}
private Runnable r=new Runnable()
{ public void run()
{ invalidate();
}
};
}
如果您需要我的完整项目代码,请查看链接.. https://stackoverflow.com/questions/22892736/balls-keep-colliding-again-and-again-android
答案 0 :(得分:0)
我认为您可以使用用于检测球与球碰撞的标准进行错误碰撞。如果AB
是球的中心A
和B
之间的向量,则rA
的半径为A
和rB
半径{ {1}}然后您可以使用此标准来检查球是否发生碰撞
B
其中|AB| < rA + rB
表示向量|AB|
计算此值的优化方法(避免昂贵的平方根计算)是
AB
另外,还有几个旁注。
我认为最好从int xDiff = b.getX()-p.x;
int yDiff = b.getY()-p.y;
int radii = b.getRadius() + r;
if ( ( xDiff * xDiff + yDiff * yDiff ) < radii * radii ) {
// Collision response. Change the balls velocity
中取出move
,这样你首先移动所有球,然后检查它们中的任何一个是否与另一个球或墙壁相撞
您的碰撞响应(当球碰撞时会发生什么),即只是反转球的方向只有在球的速度相同时才能正常工作(例如vA = 1m / s,vB = -1m /秒)。在其他情况下,球不会像预期的那样反弹。
答案 1 :(得分:0)
我稍后会适当地看一下,但乍一看我不喜欢:
if((Math.abs(b.getX()-p.x)<b.getRadius()+r)&& (Math.abs(b.getY()-p.y)<b.getRadius()+r))
您需要以下内容:
diffX = b.getX() - p.x;
diffY = b.getY() - p.y;
rad1 = this.getRadius();
rad2 = b.getRadius();
if((diffX * diffX + diffY * diffY) < (rad1 * rad1 + rad2 * rad2))
[编辑因为球的半径不同]
答案 2 :(得分:0)
问题在于,当您检测到球碰撞时,您可以向上和向左移动两个球。这会导致球一起移动而不会反弹。
为了达到预期的效果,左边的球应该是-1而右边的球应该是+1。同样的事情适用于垂直轴,上部球应该为-1而底部应该为+1
public void bounceoff(Ball b) //BALL TO BALL COLLSION DETECTION
{
float x = b.getX() - p.x;
float y = b.getY() - p.y;
float distanceSquared = x*x + y*y;
float radius = b.getRadius()+r;
float radiusSquared = radius*radius;
if (distanceSquared <= radiusSquared)
{
dx=dx * -1;
dy=dy * -1;
b.setDY(b.getDX()*-1);
b.setDY(b.getDY()*-1);
if (x<b.getX()){
x = x-1;
b.setX(b.getX()+1);
}else{
x = x+1;
b.setX(b.getX()-1);
}
if (y<b.gety()){
y = y-1;
b.setY(b.getY()+1);
}else{
y = y+1;
b.setY(b.getY()-1);
}
}
}
你还应该在Ball类中添加2个setter:
public void setX(int x)
{
p.x = x;
}
public void setY(int y)
{
p.y = y;
}
public int getDX()
{
return dx;
}
public int getDY()
{
return dy;
}
onDraw需要做一些工作:
protected void onDraw(Canvas c)
{
// ball bouncing on walls
myball.bounce(c);
greenball.bounce(c);
redball.bounce(c);
// balls bouncing on each other
myball.bounceoff(redball);
myball.bounceoff(greenball);
redball.bounceoff(greenball);
// draw balls
c.drawCircle(myball.getX(), myball.getY(),myball.getRadius(), myball.getPaint());
c.drawCircle(greenball.getX(), greenball.getY(),greenball.getRadius(), greenball.getPaint());
c.drawCircle(redball.getX(), redball.getY(),redball.getRadius(), redball.getPaint());
h.postDelayed(r, FRAME_RATE);
}
答案 3 :(得分:-1)
球类
package com.example.bagoriya.bball;
/**
* Created by Bagoriya on 27/02/2015.
*/
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Point;
public class Ball {
private Point point;
private int c;
private int r;
private int dx;
private int dy;
private Paint paint;
public Ball(int x, int y, int col, int radius) {
point = new Point(x, y);
c = col;
r = radius;
paint = new Paint();
dx = 0;
dy = 0;
}
public int getX() {
return point.x;
}
public int getY() {
return point.y;
}
public int getRadius() {
return r;
}
public Paint getPaint() {
paint.setColor(c);
return paint;
}
public void goTo(int x, int y) {
point.x = x;
point.y = y;
}
public void setDX(int speed) {
dx = speed;
}
public void setDY(int speed) {
dy = speed;
}
public void move() {
point.x = point.x + dx;
point.y = point.y + dy;
}
public void bounce(Canvas canvas) {
move();
if (point.x > canvas.getWidth() - r || point.x - r < 0) {
dx = dx * -1;
}
if (point.y > canvas.getHeight() - r || point.y - r < 0) {
dy = dy * -1;
}
}
public void bounceoff(Ball b) {
float dist = b.getX() - point.x;
float rad = b.getRadius() + r;
float dif = b.getY() - point.y;
if ((dist * dist) + (dif * dif) <= (rad * rad)) {
dx = dx * -1;
dy = dy * -1;
}
}
}
ANIMATIONVIEW CLASS
package com.example.bagoriya.bball;
/**
* Created by Bagoriya on 27/02/2015.
*/
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.os.Handler;
import android.view.View;
public class AnimationView extends View {
private final int FRAME_RATE = 15;
private Paint paint;
private Handler h;
Ball myball;
Ball greenball;
Ball redball;
public AnimationView(Context context) {
super(context);
// TODO Auto-generated constructor stub
h = new Handler();
paint = new Paint();
myball = new Ball(100, 100, Color.BLUE, 50);
greenball = new Ball(200, 200, Color.CYAN, 50);
redball = new Ball(50, 400, Color.RED, 50);
myball.setDX(1);
myball.setDY(1);
greenball.setDX(-2);
greenball.setDY(-1);
redball.setDX(1);
redball.setDY(-5);
}
protected void onDraw(Canvas c) {
c.drawColor(Color.WHITE);
myball.bounce(c);
greenball.bounce(c);
redball.bounce(c);
myball.bounceoff(greenball);
myball.bounceoff(redball);
greenball.bounceoff(redball);
greenball.bounceoff(myball);
redball.bounceoff(myball);
redball.bounceoff(greenball);
// myball.bounceoff(myball);
// greenball.bounceoff(greenball);
// redball.bounceoff(redball);
c.drawCircle(myball.getX(), myball.getY(), myball.getRadius(), myball.getPaint());
c.drawCircle(greenball.getX(), greenball.getY(), greenball.getRadius(), greenball.getPaint());
c.drawCircle(redball.getX(), redball.getY(), redball.getRadius(), redball.getPaint());
h.postDelayed(r, FRAME_RATE);
}
private Runnable r = new Runnable() {
public void run() {
invalidate();
}
};
}