67543


Nodeをタッチした際に動作させたいアクションがあるのですが、Nodeのタッチを検出致しません。  
情報不足ございましたらお申し付けください。

【実現したい事】  
class WorldNodeでは画面をスクロール動作する為のコードを記載しています。  
class GameScene内のtouchesEndedでclass WorldNodeのcontentNodeをタッチした際に、class
GameScene内のメソッドを動作させたいです。  
逆にclass WorldNode内のtouchesEndedでclass GameSceneのメソッドを動作させる方法でも良いかなと思ってます。

・タッチしたいNode：class WorldNodeのcontentNode

[code]

    var viewSizeWidth: Int = 375
    var viewSizeHeight: Int = 812
    
    class GameScene: SKScene, SKPhysicsContactDelegate {
    
        var battleship: SKSpriteNode!
    
        let worldNode =  WorldNode(size: CGSize(width: viewSizeWidth * 8, height: viewSizeHeight * 8))
    
        override func didMove(to view: SKView) {
            self.addChild(worldNode)
        }
    
        override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
           let touch = touches.first
           let location = touch!.location(in: self)
    //ここにclass WorldNode内のcontentNodeをタッチした際、class GameScene内のメソッドを動作させたい
        }
    
    //このメソッドをタッチイベントで使用したい。
        func addBattleship() {
            let battleship = SKSpriteNode(imageNamed: "battleship")
            self.battleship = battleship
            battleship.position = CGPoint(x: 0, y: 0)
            battleship.size = CGSize(width: 50, height: 50)
            battleship.zPosition = 2.0
            self.worldNode.contentNode.addChild(battleship)
            let move = SKAction.moveTo(y: 2700, duration: 10)
            battleship.run(move)
        }
    
    }
    
    //WorldNodeでは、画面をtouchesMovedでスクロールする為のコードを書いています。
    class WorldNode: SKSpriteNode {
    
        var contentNode = SKNode()
    
        private var startX: CGFloat = 0.0
        private var lastX: CGFloat = 0.0
        private var startY: CGFloat = 0.0
        private var lastY: CGFloat = 0.0
    
        init(size: CGSize) {
            super.init(texture: nil, color: SKColor.gray, size: size)
            self.isUserInteractionEnabled = true
            self.contentNode.position = CGPoint(x: 0, y: 0)
            self.contentNode.name = "contentNode"
            let ConstraintYRange = SKRange (lowerLimit: self.frame.minY + 500, upperLimit: self.frame.maxY - 500)
            let ConstraintXRange = SKRange (lowerLimit: self.frame.minX + self.frame.maxX / 2, upperLimit: self.frame.maxX - self.frame.maxX / 2)
            let yconst = SKConstraint.positionY(ConstraintYRange)
            let xconst = SKConstraint.positionX(ConstraintXRange)
            contentNode.constraints = [yconst, xconst]
            self.addChild(contentNode)
    
        }
    
        required init?(coder aDecoder: NSCoder) {
            fatalError("init(coder:) has not been implemented")
        }
    
            override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
    
                let touch = touches.first
                let location = touch!.location(in: self)
                startX = location.x
                lastX = location.x
                startY = location.y
                lastY = location.y
            }
    
        override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
            let touch = touches.first
            let location = touch!.location(in: self)
    //ここにclass GameSceneのメソッドを動作させてもOK？（GameSceneのメソッドを引っ張る方法分かりません）
    }
    
            override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
    
                let touch: UITouch = touches.first!
                let location =  touch.location(in: self)
    
                let currentX = location.x
                let currentY = location.y
    
                let scrollspeed: CGFloat = 1.0
                let newX = self.contentNode.position.x + ((currentX - lastX) * scrollspeed)
                let newY = self.contentNode.position.y + ((currentY - lastY) * scrollspeed)
    
                let limitFactir: CGFloat = 100
                let leftLimitX = self.size.width * (-limitFactir)
                let rightLimitX = self.size.width * limitFactir
                let lowLimitY = self.size.height * (-limitFactir)
                let heightLimitY = self.size.height * limitFactir
    
                if newX < leftLimitX && newY < lowLimitY {
                    self.contentNode.position = CGPoint(x: leftLimitX, y: self.contentNode.position.y)
                    self.contentNode.position = CGPoint(x: self.contentNode.position.x, y: lowLimitY)
                } else if newX > rightLimitX && newY > heightLimitY {
                    self.contentNode.position = CGPoint(x: rightLimitX, y: contentNode.position.y)
                    self.contentNode.position  = CGPoint(x: self.contentNode.position.y, y: heightLimitY)
                } else {
                    self.contentNode.position = CGPoint(x: newX, y: self.contentNode.position.y)
                    self.contentNode.position = CGPoint(x: self.contentNode.position.x, y: newY)
                }
    
    
                lastX = currentX
                lastY = currentY
    
            }
        }
    
    
    
    
[/code]


CC BY-SA 4.0
2020-06-09T15:18:26.727
67469
2020-06-11T14:33:39.530
2020-06-11T14:33:39.530
39881
39881
question
swift xcode spritekit
Swift SpriteKit Nodeのタッチ検出方法


おそらく、ですが、期待どおり動かない原因は、次の行、クラス`WorldNode`のイニシアライザ内、

[code]

    self.isUserInteractionEnabled  = true
    
[/code]

です。この行を削除するだけで、期待どおりの結果になる可能性は高いでしょう。

* * *

`SKNode`のプロパティ`isUserInteractionEnabled`は、いったいなんなのか？それはXcodeのドキュメントにあたって、しっかり把握するべきです。

[Instance Property -
isUserInteractionEnabled](https://developer.apple.com/documentation/spritekit/sknode/1483109-isuserinteractionenabled)

このページに、 **Important**
とタイトルがあるコラムがあります。重要といっているのですから、無視せずに、必ず目を通して、なにが書いてあるか理解してください。

> **Important**  
>  In addition to setting isUserInteractionEnabled to true, you  
>  must subclass the node and define event callbacks in order to respond  
>  to user input.

このプロパティ（`isUserInteractionEnabled`）を`true`にするなら、ユーザの入力（画面タッチ）に対するイベント処理を必ず定義しなければいけない。そういう意味のことが書かれています。  
なお、Xcodeのドキュメントでは、いささか表現が婉曲になる傾向が見られます。「may
be」は、「やってもいいかも」くらいのレベルで受け取られがちですが、Xcodeのドキュメントでは「やったほうがいいでしょ」のレベルで使われます。同様に「should」は、「するべき」でなく「しなければいけない」と理解するべきですし、まして「must」と言われたら、「やらないと厄災がふりかかるぞ」という最高級の強制の意味となります。  
ご提示のコードに沿って説明すると、クラス`WorldNode`のプロパティ`isUserInteractionEnabled`は、イニシアライザで`true`になるので、クラス定義の中に、`touchesBegan`、`touchesEnded`などの、ユーザの画面タッチイベントを受け取って、処理するメソッドを定義しなければいけないのですが、実際は定義されていません。そのため、ユーザの画面タッチのイベントは、なんの対処もされることなく、かつ`WorldNode`のインスタンスの段階でイベントに対する処理が完了したとみなされ、そこでイベントが消滅します。よって、クラス`GameScene`のイベント処理メソッド`touchesBegan`は、実行されることはありません。（インスタンス`worldNode`以外の場所をタッチすれば、実行されます）。


CC BY-SA 4.0
2020-06-11T11:03:13.993
67543
2020-06-11T11:03:13.993
18540
67469
answer