How to set min/max window size for mac app on catalyst

Add following four lines of code to “SceneDelegate.swift” in your project.

import UIKit

class SceneDelegate: UIResponder, UIWindowSceneDelegate {

    var window: UIWindow?

    func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
        // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`.
        // If using a storyboard, the `window` property will automatically be initialized and attached to the scene.
        // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead).
        guard let _ = (scene as? UIWindowScene) else { return }
        
// #### add following four lines of code.
        #if targetEnvironment(macCatalyst)
        window?.windowScene?.sizeRestrictions?.minimumSize = CGSize(width: 400, height: 400)
        window?.windowScene?.sizeRestrictions?.maximumSize = CGSize(width: 1280, height: 1000)
        #endif
// ### end of code
    }
...

UIImage

Reference

UIImage

Declaration

class UIImage : NSObject

概要

画像オブジェクトはすべてのプラットフォームネイティブの画像形式をサポートしていますが、アプリのほとんどの画像にはPNGまたはJPEGファイルを使用することをお勧めします。画像オブジェクトは、両方の形式の読み取りと表示用に最適化されており、これらの形式は、他のほとんどの画像形式よりも優れたパフォーマンスを提供します。PNG形式はロスレスであるため、アプリのインターフェースで使用する画像に特にお勧めします。

画像オブジェクトの作成手段は何を使うべきか

このクラスのメソッドを使用して画像オブジェクトを作成する場合は、ファイルまたはデータ構造に既存の画像データを配置する必要があります。空の画像を作成してコンテンツを描画することはできません。画像オブジェクトを作成するための多くのオプションがあり、それぞれが特定の状況に最適です。

init(named:in:compatibleWith:)init(named:)
使用方法(または、アプリケーションのメインバンドル(またはいくつかの他の既知のバンドル)にある画像アセットや画像ファイルから画像を作成する方法を)。これらの方法は画像データを自動的にキャッシュするため、頻繁に使用する画像に特にお勧めします。逆に、キャッシュされたメモリは解放されないので注意!

imageWithContentsOfFile:init(contentsOfFile:)
初期データがバンドルされていない画像オブジェクトを作成します。これらのメソッドは毎回ディスクからイメージデータをロードするため、同じイメージを繰り返しロードするために使用しないでください。頻繁にアクセスするような場合は毎回読み込むため、遅くなる可能性がある。

animatedImage(with:duration:) 、または
animatedImageNamed(_:duration:)
複数の連続した画像で構成される単一のオブジェクトを作成します。結果の画像をオブジェクトにインストールして、インターフェイスでアニメーションを作成します。

UIImageクラスの他のメソッドを使用すると、コアグラフィックス画像や自分で作成した画像データなど、特定の種類のデータからアニメーションを作成できます。UIKitのUIGraphicsGetImageFromCurrentImageContext()は、自分で描いたコンテンツから画像を作成する機能もあります。この関数は、描画コマンドをキャプチャするために使用するビットマップベースのグラフィックコンテキストと組み合わせて使用​​します。

注意

イメージオブジェクトは不変であるため、作成後にプロパティを変更することはできません。ほとんどの画像プロパティは、付随する画像ファイルまたは画像データのメタデータを使用して自動的に設定されます。画像オブジェクトの不変の性質は、どのスレッドからでも安全に作成および使用できることも意味します。

画像アセットは、アプリに付属する画像を管理する最も簡単な方法です。新しいXcodeプロジェクトにはそれぞれ、複数の画像セットを追加できるアセットライブラリが含まれています。画像セットには、アプリが使用する単一の画像のバリエーションが含まれています。単一の画像セットは、さまざまなプラットフォーム、さまざまな特性環境(コンパクトまたは通常)、およびさまざまなスケール係数に対してさまざまなバージョンの画像を提供できます。

ディスクから画像をロードすることに加えて、オブジェクトを使用して利用可能なカメラまたはフォトライブラリから画像を提供するようにユーザーに依頼できます。画像ピッカーUIImagePickerControllerは、画像を選択するためのカスタムユーザーインターフェイスを表示します。ユーザー提供の画像にアクセスするには、明示的なユーザー権限が必要です。イメージピッカーの使用の詳細については、UIImagePickerControllerを参照してください。

ストレッチ可能な画像の定義

ストレッチ可能な画像は、もとの画像データを美的に満足のいく方法で複製できる領域を定義する画像です。ストレッチ可能な画像は、利用可能なスペースを埋めるために拡大または縮小できる背景を作成するために一般的に使用されます。

resizableImage(withCapInsets:) または resizableImage(withCapInsets:resizingMode:) を使用して既存の画像にインセットを追加することにより、ストレッチ可能な画像を定義します。図は、画像を2つ以上の部分に分割します。各挿入図にゼロ以外の値を指定すると、図1に示すように、9つの部分に分割された画像が生成されます。

図1 はめ込みを使用して伸縮可能な領域を定義する

各挿入図は、指定された寸法で引き伸ばされない画像の部分を定義します。画像の上部と下部の挿入図の内側の領域は固定の高さを維持し、左右の挿入図の内側の領域は固定の幅を維持します。図2は、9つの部分からなる画像の各部分が、使用可能なスペースを埋めるために画像自体が引き伸ばされるときにどのように引き伸ばされるかを示しています。画像の角は、水平と垂直の両方のはめ込みの内側にあるため、サイズは変わりません。

 29部構成の画像の伸縮可能な部分

画像の比較

isEqual(_:)は、2つの画像に同じ画像データが含まれているかどうかを判断する唯一の信頼できる方法です。作成する画像オブジェクトは、同じキャッシュ画像データで初期化した場合でも、互いに異なる場合があります。それらの同等性を判断する唯一の方法は、実際の画像データを比較する方法を使用することです。リスト1は、画像を比較する正しい方法と正しくない方法を示しています。 

let image1 = UIImage(named: "MyImage")
let image2 = UIImage(named: "MyImage") 
if image1 != nil && image1!.isEqual(image2) {
    // Correct. This technique compares the image data correctly.
} 
if image1 == image2 {
    // Incorrect! Direct object comparisons may not work.
}

画像データへのアクセス

画像オブジェクトは、基になる画像データへの直接アクセスを提供しません。ただし、アプリで使用するために他の形式で画像データを取得することはできます。具体的には、cgImageプロパティとciImageプロパティを使用して、それぞれCoreGraphicsおよびCoreImageと互換性のあるバージョンのイメージを取得できます。pngData()jpegData(compressionQuality:) 関数を使用して、PNGまたはJPEG形式の画像データを含むNSDataオブジェクトを生成することもできます。

How to build iPhone App on mac

Reference

Creating a Mac Version of Your iPad

Error Message

‘AppDelegate’ is annotated with @main and must provide a main static function of type () -> Void or () throws -> Void.

Solution

import UIKit

@main
class AppDelegate: UIResponder, UIApplicationDelegate {

// Add following five lines of code to AppDelegate.swift
    #if targetEnvironment(macCatalyst)
    static func main() {
      UIApplicationMain(CommandLine.argc, CommandLine.unsafeArgv, nil, NSStringFromClass(AppDelegate.self))
    }
    #endif

SCNNode renderer Delegate

Reference

https://developer.apple.com/documentation/scenekit/scnscenerendererdelegate

renderer Delegates


func renderer(SCNSceneRenderer, nodeFor: ARAnchor) -> SCNNode?
新しく追加されたアンカーに対応するSceneKitノードを提供するようにデリゲートに要求します。

func renderer(SCNSceneRenderer, didAdd: SCNNode, for: ARAnchor)
新しいARアンカーに対応するSceneKitノードがシーンに追加されたことをデリゲートに通知します。

func renderer(SCNSceneRenderer, willUpdate: SCNNode, for: ARAnchor)
ノードのプロパティが対応するアンカーの現在の状態に一致するように更新されることをデリゲートに通知します。

func renderer(SCNSceneRenderer, didUpdate: SCNNode, for: ARAnchor)
SceneKitノードのプロパティが対応するアンカーの現在の状態と一致するように更新されたことをデリゲートに通知します。

func renderer(SCNSceneRenderer, didRemove: SCNNode, for: ARAnchor)
削除されたARアンカーに対応するSceneKitノードがシーンから削除されたことをデリゲートに通知します。

renderer(_:nodeFor:)
新しく追加されたアンカーに対応するSceneKitノードを提供するように要求します。

renderer(_:didRemove:for:)
レンダラー(_:didRemove:for :)削除されたARアンカーに対応するSceneKitノードがシーンから削除されたことを通知します。

Rendering Loop

renderer(_:didUpdate:for:)
SceneKitノードのプロパティが対応するアンカーの現在の状態と一致するように更新されたことを通知します。

SceneKitは、シーンを表示しているSCNViewオブジェクト(または他のオブジェクト)が一時停止されていない限り、このSCNSceneRendererメソッドをフレームごとに1回だけ呼び出します。このメソッドを実装して、レンダリングループにゲームロジックを追加します。この方法でシーングラフに加えた変更は、表示されているシーンにすぐに反映されます。つまり、SceneKitは、シーンのレンダリングに使用するプレゼンテーションノードの階層を即座に更新します

renderer(_:didApplyAnimationsAtTime:)
アクションとアニメーションの評価後に発生する必要のある更新を実行するように指示します。

renderer(_:didSimulatePhysicsAtTime:)
物理シミュレーションの実行後に発生する必要のある更新を実行するように指示します。

renderer(_:willRenderScene:atTime:)
レンダラーがビューポートをクリアし、シーンをレンダリングしようとしていることを通知します。

renderer(_:didRenderScene:atTime:)
レンダラーがシーンをレンダリングしたことを通知します。

SCNPhysics Body

Reference

https://developer.apple.com/documentation/scenekit/scnphysicsbody

宣言

class SCNPhysicsBody : NSObject

概要

SceneKitは、新しいフレームをレンダリングする準備をするときに、シーン内のノードに接続されている物理ボディに対して物理計算を実行します。これらの計算には、重力、摩擦、および他の物体との衝突が含まれます。ボディに自分の力や衝撃を加えることもできます。SceneKitはこれらの計算を完了すると、フレームをレンダリングする前にノードオブジェクトの位置と方向を更新します。

ノードに物理演算を追加するには、SCNPhysicsBodyオブジェクトを作成して構成し、それをSCNNodeオブジェクトのphysicsBodyプロパティに割り当てます。物理ボディは、力または衝撃をノードオブジェクトに適用する前に、ノードオブジェクトに関連付ける必要があります。

ボディの物理的特徴

このSCNPhysicsBodyクラスは、シーンによってシミュレートされるときのボディの物理的特性を定義します。物理シミュレーションでは、次の3つのプロパティが最も重要です。

  • typeプロパティ
    シミュレーションにおいて、ボディが力や他のボディとどのように相互作用するかを決定します。Static ボディは力や衝突の影響を受けず、移動できません。Dynamic ボディは、力や他のボディタイプとの衝突の影響を受けます。Kinematic ボディは力や衝突の影響を受けませんが、それらを直接移動することで、ダイナミックボディに影響を与える衝突を引き起こす可能性があります。
  • physicsShapeプロパティ
    衝突検出のために体の三次元形状を定義する。ノードの表示可能なジオメトリの詳細ではなく単純な形状を使用すると、物理シミュレーションがより高速に実行されます。通常、ボディの物理形状を、ノードの表示コンテンツにほぼ一致する境界ボックス、球、またはプリミティブ形状に設定します。物理シェイプの作成の詳細については、SCNPhysicsShapeを参照してください。
  • kinematic()プロパティ。動的な物体に力またはトルクを加えると、その質量に比例した加速度(または角加速度)が発生します。

SceneKitの物理シミュレーションのすべての値は、国際単位系(SI)を使用します。質量の単位はキログラムです。力、力積、およびトルクの単位は、ニュートン、ニュートン秒、およびニュートンメートルです。ノードの位置とサイズの距離の単位はメートルです。物理量に現実的な値を提供しようとする必要はないことに注意してください。探している動作やゲームプレイを生み出す値を使用してください。

Dynamic ボディの場合、力または衝突によってボディがどのように影響を受けるかを制御できます。Defining How Forces Affect a Physics Body を参照してください。

ボディのカテゴリと衝突の定義

物理学を使用するゲームを設計するときは、シーンに表示される物理学オブジェクトのさまざまなカテゴリを定義します。アプリに必要な動作に応じて、さまざまなカテゴリの物理ボディを定義します。ボディは、これらのカテゴリに必要な数だけ割り当てることができます。物理ボディは、独自のカテゴリを宣言するだけでなく、相互作用するボディのカテゴリも宣言します。

categoryBitMaskcollisionBitMaskプロパティを使用して、オブジェクトの衝突動作を定義します。SCNPhysicsCollisionCategoryにリストされている定数は、これらのプロパティのデフォルト値を提供します。さらに、contactTestBitMaskプロパティを使用すると、ボディが衝突の影響を受けることなく、ボディのペアがコンタクトメッセージ(SCNPhysicsContactDelegateプロトコルを参照)を生成するインタラクションを定義できます。

関連する物理学のクラス

物理学の分野は、渦や重力の引力など、領域内のすべての物体に影響を与える力を生み出します。詳細および使用可能なフィールドタイプのリストについては、SCNPhysicsFieldを参照してください。

関節や車輪付き車両など、複数のボディ間の相互作用を制御する高レベルの動作を追加できます。詳細および使用可能な動作のリストについては、SCNPhysicsBehaviorを参照してください。

シーンのphysicsWorldプロパティは、シーン全体に影響を与える物理特性を管理するSCNPhysicsWorldオブジェクトを保持します。

物理学とレンダリングループ

SceneKitは、SCNSceneRendererDelegateで説明されているレンダリングループの一部として物理シミュレーションを評価します。このループを通過するたびに、SceneKitは、物理ボディがアタッチされたすべてのノードの状態を判別し、たとえば、速度と角速度に基づいてボディの位置または回転を更新することにより、これらのボディに対する物理の影響を1タイムステップでシミュレートします。その後、SceneKitは物理シミュレーションの結果をシーンに適用して表示します。

SceneKitコンテンツは、物理学だけでなく、アクションや暗黙的および明示的に定義されたアニメーションを通じてもアニメーション化できるため、SceneKitは、物理シミュレーションの結果をSCNNodeシーン内のpresentationオブジェクトではなく、現在表示されている状態を表す各ノードのオブジェクトに適用します。そのため、物理学の影響を受けるノードのプロパティを変更するには、特別な考慮が必要です。

物理学の影響を受けるノードのtransform値、または変換のコンポーネントであるその他のプロパティ(positionおよびrotationなど)を変更すると、SceneKitはそのノードの物理シミュレーションをリセットします。以下に示すように、変換の1つのコンポーネントのみを変更し、他のコンポーネントは物理シミュレーション値のままにしておきたい場合は、変更を加える前にプレゼンテーションノードの変換をコピーします。

// Copy the presentation node's transform to the model
 node.node.transform = node.presentationNode.transform
// Change one component of the new transform
node.eulerAngles.z = newRollValue

トピック

物理ボディの作成

init(type: SCNPhysicsBodyType, shape: SCNPhysicsShape?)
指定されたタイプと形状の物理ボディを作成します。

class func `static`() -> Self
力や衝突の影響を受けず、移動できない物理ボディを作成します。

class func dynamic() -> Self
力や衝突の影響を受ける可能性のある物理ボディを作成します。

class func kinematic() -> Self
力や衝突の影響を受けないが、移動すると他のボディに影響を与える衝突を引き起こす可能性のある物理ボディを作成します。

力が物理体にどのように影響するかを定義する

var physicsShape: SCNPhysicsShape?
衝突検出で使用するための物理ボディのソリッドボリュームを定義するオブジェクト。

var type: SCNPhysicsBodyType
物理体が力や衝突にどのように反応するかを決定する定数。

enum SCNPhysicsBodyType
物理ボディが力や他のボディとどのように相互作用するかを決定する定数。typeプロパティで使用され、物理ボディを作成するときに使用されます。

var velocityFactor: SCNVector3
SceneKitが物理シミュレーションによって計算された変換を物理ボディを含むノードに適用する方法に影響を与える乗数。

var angularVelocityFactor: SCNVector3
SceneKitが物理シミュレーションによって計算された回転を物理ボディを含むノードに適用する方法に影響を与える乗数。

var isAffectedByGravity: Bool
シーンの一定の重力が体を加速するかどうかを決定するブール値。

ボディの物理的特性の定義

var mass: CGFloat
体の質量(キログラム)。

var charge: CGFloat
クーロン単位の体の電荷。

var friction: CGFloat
スライド運動に対する身体の抵抗。

var rollingFriction: CGFloat
転がり運動に対する体の抵抗。

var restitution: CGFloat
衝突で体が失うまたは得る運動エネルギーの量を決定する要因。

var damping: CGFloat
体の直線速度を低下させる要因。

var angularDamping: CGFloat
体の角速度を低下させる要因。

var momentOfInertia: SCNVector3
ボディを含むノードのローカル座標系で表される、ボディの慣性モーメント。

var usesDefaultMomentOfInertia: Bool
SceneKitがボディの慣性モーメントを自動的に計算するか、カスタム値を設定できるかを決定するブール値。

var centerOfMassOffset: SCNVector3
ローカル座標の原点に対するボディの重心の位置。

コンタクト先と衝突

var categoryBitMask: Int
この物理ボディが属するカテゴリを定義するマスク。

var contactTestBitMask: Int
ボディのどのカテゴリがこの物理ボディとの交差通知を引き起こすかを定義するマスク。

var collisionBitMask: Int
物理ボディのどのカテゴリがこの物理ボディと衝突できるかを定義するマスク。

struct SCNPhysicsCollisionCategory
物理ボディとプロパティのデフォルト値。

categoryBitMaskcollisionBitMaskvar continuousCollisionDetectionThreshold: CGFloat
SceneKitが他のボディとの接触を検出するためのより正確な(ただしよりコストのかかる)アルゴリズムを適用するためにボディが移動する必要のある最小距離。

力、インパルス、およびトルクの適用

func applyForce(SCNVector3, asImpulse: Bool)
重心で体に力または衝撃を加えます。

func applyForce(SCNVector3, at: SCNVector3, asImpulse: Bool)
特定のポイントで体に力または衝撃を加えます。

func applyTorque(SCNVector4, asImpulse: Bool)
正味のトルクまたは角運動量の変化を体に適用します。

func clearAllForces()
現在のシミュレーションステップ中に物理ボディに作用するすべての連続的な力とトルクをキャンセルします。

動いているボディとの相互作用

var velocity: SCNVector3
現在の速度(メートル/秒)と物理体の運動方向の両方を表すベクトル。

var angularVelocity: SCNVector4
物理体の現在の回転軸と回転速度(ラジアン/秒)の両方を表すベクトル。

いつボディが動くことができるかを定義する

var isResting: Bool
物理ボディが静止しているかどうかを示すブール値。

var allowsResting: Bool
SceneKitが静止している物理ボディを自動的にマークできるかどうかを指定するブール値。

func setResting(Bool)
ボディを現在動いているものとして扱うかどうかをSceneKitに指示します。

物理ボディとそのノードの同期

func resetTransform()
物理シミュレーションでボディの位置と方向を更新して、ボディが接続されているノードの位置と方向に一致させます。

インスタンスのプロパティ

var angularRestingThreshold: CGFloat

var linearRestingThreshold: CGFloat

RealityKit or SceneKit

RealityKit

import UIKit
import RealityKit

class ViewController: UIViewController {
    
    @IBOutlet var arView: ARView!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        // Load the "Box" scene from the "Experience" Reality File
        let boxAnchor = try! Experience.loadBox()
        
        // Add the box anchor to the scene
        arView.scene.anchors.append(boxAnchor)
    }
}

SceneKit

import UIKit
import SceneKit
import ARKit

class ViewController: UIViewController, ARSCNViewDelegate {

    @IBOutlet var sceneView: ARSCNView!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        // Set the view's delegate
        sceneView.delegate = self
        
        // Show statistics such as fps and timing information
        sceneView.showsStatistics = true
        
        // Create a new scene
        let scene = SCNScene(named: "art.scnassets/ship.scn")!
        
        // Set the scene to the view
        sceneView.scene = scene
    }
    
    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        
        // Create a session configuration
        let configuration = ARWorldTrackingConfiguration()

        // Run the view's session
        sceneView.session.run(configuration)
    }
    
    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
        
        // Pause the view's session
        sceneView.session.pause()
    }

    // MARK: - ARSCNViewDelegate
    
/*
    // Override to create and configure nodes for anchors added to the view's session.
    func renderer(_ renderer: SCNSceneRenderer, nodeFor anchor: ARAnchor) -> SCNNode? {
        let node = SCNNode()
     
        return node
    }
*/
    
    func session(_ session: ARSession, didFailWithError error: Error) {
        // Present an error message to the user
        
    }
    
    func sessionWasInterrupted(_ session: ARSession) {
        // Inform the user that the session has been interrupted, for example, by presenting an overlay
        
    }
    
    func sessionInterruptionEnded(_ session: ARSession) {
        // Reset tracking and/or remove existing anchors if consistent tracking is required
        
    }
}