Sprite Kit physics causes too much shaking - ios

In my app, once the gamepieces are stacked to a certain height, the screen starts to move down to allow more room for building. The problem is that everytime the screen moves down, the gamepieces shake so much that they topple over.
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
for (UITouch *touch in touches) {
CGPoint location = [touch locationInNode:self];
SKSpriteNode *gamePiece = [self pickObject];
gamePiece.position = location;
gamePiece.physicsBody.dynamic = NO;
[self addChild:gamePiece];
_currentTouch = touch;
currentGamePiece = gamePiece;
CGPoint touchLocation = [touch locationInNode:self.scene];
if(touchLocation.y > 350)
{
_bg.position = CGPointMake(_bg.position.x, _bg.position.y-2);
}
}
}
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
/* Called when a touch begins */
for (UITouch *touch in touches) {
CGPoint location = [touch locationInNode:self];
if ([touch isEqual:_currentTouch])
{
currentGamePiece.position = location;
}
CGPoint touchLocation = [touch locationInNode:self.scene];
if(touchLocation.y > 350)
{
_bg.position = CGPointMake(_bg.position.x, _bg.position.y-2);
}
}
}
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
/* Called when a touch begins */
for (UITouch *touch in touches)
{
CGPoint location = [touch locationInNode:self];
if ([touch isEqual:_currentTouch])
{
currentGamePiece.position = location;
currentGamePiece.physicsBody.dynamic = YES;
}
}
}

Related

How can I make UITouches offset?

In the image below, I draw and the result is at point A, right where my finger touches.
How can I make the image appear about 40pt above my actual touch. (B)
I'm using the classic coreGraphic UITouch code, like so:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
// add the first touch
UITouch *touch = [touches anyObject];
previousPoint1 = [touch previousLocationInView:self];
currentPoint = [touch locationInView:self];
//transform = CGAffineTransformTranslate(self.transform, 5.0, 10.0)
// init the bezier path
self.currentTool = [self toolWithCurrentSettings];
self.currentTool.lineWidth = self.lineWidth;
self.currentTool.lineColor = self.lineColor;
self.currentTool.lineAlpha = self.lineAlpha;
[self.pathArray addObject:self.currentTool];
[self.undoStates addObject:[self.currentTool captureToolState]];
[self.currentTool setInitialPoint:currentPoint];
}
// call the delegate
if ([self.delegate respondsToSelector:#selector(drawingView:willBeginDrawUsingTool:)]) {
[self.delegate drawingView:self willBeginDrawUsingTool:self.currentTool];
}
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
// save all the touches in the path
UITouch *touch = [touches anyObject];
previousPoint2 = previousPoint1;
previousPoint1 = [touch previousLocationInView:self];
currentPoint = [touch locationInView:self];
[self.currentTool moveFromPoint:previousPoint1 toPoint:currentPoint];
[self setNeedsDisplay];
}
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
// make sure a point is recorded
[self touchesMoved:touches withEvent:event];
CGPoint point = [[touches anyObject] locationInView:self];
[self.currentTool setInitialPoint:point];
self.draggableTextView = ((ACEDrawingDraggableTextTool *)self.currentTool).labelView;
[self.pathArray addObject:self.currentTool];
[self finishDrawing];
[self finishDrawing];
}
}
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
{
// make sure a point is recorded
[self touchesEnded:touches withEvent:event];
}
previousPoint1 = [touch previousLocationInView:self];
currentPoint = [touch locationInView:self];
// add these 2 lines below:
previousPoint1 = CGPointMake(previousPoint1.x, previousPoint1.y+40);
currentPoint = CGPointMake(currentPoint.x, currentPoint.y+40);

Sprite Kit game not detecting two simultaneous touches

I am developing a Sprite Kit game and need to react to touches on either the left or right side of the screen. I found this solution in another question:
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
CGPoint touchLocation = [touch locationInNode:self];
if (touchLocation.x < self.size.width / 2.0f) {
touching = YES;
}
if (touchLocation.x > self.size.width / 2.0f) {
[self drawRocket];
}
And,
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{
UITouch *touch = [touches anyObject];
CGPoint touchLocation = [touch locationInNode:self];
if (touchLocation.x < self.size.width / 2.0f) {
touching = NO;
}
if (touchLocation.x > self.size.width / 2.0f) {
//do nothing
}
}
And I thought, brilliant. It works. Well, it seemed to, until I happened to touch both sides at the same time with separate fingers. It calls drawRocket but does not change the value of touching to YES. This problem has happened repeatedly and is replicable.
What to do?
EDIT:
I have tried:
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
for (UITouch *touch in touches) {
UITouch *touch = [touches anyObject];
CGPoint touchLocation = [touch locationInNode:self];
if (touchLocation.x < self.size.width / 2.0f) {
touching = YES;
}
if (touchLocation.x > self.size.width / 2.0f) {
if (![rocketFlame parent]) {
[self fireRocket];
}
}
}
}
and,
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
CGPoint touchLocation = [touch locationInNode:self];
for (UITouch *touch in touches) {
if (touchLocation.x < self.size.width / 2.0f) {
touching = YES;
}
if (touchLocation.x > self.size.width / 2.0f) {
if (![rocketFlame parent]) {
[self fireRocket];
}
}
}
}
And I am still having the same problem.
You are defining a local variable that hides the variable used to loop over the touch events. See the comment in the code below.
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
for (UITouch *touch in touches) {
// The following statement is causing the issue. Delete it.
//UITouch *touch = [touches anyObject];
CGPoint touchLocation = [touch locationInNode:self];
if (touchLocation.x < self.size.width / 2.0f) {
touching = YES;
}
if (touchLocation.x > self.size.width / 2.0f) {
if (![rocketFlame parent]) {
[self fireRocket];
}
}
}
}
add the following line in the initilization method
self.view.multipleTouchEnabled = YES;
for (UITouch *touch in touches) {
CGPoint touchLocation = [touch locationInNode:self];
if (touchLocation.x < self.size.width / 2.0f) {
touching = YES;
}
if (touchLocation.x > self.size.width / 2.0f) {
[self drawRocket];
}
}
Simulator Multi-Touch gestures using a mouse and keyboard

Changing sprite nodes parent after TouchesEnded

I'm attempting to change the parent node of a sprite after it is dropped, but I'm getting a nil error.
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
for (UITouch *touch in touches) {
CGPoint location = [touch locationInNode:self];
SKSpriteNode *gamePiece = [self pickObject];
gamePiece.position = location;
gamePiece.physicsBody.dynamic = NO;
[self addChild:gamePiece];
_currentTouch = touch;
currentGamePiece = gamePiece;
CGPoint touchLocation = [touch locationInNode:self.scene];
if(touchLocation.y > 350)
{
_bg.position = CGPointMake(_bg.position.x, _bg.position.y-2);
}
}
}
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
/* Called when a touch begins */
for (UITouch *touch in touches) {
CGPoint location = [touch locationInNode:self];
if ([touch isEqual:_currentTouch])
{
currentGamePiece.position = location;
}
CGPoint touchLocation = [touch locationInNode:self.scene];
if(touchLocation.y > 350)
{
_bg.position = CGPointMake(_bg.position.x, _bg.position.y-2);
}
}
}
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
/* Called when a touch begins */
for (UITouch *touch in touches)
{
CGPoint location = [touch locationInNode:self];
if ([touch isEqual:_currentTouch])
{
currentGamePiece.position = location;
currentGamePiece.physicsBody.dynamic = YES;
SKAction *removeNode = [SKAction removeFromParent];
[gamePiece runAction: removeNode];
[_bg addChild:gamePiece];
}
}
}
Maybe it has something to do with the switch to "currentGamePiece", but when I try to remove "currentGamePiece" from its parent, I get an error like "attempting to add node that already has a parent". I may just not be going about it the right way. What's the problem?
Try replacing this code...
SKAction *removeNode = [SKAction removeFromParent];
[gamePiece runAction: removeNode];
[_bg addChild:gamePiece];
with this...
[gamePiece removeFromParent];
[_bg addChild:gamePiece];
The issue is gamePiece is added to the _gb before the SKAction has a chance to remove it from its parent. The app crashes because a node can't have two parents.

move Sprite with touches moved

i am moving a sprite using the touches moved method. currently the sprite jumps to the point on which the screen is touched but I want the sprite only to move when it is touched directly.
my code:
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
for (UITouch *touch in touches) {
CGPoint location = [touch locationInNode:self];
CGPoint newPosition = CGPointMake(location.x, self.size.height/2);
self.sprite.position = newPosition;
}
}
check if the touch location is inside the sprite, like this:
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
CGPoint positionInScene = [touch locationInNode:self];
if(CGRectContainsPoint(self.sprite.boundingBox,positionInScene)) {
CGPoint newPosition = CGPointMake(positionInScene.x, self.size.height/2);
self.sprite.position = newPosition;
}
}

How will I hold and drag the image while it is moving?

Here is my code in moving the image randomly and for the touch code.
-(void)viewDidAppear:(BOOL)animated {
timer = [NSTimer scheduledTimerWithTimeInterval:5 target:self selector:#selector(randomizeXandY) userInfo:nil repeats:YES];
}
-(void)randomizeXandY {
CGFloat x = (CGFloat) (arc4random() % (int) self.view.bounds.size.width);
CGFloat y = (CGFloat) (arc4random() % (int) self.view.bounds.size.height);
[self moveObjectsAtX:x Y:y];
}
-(void)moveObjectsAtX:(CGFloat)x Y:(CGFloat)y {
[UIView animateWithDuration:5 animations:^{
imgView.center = CGPointMake(x, y);
}];
}
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [[event allTouches]anyObject];
CGPoint touchLocation = [touch locationInView:self.view];
if ([touch view] == imgView) {
imgView.center = touchLocation;
}
}
Try the code in touchesBegin and touchesEnded
-(void)touchesBegin:(NSSet *)touches withEvent:(UIEvent *)event {
// stop timers here
}
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
// start timers here again
}
I would rather suggest to use UIPanGestureRecognizer. In it's handling method you can check possible states of the touch.
-(void)handlePan:(UIPanGestureRecognizer *)recognizer {
switch (recognizer.state) {
case UIGestureRecognizerStateBegan: {
CGPoint touchLocation = [recognizer locationInView:self.view];
...
break;
}
case UIGestureRecognizerStateChanged:
...
break;
case UIGestureRecognizerStateEnded:
...
break;
default:
break;
}
You have to use these methods:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [[event allTouches] anyObject];
CGPoint touchLocation = [touch locationInView:self.view];
//...
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [[event allTouches] anyObject];
CGPoint touchLocation = [touch locationInView:self.view];
//..
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [[event allTouches] anyObject];
CGPoint touchLocation = [touch locationInView:self.view];
//...
}
in touchesBegan method, check if the touch is on your image:
if (CGRectContainsPoint(yourImage.frame, touchLocation)){
dragging = YES;
}
if it yes set a global variable, for example bool dragging to YES.
in touchesMoved:
check
if (dragging){
yourImage.frame = CGRectMake(touchLocation.x, touchLocation.y,yourImage.frame.size.widht,yourImage.frame.size.height);
}
in touchesEnded:
set dragging to NO
dragging = NO;
So :
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [[event allTouches] anyObject];
CGPoint touchLocation = [touch locationInView:self.view];
if (CGRectContainsPoint(yourImage.frame, touchLocation)){
dragging = YES;
[timer invalidate];
timer = nil;
}
//...
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [[event allTouches] anyObject];
CGPoint touchLocation = [touch locationInView:self.view];
if (dragging){
yourImage.frame = CGRectMake(touchLocation.x, touchLocation.y,yourImage.frame.size.widht,yourImage.frame.size.height);
}
//..
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [[event allTouches] anyObject];
CGPoint touchLocation = [touch locationInView:self.view];
dragging = NO;
//...
}

Resources