WWDC Quick Look 💓 By SwiftGGTeam
Tap into virtual and physical game controllers

Tap into virtual and physical game controllers

元の動画を見る

ハイライト

iOS 15は仮想スクリーンコントローラーを起動GCVirtualController、タッチ入力をゲーム コントローラー入力に変換し、既存のGCControllerコード互換性あり。 PlayStation DualSense コントローラーのアダプティブ トリガー エフェクトもサポートしています。

主な内容

モバイル ゲーム制御の問題点

コンソール プラットフォームから iOS/iPadOS に移植されたゲームは、多くの場合、2 つのアナログ スティック、十字キー、数字ボタンを使用するように設計されています。開発者らは、これらのゲーム向けに一貫性があり、感触が良く、見た目も美しいタッチ入力を構築するのは難しいと報告しています。タッチ入力処理コードにはキーボード、マウス、ゲーム コントローラーの入力コードとは異なるパスがあり、メンテナンス コストが増加します。(06:13)

仮想コントローラー用のソリューション

Apple は、特にこれらの問題に対処するために、新しい仮想スクリーン コントローラーを発売しました。これらの画面コントロールは次のとおりです。

  • 絶妙な外観: さまざまなハンドグリップ位置に合わせて慎重に調整されており、素早い応答が可能です。
  • コードの統合: 仮想コントローラーはコード内で次のように表されます。GCController物理コントローラーと同じ入力処理ロジックを使用するオブジェクト
  • カスタマイズ可能: iOS/iPadOS のデザイン言語を維持しながら、カスタムのシンボル、色、スタイルをサポートします。
  • アダプティブ レイアウト: 構成に従ってレイアウトを自動的に調整します

仮想コントローラーの基本原理は、左右の領域が独立して構成され、レイアウトは構成によって決定されるということです。各面には、0 ~ 4 個のボタンと、ジョイスティック、D パッド、またはタッチパッドを含めることができます。(07:22)

ゲーム コントローラー フレームワークの基本

ゲーム コントローラー フレームワークの目標は、開発者が Apple プラットフォーム上でさまざまな効率的で低遅延の入力メソッドを簡単にサポートできるようにすることです。共通の API を通じて入力ハードウェアを抽象化することで、開発者は入力コードを 1 回記述するだけで済み、入力がどのように再マップされるか、または異なるコントローラー間でどのように異なるかを心配する必要がなくなります。(00:40)

iOS、iPadOS、tvOS では、プレーヤーはシステム全体およびアプリごとのゲーム コントローラー入力の再マップを作成して、ゲームをよりカスタマイズしやすくアクセスしやすくすることができます。(01:04)

##詳細

コントローラ接続・切断処理

コントローラーの接続と切断を処理するための基本パターン: (01:27)

import GameController

// コントローラ接続通知を監視する
NotificationCenter.default.addObserver(
    self,
    selector: #selector(controllerDidConnect),
    name: .GCControllerDidConnect,
    object: nil
)

// コントローラ切断通知を監視する
NotificationCenter.default.addObserver(
    self,
    selector: #selector(controllerDidDisconnect),
    name: .GCControllerDidDisconnect,
    object: nil
)

@objc func controllerDidConnect(_ notification: Notification) {
    let controller = notification.object as? GCController
    // 入力処理を設定するか、コントローラの状態をポーリングする
}

@objc func controllerDidDisconnect(_ notification: Notification) {
    let controller = notification.object as? GCController
    // コントローラ関連のリソースをクリーンアップする
}

キーポイント:

  • コントローラの接続または切断時に、システムが GCController オブジェクトを作成または削除します
  • GCControllerDidConnectGCControllerDidDisconnect の通知を送信します
  • 同じパターンは GCKeyboardGCMouse オブジェクトにも当てはまります
  • 値変更ハンドラーまたはポーリング入力ステータスを設定するオプション

仮想コントローラーの作成

仮想コントローラーを作成する手順: (08:42)

import GameController

// 設定オブジェクトを作成する
let configuration = GCVirtualControllerConfiguration()

// 左側の要素を設定する
configuration.leftThumbstick = true
configuration.leftButtons = [GCInputButtonOptions.a]

// 右側の要素を設定する
configuration.rightThumbstick = true
configuration.rightButtons = [
    GCInputButtonOptions.a,
    GCInputButtonOptions.b
]

// 仮想コントローラを作成する
let virtualController = GCVirtualController(configuration: configuration)

// コントローラを接続し、GCControllerDidConnect 通知をトリガーする
virtualController.connect()

キーポイント:

  • GCVirtualControllerConfiguration仮想コントローラーのレイアウトを定義する
  • それぞれの側にジョイスティック、方向キー、またはタッチパッドを設定できます (3 つのうちの 1 つを選択)
  • 片側あたり 0 ~ 4 個のボタンで構成可能
  • 電話connect()その後、仮想コントローラーは標準として動作します。GCController物体
  • 構成は作成時に固定され、要素は表示または非表示にすることができますが、追加または削除することはできません

ボタンの外観をカスタマイズする

仮想コントローラーのボタンの外観をカスタマイズします: (09:17)

// ボタン設定を取得する
if let buttonA = virtualController.controller?.extendedGamepad?.buttonA {
    // カスタム形状を作成する(例: 回転攻撃アイコン)
    let attackPath = UIBezierPath()
    attackPath.move(to: CGPoint(x: 0.5, y: 0))
    attackPath.addLine(to: CGPoint(x: 1, y: 1))
    attackPath.addLine(to: CGPoint(x: 0, y: 1))
    attackPath.close()

    buttonA.path = attackPath
}

if let buttonB = virtualController.controller?.extendedGamepad?.buttonB {
    // ジャンプアイコンを作成する
    let jumpPath = UIBezierPath()
    jumpPath.move(to: CGPoint(x: 0.2, y: 0.8))
    jumpPath.addLine(to: CGPoint(x: 0.5, y: 0.2))
    jumpPath.addLine(to: CGPoint(x: 0.8, y: 0.8))
    jumpPath.close()

    buttonB.path = jumpPath
}

// ボタンを非表示にする
if let buttonX = virtualController.controller?.extendedGamepad?.buttonX {
    buttonA.isHidden = true
}

キーポイント:

  • 合格pathボタンのカスタム形状を設定するプロパティ
  • 使用UIBezierPathベクターグラフィックスの作成
  • isHiddenプロパティはボタンを表示または非表示にすることができます
  • カスタム形状はシンプルかつ明確で、素早い認識に適している必要があります。

DualSense アダプティブ トリガー

PlayStation DualSense コントローラーのアダプティブ トリガー テクノロジーは、プレーヤーの動作に基づいてさまざまな抵抗を動的に適用し、没入感を高めます。弓の弦を引く感覚や張力がかかったパチンコなどをシミュレートできます (10:45)

アダプティブ トリガーをサポートする手順: (12:06)

import GameController

// 現在のコントローラを取得する
guard let controller = GCController.current else { return }

// DualSense コントローラかどうかを検証する
guard let dualSense = controller.physicalInputProfile as? GCDualSenseGamepad else {
    return
}

// 右側のアダプティブトリガーを取得する
let rightTrigger = dualSense.rightAdaptiveTrigger

// プレイヤーが狙っている間は抵抗を適用する
func updateSlingshotResistance(isAiming: Bool, pullAmount: Float) {
    if isAiming {
        if pullAmount < 1.0 {
            // 未完全拉回,应用反馈效果
            // FeedbackEffect 提供恒定阻力
            let feedbackEffect = GCAdaptiveTriggerFeedbackEffect(
                strength: pullAmount
            )
            rightTrigger.applyEffect(feedbackEffect)
        } else {
            // 完全拉回,应用振动效果
            // VibrationEffect 让扳机振动,模拟保持张力
            let vibrationEffect = GCAdaptiveTriggerVibrationEffect(
                strength: pullAmount,
                frequency: 0.5
            )
            rightTrigger.applyEffect(vibrationEffect)
        }
    } else {
        // 狙っていないときは効果をオフにする
        rightTrigger.applyEffect(nil)
    }
}

// プレイヤーがスリングショットを発射した後に効果をオフにする
func fireSlingshot() {
    rightTrigger.applyEffect(nil)
}

キーポイント:

  • 診るphysicalInputProfileそうですかGCDualSenseGamepadタイプ
  • rightAdaptiveTriggerそしてleftAdaptiveTrigger左右のアダプティブトリガーにアクセス
  • GCAdaptiveTriggerFeedbackEffect一定の抵抗を提供する
  • GCAdaptiveTriggerVibrationEffectトリガーを振動させる
  • 使用後は忘れずに電話してくださいapplyEffect(nil)エフェクトをオフにする

App Store のタグ付けとカスタマイズ

Xcode にゲーム コントローラー機能を追加して、アプリをサポートするゲーム コントローラーとしてマークします: (03:10)

  1. プロジェクト設定を開きます
  2. 署名と機能の選択
  3. ゲームコントローラー機能の追加

これにより、ゲーム コントローラーの機能がアプリの Info.plist に追加され、App Store によってアプリに「コントローラー サポート」バッジが追加されます。アプリは、ゲーム コントローラー設定のアプリごとのカスタマイズ セクションにも含まれます。(03:22)

UI のグリフを修正する

UI に正しいボタン グリフを表示することが重要です。コントローラーが異なれば、ボタンのレイアウトも異なります。

  • MFi または Xbox コントローラー: Y ボタンを表示
  • PlayStation コントローラー: 三角ボタンを表示

プレーヤーがシステムの再マッピング UI でボタンを再マッピングした場合でも、正しいグリフが表示される必要があります。(03:36)

// アクションに関連付けられたボタンを取得する
guard let buttonA = controller.extendedGamepad?.buttonA else { return }

// ボタンの SF Symbols 名を取得する
let symbolName = buttonA.sfSymbolsName

// システム画像を作成する
if let symbolName = symbolName, let image = UIImage(systemName: symbolName) {
    // UI に画像を表示する
    buttonImageView.image = image
}

キーポイント:

  • sfSymbolsNameプロパティはボタンのシステム シンボル名を返します。
  • 使用UIImage(systemName:)イメージの作成
  • これにより、システムの再マッピングが自動的に反映されます。 ・特定のボタン名ではなく、位置関係(「トップボタン」など)を表示する方法もあります

共有ボタンと画面キャプチャ

共有ボタンをサポートするコントローラーを使用すると、プレーヤーは画面をキャプチャしてビデオを録画できます: (03:46)

  • [共有] ボタンをダブルクリックします。スクリーンショットをフォト アルバムにキャプチャします。
  • 共有ボタンを長押し: ReplayKit の録画を開始および停止します。

iOS 15では、15秒のハイライトクリップ機能が追加されました。プレーヤーはいつでも自動バックグラウンド バッファリングをオンにし、長押ししてゲーム映像の最後の 15 秒を保存できます。(13:31)

グローバル設定またはアプリごとの設定は、ゲーム コントローラーの設定パネルで切り替えることができます。ゲームの重要な瞬間に独自のハイライト クリップをトリガーしたい場合は、専用の API を利用できます。

重要ポイント

  • やるべきこと: 移植されたゲームの統合制御スキームを作成する

  • 価値がある理由: 仮想コントローラーを使用すると、タッチ入力が次のように動作します。GCController、物理コントローラーと同じコード パスを使用し、メンテナンス コストを削減します。

  • 開始方法: 作成するGCVirtualControllerConfiguration、左右のロッカーとボタンを設定し、呼び出しますconnect()コントローラーを接続する

  • 内容: DualSense アダプティブ トリガーで没入感を実現

  • 実行する価値がある理由: アダプティブ トリガーは、ゲームの状態に応じて抵抗を動的に調整できるため、武器の弓を引いたり、パチンコを引いたりするアクションのリアリズムが向上します。

  • 開始方法: 確認してくださいphysicalInputProfileそうですかGCDualSenseGamepad、アダプティブ トリガーの取得、適用GCAdaptiveTriggerFeedbackEffectまたはGCAdaptiveTriggerVibrationEffect

  • 内容: コントローラー入力の再マッピングをサポート

  • 価値がある理由: プレイヤーはシステム設定でボタンを再マップできるため、ゲームがよりアクセスしやすく、カスタマイズしやすくなります。

  • 開始方法: Xcode にゲーム コントローラー機能を追加し、使用しますsfSymbolsName正しいボタンのグリフを示すプロパティ

  • 内容: 共有ボタンの統合画面キャプチャ機能

  • 実行する価値がある理由: プレイヤーはゲームの素晴らしい瞬間を簡単にキャプチャし、友人と共有してゲームの普及を促進できます。

  • 開始方法: ReplayKit API をサポートし、ゲームの重要な瞬間に 15 秒間のハイライト クリップの録画をトリガーします

  • やるべきこと: タッチ デバイス用のカスタマイズ可能なコントロール レイアウトを設計する

  • 価値がある理由: 異なるゲームには異なる制御スキームが必要であり、仮想コントローラーの柔軟な構成によりさまざまなニーズを満たすことができます。

  • 開始方法: ゲームの種類に応じてジョイスティック、方向キー、ボタンの適切な組み合わせを選択し、ボタンの形状をカスタマイズして認識性を向上させます

関連セッション

コメント

GitHub Issues · utterances