昨日は画面構成とモデル/コントローラ/ビューの関係について説明した。
今日はカードの表示を作っていく。
CardNode
カードはSKSpriteNodeを継承したノードとして実装した。
//============================== // BirdHead //------------------------------ // CardNode.swift //============================== import SpriteKit class CardNode: SKSpriteNode { // 続く
画像のロード
カードのノードで使う画像をロードしたりとか。
// 続き private static var faceDownTexture: SKTexture! = nil private static var faceUpTextures = [Int: SKTexture]() private static var disabledFaceDownTexture: SKTexture! = nil private static var disabledFaceUpTextures = [Int: SKTexture]() private(set) static var size: CGSize! = nil class func loadAssets() { let textureAtlas = SKTextureAtlas(named: "Card") CardNode.faceDownTexture = textureAtlas.textureNamed("CardBack") CardNode.disabledFaceDownTexture = textureAtlas.textureNamed("CardBackDisabled") for i in Deck.MinCard...Deck.MaxCard { let textureName = String(format: "Card%02d", i) CardNode.faceUpTextures[i] = textureAtlas.textureNamed(textureName) let disabledTextureName = String(format: "Card%02dDisabled", i) CardNode.disabledFaceUpTextures[i] = textureAtlas.textureNamed(disabledTextureName) } let dummyCard = try! CardNode.get(2, withFaceUp: false) CardNode.size = dummyCard.size } // 続く
画像はテクスチャー・アトラスとして用意してある。
(テクスチャー・アトラスについては、SpriteKitのサンプルコードを読んでみた。(その2) - いものやま。を参照)
なお、手番プレイヤー以外の手札は、暗めに表示したいので、その暗めの状態を「無効状態」として、それ用の画像も用意した。
それと、カードのサイズを参照することがけっこうあるので、ダミーのカードを作ってそのサイズを保持し、参照できるようにしてある。
カードの取得
次はカードの取得。
// 続き class func get(card: Int, withFaceUp: Bool) throws -> CardNode { guard (Deck.MinCard <= card) && (card <= Deck.MaxCard) else { throw Deck.Error.OutOfRange } let cardTexture: SKTexture if withFaceUp { cardTexture = CardNode.faceUpTextures[card]! } else { cardTexture = CardNode.faceDownTexture } return CardNode(card: card, faceUp: withFaceUp, texture: cardTexture) } // 続く
これはクラスメソッドとして、範囲外のカードを取得しようとした場合、例外を投げるようにしてある。
プロパティとイニシャライザ
続いてプロパティとイニシャライザ。
// 続き let card: Int private(set) var isFaceUp: Bool var isDisabled: Bool { didSet { if self.isDisabled { if self.isFaceUp { self.texture = CardNode.disabledFaceUpTextures[self.card]! } else { self.texture = CardNode.disabledFaceDownTexture } } else { if self.isFaceUp { self.texture = CardNode.faceUpTextures[self.card]! } else { self.texture = CardNode.faceDownTexture } } } } private init(card: Int, faceUp: Bool, texture: SKTexture) { self.card = card self.isFaceUp = faceUp self.isDisabled = false super.init(texture: texture, color: SKColor.clearColor(), size: texture.size()) } required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } // 続く
プロパティは、カードの数字、表向きかどうか、無効状態かどうか。
無効状態かどうかにはプロパティオブザーバを追加して、状態が変更されたら画像も変更されるようにした。
カードの表裏の変更
最後にカードの表裏の変更。
// 続き func faceUp() { if !self.isFaceUp { if self.isDisabled { self.texture = CardNode.disabledFaceUpTextures[self.card]! } else { self.texture = CardNode.faceUpTextures[self.card]! } self.isFaceUp = true } } func faceDown() { if self.isFaceUp { if self.isDisabled { self.texture = CardNode.disabledFaceDownTexture } else { self.texture = CardNode.faceDownTexture } self.isFaceUp = false } } }
これもプロパティオブザーバで実装してもよかったのだけど、「カードをめくる」という動作が現実にあるので、メソッドとした方が直感的だと思い、メソッドにした。
今日はここまで!