How to create egg shape physics body with CGPathRef? - ios

I have to create a CGPathRef to simulate the physic property in Sprite Kit.
I am trying to create an egg shape path by an half of circle plus half of oval.
the egg's ratio is 0.4(bottom of half circle) to 0.6 (upper of half oval);
However, I don't know why nothing is happen.
following code is the creation of the path:
self.egg = [SKSpriteNode spriteNodeWithImageNamed:IMAGE_NAME_EGG];
[self.egg setScale:0.2];
self.egg.position = CGPointMake(self.size.width/2,self.size.height - self.egg.size.height/2);
self.egg.name = IMAGE_NAME_EGG;
CGMutablePathRef path = CGPathCreateMutable();
CGPathAddArc(path, NULL, 0, self.egg.size.height*0.4, self.egg.size.width/2, M_PI, M_PI_2, NO);
CGPathAddEllipseInRect(path, NULL, self.egg.frame);
self.egg.physicsBody = [SKPhysicsBody bodyWithEdgeLoopFromPath:path];
self.egg.physicsBody.dynamic = YES;
self.egg.physicsBody.categoryBitMask = eggCategory;
self.egg.physicsBody.contactTestBitMask = floorCategory;
self.egg.physicsBody.collisionBitMask = floorCategory;
//self.eggCanMove = NO;
self.egg.physicsBody.allowsRotation = YES;
[self addChild:self.egg];

There is a better way to do this. Make a texture of your egg with p.e. Adobe Illustrator and use this method:
init(texture texture: SKTexture!,alphaThreshold alphaThreshold: CFloat,size size: CGSize) -> SKPhysicsBody
The SKTexture is your egg image. The body is defined by the colored pixels.
The alphaThresHold: The minimum alpha value for texels that should be part of the new physics body.
The Size is clear I think.
The texture is analyzed and all invisible pixels around the egg are ignored and only the color pixels are interpreted as the body of the SKPhysicsNode.
You shouldn't use too many of these because they are very expensive to calculate for the Physics Engine.
Variations of this method are found in the SpriteKit Class Reference.

Related

Find opposite transformation of SKSpriteNode

I want to add a SKShapeNode drawn from my SKScene to a SKSpriteNode. The SKSpriteNode may already have some transformations that automatically translate to the SKShapeNode, which I don't want to happen. I've added a screenshot of the way the shapenode jumps after adding. I have also added my code where I add the shape node as a child and apply some opposite transformations to the node (works fine in some cases, but for example when I scale, move and rotate the robot, the drawing jumps to another position).
func addMaskPath(_ path: CGPath) {
let drawing = MaskLayer(withPath: path)
drawing.zRotation = -zRotation
drawing.xScale = drawing.xScale / xScale
drawing.yScale = drawing.yScale / yScale
drawing.position.x = (drawing.position.x - position.x) / xScale
drawing.position.y = (drawing.position.y - position.y) / yScale
drawing.position.y = drawing.position.y*cos(zRotation) - drawing.position.x*sin(zRotation)
drawing.position.x = -drawing.position.y*sin(zRotation) + drawing.position.x*cos(zRotation)
cropMask?.eraserMask?.addChild(drawing)
}
MaskLayer is a SKShapeNode. How do I easily find the transformations of my SKSpriteNode and apply them the opposite way to my SKShapeNode so my drawing will visually stay exactly the same?
Screenshot
You shouldn't add your SKShapeNode to a SKSpriteNode if you don't want it to inherit its transformation.
I suggest having a parent SKNode that'll hold your SKSpriteNode and add your SKShapeNode to the parent SKNode instead of the SKSpriteNode

I programmed a cube to slide across the floor in scenekit for iOS, it sinks into the floor though

I currently have a scene where a cube is dropped onto a floor in scenekit. I animated the cube to move on the x axis across the floor, when it does though it sinks into the floor a bit and then repositions to be on top of the floor.
Here's just some of the code:
// create floor
SCNFloor *mainFloor = [SCNFloor floor];
SCNNode *floorNode = [SCNNode nodeWithGeometry:mainFloor];
floorNode.position = SCNVector3Make(0.0, -4.0, 0.0);
[myScene.rootNode addChildNode:floorNode];
SCNPhysicsShape *ground = [SCNPhysicsShape shapeWithGeometry:mainFloor options:nil];
SCNPhysicsBodyType kin = SCNPhysicsBodyTypeKinematic;
SCNPhysicsBody *solid = [SCNPhysicsBody bodyWithType:kin shape:ground];
floorNode.physicsBody = solid;
myScene.physicsWorld.gravity = SCNVector3Make(0.0, -9.8, 0.0);
Can someone help me find out why the cube sinks? If you can't figure out why, maybe you could provide example code of a working floor that a character can walk on? (in objective c hopefully, but i can translate from swift if need be)
I think that the category bit mask of your floor and the collision bitmask of your cube should be the same
you can do so (in swift) like this:
floorNode.physicsBody.categoryBitMask = 3
cubeNode.physicsBody.collisionBitMask = 3
Using ProBlaster's advice, I used [SCNPhysicsBody applyForce] instead and that solved the problem.

Circular body positioning not working in box2d(cocos2dx)

I'm developing a cocos2dX game. I use box2d for physics simulation. I'm trying to add a circular body and a rectangular body. Here is my code
// Create circular sprite and body
CCSprite* ball_sprite = CCSprite::create("ball.png");
this->addChild(ball_sprite);
b2BodyDef ballBodyDef;
ballBodyDef.type = b2_dynamicBody;
ballBodyDef.position.Set(screenSize.width/PTM_RATIO, screenSize.height/2/PTM_RATIO);//im running it in an iphone retina and screensize is 640x960
ballBodyDef.userData = ball_sprite;
ball_body = _world->CreateBody(&ballBodyDef);
b2CircleShape ballshape;
ballshape.m_radius = BALL_SIZE/2;
b2FixtureDef ballShapeDef;
ballShapeDef.shape = &ballshape;
ballShapeDef.density = 100.0f;
ballShapeDef.friction = 0.5f;
ballShapeDef.restitution = 0.7f;
ball_body->CreateFixture(&ballShapeDef);
// Create rectangular sprite and body
CCSprite* block_sprite = CCSprite::create("HelloWorld.png");
this->addChild(block_sprite);
b2BodyDef blockBodyDef;
blockBodyDef.type = b2_staticBody;
blockBodyDef.position.Set(0, screenSize.height/2/PTM_RATIO);
blockBodyDef.userData = block_sprite;
block_bodie = _world->CreateBody(&blockBodyDef);
b2PolygonShape blockshape;
blockshape.SetAsBox(B_WIDTH/PTM_RATIO,B_HEIGHT/PTM_RATIO);
b2FixtureDef blockShapeDef;
blockShapeDef.shape = &blockshape;
blockShapeDef.density = 100.0f;
blockShapeDef.friction = 0.5f;
blockShapeDef.restitution = 0.7f;
block_bodie->CreateFixture(&blockShapeDef);
The rectangular body is shown in the screen as expected.
But the circular body is not shown in the screen.
When I printed the position of circular body in the update function, the positions are large numbers around 2000. And this position is different each time I run the programm.
If the rectangular body is not added(commenting the line block_bodie->CreateFixture(&blockShapeDef);) then the circular body is shown in the screen as I expected.
What I'm doing wrong here?
Thanks in advance.
Are these two bodies overlapping when they are created? Most likely the circle is simply being pushed away by the rectangle, because the rectangle is static and the circle is dynamic. If you try creating both of them, but don't call the world Step function to run the physics simulation, you will probably see them both on screen.
You could create them so that they are not overlapping, or at least not overlapping as much, or make one of them a sensor, or set their collision category and mask bits so they don't interact.
Of course, I am assuming you are looking at the debug draw display, which is really the only way to know for sure what the physics engine is doing.

Error attempting to create polygon with CGPathAddEllipseInRect

I am trying to create an ellipses. I used bodyWithEdgeLoopFromPath and it worked but there seems to be something wrong with it because sometimes other objects get caught in the middle of it.
But I want the ellipses to be solid, So I tried bodyWithPolygonFromPath (I want it static)
horizontalOval = [[SKShapeNode alloc] init];
theRect = CGRectMake(0, 0, self.frame.size.width/6 , 15);
CGMutablePathRef ovalPath = CGPathCreateMutable();
CGPathAddEllipseInRect(ovalPath, NULL, theRect);
horizontalOval.path = ovalPath;
horizontalOval.fillColor = [UIColor blueColor];
horizontalOval.physicsBody.dynamic = NO;
horizontalOval.physicsBody = [SKPhysicsBody bodyWithPolygonFromPath:ovalPath];
But got the error
SKPhysicsBody: Error attempting to create polygon with 17 vertices, maximum is 12
How do I create complex paths and make them solid?
Also when I pud it in position self.frame.size.width/2 and self.frame.size.height/2 It doesn't stay center, it goes a little to the right.
I had to theRect = CGRectMake(-40, 0........) to make it center but why is that?
UIBezierPath* ovalPath = [UIBezierPath bezierPathWithOvalInRect: _paddleRect];
But has 13 vertices. Trying to use PaintCode.
You can think of an edge body as one that has no volume, just the edges, a body with 'negative space' - that's why your objects got caught in the middle of it. As the Sprite Kit Programming Guide says:
The main difference between a edge and a volume is that an edge permits movement inside its own boundaries, while a volume is considered a solid object.
Since you want your oval to be a solid object, you do need a volume-based body. For these bodies, you have three options to create their shape: a circle (bodyWithCircleOfRadius:), a rectangle (bodyWithRectangleOfSize:), or a polygon (bodyWithPolygonFromPath:).
For an oval shape, you probably have to draw a polygon - however, the Sprite Kit physics engine will only accept those with a maximum of 12 vertices (that's why you were getting an error when drawing an actual ellipse). Your best bet is drawing a polygon using a helper tool, such as this one: http://dazchong.com/spritekit/ - just drag and drop your sprite and draw the path. Remember that the polygon must be convex (no angles over 180 degrees inside it) and that it can have a maximum of 12 vertices.
Also check out this answer for a similar issue: Ellipse SKPhysicsBody

Cocos2d: Disable rotation display for CCSprite

I am creating a sprite like this:
CatSprite *aCat = [CatSprite spriteWithFile:#"Icon-Small.png"];
// add sprite to CCLayer
[self addChild:aCat];
// and then define the body and shape
cpBody *body = cpBodyNew(10.0f, cpMomentForPoly(1000.0f, num, verts, CGPointZero));
body->p = ccp(x, y);
cpSpaceAddBody(space, body);
cpShape* shape = cpPolyShapeNew(body, num, verts, CGPointZero);
shape->e = 0.5f; shape->u = 1.0f;
shape->data = aCat;
cpSpaceAddShape(space, shape);
I am applying physics and constraints to the body in chipmunk space. What I want is to disable the display of the body rotation, in other words when body rotate I want the sprite to stay on 0 degree. Any ideas please?
Thank you
So there is inevitably somewhere that you are copying the rotation of the body to the sprite. Unless you are using the released-days-ago alpha preview of Cocos2D v3, CCSprites and cpBodies don't actually work together unless you write code that syncs the sprite with the body. Simply don't copy the rotation for that sprite.
You can also disable body rotation completely, setting its inertia to INFINITY, e.g. cpBodyNew(10.0f, INFINITY);

Resources