Swift SKSpriteNodeの継承

以前にクラスを初期化してみたら早速壁にぶつかっただいだいですが、今回はもう1歩踏み出し、継承してみました。

 

SKSpriteNodeの継承

まずは赴くまま、Objective-Cライクに下記のように表記したら安定のエラーでした。

 

import SpriteKit

import Foundation

import UIKit

 

class ButtonNode : SKSpriteNode{

    

    var _NormalTexture:SKTexture? //通常時のボタン

    var _PushedTexture:SKTexture? //押下時のボタン

    var _IsContinuePush:Bool      //押し込み式ボタンフラグ(一度押下すると次に押下されるまで押下時画像が表示される)

    var _IsPushed:Bool            //押し込み式の場合のみ使用 現在押されているかどうかのフラグ

 

//----------------------------------------------

//

// 初期化

//

//----------------------------------------------

    init(){

        super.init(){

        }

        _IsContinuePush = false

        _IsPushed = false

    }

    

}

 

エラー文

Cannot invoke 'SKSpriteNode.init' with an argument list of type '*1'

'required' initializer 'init(coder:)' must be provided by subclass of 'SKSpriteNode'

 

親クラスの初期化関係とrequired initializerというものが関係していそ、か?と思って調べてみると、子クラスにイニシャライザのオーバーライドを強制させたいときはrequired修飾子を使うということでしたが詳細はわかりませんがいれときます!あとは、SKSpriteNodeに準備されているイニシャライザの引数に合わせるようにして呼び出すとエラーは消えました。下記はとりあえず意味のない引数を入れてエラーをなくした状態です。

 

import SpriteKit

import Foundation

import UIKit

 

class ButtonNode : SKSpriteNode{

    

    var _NormalTexture:SKTexture? //通常時のボタン

    var _PushedTexture:SKTexture? //押下時のボタン

    var _IsContinuePush:Bool      //押し込み式ボタンフラグ(一度押下すると次に押下されるまで押下時画像が表示される)

    var _IsPushed:Bool            //押し込み式の場合のみ使用 現在押されているかどうかのフラグ

 

//----------------------------------------------

//

// 初期化

//

//----------------------------------------------

    init(){

        _IsContinuePush = false

        _IsPushed = false

        let texture = SKTexture(imageNamed: "test")

        let col = SKColor(red: 1.0, green: 1.0, blue: 1.0, alpha: 1.0)

        super.init(texture: texture, color: col, size: texture.size())

    }

    

    required init?(coder aDecoder: NSCoder) {

        fatalError("init(coder:) has not been implemented")

    }

    

}

 

 親クラスであるSKSpriteNodeはimageNamedのイニシャライザをもっていないのか。。。とりあえずcolorとか入れてしのいでます。

*1:) -> (

アプリ制作記3 ボタンクラスの作成

前回は画面を作って表示するところまでやりましたが、今回はついにボタンをぽちるとイベントが呼ばれるところまでやりたいと思います。

 

まずは画面にボタンの代わりとなるノードを配置

ボタンを設置したいシーンを開いて、SKSpriteNodeを設置します。

f:id:daidaidaily:20180525190113p:plain

 

設置したノードのNameのところに、StartButtonを記入しておきます。まずはゲームを始めるためのスタートボタンを置こうと目論んでます。

f:id:daidaidaily:20180525190307p:plain

 

ボタンクラスの作成

SupportClassのフォルダをプロジェクトに追加して、その中にButtonNode.swiftファイルを作成します。

f:id:daidaidaily:20180525184426p:plain

 

Swiftを試行錯誤しながらがんばって作ったクラスの初期化をもとに、ButtonBodeクラスを宣言して初期化コード作成。

//ボタンクラスの初期化

init(aNormalImage:String, aPushedImage:String, aKey:String){

    _NormalTexture = SKTexture(imageNamed:aNormalImage)

    _PushedTexture = SKTexture(imageNamed:aPushedImage)

    _IsContinuePush = false

    _IsPushed = false

    _IsEnabled = true

    let col = SKColor(red: 1.0, green: 1.0, blue: 1.0, alpha: 1.0)

    super.init(texture:_NormalTexture, color: col, size:_NormalTexture.size())

    //super.initの後にselfを指定

    self.name = aKey

    //タッチ検出機能を有効化

    self.isUserInteractionEnabled = true

}

 

第1引数は通常時のボタン画像、第2引数は押下時のボタン画像です。第3引数はこのボタンを押した時の目印となるキーワードを渡しています。後にシーンクラス上でボタンがタップされたことを判断する時に使用します。

 

isUserInteractionEnabledをtrueにしてタップを有効にしておきます。親クラスの初期化の部分はとりあえず動くようにしただけなので、なんでいきなり色の宣言がでてきたん!?って感じになってますけど、今は目をつぶっています。

 

初期化関数の他にもうひとつ、ボタンの配置とイベント受け取りのための設定をするための関数を作成します。  

var delegate:CButtonDelegate?

//1,delegate指定するscene 2,位置決め用spriteNode

    func SetDelegateAndPosition(aScene:SKScene, aPositionNode:SKSpriteNode){

        //btnのdelegateプロパティにシーンをセット

        self.delegate = aScene as? CButtonDelegate

        //画面にボタンを追加

        aScene.addChild(self)

        //大きさの指定

        self.size = aPositionNode.size

        //位置の指定

        self.position = aPositionNode.position

        //位置決めノードは画面から消してしまう

        aPositionNode.removeFromParent()

    }

//ボタン押下時に呼ばれる関数定義

protocol CButtonDelegate {

    func Pushed(aButton:ButtonNode)

}

 

第1引数はボタンを配置するシーンクラス。ボタンクラス内で宣言したdelegateクラスと紐づけることで、ボタンをタップした時に元のシーンクラスにイベントが飛ぶようにしています。元のシーンクラスではどのボタンを押したかがわかるように分岐が必要になります。

 

第2引数はボタンを設置する場所に置いたSKSpriteNodeクラスです。大きさと位置を取得した後は用済みということで画面から除外しています。

 

シーン側でのイベント受け取り

シーンではボタンクラスの作成と、ボタンイベントを受け取るコードを記述します。

import SpriteKit

import GameplayKit

 

//新しく作った名前「TitleScene」でSKSceneを生成する

class TitleScene: SKScene, CButtonDelegate {

    override func didMove(to: SKView) {

        //ボタンクラス作成

        let StartButton = ButtonNode(aNormalImage: "StartButtonNormal", aPushedImage: "StartButtonPushed", aKey: "StartButtonPushed")

        //ボタンの位置と押下イベント作成

        StartButton.SetDelegateAndPosition(aScene: self, aPositionNode: childNode(withName: "//StartButton") as! SKSpriteNode)

    }

    

    //ボタンクラスで作成したボタンが押された場合に呼ばれる関数

    func Pushed(aButton: ButtonNode) {

        if (aButton.name == "StartButtonPushed") {

            print("スタートボタンが押されました")

        }

    }

 

}

 

この例では、先ほど作成したスタートボタンをタップすると、まずPushed関数が呼ばれます。ボタンを初期化する際に渡したキーワードStartButtonPushedかどうかを判定して、ボタンの名前と一致すればスタートボタンが押されたことを判断します。

 

これで、スタートボタン以外にもボタンを置いて、どのボタンが押されたかを正しく認識できるようになります。

 

例によって試行錯誤でしたが、なんとか狙い通りの動きができまーしーたー。

アプリ制作記2 タイトル画面

前回はとりあえずSwift版のプロジェクトを作りました。今回はタイトル画面を作ってみます。

 

Sceneと画像の追加

フォルダ右クリックからのファイル追加から始めます。

f:id:daidaidaily:20180519090755p:plain

 

SwiftファイルとSpriteKitSceneファイルを追加して、各々をTitleSceneと命名。

f:id:daidaidaily:20180519090902p:plain

f:id:daidaidaily:20180519090911p:plain

 

TitleScene.sksの右上の設定で、このsksに対応するクラスがTitleScene.swift内で指定されたTitleSceneクラスである事を指定しておきます。自分は忘れっぽいので、これをしなかったことでおいおい?表示されんやんなんてことが度々ありました。

f:id:daidaidaily:20180519091451p:plain

 

タイトル画面の絵と、その後使う予定のボタンの絵を通常時と押下時の2パターンつくりました。それを、フォルダごとプロジェクトに含めて、図の左のように整理しておきます。

f:id:daidaidaily:20180519091703p:plain

 

Sceneと画像の連携 からの表示

画像の整理ついでに、図の左のようにSceneも整理。

f:id:daidaidaily:20180519092048p:plain

 

デフォルトで入っているGameSceneとTitleSceneを同じフォルダに入れてまとめただけ。Xcode場でソースコードを移動させると、実際に保存されているファイルも勝手に連動して移動してくれます。整理した後、TitleScene.sks上でColor Spriteをドラッグして設置します。

 

追加したNode設定で、図の右にあるTexture、Position、Sizeを変更して、画面いっぱいいっぱいになるように設定します。

f:id:daidaidaily:20180519092325p:plain

 

最後に、GameViewController内のViewDidLoad関数を下記のように編集し、初期表示画面をGameSceneからTitleSceneに変更します。

 

  override func viewDidLoad() {

        super.viewDidLoad()

        //SKViewを取得

        let skView = self.view as! SKView

        //TitleSceneを生成

        let scene = TitleScene(fileNamed: "TitleScene")

        //画面をフィットさせる

        scene!.scaleMode = .aspectFill

        //現在シーンを設定する。

        skView.presentScene(scene)

    }

 

Swift表記の細かいミスでちょいちょいエラーが出たけど、なんとか実行までこぎつけて、無事テスト機でタイトル画面が表示できました。お疲れ様でした。

f:id:daidaidaily:20180519093917p:plain



アプリ制作記1 Hello Error

Xcodeを無事刷新して、意気揚々とだいだいです。

前回は、今まで怠けてやってなかったOSとXcodeのアップデートをしました。腰が重かった。腰が重かったけど、しょうがない、やらないとしょうがない事もあった。

  

 

Swiftでリバーシを作る!

なんのアプリを作ろうかなあと悩んでいましたが、とりあえずアプリといえばゲームでしょうと落ち着いたので、まずは王道(?)ともいえるリバーシアプリを作りたいと思います。

 

言語は何にしようか?今まではObjective-Cで組んでいたけど、コーディングが冗長な感じがして個人的には使いづらいと感じていたので、これを機にSwiftに挑戦してみようかな。言語全体で見ればまだまだマイナーな言語だと思うけど、とりあえず触ってみてから考えたいと思います^^;

 

実機で動かそうとしたら早速エラー

さっそくきました。まあ、すんなり行くわけないとは思っていたけど^^;

まずはXcodeの新規プロジェクト作成。

f:id:daidaidaily:20180518165056p:plain

 

ゲームの雛形を選択。

f:id:daidaidaily:20180518165146p:plain

 

言語はSwiftに設定。名前はシンプルにReversiあたりかな。

f:id:daidaidaily:20180518165210p:plain

 

とりあえずビルドしてみると、挨拶がわりのエラーが出ました。

f:id:daidaidaily:20180518165249p:plain

 

Code Signing Error: The operation couldn’t be completed. Unable to log in with account '*****'. The login details for account '*****' were rejected.
Code Signing Error: No signing certificate "iOS Development" found: No "iOS Development" signing certificate matching team ID "*******" with a private key was found.
Code Signing Error: Code signing is required for product type 'Application' in SDK 'iOS 11.3'
Code Signing Error: The operation couldn’t be completed. Unable to log in with account '*******'. The login details for account '*******' were rejected.

 

id承認系のエラーな感じはありますが、とりあえずプロジェクトの設定画面にあったビックリマークをなくすべく、下記の2つのボタンを押下。appleIDの承認画面にIDとパスワードを打ち込むと上記のエラーは消えました。

f:id:daidaidaily:20180518165629p:plain

 

その後、新たなエラーが出てきました。

error: Task failed with exit 1 signal 0

 

これについては、Xcodeを再起動して、リビルドしたら消えました。なんだったんだろう。。最後のエラーは謎ですが、とりあえずHello Worldの表示に成功しました!世界よこんにちは。

f:id:daidaidaily:20180518170642p:plain

Swift表記 クラスの初期化

今までObejctive-Cでアプリを作っていただいだいにとって、Swiftは全くの未知の領域です。。。

 

なんでクラスの初期化ができないの?

1つ1つ順調に壁にぶつかっております。岩がごつごつした荒野を生身で歩いています。

まあまあ落ちついてクラスの初期化からやってみよかということで、以下のコードを書いて初期化をしようとしたらすぐエラー出ました。

 

import SpriteKit

import Foundation

import UIKit

 

class ButtonNode{

    

    var _NormalTexture:SKTexture //通常時のボタン

    var _PushedTexture:SKTexture //押下時のボタン

    var _IsContinuePush:Bool     //押し込み式ボタンフラグ(一度押下すると次に押下されるまで押下時画像が表示される)

    var _IsPushed:Bool           //押し込み式の場合のみ使用 現在押されているかどうかのフラグ

 

//----------------------------------------------

//

// 初期化

//

//----------------------------------------------

    init(){

    }

 

}

 

Swiftだと、メンバ変数はコンストラクタ内で初期化しないとエラーになるんですね。

なので、Bool型の2つをfalseで初期化して、SKTextureを空で初期化するにはどうするの??

ここでもう1つ、Swiftではnilで許容する変数宣言として型の最後に?をつける表記があった。そうなのか。

ということで、SKTexture?としてnilを許容しつつnilで初期化するようにして、下記にすることでエラー解消しました。

 

import SpriteKit

import Foundation

import UIKit

 

class ButtonNode{

    

    var _NormalTexture:SKTexture? //通常時のボタン

    var _PushedTexture:SKTexture? //押下時のボタン

    var _IsContinuePush:Bool      //押し込み式ボタンフラグ(一度押下すると次に押下されるまで押下時画像が表示される)

    var _IsPushed:Bool            //押し込み式の場合のみ使用 現在押されているかどうかのフラグ

 

//----------------------------------------------

//

// 初期化

//

//----------------------------------------------

    init(){

        _IsContinuePush = false

        _IsPushed = false

    }

 

}

 

結論、手探り感半端ないけど1こ1こ調べる。

macOSとXcodeの更新

久々にアプリ開発と思ったら、Xcodeのバージョンが古くてテスト端末で実行できなくなっただいだいです。

アップデート怠けたらダメですね!

 

Xcodeがアップデートできない

いつものことながら、Xcodeがすんなりダウンロードできません!

恒例行事のごとく、アップデートを押してもくるくると待機中になるだけ。。

f:id:daidaidaily:20180518113051p:plain

 

おっけーおっけー、OSのアップデートからやればきっと大丈夫なはず。

ダウンロードページからHigh Sierraを落としてインストールしてみました。

スタバwifi頑張った!

f:id:daidaidaily:20180518113131p:plain

f:id:daidaidaily:20180518113126p:plain

 

再度Xcodeをアップデートしようと試してもダウンロードできなかったので、色々ググってみると、アプリケーションの中のXcodeの名前を変えれば大丈夫という記事をいくつか見つけたため、やってみました。

f:id:daidaidaily:20180518113114p:plain

 

それでも結局うまくいかず。。。

 

OSを最新にする事が大事

AppStoreアプリのアップデート欄をよくみて見ると、OSアップデートに追加提供分がまだ残っていましたので、これらもアップデートしときました。

f:id:daidaidaily:20180518113117p:plain

 

そしてようやく、Xcodeもインストールできました!

f:id:daidaidaily:20180518113121p:plain

 

Xcodeがうまく入らないときは、OSのバージョンも確認してみてください。

結論、スタバwifi頑張った!

f:id:daidaidaily:20180518171216p:plain

仕事と趣味の仕事の進め方

考えてから走る or 走りながら考える


仕事の進め方は大きく分類して2種類あります。1つは、はじめに頑張って綿密な計画を立ててから走り出す方法。もう1つは、まずトライしてみて小さな成果を積み重ねていく方法。

前者がフォーターフォール開発、後者がアジャイル開発と呼ばれています。フォーターフォールは「滝」、アジャイルは「俊敏な」という事でしょうか。滝!?


それぞれ良いところもあり、悪いところもありますが、大人数で開発する場合は資料を残す、コミュニケーションをとるという点が重要なことは変わりありません。

  ウォーターフォール アジャイル
利点 ・スケジュール管理しやすい
・開発フローが決定的
・手戻りによる開発ロスが少ない
・仕様変更に対応しやすい
欠点 ・手戻りによる開発ロスが大きい
・仕様変更に対応しにくい
・スケジュール管理しにくい
・開発フローが流動的



ゲームアプリ業界やIT業界など、競争が激しく移り変わる分野では最近アジャイル的開発が盛んですが、企業で使う大規模なシステムとかだと、ウォーターフォール型が好まれているように感じます。

システム系の人は、システム系の仕事は書類を書くことやねんって良く言うけど、開発前や改修時に仕様書やデータモデル関係の書類を本当に書きまくる。

 

仕事と趣味は違います


自分が趣味でアプリを作ったりする場合はアジャイルでやりたいなあ。作りたいと思った事をそのままコードに書いてみて、トライあんどエラーを繰り返したいねん。そうやって作りたいねん。許してな。

 

ただ大事にしたいのは、再利用可能な形でコーディングする事。

色々なアプリを作りたいなあっていう時に、ソースコードも使い回ししたいなあって思うことはよくあることです。そんなとき、便利機能をクラスとして固めておいたり、コピーと最低限の編集で使えるために工夫してコーディングすることは意識します。

 

そこにつながるためにも、ある程度は事前に仕様をまとめて置いた方がいいかもしれない。