检查 parents 不同的两个不同自定义视图之间的冲突
check collision between two different custom views whose parents are different
我有一个自定义视图 "Stick",它扩展了 RelativeLayout。
我有另一个自定义视图 "Ball",它也扩展了 RelativeLayout。而他们的parents是不一样的。屏幕上随时有多个(或一个)自动移动的球和棍子。每当球与棍子碰撞时,我都想得到通知。意味着我想在碰撞发生时做点什么。目前,我正在 运行 一个无限循环来检查球的当前边界矩形是否与当前的木棍边界矩形相交。但它的成本太高,而且如果屏幕上有多个棍子和球,则此方法不起作用或几乎不起作用。有没有更好的方法,或者 android 中是否有视图碰撞侦听器?
下面是棍子class
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
import android.content.Context;
import android.graphics.Color;
import android.view.View;
import android.widget.RelativeLayout;
import java.util.ArrayList;
public class Stick extends RelativeLayout {
int height;
String dest;
Context context;
RelativeLayout.LayoutParams layoutParams;
private static int stickDecelerate = 2000;
private static ArrayList<Stick> stickList = new ArrayList<Stick>();
public static ArrayList<Stick> getStickList() {
return stickList;
}
public static int getStickDecelerate() {
return stickDecelerate;
}
public static void setStickDecelerate(int stickDecelerate) {
Stick.stickDecelerate = stickDecelerate;
}
public Stick(Context context){
super(context);
}
public Stick(Context context, int height, String dest, int leftMargin, int topMargin) {
super(context);
this.context = context;
this.height = height;
this.dest = dest;
if(dest.equals("left") || dest.equals("right")){
layoutParams = new RelativeLayout.LayoutParams(height*5, height);
layoutParams.setMargins(leftMargin-(height*5)/2, topMargin-height/2, 0, 0);
}
else{
layoutParams = new RelativeLayout.LayoutParams(height, height*5);
layoutParams.setMargins(leftMargin-height/2, topMargin-(height*5)/2, 0, 0);
}
this.setLayoutParams(layoutParams);
}
public void release(){
Stick stick = new Stick(context);
stick.setBackgroundColor(Color.YELLOW);
RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(this.getWidth(), this.getHeight());
stick.setLayoutParams(layoutParams);
this.addView(stick);
ObjectAnimator animation;
if(dest.equals("right")) animation = ObjectAnimator.ofFloat(stick, "translationX", GameScreen.getMin());
else if(dest.equals("left")) animation = ObjectAnimator.ofFloat(stick, "translationX", -GameScreen.getMin());
else if(dest.equals("up")) animation = ObjectAnimator.ofFloat(stick, "translationY", -GameScreen.getMin());
else animation = ObjectAnimator.ofFloat(stick, "translationY", GameScreen.getMin());
animation.setDuration(stickDecelerate);
animation.start();
stickList.add(stick);
animation.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
stickList.remove(stick);
stick.setVisibility(View.GONE);
}
});
}
public void preview(){
}
}
下面是球class
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.os.Handler;
import android.view.View;
import android.widget.RelativeLayout;
import java.util.Random;
public class Ball extends View{
int circleBounds;
@Override
protected void onDraw(Canvas canvas) {
Paint paint = new Paint();
paint.setColor(Color.BLUE);
canvas.drawCircle(circleBounds/4, circleBounds/4, circleBounds/4, paint);
}
public Ball(Context context) {
super(context);
}
public Ball(Context context, int circleBounds) {
super(context);
this.circleBounds = circleBounds;
RelativeLayout.LayoutParams ballParams = new RelativeLayout.LayoutParams(circleBounds/2, circleBounds/2);
this.setLayoutParams(ballParams);
startMoving();
}
private void startMoving(){
Random randomAngle = new Random();
int random = randomAngle.nextInt(360);
int x = (int) ((int) GameScreen.getMin()*Math.cos(random));
int y = (int) ((int) GameScreen.getMin()*Math.sin(random));
ObjectAnimator animX = ObjectAnimator.ofFloat(this, "x", x);
ObjectAnimator animY = ObjectAnimator.ofFloat(this, "y", y);
long animDuration = (long) (Stick.getStickDecelerate()*2.2);
animX.setDuration(animDuration);
animY.setDuration(animDuration);
AnimatorSet animation = new AnimatorSet();
animation.playTogether(animX, animY);
animation.start();
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
@Override
public void run() {
if(Important.checkCollision(Ball.this)){
animation.cancel();
Ball.this.setVisibility(View.GONE);
return;
}
handler.postDelayed(this, 0);
}
}, 0);
animation.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
Ball.this.setVisibility(View.GONE);
}
});
}
}
以下是碰撞检测方法
public static boolean checkCollision(View ball){
ArrayList<Stick> stickList = Stick.getStickList();
int[] rec1Pos = new int[2];
ball.getLocationOnScreen(rec1Pos);
int v1_w = ball.getWidth();
int v1_h = ball.getHeight();
Rect ballBound = new Rect(rec1Pos[0], rec1Pos[1], rec1Pos[0] + v1_w, rec1Pos[1] + v1_h);
for(Stick stick:stickList){
int[] rec2Pos = new int[2];
stick.getLocationOnScreen(rec2Pos);
int v2_w = stick.getWidth();
int v2_h = stick.getHeight();
Rect stickBound = new Rect(rec2Pos[0], rec2Pos[1], rec2Pos[0] + v2_w, rec2Pos[1] + v2_h);
return ballBound.intersect(stickBound);
}
return false;
}
好吧,试试这个布尔方法,return如果球发生碰撞则为真。
public boolean checkCollision(View ball)
{
boolean result = false;
for(Stick stick : Stick.getStickList())
{
if(collision(ball, stick))
{
result = true;
break;
}
else result = false;
}
return result;
}
/*Gets View HitRect*/
public boolean collision(View a, View b)
{
Rect aRect = new Rect();
a.getHitRect(aRect);
Rect bRect = new Rect();
b.getHitRect(bRect);
return aRect.intersect(bRect);
}
以及您游戏的Render()
方法:
Thread t = new Thread() {
@Override
public void run() {
try {
while (!isInterrupted()) {
Thread.sleep(100);
runOnUiThread(new Runnable() {
@Override
public void run(){Render();}});}
}catch (InterruptedException e) {}}};
t.start();
}
public void Render()
{
if(checkCollision(ball))
{
//Do something
}
}
我有一个自定义视图 "Stick",它扩展了 RelativeLayout。 我有另一个自定义视图 "Ball",它也扩展了 RelativeLayout。而他们的parents是不一样的。屏幕上随时有多个(或一个)自动移动的球和棍子。每当球与棍子碰撞时,我都想得到通知。意味着我想在碰撞发生时做点什么。目前,我正在 运行 一个无限循环来检查球的当前边界矩形是否与当前的木棍边界矩形相交。但它的成本太高,而且如果屏幕上有多个棍子和球,则此方法不起作用或几乎不起作用。有没有更好的方法,或者 android 中是否有视图碰撞侦听器?
下面是棍子class
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
import android.content.Context;
import android.graphics.Color;
import android.view.View;
import android.widget.RelativeLayout;
import java.util.ArrayList;
public class Stick extends RelativeLayout {
int height;
String dest;
Context context;
RelativeLayout.LayoutParams layoutParams;
private static int stickDecelerate = 2000;
private static ArrayList<Stick> stickList = new ArrayList<Stick>();
public static ArrayList<Stick> getStickList() {
return stickList;
}
public static int getStickDecelerate() {
return stickDecelerate;
}
public static void setStickDecelerate(int stickDecelerate) {
Stick.stickDecelerate = stickDecelerate;
}
public Stick(Context context){
super(context);
}
public Stick(Context context, int height, String dest, int leftMargin, int topMargin) {
super(context);
this.context = context;
this.height = height;
this.dest = dest;
if(dest.equals("left") || dest.equals("right")){
layoutParams = new RelativeLayout.LayoutParams(height*5, height);
layoutParams.setMargins(leftMargin-(height*5)/2, topMargin-height/2, 0, 0);
}
else{
layoutParams = new RelativeLayout.LayoutParams(height, height*5);
layoutParams.setMargins(leftMargin-height/2, topMargin-(height*5)/2, 0, 0);
}
this.setLayoutParams(layoutParams);
}
public void release(){
Stick stick = new Stick(context);
stick.setBackgroundColor(Color.YELLOW);
RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(this.getWidth(), this.getHeight());
stick.setLayoutParams(layoutParams);
this.addView(stick);
ObjectAnimator animation;
if(dest.equals("right")) animation = ObjectAnimator.ofFloat(stick, "translationX", GameScreen.getMin());
else if(dest.equals("left")) animation = ObjectAnimator.ofFloat(stick, "translationX", -GameScreen.getMin());
else if(dest.equals("up")) animation = ObjectAnimator.ofFloat(stick, "translationY", -GameScreen.getMin());
else animation = ObjectAnimator.ofFloat(stick, "translationY", GameScreen.getMin());
animation.setDuration(stickDecelerate);
animation.start();
stickList.add(stick);
animation.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
stickList.remove(stick);
stick.setVisibility(View.GONE);
}
});
}
public void preview(){
}
}
下面是球class
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.os.Handler;
import android.view.View;
import android.widget.RelativeLayout;
import java.util.Random;
public class Ball extends View{
int circleBounds;
@Override
protected void onDraw(Canvas canvas) {
Paint paint = new Paint();
paint.setColor(Color.BLUE);
canvas.drawCircle(circleBounds/4, circleBounds/4, circleBounds/4, paint);
}
public Ball(Context context) {
super(context);
}
public Ball(Context context, int circleBounds) {
super(context);
this.circleBounds = circleBounds;
RelativeLayout.LayoutParams ballParams = new RelativeLayout.LayoutParams(circleBounds/2, circleBounds/2);
this.setLayoutParams(ballParams);
startMoving();
}
private void startMoving(){
Random randomAngle = new Random();
int random = randomAngle.nextInt(360);
int x = (int) ((int) GameScreen.getMin()*Math.cos(random));
int y = (int) ((int) GameScreen.getMin()*Math.sin(random));
ObjectAnimator animX = ObjectAnimator.ofFloat(this, "x", x);
ObjectAnimator animY = ObjectAnimator.ofFloat(this, "y", y);
long animDuration = (long) (Stick.getStickDecelerate()*2.2);
animX.setDuration(animDuration);
animY.setDuration(animDuration);
AnimatorSet animation = new AnimatorSet();
animation.playTogether(animX, animY);
animation.start();
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
@Override
public void run() {
if(Important.checkCollision(Ball.this)){
animation.cancel();
Ball.this.setVisibility(View.GONE);
return;
}
handler.postDelayed(this, 0);
}
}, 0);
animation.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
Ball.this.setVisibility(View.GONE);
}
});
}
}
以下是碰撞检测方法
public static boolean checkCollision(View ball){
ArrayList<Stick> stickList = Stick.getStickList();
int[] rec1Pos = new int[2];
ball.getLocationOnScreen(rec1Pos);
int v1_w = ball.getWidth();
int v1_h = ball.getHeight();
Rect ballBound = new Rect(rec1Pos[0], rec1Pos[1], rec1Pos[0] + v1_w, rec1Pos[1] + v1_h);
for(Stick stick:stickList){
int[] rec2Pos = new int[2];
stick.getLocationOnScreen(rec2Pos);
int v2_w = stick.getWidth();
int v2_h = stick.getHeight();
Rect stickBound = new Rect(rec2Pos[0], rec2Pos[1], rec2Pos[0] + v2_w, rec2Pos[1] + v2_h);
return ballBound.intersect(stickBound);
}
return false;
}
好吧,试试这个布尔方法,return如果球发生碰撞则为真。
public boolean checkCollision(View ball)
{
boolean result = false;
for(Stick stick : Stick.getStickList())
{
if(collision(ball, stick))
{
result = true;
break;
}
else result = false;
}
return result;
}
/*Gets View HitRect*/
public boolean collision(View a, View b)
{
Rect aRect = new Rect();
a.getHitRect(aRect);
Rect bRect = new Rect();
b.getHitRect(bRect);
return aRect.intersect(bRect);
}
以及您游戏的Render()
方法:
Thread t = new Thread() {
@Override
public void run() {
try {
while (!isInterrupted()) {
Thread.sleep(100);
runOnUiThread(new Runnable() {
@Override
public void run(){Render();}});}
}catch (InterruptedException e) {}}};
t.start();
}
public void Render()
{
if(checkCollision(ball))
{
//Do something
}
}