We are trying to detect collision on a image view that is moving across the screen. The problem is we only want a negative reaction when the bottom or left side of the brickRect collides with the top or right of the ballRect. If the ballRect wants to land on the top of the brickRect then NO negative reaction is desired. Our question is how to write the if statements for these three interactions of the ballRect with the brickRect? We understand how to obtain the top bottom and left values We will post that code not sure it adds to the question
Rect brickRect = new Rect();
brickFOUR.getHitRect(brickRect);
int BRICKbottom = brickRect.bottom;
int BRICKtop = brickRect.top;
int BRICKleft = brickRect.left;
int BRICKright = brickRect.right;
The object here is to have the ballRect jump up and land on the brickRect
If the ballRect jumps and hits the bottom of the brickRect then do what ever
If the ballRect.right intercepts the brickRect.left then do what ever
So how do we turn this logic into code?
We have looked at numerous post but they all deal with over all detection
Assuming that you have a pair of positions or Rect models, for the before and after movement of the ball and that the position increases to the top and right, then you could write the code as follows:
Rect ballBefore = ...
Rect ballAfter = ...
Rect brickRect = new Rect();
brickFOUR.getHitRect(brickRect);
if(ballBefore.top > ballAfter.top
&& ballBefore.top < brickRect.bottom
&& ballAfter.top >= brickRect.bottom) {
//movement in top direction
//and position before is below
//and position after is not
}
if(ballBefore.right > ballAfter.right
&& ballBefore.right < brickRect.left
&& ballAfter.right >= brickRect.left) {
//if movement is in right direction
//and position before is left
//and position after is not
}
Related
I am developing a Gdx game but I have got stuck on some part and I will explain briefly about it:
I have 9 balls organized on 3*3 and I need to detect the ball that I'm touching as shown in the image below:
enter image description here
and I typed this code:
for (int i : listBalls) {
touchPoint = new Vector3(Gdx.input.getX(), Gdx.input.getY(), 0);
rectangle = new Rectangle(sprite[i].getX(), sprite[i].getY(), spriteSize, spriteSize);
if (rectangle.contains(touchPoint.x, touchPoint.y)) {
Gdx.app.log("Test", "Touched dragged " + String.valueOf(i));
pointer = i;
}
}
In case of touching any ball of the above row, it detects the opposite ball in the bottom row. For example in the above image, if I touch ball no 2 on the top it will point to ball no 8, and same if touching any of the bottom balls.
In case of touching any ball of the middle ball, it gives the right on.
I hope I could explain clearly my issue. Please help.
As explained here: LibGDX input y-axis flipped the coordinate system of the input is inverted on the y-axis, try substracting the screen height of your device or camera
int y = screenHeight - Gdx.input.getY();
Keep in mind that using a Camera and unprojecting the input coordinates is the most recommended way to go about detecting input in LibGDX. Example:
#Override
public boolean touchDown(int screenX, int screenY, int pointer, int button) {
Vector3 unprojected = camera.unproject(new Vector3(screenX, screenY,0));
}
You don't even have to invert the y-coordinate, unproject() does this automatically for you. To use the correct x and y coordinates you then could use:
float x = unprojected.x;
float y = unprojected.y;
I'm doing a simple android animation using my self-customized VIEW. I have two circles drawn on the onDraw() method of the class extends to View class. The one circle is moving upon dragging using MotionEvent while the other one is static on a certain position. If the moving circle touches any point of a static circle, the color of the moving circle will change to the color of the static circle.
For example
int_circle_radius= 50;
int circle1_x = 0;
int circle1_y = 0;
int circle2_x = 200;
int circle2_y = 200;
let's assume that the moving circle which is the circle 1 was drag and drop to a certain point of the circle 2.
I tried using the below formula but the circle 1's color only change if it really goes to the exact location of the circle 2.
if (circle1_x == circle1_x && circle1_y == circle2_y){
paint.setColor(Color.RED);
}
I know that the problem here is a circle has many points from it's radius, but how can I trigger a specific action if the a circle touches any of his point to another circle? Thanks.
You can simply calculate the distance between the centers of the two circles. If the distance is less than two times the radius, the circles are intersecting. Calculating that is easy. You can not expect to get the exact MotionEvent where the circles distance equals the double radius, so you have to check for a distance that is less or equal:
int deltaX = circle1_x - circle2_x;
int deltaY = circle1_y - circle2_y;
if(Math.sqrt(Math.pow(deltaX, 2) + Math.pow(deltaY, 2)) <= 2 * circle_radius) {
paint.setColor(Color.RED);
}
I want to create a translate animation in relation to other objects on the screen
if(vipUpSet == null) {
Rect contactUsLocation = new Rect();
Rect infoLocation = new Rect();
Rect vipLocation = new Rect();
contactUs.getGlobalVisibleRect(contactUsLocation);
info.getGlobalVisibleRect(infoLocation);
vip.getGlobalVisibleRect(vipLocation);
vipUp = new TranslateAnimation(vipLocation.left, contactUsLocation.right + 20, vipLocation.top, contactUsLocation.top);
vipUpSet = new AnimationSet(true);
vipUpSet.setInterpolator(new LinearInterpolator());
vipUpSet.addAnimation(scaleDown);
vipUpSet.addAnimation(vipUp);
vipUpSet.setDuration(1000);
vipUpSet.setFillAfter(true);
}
I have two buttons at the top of the screen called contactUs and info
I want vip to take off from where it is, and be to the right side of the contactUs button
the current setup, makes the view disappear and fly in from the bottom, I want it to fly from its current state.
How do I do that ?
You are using the wrong deltas.
This should do:
float deltaY = contactUsLocation.top - vipLocation.top;
vipUp = new TranslateAnimation(0.f, 0.f, 0.f, deltaY);
// ... same ...
This code will shift contactUs from its current position up to where it is aligned horizontally with vip (but no horizontal translation).
The initial deltas set to 0.f mean the View starts animating from its current position. The final deltas are the offsets of the translation.
Be also careful that the scaleDown animation don't interfere with the translation.
I have many images that I need to place on a canvas over a long period of time so that they look random. However, I don't want any of the images to overlap with each other. My solution so far is to randomly place the image somewhere on the canvas. If it overlaps I'll generate a new random location to try.
Now the tricky part is to see if where I am about to place the image is going to overlap with another image.
I was going to make a large array of 1's and 0's and manually mark off where I put the images. However, I was wondering if anyone knew of a way to "auto detect" using a method if where I am about to place an image will overlap with an existing image? Or if there is a way to do collision detection using some Android function?
Checking to see if two rectangles overlap is really simple, just use Rect.intersect()
Check out the Rect docs for more information:
http://developer.android.com/reference/android/graphics/Rect.html
Although I would recommend you try something different than what you have described above. In the beginning the probability of a collision will be very low. However as the screen fills up the probability of a collision will rise. This result in a lot of collisions and wasted computational power.
You should use something more efficient, off the top of my head you could try something like this:
Split the screen into a grid of size MxN
Keep a list of all unpopulated grid locations
Pick a random grid location for a new image i
Pick a random width and height for image i
If i intersects a grid location that is already populated or it if goes off the screen shrink it
Draw i
If all grid locations are taken quit, else go to 3
A simple 2D isinbox function could be:
bool IsInBox(int x1, int y1, int width1, int height1, int x2, int y2, int width2, int height2) {
int right1 = x1 + width1;
int right2 = x2 + width2;
int bottom1 = y1 + height1;
int bottom2 = y2 + height2;
// Check if top-left point is in box
if (x2 >= x1 && x2 <= right1 && y2 >= y2 && y2 <= bottom1) return true;
// Check if bottom-right point is in box
if (right2 >= x1 && right2 <= right1 && bottom2 >= y2 && bottom2 <= bottom1) return true;
return false;
}
Not sure if works though xd
Or you could use Rect.Intersect()
I want to know how I can detect child views if I move a view from one ViewGroup to another ViewGroup, particularly when doing a touch event. Is there a method I can call that will let me know which views i'm "hovering" over?
What I'm doing right now is when I detect an ACTION_MOVE event on my view i'm raising it to the top level parent so that it can move and be drawn within the entire window ( and not just inside it's original parent bounds ), then I want to move the view across to a different ViewGroup and on ACTION_UP attach the view to that ViewGroup.
Inspired by Ami's response, but discovering that MotionEvent#getX()/getY() along with View#getTop()/etc return coordinates wrt the parent View, I ended up doing the following below to operate in screen coordinates, allowing me to work across ViewGroups:
private boolean inRegion(float x, float y, View v) {
v.getLocationOnScreen(mCoordBuffer);
return mCoordBuffer[0] + v.getWidth() > x && // right edge
mCoordBuffer[1] + v.getHeight() > y && // bottom edge
mCoordBuffer[0] < x && // left edge
mCoordBuffer[1] < y; // top edge
}
whose usage inside an OnTouchListener is e.g.:
boolean inside = inRegion(event.getRawX(), event.getRawY(), targetView);
I think I found a simpler way to do this.
Create an ArrayList of possible targets
Call this method from your touch event, supplying your targets list and the coords
private View findView(float x, float y, ArrayList<View> targets)
{
final int count = targets.size();
for (int i = 0; i < count; i++) {
final View target = targets.get(i);
if (target.getRight() > x && target.getTop() < y
&& target.getBottom() > y && target.getLeft() < x) {
return target;
}
}
return null;
}
I found Sebastian Roth's answer very helpful with resources, but since it wasn't really an answer to my question, I thought I'd share what I came up with.
Here is the code I use to detect views ( only views that will accept a drop that is ) given a coordinate on the screen.
private DropView findDropTarget( int x, int y, int[] dropCoordinates ){
final Rect r = mRectTemp;
final ArrayList<DropView> dropTargets = ((main) context).getBoardDropTargets();
final int count = dropTargets.size();
for (int i=count-1; i>=0; i--) {
final DropView target = dropTargets.get(i);
target.getHitRect(r);
target.getLocationOnScreen(dropCoordinates);
r.offset(dropCoordinates[0] - target.getLeft(), dropCoordinates[1] - target.getTop());
if (r.contains(x, y)) {
dropCoordinates[0] = x - dropCoordinates[0];
dropCoordinates[1] = y - dropCoordinates[1];
return target;
}
}
}
Ok, first off mRectTemp is just an allocated Rectangle so you don't have to keep creating new ones ( I.E. final Rect r = new Rect() )
The next line dropTargets is a list of views that will accept a drop in my app.
Next I loop through each view.
I then use getHitRect(r) to return the screen coordiantes of the view.
I then offset the coordiantes to account for the notification bar or any other view that could displace the coordiantes.
finally I see if x and y are inside the coordinates of the given rectangle r ( x and y are the event.rawX() and event.rawY() ).
It actually turned out to be simpler then expected and works very well.
Read this:
http://developer.android.com/reference/android/view/ViewGroup.html#onInterceptTouchEvent(android.view.MotionEvent)
http://developer.android.com/reference/android/view/View.html#onTouchEvent(android.view.MotionEvent)
I had implemented a Drag and Drop using that method.
I also highly recommend a read of the HomeScreen sourcecode, which contains this thing (kind of):
https://android.googlesource.com/platform/packages/apps/Launcher2