select场景中的一个点放置一个节点(SpriteKit,Swift)

select a point in the scene to place a node (SpriteKit, Swift)

我想这样做,当玩家按下标签时,他必须再次按下屏幕上的某个点以选择建造房屋的地方。到目前为止,我得到的是:当玩家按下标签 "build" 时,一个布尔值 ("wantsToBuild") 被设置为 true,但现在显然房子建在标签。我不知道如何检查那个地方是否已经很忙,或者玩家是否可以在那里建造。我考虑过使用一些占位符,但我不知道如何正确设置它们。你能帮我解决这个问题吗?谢谢你。 编辑:我已经按照答案中的建议更改了问题中的代码,但现在我遇到了几个问题:操纵杆(我之前没有提到)甚至四处移动如果我不触摸操纵杆本身。另外,即使我已经用打印语句检查了 wantsToBuild 的值,而且它似乎设置为 false,但无论何时,我在屏幕上按下,总是会建造一座房子。你能进一步帮助我吗?

class 游戏场景:SKScene {

var ship  = LCDShip()
var shipSpeed : CGFloat = 0.08
var base = SKSpriteNode(imageNamed: "base")
var joystick = SKSpriteNode(imageNamed: "joystick")
var joystickActive = false

var length:CGFloat! = nil
var xDist:CGFloat! = nil
var yDist:CGFloat! = nil

var deltaVector:CGVector! = nil

let build = SKLabelNode()
var wantsToBuild = false

override func didMoveToView(view: SKView) {

    build.name = "build"
    build.fontName = "Chalkduster"
    build.fontSize = 25
    build.text =  "Build a house"
    build.zPosition = 2
    build.position = CGPoint(x: self.frame.width/2, y: self.frame.height/2)
    addChild(build)


    backgroundColor = SKColor.blackColor()
    ship.position = CGPoint(x: self.frame.width/2, y: self.frame.height/2)
    addChild(ship)

    base.position = CGPoint(x: 150, y: 200)
    base.setScale(2)
    base.alpha = 0.3
    addChild(base)

    joystick.position = base.position
    joystick.setScale(2)
    joystick.alpha = 0.4
    joystick.name = "base"
    addChild(joystick)
}

override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {

    for touch in touches {
        let house = SKSpriteNode(imageNamed: "house")
        let location = touch.locationInNode(self)
        let node = nodeAtPoint(location)
        let label = self.childNodeWithName("build")!

        if node.name == "build"{
            print("where should i build the hosue?")
            wantsToBuild = true
        } else if wantsToBuild == true && node.name != "house" && location.x <= label.position.x - 15 || location.x >= label.position.x + 15 || location.y >= label.position.y + 15 || location.y <= label.position.y - 15 {
            house.position = location
            house.name = "house"
            addChild(house)
            wantsToBuild = false
        }
    }
}
override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) {
    for touch in touches {
        let location = touch.locationInNode(self)
        deltaVector = CGVector(dx: location.x - base.position.x, dy: location.y - base.position.y)

        let angle = atan2(deltaVector.dy, deltaVector.dx)

        length = base.frame.size.height/2

        xDist = sin(angle - 1.57079633) * length
        yDist = cos(angle - 1.57079633) * length

        if(CGRectContainsPoint(base.frame, location)){
            joystick.position = location
        } else {
            joystick.position = CGPointMake(base.position.x - xDist, base.position.y + yDist)
        }

        ship.zRotation = angle - 1.57079633
    }
}

override func update(currentTime: NSTimeInterval) {
    if deltaVector != nil {
        ship.position.x += deltaVector.dx * shipSpeed
        ship.position.y += deltaVector.dy * shipSpeed
    }
}

}

我觉得你的条件不好,我没有什么可以尝试的,但我会这样做:

override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {

    for touch in touches {
        let location = touch.locationInNode(self)
        let node = nodeAtPoint(location)

        if node.name == "build"{
            print("where should i build the house?")
            wantsToBuild = true
        }
        else if wantsToBuild == true && node.name != "house" {
            let sprite = SKSpriteNode(imageNamed: "house")
            sprite.position = location
            sprite.name = "house"
            addChild(sprite)
            wantsToBuild = false
        }
    }
}

Bogy 的方法会奏效,但您可能希望它是 && node.name!= "build",除非您正在建造多栋房屋,在这种情况下您可能需要两者node.name != "build" && node.name != "house"

总之... 这种方法会起作用,除非你的房子精灵足够大,这样当你触摸标签旁边而不是实际标签时,房子可能会与标签重叠,并且基本上仍然在标签的正上方。同样,IDK 精灵大小和所有内容。要处理这种情况,您可以在不允许放置的标签周围创建一个范围,方法是:

 let label = self.childNodeWithName("build")!

 if wantsToBuild == true && (location.x <= label.position.x - 15 || location.x >= label.position.x + 15 || location.y <= label.position.y - 15 || location.y >= label.position.y + 15) {
        let sprite = SKSpriteNode(imageNamed: "house")
        sprite.position = location
        addChild(sprite)
        wantsToBuild = false
    }

这会在标签周围创建一个更大的框,并且不允许您将房子放在该框内,因此如果您使框足够大(您可能需要修改 +15和 - 15's),即使你把它尽可能地靠近标签,你也不能把它放得足够近以至于重叠。

如果你的标签是一个精灵,而不是一个 SKLabelNode,你可以按照 Bogy 所说的那样做,只需在实际的精灵图像上添加一个不可见的边框 space,这样最接近的点不在 sprite 中的 sprite 将距离足够远而不会重叠。

所以我实际上通过清理我的代码并更好地使用您的建议来解决问题。不确定这是很棒的代码,但它确实有效。我添加了成本和更多的 if 语句。这是我现在拥有的,以防有人发现它有用:)

   override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {

    for touch in touches {
        let location = touch.locationInNode(self)
        let node = nodeAtPoint(location)
        if CGRectContainsPoint(base.frame, location){
            joystickActive = true
        }else {
            joystickActive = false
            if node.name == "build" {
                wantsToBuild = true
            } else if node.name != "house" {
                checkPlace(location)
                wantsToBuild = false
            }
        }
    }
}

func checkPlace(location : CGPoint) {
    let label = self.childNodeWithName("build")!
    let deltaX = location.x - label.position.x
    let deltaY = location.y - label.position.y
    let houseRadius : CGFloat = 60

    let distance = sqrt(deltaX * deltaX + deltaY * deltaY)
    if distance <= houseRadius{
        print("YOU CANNOT BUILD HERE")
    } else if distance > houseRadius && wantsToBuild == true{
        if money > 0 {
            buildConstruction(10, location: location)
        }
    }
}

func buildConstruction(cost: Int, location: CGPoint) {
    let house = SKSpriteNode(imageNamed: "house")
    house.position = location
    house.name = "house"
    addChild(house)
    money -= cost
    print(money)
}

再次感谢@Arkidillo 和@Bogy,是他们让我走上了正轨:)