This week, I created something similar to pendulum, with Physics bodies, physics joints, and Field Nodes.
I say something similar, because it did not reach the exact pendulum swing that I wanted. But it is closer. If the values are tweaked a bit, it would reach the optimal pendulum swing motion. Before that I thought I would publish this post.
First create a simple empty game in Xcode for swift language. In GameScene.swift, inside class GameScene, in didMoveToView(), add the following nodes.
Then comes the physics body. The Physics body gives movement to the node, and makes it behave in accordance with the gravity law. Collision is taken care of by the physics bodies.
Create a rectangular physics body of the same size as that of the rectangular node. Then I made sure the physics body is not affected by gravity because, I want them to be affected only by the two Field bodies' gravitational forces.
Let the physics body have a mass of 5. Make sure dynamic is set to true, so that they can move with respect to the forces acting on them.
Set the physics Body of the rectangular SKNode to the newly created physics body. Then add the node to the scene. Scene is the parent of the node.
Similarly create circle node :
For the sake of clarity, the red circle has an alpha of 1, and is visible. But it will be rendered transparent in the final code.
Now that the three major nodes are created, I am going to create two Field Nodes which would act as radial gravity nodes, which means, objects would be attracted towards them and would follow a natural curve of moving towards them and moving away from them.
I tried to create pendulum with one such node. but It did not give expected results, hence I am falling back to two nodes.
The cyan colored circles are the Field nodes which would try to pull the bob towards them. Note: SKFieldNode is available only for iOS 8.0 and above.
Here is the code snippet for them.
I say something similar, because it did not reach the exact pendulum swing that I wanted. But it is closer. If the values are tweaked a bit, it would reach the optimal pendulum swing motion. Before that I thought I would publish this post.
First create a simple empty game in Xcode for swift language. In GameScene.swift, inside class GameScene, in didMoveToView(), add the following nodes.
/* Setup your scene here */
let myLabel = SKLabelNode(fontNamed:"Chalkduster")
myLabel.text = "Pendulum";
myLabel.fontSize = 15;
myLabel.position = CGPoint(x:CGRectGetMidX(self.frame), y:CGRectGetMidY(self.frame));
self.addChild(myLabel)
These lines create label node, set its font size, and mention the idea of the game. Though the empty project is a game. This is no where closer to being a game. This is purely for experimentation and blogging purpose.
Place the label at the center of the screen. CGRectGetMidX() is a CGGeometry function which returns center x position of the rectangle passed as the parameter. Similarly CGRectGetMidY. Csdfs
I created three main nodes. One is a rectangle which will act as the rod. A circle which will act as the bob. And an invisible circle which will act as the anchor point for the rod. It will be on the other side of the rod, on opposite end to the bob circle.
let rectNode = SKShapeNode(rect: CGRectMake(500,300, 5, 250))
rectNode.strokeColor = SKColor.greenColor()
rectNode.fillColor = SKColor.yellowColor();
rectNode.lineWidth = 1
let rectBody = SKPhysicsBody(rectangleOfSize: rectNode.frame.size)
rectBody.affectedByGravity = false
rectBody.mass = 5
rectBody.dynamic = true // should be dynamic
rectNode.physicsBody = rectBody;
self.addChild(rectNode)
This snippet creates a rectangle node positioned at 500,300. Stroke color is green, fill color is yellow. You can provide any color you want. I simply created colors to provide contrast against black background.
Create a rectangular physics body of the same size as that of the rectangular node. Then I made sure the physics body is not affected by gravity because, I want them to be affected only by the two Field bodies' gravitational forces.
Let the physics body have a mass of 5. Make sure dynamic is set to true, so that they can move with respect to the forces acting on them.
Set the physics Body of the rectangular SKNode to the newly created physics body. Then add the node to the scene. Scene is the parent of the node.
Similarly create circle node :
let circleNode = SKShapeNode(circleOfRadius: 20);
circleNode.position.x = 500;
circleNode.position.y = 300
circleNode.strokeColor = SKColor.greenColor()
circleNode.fillColor = SKColor.orangeColor()
let circleBody = SKPhysicsBody(circleOfRadius: 20)
circleBody.affectedByGravity = rectBody.affectedByGravity
circleBody.mass = 10
circleBody.dynamic = true //should be dynamic
circleNode.physicsBody = circleBody
self.addChild(circleNode)
And create the anchor node:
let AnchorNode = SKShapeNode(circleOfRadius: 25);
AnchorNode.position.x = circleNode.position.x
AnchorNode.position.y = circleNode.position.y + 250
AnchorNode.alpha = 0
AnchorNode.strokeColor = SKColor.greenColor()
AnchorNode.fillColor = SKColor.redColor()
let AnchorBody = SKPhysicsBody(circleOfRadius: 20)
AnchorBody.affectedByGravity = false
AnchorBody.dynamic = false //should be dynamic
AnchorNode.physicsBody = AnchorBody
AnchorBody.affectedByGravity = false
self.addChild(AnchorNode)
The important points to note in the anchor node are as follows: Anchor node is invisible because I want the rod to look closer to a real pendulum. Position is same as that of the other end of the rod. It also has a body but it is not affected by gravity. It is not dynamic as well. It should stay put like a nail on the wall. It needs a physics body, in order to create a Pin joint later with the rod. Red circle is the anchor, orange is the pendulum bob.
Now that the three major nodes are created, I am going to create two Field Nodes which would act as radial gravity nodes, which means, objects would be attracted towards them and would follow a natural curve of moving towards them and moving away from them.
I tried to create pendulum with one such node. but It did not give expected results, hence I am falling back to two nodes.
Here is the code snippet for them.
let GravityNode = SKFieldNode.radialGravityField()
GravityNode.position.x = 350
GravityNode.position.y = 290
GravityNode.strength = 6
GravityNode.falloff = 3.5
self.addChild(GravityNode)
lAs we already know, let keyword creates a constant reference to the object, meaning, the GravityNode cannot point to any other object. The properties inside the object are editable, but not the GravityNode.
Set the position of one of the radial gravity node on the left side of the pendulum. Set its strength to be 6, and falloff to be 3.5 . Strength is the pull strength of its gravity. FallOff is the variable which sets the exponent value which determines how much of gravitational pull the objects would feel, after a certain distance.
Strength and falloff had to be tweaked in order to get a smooth swinging pendulum.
Add the node to the scene.
let GCircleNode = SKShapeNode(circleOfRadius: 25);
GCircleNode.position = GravityNode.position
GCircleNode.strokeColor = SKColor.greenColor()
GCircleNode.fillColor = SKColor.cyanColor()
GCircleNode.alpha = 1
self.addChild(GCircleNode)
This is a debug node which was created to show the position of the field node. This is not required to be rendered for the final run.
Similarly create a second field node, to pull the pendulum towards the other direction.
let GravityNode1 = SKFieldNode.radialGravityField()
GravityNode1.position.x = 650
GravityNode1.position.y = GravityNode.position.y
GravityNode1.strength = GravityNode.strength
GravityNode1.falloff = GravityNode.falloff
self.addChild(GravityNode1)
let GCircleNode1 = SKShapeNode(circleOfRadius: 25);
GCircleNode1.position = GravityNode1.position
GCircleNode1.strokeColor = SKColor.greenColor()
GCircleNode1.fillColor = SKColor.cyanColor()
GCircleNode1.alpha = 1
self.addChild(GCircleNode1)
Now the rod needs to be pinned to the invisible anchor node, and the bob circle needs to be pinned to the other end of the rod, in order to move in alignment with the rod.
let PinJoint = SKPhysicsJointPin.jointWithBodyA(circleNode.physicsBody, bodyB:
rectNode.physicsBody, anchor: circleNode.position)
let stickJoint = SKPhysicsJointPin.jointWithBodyA(rectNode.physicsBody, bodyB:
AnchorNode.physicsBody, anchor: AnchorNode.position)
self.physicsWorld.addJoint(PinJoint)
self.physicsWorld.addJoint(stickJoint)
The physics joint Pin, fixes bodyA to Body B at a certain point. This point is called anchor point. Body A is circle (bob) and body B is the rod in the first PinJoint. They are fixed at the bob's position.
Second stickJoint(for lack of better term) joins the rod and the invisible anchor node at the anchor node's position.
Add these two joints to the world. Now since the anchor's dynamic property is set to false, and it is not affected by gravity, It would stay put, and the rod has no other option than to stay put at that end. But the other end can move freely, and the bob circle will move whereever the other end moves because it is pinned to the rod at that point.
Now we have a working pendulum, whose bob is being pulled equally by left and right gravity nodes. When the bob reaches the center after being pulled by right node, it will be pulled by the left one, thereby swinging from one end to the other.
Code Jam for the week of Mar 15 2015
Project uploaded here : https://github.com/swtsvn/CJAW/tree/master/PhysicsGame




No comments:
Post a Comment