选择场景中的一个点来放置一个节点(SpriteKit,Swift)

时间:2016-06-13 11:20:52

标签: ios xcode swift touchesbegan

我想这样做,当玩家按下标签时,他必须再次按下屏幕上的一个点来选择建造房屋的地方。到目前为止,这就是我所拥有的:当玩家按下标签" build"时,布尔值(" wantsToBuild")设置为true,但是现在显然房子就建在标签的顶部。我不知道如何检查那个地方是否已经忙碌,或者玩家是否可以在那里建造。我想过有一些占位符,但我不知道如何正确设置它们。你能帮我解决这个问题吗?谢谢。 编辑:我已经根据答案中的建议更改了问题中的代码,但现在我遇到了一些问题:操纵杆(之前我没有提到)移动即使我没有碰到操纵杆本身。即使我已经使用print语句检查了wantToBuild的值,并且它似乎设置为false,每当我按下屏幕时,一个房子总是被建造。你能帮我进一步吗?

类GameScene: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
    }
}

}

3 个答案:

答案 0 :(得分:0)

我认为你的情况不好,我没有什么可以尝试但是我会做这样的事情:

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

答案 1 :(得分:0)

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的说法进行操作,只需在实际的精灵图像中添加一个不可见空间的边框,因此最接近精灵的最近点就是&#39;精灵中的t将足够远,不会重叠。

答案 2 :(得分:0)

所以我实际上设法通过清理代码并更好地使用您的建议来解决问题。不确定它是很棒的代码,但它确实有用。我添加了一个成本和几个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让我走上正轨:)