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を設置します。
設置したノードのNameのところに、StartButtonを記入しておきます。まずはゲームを始めるためのスタートボタンを置こうと目論んでます。
ボタンクラスの作成
SupportClassのフォルダをプロジェクトに追加して、その中にButtonNode.swiftファイルを作成します。
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と画像の追加
フォルダ右クリックからのファイル追加から始めます。
SwiftファイルとSpriteKitSceneファイルを追加して、各々をTitleSceneと命名。
TitleScene.sksの右上の設定で、このsksに対応するクラスがTitleScene.swift内で指定されたTitleSceneクラスである事を指定しておきます。自分は忘れっぽいので、これをしなかったことでおいおい?表示されんやんなんてことが度々ありました。
タイトル画面の絵と、その後使う予定のボタンの絵を通常時と押下時の2パターンつくりました。それを、フォルダごとプロジェクトに含めて、図の左のように整理しておきます。
Sceneと画像の連携 からの表示
画像の整理ついでに、図の左のようにSceneも整理。
デフォルトで入っているGameSceneとTitleSceneを同じフォルダに入れてまとめただけ。Xcode場でソースコードを移動させると、実際に保存されているファイルも勝手に連動して移動してくれます。整理した後、TitleScene.sks上でColor Spriteをドラッグして設置します。
追加したNode設定で、図の右にあるTexture、Position、Sizeを変更して、画面いっぱいいっぱいになるように設定します。
最後に、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表記の細かいミスでちょいちょいエラーが出たけど、なんとか実行までこぎつけて、無事テスト機でタイトル画面が表示できました。お疲れ様でした。
アプリ制作記1 Hello Error
Xcodeを無事刷新して、意気揚々とだいだいです。
前回は、今まで怠けてやってなかったOSとXcodeのアップデートをしました。腰が重かった。腰が重かったけど、しょうがない、やらないとしょうがない事もあった。
Swiftでリバーシを作る!
なんのアプリを作ろうかなあと悩んでいましたが、とりあえずアプリといえばゲームでしょうと落ち着いたので、まずは王道(?)ともいえるリバーシアプリを作りたいと思います。
言語は何にしようか?今まではObjective-Cで組んでいたけど、コーディングが冗長な感じがして個人的には使いづらいと感じていたので、これを機にSwiftに挑戦してみようかな。言語全体で見ればまだまだマイナーな言語だと思うけど、とりあえず触ってみてから考えたいと思います^^;
実機で動かそうとしたら早速エラー
さっそくきました。まあ、すんなり行くわけないとは思っていたけど^^;
まずはXcodeの新規プロジェクト作成。
ゲームの雛形を選択。
言語はSwiftに設定。名前はシンプルにReversiあたりかな。
とりあえずビルドしてみると、挨拶がわりのエラーが出ました。
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とパスワードを打ち込むと上記のエラーは消えました。
その後、新たなエラーが出てきました。
error: Task failed with exit 1 signal 0
これについては、Xcodeを再起動して、リビルドしたら消えました。なんだったんだろう。。最後のエラーは謎ですが、とりあえずHello Worldの表示に成功しました!世界よこんにちは。
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がすんなりダウンロードできません!
恒例行事のごとく、アップデートを押してもくるくると待機中になるだけ。。
おっけーおっけー、OSのアップデートからやればきっと大丈夫なはず。
ダウンロードページからHigh Sierraを落としてインストールしてみました。
スタバwifi頑張った!
再度Xcodeをアップデートしようと試してもダウンロードできなかったので、色々ググってみると、アプリケーションの中のXcodeの名前を変えれば大丈夫という記事をいくつか見つけたため、やってみました。
それでも結局うまくいかず。。。
OSを最新にする事が大事
AppStoreアプリのアップデート欄をよくみて見ると、OSアップデートに追加提供分がまだ残っていましたので、これらもアップデートしときました。
そしてようやく、Xcodeもインストールできました!
Xcodeがうまく入らないときは、OSのバージョンも確認してみてください。
結論、スタバwifi頑張った!
仕事と趣味の仕事の進め方
考えてから走る or 走りながら考える
仕事の進め方は大きく分類して2種類あります。1つは、
前者がフォーターフォール開発、後者がアジャイル開発と呼ばれています。フォーターフォールは「滝」、アジャイルは「俊敏な」という事でしょうか。滝!?
それぞれ良いところもあり、悪いところもありますが、大人数で開発する場合は資料を残す、コミュニケーションをとるという点が重要なことは変わりありません。
ウォーターフォール | アジャイル | |
利点 | ・スケジュール管理しやすい ・開発フローが決定的 |
・手戻りによる開発ロスが少ない ・仕様変更に対応しやすい |
欠点 | ・手戻りによる開発ロスが大きい ・仕様変更に対応しにくい |
・スケジュール管理しにくい ・開発フローが流動的 |
ゲームアプリ業界やIT業界など、
システム系の人は、
仕事と趣味は違います
自分が趣味でアプリを作ったりする場合はアジャイルでやりたいな
ただ大事にしたいのは、再利用可能な形でコーディングする事。
色々なアプリを作りたいなあっていう時に、ソースコードも使い回ししたいなあって思うことはよくあることです。そんなとき、便利機能をクラスとして固めておいたり、コピーと最低限の編集で使えるために工夫してコーディングすることは意識します。
そこにつながるためにも、ある程度は事前に仕様をまとめて置いた方がいいかもしれない。