Moving a Node over a Moving Platform

I have a moving platform, but when the node is above the platform, it does not move horizontally with the platform

This article explains the problem: Moving the Hell Platform

http://www.learn-cocos2d.com/2013/08/physics-engine-platformer-terrible-idea/

And in the comment there are solutions for Box2D: Kinematic body

But what about SpriteKit?

Update

I am moving the platform with

let moveHPart1 = SKAction.moveByX(origW, y: 0, duration: moveDuration); let moveHPart2 = SKAction.moveByX(-origW, y: 0, duration: moveDuration); platform(SKAction.repeatActionForever(SKAction.sequence([moveHPart1, moveHPart2]))); 
+4
source share
1 answer

Personally, I am opposed to using physics for moving platforms, because the physical body of the platform platform must be dynamic.

Static platforms

For static platforms, the physical body of the dynamic property false is the ideal solution. And so it should be. Static bodies are independent of forces, but still give you a collision reaction. So the problem is resolved.

But you cannot change the position of bodies of static physics using forces. You can do this using actions or manually setting your position. But then you remove the platform from the physical simulation.

To do everything with physics, you must maintain the dynamics of the platform. But this can lead to other problems. For example, when a player sits on a platform, he will push out the platform because the player has a lot. Even if the platform has a large mass, it will come down over time. Remember, we cannot just update the x position platform manually, because it can lead to a mess in the physical simulation.

"Moving the hell platform," as stated in this wonderful article in LearnCocos2d, is probably the best description of what can happen when using physics for this task :-)

Work platform example

To show you some of the possibilities, I made a simple example of how you can move a platform using force to it and make the character stay on it. There are several things that I did to make this work:

  • The mass of the platform has been changed. This will prevent the platform from moving when the player encounters it from below.

  • Created a physical body based on the edge to prevent the platform from falling when the player landed on it.

  • Plays with properties, such as rotation and friction, to achieve the desired effect.

Here is the code:

 import SpriteKit class GameScene: SKScene,SKPhysicsContactDelegate { let BodyCategory : UInt32 = 0x1 << 1 let PlatformCategory : UInt32 = 0x1 << 2 let WallCategory : UInt32 = 0x1 << 3 let EdgeCategory : UInt32 = 0x1 << 4 // This will prevent a platforom from falling down let PlayerCategory : UInt32 = 0x1 << 5 let platformSpeed: CGFloat = 40.0 let body = SKShapeNode(circleOfRadius: 20.0) let player = SKShapeNode(circleOfRadius: 20.0) let platform = SKSpriteNode(color: SKColor.greenColor(), size: CGSize(width:100, height:20)) let notDynamicPlatform = SKSpriteNode(color: SKColor.greenColor(), size: CGSize(width:100, height:20)) override func didMoveToView(view: SKView) { //Setup contact delegate so we can use didBeginContact and didEndContact methods physicsWorld.contactDelegate = self //Setup borders self.physicsBody = SKPhysicsBody(edgeLoopFromRect: self.frame) self.physicsBody?.categoryBitMask = WallCategory self.physicsBody?.collisionBitMask = BodyCategory | PlayerCategory //Setup some physics body object body.position = CGPoint(x: CGRectGetMidX(self.frame), y: CGRectGetMidY(self.frame)) body.fillColor = SKColor.greenColor() body.physicsBody = SKPhysicsBody(circleOfRadius: 20) body.physicsBody?.categoryBitMask = BodyCategory body.physicsBody?.contactTestBitMask = PlatformCategory body.physicsBody?.collisionBitMask = PlatformCategory | WallCategory body.physicsBody?.allowsRotation = false body.physicsBody?.dynamic = true self.addChild(body) //Setup player player.position = CGPoint(x: CGRectGetMidX(self.frame), y:30) player.fillColor = SKColor.greenColor() player.physicsBody = SKPhysicsBody(circleOfRadius: 20) player.physicsBody?.categoryBitMask = PlayerCategory player.physicsBody?.contactTestBitMask = PlatformCategory player.physicsBody?.collisionBitMask = PlatformCategory | WallCategory | BodyCategory player.physicsBody?.allowsRotation = false player.physicsBody?.friction = 1 player.physicsBody?.dynamic = true self.addChild(player) //Setup platform platform.position = CGPoint(x: CGRectGetMidX(self.frame), y: CGRectGetMidY(self.frame) - 100) platform.physicsBody = SKPhysicsBody(rectangleOfSize: platform.size) platform.physicsBody?.categoryBitMask = PlatformCategory platform.physicsBody?.contactTestBitMask = BodyCategory platform.physicsBody?.collisionBitMask = BodyCategory | EdgeCategory | PlayerCategory platform.physicsBody?.allowsRotation = false platform.physicsBody?.affectedByGravity = false platform.physicsBody?.dynamic = true platform.physicsBody?.friction = 1.0 platform.physicsBody?.restitution = 0.0 platform.physicsBody?.mass = 20 //Setup edge let edge = SKNode() edge.physicsBody = SKPhysicsBody(edgeFromPoint: CGPoint(x: 0, y:-platform.size.height/2), toPoint: CGPoint(x: self.frame.size.width, y:-platform.size.height/2)) edge.position = CGPoint(x:0, y: CGRectGetMidY(self.frame) - 100) edge.physicsBody?.categoryBitMask = EdgeCategory edge.physicsBody?.collisionBitMask = PlatformCategory self.addChild(edge) self.addChild(platform) } override func update(currentTime: NSTimeInterval) { if(platform.position.x <= platform.size.width/2.0 + 20.0 && platform.physicsBody?.velocity.dx < 0.0 ){ platform.physicsBody?.velocity = CGVectorMake(platformSpeed, 0.0) }else if((platform.position.x >= self.frame.size.width - platform.size.width/2.0 - 20.0) && platform.physicsBody?.velocity.dx >= 0.0){ platform.physicsBody?.velocity = CGVectorMake(-platformSpeed, 0.0) }else if(platform.physicsBody?.velocity.dx > 0.0){ platform.physicsBody?.velocity = CGVectorMake(platformSpeed, 0.0) }else{ platform.physicsBody?.velocity = CGVectorMake(-platformSpeed, 0.0) } } override func touchesBegan(touches: NSSet, withEvent event: UIEvent) { let touch: AnyObject? = touches.anyObject() let location = touch?.locationInNode(self) if(location?.x > 187.5){ player.physicsBody?.applyImpulse(CGVector(dx: 3, dy: 50)) }else{ player.physicsBody?.applyImpulse(CGVector(dx: -3, dy: 50)) } } } 

Here is the result:

enter image description here

+8
source

Source: https://habr.com/ru/post/1267157/


All Articles