SKStoreProductViewControllerでアプリから移動せずにStore画面に行く
StoreKitのSKStoreProductViewControllerを使ってアプリ内でアプリのページに移動してみました。
まずはStoreKitを追加します。
SKStoreProductViewControllerはUIViewController同様にpresentをして表示します。
Storeの情報はloadProductメソッドで読み込みます。
import UIKit import StoreKit class ViewController: UIViewController { override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) let c = SKStoreProductViewController() c.delegate = self present(c, animated: true, completion: { let params = [SKStoreProductParameterITunesItemIdentifier: "1099462086"] c.loadProduct(withParameters: params, completionBlock: { _ in }) }) } } extension ViewController: SKStoreProductViewControllerDelegate { func productViewControllerDidFinish(_ viewController: SKStoreProductViewController) { // キャンセルを押した時に呼ばれる } }
複数のGKGoalを使って複雑なAIを作成する
昨日調べた事の続きです。
この記事では、GKGoalを使って特定のオブジェクトに向かって移動するAgentを作成しました。
今回は「特定のオブジェクトに向かって移動」「別のオブジェクトから逃げる」の複数を指定した場合を試してみます。
GKGoalとGKAgentで目的に向かって動くオブジェクトを作ってみる - しめ鯖日記
昨日同様に、Gameプロジェクトを作成します。
GameScene.swiftを以下のように置き換えます。
昨日の記事と違い、GKBehaviorに複数のGKGoalを与えています。
こうする事でagent3にagent2から遠ざかりつつagent1へ移動する動きをさせる事ができます。
import SpriteKit import GameplayKit class GameScene: SKScene { let agentSystem = GKComponentSystem(componentClass: GKAgent2D.self) let agent1 = GKAgent2D() let agent2 = GKAgent2D() let agent3 = GKAgent2D() let node1 = SKSpriteNode(color: UIColor.brown, size: CGSize(width: 10, height: 10)) let node2 = SKSpriteNode(color: UIColor.green, size: CGSize(width: 10, height: 10)) let node3 = SKSpriteNode(color: UIColor.red, size: CGSize(width: 10, height: 10)) var prevTime: TimeInterval = 0 override func didMove(to view: SKView) { agent1.position = vector_float2(x: 100, y: 100) agent2.position = vector_float2(x: 300, y: 100) node1.position = CGPoint(x: Double(agent1.position.x), y: Double(agent1.position.y)) node2.position = CGPoint(x: Double(agent2.position.x), y: Double(agent2.position.y)) agent3.position = vector_float2(x: 300, y: 500) agent3.maxAcceleration = 10 agent3.maxSpeed = 10 agent3.delegate = self agent3.behavior = GKBehavior(goals: [ GKGoal(toSeekAgent: agent1), GKGoal(toFleeAgent: agent2) ], andWeights: [100, 10] ) agentSystem.addComponent(agent3) addChild(node1) addChild(node2) addChild(node3) } override func update(_ currentTime: TimeInterval) { let deltaTime = prevTime == 0 ? 0 : currentTime - prevTime prevTime = currentTime agentSystem.update(deltaTime: deltaTime) } } extension GameScene: GKAgentDelegate { func agentDidUpdate(_ agent: GKAgent) { if let agent = agent as? GKAgent2D { node3.position = CGPoint(x: Double(agent.position.x), y: Double(agent.position.y)) print(agent.position) } } }
この状態で起動するとagent2を避けつつagent1に向かう動きをします。
下図の右上がagent3、右下がagent2、左下はagent1を表しています。
もしここでandWeightsを両方100にした場合は少し動きが変わってきます。
agent3.behavior = GKBehavior(goals: [ GKGoal(toSeekAgent: agent1), GKGoal(toFleeAgent: agent2) ], andWeights: [100, 100] )
agent1に近づく動きとagent2から遠ざかる動きが重なり、下図のように真っ直ぐ左側に移動する事になります。
GKGoalとGKAgentで目的に向かって動くオブジェクトを作ってみる
GameplayKitの「Agents, Goals, and Behaviors」という機能を試してみました。
GameplayKit Programming Guide: Agents, Goals, and Behaviors
これは特定のオブジェクトに向かって移動したり、特定のオブジェクトから逃げるようなものを作れる機能です。
早速実装をしてみます。
まずはXcodeでゲームプロジェクトを作成します。
GameScene.swiftを以下のように置き換えます。
こちらはagent2がagent1に向かって移動するサンプルです。
import SpriteKit import GameplayKit class GameScene: SKScene { var agentSystem = GKComponentSystem(componentClass: GKAgent2D.self) var agent1 = GKAgent2D() var agent2 = GKAgent2D() var prevTime: TimeInterval = 0 override func didMove(to view: SKView) { agent1.position = vector_float2(x: 100, y: 100) agent2.position = vector_float2(x: 300, y: 500) agent2.delegate = self agent2.behavior = GKBehavior(goal: GKGoal(toSeekAgent: agent1), weight: 100) agentSystem.addComponent(agent2) } override func update(_ currentTime: TimeInterval) { let deltaTime = prevTime == 0 ? 0 : currentTime - prevTime prevTime = currentTime agentSystem.update(deltaTime: deltaTime) } } extension GameScene: GKAgentDelegate { func agentDidUpdate(_ agent: GKAgent) { print((agent as? GKAgent2D)?.position) } }
実際に起動すると以下のようなログが表示されます。
agent2を表示しているのですが、agent1(x: 100, y: 100)に向かって移動している事が分かるります。
agent1(x: 100, y: 100)の座標に移動したあとは、バネのような動きをします。
【Swift】BuildTimeAnalyzer-for-Xcodeでコンパイルが遅い原因を探ってみる
インストールすると下のようなフォルダ構成になっているのでプロジェクトを立ち上げます。
立ち上げると以下のような画面になります。
ウインドウの指示通り、Other Swift Flagsにフラグを追加します。
フラグを追加したら、Cleanとプロジェクトのビルドを行います。
その後、先程のWindowのプロジェクト名を選択すると下のような画面になります。
どのメソッドがどの程度時間がかかったかが分かるようになりました。
iOS10でAutolayoutのアニメーションが効かなくなってた対策
iOS10になって、以下のようにAutolayoutのconstantを変更 & layoutIfNeededでアニメーションしてくれないという問題に遭遇しました。
constraint.constant = x UIView.animate(withDuration: 0.1, animations: { self.contentView.layoutIfNeeded() })
ひとまず直接constantとxを代入する事でアニメーションしてくれるようにはなりました。
constraint.constant = x UIView.animate(withDuration: 0.1, animations: { self.contentView.frame.origin.x = x })
【iOS10】UISearchBarのUITextFieldを取得する
UISearchBarのUITextFieldを取得する方法です。
subviewから無理やり取っているので、今後取れなくなる可能性もあるので注意が必要です。
let searchBar = UISearchBar() let textField = searchBar.subviews.first?.subviews.flatMap { $0 as? UITextField }.first
Swift3.0でインスタンスのクラス名を取得する
- 2017/10: Swift4.0でも動作確認済
Swift3.0でクラス名の取得方法が少し変わっていたのでメモ。
dynamicTypeでなくtypeという大域関数を使うようになりました。
// Swift2.0 let view = UIView() NSStringFromClass(view.dynamicType)
// Swift3.0 let view = UIView() NSStringFromClass(type(of: view))
NSStringFromClassを使わずにStringを使うことも可能です。
let view = UIView() String(reflecting: type(of: view))