goo blog サービス終了のお知らせ 

タブレット用プログラムの書き止め

android OS & iPadOS の記録。

【Swift P4.6.2】SpriteKit 4 (SwiftUI) 落ちパズルっぽい

2025-05-26 19:52:41 | Swift iPadOS用

今回は落下オブジェクトの周囲回転機能と2タイプオブジェクトの追加。

後は積み上げ機能と消去させる接触グループの調査に対象消去(連鎖)の機能。
消去アニメーション追加。

連鎖が面倒いな。

( 投稿した後にコードの一部が消える。プレビューは正常なのに投稿すると一部が消える…。面倒い。)

【ContentView.swift】
import SwiftUI
import SpriteKit

struct ContentView: View {
    var currentScene = MySKScene()
    init(){
        currentScene.scaleMode = .resizeFill
        currentScene.backgroundColor = .yellow
    }

    var body: some View {
        VStack {
            SpriteView(scene: currentScene)
                .frame(width: currentScene.sceneWidth(), height: currentScene.sceneHeight())
            HStack {
                Button("⬅️"){
                    currentScene.moveLeft()
                }
                Button("🔄"){
                    currentScene.rotation()
                }
                Button("➡️"){
                    currentScene.moveRight()
                }
            }
        }
    }
}


【MyTextures.swift】
import SwiftUI
import SpriteKit

class MyTextures {
    private var _imageTextures:[SKTexture] = []

    func imageTextures(type:Int) -> [SKTexture] {
        switch (type) {
        case 1:
            if let uii = UIImage(systemName: "arrowshape.up.circle" ) {
                _imageTextures.append(SKTexture(image: uii))
            }
            if let uii = UIImage(systemName: "arrowshape.forward.circle" ) {
                _imageTextures.append(SKTexture(image: uii))
            } 
            if let uii = UIImage(systemName: "arrowshape.down.circle" ) {
                _imageTextures.append(SKTexture(image: uii))
            } 
            if let uii = UIImage(systemName: "arrowshape.backward.circle" ) {
                _imageTextures.append(SKTexture(image: uii))
            }
        case 2:
            if let uii = UIImage(systemName: "arrowshape.up.circle.fill" ) {
                _imageTextures.append(SKTexture(image: uii))
            }
            if let uii = UIImage(systemName: "arrowshape.forward.circle.fill" ) {
                _imageTextures.append(SKTexture(image: uii))
            } 
            if let uii = UIImage(systemName: "arrowshape.down.circle.fill" ) {
                _imageTextures.append(SKTexture(image: uii))
            } 
            if let uii = UIImage(systemName: "arrowshape.backward.circle.fill" ) {
                _imageTextures.append(SKTexture(image: uii))
            }
        default: break
            //
        }

        return _imageTextures
    }
}


【MySKScene.swift】
import SwiftUI
import SpriteKit

class MySKScene: SKScene {
    var gameObj0: GameObject = GameObject(x:4,y:0,type:1)
    var gameObj1: GameObject = GameObject(x:5,y:0,type:2)

    var imageSize:CGFloat = 32.0
    // 10x15の2次元配列を0で初期化。グループNOを格納する2次元配列。grid[gridMaxX][gridMaxY]
    let gridMaxX = 10
    let gridMaxY = 15
    var grid = Array(repeating:
            Array(repeating: GameObject(x: 0, y: 0, type: 0), count: 15), count: 10)

    var lastUpdateTime : TimeInterval = 0

    // シーンがViewに表示されたときに実行する処理をdidMoveメソッド内に書きます
    override func didMove(to view: SKView) {
        setGameObj(obj: gameObj0)
        setGameObj(obj: gameObj1)
    }

    //一定時間毎の処理
    override func update(_ currentTime: TimeInterval) {
        if (lastUpdateTime == 0) {
            lastUpdateTime = currentTime
        }
        if (lastUpdateTime + 1.0 <= currentTime) {
            downPosition()
            lastUpdateTime = currentTime
        }
    }
}
extension MySKScene {
    func sceneWidth()-> CGFloat {
        return imageSize * CGFloat(gridMaxX)
    }
    func sceneHeight()-> CGFloat {
        return imageSize * CGFloat(gridMaxY)
    }
    func setGameObj(obj:GameObject) {
        if obj.image != nil {
            obj.image.removeFromParent()
        }
        obj.image = SKSpriteNode()
        obj.image.size = CGSize(width: self.imageSize, height: self.imageSize)
        obj.image.position = getPosition(x: Double(obj.posX), y: Double(obj.posY))

        self.addChild(obj.image)
        obj.image.run(.repeatForever(
            .animate(with: MyTextures().imageTextures(type: obj.type), timePerFrame: 0.3)
        ))
    }
    func removeGameObj(obj:GameObject){
        obj.image.removeFromParent()
    }
    func moveLeft() { // 落下オブジェクトの左移動
        if (gameObj0.posX - 1) >= 0 && (gameObj1.posX - 1) >= 0 { 
            gameObj0.posX -= 1
            gameObj0.image.position = getPosition(x: Double(gameObj0.posX), y: Double(gameObj0.posY))
            gameObj1.posX -= 1
            gameObj1.image.position = getPosition(x: Double(gameObj1.posX), y: Double(gameObj1.posY))
       }
    }
    func moveRight() { // 落下オブジェクトの右移動
        if (gameObj0.posX + 1) <  gridMaxX && (gameObj1.posX + 1) <  gridMaxX { 
            gameObj0.posX += 1
            gameObj0.image.position = getPosition(x: Double(gameObj0.posX), y: Double(gameObj0.posY))
            gameObj1.posX += 1
            gameObj1.image.position = getPosition(x: Double(gameObj1.posX), y: Double(gameObj1.posY))
        }
    }
    func downPosition() { // 落下オブジェクトの下移動
        gameObj0.posY += 1
        if gameObj0.posY >= gridMaxY { 
            gameObj0.posY = 0 // 仮、上に戻している
        }
        gameObj0.image.position = getPosition(x: Double(gameObj0.posX), y: Double(gameObj0.posY))

        gameObj1.posY += 1
        if gameObj1.posY >= gridMaxY { 
            gameObj1.posY = 0 // 仮、上に戻している
        }
        gameObj1.image.position = getPosition(x: Double(gameObj1.posX), y: Double(gameObj1.posY))
    }
    func rotation(){
        if rotationCheck() {return}
        if gameObj0.posY == gameObj1.posY {
            gameObj1.posY += (gameObj0.posX <  gameObj1.posX ? 1: -1)
            gameObj1.posX = gameObj0.posX
        } else if gameObj0.posX == gameObj1.posX {
            gameObj1.posX += (gameObj0.posY <  gameObj1.posY ? -1: 1)
            gameObj1.posY = gameObj0.posY
        }
        gameObj1.image.position = getPosition(x: Double(gameObj1.posX), y: Double(gameObj1.posY))
    }
    private func rotationCheck()-> Bool {
        if gameObj0.posY == 0 &&
            gameObj1.posY == 0 && 
            gameObj0.posX > gameObj1.posX 
        {return true}

        if gameObj0.posY == gridMaxY-1 &&
            gameObj1.posY == gridMaxY-1 && 
            gameObj0.posX <  gameObj1.posX 
        {return true}

        if gameObj0.posX == 0 &&
            gameObj1.posX == 0 &&
            gameObj0.posY <  gameObj1.posY 
        {return true}

        if gameObj0.posX == gridMaxX-1 &&
            gameObj1.posX == gridMaxX-1 &&
            gameObj0.posY > gameObj1.posY 
        {return true}

        return false
    }
    func clearGrid(){ // 2次元配列のクリア
        for i in 0..<  gridMaxX { 
            for j in 0..<  gridMaxY { 
                grid[i][j].clear()
            }
        }
    }
    func getPosition(x:Double, y:Double) -> CGPoint { 
        // 2次元配列の位置(x,y)からSpriteViewの位置に変換する
        return CGPoint(x:32.0 * x + 16.0, y:480.0 - 32.0 * y - 16.0)
    }
}

class GameObject {
    var image: SKSpriteNode!
    var type: Int = 0
    private var _imageGridPositionX = 0 // 落下するオブジェクトのマス目位置
    var posX: Int {
        get {return _imageGridPositionX}
        set { _imageGridPositionX = newValue}
    }
    private var _imageGridPositionY = 0
    var posY: Int {
        get {return _imageGridPositionY}
        set { _imageGridPositionY = newValue}
    }
    init(){
        _imageGridPositionX = 0
        _imageGridPositionY = 0
        self.type = 0
    }
    init(x:Int,y:Int,type:Int){
        setProperties(x:x,y:y,type:type)
    }
    func setProperties(x:Int,y:Int,type:Int){
        _imageGridPositionX = x
        _imageGridPositionY = y
        self.type = type
    }
    func clear(){
        image.removeFromParent()
        image = nil
        _imageGridPositionX = 0
        _imageGridPositionY = 0
        type = 0
    }
}

goo blog 作成者が、このコード消去に対応するには、

<"半角空白" の部分周辺が消える場合がある所の

”<” を全角にするか、"<"の後に半角空白を2個入れる。

表示テキストをHTML文法に変換する時に間違いが起こるのでしょうね。

単純にコードのコピペで済ませたい…。

 


【Swift P4.6.2】SpriteKit 3 (SwiftUI)

2025-05-23 17:57:41 | Swift iPadOS用

落ちものパズルっぽいゲームの基礎部分。
マス目、横10x縦15を想定してオブジェクトを一定時間で落としていく。
底に着くまで左右に動かせる。

マス目の10x15を二次元配列[10、15]に対応させる。
オブジェクトの種類を数値にして配列に積んでいく。
配列の積まれた状態をSpriteViewへ表示する。座標系が異なるので変換させる。
配列の並びを調べてパターンに合致したら消す。
上まで積み上がってしまったらゲームオーバー。

今回は落ちていくオブジェクトの左右移動と一定時間で下へマス目落下させる部分。

【ContentView.swift】

import SwiftUI
import SpriteKit

struct ContentView: View {
 
    var currentScene = MySKScene()
    init(){
        currentScene.scaleMode = .resizeFill
        currentScene.backgroundColor = .yellow
    }
    
    var body: some View {
        VStack {
            SpriteView(scene: currentScene)
                .frame(width: currentScene.sceneWidth(), height: currentScene.sceneHeight())
            HStack {
                Button("⬅️"){
                    currentScene.moveLeft()
                }
                Button("🔄"){
                    // 
                }
                Button("➡️"){
                    currentScene.moveRight()
                }
            }
        }
    }
}

【MySKScene.swift】

import SwiftUI
import SpriteKit

class MySKScene: SKScene {
    
    var image: SKSpriteNode!
    var imageGridPosition = (x:4,y:0) // 落下するオブジェクトのマス目位置
    var imageSize:CGFloat = 32.0
    // 10x15の2次元配列を0で初期化。グループNOを格納する2次元配列
    let gridMaxX = 10
    let gridMaxY = 15
    var grid = Array(repeating: Array(repeating: 0, count: 10), count: 15)
    
    var lastUpdateTime : TimeInterval = 0
    
    // シーンがViewに表示されたときに実行する処理をdidMoveメソッド内に書きます
    override func didMove(to view: SKView) {
        image = SKSpriteNode()
        image.size = CGSize(width: imageSize, height: imageSize)
        image.position = 
            getPosition(x: Double(imageGridPosition.x), y: Double(imageGridPosition.y))
        
        self.addChild(image)
        image.run(.repeatForever(
            .animate(with: MyTextures().imageTextures(), timePerFrame: 0.3)
        ))
    }
    
    //一定時間毎の処理
    override func update(_ currentTime: TimeInterval) {
        if (lastUpdateTime == 0) {
            lastUpdateTime = currentTime
        }
        if (lastUpdateTime + 1.0 <= currentTime) {
            downPosition()
            lastUpdateTime = currentTime
        }
    }
}

extension MySKScene {
    func sceneWidth()-> CGFloat {
        return imageSize * CGFloat(gridMaxX)
    }

    func sceneHeight()-> CGFloat {
        return imageSize * CGFloat(gridMaxY)
    }

    func moveLeft() { // 落下オブジェクトの左移動
        imageGridPosition.x -= 1
        if imageGridPosition.x < 0 {
            imageGridPosition.x = 0
        }

        image.position = getPosition(x: Double(imageGridPosition.x), y: Double(imageGridPosition.y))
    }

    func moveRight() { // 落下オブジェクトの右移動
        imageGridPosition.x += 1
        if imageGridPosition.x >= gridMaxX {
            imageGridPosition.x = gridMaxX - 1
        }

        image.position = getPosition(x: Double(imageGridPosition.x), y: Double(imageGridPosition.y))
    }

    func downPosition() { // 落下オブジェクトの下移動。色々省略中
        imageGridPosition.y += 1
        if imageGridPosition.y >= gridMaxY {
            imageGridPosition.y = 0 // 仮、上に戻している
            // 底に着いたor下に降ろせない時の処理。
        }

        image.position = getPosition(x: Double(imageGridPosition.x), y: Double(imageGridPosition.y))
    }

    func getPosition(x:Double, y:Double) -> CGPoint
    {
        // 2次元配列の位置(x,y)からSpriteViewの位置に変換する
        return CGPoint(x:32.0 * x + 16.0, y:480.0 - 32.0 * y - 16.0)
    }
}

【MyTextures.swift】

import SwiftUI
import SpriteKit

class MyTextures {
    public func imageTextures() -> [SKTexture] {
        return _imageTextures
    }
    private var _imageTextures:[SKTexture] = []

    init() {
        if let uii = UIImage(systemName: "arrowshape.up.circle" ) {
            _imageTextures.append(SKTexture(image: uii))
        }
        if let uii = UIImage(systemName: "arrowshape.forward.circle" ) {
            _imageTextures.append(SKTexture(image: uii))
        } 
        if let uii = UIImage(systemName: "arrowshape.down.circle" ) {
            _imageTextures.append(SKTexture(image: uii))
        } 
        if let uii = UIImage(systemName: "arrowshape.backward.circle" ) {
            _imageTextures.append(SKTexture(image: uii))
        }
    }
}

 


【Swift P4.6.2】SpriteKit 2 (SwiftUI)

2025-05-15 19:22:55 | Swift iPadOS用

SpriteKit でフリックが分からないのでドラッグ(スワイプ)でオブジェクトを動かしています。
View の端でベクトル反転(壁方向)してオブジェクトを弾ませています。

次はオブジェクトのアニメーションと移動ができるので、あまりサンプルで見ない落ちゲーに挑戦できそう。昔、自己流でHTML文書のJavaScriptでWebブラウザの落ちゲーっぽいものを作れたから何とかなるでしょうw

 

View内をドラッグするとその方向にオブジェクトが動くもの。

import SwiftUI
import SpriteKit

struct ContentView: View {
    
    var currentScene: SKScene {
        let scene = MySKScene()
        scene.scaleMode = .resizeFill
        scene.backgroundColor = .yellow
        return scene
    }
    var body: some View {
        ZStack {
            SpriteView(scene: self.currentScene)
                .frame(width: 300, height: 250)
        }
    }
}
class MySKScene: SKScene {
    var image: SKSpriteNode!
    var beforeDragPosition: CGPoint?
    var touchPosition: CGPoint = .zero
    var movementVector: CGPoint = .zero
    var lastUpdateTime : TimeInterval = 0
    var imagePosXMin: CGFloat = .zero
    var imagePosXMax: CGFloat = .zero
    var imagePosYMin: CGFloat = .zero
    var imagePosYMax: CGFloat = .zero
    
    // シーンがViewに表示されたときに実行する処理をdidMoveメソッド内に書きます
    override func didMove(to view: SKView) {
        self.image = SKSpriteNode()
        self.image.size = CGSize(width: 32, height: 32)
        self.image.position = CGPoint(x:CGRectGetMidX(self.frame), y:CGRectGetMidY(self.frame))
        
        self.imagePosXMin = self.image.size.width/2
        self.imagePosXMax = self.size.width - imagePosXMin
        self.imagePosYMin = self.image.size.height/2
        self.imagePosYMax = self.size.height - imagePosYMin
        
        self.addChild(image)
        
        self.image.run(.repeatForever( // SKActionのメソッドと決められているからSKAction省略可能?
            .animate(with: MyTextures().imageTextures(), timePerFrame: 0.3)
        ))
    }
    
    // ドラッグした際に呼ばれる
    override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
        for t in touches {
            self.touchMoved(toPoint: t.location(in: self))
        }
    }
    
    //ドラッグが終了したとき(画面から指が離れたとき)に呼ばれる
    override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
        for t in touches { self.touchUp(atPoint: t.location(in: self)) }
    }
    
    // 指が画面から離れた際に呼ばれる
    func touchUp(atPoint pos : CGPoint){
        // ドラッグ方向をベクトル調整する。動く方向&スピード
        self.movementVector.x = min(max((pos.x - self.touchPosition.x)/5.0,-5.0),5.0)
        self.movementVector.y = min(max((pos.y - self.touchPosition.y)/5.0,-5.0),5.0)
        self.beforeDragPosition = nil
    }
    // 画像の位置を更新
    func touchMoved(toPoint pos : CGPoint) {
        if self.beforeDragPosition == nil {
            self.touchPosition = pos
        }
        if let p1 = self.beforeDragPosition {
            self.image.position.x += pos.x - p1.x
            self.image.position.y += pos.y - p1.y
            // ドラッグ時、SpriteView の左右に飛び出ないようにする
            if ( self.image.position.x
                self.image.position.x = self.imagePosXMin
            }
            else if ( self.image.position.x > self.imagePosXMax ) {
                self.image.position.x = self.imagePosXMax
            }
            // ドラッグ時、SpriteView の上下に飛び出ないようにする
            if ( self.image.position.y
                self.image.position.y = self.imagePosYMin
            }
            else if ( self.image.position.y > self.imagePosYMax ) {
                self.image.position.y = self.imagePosYMax
            }
        }
        self.beforeDragPosition = pos
    }
    
    //一定時間毎の処理
    override func update(_ currentTime: TimeInterval) {
        //...
        if (self.lastUpdateTime == 0) {
            self.lastUpdateTime = currentTime
        }
        if (self.lastUpdateTime + 0.01 <= currentTime) {
            //0.01秒毎に処理
            self.image.position.x += self.movementVector.x
            // SpriteView の左右に飛び出ないようにする
            if ( self.image.position.x <= self.imagePosXMin ) {
                self.image.position.x = self.imagePosXMin
                self.movementVector.x *= -1.0 // 壁に触れたら方向反転
            }
            else if ( self.image.position.x >= self.imagePosXMax ) {
                self.image.position.x = self.imagePosXMax
                self.movementVector.x *= -1.0 
            }
            // SpriteView の上下に飛び出ないようにする
            self.image.position.y += self.movementVector.y
            if ( self.image.position.y <= self.imagePosYMin ) {
                self.image.position.y = self.imagePosYMin
                self.movementVector.y *= -1.0 
            }
            else if ( self.image.position.y >= self.imagePosYMax ) {
                self.image.position.y = self.imagePosYMax
                self.movementVector.y *= -1.0 
            }
            self.lastUpdateTime = currentTime
        }
    }
}


class MyTextures {
    
    public func imageTextures() -> [SKTexture] {
        return _imageTextures
    }
    private var _imageTextures:[SKTexture] = []
    
    init() {
        if let uii = UIImage(systemName: "arrowshape.up.circle" ) {
            _imageTextures.append(SKTexture(image: uii))
        }
        if let uii = UIImage(systemName: "arrowshape.forward.circle" ) {
            _imageTextures.append(SKTexture(image: uii))
        } 
        if let uii = UIImage(systemName: "arrowshape.down.circle" ) {
            _imageTextures.append(SKTexture(image: uii))
        } 
        if let uii = UIImage(systemName: "arrowshape.backward.circle" ) {
            _imageTextures.append(SKTexture(image: uii))
        }
    }
}

 


【Swift P4.6.2】物理エンジンっぽい (SwiftUI)

2025-05-13 20:02:03 | Swift iPadOS用

Apple Developer のサンプルを組み込み。
理解途中、とりあえず弄って動きを確認します。

小さいオブジェクトがグルグル&移動。
SKAction.move() が移動方向なんだろうけど…射出するには?
物理エンジンを使わなくてもできるから程々にしておこうかな。

【ContentView.swift】

import SwiftUI
import SpriteKit

struct ContentView: View {
    
    var currentScene: SKScene {
        let scene = MySKScene()
        scene.scaleMode = .resizeFill
        scene.backgroundColor = .yellow
        return scene
    }
    var body: some View {
        ZStack {
            SpriteView(scene: self.currentScene)
                .frame(width: 300, height: 250)
        }
    }
}

class MySKScene: SKScene {
    var image: SKSpriteNode!
    var beforeDragPosition: CGPoint?

    // シーンがViewに表示されたときに実行する処理をdidMoveメソッド内に書きます
    override func didMove(to view: SKView) {
        
        image = SKSpriteNode()
        image.size = CGSize(width: 32, height: 32)
        // ノードにこれを付けると処理されるみたい。サイズは適当w
        image.physicsBody = SKPhysicsBody(rectangleOf: image.size)
        image.physicsBody?.isDynamic = false // 自由落下OFF

        image.position = CGPoint(x:CGRectGetMidX(self.frame), y:CGRectGetMidY(self.frame))
        
        self.addChild(image)
        
        image.run(.repeatForever( // SKActionのメソッドと決められているからSKAction省略可能?
            .animate(with: MyTextures().imageTextures(), timePerFrame: 0.3)
        ))
        // 新しいノードを追加する
        run(.repeatForever(.sequence(
                [SKAction.run(addNeutron),SKAction.wait(forDuration: 1)]
            )))
    }
    
    func random() -> CGFloat {
        return CGFloat(Float(arc4random()) / 0xFFFFFFFF)
    }
    
    func random(min: CGFloat, max: CGFloat) -> CGFloat {
        return random() * (max - min) + min
    }
    
    func addNeutron() { // 新規追加部分
        
        let neutron = SKSpriteNode()
        neutron.size = CGSize(width: 20, height: 20)
        
        neutron.physicsBody = SKPhysicsBody(rectangleOf: neutron.size)
        neutron.physicsBody?.isDynamic = true
        
        let actualX = random(min: 0, max: size.width)
        let actualY = random(min: 0, max: size.height)
        
        neutron.position = CGPoint(x: actualX, y: actualY)
        addChild(neutron)
        
        neutron.run(.repeatForever(
            .animate(with: MyTextures().imageTextures(), timePerFrame: 0.3)
        ))
        
        let actualDuration = random(min: CGFloat(4.0), max: CGFloat(6.0))
        
        let actualX2 = random(min: 0, max: size.width)
        let actualY2 = random(min: 0, max: size.height)
        
        let actionMove = SKAction.move(to: CGPoint(x: actualX2, y: actualY2), duration: TimeInterval(actualDuration))
        let actionMoveDone = SKAction.removeFromParent()
        
        neutron.run(.sequence([actionMove, actionMoveDone]))
    }
    
    // ドラッグした際に呼ばれる
    override func touchesMoved(_ touches: Set, with event: UIEvent?) {
        for t in touches {
            self.touchMoved(toPoint: t.location(in: self))
        }
    }
    
    //ドラッグが終了したとき(画面から指が離れたとき)に呼ばれる
    override func touchesEnded(_ touches: Set, with event: UIEvent?) {
        for t in touches { self.touchUp(atPoint: t.location(in: self)) }
    }
    
    // 指が画面から離れた際に呼ばれる
    func touchUp(atPoint pos : CGPoint){
        self.beforeDragPosition = nil
    }
    
    // 画像の位置を更新
    func touchMoved(toPoint pos : CGPoint) {
        
        if let p1 = self.beforeDragPosition {
            self.image.position.x += pos.x - p1.x
            self.image.position.y += pos.y - p1.y
            // SpriteView の左右に飛び出ないようにする
            let imagePosXMin = self.image.size.width/2
            let imagePosXMax = self.size.width - imagePosXMin
            if ( self.image.position.x < imagePosXMin ) {
                self.image.position.x = imagePosXMin
            }
            else if ( self.image.position.x > imagePosXMax ) {
                self.image.position.x = imagePosXMax
            }
            // SpriteView の上下に飛び出ないようにする
            let imagePosYMin = self.image.size.height/2
            let imagePosYMax = self.size.height - imagePosYMin
            if ( self.image.position.y < imagePosYMin ) {
                self.image.position.y = imagePosYMin
            }
            else if ( self.image.position.y > imagePosYMax ) {
                self.image.position.y = imagePosYMax
            }
        }
        self.beforeDragPosition = pos
    }
}


【MyTextures.swift】

import SwiftUI
import SpriteKit

public class MyTextures {
    
    public func imageTextures() -> [SKTexture] {
        return _imageTextures
    }
    private var _imageTextures:[SKTexture] = []
    
    init() {
        if let uii = UIImage(systemName: "arrowshape.up.circle" ) {
            _imageTextures.append(SKTexture(image: uii))
        }
        if let uii = UIImage(systemName: "arrowshape.forward.circle" ) {
            _imageTextures.append(SKTexture(image: uii))
        } 
        if let uii = UIImage(systemName: "arrowshape.down.circle" ) {
            _imageTextures.append(SKTexture(image: uii))
        } 
        if let uii = UIImage(systemName: "arrowshape.backward.circle" ) {
            _imageTextures.append(SKTexture(image: uii))
        }
    }
}

 


【Swift P4.6.2】SKTexture 2 (SwiftUI)

2025-05-09 01:37:36 | Swift iPadOS用

SpriteViewの中にスプライト画像を表示し、それをドラッグで移動させる。
テクスチャーの初期化部分をMyTextureクラスに分離しました。

 

【ContentView.swift】

import SwiftUI
import SpriteKit

struct ContentView: View {
    
    var currentScene: SKScene {
        let scene = MySKScene()
        scene.scaleMode = .resizeFill
        scene.backgroundColor = .yellow
        return scene
    }
    var body: some View {
        ZStack {
            SpriteView(scene: self.currentScene)
                .frame(width: 300, height: 250)
        }
    }
}

class MySKScene: SKScene {
    var image: SKSpriteNode!
    var beforeDragPosition: CGPoint?

    // シーンがViewに表示されたときに実行する処理をdidMoveメソッド内に書きます
    override func didMove(to view: SKView) {
        
        image = SKSpriteNode()
        image.size = CGSize(width: 32, height: 32)
        image.position = CGPoint(x:CGRectGetMidX(self.frame), y:CGRectGetMidY(self.frame))
        self.addChild(image)
        
        let action = SKAction.animate(with: MyTextures().imageTextures(), timePerFrame: 0.3)
        image.run(.repeatForever(action))
    }
    
    // ドラッグした際に呼ばれる
    override func touchesMoved(_ touches: Set, with event: UIEvent?) {
        for t in touches {
            self.touchMoved(toPoint: t.location(in: self))
        }
    }
    
    //ドラッグが終了したとき(画面から指が離れたとき)に呼ばれる
    override func touchesEnded(_ touches: Set, with event: UIEvent?) {
        for t in touches { self.touchUp(atPoint: t.location(in: self)) }
    }
    
    // 指が画面から離れた際に呼ばれる
    func touchUp(atPoint pos : CGPoint){
        self.beforeDragPosition = nil
    }
    
     // 画像の位置を更新
     func touchMoved(toPoint pos : CGPoint) {
    
         if let p1 = self.beforeDragPosition {
             self.image.position.x += pos.x - p1.x
             self.image.position.y += pos.y - p1.y
             // SpriteView の左右に飛び出ないようにする
             let imagePosXMin = self.image.size.width/2
             let imagePosXMax = self.size.width - imagePosXMin
             if ( self.image.position.x < imagePosXMin ) {
                 self.image.position.x = imagePosXMin
             }
             else if ( self.image.position.x > imagePosXMax ) {
                 self.image.position.x = imagePosXMax
             }
             // SpriteView の上下に飛び出ないようにする
             let imagePosYMin = self.image.size.height/2
             let imagePosYMax = self.size.height - imagePosYMin
             if ( self.image.position.y < imagePosYMin ) {
                 self.image.position.y = imagePosYMin
             }
             else if ( self.image.position.y > imagePosYMax ) {
                 self.image.position.y = imagePosYMax
             }
         }
         self.beforeDragPosition = pos
     }
}

 

テクスチャーの初期化。
【MyTextures.swift】

import SwiftUI
import SpriteKit

public class MyTextures {
    
    public func imageTextures() -> [SKTexture] {
        return _imageTextures
    }
    private var _imageTextures:[SKTexture] = []
    
    init() {
        if let uii = UIImage(systemName: "arrowshape.up.circle" ) {
            _imageTextures.append(SKTexture(image: uii))
        }
        if let uii = UIImage(systemName: "arrowshape.forward.circle" ) {
            _imageTextures.append(SKTexture(image: uii))
        } 
        if let uii = UIImage(systemName: "arrowshape.down.circle" ) {
            _imageTextures.append(SKTexture(image: uii))
        } 
        if let uii = UIImage(systemName: "arrowshape.backward.circle" ) {
            _imageTextures.append(SKTexture(image: uii))
        }
    }
}

init() {} 内のコードを書き換えました。
UIImageが使えないと思い込み CGImage で設定していました。

 

参考にしたサイトのURLを見失ってしまいました。
見つけ次第掲載します。