¿Cómo se puede hacer que solo un lado de un cuerpo de física esté activo en SpriteKit?

Tengo un héroe, suelo y una table. Quiero hacer una table activa para la colisión y el contacto con el héroe. Pero el héroe debería ser capaz de no saltar en la parte superior y simplemente correr "a través" y saltar sobre él, si el jugador lo quiere, donde quiera. Para mejor ejemplo de lo que bash lograr, piensa en Mario. Cuando corres por tierra, aparecen algunas plataforms de cielo. Podrías saltar sobre él en medio de una plataforma y quedarte allí. Entonces necesito un cuerpo de física para no detener a un héroe cuando lo está contactando desde abajo, pero manténgalo si está encima. Por ahora estoy usando cuerpo con textura para la table:

self.table.physicsBody = SKPhysicsBody(texture:table.texture, size:self.table.size) self.table.physicsBody?.dynamic = false self.table.physicsBody?.categoryBitMask = ColliderType.Table.rawValue self.table.physicsBody?.contactTestBitMask = ColliderType.Hero.rawValue self.table.physicsBody?.collisionBitMask = ColliderType.Hero.rawValue 

Obviamente, no funciona. ¿Cómo puedo implementar tal cosa?

Intenté cambiar la máscara de bits de colisión de plataforms, pero no funcionaba bien. Encontré una solución diferente.

Dentro de la function de actualización () puede verificar lo siguiente

 if player.physicsBody?.velocity.dy <= 0 { player.physicsBody?.collisionBitMask = PhysicsCategory.Platform } else { player.physicsBody?.collisionBitMask = PhysicsCategory.None } 

De esta manera, cada vez que el jugador sube, puede pasar a través de las rocas, y cada vez que cae, puede mantenerse.

La respuesta a esta pregunta en realidad no es muy difícil, pero la implementación en un juego completo será mucho más difícil para usted. Esto no es algo para que un progtwigdor principiante comience.

Primero el mismo proyecto de código (toque / click la pantalla para saltar):

 #import "GameScene.h" typedef NS_OPTIONS(uint32_t, Level1PhysicsCategory) { CategoryPlayer = 1 << 0, CategoryFloor0 = 1 << 1, CategoryFloor1 = 1 << 2, }; @implementation GameScene { int playerFloorLevel; SKSpriteNode *node0; SKSpriteNode *node1; SKSpriteNode *node2; } -(void)didMoveToView:(SKView *)view { self.backgroundColor = [SKColor whiteColor]; node0 = [SKSpriteNode spriteNodeWithColor:[SKColor grayColor] size:CGSizeMake(400, 10)]; node0.position = CGPointMake(300, 200); node0.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:node0.size]; node0.physicsBody.dynamic = NO; node0.physicsBody.categoryBitMask = CategoryFloor0; node0.physicsBody.collisionBitMask = CategoryPlayer; [self addChild:node0]; node1 = [SKSpriteNode spriteNodeWithColor:[SKColor grayColor] size:CGSizeMake(400, 10)]; node1.position = CGPointMake(300, 300); node1.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:node1.size]; node1.physicsBody.dynamic = NO; node1.physicsBody.categoryBitMask = CategoryFloor1; node1.physicsBody.collisionBitMask = CategoryPlayer; [self addChild:node1]; node2 = [SKSpriteNode spriteNodeWithColor:[SKColor networkingColor] size:CGSizeMake(50, 50)]; node2.position = CGPointMake(300, 250); node2.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:node2.size]; node2.physicsBody.categoryBitMask = CategoryPlayer; node2.physicsBody.collisionBitMask = CategoryFloor0; [self addChild:node2]; playerFloorLevel = 0; } -(void)update:(CFTimeInterval)currentTime { if(((node2.position.y-25) > (node1.position.y+10)) && (playerFloorLevel == 0)) { node2.physicsBody.collisionBitMask = CategoryFloor0 | CategoryFloor1; playerFloorLevel = 1; } } -(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { for (UITouch *touch in touches) { CGPoint touchLocation = [touch locationInNode:self]; //SKNode *node = [self nodeAtPoint:touchLocation]; // change 75 value to 50 to see player jump half way up through floor 1 [node2.physicsBody applyImpulse:CGVectorMake(0, 75)]; } } 

La esencia del código es que el nodo jugador (nodo2) debe seguir revisando su position y (método de actualización) en relación con los otros pisos. En el ejemplo, el jugador salta a través del piso1. Una vez que el jugador está más alto que el piso1, el cuerpo de física del nodo del jugador modifica su máscara de bit de colisión para include floor1.

Suena bastante fácil. Sin embargo, en un juego real tendrás una gran cantidad de pisos y todos los pisos podrían no estar separados por distancias iguales. Tienes que tener todo esto en count al codificar.

No estoy seguro de cómo se parecen tus plataforms (basadas en bordes o en los cuerpos basados ​​en volúmenes), pero puedes considerar algunas de ellas:

1. Comprobando posiciones

  • Verifique si la position del héroe está por debajo / sobre la plataforma e ignora / maneja la colisión.

2. Comprobando la velocidad

  • O para comprobar si el nodo del jugador está cayendo, lo que se indica mediante un valor de velocidad.dy negativo.

No puedo decir si alguno de estos puede ayudarte completamente con tu juego o si es posible con tu configuration, pero puedes tener una idea básica sobre dónde comenzar.

Habilitar / deshabilitar colisiones se puede hacer cambiando las máscaras de bits de colisión del jugador y la plataforma. Si es posible, trate de evitar los estados de seguimiento como isInTheAir , isOnPlatform , isFaling , isJumping y similar, ya que puede volverse desorderado a medida que crece el número de estados. Por ejemplo, en lugar de agregar una variable boolean personalizada llamada "isFalling" y mantener constantemente su estado, puede verificar si velocidad.dy es negativa para ver si el jugador está cayendo.

Usando swift puede crear una subclass de nodo sprite como esta:

 class TableNode: SKSpriteNode { var isBodyActivated: Bool = false { didSet { physicsBody = isBodyActivated ? activatedBody : nil } } private var activatedBody: SKPhysicsBody? init(texture: SKTexture) { super.init(texture: texture, color: SKColor.clearColor(), size: texture.size()) // physics body setup. Assuming anchorPoint = (0.5, 0.5) let bodyInitialPoint = CGPoint(x: -size.width/2, y: +size.height/2) let bodyEndPoint = CGPoint(x: +size.width/2, y: +size.height/2) activatedBody = SKPhysicsBody(edgeFromPoint: bodyInitialPoint, toPoint: bodyEndPoint) activatedBody!.categoryBitMask = ColliderType.Table.rawValue activatedBody!.collisionBitMask = ColliderType.Hero.rawValue physicsBody = isBodyActivated ? activatedBody : nil name = "tableNode" } } 

Luego, actualiza todos los Nodos de tabla en el juego Escenas:

 override func didSimulatePhysics() { self.enumerateChildNodesWithName("tableNode") { node, stop in if let tableNode = node as? TableNode { // Assuming anchorPoint = (0.5, 0.5) for table and hero let tableY = tableNode.position.y + tableNode.size.height/2 let heroY = hero.position.y - hero.size.height/2 tableNode.isBodyActivated = heroY > tableY } } }