Zoom & Panning questions (AS3) - ios

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);
}

Related

UIScrollView detect circular tap

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;
}

Stop SKAction at collision with PhysicsBody

I have a SpriteNode which is affected by gravity only on the y-Axis and can be moved with the accelerometer on the x-Axis. I also have a border (SKPhysicsBody) on my Scene which keeps my node inside my scene. The problem is now that my node ignores the border when it performs its SKAction caused by the accelerometer.
My code for the x movement/ accelerometer and its action:
birdNode is my SpriteNode
float destX = 0.0;
float currentX = birdNode.position.x;
BOOL shouldMove = NO;
if (data.acceleration.x < -0.1) {
destX = currentX + (data.acceleration.x * playerXSpeed);
shouldMove = YES;
}
else if (data.acceleration.x > 0.1) {
destX = currentX + (data.acceleration.x * playerXSpeed);
shouldMove = YES;
}
if (shouldMove) {
if (birdNode.position.x + destX < self.frame.size.width || birdNode.position.x - destX > 0) {
SKAction *moveBird = [SKAction moveToX:destX duration:0.1];
[birdNode runAction:moveBird];
}
}
I assume that you have your collision bit masks properly set up to handle collisions. You should confirm this with a test to double check.
I believe your issue is with the speed of your object. If the object is moving too fast, and I do not see any velocity limits in your posted code, your object can move past the screen boundary in one update cycle.
For example, your current object's position is (400,100). Given enough velocity, your object's next update: position could be (600,100). This means that your object literally jumped past the boundary without causing a collision.
The solution is to either limit the velocity or to institute a position check before setting your object's new position. For example, if the new x position is > the screen width then set the x position to the max allowed screen width x.

iOS GestureRecognizers All Directions

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
}
}

Avoid translation when scaling polynom and center to mouse position

in my application i have a polygon (with 4 points = rectangle) in a canvas. I want to scale the polygon by a factor by using the mouse wheel. For that i use this code:
double scale = 1.0, factor = 1.01, cX, cY;
void polygon_MouseWheel(object sender, MouseWheelEventArgs e)
{
cX = e.GetPosition(polygon).X;
cY = e.GetPosition(polygon).Y;
if (e.Delta > 0) scale *= factor;
else scale /= factor;
polygon.RenderTransform = new ScaleTransform(scale, scale, cX, cY);
}
This works fine, when i place the mousepointer to a point P (let's say P is a point near to the top left corner of the polygon) in the polygon and scroll up or down. So the polygon zooms in or out according to that point. But when i move the mouse pointer to an other point Q (near the bottom right corner) and continue zooming in or out, the polygon is shifted towards to top left corner by an amount s. It seems that the amount s depends on the distance between P and Q. So if the distance between P and Q is large, the shift is large.
The desired behaviour in this case is, that the polygon is not shifted, but just scaled to the new point Q.
Does anyone has an idea, whats the reason of the shift? I'm thankful for any hints.
Example code:
<window ...>
<Grid>
<Canvas Name="canvas1" Background="LightBlue">
<Polygon Points="100,100 100,300 300,300 300,100" Name="polygon" Fill="Black" MouseWheel="polygon_MouseWheel"/>
</Canvas>
</Grid>
</Window>
public MainWindow()
{
InitializeComponent();
}
double scale = 1.0, factor = 1.01, cX, cY;
void polygon_MouseWheel(object sender, MouseWheelEventArgs e)
{
cX = e.GetPosition(polygon).X;
cY = e.GetPosition(polygon).Y;
if (e.Delta > 0) scale *= factor;
else scale /= factor;
polygon.RenderTransform = new ScaleTransform(scale, scale, cX, cY);
}
Ok, after trying around a while i found out what causes this behaviour. The MSDN article of the UIElement.RenderTransform property says:
A render transform does not regenerate layout size or render size information. Render transforms are typically intended for animating or applying a temporary effect to an element. For example, the element might zoom when focused or moused over, or might jitter on load to draw the eye to that part of the user interface (UI).
That means, that the polygon itself, respectively the points of the polygon, isn't transformed. When applying the ScaleTransform the points of the polygon do not change and will remain as they were set in the xaml. Nevertheless the transformed polygon will react on mouse events, but the mouse position is mapped to the original bounds.
Example: Let's take the polygon, defined above in the xaml and scale it by factor 1.5. The polygon is displayed scaled and it seems that its points has the values (150,150 150,450 450,450 450,150) now. But internally it still has the old values (100,100 100,300 300,300 300,100). If you catch the position of the mouse pointer at the scaled top right corner, it will be (300,100) instead of (450,150).
Using the mouse position as center for the scaling causes the shift of the scaled polygon.
A solution for this is to scale the points of the polygon itself, instead of using ScaleTransform:
void Scale(double factor, double centerX, double centerY)
{
PointCollection pc = new PointCollection();
foreach (Point p in polygon.Points)
{
Point q = new Point();
q.X = p.X;
q.Y = p.Y;
q.X -= centerX; // translate
q.Y -= centerY;
q.X *= factor; // scale
q.Y *= factor;
q.X += centerX; // translate back
q.Y += centerY;
pc.Add(q);
}
polygon.Points = pc; // polygon is defined in xaml
}
I'm not sure if this is the right way to do it, but it works for me.

Looping character around width of screen?

What I am trying to do is lets say my character moves off the right side of the screen, I want it to come back around from the left part of the screen with the same Y coordinate. I am using Cocos2D also. I am currently trying to do this in my UIAccelerometer method but it does not seem to work.
Can someone show me what I should do instead?
Thanks!
This will change your character's position if it leaves the left or right side of the screen to the other side, without modifying the y coordinate.
CGSize size = [CCDirector sharedDirector].winSize;
CGPoint pos = character.position;
if (pos.x >= size.width)
pos.x -= size.width;
else if (pos.x < 0.0f)
pos.x += size.width;
character.position = pos;
The reason why I add or subtract the width rather than setting the x coordinate directly to 0 or width is that the character may be moving faster than 1 pixel per frame. That means if he's moving fast and moves let's say from X coordinate 479 to 495 in one frame, then he should be set to X coordinate 15 on the other side to make sure the velocity of the character is unaffected.

Resources