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,是他们让我走上了正轨:)
我想这样做,当玩家按下标签时,他必须再次按下屏幕上的某个点以选择建造房屋的地方。到目前为止,我得到的是:当玩家按下标签 "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,是他们让我走上了正轨:)