Drag and drop SKSpriteNode with the shape of a oval - ios

I have a scene with one sprite, the image used for the sprites is an oval.
The problem I'm facing is that, whenever I use touchAtPoint it returns the sprite even if the touch occurs at a transparent area of the image.
How can I solve that?
My current code looks like:
-(id)initWithSize:(CGSize)size {
if (self = [super initWithSize:size]) {
self.backgroundColor = [SKColor blackColor];
self.physicsBody = [SKPhysicsBody bodyWithEdgeLoopFromRect:self.frame];
SKSpriteNode *sprite = [SKSpriteNode spriteNodeWithImageNamed:#"Red"];
sprite.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:50.0];
sprite.physicsBody.affectedByGravity = NO;
sprite.physicsBody.usesPreciseCollisionDetection = YES;
[self addChild: sprite];
}
return self;
}
- (void)didMoveToView:(SKView *)view {
UIPanGestureRecognizer *gestureRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:#selector(handlePanFrom:)];
[self.view addGestureRecognizer:gestureRecognizer];
}
- (void)handlePanFrom:(UIPanGestureRecognizer *)recognizer {
if (recognizer.state == UIGestureRecognizerStateBegan) {
CGPoint touchLocation = [recognizer locationInView:recognizer.view];
touchLocation = [self convertPointFromView:touchLocation];
SKNode *touchedNode = (SKNode *)[self nodeAtPoint:touchLocation];
_selectedNode = touchedNode;
}
else if (recognizer.state == UIGestureRecognizerStateChanged) {
CGPoint translation = [recognizer translationInView:recognizer.view];
translation = CGPointMake(translation.x, -translation.y);
[self panForTranslation:translation];
[recognizer setTranslation:CGPointZero inView:recognizer.view];
}
}
- (void)panForTranslation:(CGPoint)translation {
CGPoint position = [_selectedNode position];
[_selectedNode setPosition:CGPointMake(position.x + translation.x, position.y + translation.y)];
}

OK, so the only relevant code here is...
CGPoint touchLocation = [recognizer locationInView:recognizer.view];
touchLocation = [self convertPointFromView:touchLocation];
SKNode *touchedNode = (SKNode *)[self nodeAtPoint:touchLocation];
_selectedNode = touchedNode;
This needs to change to something like this...
CGPoint touchLocation = [recognizer locationInView:recognizer.view];
touchLocation = [self convertPointFromView:touchLocation];
SKNode *touchedNode = (SKNode *)[self nodeAtPoint:touchLocation];
// Work out if the touch is inside the circle
CGPoint centerOfNode = CGPointMake(touchedNode.position.x + touchedNode.size.width * 0.5, touchedNode.positiony + touchedNode.size.height * 0.5);
CGFloat dx = touchedNode.position.x - touchLocation.x;
CGFloat dy = touchedNode.position.y - touchLocation.y;
CGFloat distanceFromCenter = sqrtf(dx * dx + dy * dy);
if (distanceFromCenter <= touchedNode.size.width * 0.5) {
_selectedNode = touchedNode;
}

Related

Objective C - SpriteKit - Unable to detect contact between ball and paddle node

I am trying to detect the collision between the ball node and either one of the paddle nodes but the message to confirm the collision is not being fired.
Could somebody help me understand where I am going wrong?
//categories for detecting contacts between nodes
static const uint32_t ballCategory = 0x1 << 0;
static const uint32_t paddleCategory = 0x1 << 1;
#interface GameScene ()
#property BOOL contentCreated;
#property(nonatomic) UITouch *playerOnePaddleControlTouch;
#property(nonatomic, weak) UITouch *paddleTouch;
#property(nonatomic) SKSpriteNode *paddleOneNode;
#property(nonatomic) SKSpriteNode *paddleTwoNode;
#property(nonatomic) SKSpriteNode *ballNode;
#property(nonatomic) SKLabelNode *playerOneScoreNode;
#property(nonatomic) SKLabelNode *playerTwoScoreNode;
#property(nonatomic) NSInteger playerOneScore;
#property(nonatomic) NSInteger playerTwoScore;
#end
#implementation GameScene
- (void)didMoveToView:(SKView *)view
{
if (!self.contentCreated)
{
[self createSceneContents];
self.contentCreated = YES;
}
}
- (void) createSceneContents
{
self.backgroundColor = [SKColor blackColor];
self.scaleMode = SKSceneScaleModeAspectFit;
[self addChild: [self newGameNode]];
self.physicsWorld.gravity = CGVectorMake(0, 0);
self.physicsWorld.contactDelegate = self;
// Create border around screen
SKPhysicsBody* borderBody = [SKPhysicsBody bodyWithEdgeLoopFromRect:self.frame];
self.physicsBody = borderBody;
self.physicsBody.friction = 0;
// Create Paddle One
SKSpriteNode *paddleOne = [self newPaddle];
paddleOne.position = CGPointMake(CGRectGetMidX(self.frame)/8, CGRectGetMidY(self.frame));
paddleOne.name = #"paddleOne";
paddleOne.physicsBody.categoryBitMask = paddleCategory;
paddleOne.physicsBody.contactTestBitMask = ballCategory;
[self addChild:paddleOne];
// Create Paddle Two
SKSpriteNode *paddleTwo = [self newPaddle];
paddleTwo.position = CGPointMake((CGRectGetMaxX(self.frame) - CGRectGetMidX(self.frame) / 8), CGRectGetMidY(self.frame));
paddleTwo.name = #"paddleTwo";
paddleTwo.physicsBody.categoryBitMask = paddleCategory;
paddleTwo.physicsBody.contactTestBitMask = ballCategory;
[self addChild:paddleTwo];
// Create ball
SKSpriteNode *ball = [self newBall];
ball.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame));
[self addChild:ball];
ball.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:ball.frame.size.width/2];
ball.physicsBody.friction = 1.0f; //normally 1.0f
ball.physicsBody.restitution = 1.0f; //normally 1.0f
ball.physicsBody.linearDamping = 0.0f; //normally 0.0f
ball.physicsBody.allowsRotation = NO;
ball.physicsBody.categoryBitMask = ballCategory;
ball.physicsBody.contactTestBitMask = paddleCategory;
[ball.physicsBody applyImpulse:CGVectorMake(1.0f, -1.0f)];
// Create score labels
self.playerOneScoreNode = [SKLabelNode labelNodeWithFontNamed:#"Helvetica"];
self.playerTwoScoreNode = [SKLabelNode labelNodeWithFontNamed:#"Helvetica"];
self.playerOneScoreNode.fontColor = self.playerOneScoreNode.fontColor = [SKColor whiteColor];
self.playerOneScoreNode.fontSize = self.playerTwoScoreNode.fontSize = 90;
self.playerOneScoreNode.position = CGPointMake((CGRectGetWidth(self.frame))* 0.25, (CGRectGetHeight(self.frame)) - 80);
self.playerTwoScoreNode.position = CGPointMake((CGRectGetWidth(self.frame)) * 0.75, (CGRectGetHeight(self.frame)) - 80);
[self addChild:self.playerOneScoreNode];
[self addChild:self.playerTwoScoreNode];
// Set Scores to 0
self.playerOneScore = 7;
self.playerTwoScore = 0;
self.playerOneScoreNode.text = [NSString stringWithFormat:#"%ld",self.playerOneScore];
self.playerTwoScoreNode.text = [NSString stringWithFormat:#"%ld",self.playerTwoScore];
}
- (SKSpriteNode *)newPaddle
{
SKSpriteNode *paddle = [[SKSpriteNode alloc]initWithColor:[SKColor whiteColor] size:CGSizeMake(16,64)];
return paddle;
}
- (SKSpriteNode *)newBall
{
SKSpriteNode *ball = [[SKSpriteNode alloc]initWithColor:[SKColor redColor] size:CGSizeMake(16, 16)];
return ball;
}
- (SKLabelNode *) newGameNode
{
SKLabelNode *gameNode = [SKLabelNode labelNodeWithFontNamed:#"Chalkduster"];
gameNode.text = #" Pong";
gameNode.fontSize = 50;
gameNode.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame));
gameNode.fontColor = [SKColor blueColor];
return gameNode;
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
self.paddleTouch = [touches anyObject];
UITouch *touch = [touches anyObject];
CGPoint touchPoint = [touch locationInNode:self];
SKNode *paddleOne = [self childNodeWithName:#"paddleOne"];
SKNode *paddleTwo = [self childNodeWithName:#"paddleTwo"];
if (touchPoint.x < CGRectGetMidX(self.frame)) {
paddleOne.position = CGPointMake(paddleOne.position.x, touchPoint.y);
}
else
{
paddleTwo.position = CGPointMake(paddleTwo.position.x, touchPoint.y);
}
}
- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
if (self.paddleTouch) {
UITouch *touch = [touches anyObject];
CGPoint touchPoint = [touch locationInNode:self];
CGPoint previousPoint = [touch previousLocationInNode:self];
SKSpriteNode *paddleOne = (SKSpriteNode*)[self childNodeWithName:#"paddleOne"];
SKSpriteNode *paddleTwo = (SKSpriteNode*)[self childNodeWithName:#"paddleTwo"];
int paddleOneY = paddleOne.position.y + (touchPoint.y - previousPoint.y);
int paddleTwoY = paddleTwo.position.y + (touchPoint.y - previousPoint.y);
if (touchPoint.x < CGRectGetMidX(self.frame)) {
paddleOne.position = CGPointMake(paddleOne.position.x, paddleOneY);
}
else
{
paddleTwo.position = CGPointMake(paddleTwo.position.x, paddleTwoY);
}
}
}
// React to collision's between nodes/bodies
// Currently not working....need to understand this set of code.
-(void)didBeginContact:(SKPhysicsContact *)contact
{
SKPhysicsBody *firstBody;
SKPhysicsBody *secondBody;
if (contact.bodyA.categoryBitMask < contact.bodyB.categoryBitMask)
{
firstBody = contact.bodyA;
secondBody = contact.bodyB;
}
else
{
firstBody = contact.bodyB;
secondBody = contact.bodyA;
}
if (firstBody.categoryBitMask == ballCategory && secondBody.categoryBitMask == paddleCategory)
{
NSLog(#"Ball has touched Paddle");
}
}
#end
Your paddleOne and paddleTwo does not have SKPhysicsBody.
Add these (change size of physics body if needed)
paddleOne.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize: paddleOne.size];
paddleTwo.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize: paddleTwo.size];

Projectile not starting at correct point?

I'm making a simple iOS game where the goal is to have an angel in the middle of the screen shoot arrows at monsters coming at him from all sides. When the user taps the screen, I want an arrow to travel from the angel in the direction of the tap. But when I tap the screen, it travels from the corner of the screen, not the middle. Here's my code:
#import "MyScene.h"
static inline CGPoint rwAdd(CGPoint a, CGPoint b)
{
return CGPointMake(a.x + b.x, a.y + b.y);
}
static inline CGPoint rwSub(CGPoint a, CGPoint b)
{
return CGPointMake(a.x - b.x, a.y - b.y);
}
static inline CGPoint rwMult(CGPoint a, float b)
{
return CGPointMake(a.x * b, a.y * b);
}
static inline float rwLength(CGPoint a)
{
return sqrtf(a.x * a.x + a.y * a.y);
}
static inline CGPoint rwNormalize(CGPoint a)
{
float length = rwLength(a);
return CGPointMake(a.x / length, a.y / length);
}
#implementation MyScene
- (id) initWithSize: (CGSize) size
{
if (self = [super initWithSize:size])
{
self.backgroundColor = [SKColor colorWithRed: 1.0 green: 1.0 blue: 1.0 alpha: 1.0];
SKSpriteNode *angel = [SKSpriteNode spriteNodeWithImageNamed: #"Angel"];
angel.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame));
angel.xScale = 0.25;
angel.yScale = 0.25;
[self addChild: angel];
}
return self;
}
- (void) touchesBegan: (NSSet *) touches withEvent: (UIEvent *) event
{
UITouch * touch = [touches anyObject];
CGPoint location = [touch locationInNode: self];
SKSpriteNode *arrow = [SKSpriteNode spriteNodeWithImageNamed: #"Arrow"];
arrow.xScale = 0.25;
arrow.yScale = 0.25;
SKNode *angel = [self childNodeWithName: #"Angel"];
arrow.position = angel.position;
CGPoint offset = rwSub(location, arrow.position);
[self addChild: arrow];
CGPoint direction = rwNormalize(offset);
CGPoint shootAmount = rwMult(direction, 500);
CGPoint realDest = rwAdd(shootAmount, arrow.position);
float velocity = 480.0/1.0;
float realMoveDuration = self.size.width / velocity;
SKAction *actionMove = [SKAction moveTo: realDest duration: realMoveDuration];
SKAction *actionMoveDone = [SKAction removeFromParent];
[arrow runAction: [SKAction sequence: #[actionMove, actionMoveDone]]];
}
#end
Suggestions? Thanks.
Make the following modifications:
#implementation MyScene
{
SKSpriteNode *angel; // <- add this
}
- (void) touchesBegan: (NSSet *) touches withEvent: (UIEvent *) event
{
UITouch * touch = [touches anyObject];
CGPoint location = [touch locationInNode: self];
SKSpriteNode *arrow = [SKSpriteNode spriteNodeWithImageNamed: #"Arrow"];
arrow.xScale = 0.25;
arrow.yScale = 0.25;
//SKNode *angel = [self childNodeWithName: #"Angel"]; // <- delete this
arrow.position = angel.position;
CGPoint offset = rwSub(location, arrow.position);
[self addChild: arrow];
CGPoint direction = rwNormalize(offset);
CGPoint shootAmount = rwMult(direction, 500);
CGPoint realDest = rwAdd(shootAmount, arrow.position);
float velocity = 480.0/1.0;
float realMoveDuration = self.size.width / velocity;
SKAction *actionMove = [SKAction moveTo: realDest duration: realMoveDuration];
SKAction *actionMoveDone = [SKAction removeFromParent];
[arrow runAction: [SKAction sequence: #[actionMove, actionMoveDone]]];
}

Move a SKSpriteNode with a single tap, but move continously when long tap - Sprite Kit

I'm trying to change some SKActions of an existing Sprite Kit tutorial project, but I'm running into issues when it comes to movement. The Tutorial and GitHub project is here:
https://www.codefellows.org/blogs/simple-sprite-kit-game-tutorial-part1
https://github.com/megharastogi/GameTutorial
As you can see in the code below, each tap only moves the node once. How do I change it so that a long tap will move continuous move the node? I tried a few things like repeatActionForever, but that didn't work very well.
-(void)addShip
{
//initalizing spaceship node
ship = [SKSpriteNode spriteNodeWithImageNamed:#"Spaceship"];
[ship setScale:0.5];
ship.zRotation = - M_PI / 2;
//Adding SpriteKit physicsBody for collision detection
ship.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:ship.size];
ship.physicsBody.categoryBitMask = shipCategory;
ship.physicsBody.dynamic = YES;
ship.physicsBody.contactTestBitMask = obstacleCategory;
ship.physicsBody.collisionBitMask = 0;
ship.physicsBody.usesPreciseCollisionDetection = YES;
ship.name = #"ship";
ship.position = CGPointMake(120,160);
actionMoveUp = [SKAction moveByX:0 y:30 duration:.2];
actionMoveDown = [SKAction moveByX:0 y:-30 duration:.2];
[self addChild:ship];
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
CGPoint touchLocation = [touch locationInNode:self.scene];
if(touchLocation.y >ship.position.y){
if(ship.position.y < 270){
[ship runAction:actionMoveUp];
}
}else{
if(ship.position.y > 50){
[ship runAction:actionMoveDown];
}
}
}
- (void)didMoveToView:(SKView *)view
{
UILongPressGestureRecognizer *tapper = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:#selector(tappedScreen:)];
tapper.minimumPressDuration = 0.1;
[view addGestureRecognizer:tapper];
}
- (void)tappedScreen:(UITapGestureRecognizer *)recognizer
{
float touchY = [self convertPointFromView:[recognizer locationInView:self.view]].y;
SKSpriteNode *ship = [self childNodeWithName:#"ship"];
if (recognizer.state == UIGestureRecognizerStateBegan) {
if(touchY >ship.position.y){
[ship runAction:[SKAction repeatActionForever:actionMoveUp] withKey:#"longTap"];
}else{
[ship runAction:[SKAction repeatActionForever:actionMoveDown] withKey:#"longTap"];
}
}
if (recognizer.state == UIGestureRecognizerStateEnded) {
[ship removeActionForKey:#"longTap"];
}
}
Add these two methods in your code.

Understanding SpriteKit : Moving Sprites

This is my first post and I am trying to use Apple's SpriteKit framework.
I believe I have a misunderstanding of how to move sprites using the framework. I have a simple example where I would like to move a hero in a simple UP, DOWN, LEFT, RIGHT direction based on the a tap location, respective to the "hero" location. Once the hero hits a block the "hero" should stop.
For testing purposes I am just trying to tap above the "hero" hit the wall of blocks on the top of the screen. Then after the collision occurs, tap below the "hero". I was expecting the "hero" to move toward the wall of blocks on the bottom row; however it seem that the "hero" continues to move UP and through the top wall. I am sure I am making a fundamental flaw, I would appreciate any help.
Thanks
Here is the sample scene I wrote:
static inline CGPoint CGPointSubtract(const CGPoint a, const CGPoint b)
{
return CGPointMake(a.x - b.x, a.y - b.y);
}
typedef enum DIRECTION_e
{
UP,
DOWN,
LEFT,
RIGHT
} DIRECTION_t;
typedef NS_OPTIONS(uint32_t, CNPhysicsCategory)
{
PhysicsCategoryBlock = 1 << 0,
PhysicsCategoryHero = 1 << 1
};
#interface LevelScene ()
#property (nonatomic) SKSpriteNode * hero;
#property (nonatomic) BOOL inMotion;
#end
#implementation LevelScene
-(id) initWithSize:(CGSize)size
{
if (self = [super initWithSize:size])
{
self.physicsWorld.gravity = CGVectorMake(0,0);
self.physicsWorld.contactDelegate = self;
[self createLevel];
[self createHero];
self.inMotion = NO;
}
return self;
}
- (void) createHero
{
[self addHeroAtRow:5 column:2];
}
- (void) createLevel
{
self.backgroundColor = [SKColor blackColor];
self.scaleMode = SKSceneScaleModeAspectFit;
[self addBlockAtRow:1 column:1];
[self addBlockAtRow:1 column:2];
[self addBlockAtRow:1 column:3];
[self addBlockAtRow:10 column:1];
[self addBlockAtRow:10 column:2];
[self addBlockAtRow:10 column:3];
}
- (void) addBlockAtRow:(NSInteger)row column:(NSInteger)column
{
SKSpriteNode *block = [[SKSpriteNode alloc] initWithColor:[SKColor brownColor] size:CGSizeMake(64,64)];
block.position = CGPointMake(32 + (column * 64), 32 + ((11-row) * 64));
block.name = #"block";
block.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:block.size];
block.physicsBody.dynamic = NO;
block.physicsBody.categoryBitMask = PhysicsCategoryBlock;
block.physicsBody.collisionBitMask = PhysicsCategoryBlock | PhysicsCategoryHero;
block.physicsBody.contactTestBitMask = PhysicsCategoryBlock | PhysicsCategoryHero;
[self addChild:block];
}
- (void) addHeroAtRow:(NSInteger)row column:(NSInteger)column
{
self.hero = [[SKSpriteNode alloc] initWithColor:[SKColor redColor] size:CGSizeMake(64,64)];
self.hero.position = CGPointMake(32 + (column * 64), 32 + ((11-row) * 64));
self.hero.name = #"hero";
self.hero.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:CGSizeMake(self.hero.size.width/2, self.hero.size.height/2)];
self.hero.physicsBody.usesPreciseCollisionDetection = YES;
self.hero.physicsBody.dynamic = YES;
self.hero.physicsBody.categoryBitMask = PhysicsCategoryHero;
self.hero.physicsBody.collisionBitMask = PhysicsCategoryHero | PhysicsCategoryBlock;
self.hero.physicsBody.contactTestBitMask = PhysicsCategoryHero | PhysicsCategoryBlock;
[self addChild:self.hero];
NSLog(#"ADDING HERO: %f, %f", self.hero.position.x, self.hero.position.y);
}
- (void)didBeginContact:(SKPhysicsContact *)contact
{
if (contact.bodyA.categoryBitMask == PhysicsCategoryBlock && contact.bodyB.categoryBitMask == PhysicsCategoryHero)
{
[self.hero removeAllActions];
self.hero.position = contact.bodyB.node.position;
NSLog(#"COLLISION: %f, %f", self.hero.position.x, self.hero.position.y);
self.inMotion = NO;
}
else if (contact.bodyB.categoryBitMask == PhysicsCategoryBlock && contact.bodyA.categoryBitMask == PhysicsCategoryHero)
{
[self.hero removeAllActions];
self.hero.position = contact.bodyA.node.position;
NSLog(#"COLLISION: %f, %f", self.hero.position.x, self.hero.position.y);
self.inMotion = NO;
}
}
- (void) moveHeroTowardDirection:(DIRECTION_t)direction
{
CGPoint location;
switch (direction)
{
case UP:
{
location = CGPointMake(self.hero.position.x, self.hero.position.y + 600);
}
break;
case DOWN:
{
location = CGPointMake(self.hero.position.x, self.hero.position.y + -600);
}
break;
case LEFT:
{
location = CGPointMake(self.hero.position.x + -600, self.hero.position.y);
}
break;
case RIGHT:
{
location = CGPointMake(self.hero.position.x + 600, self.hero.position.y);
}
break;
default: return;
}
NSLog(#"MOVE POSITION: %f, %f", location.x, location.y);
SKAction *action = [SKAction moveTo:location duration:10];
[self.hero runAction:action];
}
-(void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
if (self.inMotion)
return;
self.inMotion = YES;
UITouch *touch = [touches anyObject];
CGPoint touchLocation = [touch locationInView:self.view];
CGPoint diff = CGPointSubtract(self.hero.position, touchLocation);
NSLog(#"TOUCH POSITION: %f, %f", touchLocation.x, touchLocation.y);
NSLog(#"HERO POSITION: %f, %f", self.hero.position.x, self.hero.position.y);
NSLog(#"DIFF POSITION: %f, %f", diff.x, diff.y);
//
// Magnitude to find out which direction is dominate
//
if (abs(diff.x) > abs(diff.y))
{
if (touchLocation.x > self.hero.position.x)
{
NSLog(#"LEFT");
[self moveHeroTowardDirection:LEFT];
}
else
{
NSLog(#"RIGHT");
[self moveHeroTowardDirection:RIGHT];
}
}
else
{
if (touchLocation.y < self.hero.position.y)
{
NSLog(#"UP");
[self moveHeroTowardDirection:UP];
}
else
{
NSLog(#"DOWN");
[self moveHeroTowardDirection:DOWN];
}
}
}
#end
Here try this, you need to remove/disable your touches ended as well
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
for (UITouch *touch in touches) {
for (UITouch *touch in touches) {
CGPoint location = [touch locationInNode:self];
CGPoint diff = CGPointMake(location.x - self.hero.position.x, location.y - self.hero.position.y);
CGFloat angleRadians = atan2f(diff.y, diff.x);
[self.hero runAction:[SKAction sequence:#[
[SKAction rotateToAngle:angleRadians duration:1.0],
[SKAction moveByX:diff.x y:diff.y duration:3.0]
]]];
}
}
}

Drag, scale and rotate multiple UIImageviews

I've got it so far that I can move, scale and rotate all the objects, but the multiple objects all move together. I want them to move seperate. I guess I have to change the objectatIndex to 1, but it just crashes.
I've used the following code:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
NSArray *allTouches = [touches allObjects];
UITouch* t;
if([[event allTouches] count]==1){
if (CGRectContainsPoint([Birdie frame], [[allTouches objectAtIndex:0] locationInView:theimageView]) && CGRectContainsPoint([imageViewauto frame], [[allTouches objectAtIndex:0] locationInView:theimageView])) {
t=[[[event allTouches] allObjects] objectAtIndex:0];
touch1=[t locationInView:nil];
}
}else{
t=[[[event allTouches] allObjects] objectAtIndex:0];
touch1=[t locationInView:nil];
t=[[[event allTouches] allObjects] objectAtIndex:1];
touch2=[t locationInView:nil];
}
}
-(double)distance:(CGPoint)point1 toPoint:(CGPoint)point2
{
double deltaX, deltaY;
deltaX = point1.x - point2.x;
deltaY = point1.y - point2.y;
return sqrt(deltaX * deltaX + deltaY * deltaY);
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
CGPoint currentTouch1;
CGPoint currentTouch2;
NSArray *allTouches = [touches allObjects];
UITouch* t;
float scale,rotation;
if([[event allTouches] count]==1){
t=[[[event allTouches] allObjects] objectAtIndex:0];
if (CGRectContainsPoint([Birdie frame], [[allTouches objectAtIndex:0] locationInView:theimageView]) && CGRectContainsPoint([imageViewauto frame], [[allTouches objectAtIndex:0] locationInView:theimageView]))
{
touch2=[t locationInView:nil];
Birdie.center=CGPointMake(Birdie.center.x+touch2.x-touch1.x,Birdie.center.y+touch2.y-touch1.y);
imageViewauto.center=CGPointMake(imageViewauto.center.x+touch2.x-touch1.x,imageViewauto.center.y+touch2.y-touch1.y);
touch1=touch2;
}
}
else if([[event allTouches] count]==2)
{
t=[[[event allTouches] allObjects] objectAtIndex:0];
currentTouch1=[t locationInView:nil];
t=[[[event allTouches] allObjects] objectAtIndex:1];
currentTouch2=[t locationInView:nil];
double distance1 = [self distance:currentTouch1 toPoint:currentTouch2];
double distance2 = [self distance:touch1 toPoint:touch2];
if (distance2 == 0)
{
//handle the case where distance is zero
}
else {
scale =distance1 / distance2;}
rotation=atan2(currentTouch2.y-currentTouch1.y, currentTouch2.x-currentTouch1.x)-atan2(touch2.y-touch1.y,touch2.x-touch1.x);
if(isnan(scale)){
scale=1.0f;
}
NSLog(#"rotation %f",rotation);
NSLog(#"scale %f",scale);
if (CGRectContainsPoint([Birdie frame], [[allTouches objectAtIndex:0] locationInView:theimageView]) && CGRectContainsPoint([imageViewauto frame], [[allTouches objectAtIndex:0] locationInView:theimageView]))
{
Birdie.transform=CGAffineTransformScale(Birdie.transform, scale,scale);
Birdie.transform=CGAffineTransformRotate(Birdie.transform, rotation);
imageViewauto.transform=CGAffineTransformScale(imageViewauto.transform, scale,scale);
imageViewauto.transform=CGAffineTransformRotate(imageViewauto.transform, rotation);
}
else // In case of scaling or rotating the background imageView
{
imageView.transform=CGAffineTransformScale(imageView.transform, scale,scale);
imageView.transform=CGAffineTransformRotate(imageView.transform, rotation);
}
touch1=currentTouch1;
touch2=currentTouch2;
}
}
First of all, an easy way to handle drag, scale and rotate is to use GestureRecognizers like the bellow one:
UIPinchGestureRecognizer *pinchRecognizer = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:#selector(scale:)];
[pinchRecognizer setDelegate:self];
[self.view addGestureRecognizer:pinchRecognizer];
UIRotationGestureRecognizer *rotationRecognizer = [[UIRotationGestureRecognizer alloc] initWithTarget:self action:#selector(rotate:)];
[rotationRecognizer setDelegate:self];
[self.view addGestureRecognizer:rotationRecognizer];
UIPanGestureRecognizer *panRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:#selector(move:)];
[panRecognizer setMinimumNumberOfTouches:1];
[panRecognizer setMaximumNumberOfTouches:1];
[panRecognizer setDelegate:self];
[self.view addGestureRecognizer:panRecognizer];
UITapGestureRecognizer *tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(tapped:)];
[tapRecognizer setNumberOfTapsRequired:1];
[tapRecognizer setDelegate:self];
[self.view addGestureRecognizer:tapRecognizer];
To handle multiple UIImageViews you may use the position of touched points, you can use the bellow functions to do so:
- (CGPoint)locationInView:(UIView*)view;
- (CGPoint)locationOfTouch:(NSUInteger)touchIndex inView:(UIView*)view;
According to the number of touched you can use either the first or second function, and then see if the touched point is inside the frame of considered UIImageView, for example for scaling you can do as what is show in bellow:
-(void)scale:(id)sender {
UIView * pinchView = [(UIPinchGestureRecognizer*)sender view];
CGPoint first_point = [sender locationOfTouch:0 inView:pinchView];
CGPoint second_point = [sender locationOfTouch:1 inView:pinchView];
if (CGRectContainsPoint(my_image_view.frame, first_point) && CGRectContainsPoint(my_image_view.frame, second_point)) {
[self.view bringSubviewToFront:pinchView];
if([(UIPinchGestureRecognizer*)sender state] == UIGestureRecognizerStateEnded) {
lastScale = 1.0;
return;
}
CGFloat scale = 1.0 - (lastScale - [(UIPinchGestureRecognizer*)sender scale]);
CGAffineTransform currentTransform = my_image_view.transform;
CGAffineTransform newTransform = CGAffineTransformScale(currentTransform, scale, scale);
[my_image_view setTransform:newTransform];
lastScale = [(UIPinchGestureRecognizer*)sender scale];}}
its working
-(void)scale:(id)sender {
if([(UIPinchGestureRecognizer*)sender state] == UIGestureRecognizerStateBegan) {
_lastScale = 1.0;
}
CGFloat scale = 1.0 - (_lastScale - [(UIPinchGestureRecognizer*)sender scale]);
CGAffineTransform currentTransform = self.transform;
CGAffineTransform newTransform = CGAffineTransformScale(currentTransform, scale, scale);
[self setTransform:newTransform];
_lastScale = [(UIPinchGestureRecognizer*)sender scale];
[self showOverlayWithFrame:self.frame];
}
-(void)rotate:(id)sender {
if([(UIRotationGestureRecognizer*)sender state] == UIGestureRecognizerStateEnded) {
_lastRotation = 0.0;
return;
}
CGFloat rotation = 0.0 - (_lastRotation - [(UIRotationGestureRecognizer*)sender rotation]);
CGAffineTransform currentTransform = self.transform;
CGAffineTransform newTransform = CGAffineTransformRotate(currentTransform,rotation);
[self setTransform:newTransform];
_lastRotation = [(UIRotationGestureRecognizer*)sender rotation];
[self showOverlayWithFrame:self.frame];
}
-(void)move:(id)sender {
CGPoint translatedPoint = [(UIPanGestureRecognizer*)sender translationInView:self];
if([(UIPanGestureRecognizer*)sender state] == UIGestureRecognizerStateBegan) {
_firstX = [self center].x;
_firstY = [self center].y;
}
translatedPoint = CGPointMake(_firstX+translatedPoint.x, _firstY+translatedPoint.y);
[self setCenter:translatedPoint];
[self showOverlayWithFrame:self.frame];
NSLog(#"after move x= %f y=%f " , _firstX,_firstY);
}

Resources