【问题标题】:Check if player is on top of another node?检查播放器是否在另一个节点之上?
【发布时间】:2014-07-18 17:46:15
【问题描述】:

我正在尝试让我的玩家跳跃。但是我不能让他在半空中跳跃,所以我需要在施加脉冲之前检查它是否站在另一个节点的顶​​部。

其他精灵套件游戏通常如何做到这一点?


现在我正在尝试两种方法,第一种就是这个。这很棒,但是我不知道如何判断玩家正在触摸的节点是真的在玩家的下方还是在玩家的一侧。

override func touchesBegan(touches: NSSet, withEvent event: UIEvent) {
    var allowJump = false
    let bodies = player.physicsBody.allContactedBodies()
    for body : AnyObject in bodies {
        if let node = body.node {
            allowJump = true // Player is touching another node but we don't know where (the bottom of the player or it's sides)
        }
    }
}

这是另一种方法,它可以有效地判断接触是否开始,以及接触是否真的与地面(玩家下方)而不是墙壁等接触。但是我不知道如何判断玩家何时停止在任何节点之上,因为即使联系结束,他可能仍在联系另一个节点。

func didBeginContact(contact: SKPhysicsContact!){
    if(contact.bodyA.node.position.y < contact.contactPoint.y) {
        println("BodyA is on top of another node")
    }

    if(contact.bodyB.node.position.y < contact.contactPoint.y) {
        println("BodyB is on top of another node")
    }
}

func didEndContact(contact: SKPhysicsContact!){
     if(contact.bodyA.node.position.y < contact.contactPoint.y) {
        println("BodyA is on no longer on top of BodyB")
    }

    if(contact.bodyB.node.position.y < contact.contactPoint.y) {
        println("BodyB is no longer on top of BodyA")
    }
}

【问题讨论】:

    标签: ios swift sprite-kit


    【解决方案1】:

    这就是我现在正在做的事情,但是它不会让我知道它所接触的节点是否在下方/左/右。我可以简单地将它的位置与我的节点进行比较,但是有些节点像 edgeLoopF​​romPath 一样是空心的,或者具有不同的形状。

    override func touchesBegan(touches: NSSet, withEvent event: UIEvent) {
        var allowJump = false
        let bodies = player.physicsBody.allContactedBodies()
        for body : AnyObject in bodies {
            if let node = body.node { // Additionally check contactBitMask
                allowJump = true
            }
        }
    }
    

    【讨论】:

      【解决方案2】:
      typedef  NS_OPTIONS(uint32_t, CNPhysicsCategory)
      {
          CNPhysicsCategoryChick = 1,
          CNPhysicsCategoryEdge = 2,
          CNPhysicsCategoryStrawberry = 3,
      };
      
      @interface MyScene() <SKPhysicsContactDelegate>
      
      @end
      
      
      @implementation MyScene
      {
          SKSpriteNode *strawberry;
          SKSpriteNode *chick;
      
      }
      
      -(id)initWithSize:(CGSize)size {    
          if (self = [super initWithSize:size]) {
              /* Setup your scene here */
      
              self.physicsBody = [SKPhysicsBody bodyWithEdgeLoopFromRect:self.frame];
              self.physicsBody.categoryBitMask = CNPhysicsCategoryEdge;
              self.physicsWorld.contactDelegate = self;
              self.physicsBody.restitution = 0.0;
      
              chick = [SKSpriteNode spriteNodeWithImageNamed:@"chick"];
              [chick setScale:0.3];
              chick.position = CGPointMake(self.size.width/2, chick.size.height/2);
              chick.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:chick.size];
              chick.physicsBody.categoryBitMask = CNPhysicsCategoryChick;
              chick.physicsBody.collisionBitMask = CNPhysicsCategoryEdge;
              chick.physicsBody.restitution = 0.0;
              [self addChild:chick];
      
      
              strawberry = [SKSpriteNode spriteNodeWithImageNamed:@"strawberry"];
              strawberry.position = CGPointMake(chick.position.x, chick.position.y - chick.size.height/2 + strawberry.size.height/2);
      
              //You should make this hidden
              //strawberry.hidden = YES;
      
              strawberry.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize: CGSizeMake(strawberry.size.width, strawberry.size.height)];
              strawberry.physicsBody.categoryBitMask = CNPhysicsCategoryStrawberry;
              strawberry.physicsBody.collisionBitMask = kNilOptions;
              strawberry.physicsBody.contactTestBitMask = CNPhysicsCategoryEdge;
              strawberry.physicsBody.density = 0.001;
              strawberry.physicsBody.restitution = 0.0;
              [self addChild:strawberry];
      
              SKPhysicsJointFixed *point = [SKPhysicsJointFixed jointWithBodyA:strawberry.physicsBody bodyB:chick.physicsBody anchor:CGPointZero];
              [self.physicsWorld addJoint:point];
          }
          return self;
      }
      
      -(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
      
          [chick.physicsBody applyImpulse:CGVectorMake(0, 60)];
      }
      
      -(void)didBeginContact:(SKPhysicsContact *)contact
      {
          uint32_t collision = (contact.bodyA.categoryBitMask | contact.bodyB.categoryBitMask);
      
          if (collision == (CNPhysicsCategoryEdge | CNPhysicsCategoryStrawberry)) {
              NSLog(@"In Contact");
          }
      }
      
      -(void)didEndContact:(SKPhysicsContact *)contact
      {
          uint32_t collision = (contact.bodyA.categoryBitMask | contact.bodyB.categoryBitMask);
      
          if (collision == (CNPhysicsCategoryEdge | CNPhysicsCategoryStrawberry)) {
              NSLog(@"Contact Is Lost");
          }
      }
      
      
      @end
      

      【讨论】:

      • 问题是可能有一个壁架,或者玩家可以站立的某种盒子。
      • 我明白了,所以对于一个通用的解决方案,你应该使用 SKPhysicsContactDelegate 和 -(void)didBeginContact:(SKPhysicsContact *)contact 方法,网上有很多例子,我想你现在可以轻松解决你的问题
      • 我检查了它们,但是当联系开始时它们似乎会触发,但我不明白如何知道节点是否在 update() 方法中接触。我会在稍后添加赏金!
      • 我的建议是使用 didBeginContact 和 didEndContact 方法来检查对象是否相互接触,如果有必要在这些方法中也使用 flags 或 performSelector
      • 嗨 Ahmet,我用我当前的代码更新了你的答案。我设法知道我的播放器(或任何节点)是否在另一个之上。但是我不知道如何准确判断节点何时不再位于任何东西之上。
      【解决方案3】:

      Swift 5

      更新
      guard let bodies = player.physicsBody?.allContactedBodies() else { return }
      for body: SKPhysicsBody in bodies {
          if let node = body.node {
              if node.name == "ground" {
                  isJumping = false
              }
          }
      }
      

      【讨论】:

        【解决方案4】:

        使用状态来完成此操作。

        假设你的玩家可以处于两种状态 - 1. touchingTheGround 2. inTheAir

        • 仅当播放器状态为 touchingTheGround 并将状态更改为 inTheAir 时才对播放器应用向上推动力
        • 当玩家接触地面时,将其状态设置为 touchingTheGround。同样在这一点上,您可以检查通过玩家节点中心和接触点的线所形成的角度与 +x 轴形成 -90 度(或大约 -90)角。(玩家站起来)
        • 如果玩家没有用脚着地,您可以将玩家发送到其他状态并为该状态编写不同的逻辑。

        为了实现状态,我建议使用 NS_ENUM

        【讨论】:

        • 我不确定这是否可行。我认为我需要一个真正检查用户是否接触地面的功能,毕竟如果他从具有这种逻辑的壁架上掉下来,玩家就会接触地面
        • 嗨,sps,我真的很接近解决方案。请查看更新后的问题。
        【解决方案5】:

        在你的玩家节点底部添加另一个节点(如果你愿意的话,可以用脚)并使用它来检测碰撞。使这个“脚节点”比你的玩家稍微窄一点,这样它就不会触发侧面碰撞。当脚与可能不是玩家本身的身体接触时,您就知道它站在某物上。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2021-10-16
          • 1970-01-01
          • 2015-09-13
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-01-01
          相关资源
          最近更新 更多