我正在Swift 3的SpriteKit中创建一个移动应用程序。我试图创造一个角色必须躲闪的两块岩石。我随机生成了 - >
func createTopRock(){
var topRockChoice = [SKTexture(image: #imageLiteral(resourceName: "rockDown")), SKTexture(image: #imageLiteral(resourceName: "rockGrassDown")), SKTexture(image: #imageLiteral(resourceName: "rockSnowDown")), SKTexture(image: #imageLiteral(resourceName: "rockIceDown"))]
let topRock = SKSpriteNode.init(texture: topRockChoice[mapChoice], size: CGSize(width: (self.scene?.size.width)! / 10, height: (self.scene?.size.height)! / 2.2))
topRock.zPosition = -9
topRock.name = "TopRock"
topRock.position = CGPoint(x: self.frame.width + topRock.size.width * 2, y: frame.maxY - topRock.frame.height / 2)
topRock.physicsBody = SKPhysicsBody(texture: topRockChoice[mapChoice], size: CGSize(width: (self.scene?.size.width)! / 10, height: (self.scene?.size.height)! / 2.2))
topRock.physicsBody?.categoryBitMask = physicsCatagory.topRock
topRock.physicsBody?.collisionBitMask = physicsCatagory.plane
topRock.physicsBody?.contactTestBitMask = physicsCatagory.plane
topRock.physicsBody?.affectedByGravity = false
topRock.physicsBody?.isDynamic = false
self.addChild(topRock)
let randomNumTop = arc4random_uniform(3) + 3
spawnDelayForeverTop = Timer.scheduledTimer(timeInterval: TimeInterval(randomNumTop), target: self, selector: #selector(self.createTopRock), userInfo: nil, repeats: false)
}
func createBtmRock(){
var btmRockChoice = [SKTexture(image: #imageLiteral(resourceName: "rock")), SKTexture(image: #imageLiteral(resourceName: "rockGrass")), SKTexture(image: #imageLiteral(resourceName: "rockSnow")), SKTexture(image: #imageLiteral(resourceName: "rockIce"))]
let btmRock = SKSpriteNode.init(texture: btmRockChoice[mapChoice], size: CGSize(width: (self.scene?.size.width)! / 10, height: (self.scene?.size.height)! / 2.2))
btmRock.zPosition = -9
btmRock.position = CGPoint(x: self.frame.width, y: frame.minY + btmRock.frame.height / 2)
btmRock.name = "BtmRock"
btmRock.physicsBody = SKPhysicsBody(texture: btmRockChoice[mapChoice], size: CGSize(width: (self.scene?.size.width)! / 10, height: (self.scene?.size.height)! / 2.2))
btmRock.physicsBody?.categoryBitMask = physicsCatagory.topRock
btmRock.physicsBody?.collisionBitMask = physicsCatagory.plane
btmRock.physicsBody?.contactTestBitMask = physicsCatagory.plane
btmRock.physicsBody?.affectedByGravity = false
btmRock.physicsBody?.isDynamic = false
self.addChild(btmRock)
let randomNumBtm = arc4random_uniform(2) + 1
spawnDelayForeverBtm = Timer.scheduledTimer(timeInterval: TimeInterval(randomNumBtm), target: self, selector: #selector(createBtmRock), userInfo: nil, repeats: false)
}
从代码中可以看出一切正常。我不想做的一件事就是让它像Flappy Bird一样让btmRock
和topRock
具有相同的位置,以防止我添加了timeIntervals
不同。这在一定程度上起作用;但是玩家仍然遇到几乎无法通过的岩石。
我觉得我错了,我不知道如何解决这个问题。我希望它们足够接近有时候很难但几乎不可能。当我尝试将bool
系统用于创建顶部岩石并且在一定距离内时,不要创建底部岩石。我试图做到这一点的原因是,在那之后我永远不会有底石。提前致谢。
答案 0 :(得分:1)
最后一段中的逻辑似乎是一个合理的解决方案。您需要实现某种自定义逻辑,以防止顶部和底部岩石在某个设定距离内产生。
在createBtmRock
功能中,当您设置新摇滚的位置时,请检查它是否靠近任何现有的顶部岩石。您可以通过比较新岩石的position
属性与所有现有岩石来确定贴近度。
如果您发现新岩石太靠近现有岩石,请不要将新岩石添加到场景中,并继续计时以确保将来生成底部岩石。
这是解决您眼前问题的简单方法。您可能希望研究用于生成岩石的程序生成策略。如果你想稍后改进行为(例如,在游戏进行过程中让岩石更难通过),你将需要一个更持久的解决方案。
考虑创建一个单独的函数,为您的岩石生成位置。您可以单独处理所有位置生成逻辑,并使用结果来定位您的岩石。
func generateRockPositions() -> [CGPoint]
您可以在用户启动游戏时提前执行此操作,或在游戏进行时生成位置。这样您就可以更轻松地在将来对程序生成算法进行更改。
希望这对你的游戏有所帮助!
答案 1 :(得分:1)
我个人不会在我的SpriteKit游戏中使用Timer(因为你可以找到所有的SO)。一个非常简单的解决方案可能是从Update func调用岩石的生成。
我还会创建一个底部底部岩石和基础顶部岩石,并根据需要复制它,因为动态创建物理对象可能会变得昂贵(或者我会在开始时创建一个对象数组并从数组中提取根据需要)
P.S。我把它从袖口上写下来,所以我不能保证拼写错误不存在;)
var genInterval = 4 //How many seconds between rocks on bottom or top (not between top & bottom. that will be half of this value)
var genOffset = genInterval / 2 //offset the bottom rocks half of the interval so that they do't line up
var bottomRock: SKSpriteNode! //your base bottom rock for copying
var topRock: SKSpriteNode! //your base top rock for copying
var updateTopTime: Double = 0
var updateBottomTime: Double = 0
func setupRocks() {
//create the base bottom rock
var btmRockChoice = [SKTexture(image: #imageLiteral(resourceName: "rock")), SKTexture(image: #imageLiteral(resourceName: "rockGrass")), SKTexture(image: #imageLiteral(resourceName: "rockSnow")), SKTexture(image: #imageLiteral(resourceName: "rockIce"))]
bottomRock = SKSpriteNode(texture: btmRockChoice[mapChoice], size: CGSize(width: (self.scene?.size.width)! / 10, height: (self.scene?.size.height)! / 2.2))
btmRock.zPosition = -9
btmRock.position = CGPoint(x: self.frame.width, y: frame.minY + btmRock.frame.height / 2)
btmRock.name = "BtmRock"
btmRock.physicsBody = SKPhysicsBody(texture: btmRockChoice[mapChoice], size: CGSize(width: (self.scene?.size.width)! / 10, height: (self.scene?.size.height)! / 2.2))
btmRock.physicsBody?.categoryBitMask = physicsCatagory.topRock
btmRock.physicsBody?.collisionBitMask = physicsCatagory.plane
btmRock.physicsBody?.contactTestBitMask = physicsCatagory.plane
btmRock.physicsBody?.affectedByGravity = false
btmRock.physicsBody?.isDynamic = false
//create the base top rock
var topRockChoice = [SKTexture(image: #imageLiteral(resourceName: "rockDown")), SKTexture(image: #imageLiteral(resourceName: "rockGrassDown")), SKTexture(image: #imageLiteral(resourceName: "rockSnowDown")), SKTexture(image: #imageLiteral(resourceName: "rockIceDown"))]
topRock = SKSpriteNode(texture: topRockChoice[mapChoice], size: CGSize(width: (self.scene?.size.width)! / 10, height: (self.scene?.size.height)! / 2.2))
topRock.zPosition = -9
topRock.name = "TopRock"
topRock.position = CGPoint(x: self.frame.width + topRock.size.width * 2, y: frame.maxY - topRock.frame.height / 2)
topRock.physicsBody = SKPhysicsBody(texture: topRockChoice[mapChoice], size: CGSize(width: (self.scene?.size.width)! / 10, height: (self.scene?.size.height)! / 2.2))
topRock.physicsBody?.categoryBitMask = physicsCatagory.topRock
topRock.physicsBody?.collisionBitMask = physicsCatagory.plane
topRock.physicsBody?.contactTestBitMask = physicsCatagory.plane
topRock.physicsBody?.affectedByGravity = false
topRock.physicsBody?.isDynamic = false
}
override func update(_ currentTime: CFTimeInterval) {
//optional prevents generation if game is not playing
guard gameState == .playing else { return }
if updateTopTime == 0 {
updateTopTime = currentTime
}
if updateBottomTime == 0 {
updateBottomTime = currentTime
}
if currentTime - updateBottomTime > genOffset {
createBtmRock()
genOffset = genInterval
updateBottomTime = currentTime
}
else if currentTime - updateTopTime > genInterval {
createTopRock()
updateTopTime = currentTime
}
}
func createTopRock() {
//You can make this number a class variable to increase the rate as the game progresses
let randomNum = arc4random_uniform(3)
//there is a 1 in 3 chance that this rock will get created
if randomNum == 1 {
let rock = topRock.copy as! SKSpriteNode()
self.addChild(rock)
}
}
func createBtmRock() {
//You can make this number a class variable to increase the rate as the game progresses
let randomNum = arc4random_uniform(2)
//there is a 1 in 2 chance that this rock will get created
if randomNum == 0 {
let rock = bottomRock.copy as! SKSpriteNode()
self.addChild(rock)
}
}