I'm trying to create a House Stack-like game (https://apps.apple.com/gb/app/house-stack/id1458713825?l) but having problem to assign physics mechanism.
My main problem is to create a single object when Node drop and contact with others and move them down in a solid form, once they reach to specific height.
I've tried to create fixed-joints with contact between nodes and move them when last Node position y = 0 but fixed-joints are not working as i thought. Nodes are shaking like a snake and collapsing when they moved.
Also tried to create a new single object with contact and calculate its height but couldn't figure out how should i use init(bodies: [SKPhysicsBody]). Even if i assign physicsbody properties to new object, i can't measure or call its height and update body with another Node contact.
Any idea or example would be nice. Here is my codes, thanks in advance.
SKNode(inside touchesBegan to create same node multiple times):
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
let Node1 = SKSpriteNode(imageNamed: "Object1")
Node1.position = MovingObject.position
Node1.zPosition = 2
Node1.physicsBody = SKPhysicsBody(rectangleOf: CGSize(width: Node1.size.width, height: Node1.size.height))
Node1.physicsBody?.friction = 0.9
Node1.physicsBody?.restitution = 0.1
Node1.physicsBody?.allowsRotation = true
Node1.physicsBody!.contactTestBitMask = Node1.physicsBody!.collisionBitMask
Node1.physicsBody!.categoryBitMask = Node1Category
addChild(Node1)
}
Moving Object:
Inside GameScene;
var MovingObject = SKSpriteNode(imageNamed: "Object1")
let ObjectMove = SKAction.sequence([(SKAction.moveBy(x: 200, y: 0, duration: 0.5)),(SKAction.moveBy(x: -400, y: 0, duration: 1)),(SKAction.moveBy(x: 200, y: 0, duration: 0.5))])
Inside override func didMove(to view: SKView);
MovingObject.position = CGPoint(x: 0, y: frame.maxY * 0.55)
MovingObject.zPosition = 1
MovingObject.run(SKAction.repeatForever(ObjectMove))
addChild(MovingObject)
Joints and moves:
func didBegin(_ contact: SKPhysicsContact) {
if contact.bodyA.node?.name == "Node1" && contact.bodyB.node?.name == "Node1"
{
let joint2 = SKPhysicsJointFixed.joint(withBodyA: contact.bodyA , bodyB: contact.bodyB, anchor: CGPoint(x: contact.contactPoint.x, y:contact.contactPoint.y))
let pos2 = (contact.bodyA.node?.position.x)!-(contact.bodyB.node?.position.x)!
if pos2 <= Node1.size.width * 0.5 && pos2 >= -Node1.size.width * 0.5{
physicsWorld.add(joint2)
}
if (contact.bodyB.node?.position.y)! >= 0 {
let movenodedown = SKAction.moveBy(x: 0, y: -Node1.size.height, duration: 0.5)
contact.bodyB.node?.run(movenodedown)
ground.run(movenodedown)
}
}
For those who need to be enlightened about similar problems;
I found my solution by using enumerateChildNodes(withName:using:)
and physicsBody.isDynamic = false
together instead of fixed joints. Code is below.
func didBegin(_ contact: SKPhysicsContact)
{
if contact.bodyA.node?.name == "Node1" && contact.bodyB.node?.name == "Node1"
{
let pos2 = (contact.bodyA.node?.position.x)!-(contact.bodyB.node?.position.x)!
if pos2 <= Node1.size.width * 0.5 && pos2 >= -Node1.size.width * 0.5.
{
contact.bodyB.node?.physicsBody?.isDynamic = false
contact.bodyA.node?.physicsBody?.collisionBitMask = 0
contact.bodyA.node?.physicsBody?.contactTestBitMask = 0
if (contact.bodyB.node?.position.y)! >= 0
{
let movenodesdown = SKAction.moveBy(x: 0, y: Node1.size.height , duration: 0.5)
enumerateChildNodes(withName: "Node1") { (nodes, stop) in
let Node1 = nodes as! SKSpriteNode
Node1.run(movenodesdown)
}
}
}
}
}