37387


お世話になります。

textureとして、不透明な四角いpng画像を使っています。  
＜画像２＞のように、画像ファイルは色のついた部分だけなのですが、spriteにすると、  
並んだ時に＜画像１＞のように隙間が空いてしまいます。  
隙間を設定するプロパティなどあるのでしょうか？

* * *

＜画像１＞  
[![＜画像１＞](https://i.stack.imgur.com/fwseq.png)](https://i.stack.imgur.com/fwseq.png)

[GameScene.swift]

[code]

    import SpriteKit
    import CoreMotion
    
    class GameScene: SKScene, SKPhysicsContactDelegate {
    
        let ballCount = 3
        let accelerationSpeed : CGFloat = 5
        let textureCount : UInt32 = 4
    
        var textures = [SKTexture]()
    
        let texture_left = SKTexture(imageNamed: "Frame_left")
        let texture_right = SKTexture(imageNamed: "Frame_right")
    
        var motionManager: CMMotionManager!
    
        var ballXposition : Double = 0
        var ballYposition : Double = 0
    
        var accelerationX : Double = 0
        var accelerationY : Double = 0
    
    
    
    
        override func didMove(to view: SKView) {
    
            for i in 0..<textureCount {
                let texture = SKTexture(imageNamed: "Ball_\(i+1)")
                textures.append(texture)
            }
    
            self.physicsWorld.contactDelegate = self
            self.physicsWorld.gravity = CGVector.zero
            self.physicsWorld.speed = 1.0
    
            self.size = CGSize(width: 320, height: 568)
    
            setupObjects()
    
            motionManager = CMMotionManager()
            motionManager.accelerometerUpdateInterval = 0.1
            motionManager.startAccelerometerUpdates(to: OperationQueue.main){data,_ in
                self.accelerationX = data!.acceleration.x
                self.accelerationY = data!.acceleration.y
            }
        }
    
    
        func setupObjects() {
    
            //壁
            let sprite_left = SKSpriteNode(texture: texture_left)
            let sprite_right = SKSpriteNode(texture: texture_right)
    
            sprite_left.position = CGPoint(x: 80, y: 284)
            sprite_right.position = CGPoint(x: 240, y: 284)
    
            sprite_left.physicsBody = SKPhysicsBody(texture: texture_left, size: sprite_left.size)
            sprite_left.physicsBody?.isDynamic = false
            sprite_left.physicsBody?.categoryBitMask = 1 << 0
            sprite_left.physicsBody?.contactTestBitMask = 1 << 1
            sprite_left.physicsBody?.restitution = 0.9
    
            sprite_right.physicsBody = SKPhysicsBody(texture: texture_right, size: sprite_right.size)
            sprite_right.physicsBody?.isDynamic = false
            sprite_right.physicsBody?.categoryBitMask = 1 << 0
            sprite_right.physicsBody?.contactTestBitMask = 1 << 1
            sprite_right.physicsBody?.restitution = 0.9
    
            self.addChild(sprite_left)
            self.addChild(sprite_right)
    
            //Ball
            for i in 0..<ballCount {
                let textureRand = Int(arc4random_uniform(textureCount))
                let ball = SKSpriteNode(texture: textures[textureRand])
                ball.size = CGSize(width: 30, height: 30)
                ball.position = CGPoint(x: self.size.width*0.5, y: self.size.height*0.5+CGFloat(i)*0.1)
                self.addChild(ball)
    
                ball.physicsBody = SKPhysicsBody(texture: textures[textureRand], size: CGSize(width: ball.size.width*1, height: ball.size.height*1))
    
                ball.physicsBody?.categoryBitMask = 1 << 1
                ball.physicsBody?.contactTestBitMask = 1 << 0 | 1 << 1
            }
        }
    
    
        override func update(_ currentTime: TimeInterval) {
    
            self.physicsWorld.gravity = CGVector(dx: CGFloat(self.accelerationX)*accelerationSpeed, dy: CGFloat(self.accelerationY)*accelerationSpeed)
        }
    
    
        func didBegin(_ contact: SKPhysicsContact) {
            print("Contact!")
        }
    }
    
[/code]

[GameViewController.swift]

[code]

    import UIKit
    import SpriteKit
    
    
    class GameViewController: UIViewController {
    
        override func viewDidLoad() {
            super.viewDidLoad()
    
            if let view = self.view as! SKView? {
    
                let scene = GameScene()
                scene.size = view.frame.size
                print(scene.size)
    
                view.presentScene(scene)
                view.ignoresSiblingOrder = true
    
                view.showsFPS = true
                view.showsNodeCount = true
            }
        }
        //...
    }
    
[/code]

「Frame_right」はグリーンの縁の部分の画像です。

＜画像２＞  
[![画像の説明をここに入力](https://i.stack.imgur.com/AN3yV.png)](https://i.stack.imgur.com/AN3yV.png)


CC BY-SA 3.0
2017-08-21T02:59:28.723
37364
2017-09-27T14:07:09.097
2017-09-27T14:07:09.097
369
12297
question
swift ios spritekit
SpriteKitでテクスチャー同士の間に隙間が空いてしまう。


コメントに示しましたが、`SKPhysicsBody.init(texture:size:)`が内部的に使用する輪郭抽出のアルゴリズムでは1point程度の誤差が出るようになっているのではないかと思います。

画像データの中身が真四角であれば、もう少し精度の高い検出ができそうにも思いますが、そう言う場合には`SKPhysicsBody.init(rectangleOf:)`を使うべきなので、特殊な場合の結果だけ最適化するようなことはしていないのだと思われます。

(「思います」「思われます」ばかりで申し訳ありません。)

さて、少し精度を高めるための工夫ですが、Ballについては以下のようなコードを試してみてください。

[code]

        //Ball
        for i in 0..<ballCount {
            let textureRand = Int(arc4random_uniform(textureCount))
            let ball = SKSpriteNode(texture: textures[textureRand])
            //### ball.size = CGSize(width: 30, height: 30) //<-ここではサイズを指定せず
            ball.position = CGPoint(x: self.size.width*0.5, y: self.size.height*0.5+CGFloat(i)*0.1)
            self.addChild(ball)
    
            //### texture本来のサイズのままで輪郭を抽出する
            ball.physicsBody = SKPhysicsBody(texture: textures[textureRand], size: textures[textureRand].size())
    
            ball.physicsBody?.categoryBitMask = 1 << 1
            ball.physicsBody?.contactTestBitMask = 1 << 0 | 1 << 1
    
            ball.scale(to: CGSize(width: 30, height: 30)) //<-ここでスケールを指定して所望の大きさにする
        }
    
[/code]

元画像サイズは200x200ですから、その画像で1point程度の誤差が出ても、表示サイズの30x30まで縮小すれば、誤差も縮小され目立たなくなると言うのを狙っています。

(目立たなくしたせいというよりも物理計算の限界ですが、最初のコメントに示したような「細い黒い筋」は残ってしまうかもしれません。)

なお、物理形状が長方形とわかっているなら`SKPhysicsBody.init(rectangleOf:)`を、円形とわかっているなら`SKPhysicsBody(circleOfRadius:)`を使用した方が、一般的には高速かつ高精度に物理形状を表すことができます。

* * *

`sprite_left`と`sprite_right`については画像データがないので試していませんが、こちらも長方形だとわかっているのであれば、`SKPhysicsBody.init(rectangleOf:)`を使ったり、長方形の組み合わせなのであれば、`SKPhysicsBody.init(bodies:)`を使うと言う手もあります。

最終的にはどのようなやり方があなたの目的に一番合うのかはわかりませんが、お試しください。


CC BY-SA 3.0
2017-08-21T18:51:06.757
37387
2017-08-21T18:51:06.757
13972
37364
answer