2018年9月28日金曜日
Mojaveにしたらビルドが超遅い
macOS 10.14 Mojaveに上げたところ、Xcode10.0で実機のビルドが途中で止まってしまうようになった。(シミュレータでも同じになるかはわからんが)
Building xx of yy tasksって出て、xxが25で止まったまま動かない。
しょうがないからビルドを止めようとSTOPボタンを押してもダメ。強制終了するしかなく、Xcodeの再起動にもまたえらい時間がかかる。
しょうがないのでそのまま数分間我慢してたら、いつもと同じようにビルドできるようになったけど、他のプロジェクトをビルドすると同じように途中で長々と止まる。
その後、Macを再起動したところ、このやたら時間のかかるビルドは解消されたっぽい。
Mojave自体、日本語入力がかなりもたつくなど、10.14.0の完成度は高くなさげ。
まあしばらくしたらアップデートされるだろうけど、もうちょっとこう、最初からちゃんとしててほしい。
2018年9月13日木曜日
ARのお勉強/Sprite版
ARSessionの開始手順
AR空間に表示するSpriteや3Dオブジェクトは別として、とりあえずARSessionだけ開始する方法
SKSceneを読み込み、SKSceneViewのsceneとして表示
@IBOutlet var sceneView: ARSKView! //StoryboardのSceneViewと接続されてる
if let scene = SKScene(fileNamed: "Scene") {
sceneView.presentScene(scene)
}
Scene.swiftへのアクセスは以下のようにすればできる。
let s = sceneView.scene as! Scene
AR空間を認識させる
バックカメラを使い、デバイスの位置、向き、AR空間の認識などを行う。開始時に行われ、数秒間待たされる。
let configuration = ARWorldTrackingConfiguration()
let configuration = ARWorldTrackingConfiguration()
ARSession開始
ARWorldTrackingConfigurationで認識したAR設定に基づいてARSessionを開始する。
sceneView.session.run(configuration)
AR空間にオブジェクトを表示させる
ARAnchor
ARのオブジェクトを表示する位置を指定するのがARAnchor。ARAnchorをAR空間に貼り付けた後、動かせるのか、動かせないのかはまだ不明。
行列でできている
ARAnchorの値は4*4の行列(matrix_identity_float4x4)で示される。例)以下は変数に作られたばかりの行列の値
simd_float4x4([[1.0, 0.0, 0.0, 0.0)], [0.0, 1.0, 0.0, 0.0)], [0.0, 0.0, 1.0, 0.0)], [0.0, 0.0, 0.0, 1.0)]])
その行列の4個目(0オリジンなのでindexなら3)の要素のうちx, y, zがそれぞれAR空間の軸に対応しており、デバイスを中心にしたARAnchorの位置を1m = 1.0としてFloatで指定する。
- xは0がデバイス位置、プラスが下↓、マイナスが上↑
- yは0がデバイス位置、プラスが右方向→、マイナスが左方向←
- zは0がデバイス位置、プラスが後方(液晶モニタ側)、マイナスが前方(カメラの先)
指定方法
//世界座標と向きを表す4*4の行列
var transform = matrix_identity_float4x4
//行列の3列目のz値に-0.2で前方0.2mを指定
transform.columns.3.x = 0
transform.columns.3.y = 0
transform.columns.3.z = -0.2
ARSKViewDelegate
AR空間に表示するものには、2DのSpriteと3Dのオブジェクトの2つあるが、今回は2DのSprite。ARAnchorに実際にSpriteを貼るには以下のDelegateメソッドを利用する。
新規ARAnchor追加で呼ばれる
func view(_ view: ARSKView, nodeFor anchor: ARAnchor) -> SKNode? { }新しいARAnchorが追加されると呼ばれ、そこに貼りたいSpriteをreturnしてやればいい。
ARAnchorにSKNodeが貼られると呼ばれる
func view(_ view: ARSKView, didAdd node: SKNode, for anchor: ARAnchor) { }
SpriteのActionを使う
view(_ view: ARSKView, nodeFor anchor: ARAnchor) -> SKNode? で返すSpriteNodeにActionを設定してやればいいのだが、直接そのSpriteNodeを返してもARAnchorに固定されているため、思ったような動きをしてくれない。
そこで空のSKNodeを作り(仮にreturnNodeとする)、それにaddChildeした上で、そのreturnNodeを返してやればいい。
そこで空のSKNodeを作り(仮にreturnNodeとする)、それにaddChildeした上で、そのreturnNodeを返してやればいい。
let returnNode = SKNode()
中略
returnNode.addChild(spriteNode)
return returnNode
Spriteを消す時には、このダミーの親ノードも消さないとゴミが残っちゃうぞ。
Spriteを消す時には、このダミーの親ノードも消さないとゴミが残っちゃうぞ。
2018年9月10日月曜日
Spriteの衝突検出
衝突判定検出用delegateの設定
class GameScene: SKScene, SKPhysicsContactDelegate { }
self.physicsWorld.contactDelegate = self
エッジベースの物理体とは
ゲーム中の障害物など、重力の影響を受けないスプライト。
縁(エッジ)しか使われないということか?
GameSceneの場合、範囲として自分のframeを与えてやればいい。
self.physicsBody = SKPhysicsBody(edgeLoopFrom: self.frame)
ほかのSpriteは中心位置をoriginにした矩形になっているため、以下のようにwidthとheightの1/2だけ左上にずらしたCGRectで指定する。ちとめんどい。
self.label?.physicsBody = SKPhysicsBody(edgeLoopFrom:
CGRect(x: -((self.label?.frame.size.width)! / 2),
y: -((self.label?.frame.size.height)! / 2),
width: self.frame.size.width,
height: self.frame.size.height))
ボリュームベースの物理体とは
ゲーム中のキャラクターなど、重力の影響を与えるスプライト。
categoryBitMaskの設定
操作する自分のキャラなのか、敵のキャラなのか、壁などの障害物なのかなどをざっくりカテゴライズすることで、衝突の影響を受けるのか、衝突時に didBegin()メソッドでチェックをするのかなどを細かに設定する。
32bitの任意のビットのみを1にすることで設定する。
以下のようにあらかじめカテゴライズ用定数を用意しておくと便利。
let rocketCate:UInt32 = 0x1 << 0
let labelCate:UInt32 = 0x1 << 1
let frameCate:UInt32 = 0x1 << 2
self.physicsBody?.categoryBitMask = frameCate
self.label?.physicsBody?.categoryBitMask = labelCate
sprite.physicsBody?.categoryBitMask = rocketCate
collisionBitMaskの設定
spriteのカテゴリーどうしの衝突(collision)の有無を決める。
これも32bitのプロパティで、categoryBitMaskの値を使って指定し、ビットが1になっているカテゴリーと衝突する。
デフォルトではすべてのカテゴリーどうしが衝突することになり、0に設定するとすり抜ける事になる。
2カテゴリー以上指定する場合は、カテゴリーどうしをor(|)でつないで指定する。
sprite.physicsBody?.collisionBitMask = frameCate | labelCate
contactTestBitMaskの設定
collisionBitMaskの設定だけでは、衝突して跳ね返ったりするものの、その検知がされないので、delegateメソッドのdidBegin()で検知する相手のカテゴリーを指定する。
sprite.physicsBody?.contactTestBitMask = labelCate
応用
collisionBitMaskを設定せず、contactTestBitMaskだけ設定すれば、すり抜けるけど衝突は検知するなんてこともできるわけだ。
衝突時のdelegateメソッド
引数のcontactで、どのspriteどうしが衝突したのか検出できる。
衝撃の値と衝突した位置も。
これを使って敵キャラを消したりするわけですな。
func didBegin(_ contact: SKPhysicsContact) {
let bodyA = contact.bodyA
let bodyB = contact.bodyB
print("bodyA = \(String(describing: bodyA.node?.name)), bodyB = \(String(describing: bodyB.node?.name))")
print("衝撃値 = \(contact.collisionImpulse)")
print("衝突位置 = \(contact.contactPoint)")
}
撃ち落としたら消す
敵機を発射したミサイルが当たったら撃ち落とす場合は、最後に以下のようなコードを書いておく。あらかじめ敵機のnodeにenemyとでも名前をつけておく。
if bodyA.node?.name == "enemy" || bodyB.node?.name == "enemy" {
bodyA.node?.parent?.removeFromParent()
bodyB.node?.parent?.removeFromParent()
}
bodyAとbodyBのどっちが敵機、ミサイルになるのかは不定なので、どちらかが敵機だったら双方をremoveするようにする。
爆発の表現(particle)は未実装だが、remove処理の直前に処理を書けばいいだろう。
登録:
投稿 (Atom)