我正在学习使用SprikeKit制作游戏,游戏与寿司列车有关。
为了模拟所有菜肴在移动的传送带上的外观,我沿着一条矩形路径跟着20个菜肴。
我尝试使用场景编辑器放置几个精灵节点并让它们在方形路径上移动。
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道菜一样。
我想知道是否可以使用物理工具包并让一个矩形节点使所有菜肴沿着路径移动,只要它们在矩形节点区域内。
答案 0 :(得分:1)
asOffset
似乎不正确。根据{{3}},完全是您想要的相反行为。
如果是,则路径中的点是相对于节点起始位置的偏移量。如果为NO,则节点中的点为绝对坐标值。
将此设置为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
(如果您正在模拟寿司传送带,它们顺时针移动,上面的“第一”和“第二”术语在技术上是向后的。交换这个是留给读者的练习。:-P)
答案 1 :(得分:1)
好吧,我可能会以类似的方式完成它,我认为使用SKAction.follow是一个解决方案。
但是您可以在代码中进行一些改进。首先,您不需要将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)
现在另一件重要的事情是,为了节省您的内存使用量,而不是每次都重新创建一个新菜(20次),您可以在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:)
方法来指定你想要每5秒创建一个新的寿司盘例如:)。
而且,如果您在任何时候需要访问任何这些副本,只需访问dishes
数组即可。
例如,这就是你删除所有副本的方法(如果你把它添加到场景中你必须处理原始菜):
// And just iterate through all of your dish copies:
for dish in dishes {
dish.removeFromParent()
// Do whatever you need here :)
}
它非常简单,它可以让您完美地控制添加到worldNode
的所有对象和/或副本。
如果您有任何其他问题,请告诉我,我很乐意为您提供帮助!
顺便说一句,今晚我会去你正在谈论的寿司餐厅,那个有小火车的那家..很巧合! :d