I am fairly new to iOS development. I have just started about a month or two ago. I have an idea for an application, but it would require Gesture Recognizers. I have looked for the documentation for Gesture Recognizers but as far as I can tell, it can only detect 4 directions. Up, left, right, and down. Is there anyway to write some code that will let you detect any direction the user swipes. For example, if the user were to swipe towards the upper-right direction or bottom-right direction, is there a way to detect that?
EDIT: After thinking about this I have come up with a better way to explain what I need code for. If I was developing a game for iOS and the user is usually in a camera view (birds-eye view) and I wanted to allow them to move their view in a map so that they could perhaps view an enemy's base or their ally's base, how would I detect those diagonal swipes rather than just up, right, left, and down swipes?
I think you are a little confused.
UISwipeGestureRecognizer is a subclass of UIGestureRecognizer, and, as you say, it only detects swipes for those 4 directions.
But then there's UIPanGestureRecognizer which you can use to detect movement in any direction. It gives you a method called translationInView: which gives you just that, the change of the position of your finger in whichever direction.
I ran across your question, since it was something similar to what I wanted to do, but then ended up not using it. So I figured I'd leave the code here for posterity. Just use an UIPanGestureRecognizer and set a method similar to this one for your target/selector:
typedef enum {
NONE = 0,
LEFT = 1,
RIGHT = 2,
UP = 4,
DOWN = 8
} BLDirection;
-(void)detectDirection:(UIPanGestureRecognizer*)pan {
if (pan.state == UIGestureRecognizerStateEnded) {
CGPoint stopPan = [pan translationInView:self.view];
CGPoint velocity = [pan velocityInView:self.view];
int direction = NONE;
// first determine the directions
if (velocity.x < 0) {
direction |= LEFT;
} else if (velocity.x > 0) {
direction |= RIGHT;
}
if (velocity.y < 0) {
direction |= UP;
} else if (velocity.y > 0) {
direction |= DOWN;
}
// now we figure out the angle of the swipe
double x2 = stopPan.x;
double x1 = 0;
double y2 = abs(stopPan.y);
double y1 = 0;
// angle is in degrees
double angle = atan((y2 - y1 + 1) / (x2 - x1 + 1)) * 57.29577951308233; // 180/pi
// mask out the vertical directions if they aren't sufficiently strong
if ((angle < 0 && angle < -55) || (angle > 0 && angle > 55)) {
direction &= (UP | DOWN);
}
// mask out the horizontal directions if they aren't sufficiently strong
if ((angle < 0 && angle > -35) || (angle > 0 && angle < 35)) {
direction &= (LEFT | RIGHT);
}
NSLog(#"Direction is %s%s%s%s", ((direction & UP) == UP) ? "UP" : "",
((direction & DOWN) == DOWN) ? "DOWN" : "",
((direction & LEFT) == LEFT) ? "LEFT" : "",
((direction & RIGHT) == RIGHT) ? "RIGHT" : "");
// do something here now that you know the direction. The direction could be one of the following:
// UP
// DOWN
// LEFT
// RIGHT
// UP|LEFT
// UP|RIGHT
// DOWN|LEFT
// DOWN|RIGHT
}
}
Related
JavaCV ~ OpenCV
It is necessary to determine the direction of a person's movement (left or right) in real time. I use JavaCV. My code gives the correct answer only based on movement in ideal conditions (there are no shadows, the lighting does not change, the person does not change the trajectory of movement):
We place the found moving object in a green rectangle, calculate the sum of the centers of mass of all rectangles, calculate the difference between the centers of mass of the previous and current frames, keep statistics from a few comparisons (to reduce the probability of an error in the final result) and on its basis we make a verdict - moves to the right or to the left.
I found the function calcGlobalOrientation(), but I don't have an example of how to use it.
Perhaps someone will give advice on how to use JavaCV with a fairly high performance and low probability of error to determine the direction of movement of the object?
if (cnts.size() > 0) {
firstEntry = true;
center_current = newPoint();
for (int i = 0; i < cnts.size(); i++) {
//continue to work only with areas that satisfy the condition
if (contourArea(cnts.get(i)) < 2000) {
continue;
}
Rect r = boundingRect(cnts.get(i));
// check if the center of mass of the figure is in the "gray" area
if (
isInside(r.x() + r.width() / 2, r.y() + r.height() / 2, getArrayGrayZone().get(0)) ||
isInside(r.x() + r.width() / 2, r.y() + r.height() / 2, getArrayGrayZone().get(1))
) {
// System.out.println("Movement in the \"grey\" zone");
continue;
}
//4th parameter - characterization of the contour of the figure ("< 0" the figure is filled, "> 0" the line thickness)
rectangle(frame, r, new Scalar(0, 255, 0, 0), 3, 0, 0);
if (firstEntry) {
//+1 frame with recognized motion that satisfies the condition
counterFrame++;
firstEntry = false;
}
//look for the center of mass of the given rectangle
center = newPoint();
center.x = r.x() + r.width() / 2;
center.y = r.y() + r.height() / 2;
//if the current center of mass has not yet been calculated, then enter a new value
if (center_current.x == 0) {
center_current = center;
continue;
}
//calculate the common center of mass of the current and past rectangles
center_current.x = (center_current.x + center.x) / 2;
center_current.y = (center_current.y + center.y) / 2;
}
//if it was possible to calculate the current center of mass of the rectangles
if (center_current.x != 0) {
//if the previous center of mass has not yet been calculated, then equalize the current and previous
if (center_prev.x == 0) {
center_prev = center_current;
} else {
difference = new Vec2d(center_current.x - center_prev.x, center_current.y - center_prev.y);
if (difference.x < 0) {
indexL++;
}
if (difference.x > 0) {
indexR++;
}
}
}
}
if (counterFrame % 10 == 0 && counterFrame > 0) {
if (indexR > indexL) {
System.out.println(
"Right" + df.format(new Date()));
}
if (indexL > indexR) {
System.out.println(
"Left" + df.format(new Date()));
}
//reset the counter of frames with a recognized motion that satisfies the condition
counterFrame = 0;
//reset the "statistical" variables for detecting shift to the right or left
indexL = indexR = 0;
}
//make current center of mass "previous"
center_prev = center_current;
I have a control in my game so that a character rotates to 45 degrees when touched.x < 0 and -45 when touch.x > 0
if touched.x < 0 {
getawaycar.zRotation = CGFloat(.pi/4.0);
}
if touched.x > 0 {
getawaycar.zRotation = CGFloat(-(.pi/4.0));
}
So if I slide my finger to
CGPoint(x: touched.x, y: 0)
Getawaycar rotates to the left. But as soon as I slide my finger towards are more positive x value I want the Getwawaycar to rotate towards the right.
Maybe this way?
if touched.x < 0 {
getawaycar.zRotation = CGFloat(.pi/4.0);
} else {
getawaycar.zRotation = CGFloat(-(.pi/4.0));
}
I'm having a trouble with the Pan gesture in AS3. As I understand, making this:
function fl_PanHandler(event:TransformGestureEvent):void
{
if (escenario.scaleX && escenario.scaleY == 1)
{
trace("MAX ZOOM!");
}
else
{
event.currentTarget.x += event.offsetX;
event.currentTarget.y += event.offsetY;
}
}
Okay. Now if I make zoom, the scale will be more than 1 so, I'll be able to pan. But the pan goes outside of the MovieClip I'm zooming.
The project is 500x500, so, I need to Pan only in 500x500 not the white background of flash (project of 500x500 has black background, in a MC, is the MC that is going to be panned.
You just need to put in some constraints:
var target:DisplayObject = event.currentTarget as DisplayObject;
target.x += event.offsetX;
target.y += event.offsetY;
//if the x or y is greater than 0, that means you can see the left/top edge of the target, so make it go back to 0
if(target.x > 0) target.x = 0;
if(target.y > 0) target.y = 0;
//the stage width less the target width should be negative so long as the target is bigger than the stage.
//It will get the x point that would make the right edge line up with the stage's right edge.
if(target.x < stage.stageWidth - target.width){
//so if the x is less than that point (which would make the right edge of target visible), force the x back so the right edges align
target.x = stage.stageWidth - target.width;
}
if(target.y < stage.stageHeight - target.height){
target.y = stage.stageHeight - target.height);
}
I want to know how to detect tap for my UIScrollView as circular shape instead of rect? can you please show me how with obj c??
i can detect tap like this:
if (CGRectContainsPoint(scrollView.frame, tappedPoint)) {
NSLog(#"hello");
}
but this treat it like rect shape and i want to detect the tap as circular.
From this answer :
If you have a circle with center (center_x, center_y) and radius radius, how do you test if a given point with coordinates (x, y) is inside the circle?
In general, x and y must satisfy (x - center_x)^2 + (y - center_y)^2 < radius^2.
Please note that points that satisfy the above equation with < replaced by == are considered the points on the circle, and the points that satisfy the above equation with < replaced by > are considered the outside the circle.
Now, its pretty simple to get the center and radius from a frame:
CGPoint center = frame.center;
CGFloat radius = frame.size.width/2;
Update : So ur code would be -
- (BOOL) isPoint:(CGPoint)point insideCircleFromRect:(CGRect)frame
{
CGPoint center = frame.center;
CGFloat radius = frame.size.width/2;
//(x - center_x)^2 + (y - center_y)^2 < radius^2
CGFloat lhs = pow((point.x-center.x),2) + pow((point.y-center.y),2);
CGFloat rhs = pow(radius,2);
if(lhs<rhs)
return YES;
else
return NO;
}
Im wondering at my setting ball.position function, the point is to set ball's point to other spritenode(in left/middle/right side), i tried to write my own function, but it was full of bugs, (it's commented), next after review developer lib's. I found anchorPoint to parent position, but it's not working, i dont know exactly how to set current parent for ball. I'll be really grateful for some advices.
if (ball.position.y < block.position.y +10 && ball.position.y > block.position.y -10) {
midX = CGRectGetMidX(self.frame);
side = block1.size.width/2;
if (emitter.position.x < midX - side+5) {
// fixedEmitterPos = emitter.position.x+side;
ball.anchorPoint = CGPointMake(0,0.5);
}
if (emitter.position.x > midX + side-5){
// fixedEmitterPos = emitter.position.x-side;
ball.anchorPoint = CGPointMake(1,0.5);
}
if (emitter.position.x == 160) {
// fixedEmitterPos = emitter.position.x;
ball.anchorPoint = CGPointMake(0.5,0.5);
}
}
I don't know what exactly is your question but to change your anchor point you don't change anything in parent node. For example if anchor point is
ball.anchorPoint = CGPointMake(0.5,0.5);
the anchor point in exactly in the middle and if you change position of the ball like:
ball.position == CGPointMake(50,50);
the ball center will be exactly in that point (50, 50).
but if the anchor point will be:
ball.anchorPoint = CGPointMake(1, 1);
and you change the position to :
ball.position == CGPointMake(50,50);
the ball centre will be in
X = 50 - (ball width / 2)
Y = 50 - (ball height / 2)
If you want to set up ball position base on other sprite node you can do something like that:
//Attach left centre side of ball to other sprite:
ball.anchorPoint = CGPointMake(0, 0.5);
ball.position.x == otherSprit.position.x + otherSprit.size.with;
ball.position.y == otherSprit.position.y;
//Attach right centre side of ball to other sprite:
ball.anchorPoint = CGPointMake(1, 0.5);
ball.position.x == otherSprit.position.x;
ball.position.y == otherSprit.position.y;
Hope this is what you are about.