Speed of touch varies with number of objects on Scene - ios

I am creating game in which user can hit the object falling from the top of the screen with the racket. user can continuously move the racket but if it is at minimal speed or is at rest it should not hit the object, but if it above the minimal speed user should hit them. I have achieved that but the issue is when user start touching the racket which continously move with the user touch, the speed varition is their it does not start with the same speed and while touch is moving at that time also some times speed is very less even though the movement is fast. Here is my piece of code
-(void)didMoveToView:(SKView *)view {
self.physicsWorld.contactDelegate = (id)self;
racketNode = [SKSpriteNode spriteNodeWithImageNamed:#"racket"];
racketNode.size = CGSizeMake(50,50);
racketNode.position = CGPointMake(self.frame.origin.x + self.frame.size.width - 50,50);
racketNode.name = #"racket";
[self addChild:racketNode];
}
-(void) didBeginContact:(SKPhysicsContact *)contact {
SKSpriteNode *nodeA = (SKSpriteNode *)contact.bodyA.node ;
SKSpriteNode *nodeB = (SKSpriteNode *) contact.bodyB.node;
if (([nodeA.name isEqualToString:#"racket"] && [nodeB.name isEqualToString:#"fallingObject"])) {
if (racketNode.speed > kMinSpeed)
[nodeB removeFromParent];
else {
nodeB.physicsBody.contactTestBitMask = 0;
[self performSelector:#selector(providingCollsion:) withObject:nodeB afterDelay:0.1];
}
}
}
-(void) providingCollsion:(SKSpriteNode *) node {
node.physicsBody.contactTestBitMask = racketHit;
}
-(void) touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
for (UITouch *touch in touches) {
CGPoint location = [touch locationInNode:self];
start = location;
startTime = touch.timestamp;
racketNode.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:racketNode.frame.size];
racketNode.physicsBody.categoryBitMask = racket;
racketNode.physicsBody.contactTestBitMask = HitIt;
racketNode.physicsBody.dynamic = NO;
racketNode.physicsBody.affectedByGravity = NO;
[racketNode runAction:[SKAction moveTo:location duration:0.01]];
}
}
- (void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
racketNode.physicsBody = nil;
racketNode.speed = 0;
}
-(void) touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
CGPoint location = [touch locationInNode:self];
CGFloat dx = location.x - start.x;
CGFloat dy = location.y - start.y;
CGFloat magnitude = sqrt(dx*dx+dy*dy);
// Determine time difference from start of the gesture
CGFloat dt = touch.timestamp - startTime;
// Determine gesture speed in points/sec
CGFloat speed = magnitude/dt;
racketNode.speed = speed;
[handNode runAction:[SKAction moveTo:[touch locationInNode:self] duration:0.01]];
}
Please tell me which part my code is wrong so as to make same object collide with high speed only not on slow speed and also no collision on stable state.

Instead of doing it manually, use UIPanGestureRecognizer to handle your swipes. With it, there is a velocity property that you can use to check if the speed is greater than a given value.
Here is a great tutorial to do it:
https://www.raywenderlich.com/76020/using-uigesturerecognizer-with-swift-tutorial

Related

How to make character accelerate while pressing arrow key (iOS)

I'm trying to make a game through sprite kit framework, but I'm stuck while trying to make a character move. I want to make the character move (left/right) when I press the key(left/right). While pressing, the character should be speeding up (w/ speed limit), and when I let go of the key, the character should be slowing down to a complete stop. I can't figure out a way to implement this through SKAction... Can anyone shed me some light? Thanks.
This is what I've tried so far.
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
/* Called when a touch begins */
UITouch *touch = [touches anyObject];
CGPoint touchLocation = [touch locationInNode:self];
if (touchLocation.x > [[UIScreen mainScreen]applicationFrame].size.width / 2) {
_rightPressed = YES;
} else {
_leftPressed = YES;
}
}
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
_rightPressed = NO;
_leftPressed = NO;
_speedDelimiter = 0;
}
-(void)update:(CFTimeInterval)currentTime {
// ... code ...
if (_rightPressed && !_leftPressed && _speedDelimiter < 10) {
SKAction * moveRight = [SKAction moveBy:CGVectorMake(10, 0) duration:5];
[self.player runAction:moveRight];
_speedDelimiter++;
} else if (_leftPressed && !_rightPressed && _speedDelimiter < 10){
SKAction * moveLeft = [SKAction moveBy:CGVectorMake(-10, 0) duration:5];
[self.player runAction:moveLeft];
_speedDelimiter++;
}
}
What I think I should make use of is the velocity property in my character's SKPhysicsBody property. But I'm not sure.

Drag SKSpriteNode based on touch location

I am trying to drag a sprite in the y axis but make the sprite "stick" to the users finger depending on where the touches began on the node.
The sprite is currently dragging but it seems to be snapping the anchorpoint of the sprite to the touch location within the node.
Im assuming it has something to do with getting the location within the node by doing [touch locationInNode:selectedNode]; but I am unsure where to go from there.
Here is my current code.
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
for (UITouch *touch in touches) {
CGPoint location = [touch locationInNode:self];
SKNode *node = [self nodeAtPoint:location];
CGPoint newPosition = CGPointMake(node.position.x, location.y);
if ([node.name isEqualToString:self.selectedNode] ) {
if (newPosition.y > 230) {
newPosition.y = 230;
}
node.position = newPosition;
}
}
}
You need to offset the newPosition based on the current touch position on the node.
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
for (UITouch *touch in touches)
{
CGPoint location = [touch locationInNode:self];
SKNode *node = [self nodeAtPoint:location];
if ([node.name isEqualToString:self.selectedNode] )
{
CGPoint previousLocation = [touch previousLocationInNode:self];
float diff = location.y - previousLocation.y;
CGPoint newPosition = CGPointMake(node.position.x, node.position.y + diff);
if (newPosition.y > 230) {
newPosition.y = 230;
}
node.position = newPosition;
}
}
}
There are a couple of ways of doing this. The sample code below tracks the user's touch location and moves the sprite towards that position during the update method. You can modify the code to only move on the y axis or x axis.
#implementation MyScene
{
SKSpriteNode *object1;
CGPoint destinationLocation;
}
-(id)initWithSize:(CGSize)size
{
if (self = [super initWithSize:size])
{
[self createObject];
destinationLocation = CGPointMake(300, 150);
}
return self;
}
-(void)createObject
{
object1 = [SKSpriteNode spriteNodeWithColor:[SKColor redColor] size:CGSizeMake(50, 50)];
object1.position = CGPointMake(300, 150);
[self addChild:object1];
}
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
destinationLocation = [touch locationInNode:self.scene];
}
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
destinationLocation = [touch locationInNode:self.scene];
}
-(void)update:(CFTimeInterval)currentTime
{
float x = fabs(object1.position.x - destinationLocation.x);
float y = fabs(object1.position.y - destinationLocation.y);
float divider = 0;
if(x > y)
{
divider = x;
} else
{
divider = y;
}
float xMove = (x/divider)*8; // change number to increase or decrease speed
float yMove = (y/divider)*8; // change number to increase or decrease speed
if(object1.position.x > destinationLocation.x)
object1.position = CGPointMake(object1.position.x-xMove, object1.position.y);
if(object1.position.x < destinationLocation.x)
object1.position = CGPointMake(object1.position.x+xMove, object1.position.y);
if(object1.position.y > destinationLocation.y)
object1.position = CGPointMake(object1.position.x, object1.position.y-yMove);
if(object1.position.y < destinationLocation.y)
object1.position = CGPointMake(object1.position.x, object1.position.y+yMove);
}
#end

how can I fix this turret so that it moves smoothly

Okay guys I have managed to make a sprite kit game where I have a turret that shoots candies but the problem I have is that the turret doesn't move smoothly as I point a location with my finger. It just jumps to point to the location.
so here is my code below:
- (void) rotateSprite:(SKSpriteNode *)sprite toFace:(CGPoint)velocity rotateRadiansPerSec:(CGFloat)rotateRadiansPerSec {
float targetAngle = CGPointToAngle(velocity);
float shortest = ScalarShortestAngleBetween(sprite.zRotation, targetAngle);
float amtToRotate = rotateRadiansPerSec * _dt;
if (ABS(shortest) < amtToRotate) {
amtToRotate = ABS(shortest);
}
sprite.zRotation += ScalarSign(shortest) * amtToRotate;
}
- (void) movePlayerToward:(CGPoint)location {
_lastTouchLocation = location;
CGPoint offset = CGPointSubtract(location, _Player.position);
CGPoint direction = CGPointNormalize(offset);
_velocity = CGPointMultiplyScalar(direction, PLAYER_MOVE_POINTS_PER_SEC);
}
- (void) update:(NSTimeInterval)currentTime {
if (_lastUpdateTime) {
_dt = currentTime - _lastUpdateTime;
}
else {
_dt = 0;
}
_lastUpdateTime = currentTime;
CGPoint offset = CGPointSubtract(_lastTouchLocation, _Player.position);
float distance = CGPointLength(offset);
if (distance < PLAYER_MOVE_POINTS_PER_SEC * _dt) {
_velocity = CGPointZero;
}
else
{
[self rotateSprite:_Player toFace:_velocity rotateRadiansPerSec:PLAYER_ROTATE_RADIANS_PER_SEC];
}
}
- (void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
CGPoint touchLocation = [touch locationInNode:self.scene];
[self movePlayerToward:touchLocation];
}
- (void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
CGPoint touchLocation = [touch locationInNode:self.scene];
[self movePlayerToward:touchLocation];
}
I assume you are using the Zombie Conga code which uses static const to set fixed movement and rotation speed values.
In your code you have the line float amtToRotate = rotateRadiansPerSec * _dt;
Make sure you have the rotateRadiansPerSec value set properly as this controls the speed of your rotation.
In the Conga code, the value was:
static const float ZOMBIE_ROTATE_RADIANS_PER_SEC = 4 * M_PI;

touchesMoved on a specific moving object

Im using Spritekit to create a game for iOS 7. The game has circles moving across the screen using this code
_enemy = [SKSpriteNode spriteNodeWithImageNamed:#"greeny"];
_enemy.position = CGPointMake(CGRectGetMidX(self.frame)+300,
CGRectGetMidY(self.frame));
_enemy.size = CGSizeMake(70, 70);
_enemy.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:35];
_enemy.physicsBody.mass = 0;
_enemy.physicsBody.categoryBitMask = Collisiongreen;
[_enemies addObject:_enemy];
NSLog(#"Enemies%lu",(unsigned long)_enemies.count);
[self addChild:_enemy];
[_enemy runAction:[SKAction moveByX:-900 y:0 duration:4]];
[self runAction:[SKAction playSoundFileNamed:#"Spawn.wav" waitForCompletion:NO]];
[self runAction:[SKAction sequence:#[
[SKAction waitForDuration:1.4],
[SKAction performSelector:#selector(move)
onTarget:self],
]]];
I would like to have it that when the user touches one of the objects moving across the screen that they can move it with their finger either up or down (thats why I'm using touches moved)
The code i have set up right now is
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
if(_dead)
return;
UITouch *touch = [touches anyObject];
CGPoint location = [touch locationInNode:self];
if(CGRectContainsPoint(_enemy.frame, location)){
[_enemy runAction:[SKAction moveTo:[[touches anyObject] locationInNode:self] duration:0.01]];
}
My problem is that if i touch it the object will move a few pixels but will stop right after. How can I get it to move with my finger and if i let go it will continue moving left like programed before? Thanks!!
So the trick here is that in the touchesMoved method, you want the enemy's postion set to the location of your touch. Use the touchesEnded method to execute a method that makes the enemy continue in the direction of your last touch. This is a rough non-tested example.
You need to store the difference of the current location with the previous location.
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
if(_dead)
return;
UITouch *touch = [touches anyObject];
CGPoint location = [touch locationInNode:self];
if(CGRectContainsPoint(_enemy.frame, location)){
someBool = False;
[_enemy setPosition:location];
changeInX = location.x - lastX;
changeInY = location.y - lastY;
lastX = location.x;
lastY = location.y;
}
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
someBool = True;
}
- (void)update:(NSTimeInterval)currentTime
{
...
if (someBool) {
enemy.position = CGPointMake((enemy.position.x + changeInX), (enemy.position.y + changeInY));
}
...
}

Passing iOS sprites from one class to another

I have a Spritekit project in xcode on my main screen. However I would really like to manage it from another class so as to not cluster my main. So I added a new class to manage and handle it. Sadly I can't seem to get it to show in my main (or I might be doing it wrong). My myscene.m consists of pretty much the same code including the spaceship and this is where I moved the code too ( I didn't bother adding the methods like touchesBegan)
// joysitck.m
// controlpad
//
#import "joysitck.h"
#implementation joysitck
{
BOOL controlButtonOn;
}
float controlx=200;
float controly=200;
float touchX = 0.0;
float touchY=0.0;
- (instancetype)init
{
if (self = [super init]) {
self.name = #"controlPadNode";
SKSpriteNode *controlPadNode = [SKSpriteNode spriteNodeWithImageNamed:#"game-controller-frontb"];
controlPadNode.position = CGPointMake(controlx,controly);
[controlPadNode setScale:0.5];
controlPadNode.name = #"controlPadNode";
controlPadNode.zPosition = 1.0;
[self addChild:controlPadNode];
}
return self;
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
CGPoint location = [touch locationInNode:self];
SKNode *node = [self nodeAtPoint:location];
//if control pad touched
if ([node.name isEqualToString:#"controlPadNode"]) {
touchX = location.x;
touchY = location.y;
controlButtonOn= true;
}
}
//when touch moves
- (void) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
CGPoint location = [touch locationInNode:self];
SKNode *node = [self nodeAtPoint:location];
//if control pad touched
if ([node.name isEqualToString:#"controlPadNode"]) {
touchX = location.x;
touchY = location.y;
controlButtonOn= true;
}
}
- (void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
CGPoint location = [touch locationInNode:self];
SKNode *node = [self nodeAtPoint:location];
//if control pad touched
if ([node.name isEqualToString:#"controlPadNode"]) {
controlButtonOn= false;
}
}
//update method
-(void)update:(NSTimeInterval)currentTime {
if (controlButtonOn) {
//the control pad
SKNode *controlNode = [self childNodeWithName:#"controlPadNode"];
SKNode *node = [self childNodeWithName:#"spaceShipNode"];
float angle = atan2f (touchY - controly, touchX - controlx) ;
SKAction *moveShip=[SKAction moveByX:6*cosf(angle) y:0 duration:0.005];
[node runAction: moveShip];
}
}
#end
You haven't added joystick node to the scene.
Add this code to MyScene's initWithSize method (before [self addship]):
joysitck *joysitckNode = [[joysitck alloc] init];
[self addChild:joysitckNode];

Resources