Swift多节点访问
Posted
技术标签:
【中文标题】Swift多节点访问【英文标题】:Swift multiple node access 【发布时间】:2015-11-11 19:52:05 【问题描述】:假设我们添加了大约 1000 次相同的节点,如下面的代码所示。有什么方法可以访问每个平台吗?
例如,如果 PlatformCategory
和 PlayerCategory
之间发生冲突,则发生冲突的平台应将其颜色更改为绿色并运行 SKAction
。
编辑:感谢 Whirlwind,我可以让与玩家发生碰撞的平台变为绿色,而所有其他平台保持红色。现在我需要正确设置碰撞,这意味着我只希望Player
在它上方时与Platform
碰撞。
例如,玩家从 1. 平台跳到 2. 平台。跳跃时,不能撞到第二个平台,只有经过第二个平台。
class GameScene: SKScene, SKPhysicsContactDelegate
let PlayerCategory : UInt32 = 0x1 << 1
let PlatformCategory : UInt32 = 0x1 << 2
var Platform: SKSpriteNode!
var Player: SKSpriteNode!
override func didMoveToView(view: SKView)
/* Setup your scene here */
self.physicsWorld.contactDelegate = self
self.physicsBody?.velocity = CGVectorMake(0, 0)
.....
SpawnPlayer()
generatePlatforms()
func SpawnPlatforms(position: CGPoint)->SKSpriteNode
Platform = SKSpriteNode(color: SKColor.redColor(), size: CGSize(width: self.frame.size.width, height: 25))
Platform.position = position
Platform.zPosition = 1
Platform.physicsBody = SKPhysicsBody(rectangleOfSize: CGSize(width: self.frame.size.width, height: 25))
Platform.physicsBody?.dynamic = false
Platform.physicsBody?.restitution = 0.0
Platform.physicsBody?.allowsRotation = false
Platform.physicsBody?.usesPreciseCollisionDetection = true
Platform.physicsBody?.categoryBitMask = PlatformCategory
Platform.physicsBody?.contactTestBitMask = PlayerCategory
Platform.physicsBody?.collisionBitMask = PlayerCategory
return Platform
func generatePlatforms()
for i in 1...1000
let position = CGPoint(x: self.frame.size.width / 2, y: 140 * CGFloat(i))
let platform = SpawnPlatforms(position)
self.addChild(platform)
func didBeginContact(contact: SKPhysicsContact)
let contactMask = contact.bodyA.categoryBitMask | contact.bodyB.categoryBitMask
let platform = contact.bodyB.node as! SKSpriteNode
switch(contactMask)
case PlayerCategory | PlatformCategory:
//either the contactMask was the bro type or the ground type
print("Contact Made0")
if(Player.position.y >= platform.position.y && Player.position.y <= platform.position.y + Player.size.height)
Player.physicsBody?.collisionBitMask = PlatformCategory
platform.color = SKColor.greenColor()
default:
return
func didEndContact(contact: SKPhysicsContact)
let contactMask = contact.bodyA.categoryBitMask | contact.bodyB.categoryBitMask
switch(contactMask)
case PlayerCategory | PlatformCategory:
//either the contactMask was the bro type or the ground type
print("Contact Made0")
default:
return
【问题讨论】:
这段代码没有意义,因为在很少创建平台之后,下一个平台将不在屏幕上。接下来是 SpawnPlatforms 方法有问题,因为您没有在本地创建平台节点(或者您不小心错过了那部分代码)。关于实际问题...要检测平台和玩家之间的接触,您必须遵守 SKPhysicsContactDelegate 协议,并将physicsWorld.contactDelegate 属性设置为您的场景。之后,您必须实现 didBeginContact 方法。如果您需要代码示例,请告诉我。 SpawnPlatforms 将在屏幕外创建节点,因为它们都将在 y 轴上向下移动(相机已设置)。我知道如何检测 2 个对象之间的碰撞,唯一的问题在于我创建了 1000 个 SKSpriteNode 节点,而我不能为例如改变与玩家碰撞的平台的颜色,而不是全部。 是的,但它仍然不是一个高效的解决方案...因为屏幕外节点仍在节点树中并占用资源...理想情况下,您应该在屏幕顶部上方生成一个平台,然后向下移动所有平台,然后从底部移除第一个平台。您可以更改平台的颜色。您在 didBeginContact 方法中执行此操作... 碰撞发生时您可以访问平台。为什么你需要一次访问它们?如果您出于某种原因想一次访问它们,您可以将它们全部命名为“Platform”,并以“Platform”的名称枚举子项。我觉得你想多了。只需从SKPhysicsContact
获得平台,您就可以在didBeginContact
获得。
【参考方案1】:
正如我所说,要检测接触以更改平台的颜色,您必须做几件事:
符合 SKPhysicsDelegate 协议 适当设置physicsWorld 的contactDelegate 属性 实现 didBeginContact 方法符合 SKPhysicsDelegate 协议
这个任务的语法很简单:
class GameScene: SKScene,SKPhysicsContactDelegate
//your GameScene properties and methods go here...
符合协议意味着类必须实现该协议所需的方法。 SKPhysicsDelegate 协议的特定方法是 didBeginContact 和 didEndContact。如果你查看头文件,你会看到:
protocol SKPhysicsContactDelegate : NSObjectProtocol
optional func didBeginContact(contact: SKPhysicsContact)
optional func didEndContact(contact: SKPhysicsContact)
即使这些方法是可选的,我们也需要它们来获取描述联系人的联系人对象。
设置physicsWorld联系人委托属性
唯一需要的代码是:
self.physicsWorld.contactDelegate = self //self is a scene (eg. GameScene)
因此,当物理世界中发生物理接触时,我们应该以某种方式得到通知。根据文档,contactDelegate 属性是在发生联系时调用的委托。通过将场景设置为联系人代表,我们将处理联系人的责任委托给它。这应该提到 didBeginContact。
这是你应该如何实现它(可能还有更多的方法):
func didBeginContact(contact: SKPhysicsContact)
var firstBody, secondBody: SKPhysicsBody
if contact.bodyA.categoryBitMask < contact.bodyB.categoryBitMask
firstBody = contact.bodyA
secondBody = contact.bodyB
else
firstBody = contact.bodyB
secondBody = contact.bodyA
if ((firstBody.categoryBitMask & CharacterCategory) != 0 &&
(secondBody.categoryBitMask & PlatformCategory != 0))
//secondBody would be a platform
在这里,您可以像这样轻松更改一个平台的颜色:
let platform = secondBody.node as SKSpriteNode
platform.color = UIColor.redColor()
或者您可以更改所有平台的颜色:
self.enumerateChildNodesWithName("platform", usingBlock:
node, stop in
var platformNode = node as SKSpriteNode
platformNode.color = UIColor.redColor()
)
我还看到你正在使用这个问题的代码:
https://***.com/a/31454044/3402095
所以我对其进行了编辑(更改了 didBeginContact),以在该示例中向您展示如何将精灵的颜色更改为红色。
【讨论】:
首先,很抱歉回复晚了。其次,现在我可以将与玩家碰撞的平台的颜色更改为绿色,而不是更改所有平台的颜色。但是我怎样才能实现播放器仅在其上方时才与平台发生碰撞呢?我编辑了我的代码。 @Albert 你的意思是你想在玩家降落在平台表面后改变平台的颜色? 不,我得到了所有的颜色。我希望只有当玩家在平台上方时才有玩家和平台交叉点,所以如果玩家从底部跳到 1. 平台(通过它),它只会在他通过它后发生碰撞。 @Albert 这里不是已经解决了吗:***.com/a/31454044/3402095 玩家从第一个平台跳下后,会经过第二个平台,落地后停留在上面... 不,因为这段代码实际上不起作用,在大约 3-4 个平台之后,播放器不再与任何东西发生碰撞,有时从一开始就发生了。以上是关于Swift多节点访问的主要内容,如果未能解决你的问题,请参考以下文章
如何访问 SpriteKit 场景编辑器参考节点上自定义类中包含的 Swift 中的变量?
RabbitMQ上手记录–part 4-节点集群(单机多节点)