【问题标题】:How can one make only one side of a physics body active in SpriteKit?如何在 SpriteKit 中只激活物理体的一侧?
【发布时间】:2016-06-15 18:26:21
【问题描述】:

我有一个英雄、场地和一张桌子。我想激活一个桌面以与英雄发生碰撞和接触。但是英雄应该能够不跳到顶部而只是“穿过”并跳上它,如果玩家想要它,无论他想去哪里。为了更好地说明我正在努力实现的目标 - 想想马里奥。当您在地面上跑步时,会出现一些天空平台。您可以在平台中间跳上它并停留在那里。所以我需要物理身体在他从底部接触它时不要阻止英雄,但如果他在它上面就抓住他。 到目前为止,我正在使用带有纹理的主体作为表格:

    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

显然,它不起作用。我怎样才能实现这样的事情?

【问题讨论】:

    标签: ios sprite-kit


    【解决方案1】:

    这个问题的答案实际上并不太难,但对你来说,实现一个完整的游戏会困难得多。这不适合新手程序员一开始。

    首先相同的代码项目(点击/点击屏幕跳转):

    #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 redColor] 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)];
        }
    }
    

    代码的要点是玩家节点(node2)必须不断检查其相对于其他楼层的 y 位置(更新方法)。在示例中,玩家从 floor1 跳了起来。一旦玩家高于 floor1,玩家节点的物理主体会修改其碰撞位掩码以包含 floor1。

    听起来很简单。但是,在真实游戏中,您将拥有大量楼层,并且所有楼层的 y 距离可能不均匀。编码时必须牢记所有这些。

    【讨论】:

    • 嗯,你是对的!现在对我来说有点太难了。我想我会开始寻找替代方法来做类似的事情。不过还是谢谢你,这是一个很好的例子!
    【解决方案2】:

    我不确定您的平台是什么样子(基于边缘或基于体积的主体),但您可以考虑其中一些:

    1.检查位置

    • 检查英雄的 position.y 是否在平台下方/上方并忽略/处理碰撞。

    2。检查速度

    • 或者检查玩家节点是否下落,由负velocity.dy值表示。

    我不能说这些中的任何一个是否可以完全帮助您完成游戏,或者您的设置是否可能,但您可以了解从哪里开始的一些基本概念。

    可以通过更改玩家和平台的碰撞位掩码来启用/禁用碰撞。如果可能,尽量避免跟踪状态,如 isInTheAirisOnPlatformisFalingisJumping 等,因为它可能会变得混乱随着国家数量的增加。例如,无需添加名为“isFalling”的自定义布尔变量并不断保持其状态,您可以检查velocity.dy 是否为负以查看玩家是否正在下落。

    【讨论】:

      【解决方案3】:

      我尝试更改平台冲突位掩码,但无法正常工作。我找到了不同的解决方案。

      在 update() 函数中,您可以检查以下内容

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

      这样玩家每次上去都能穿过石块,每次下落都能站立。

      【讨论】:

        【解决方案4】:

        使用 swift 你可以像这样创建一个精灵节点子类:

        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"
            }
        }
        

        然后,更新游戏场景中的所有tableNode:

        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
                }
            }
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多