SpriteKit敌人精灵在与玩家

时间:2017-04-14 15:32:58

标签: sprite-kit

我做了一个游戏,其基本思想是玩家精灵必须与敌人的精灵发生碰撞或避免掉落敌人的精灵,这取决于分配给敌人的信件。问题是,当我的玩家与精灵接触时,周围的敌人会向前跳跃。这使得游戏太难玩了,因为没有足够的时间让玩家摆脱迎面而来的敌人精灵。这发生在设备和模拟器上。

要了解我的意思,请看这个简短的视频。您可以在00:06和00:013看到延迟:https://www.dropbox.com/s/8pp66baxc9uhy26/SimulatorScreenSnapz002.mov?dl=0

这是我的玩家和敌人联系的代码:

class GameplaySceneClass: SKScene, SKPhysicsContactDelegate {

private var player:Player?

private var center = CGFloat()

private var canMove = false, moveLeft = false

private var itemController = ItemController()

private var scoreLabel: SKLabelNode?

private var wordLabel: SKLabelNode?

private var score = 0

private var theWord = ""

private var vowelPressed = false

let correct = SoundSFX("correct.wav")

let wrong = SoundSFX("nomatch.wav")

let explosion = SoundSFX("explosion.wav")

var arrayOfStrings: [String]?

var theCheckedWord = ""

var currentCount = 0

var itemsArray = [String]()

var partialExists = false

var characterScore = 0

var onePointLetters = [12, 14, 18, 19, 20]

var twoPointLetters = [4, 7]

var threePointLetters = [2, 3, 13, 16]

var fourPointLetters = [6, 8, 22, 23, 25]

var fivePointLetters = [11]

var eightPointLetters = [10, 24]

var tenPointLetters = [17, 26]

var letter = 0

var scoreArray = [Int]()

var matchingTerms = [String]()

var gravity:CGFloat = -0.35

var result = CGSize()

let synth = AVSpeechSynthesizer()
var myUtterance = AVSpeechUtterance(string:"")



override func didMove(to view: SKView) {

    SoundEngine.shared.backgroundMusicVolume = 1.0

    SoundEngine.shared.playBackgroundMusic("Jungle Audio-1.m4a", loop: true)

    initializeGame()



}

override func update(_ currentTime: TimeInterval) {
    managePlayer()
}


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

    for touch in touches {

        let location = touch.location (in: self)


        if atPoint(location).name == "LetterA" {

            print ("Letter A pressed")
            vowelPressed = true
            theWord = theWord + "A"
            wordLabel?.text = theWord
            if theWord.characters.count >= 3 {
                checkWord()

            }
             vowelPressed = false

        }

        else if atPoint(location).name == "LetterE" {

        print ("Letter E pressed")
            vowelPressed = true
            theWord = theWord + "E"
            wordLabel?.text = theWord
            if theWord.characters.count >= 3 {
                checkWord()

            }
            vowelPressed = false

    }

        else if atPoint(location).name == "LetterI" {

            print ("Letter I pressed")
            vowelPressed = true
            theWord = theWord + "I"
            wordLabel?.text = theWord
            if theWord.characters.count >= 3 {
                checkWord()

            }

            vowelPressed = false


        }

        else if atPoint(location).name == "LetterO" {

            print ("Letter O pressed")
            vowelPressed = true
            theWord = theWord + "O"
            wordLabel?.text = theWord
            if theWord.characters.count >= 3 {
            checkWord()

            }

            vowelPressed = false

        }

        else if atPoint(location).name == "LetterU" {

            print ("Letter U pressed")
            vowelPressed = true
            theWord = theWord + "U"
            wordLabel?.text = theWord
            if theWord.characters.count >= 3 {
                checkWord()

            }

            vowelPressed = false


        }

        else if atPoint(location).name == "Pause"  {

            showPauseAlert()


        }



        else if atPoint(location).name == "delete" {

            theWord = ""
            theCheckedWord = ""
            wordLabel?.text = theWord

        }





        else {


        if location.x > center && !vowelPressed {

            moveLeft = false
        }

        else if location.x < center && !vowelPressed {

            moveLeft = true
        }



    canMove = true

        }
    }
}

override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
    canMove = false
}

func didBegin(_ contact: SKPhysicsContact) {

    if !gamePaused {

    var firstBody = SKPhysicsBody()
    var secondBody = SKPhysicsBody()

    if contact.bodyA.node?.name == "Player" {

        firstBody = contact.bodyA
        secondBody = contact.bodyB

    }

        else {

            firstBody = contact.bodyB
            secondBody = contact.bodyA

        }

    if firstBody.node?.name == "Player" && secondBody.node?.name == "Tile" {


        letter = secondBody.node?.userData?.value(forKey:"key") as! Int
        print ("The value of letter is \(letter)")
        var letterCode = String(describing: letter)
        var letterValue = Int(letterCode)
        var finalLetterValue = letterValue!+64
        var ASCIICode = Character(UnicodeScalar(finalLetterValue)!)
        var letterString = String(describing:ASCIICode)
        theWord = theWord + letterString
        print (theWord)

        if onePointLetters.contains(letter) {

            characterScore += 1



        }

        else if twoPointLetters.contains(letter) {

            characterScore += 2


        }

        else if threePointLetters.contains(letter) {

            characterScore += 3


        }

        else if fourPointLetters.contains(letter) {

            characterScore += 4
                        }

        else if fivePointLetters.contains(letter) {

            characterScore += 5


        }


        else if eightPointLetters.contains(letter) {

            characterScore += 8

        }

        else if tenPointLetters.contains(letter) {

            characterScore += 10

        }

        wordLabel?.text = theWord
        theCheckedWord = theWord.lowercased()
        print ("The checked word is \(theCheckedWord)")


        checkWord()

        secondBody.node?.removeFromParent()

    }


    if firstBody.node?.name == "Player" && secondBody.node?.name == "Bomb" {

        explosion.play()
        firstBody.node?.removeFromParent()
        secondBody.node?.removeFromParent()
        theWord = ""
        score = 0
        scoreLabel?.text = String(score)
        var delayTimer = SKAction.wait(forDuration:1)
        run (delayTimer)
        restartGame()

    }


}

}



private func initializeGame() {





    do {
        // This solution assumes  you've got the file in your bundle
        if let path = Bundle.main.path(forResource: "en", ofType: "txt"){
            let data = try String(contentsOfFile:path, encoding: String.Encoding.utf8)
            arrayOfStrings = data.components(separatedBy: "\n")

        }
    } catch let err as NSError {
        // do something with Error
        print(err)
    }

    physicsWorld.contactDelegate = self
    physicsWorld.gravity = CGVector(dx:0,dy:gravity)





    player = childNode(withName: "Player") as? Player!
    player?.initializePlayer()
    player?.position = CGPoint(x:0, y: -420)
    scoreLabel = childNode(withName: "ScoreLabel") as? SKLabelNode!
    scoreLabel?.text = String(score)
    wordLabel = childNode(withName:"WordLabel") as? SKLabelNode!
    wordLabel?.text = ""
    center = self.frame.size.width/self.frame.size.height



    var spawnBlocks = SKAction.repeatForever(SKAction.sequence([SKAction.wait(forDuration:1),SKAction.run(spawnItems)]))



    var removeBlocks = SKAction.repeatForever(SKAction.sequence([SKAction.wait(forDuration:1),SKAction.run(removeItems)]))


    if gamePaused == true {

        self.scene?.isPaused = true

    }

    self.run(spawnBlocks)


    self.run(removeBlocks)


}

private func checkWord() {

    theCheckedWord = theWord.lowercased()


    if (arrayOfStrings?.contains(theCheckedWord))! {

        print ("Yes! \(theCheckedWord) is a word")





        correct.play()
        print ("The current value of score is \(score)")
        score += characterScore
        print ("Current gravity setting is \(gravity)")
        scoreLabel?.text = String(score)
        characterScore = 0

        matchingTerms = (arrayOfStrings?.filter({$0.hasPrefix(theCheckedWord)

        }))!


        if matchingTerms.count == 1 {


            characterScore = 0
            print ("Current gravity setting is \(gravity)")
            theWord = ""
            theCheckedWord = ""
            wordLabel?.text = ""


        }

    }



    else if !(arrayOfStrings?.contains(theCheckedWord))! {



        matchingTerms = (arrayOfStrings?.filter({$0.hasPrefix(theCheckedWord)

        }))!



        if matchingTerms.count == 0 {

            wrong.play()

            characterScore = 0

            if score >= 5 {

                score -= 5

            }



            theWord = ""
            theCheckedWord = ""
            wordLabel?.text = ""

        }
    }



}

这是我的敌人代码:

import SpriteKit

struct ColliderType {

static let PLAYER: UInt32 = 0
static let TILE_AND_BOMB: UInt32 = 1;

}


public var bounds = UIScreen.main.bounds
public var width = bounds.size.width
public var height = bounds.size.height


class ItemController {



private var minX = CGFloat(-(width/2)), maxX = CGFloat(width/2)

private var vowelNumbers = [1, 5, 9, 15, 21]

func spawnItems() -> SKSpriteNode {
    let item: SKSpriteNode?

    if Int(randomBetweenNumbers(firstNum: 0, secondNum: 10)) > 7 {
        item = SKSpriteNode(imageNamed: "Bomb")
        item!.name = "Bomb"
        item!.setScale(0.6)
        item!.physicsBody = SKPhysicsBody(circleOfRadius:          item!.size.height / 2)
        print ("The value of width is \(width)")

    } else {
        var num = Int(randomBetweenNumbers(firstNum: 1, secondNum: 26))

        if vowelNumbers.contains(num) {

            num = num + 1
        }

        item = SKSpriteNode(imageNamed: "Tile \(num)")
        item?.userData = NSMutableDictionary()
        item!.name = "Tile"
        item!.userData!.setValue(num, forKey:"key")
        item!.zRotation = 0
        item!.setScale(0.9)
        item!.physicsBody = SKPhysicsBody(circleOfRadius:   item!.size.height / 2)
        if gamePaused == true {

            item!.isPaused = true

        }

        else {

            item!.isPaused = false

        }
    }

    item!.physicsBody?.categoryBitMask = ColliderType.TILE_AND_BOMB;
    item!.physicsBody?.isDynamic = true

    item!.zPosition = 3
    item!.anchorPoint = CGPoint(x: 0.5, y: 0.5)

    item!.position.x = randomBetweenNumbers(firstNum: minX, secondNum: maxX)
    item!.position.y = 600

    return item!
}



func randomBetweenNumbers(firstNum: CGFloat, secondNum: CGFloat) -> CGFloat {
    return CGFloat(arc4random()) / CGFloat(UINT32_MAX) * abs(firstNum - secondNum) + min(firstNum, secondNum);
}

}

这是我的播放器代码:

import SpriteKit

class Player: SKSpriteNode {

private var minX = CGFloat(-300), maxX = CGFloat(300)

func initializePlayer() {

    name = "Player"

    physicsBody = SKPhysicsBody(circleOfRadius: size.height/2)
    physicsBody?.affectedByGravity = false
    physicsBody?.isDynamic = false
    physicsBody?.categoryBitMask = ColliderType.PLAYER
    physicsBody?.contactTestBitMask = ColliderType.TILE_AND_BOMB


  }

 func move(left:Bool){

    if left {
    position.x -= 15

        if position.x < minX {

            position.x = minX
        }

  }
  else {

    position.x += 15

        if position.x > maxX {

            position.x = maxX
        }


     }

   }

}

2 个答案:

答案 0 :(得分:0)

考虑从SKAction调用checkWord()方法:

let checkWordsAction = SKAction.run() {
    [weak self] in
    self?.checkWord()
}
self.run(checkWordsAction)

这样,如果你的数组太大,代码就不会因为你走路来检查你的单词而中断。

此外,当你与炸弹发生碰撞时,我不确定你在didBegin(contact:)方法结束时使用等待动作尝试做什么。如果您在重新启动游戏之前尝试等待1秒钟,请记住,按照您的方式调用等待操作不会暂停代码。实际上它只会让场景空闲1秒钟并在后台重启游戏。如果这是预期的效果,那没关系,但您最好使用run(_:completion:)方法,并从完成闭包中调用restartGame()

let waitAction = SKAction.wait(1)
self.run(waitAction) { [weak self] in
    self?.restartGame()
}

希望这有帮助!

答案 1 :(得分:0)

在didBegin(_ contact:SKPhysicsContact)中,您可以创建两个物理实体:

var firstBody = SKPhysicsBody()
var secondBody = SKPhysicsBody()

因为你创建了两个 new 物理实体,所以可能会创建延迟。如果您不创建物理实体,但只是创建对现有实体的引用,该怎么办?我还没有对此进行过测试,但也许可以尝试:

let firstBody: SKPhysicsBody
let secondBody: SKPhysicsBody

if contact.bodyA.node?.name == "Player" {

    firstBody = contact.bodyA
    secondBody = contact.bodyB
}

else {
    firstBody = contact.bodyB
    secondBody = contact.bodyA
}