SKPhysicsContact body, не может изменять свойства

У меня есть физический контакт SpriteKit, стреляющий в didBegin(contact:). Я беру физическое тело для экземпляра объекта Dot, который хочу переместить за пределы экрана, но когда я пытаюсь изменить его положение таким образом, ничего не происходит:

Первый подход

/* In GameScene.swift */

func didBegin(_ contact: SKPhysicsContact) {
    let dotBody: SKPhysicsBody
    if contact.bodyA.categoryBitMask == 0b1 {
        dotBody = contact.bodyB
    } else {
        dotBody = contact.bodyA
    }

    if let dot = dotBody.node as? Dot {
        dot.position.x = 10000
    }
}

Однако, если я вместо этого вызываю метод в своем классе Dot, передавая это тело, позиция устанавливается правильно:

Второй подход

/* In GameScene.swift */

func didBegin(_ contact: SKPhysicsContact) {
    let dotBody: SKPhysicsBody
    if contact.bodyA.categoryBitMask == 0b1 {
        dotBody = contact.bodyB
    } else {
        dotBody = contact.bodyA
    }

    if let dot = dotBody.node as? Dot {
        dot.move()
    }        
}

Вот класс Dot:

import SpriteKit
class Dot : SKSpriteNode {
    let dotTex = SKTexture(imageNamed: "dot")
    init() {
        super.init(texture: dotTex, color: .clear, size: dotTex.size())
        self.physicsBody = SKPhysicsBody(circleOfRadius: size.width / 2)
        self.physicsBody?.categoryBitMask = 0b1 << 1
        self.physicsBody?.contactTestBitMask = 0b1
    }

    func move() {
        let reset = SKAction.run {
            self.position.x = 10000
        }
        self.run(reset)
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }
}

Может ли кто-нибудь объяснить, почему изменение позиции во втором подходе работает, но не работает в моем первом подходе?

Вот ссылка на проект на Github.


person peacetype    schedule 26.05.2017    source источник
comment
При втором подходе вы меняете положение точки с помощью SKAction. Что произойдет, если вы попробуете первый подход, но с тем же SKAction?   -  person Steve Ives    schedule 26.05.2017
comment
При первом подходе, как перемещаются тела при контакте? Если они перемещаются SKActions, а затем вы вручную устанавливаете положение одного из тел (что вы делаете), это изменение положения может не вступить в силу, если действие движения все еще выполняется.   -  person Steve Ives    schedule 26.05.2017
comment
@Steve Ives - Все движения показаны в коде. В первом подходе я пытаюсь переместить узел прямо из игровой сцены с помощью dot.position.x = 1000. Я не участвую в каких-либо SKA с таким подходом. Второй подход в основном такой же, как и первый, только я использую SKAction для запуска строки dot.position.x = 1000 и делаю это внутри отдельного класса Dot, а не в классе игровой сцены.   -  person peacetype    schedule 26.05.2017
comment
Если это все движение, как тела вступают в контакт?   -  person Steve Ives    schedule 26.05.2017
comment
У меня есть стационарный узел, положение которого я установил с помощью touchesBegan. Таким образом, игрок касается узла точки на экране, и его узел спрайта игрока появляется прямо поверх узла точки. Это момент, когда два тела соприкасаются.   -  person peacetype    schedule 26.05.2017
comment
«Стационарный узел» - это игрок? Установлены ли физические тела узла Player и Dot так, что они сталкиваются? Итак, игрок касается точки, спрайт игрока помещается поверх точки, и точка должна быть немедленно перемещена за пределы экрана? Что происходит на самом деле - точка остается на экране на том же месте (или сбоку) от спрайта игрока?   -  person Steve Ives    schedule 26.05.2017
comment
Да, все правильно подключено к коллизиям. Как вы говорите, точку нужно убрать с экрана, но она остается на месте и не перемещается. Однако второй подход работает должным образом. Я подозреваю, что это как-то связано с тем, что в didBegin(contact:) я беру SKPhysicsBody и преобразую его как объект Dot, а затем пытаюсь напрямую установить его положение. Поскольку я создаю много точечных объектов в сцене, я подозреваю, что попытка создать физическое тело не дает мне ссылки на точечный объект, который мне нужен. Но вроде должно работать, и компилятор ошибок не выдает.   -  person peacetype    schedule 26.05.2017
comment
Мне кажется, вы меняете положение своей точки в другом месте, вы просто не говорите нам об этом   -  person Knight0fDragon    schedule 26.05.2017
comment
Если вы поместите игрока на вершину точки, и они настроены на столкновение (я имею в виду столкновение, а не контакт), то физический движок немедленно попытается переместить их так, чтобы они больше не были поверх друг друга. пока это происходит, вы также устанавливаете положение точки. Это может вызвать проблему. Если вы действительно хотите, чтобы спрайт игрока мог быть помещен поверх точки, вам нужно настроить их «collisionBitMask», чтобы они не сталкивались.   -  person Steve Ives    schedule 26.05.2017
comment
@peacetype Вы не используете SKPhysicsBody как точку, вы используете contact.body как dotBody, а затем dotBody.node как точку. Если вы нажмете опцию на переменную в Xcode, она сообщит вам, что это такое. (dotBody будет SKPhysicsBody, а dot будет точкой).   -  person Steve Ives    schedule 26.05.2017
comment
@Steve Ives - я снова протестировал с параметром collisionBitMask, установленным на 0 как для узлов player, так и для узлов точек, но получил то же поведение. Вы правы насчет кастинга ... Думаю, проблема в этом. Вероятно, из-за того, как создаются экземпляры моих точечных объектов, и я просто не получаю правильную ссылку в моей игровой сцене. Наверное, сложно анализировать, не поделившись проектом целиком. Я пытался сделать это лаконичным, лол   -  person peacetype    schedule 26.05.2017
comment
Верны ли ваши категории физических тел? Если это работает с действием, это странно. Можете ли вы поместить действие движения в 1-й подход?   -  person Steve Ives    schedule 26.05.2017
comment
Есть несколько файлов сцены, поэтому я урезал код и поместил проект на github: github.com/prinomen/dotTest1 < / а>   -  person peacetype    schedule 26.05.2017
comment
@Steve Ives - Я попытался перенести действие в GameScene (как в первом подходе), и это сработало. Думаю, это не слишком удивительно, учитывая, что тот же код работал в классе Dot. Хотя интересно, что это работает в GameScene. Я все еще ломаю голову, почему строка для изменения положения в didBegin(contact:) не работает.   -  person peacetype    schedule 26.05.2017
comment
Интересно - посмотрим, смогу ли я воссоздать проблему.   -  person Steve Ives    schedule 26.05.2017


Ответы (2)


func didBegin(_ contact: SKPhysicsContact) {
  let hitDot = contact.bodyB.node! as! SKSpriteNode
  let hitDot1 = contact.bodyA.node! as! SKSpriteNode
    if hitDot.name? == "dot" || hitDot1.name? == "dot" {
       reset = true
    }        
}

   override func update(_ currentTime: TimeInterval) {
    if reset {
        newDot.position.x = 0
        reset = false
    }
}

В коде могут быть небольшие ошибки, потому что я только что отредактировал здесь. Но надеюсь, что это дает вам идею. Это должно работать без ошибок.

person Chipster Chops    schedule 29.05.2017
comment
Я читал, что это происходит из-за ошибки в spriteKit. Надеюсь, это даст ответ на вопрос. Ваше здоровье - person Chipster Chops; 30.05.2017
comment
Потрясающие! Это работает. Большое спасибо за Вашу помощь. Я думаю, это хороший способ обхода. Интересно знать, что это ошибка в SpriteKit. Это единственное объяснение, которое имеет смысл! Я не мог понять, почему иначе это не работает. - person peacetype; 30.05.2017
comment
Кстати, если у вас есть ссылка на то, что вы читали, в котором указывается, что это поведение является ошибкой, сообщите мне. Может помочь отправить отчет в Apple, если они еще не знают об этой проблеме. - person peacetype; 30.05.2017
comment
Я прочитал это с этого веб-сайта, представленного и одобренного в качестве ответа. Когда я просматривал, что могло быть причиной, но сейчас у меня нет конкретной ссылки. Но я думаю, вы легко можете поискать и найти его. Гудлак с игрой. - person Chipster Chops; 30.05.2017
comment
Здесь вы можете stackoverflow .com / questions / 22810237 / - person Chipster Chops; 30.05.2017

РЕДАКТИРОВАТЬ:

Я думаю, это происходит потому, что вы создаете подкласс SKSpriteNode, а не создаете экземпляр SKSpriteNode. Если вы не собираетесь специализироваться на чем-то еще, я не вижу причин для этого. Вместо этого я использовал эти

import Foundation
import SpriteKit

class Dot {

let dotSprite: SKSpriteNode

init() {
    dotSprite = SKSpriteNode(imageNamed: "Spaceship")
//        dotSprite.physicsBody = SKPhysicsBody(circleOfRadius: dotSprite.size.width/2)
//        dotSprite.physicsBody?.categoryBitMask = 0b1 << 1
//        dotSprite.physicsBody?.contactTestBitMask = 0b1

}

func move() {
    self.dotSprite.position.x = 0
}

func moveAnim(){
    let reset = SKAction.moveTo(x: 0, duration: 3)
    dotSprite.run(reset)
}

}

И в моей SKScene

import SpriteKit
import GameplayKit

class GameScene: SKScene {

let newDot = Dot()


override func didMove(to view: SKView) {

    self.addChild(newDot.dotSprite)
    newDot.dotSprite.setScale(0.5)
    newDot.dotSprite.position = CGPoint(x: frame.midX, y: frame.midY)

}


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

    newDot.dotSprite.position.x = 200
    newDot.moveAnim()

}

}

Обратите внимание, что я отключил физическое тело, потому что я не создал другое тело, на которое оно могло бы приземлиться (чтобы оно продолжало падать). Также я использовал космический корабль в качестве спрайта.

Итак, теперь у вас могут быть любые пользовательские методы в классе точек. Также вы можете напрямую управлять свойствами точки SpriteNode. Также создайте несколько экземпляров. И теперь вы можете изменить его напрямую, когда происходит контакт, или вызвать метод в классе точек для перемещения. Надеюсь, это было полезно. :)

person Chipster Chops    schedule 26.05.2017
comment
Хорошо, я только что попробовал, но все равно безрезультатно. Люди думают, что вы можете переместить узел из didBegin(contact:), изменяя его положение таким образом. Все еще пытаюсь понять, почему он не работает. - person peacetype; 27.05.2017
comment
Спасибо! Это полезный обходной путь. Вы упомянули, что подкласс SKSpriteNode может быть причиной проблемы. Похоже, вы на правильном пути, поскольку SKSpriteNode не имеет свойства с именем position. Однако это заставляет меня задуматься, потому что SKSpriteNode наследуется от SKNode, у которого есть свойство position. Насколько я понимаю, подкласс должен иметь доступ ко всем методам своего суперкласса. Я также не уверен, как использовать этот обходной путь в методе didBegin. Я пробовал сделать это несколькими способами, но получал только ошибки. - person peacetype; 29.05.2017
comment
Я не могу точно сказать, что не так, не глядя на то, что вы делаете в SKScene. Я создал подклассы от SKSpriteNode, и я могу изменить его с начала прикосновений (после того, как я создал экземпляр моего класса Dot). Но я обычно не делаю его подклассом, поскольку я не предоставляю новые свойства или методы. Но это зависит от человека. SKSpriteNode будет иметь позицию, поскольку он унаследован от SKNode. - person Chipster Chops; 30.05.2017
comment
Хорошо, позвольте мне попробовать использовать контакт - person Chipster Chops; 30.05.2017
comment
Кажется, я не могу редактировать свойства непосредственно в контакте didbegin. Но вы можете использовать SKAction. Но вы можете легко создать глобальный Bool, поэтому, когда условие выполнено, установите для него значение true. И используйте его в функции обновления, чтобы внести необходимые изменения. В твоем случае. есть сбросить bool. Установите значение false в перемещении для просмотра. И когда ваше условие выполнено, установите для него значение true в didbegincontact. А в функции обновления просто поставь. если сбросить {ваш код .. reset = false}. Надеюсь это поможет. Позвольте мне выразить это в формате кода в другом ответе - person Chipster Chops; 30.05.2017