I have a standard cocos2d startup layer( HelloWorldLayer). I created another class of type CCNode named "Terrain" for my terrain. Then i add it to my layer in the layer's init:
terrain = [[Terrain alloc] initWithWorld:world AndLevel:0];
[self addChild:terrain z:1];
i add a 'CarObject' class (a CCSprite class), and add a car object to my terrain
car = [[CarObject alloc] initWithWorld:world];
[terrain addChild:car];
-i.e. in both the initWithWorld for terrain and car, i initialize some Box2d code
I then try to center my car object to my screen when i move it, i do this in my update method:
float offsetX = car.position.x;
float offsetY = car.position.y;
[terrain setOffsetX:(int)offsetX andOffsetY:(int)offsetY];
where the setOffsetX.. method is:
- (void) setOffsetX:(int)newOffsetX andOffsetY:(int)newOffsetY {
_offsetX = newOffsetX;
_offsetY = newOffsetY;
CGSize winSize = [CCDirector sharedDirector].winSize;
self.position = CGPointMake(-(_offsetX - winSize.width/2), -(_offsetY - winSize.height/2));
}
When i use a NSLog to see if the terrain position changes, i can see that the position actually chages, but the view does not. What am i doing wrong? am sure it's a dumb mistake!
btw, if i try this in my HelloWorldLayer's update method (instead of [terrain setOffsetX..])
self.position = CGPointMake(self.position.x-1, self.position.y);
the terrain is moving.
Car is a child of Terrain. Car's position is therefore relative to Terrain's position. Since you base Terrain's position on Car's position, which is actually relative to Terrain's position, you may be simply running into the effect that your position updates simply cancel each other out.
If you want to move the Terrain while keeping the Car centered, you shouldn't add the Car as a child of Terrain. Instead add it to the same node as the Terrain (HelloWorldLayer). Then you can move the Car and Terrain independently of each other.
Related
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.
I am trying to move an SKSpriteNode with physics by setting it's velocity. I am doing this on top of another SKNode (the map) that is part of the SKScene. Positions of "cities" are stored in custom Location objects.
I know the location of the initial SKSpriteNode (the ship) and I know the desired location. From what I've read, I can move the sprite by setting it's velocity. I do so like this:
float dy = _player.desiredLocation.yCoordinate - _mapNode.pin.position.y;
float dx = _player.desiredLocation.xCoordinate - _mapNode.pin.position.x;
_mapNode.pin.physicsBody.velocity = CGVectorMake(dx, dy);
This is all inside the didSimulatePhysics function inside the SKScene. Once the user taps a Location, I find the position and set the velocity. This seems to work well the FIRST time, but the sprite moves all over the place in subsequent times. Any idea what could be going wrong here?
PS: Setting skView.showsPhysics = YES; puts the circle of the physics body way off the position of the sprite.
In the map node:
self.pin = [SKSpriteNode spriteNodeWithImageNamed:[IPGameManager sharedGameData].world.player.ship.type];
self.pin.userInteractionEnabled = NO;
self.pin.position = CGPointMake([IPGameManager sharedGameData].world.player.location.xCoordinate, [IPGameManager sharedGameData].world.player.location.yCoordinate);
self.pin.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:10.0];
self.pin.physicsBody.dynamic = YES;
self.pin.physicsBody.allowsRotation = NO;
self.pin.physicsBody.friction = 0.0;
self.pin.physicsBody.linearDamping = 0.0;
[self addChild:self.pin];
I've been looking around for a while, and I have not been able to find an answer to this for some reason. It seems simple enough, but maybe I just can't find the right function in the library.
I have a scene with a layer that contains a bunch of CCNodes with each one CCSprite in them.
During the application, I move around the position of the main layer, so that I "pan" around a camera in a way. (i.e. I translate the entire layer so that the viewport changes).
Now I want to determine the absolute position of a CCNode in screen coordinates. The position property return the position relative to the parent node, but I really would like this transformed to its actual position on screen.
Also, as an added bonus, it would be awesome if I could express this position as coordinate system where 0,0 maps to the upper left of the screen, and 1,1 maps to the lower right of the screen. (So I stay compatible with all devices)
Edit: Note that the solution should work for any hierarchy of CCNodes preferably.
Every CCNode, and descendants thereof, has a method named convertToWorldSpace:(CGPoint)p
This returns the coordinates relative to your scene.
When you have this coordinate, flip your Y-axis, as you want 0,0 to be in the top left.
CCNode * myNode = [[CCNode alloc] init];
myNode.position = CGPointMake(150.0f, 100.0f);
CCSprite * mySprite = [[CCSprite alloc] init]; // CCSprite is a descendant of CCNode
[myNode addChild: mySprite];
mySprite.position = CGPointMake(-50.0f, 50.0f);
// we now have a node with a sprite in in. On this sprite (well, maybe
// it you should attack the node to a scene) you can call convertToWorldSpace:
CGPoint worldCoord = [mySprite convertToWorldSpace: mySprite.position];
// to convert it to Y0 = top we should take the Y of the screen, and subtract the worldCoord Y
worldCoord = CGPointMake(worldCoord.x, ((CGSize)[[CCDirector sharedDirector] displaySizeInPixels]).height - worldCoord.y);
// This is dry coded so may contain an error here or there.
// Let me know if this doesn't work.
[mySprite release];
[myNode release];
Help me out with some sample code for getting the position of a sprite in Box2d in iPhone.
To get the position of a sprite from a box2d bodyDef you would first want to save your sprite in the userData property of the bodyDef.
For example, in a factory method that creates a ball within the physics environment:
//create the body
b2BodyDef initBodyDef;
initBodyDef.type = b2_dynamicBody;
initBodyDef.position.Set(p.x/PTM_RATIO, p.y/PTM_RATIO);
//Save the sprite in the userData property of the bodyDef, to access later
initBodyDef.userData = ballSprite;
b2Body *body = world->CreateBody(&initBodyDef);
//Rest of the factory method ............ (i.e. create shape, create fixture)
Then when you want to access the position of the sprite, for example when doing collision detection, you would get the pointer to the sprite within the userData property of the bodyDef:
This would be in the tick method (where collision detection takes place), or whereever you need to get the position of the sprite.
CCSprite *mySprite = (CCSprite *) bodyDef->GetUserData();
CGPoint spritePosition = mySprite.position;
In the first line of code above we create a sprite object and call the GetUserData method on our bodyDef, which returns the sprite we saved earlier. Note we have to cast the returned userData or it will return an error. Once we have the sprite saved all we have to do is call the position property on our mySprite pointer. Thats it.
I got 2 sprites, ball and arrow.
the arrow is not moving.
the ball is rotating on it's anchor point.
id rotate = [CCRotateBy actionWithDuration:.5 angle: 360];
I want to detect collision when the ball reaches to arrow.
Tried CGRectIntersectsRect but it does not detect collision.
Any help?
Thanks...
You probably don't want this answer, but I would use Box2D or Chipmunk and use the Vertex Helper application to specify vertices.
use circle-circle collision method.. here is the method..
-(float)asbs:(CGPoint)_arrowPos ballPos:(CGPoint)_ballPos
{
float x = _arrowPos.x-_ballPos.x;
float y = _arrowPos.y-_ballPos.y;
float xy = x*x+y*y;
return xy;
}
if([self asbs:arrow.position ballPos:ball.position]<=size)
{
//collision
}
note that size = ball radius + arrow radius * ball radius + arrow radius
the method above is using a(square) + b(square) = c(square) to check distance between two points..
You might need to convert the ball to world space in an update method then call that rather than the balls position. If it is in a parent layer is position will always be static in respect to its parent.