2022.09.25 Programming  spritekit  swiftui  
 2022.09.19 Programming  swiftui  
 2022.09.11 Programming  swiftui  
 2022.09.04 Programming  swiftui  
 2022.08.28 Programming  spritekit  
 2022.08.28 Programming  spritekit  
 2022.08.28 Programming  spritekit  
 2022.07.31 Programming  spritekit  
 2022.07.10 Programming  spritekit  
 2022.07.03 Programming  spritekit  
 2022.06.26 Programming  spritekit  
 2022.06.19 Programming  spritekit  
 2022.06.14 Programming  spritekit  swiftui  
 2022.06.04 Programming  spritekit  
 2022.05.22 Programming  spritekit  
 2022.05.04 Programming  spritekit  
 2022.04.29 Programming  spritekit  
 2022.04.24 Programming  spritekit  

Swift Learning


node
var spaceship: SKSpriteNode!
var bird = SKSpriteNode()
let player = SKSpriteNode(imageNamed: "girl")
var hearts: [SKSpriteNode] = []
______________________
toggle
var toggle:Bool = true

 func toggleTest() {
  if(toggle){
    videoNode.play()
    toggle = false;
 }else{
   videoNode.pause()
   toggle = true;
 }
_________________________
配列
var word: [String] = []  //空の要素
var namber = [String]()
var data = Array()

var hearts: [SKSpriteNode] = []
var possibleEnemies = ["ball", "hammer", "tv"]
var obstacles: [SKSpriteNode] = []
var items = [String]()
var teleport = [CGPoint]()
var scores: [Int] = [0, 0]
__________________
CGPoint
anchorPoint の初期値は
CGPoint(x: 0.5, y: 0.5)
scene.anchorPoint = CGPoint(x: 0.5, y: 0.5)
ImageNode.anchorPoint = CGPoint(x: 0.5, y: 0.5)//center
ImageNode.position = CGPoint(x: size.width * 0.5, y: size.height * 0.5)
let center = CGPoint(x: frame.midX, y: frame.midY)
label.text = "Hello World!"
label.position = CGPoint(x: self.frame.midX + 200, y: self.frame.midY + 450)
_________________________
SKLabelNode
var scoreLabel: SKLabelNode!
var score: Int = 0 {
didSet {
scoreLabel.text = "SCORE: \(score)"
}
}
class HelloLabel: SKLabelNode {
 init(fontNamed: String) {
   super.init(fontNamed: fontNamed)
   self.text = "Hello, World!"
   self.fontSize = 65;
   self.position = CGPoint(x: 400, y: 500);
 }
}
class GameScene: SKScene {
 override func didMoveToView(view: SKView) {
//let myLabel = SKLabelNode(fontNamed:"Chalkduster")
//myLabel.text = "Hello, World!";
//myLabel.fontSize = 65;
//myLabel.position = CGPoint(x: 400, y: 500);
 let myLabel = HelloLabel(fontNamed: "Chalkduster")
 self.addChild(myLabel)
 }
}
func createScore() {
    scoreLabel = SKLabelNode(fontNamed: "Optima-ExtraBlack")
    scoreLabel.fontSize = 24
    scoreLabel.position = CGPoint(x: frame.midX, y: frame.maxY - 60)
    scoreLabel.text = "SCORE: 0"
    scoreLabel.fontColor = SKColor.black
// scoreLabel.fontName = "Avenir"
// scoreLabel = SKLabelNode(text: "kaisu: 0kai")
    addChild(scoreLabel)
}
________________________
Button(spritekit)

TappedNodes(参照)

//////////////////////
変数・定数 / データ型

// 定数は let
// 変数は var

let msg: String = "hello world"

// Int型で定数定義
let i: Int = 10
let i = 10

// Float Double
let d = 53.8

// String
let s = "hello"

// Bool true/false
let flag = true

var x = "five"
x = String(5)

 
演算子

// 数値
print(10 / 3) // 3
print(10.0 / 3) // 3.3333
print(10 % 3) // 1

var y = 10
//y = y + 5
y += 5
print(y) // 15


// 文字列
print("hello " + "world")
print("y is \(y)")
print("y2 is \(y * 2)")


// 論理値 true false
print(true && false) // false
print(true || false) // true
print(!true) // false

 
条件分岐(if / switch)

// if文
let score = 40
let result: "" // String

// 基本
if score > 80 {
    result = "great"
} else if score > 60 {
    result = "good"
} else {
    result = "so so ..."
}

// 条件演算子
// 条件 ? A : B
result = score > 80 ? "great" : "so so ..."



// switch文
let num = 15

// 基本
switch num {
case 0:
    print("zero")
case 1, 2, 3:
    print("small")
case 4...6:
    print("4/5/6")
case 7..<9:
    print("7/8")
case let n where n > 20:
    print("\(n) is huge!")
default:
//    print("n.a.")
    break
}

 
繰り返し(for / while)

// for 変数 in データの集合 { 処理 }
// break
// continue

for i in 0...5 {
    if i == 3 {
//        break
        continue
    }
    print(i)
}

// while

var n = 10

while n < 3 {
    print(n)
    n += 1
}

//repeat {
//    print(n)
//    n += 1
//} while n < 3

 
配列

// 配列は全て中身が同じ型になる
// 可変長で、繰り返し処理も可能

// 基本
var scores: [Int] = [50, 40]

// 型省略
var scores = [50, 40]

// 取り出し
print(scores[0]) // 50

// 更新
scores[1] = 30

// その他
print(scores.count) // 2
print(scores.isEmpty) // false


// 空の配列
var names = [String]()

// 追加
names.append("田中")
names.append("鈴木")
names += ["佐藤"]

// forで取り出し
for name in names {
    print(name)
}

 
集合(Set)

// 基本(setは重複無視される)
var winners: Set = [3, 5, 8, 8]

// 型の省略
var winners: Set = [3, 5, 8, 8]

// 取り出し
print(winners.contains(3))

// 追加
winners.insert(10)

// 削除
winners.remove(5)

// 空の集合
let s = Set()
print(s.isEmpty)

// 集合の演算
let a: Set = [1, 3, 5, 8]
let b: Set = [3, 5, 8, 9]

print(a.union(b)) // 和集合
print(a.intersection(b)) // 積集合
print(a.subtracting(b)) // 差集合

 
タプル

// タプルは、最初に定義したときに長さが固定(可変長ではない)
// また、型の場所も固定になる(最初の定義時に1番目が文字列型、二番目が数値型だったら、再代入する場合も1番目が文字列型、二番目が数値型でなければならず、違う場合エラーが出る)

var items = ("apple", 5)
print(items.0)
items.1 = 8
print(items)

let (product, amount) = items
print(product)
print(amount)

let (product, _) = items
print(product)

var items = (product: "apple", amount: 5)
print(items.product)

 
辞書(Dictionary)

// 基本
var sales: Dictionary<string, int=""> = ["a": 200, "b": 300]

// 型を省略
var sales = ["a": 200, "b": 300]

// 更新
sales["b"] = 500

// 辞書からの取り出しはオプショナル型を含む可能性があるためunwrap
print(sales["a"] ?? "n.a.")

// 値の追加
sales["c"] = 400

// countで数を取り出す
print(sales.count)

// タプルで分けて取り出す
for (key, value) in sales {
    print("\(key): \(value)")
}

// 空の辞書
let d = [String: Int]()
print(d.isEmpty)

 
Optional型

// nilの可能性を含む型
// 値を取り出す場合はunwrapする必要がある

// 基本
let s: Optional = nil

// 省略形
let s: String? = nil

// unwrapその1
if s != nil {
    print(s!) // unwrap
}

// unwrapその2 (Optional Binding)
if let value = s {
    print(value)
}

// unwrapその3
print(s ?? "this is nil!")

 
inoutキーワード

// 関数の引数は基本は「定数」となる
// 引数で受けた変数に再代入したい場合はinoutキーワードを使う

func add10(x: inout Int) {
    x = x + 10
    print(x)
}

var i = 10
add10(x: &i) // 20
print(i) // 20(iの中身が再代入された値で保存される)

 
 
まとめ

Swiftはバージョンで互換性がなくなって過去のバージョンで作ってたアプリが壊れるらしい。

////////////////////////////////////////////////////////////////////////////
Class
基本

// クラスは「型」として扱う
// 頭は大文字

class User {
    let name: String // propertyと呼ぶ
    var score: Int // property
    init() {
        self.name = "me!"
        self.score = 23
    }
}

// 基本
let user: User = User()

// 省略形
let user = User() // instance

// アクセス・値の変更
print(user.name)
print(user.score)
user.score = 26
print(user.score)

 
イニシャライザ

// 初期化メソッドのこと

class User {
    let name: String
    var score: Int
		
    // イニシャライザ使用時
    init(_ name: String, _ score: Int) {
        self.name = name
        self.score = score
    }
		
    // 引数がなかった時(default設定)
    init() {
        self.name = "bob"
        self.score = 30
    }
}

//let tom = User(name: "tom", score: 23)
let tom = User("tom", 23)
print(tom.name)
print(tom.score)

let bob = User()
print(bob.name)
print(bob.score)

 
計算プロパティ(getとset)

// プロパティを動的に計算させることも可能

class User {
    let name: String
    var score: Int
		
    // 計算プロパティ
    var level: Int {
        get {
            return Int(self.score / 10)
	    // 自明の時はselfの省略可能
        }
        set {
	    // 渡された値をnewValueで受け取ることができる
            if newValue >= 0 {
                score = newValue * 10
            }
        }
    }
		
      // getのみの場合
//    var level: Int {
//        return Int(score / 10)
//    }

    init(_ name: String, _ score: Int) {
        self.name = name
        self.score = score
    }
}

let tom = User("tom", 23)

// getが動く
print(tom.level) // 23/10 = 2

// setに対して値を渡す
tom.level = 5
// すると、scoreが書き換わる
print(tom.score) // 50
// マイナスの値は、newValue >= 0の条件より反応しない
tom.level = -3
// したがって、変化せず50のまま
print(tom.score) // 50

 
プロパティの値の監視(willSetとdidSet)

// willSetとdidSetでプロパティの値の変化を監視できる

class User {
    let name: String
    var score: Int {
		
	// プロパティの値が変わる前の処理
        willSet {
            print("\(score) -> \(newValue)")
	    // newValueで変化後の値を取得可能
        }
				
	// プロパティの値が変わった後の処理
        didSet {
            print("Changed: \(score - oldValue)")
	    // newValueで変化後の値を取得可能
        }
    }
		
    // プロパティが最初に初期化される時は
    // willSetとdidSetは実行されない
    init(_ name: String, _ score: Int) {
        self.name = name
        self.score = score
    }
}

let tom = User("tom", 23)
tom.score = 53
tom.score = 40

 
メソッド作成

class User {
    let name: String
    var score: Int
    init(_ name: String, _ score: Int) {
        self.name = name
        self.score = score
    }
    // method
    func sayHi(_ msg: String) {
        print("\(msg) \(name)")
    }
}

let tom = User("tom", 23)
tom.sayHi("hola")

 
継承

class User {
    let name: String
    var score: Int
    init(_ name: String, _ score: Int) {
        self.name = name
        self.score = score
    }
		
    func sayHi() {
        print("hi \(name)")
    }
    // 頭にfinalをつけるとoverrideされない
}

class AdminUser: User {
    func sayHello() {
        print("hello \(name)")
    }
		
    // 親クラスメソッドの上書き
    override func sayHi() {
        print("[admin] hi \(name)")
    }
}

let tom = User("tom", 23)
let bob = AdminUser("bob", 33)
print(bob.name)
print(bob.score)
bob.sayHi()
bob.sayHello()

 
型プロパティ、型メソッド

class User {
    let name: String
    var score: Int
		
    // 頭にstaticで型プロパティ
    static var count = 0
		
    init(_ name: String, _ score: Int) {
        self.name = name
        self.score = score
				
        // インスタンス化されるたびに、+1
        User.count += 1
    }
    func sayHi() {
        print("hi \(name)")
    }
		
    // override可能な型メソッドにする場合はstaticではなくclass func
    class func getInfo() {
        print("\(count) instances")
    }
}

class AdminUser: User {
    func sayHello() {
        print("hello \(name)")
    }
    override func sayHi() {
        print("[admin] hi \(name)")
    }
    override class func getInfo() {
        print("[admin] \(count) instances")
    }
}

User.getInfo() // 0

let tom = User("tom", 23)
User.getInfo() // 1

AdminUser.getInfo() // 1

let bob = AdminUser("bob", 33)
AdminUser.getInfo() // 2

 
型キャスト(as)

// as  : キャストが成功すると保証されるときに使用(アップキャストなど)
// as! : 強制ダウンキャストの際に使用
// as? : ダウンキャストが成功するか分からない場合に使用(失敗すると戻り値はnil)

class User {
    let name: String
    init(_ name: String) {
        self.name = name
    }
}
class AdminUser: User {}

let tom = User("tom")
let bob = AdminUser("bob")

// User型の配列
// AdminUser型はUser型を継承していることをswiftが判別してくれていて
// エラー出ない
let users: [User] = [tom, bob]

for user in users {
		
    // as?(型キャスト)
    // あるクラスを、他のクラスに変換すること
    // if let文と組み合わせて、
    // AdminUserのみ名前を表示させている
		
    // こっちは一旦User型のuserをAdminUser型に変えてみて、
    // うまくいく場合はuにuserが代入される
    if let u = user as? AdminUser {
        print(u.name)
    }
	
    // こっちはまずuserがAdminUser型か確認している
    // User型のuserをAdminUser型に変えて、
    // 且つoptional型をunwrapする
    if user is AdminUser {
        let u = user as! AdminUser
        print(u.name)
    }
}

 
protocol

// クラスに対して「このプロパティやメソッドは絶対実装してね」という約束をさせるために利用する
// Protocolは継承と違って複数適合させることができる
// Protocol自体がProtocolを継承できる

protocol Printable {
    // 読み込み
    var type: String { get }
	
    // 読み書き可能
    var count: Int { get set }
	
    func printout()
}

class User: Printable {
    let type = "Laser"
    var count = 0
    let name: String
	
    init(_ name: String) {
        self.name = name
    }
	
    func printout() {
        count += 1
        print("\(type): \(count)")
    }
}

let tom = User("tom")
tom.printout()
tom.printout()
tom.printout()

 

extension

// 既存の型に新しいプロパティやメソッドを追加できる仕組み

// String型の拡張
extension String {
    var length: Int {
        return self.characters.count
    }
}

let msg = "hello"

// lengthが使用可能
print(msg.length)


// protocolとextensionを組み合わせる
protocol Printable {
    func printout()
}

extension Printable {
    func printout() {
        print("now printing...")
    }
}

// User型にprotocolを適用
class User: Printable {
    let name: String
    init(_ name: String) {
        self.name = name
    }
}

let tom = User("tom")
tom.printout() // now printing...

//////////////////////////////////////

https://whatsupguys.net/?p=2130

値型と参照型

// Int, Double, Array .. -> 値型
// Class -> 参照型
// 値型と参照型で再代入したときの挙動が異なる

// 値型の場合
var original = 10
var copy = original // originalの値そのもの
original = 20
print(original) // 20
print(copy) // 10

class User {
    var name: String
    init(_ name: String) {
        self.name = name
    }
}

// 参照型の場合
var original = User("tom")
var copy = original // originalが格納されている場所
original.name = "bob"
print(original.name) // "bob"
print(copy.name) // "bob"

 
構造体(struct)

// 構造体
// - クラスとほぼ同機能
// - 値型
// - 継承ができない
// - extension, protocolは使える
// 基本的に一回作ったら値が変わってほしくないようなデータに使用

//class User {
struct User {
    var name: String
    init(_ name: String) {
        self.name = name
    }
	
    // 本来構造体では値の変更ができない
    // 明示的にmutatingを用いると値の変更が可能
    mutating func changeName() {
        self.name = name.uppercased()
    }
}

var original = User("tom")
var copy = original // copy: originalの値
original.name = "bob"
print(original.name) // bob
print(copy.name) // tom

 
列挙型(enum)

// 関連する値をまとめて型にする
// 列挙型は値型

// enumちょっとよくわからん、まだ勉強が必要

enum Direction {
    case right
    case left
}

var dir: Direction.right

switch (dir) {
case .right:
    print("right")
case .left:
    print("left")
}

enum Direction: Int {
    case right = 1
    case left = -1
}

print(Direction.right.rawValue)

 
ジェネリクス

// 汎用化されたデータ型

// TはTypeのT

//func getThree(x: Int) {
func getThree(x: T) {
    print(x)
    print(x)
    print(x)
}
// Int型だけでなく、どの型が引数に与えられても対応できる
getThree(x: 5)
getThree(x: "hello")
getThree(x: 2.3)

subscript

// クラス、構造体、列挙型などにインデックスをつけられる

class Team {
    var members = ["aaa", "bbb", "ccc"]
	
    // インスタンスにインデックスが付与されていた時反応
    subscript(index: Int) -> String {
        get {
            return members[index]
        }
        set {
            members.insert(newValue, at: index)
        }
    }
}

var giants = Team()
print(giants[1]) // bbb
giants[3] = "ddd"
print(giants[3]) // ddd

 
guard文

// 異常処理をわかりやすく書くための仕組み

// if letで書く場合
func sayHi(_ msg: String?) {
    if let s = msg {
        print(s)
    } else {
        print("value not set!")
    }
}

// early returnの場合
func sayHi(_ msg: String?) {
    if msg == nil {
        print("value not set!")
        return
    }
    print(msg!)
}

// guardで書く場合
func sayHi(_ msg: String?) {
    guard let s = msg else {
        print("value not set!")
        return
    }
    print(s)
}

sayHi(nil)
sayHi("hello")

 
例外処理

// 列挙型でエラーパターンを定義
enum LoginError: Error {
    case emptyName
    case shortName
}

class User {
    let name: String
    init(_ name: String) {
        self.name = name
    }
	
    // 例外発生の可能性がある場合、throwsを使う
    func login() throws {
        guard name != "" else {
            throw LoginError.emptyName
        }
        guard name.count > 5 else {
            throw LoginError.shortName
        }
        print("login success")
    }
}

let tom = User("tom")
let tom = User("takahashi")
let tom = User("")

// do catchでエラー表示
do {
    try tom.login()
} catch LoginError.emptyName {
    print("please enter your name")
} catch LoginError.shortName {
    print("too short")
}

 
Optional Chaining

// オプショナル型のnilチェックをスッキリ書くためのもの
// 変数が nil だったら nil を、そうではなかったらその値を含む Optional 型を返す
// nilだった場合も、単に返り値がnilになるだけでエラーにならない

// 非オプショナル型の場合...
//class User {
//    var name: String = ""
//}
//
//let user: User()
//user.name = "him"
//let s = user.name.uppercased()
//print(s)

// オプショナル型の場合
class User {
    // optional宣言の省略型
    var name: String? = ""
}

// optional宣言の省略型
var user: User?
user = User()

// Optional Chaining(後ろに?をつける)
user?.name = "him"
if let s = user?.name?.uppercased() {
    print(s)
}

 
暗黙的 unwrap optional

// Implicitly Unwrapped Optional
// 宣言で「!」をつけることで、値を使う時にUnwrapしなくてもいいOptional型だと理解する

// 通常のoptional型定義(後ろに?)
//var msg: String?

// Implicitly Unwrapped Optional(後ろに!)
var msg: String!
msg = "hello"

// 本来ならunwrap処理が必要であるが、
//if msg != nil {
//    print(msg!)
//}
// この場合はunwrap不要で利用できる
print(msg)
</string,>