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

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

android OS & iPadOS の記録。

【Swift P4.6.2】SKTexture (SwiftUI)

2025-05-07 20:05:24 | Swift iPadOS用

2Dキャラをアニメーションさせる為に画像(png 透明有)を複数用意してアセットフォルダに保存する。

Playgroundアプリ画面の左上の

サイドバー アイコン>追加ファイル アイコン>写真

でアセットフォルダにコピーする画像を選ぶ。
コピー後にファイル名を分かりやすい名前に変更しておく。
透明部分有りのPNGファイルはパソコンで作った方が簡単かな?

動作テストなら写真フォルダ内の適当な画像を設定する。かなり縮小されますが(笑)

【ContentView.swift】

import SwiftUI
import SpriteKit

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

class MySKScene: SKScene {
    
    // シーンがViewに表示されたときに実行する処理をdidMoveメソッド内に書きます
    override func didMove(to view: SKView) {
    
        let node = SKSpriteNode()
        node.size = CGSize(width: 50, height: 50)
        node.position = CGPoint(x:CGRectGetMidX(self.frame), y:CGRectGetMidY(self.frame))
        self.addChild(node)

        //  複数の画像を用意して順次0.3秒で切り替えてアニメーション表示させる
        let textures: [SKTexture] = [
            .init(imageNamed: "Test-a"), // アセット内のファイル名を指定する
            .init(imageNamed: "Test-b"),
            .init(imageNamed: "Test-c")
        ]
        let action = SKAction.animate(with: textures, timePerFrame: 0.3)
        node.run(.repeatForever(action))
    }
}

 

【追記】

システムのアイコンを画像変換して利用をし、アニメーションの確認をするコード。


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 {
    
    // シーンがViewに表示されたときに実行する処理をdidMoveメソッド内に書きます
    override func didMove(to view: SKView) {

        let node = SKSpriteNode()
        node.size = CGSize(width: 50, height: 50)
        node.position = CGPoint(x:CGRectGetMidX(self.frame), y:CGRectGetMidY(self.frame))
        self.addChild(node)

        let dummy = SKTexture(imageNamed: "dummy") // cgiが失敗した時の画像。アセットに用意しておく
        var texture1 = dummy
        if let cgi1 = UIImage(systemName: "arrowshape.up.circle" )?.cgImage { // システムのアイコンを利用する
            texture1 = SKTexture(cgImage: cgi1)
        }
        
        var texture2 = dummy
        if let cgi2 = UIImage(systemName: "arrowshape.forward.circle" )?.cgImage {
            texture2 = SKTexture(cgImage: cgi2)
        } 
        
        var texture3 = dummy
        if let cgi3 = UIImage(systemName: "arrowshape.down.circle" )?.cgImage {
            texture3 = SKTexture(cgImage: cgi3)
        } 
        
        var texture4 = dummy
        if let cgi4 = UIImage(systemName: "arrowshape.backward.circle" )?.cgImage {
            texture4 = SKTexture(cgImage: cgi4)
        } 

         let textures: [SKTexture] = [
            texture1,
            texture2,
            texture3,
            texture4
         ]
         let action = SKAction.animate(with: textures, timePerFrame: 0.3)
         node.run(.repeatForever(action))
    }
}

 


  • X
  • Facebookでシェアする
  • はてなブックマークに追加する
  • LINEでシェアする

【Swift P4.6.2】SpriteKit (SwiftUIで利用)

2025-05-05 00:53:04 | Swift iPadOS用

画像ビュアーを作るにはファイルを開くのにやや面倒だったし、じゃぁ画像編集と思ったけど、PCの方が都合良さそうなのでSwift playground は休止でした。

Playground はゲームも簡単に出来るらしいと言うのでチュートリアルの「ブロック崩し」を見ました。

MyApp.swift が無い。
Main(bookアイコン)から始まってそうだけど、チュートリアル用の型式みたい。
新規アプリ作成でゲームコード選択は無し。
ゲーム作れないジャン。

ブロック崩しのコード仕様は、iPad Swift Playground の書式とは相違があり、新規アプリのファイルにコピペで新規swiftファイルを作るとエラー乱立。
 “Cannot find 〜”
Class 、struct の名前が違うか内容の構成が違うのかスペシャルコード仕様なのか(笑)
iPad Swift Playground ではゼロからブロック崩しのようなゲームアプリを作る手立てが無いのは分かった。

ブロック崩しチュートリアルの意味ないジャン。

仕方ないのでWeb検索しました。
情報少な!(検索ワード設定がムズイ)

少ない情報からSpriteKit クラスを使って、 
ContentView.swift に SwiftUI 上でゲーム用のSpriteViewが作れるのが分かりました。
ゲーム作りは参考書を買って勉強しないと素人はダメのようです。


2Dゲーム用のSpriteViewをSwiftUIに設置する最小コードです。
テキスト表示&回転のみ。

【ContentView.swift 】

import SwiftUI
import SpriteKit

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

class MySKScene: SKScene {
    
    // シーンがViewに表示されたときに実行する処理をdidMoveメソッド内に書きます
    override func didMove(to view: SKView) {
        
        let myLabel = SKLabelNode(fontNamed:"Chalkduster")
        myLabel.text = "Hello, World!";
        myLabel.fontSize = 20;
        myLabel.position = CGPoint(x:CGRectGetMidX(self.frame), y:CGRectGetMidY(self.frame));
        myLabel.fontColor = .red
        self.addChild(myLabel)
        
        // 回転アクションを生成(360度を3秒かけて回転)。それを連続する
        let rotation = SKAction.repeatForever(
            SKAction.rotate(byAngle: .pi*2, duration: 3)
        )
        // アクションをNodeに適用
        myLabel.run(rotation)
    }
}


  • X
  • Facebookでシェアする
  • はてなブックマークに追加する
  • LINEでシェアする

【Swift P4.6.2】ボタンタップアクション

2025-02-18 19:20:23 | Swift iPadOS用

Button()はタップすると明暗変化?している。
ボタン画像をタップした時に拡大縮小してアピールを大きくしたい。
新しい iOS に制限されるけど、androidOSより簡単にアニメーションです。

【MyApp.swift】
@main
struct MyApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
    }
}


【ContentView.swift】
struct ContentView: View {
    var body: some View {
        ButtonView()
    }
}


・ボタンパーツ
 ボタンに使う画像をPNGファイルで用意して背景を透明設定しておくと良い。

【ButtonView.swift】
struct ButtonView: View {
    @State var scale: CGFloat = 2.0 // 大きさ調整
    var body: some View {
        Image(systemName:"arrowshape.forward.circle.fill")
            .gesture(
                TapGesture()
                    .onEnded{_ in
                        ZoomAnimation()
                        /* 処理本体を書く */
                    }
            )
            .scaleEffect(scale)
    }
    
    func ZoomAnimation() { // ボタン代わりの画像を拡大縮小させる
        withAnimation(Animation.linear(duration: 0.1)){ // 変化する時間も設定
            scale = 3.0
        } completion: { // ios17以降?
            withAnimation(Animation.linear(duration: 0.1)){ 
                scale = 2.0
            }
        }
    }
}




  • X
  • Facebookでシェアする
  • はてなブックマークに追加する
  • LINEでシェアする

【Swift P4.6.2】 SlideMenu 改修版

2025-02-15 19:19:40 | Swift iPadOS用

なんちゃってスライドメニュー 2

.offset()を使ってメニューを出し入れするもので条件により不具合が起こるみたい。
原因ははっきりしないけれど、おそらくViewサイズの取得タイミングとかで正確な値が取れないのかもしれない。

なので
.position()を使ってメニューを出し入れします。

位置固定なら.offset()で問題ないんでしょうが変更する事があるのなら.position()を使う方が良さそうです。


【MyApp.swift】

@main
struct MyApp: App {
    @StateObject var dataModel = DataModel()
    var body: some Scene {
        WindowGroup {
            ContentView()
                .environmentObject(dataModel)
        }
    }
}


・Viewサイズは削除してCGPointを返す関数に変更しました。

【DataModel.swift】

class DataModel: ObservableObject {
    @Published var menuWidth: CGFloat = 200.0
    @Published var menuHeight: CGFloat = 300.0
    @Published var showMenu: Bool = true
    @Published var originalImage: UIImage? = UIImage(named: "Test1")

    func MenuPosition() -> CGPoint {
        let x :Double = showMenu ? menuWidth/2.0: -(menuWidth/2.0)
        return CGPoint(x: x, y: menuHeight/2.0+20)
    }
}


・シンプルにしました。

【ContentView.swift】

struct ContentView: View {
    @EnvironmentObject var dataModel: DataModel
    var body: some View {
        ZStack {
            ImageView()
            MenuView()
        }
    }
}


・ここに .position()を付けてメニュー関係をまとめました。

【MenuView.swift】

struct MenuView: View {
    @EnvironmentObject var dataModel: DataModel
    var body: some View {
        HStack(alignment: .top) { 
            ZStack {
                RoundedRectangle(cornerRadius: 15.0)
                    .fill(Color.white)
                    .frame(width: dataModel.menuWidth, height: dataModel.menuHeight )
                    .shadow(color: .black,radius: 10, x: 5, y: 5)
                VStack(alignment:.center, content: {
                    Button("Test1") {
                        withAnimation { 
                            dataModel.originalImage = UIImage(named: "Test1")
                        }
                    }
                    Button("Test2") {
                        withAnimation { 
                            dataModel.originalImage = UIImage(named: "Test2")
                        }
                    }
                })
            }
            Image(systemName: dataModel.showMenu ?  "arrowshape.left.fill":"arrowshape.right.fill")
                .background(Color.white)
                .offset(x:dataModel.showMenu ? -40: 10,y:20)
                .gesture(
                    TapGesture()
                        .onEnded{_ in
                            withAnimation { 
                                dataModel.showMenu.toggle()
                            }
                        }
                )
        }
        .position(dataModel.MenuPosition())
    }
}


・変更無し。

【ImageView.swift】

struct ImageView: View {
    @EnvironmentObject var dataModel: DataModel
    
    var body: some View {
        if let image = dataModel.originalImage {
            Image(uiImage: image)
                .resizable()
                .scaledToFill()
        }
        else {
            Image(systemName: "doc")
            Text("No data")
        }
    }    
}

 


  • X
  • Facebookでシェアする
  • はてなブックマークに追加する
  • LINEでシェアする

【Swift P4.6.2】SlideMenu

2025-02-14 21:09:32 | Swift iPadOS用

なんちゃってスライドメニュー

スイッチボタンをタップするとメニューがスクリーン外へ出て行ったり外から入ってきたりする。

作業用のViewとメニュー用のViewを用意して、ContentViewに配置する。
メニューのViewのオフセットを変更するとメニューがスライドする感じで。
x: を変更すると左右にスライド。
y: を変更すると上下にスライド。

 

【MyApp.swift】

@main
struct MyApp: App {
    @StateObject var dataModel = DataModel()
    var body: some Scene {
        WindowGroup {
            ContentView()
                .environmentObject(dataModel)
        }
    }
}


・分かりやすいようにデータをまとめておく。

【DataModel.swift】

class DataModel: ObservableObject {
    @Published var viewWidth: CGFloat = CGFloat.zero
    @Published var viewHeight: CGFloat = CGFloat.zero
    @Published var menuWidth: CGFloat = 200.0
    @Published var menuHeight: CGFloat = 300.0
    @Published var showMenu: Bool = true
    @Published var originalImage: UIImage? = UIImage(named: "Test1") // フォルダに画像ファイルを用意
    
    func MenuWidthOffset() -> CGFloat {
        let value: CGFloat = (menuWidth - viewWidth)/2.0
        return showMenu ? (value) : (value - menuWidth)
    }
    func MenuHeightOffset() -> CGFloat {
        return (menuHeight - viewHeight)/2.0
    }
}


・ContentViewが表示された時に .onAppearで幅と縦を保存しておく。

【ContentView.swift】

struct ContentView: View {
    @EnvironmentObject var dataModel: DataModel
    var body: some View {
        GeometryReader{ geometry in
            ZStack {
                ImageView()
                MenuView()
                    .offset(x:dataModel.MenuWidthOffset(),y:dataModel.MenuHeightOffset())
            }
            .onAppear{
                dataModel.viewWidth = geometry.size.width
                dataModel.viewHeight = geometry.size.height
            }
        }
    }
}


・基本という事でシンプル構成で。

【MenuView.swift】

struct MenuView: View {
    @EnvironmentObject var dataModel: DataModel
    var body: some View {
        HStack(alignment: .top) { 
            ZStack {
                RoundedRectangle(cornerRadius: 15.0) // メニューの下地
                    .fill(Color.white)
                    .frame(width: dataModel.menuWidth, height: dataModel.menuHeight )
                    .shadow(color: .black,radius: 10 , x: 5, y: 5)
                VStack(alignment: .center, content: {
                    Button("Test1") {
                        withAnimation { // Test1、2、画像ファイルをフォルダに用意した
                            dataModel.originalImage = UIImage(named: "Test1")
                        }
                    }
                    Button("Test2") {
                        withAnimation { 
                            dataModel.originalImage = UIImage(named: "Test2")
                        }
                    }
                })
            }
            // メニューの開閉ボタン。矢印を左向き右向きに切り替え
            Image(systemName: dataModel.showMenu ?  "arrowshape.left.fill":"arrowshape.right.fill")
                .background(Color.white)
                .offset(x:dataModel.showMenu ? -40: 10,y:20) // 微調整(笑)
                .gesture(
                    TapGesture()
                        .onEnded{_ in
                            withAnimation { 
                                dataModel.showMenu.toggle()
                            }
                        }
                )
        }
    }
}


・作業用Viewの代わり。

【ImageView.swift】

struct ImageView: View {
    @EnvironmentObject var dataModel: DataModel
    
    var body: some View {
        if let image = dataModel.originalImage { // 画像ファイル読み込みで問題有無の分岐
            Image(uiImage: image)
                .resizable()
                .scaledToFill()
        }
        else {
            Image(systemName: "doc")
            Text("No data")
        }
    }    
}

 

作成アプリを初回起動した時にメニュー位置がバグります。
終了して起動し直すと正常な位置にメニューが表示されます。
作成ツールのバグか、お行儀がよろしくないか、後で調査する。

 


  • X
  • Facebookでシェアする
  • はてなブックマークに追加する
  • LINEでシェアする