I have a custom drawn rectangle which i want to move in a circular path based on touch events.
It follows the direction of the touch for clockwise or anticlockwise movement but basically move in circular motion, as if moving on the edge of the circle.
My current thought process is as follows:
Based on the users current and previous x,y i shall find the angle in degrees and then move this rectangle by the same angle by re-drawing in the new position, just making sure that it moves on the edge of a circle.
But this leads to some confusion on the following:
1. how do i decide whether angle movement is clockwise or anti-clockwise.
2. I am not being able to figure out the math for this properly.
Would this be the best approach or is there a better idea for doing this?
Also, if this is the best approach, could someone please tell me the formula for calculating the angle by which i should move it while taking care of the clocking and anticlockwise ?
could someone please help?
please let me know if any more details are required.
Thanks
Steps
Here are a few steps in order to move your rectangle along a circle's rim when the user taps and holds to the side of the circle:
1. Obtain direction desired.
2. Obtain angle from current x and y coordinates.
3. Add direction (+1 if counterclockwise, -1 if clockwise) to angle.
4. Calculate new x and y coordinates.
5. Update/display rectangle.
Details
1. In pseudocode, direction = sign(Rectangle1.x - UsersFingerPosition.x). Here sign is a function returning -1 if the number was negative, 0 if it is 0, and 1 if it is positive. Note that sign(0) will only result when the user is on the exact x and y of your rectangle's location. In that case, the rectangle would not move (which should be good). In Java, the sign function is Math.signum().
2. To obtain the current angle use the following java code:
double angle = Math.toDegrees(Math.atan2(Circle.y-Rectangle1.y, Rectangle1.x-Circle.x));
Note the order of Circle.y-Rectangle.y and Rectangle.x...Circle.x. This is a result of the coordinate (0, 0) being in the top left corner instead of the center of the screen.
3. Simple enough, just add direction to angle. If desired, do something like
angle += direction*2; //So it will move more quickly
4. To get the new x and y coordinates of your rectangle, use the trigonometric functions sine and cosine:
Rectangle1.x = Math.cos(Math.toRadians(angle))*Circle.radius + Circle.x - Rectangle1.width;
Rectangle1.y = Math.sin(Math.toRadians(angle))*Circle.radius + Circle.y - Rectangle1.height;
(where Circle.x and Circle.y are the coordinates of the center of your circle and Circle.radius is naturally it's radius).
5. This one you'll have to take care of (or have already) :)!
Hope this helps you!
Steps
Here are a few steps in order to move your rectangle along a circle's rim:
1. Obtain finger position/Check that it's still dragging the rectangle.
2. Obtain angle from current x and y coordinates.
3. Calculate new x and y coordinates.
4. Update/display rectangle.
Details
1. This one is probably specific to your code, however, make sure that when the user starts dragging the rectangle, you set a variable like rectangleDragging to true. Before you run the next steps (in the code), check that rectangleDragging == true. Set it to false once the user lets go.
2. To obtain the current angle use the following java code:
double angle = Math.toDegrees(Math.atan2(Circle.y-Finger.y, Finger.x-Circle.x));
Note the order of Circle.y-Finger.y and Finger.x...Circle.x. This is a result of the coordinate (0, 0) being in the top left corner instead of the center of the screen.
3. To get the new x and y coordinates of your rectangle, use the trigonometric functions sine and cosine:
Rectangle1.x = Math.cos(Math.toRadians(angle))*Circle.radius + Circle.x - Rectangle1.width;
Rectangle1.y = Math.sin(Math.toRadians(angle))*Circle.radius + Circle.y - Rectangle1.height;
(where Circle.x and Circle.y are the coordinates of the center of your circle and Circle.radius is naturally it's radius). Subtracting the width and height of the rectangle should center it on the circle's border instead of placing the left, upper corner on the circle.
4. This one you'll have to take care of (or have already) :)!
Hope this helps you!
Related
I would like to detect collisions between shapes dynamically drawn on a canvas (SurfaceView) for an Android game.
I can easily use intersect method of Rect or RectF objects but the result is not very good (see picture below where I have a "false" detection).
I don't want to use Bitmap so it's impossible to use the "pixel perfect" method.
Do you know a way to do this for circle, rect, triangle and other basic shapes intersection ?
Thx for help ;)
For a good collision detection you have to create your own models behind. In those models you specify the conditions that two objects colide.
For example, a circle is described by the center position and by the radius. A square is described by the left down corner and by the edge length.
You don' t have to describe all possible poligons, you can use the so called bounding boxes, meaning that, for a complex random poligon you can use a square or whathever shape fits it best(also you can use multiple shapes for a single object).
After you have the objects in mind you compute the condition that each one of them will colide with all other shapes including itself.
In your example The sphere and the square colides if the distance between any corner of the square is greater than the circle's radius.
Here you can read more http://devmag.org.za/2009/04/13/basic-collision-detection-in-2d-part-1/
This problem can get very complex, keep it simple if you want something simple.
Here is a directly applicable method I use in my own game to detect circle and rectangle intersection. It takes the ball (which is a view in this case) and the rectangle (also a view) to be checked for collision with the ball as parameters. You can put the method in a Timer and set the interval you want the circle and rectangle to be checked for collision.
Here is the method:
public boolean intersects(BallView ball, Rectangle rect) {
boolean intersects = false;
if (ball.getX() + ball.getR() >= rect.getTheLeft() &&
ball.getX() - ball.getR() <= rect.getTheRight() &&
ball.getY() + ball.getR() <= rect.getTheBottom() &&
ball.getY() - ball.getR() >= rect.getTheTop())
{
intersects = true;
}
return intersects;
}
getR() gets the circle's radius
getX() gets the center of the circle's X position value
getTheLeft() gets the rectangle's left X value
getTheRight() gets the rectangle's right X value
getTheTop() gets the rectangle's top Y value
getTheBottom() gets the rectangle's bottom Y value
If you can't directly use this method in your code you can still conjecture the logic it entails to implement it where it would work for you. It detects all collisions without using pseudo-collision detection like a collision box for the circle.
Good luck! And if you have any questions feel free to ask, I'm here to help!
To know if a polygon in 2d is colliding with a circle, you can test, for each of its lines, where is the point on the line that is closest to the center of the circle (this might help).
Then, check if the point you found is between to two corners that make the line - that is, that the point is actually on the line, and not just on its continuation - and if the distance of that point to the center of the circle is smaller or equal to the radius of the circle. If both are true for any of the lines of the polygon, you have a collusion. You also have to check for the edge cases where the corners of the polygon might be in, or touching the circle.
For two circles, this is easier. Check the distance between the centers, and compare it to the sum of their radiuses. If the distance is smaller or equal to the sum, you have a collusion.
I will have an oval in the plane.The x and y co-ordinates of the center of oval and radius of the oval is known.Using a particle to move around the plane,have to verify whether the oval is circled(by moving the particle through all the sides of the oval).
How can I verify whether the oval is circled by the particle?
Consider centre of oval is (0, 0deg) in polar coordinates.
I am assuming your particle doesn't go inside the boundary of oval(from your words side of oval).
Minimize min and max with start position(atan(yParticle-yOvalCentre, xParticle-xOvalCentre)) of particles. Everytime particles goes towards min update min angle and similar for max. Once max - min > 360, you have completed the circle.
When you decided to start painting oval around circle, you created the starting vector from circle center to point (let's call it mouse point).
(mouseX-circleX, mouseY-circleY) = start vector
So, initial angle between current and starting vector will be 0 (until you move your mouse).
Mohit suggested you to check whether your current vector achieved some delta (359 deg is enough) between minimal and maximal angle value (angle can vary between -180 .. 180).
I'm not sure about his formula, though. I think it's better to find angle between starting vector (ax,ay) and current (bx,by) using the fact that
[a,b] = |a|*|b|*sin(alpha) = ax*by - ay*bx
(a,b) = |a|*|b|*cos(alpha) = ax*bx + ay*by
atan( [a,b] / (a,b) ) = atan(tan(alpha)) = alpha
So, calculate current angle on every mouse move and update min/max values, until max-min < 359
If you want to check it simultaneously for several circles, do it simultaneously for array of starting vectors and min/max values)
UPD I've noted big problem here, after painting 180 degrees around circle you'll achive -180 point immediately. So I think the best thing to do is to accumulate some summary value of signed delta angles between current and prevous "MouseMove" callback. So, when summary value will become 359 or -359 that mean you maked valid clock or counter-clockwise rotation.
Ohh.. damm Math !! once again stuck. It seems to be easy but i think its not that easy,
Problem Statement: I want to rotate the 3 fixed points which lies on a fixed circle.
1.when 1 point is selected remaining 2 points should be static mode and only selected point should move/rotate on circumference of circle.
2.And all 3 points are connected via 3 lines as shown in images..when we select a point and rotate it,connected lines also increase and decrease..
I already tried to solve this problem finding angle at each instant after touch.but its not quite working as per my need..
something like this
I hope the following explanation enable you to put the steps into your coding language.
Presumption is that the vertex to be moved has already selected and so the calculation of (xcnd,ycnd) as defined below is used to set the selected vertex of the triangle.
Let the constraining circle have centre at (cx,cy) and radius r.
Let the coordinates of where the screen is touched be (xtch,ytch)
Let the coordinates of where the screen is touched relative to the centre be (xrel,yrel)
then xrel = xtch - cx and yrel = ytch - cy
Let the coordinates of the point on the constraining circle when the screen is touched at (xtch,ytch) be (xcnd,ycnd).
xcndrel = xcnd - cx, and ycndrel = ycnd - cy give the coordinates on the constraining circle relative to its centre,
Note that
xrel and xcndrel will have the same signs (ie both positive or both negative)
and yrel and ycndrel will also have the same signs.
the function abs(x) = x if x>=0 and -x if x<0 should be available in whatever language you are using
the function sign(x) may or may not be available, sign(x) =1 if x>0 and -1 if x<0 and undefined for x=0
If not available then sign(x)=x/abs(x)
Check if xrel=0
if xrel=0 xcndrel=0, ycndrel=r*sign(yrel)
Otherwise work in first quadrant ie where x>0 and y>0 using abs(xrel) and abs(yrel)
find angle where screen is touched relative to centre of circle using
theta=arctan(abs(yrel)/abs(xrel))
find the coordinates (xcndrel, ycndrel) by using theta in the first quadrant and then placing in the correct quadrant using the signs of xrel and yrel
xcndrel = sign(xrel)*r*COS(theta)
ycndrel = sign(yrel)*r*SIN(theta)
Screen coordinates can now be found
xcnd = xcndrel +cx
ycnd = ycndrel + cy
I want to achieve a tilt effect when a button is clicked, on Android OS.
Tilt Effect: Not the whole button will be seen as pressed. Only the part that touch event occured should seem to be pressed.
Is this easily possible on Android?
A simple way would be to use canvas draws to draw 4 sided shapes.
Consider each 4 corners. The "untouched" rectangle would be full size the touched rectangle would be smaller.
You just need to draw your four sided shape using a point you calculate for each part of the rectangle. You can get the touch position, then figure out how much "weight" to give each point.
to calculate each corner, you need to figure out how much "weight" to give the touched coordinate, and how much "weight" to give the untouched coordinate. If you touch the top left corner, that corner would use 100% of the touched coordinate, and the other three corners would all use the untouched coordinate.
If you touched the top middle, you would get a shape like this:
We can calculate the corners for any touch spot, by calculating how far from the corner your touch is
float untouchedXWeight1 = Math.abs(xt - x1)/width;
//maximum of 1, minimum of 0
float untouchedYWeight1 = Math.abs(yt - y1)/height;
float untouchedWeight1 = (untouchedXWeight1 + untouchedYWeight1)/2;
//also maximum of 1, minimum of 0
float touchedWeight1 = 1 - untouchedWeight1;
so with those weights, you can calculate your x and y positions for that corner:
x1 = xUntouched1 * untouchedWeight + xTouched1 * touchedWeight1;
y1 = yUntouched1 * untouchedWeight + yTouched1 * touchedWeight1;
Then do similarly for the other 3 corners.
I've created a first draft here : https://github.com/flavienlaurent/TiltEffect
In a second step, I will make it usable with Button etc.
Unfortunatly, I didn't use the very good (but too mathematical for me) answer of HalR
I have a square that rotates to a random angle and then travels in a straight line in the direction it is pointing. It does this by using a variable as its x axis and then calling
Variable++
Each frame.
unfortunatley i cannot work out how to return the exact position of the square because the square can be travelling at any angle and therefore doesn't rigidly follow the world coordinte grid. This means that the x variable is not the shapes x coordinate.
How do i return the shapes exact coordinates and how do i do it in such a way that i can have two squares drawn from the same class behaving differently.
So you've got a measure of distance from where the object started along its internal sideways axis and a measure of the angle between that axis and the horizontal?
If so then the formula you want is simple trigonometry. Assuming the object started at (x, y) and has travelled 'distance' units along an axis at an angle of 'angle' with the horizontal then the current position (x', y') is:
x' = x + distance * cos(angle)
y' = y + distance * sin(angle)
If you have the origin in the lower left of the screen and axes arranged graph paper style with x increasing to the right and y increasing as you go upward, that assumes that the angle is measured anticlockwise and that the object is heading along positive x when angle is zero.
If you'll permit a hand waving explanation, the formula works because one definition of sine and cosine is that they're the (x, y) coordinates of the point on the outside of a unit circle at the angle specified. It also matches with the very first thing most people learn about trigonometry, that sine is 'opposite over hypotenuse', and cosine is 'adjacent over hypotenuse'. In this case your hypotenuse has length 'distance' and and you want to get the 'opposite' and 'adjacent' lengths of a right angled triangle that coincides with the axes.
Assuming Android follows J2SE in this area, the one thing to watch out for is that Math.sin and Math.cos take an angle in radians, whereas OpenGL's rotatef takes an argument in degrees. Math.toDegrees and Math.toRadians can do the conversion for you.
When you made the shape you should have already specified its X & Y coordinates. Im not too sure what you mean when you say you cant find the coordinates?
Also make sure you do fame independent movement; currently you are adding one to your variable on every loop of your program. This means if it runs a 60 Frame Per Second(FPS) it will move 60 units, but if it runs at 30FPS it will move at half the speed