I am using Apple's Sprite Kit to create a game, and currently I have drawn an SKShapeNode object that looks similar to the following:
My actual sprite has rounded edges, but for simplicity, I am trying to get everything working with this shape first. I am able to draw the sprite perfectly fine. However, I am having trouble creating a physics body to cover the sprite. I want the sprite to recognize collisions anywhere along its surface, so I want a physics body that covers only the dark gray area. Also, I want the sprite to respond to forces and impulses, so I need a volume-based physics body.
My first idea was to simply use the same CGPathRef that I used to create the image for the sprite, and pass it to the bodyWithPolygonFromPath method to create a corresponding physics body. I have come to find this will not work, as my shape is not convex.
So, now I am thinking I should be able to use bodyWithBodies to create a physics body shaped appropriately. I want to create three rectangular physics bodies (one to cover the left of the gray area, one to cover the top, and one to cover the right), and use those to create one physics body whose area covers the gray area of my sprite by using this:
mySprite.physicsbody = [SKPhysicsBody bodyWithBodies:#[body1, body2, body3]];
However, the main problem I am having is correctly positioning the individual bodies that go into the array, which is passed to the bodyWithBodies method. By using the above method, I obviously have no way of controlling where these physics bodies are being placed in relation to each other. The result is all three physics bodies stacking on top of each other in the center of mySprite.
How exactly are you supposed to position the physics bodies in the array relative to each other before passing them to the bodyWithBodies method?
Related
I'm working in Swift 3.1. I want to create a shadow for a SKSpriteNode. I'm thinking of doing a SKShapeNode from my SKSpriteNode and giving it some glow and alpha.
But how can I convert SKSpriteNode into SKShapeNode?
If your plan is to make a shadow that looks like your sprite, then using another SpriteNode instead would be advisable. SKShapeNodes have poor performance and the process of converting the sprite into a vector shape will be processing heavy.
You should have read about SKEffectNode because you could use them to create a SpriteNode with your current texture and apply some effects on it to turn your texture black, blured ans maybe even use affine transformation to distort and rotate the texture so it looks like a shadow.
To make things more GPU/CPU efficient in the case where you have many shadows, you could simply put all the shadow sprites as child of a single SKEffectNode that will apply the effects on every shadow sprite all at once. I assume that positionning the shadow under the main sprite would not be a challenge for you.
Having the shadow as a child of the main sprite would force you to put an effect node for every sprite casting a shadow, and would cause the effects to be processed over and over. By putting every shadow as a child of the same node, they will get rendered all at once and the effect will be processed only once every frame.
I hope it helps!
SKShapeNode's are known to have poor performance in SpriteKit. Instead, you should add another SKSpriteNode for the shadow, and add it as a child to the main SKSpriteNode.
If you want the shadow to appear below its parent, you may have to adjust it's relative z-position as well.
I'm creating a semi-circle node when i try to develop a simple sprite kit game, but i wish the physics body of the node just cover the circle object's edge, and the physics body rotates with the circle(to change the physics body programatically), what should i do?
You can do complex shapes using SKPhysicsBody -bodyWithPolygonFromPath:
There are even tools that let you draw your shape and generate the code for you. See this question for examples: SpriteKit's SKPhysicsBody with polygon helper tool
I am new to Objective-C and I am trying to make a simple spriteKit game which contains a circle and a ball inside it. I want to move the ball around in this circle as well on the iPhone movement. So far I have created the circle and am able to put the ball on the screen.
My problem is that I am not sure the ball is actually inside the circle or on top of it. When I attach a physics body on the ball, it drops out of the screen and does not stop on the circle's bottom edge. I am using SKShapeNode for both the circle and ball.
Please help me to provide the right documentation to go through or a little piece of code that can resolve this.
You need to assign appropriate physics bodies to your nodes. See Simulating Physics in the Sprite Kit Programming Guide.
From your description, it sounds like you need to create the outter circle's physics body with the bodyWithEdgeLoopFromPath: method (and provide a path representing the circle). Note that an edge loop physics body is not dynamic and can only collide with volume-based bodies.
The inner balls physics body can be created with bodyWithCircleOfRadius:.
I've created a box2d body that is attached to a second box2d body with a weld joint. The first box2d sprite associated with the body is in the shape of a stick. The second box2d body is a person that throws the first box2d body. The first box2d body is initialized as a polygon shape with a specified density, friction, and restitution. Depending on the game state, the first box2d body may get changed to a different sprite (but the box2d body remains the same). The new sprite is in the shape of a box. When the change to a new sprite is made, the original weld joint is destroyed and the new sprite is substituted. A new weld joint is created to reattach the box2d body to the second box2d body (i.e. reattached to the person). In addition, the box2d fixture of the first body is changed to have more friction and less restitution because I don't want the second type of sprite to bounce and slide as much as the first type of sprite.
In each case, I have an impulse that I apply to the first box2d body when I programmatically break the weld joint. With the second sprite (the box), the distance traveled after applying the impulse is much farther than the first sprite (the stick). I don't understand why there is such a difference since I've only changed the "look" of what is being thrown. The density and mass is the same. When I step through the code, the linear velocity appears to be the same in the box2d structure. There is apparently something in the physics that I don't understand.
My goal is to have both sprite types travel to the same location if given the same impulse. Is it possible to enable each sprite type behave the same? Please provide some guidance to achieve my goal.
Below is the code where I remove the old sprite and reattach the new sprite (note that "attachedBody" is the box2D body that was previously defined with the old sprite):
b2WeldJoint *myJoint;
// break the existing joint
// Destroy joint so the attachedBody will be free from the player
world->DestroyJoint(myJoint);
// Substitute the existing sprite with a new sprite. Also transform the position of the new sprite so that it is still touching the players hand
Box2DSprite *sprite = (Box2DSprite *) attachedBody->GetUserData();
[sprite setDisplayFrame: [[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName: #"newSprite.png"] ];
attachedBody->SetTransform(teamA.foreArmBody->GetWorldPoint(b2Vec2(65.0/100.0, -25.0/100.0)), -40.0f); // move new sprite to the players hand. Rotate the angle by 40.
// Make this new sprite stick when it lands
attachedBody->GetFixtureList()->SetFriction(8.0);
attachedBody->GetFixtureList()->SetRestitution(0.0);
// Create a new weld joint with the players hand and the new sprite
b2WeldJointDef weldJointDef;
weldJointDef.Initialize(attachedBody, teamA.foreArmBody, teamA.foreArmBody->GetWorldPoint(b2Vec2(6.0/100.0, -10.0/100.0)));
weldJointDef.collideConnected = false;
myJoint = (b2WeldJoint*)world->CreateJoint(&weldJointDef);
After digging deeper to answer the above comments, I found that I was not comparing apples and oranges. My problem is that in one case, the first body (the stick) had zero velocity when I applied the impulse. When I substituted the sprite of the first body with a new sprite and then gave it the same impulse, the body had a non-zero initial velocity. Therefore it travelled much farther. My solution is simple. I just need to set the velocity to zero before applying the impulse to cause the two different sprites to travel the same distance. For example:
attachedBody->SetLinearVelocity(b2Vec2(0,0));
I am using Cocos2D with the following settings:
[director_ setProjection:kCCDirectorProjection3D]; in the appDelegate class
kmGLRotatef(-47, 1.0, 0, 0); in my layer's draw method
This ensures that my objects are presented in a simulated 3D environment.
I've added Box2D for collision detection. I've setup the bodies. When I enable the debug drawing, then the bodies are arranged on the whole screen and the sprites are arranged in a perspective.
How can I add the same perspective for the bodies too?
The advice given is to find a bounding box from the fake 3d transformation in cocos2d of the sprite. Then use this bounding box for both the body's debug drawing and also to determine the new (or transformed) body for box2d.