Move SKSpriteNode with CoreMotion - sprite-kit

I have a SKSpriteNode that represents the user and I'd like this node gets move with the user movement, if the user walks then the node moves in the same direction.
The start position is the center of the view and I think it's possible to make this works with rotationRate, userAcceleration and gravity from CMMotionManager (iOS 7) but I don't know if I'm wrong or what operations I should do with these values.
I appretiate if someone could help me.
Thanks.

Now, I'm do
if ([self.motionManager isDeviceMotionAvailable] == YES) {
[self.motionManager startDeviceMotionUpdatesToQueue:self.queueMotion withHandler:^(CMDeviceMotion *motion, NSError *error) {
self.xpos = motion.userAcceleration.x * motion.gravity.x * motion.rotationRate.x;
self.ypos = motion.userAcceleration.y * motion.gravity.y * motion.rotationRate.y;
[self performSelectorOnMainThread:#selector(updatePosition:) withObject:nil waitUntilDone:YES];
}];
}
Then I add these x and y coordinates to the SKSpriteNode position and I move the SKSpriteNode to this final position. What I am getting is that the SKSpriteNode doesn't get move while I'm walking but if I make a hard acceleration it moves but just a moment, if I'm walking with a constant velocity it doesn't get move.

Related

How to translate SKPhysicsContact contactPoint into my SKSpriteNode position

I've spent too long on this. Someone has solved this already, please help.
Enemy fires on my ship. SKPhysicsContact takes over and I get contactPoint. I explode the fired missile at the contactPoint, in world coordinates. All good. Now I would like to use the point, not in the scene coordinates returned by contactPoint, but in my ship coordinates to start emitting smoke from the ship, where I've been hit. I've used convertPoint function before, with success, but I can't seem to get it right here...Docs say the contactPoint is expressed in Scene coordinates, while myShip has its coordinates, living as a child of a world node, which is a child of the scene node. They are in the same Node hierarchy. I think...I have a Scene->World->Camera, where myShip is a child of World. My code, I think, is saying convert contactPoint from Scene coordinates to coordinates in myShip. But this does not work. Nor does any other combination. What am I missing? I suspect the Camera hierarchy, but unsure. The numbers being returned into smoke.position are way out of whack...
- (SKEmitterNode *) newSmokeEmitter: (SKPhysicsContact *) contact
{
NSString *smokePath = [[NSBundle mainBundle] pathForResource:#"ShipSmoke" ofType:#"sks"];
SKEmitterNode *smoke = [NSKeyedUnarchiver unarchiveObjectWithFile:smokePath];
smoke.targetNode = myShip;
smoke.name = #"shipSmoke";
smoke.position = [self convertPoint:contact.contactPoint toNode:myShip];
//my temporary kludge that places the smoke on the ship, randomly
//smoke.position = CGPointMake(skRand(-25,25), skRand(-25,+25));
NSLog(#"Ship at world pos: %f,%f", myShip.position.x, myShip.position.y);
NSLog(#"Contact at scene pos: %f,%f", contact.contactPoint.x, contact.contactPoint.y);
NSLog(#"Smoke position at ship pos: %f,%f", smoke.position.x, smoke.position.y);
[myShip addChild:smoke];
return smoke;
}
If you haven't solved it already, the answer is to convert from the node's scene:
smoke.position = [self convertPoint:contact.contactPoint fromNode:self.scene];
Or, in Swift:
smoke.position = convertPoint(contact.contactPoint, fromNode: scene)
If I understand your node hierarchy correctly this could fix the issue.
CGPoint contact = [self convertPoint:contact.contactPoint toNode:self.world];
smoke.position = [self.world convertPoint:contact toNode:myShip];
I don't think you can convert the point directly to ship. You have to convert it down the hierarchy until you get to the node you want.
Hopefully that helps.
Edit
To verify that the actual contact point is on the scene where I would expect you could try this.
SKSpriteNode *sprite = [SKSpriteNode spriteNodeWithColor:[SKColor greenColor] size:CGSizeMake(50, 50)];
sprite.position = contact.contactPoint;
[self addChild:sprite];
This should add a sprite exactly where the contact point is if the point returned is in the scene coordinate system. If it it does show up at the right spot than it truly does come down to converting points correctly.

Sprite Kit shooting projectiles at target

I wanted to make my turret Sprite shoot at the monster. i have already got the turret to turn to the monster and follow it until its out of range, now i just need to make the shooting occur.
what is the best way to shoot a projectile from the turret to the monster?
i have already done this part:
-(void)shoot
{
SKSpriteNode *bullet = [SKSpriteNode spriteNodeWithImageNamed:#"CannonMissile-hd.png"]; ... i don't know what to do next
}
also, i need it to shoot at intervals of x seconds,
thanks
-(void)shoot
{
SKSpriteNode *turretNode;//I assume you have this node already in the scene . Dont use this line
SKSpriteNode *enemy;//I assume you have this node already in the scene . Dont use this line
SKSpriteNode *bullet = [SKSpriteNode spriteNodeWithImageNamed:#"CannonMissile-hd.png"];
bullet.zPosition = turretNode.zPosition -1;//if you want your bullet not to spawn on top of your turret
[turretNode addChild:bullet];
//you need to set the physics body of the bullet so you can detect contacts
SKAction *move = [SKAction moveTo:enemy.position duration:0.5];//if u have multiple enemies then you have to deceide which one to hit
[bullet runAction:move completion:^{
[bullet removeFromParent];//removes the bullet when it reaches target
//you can add more code here or in the didBeginContact method
}];
//repeat the process
[self performSelector:#selector(shoot) withObject:nil afterDelay:5];//replace 5 with ur x seconds
//that's it
}

Creating a trail with SKEmitterNode and particles in SpriteKit

I am trying to make it so a particle I made follows the player whenever the player is moved. The effect I am trying to replicate is like when you are on a website and they have some sort of set of objects following your mouse. I tried to do this by making the particle move by the amount the player does, but it is not reproducing the intended effect. Any suggestions? My code:
Declaring particle
NSString *myParticlePath = [[NSBundle mainBundle] pathForResource:#"trail" ofType:#"sks"];
self.trailParticle = [NSKeyedUnarchiver unarchiveObjectWithFile:myParticlePath];
self.trailParticle.position = CGPointMake(0,0);
[self.player addChild:self.trailParticle];
Move method
-(void)dragPlayer: (UIPanGestureRecognizer *)gesture {
if (gesture.state == UIGestureRecognizerStateChanged) {
//Get the (x,y) translation coordinate
CGPoint translation = [gesture translationInView:self.view];
//Move by -y because moving positive is right and down, we want right and up
//so that we can match the user's drag location (SKView rectangle y is opp UIView)
CGPoint newLocation = CGPointMake(self.player.position.x + translation.x, self.player.position.y - translation.y);
CGPoint newLocPart = CGPointMake(self.trailParticle.position.x + translation.x, self.trailParticle.position.y - translation.y);
//Check if location is in bounds of screen
self.player.position = [self checkBounds:newLocation];
self.trailParticle.position = [self checkBounds:newLocPart];
self.trailParticle.particleAction = [SKAction moveByX:translation.x y:-translation.y duration:0];
//Reset the translation point to the origin so that translation does not accumulate
[gesture setTranslation:CGPointZero inView:self.view];
}
}
Try this:
1) If your emitter is in the Scene, use this emitter's property targetNode and set is as Scene. That means that particles will not be a child of emitter but your scene which should leave a trail..
Not sure if this is correct (I do it in C#):
self.trailParticle.targetNode = self; // self as Scene
And some extra:
2) I think you could rather attach your emitter to self.player as child so it would move together and automatically with your player and then there is no need of this:
self.trailParticle.position = [self checkBounds:newLocPart];
self.trailParticle.particleAction = [SKAction moveByX:translation.x y:-translation.y duration:0];
In your update loop Check if your player is moving along the X axis.
Then create a sprite node each time this is happening. In this example name your player "player1"
The key here is your particle must have a max set in the particles column near birthrate.
The blow code works for me.
-(void)update:(CFTimeInterval)currentTime {
// Find your player
SKNode* Mynode = (SKSpriteNode *)[self childNodeWithName:#"player1"];
// Check if our player is moving. Lower the number if you are not getting a trail.
if (Mynode.physicsBody.velocity.dx>10|
Mynode.physicsBody.velocity.dy>10|
Mynode.physicsBody.velocity.dx<-10|
Mynode.physicsBody.velocity.dy<-10){
// Unpack your particle
NSString *myParticlePath = [[NSBundle mainBundle] pathForResource:#"trail" ofType:#"sks"];
//Create your emitter
SKEmitterNode *myTrail = [NSKeyedUnarchiver unarchiveObjectWithFile:myParticlePath];
// This ensures your trail doesn't stay forever . Adjust this number for different effects
myTrail.numParticlesToEmit=10;
// The length of your trail - higher number, longer trail.
myTrail.particleLifetime = 2.0;
//Set the trail position to the player position
myTrail.position=Mynode.position;
//Add the trail to the scene
[self addChild:myTrail];
}
}

Collision of Sprites in CCSpriteBatchNode and CCParallaxNode

I have two sprites one is added as the child of CCSpriteBatchNode and the other as the child of CCParallaxNode. Is there any method to detect their collision? I have used the following code.
-(void)CheckCollition:(CCSprite *)Opp_Obs Opponent:(CCSprite *) H_man
{
// NSLog(#"inside check collision");
CGRect b_rect=[Opp_Obs boundingBox];
CGPoint p_position=[H_man position];
if (CGRectContainsPoint(b_rect,p_position))
{
NSLog(#"collision with opponent");
// Zoom Animation with Points
CCScaleBy *zzomscal=[CCScaleTo actionWithDuration:.2 scale:.12];
CCRotateTo * rotLeft = [CCRotateBy actionWithDuration:0.2 angle:360];
CCCallFunc *ccfun=[CCCallFunc actionWithTarget:self selector:#selector(zoomComplete)];
CCSequence * zzomseq = [CCSequence actions:zzomscal,rotLeft,ccfun, nil];
[H_man runAction:zzomseq];
}
else
{
NSLog(#"no collision");
}
}
But here the control never enters into the loop. Is there any other solution? Anyone please help me.
Set a breakpoint and compare the values of rect and position. One of them may be zero, or way off.
In the latter case you may need to convert the bbox origin and position to world coordinates first in order to compare them. This is the case when the sprites' parents are moving too (parent position != 0,0).

Destroying Sprites in and around the Collided Sprite

I need help in destroying the sprites which are in and around the collided sprites ie in a radius of 2.5 cms all sprites should be destroyed. Idea here is i will be shooting a projectile from bottom to the objects falling from the top. Once collision happens all the sprites around that radius also should be destroyed. Like a Bomb Effect. I have used box2d for collision ie contact listener. How to go about doing that?
Please Suggest:-)
Regards,
Karthik
Hold an array of your sprites, or if you are using a batchNode you can do that.
When the collision happens, go through your sprites. Check the distance with their position and the explosion center and kill them if they are in range.
e.g.
CCSprite *sprite;
for (sprite in [batchNode descendants]) {
if ([sprite isInRangeOf:[explosionSprite position]]) {
[sprite yourRemovalMethod];
}
}
the method 'isInRangeOf:' would be within your sprite subclass
Something like..
-(BOOL) isInRangeOf:(CGPoint)explosionCenter {
//Use pythagoras theorem to work out the distance between [sprite position] and [explosionCenter]
CGFloat dx = explosionCenter.x - [self position].x;
CGFloat dy = explosionCenter.y - [self position].y;
float distance = sqrt(dx*dx + dy*dy );
// If your distance is less than or equal to your 'death radius' return YES, else No.
if (distance <= 25) {
return TRUE;
} else {
return FALSE;
}
}
Hope that helps.