Sprite kit 精灵与玩家接触后,敌人精灵跳跃
我做了一个游戏,游戏的基本思想是玩家的精灵必须根据指定给敌人的字母与敌人的精灵碰撞或避免掉落。问题是,当我的玩家与精灵接触时,周围的敌人会明显地向前跳跃。这使得游戏很难玩,因为玩家没有足够的时间离开迎面而来的敌人精灵。这发生在设备和模拟器上 要了解我的意思,请看这段简短的视频。您可以在00:06和00:013看到滞后: 这是我的玩家和敌人联系代码:Sprite kit 精灵与玩家接触后,敌人精灵跳跃,sprite-kit,Sprite Kit,我做了一个游戏,游戏的基本思想是玩家的精灵必须根据指定给敌人的字母与敌人的精灵碰撞或避免掉落。问题是,当我的玩家与精灵接触时,周围的敌人会明显地向前跳跃。这使得游戏很难玩,因为玩家没有足够的时间离开迎面而来的敌人精灵。这发生在设备和模拟器上 要了解我的意思,请看这段简短的视频。您可以在00:06和00:013看到滞后: 这是我的玩家和敌人联系代码: class GameplaySceneClass: SKScene, SKPhysicsContactDelegate { private var
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
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
}
}
}
}
导入SpriteKit
职业球员:斯普瑞泰诺德{
私有变量minX=CGFloat(-300),maxX=CGFloat(300)
func initializePlayer(){
name=“玩家”
physicsBody=SKPhysicsBody(圆形半径:尺寸高度/2)
physicsBody?受重力影响=错误
physicsBody?.isDynamic=错误
physicsBody?.categoryBitMask=ColliderType.PLAYER
physicsBody?.contactTestBitMask=ColliderType.TILE\u和\u
}
func移动(左:布尔){
如果留下{
位置x-=15
如果位置.xmaxX{
位置x=最大值x
}
}
}
}
考虑从SKAction调用checkWord()
方法:
let checkWordsAction = SKAction.run() {
[weak self] in
self?.checkWord()
}
self.run(checkWordsAction)
这样,如果您的数组太大,代码就不会被中断,因为您正在遍历它以检查您的单词
另外,我也不确定当你与炸弹相撞时,你在didbeagin(contact:)
方法末尾的等待动作是什么。如果您试图在重新启动游戏之前等待1秒,请记住,以这种方式调用等待操作不会暂停代码。实际上,它只需将场景闲置1秒,然后在后台重新启动游戏。如果这是预期的效果,也没关系,但是您最好使用运行(\uuuz:completion:)
方法,并从completion闭包调用restartGame()
:
let waitAction = SKAction.wait(1)
self.run(waitAction) { [weak self] in
self?.restartGame()
}
希望这有帮助 在didbeagin(ucontact:skphysiccontact)中,您可以在中创建两个物理实体:
var firstBody = SKPhysicsBody()
var secondBody = SKPhysicsBody()
可能是因为你创建了两个新的物理体,所以产生了延迟。如果不创建物理实体,而只是创建对现有实体的引用,该怎么办?我还没有测试过这个,但也许可以尝试:
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
}
设备上也会发生这种情况吗?您的
数组中有多少字符串。。。如果使用skspritenode的子类并添加一个字母属性或类似的属性,那么您的checkWords方法和检查字母的整个方法可能会更加有效。arrayOfStrings.count是274921。谢谢您的回答,我将按照您的建议尝试一个子类。@user3140521如果您的设备上有20-30 fps的速度来完成这种简单的操作,那么您应该真正更改代码中的某些内容。首先要记住的是,您应该使用地图集。其次,在SKView上,执行SKView.showsdrawscont=true
以查看渲染场景需要多少绘制调用(并在此处公布该数字)。问题显然是您建议的数组大小。我从简单的“滚动你自己的”数组切换到LexicContext,它提供了一个简单而即时的解决方案,只需20美元。可能也有免费的解决方案,但是LexicContext对于文字游戏来说非常容易实现。
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
}