代码之家  ›  专栏  ›  技术社区  ›  Seong Lee

模拟寿司列车-Swift SpriteKit

  •  1
  • Seong Lee  · 技术社区  · 7 年前

    我正在学习使用SprikeKit创建一个游戏,这个游戏与寿司训练有关。

    我尝试使用场景编辑器放置两个精灵节点,并使它们在这样的方形路径上移动。

    let dish_1 = self.childNode(withName: "dish_1");
    let dish_2 = self.childNode(withName: "dish_2");
    
    let square = UIBezierPath(rect: CGRect(x: 0, y: 0,  width: 200, height: 200));
    let followSquare = SKAction.follow(square.cgPath, asOffset: true, orientToPath: false, duration: 5.0);
    
    dish_1?.run(SKAction.sequence([followSquare]))
    dish_2?.run(SKAction.sequence([followSquare]))
    

    目前,两个盘子使用相同的正方形,正方形位置相对于每个盘子,因此它们看起来像是在两个不同的矩形路径上,因为它们的起点不同。

    这是模拟我想要的样子的合理方式吗? 我问这个问题的原因是,为了使所有的菜看起来像是在同一条路径上移动,我需要调整每个菜的x,y位置,它将像20个菜。

    我想知道是否可以使用物理工具包,让一个矩形节点使所有盘子沿着路径移动,只要它们在矩形节点区域内。

    2 回复  |  直到 7 年前
        1
  •  1
  •   user8606263 user8606263    7 年前

    我可能会用类似的方式来做,我认为使用SKAction。下面是一个解决方案。

    但是,您可以在代码中做一些改进。首先,您不需要将SKAction编写为序列,因为它只由一个动作组成,因此您可以将代码简化为:

        let squarePath = UIBezierPath(rect: CGRect(x: 0, y: 0,  width: 200, height: 200))
    
        let followAction = SKAction.follow(path: squarePath.cgPath, duration: 5.0)
    
        dish?.run(followAction)
    

    copy() 在您的 SKSpriteNode

    您可以创建SKSpriteNode的副本,如下所示:

    import GameplayKit
    
     if let dishCopy = dish?.copy() as? SKSpriteNode {
          dishCopy.position = CGPoint(x: GKRandomDistribution(lowestValue: 0, highestValue: 200).nextInt(), y: GKRandomDistribution(lowestValue: 0, highestValue: 500).nextInt())
          self.addChild(dishCopy)
     }
    

    对于每个盘副本的位置,当然可以根据自己的值进行调整,但在这里我使用了GameplayKit及其非常有用的随机值生成器。

    更新:

    如果您想在仍使用copy()的情况下为每个菜肴设置一个唯一的名称,您有几个选项。

    一种可能是使用递增的计数器生成唯一名称,另一种可能是在更新方法中使用currentTime。

    但另一种更优雅的方法是创建一个数组来存储所有副本,以跟踪所有副本的位置。

    在场景子类的顶部,按如下方式声明您的盘子数组:

     var dishes = [SKSpriteNode]()
    

    目前,它仍然为空,因此您需要在创建每个副本时将其添加到阵列中:

        // Create (safely) a dish copy:
    
        if let dishCopy = dish?.copy() as? SKSpriteNode {
    
            // Add the dish copy to the dishes array:
    
            dishes.append(dishCopy)
    
            // And add the dish copy to the world node:
    
            worldNode?.addChild(dishCopy)
        }
    

    如果您想创建这样的多个副本,可以使用 for loop ,或者你可以玩 update(_ currentTime:)

    好的,如果您需要在任何时候访问这些副本,只需访问 dishes 大堆

    例如,这是删除所有副本的方式(如果将原始盘添加到场景中,则必须处理原始盘):

    // And just iterate through all of your dish copies:
    
    for dish in dishes {
    
       dish.removeFromParent()
    
       // Do whatever you need here :)
    
    }
    

    worldNode .

    如果你有任何其他问题,请告诉我,我很乐意帮助你!

    顺便说一句,今晚我要去你在问题中提到的寿司店,那家有小火车的。。太巧了!:D

        2
  •  1
  •   lc.    7 年前

    asOffset 似乎不正确。根据 the documentation 恰恰相反的行为 你想要的。

    如果是,则路径中的点是相对于节点起始位置的相对偏移。如果否,则节点中的点是绝对坐标值。

    如果将其设置为true,则会为每个盘子提供其自己的矩形路径,以及相对于其起始位置的坐标,如您在问题中所述:

       v First dish
          v Second dish
       O--O-----.---.
       |  |     |   |
       |  |     |   |
       '--'-----'---'
                  ^^ Second dish's path
         ^^ First dish's path
    

       v First dish (starting point x=0; y=0)
          v Second dish (starting point x=20; y=0)
       O--O-----.
       |        |
       |        |
       '--------'
    
         ^^ Single, absolute path
    

    (如果你在模拟寿司传送带,它们会顺时针移动,上面的术语“first”和“second”在技术上是向后的。交换这一点留给读者作为练习。:-P)