大多数浏览器和
Developer App 均支持流媒体播放。
-
了解适用于 visionOS 的 TabletopKit
使用 TabletopKit,从头开始打造 visionOS 棋盘游戏。我们将展示如何准备你的游戏、使用 RealityKit 添加强大的渲染功能,还将介绍如何仅添加几行代码便可以通过 Spatial Persona 在 FaceTime 通话中开启多人游戏体验。
章节
- 0:00 - Introduction
- 2:37 - Set up the play surface
- 7:45 - Implement rules
- 12:01 - Integrate RealityKit effects
- 13:30 - Configure multiplayer
资源
相关视频
WWDC24
WWDC23
-
下载Array
-
-
3:52 - Make a rectangular table
// Make a rectangular table. let entity = try! Entity.load(named: "table", in: table_Top_KitBundle) let table: Tabletop = .rectangular(entity: entity)
-
4:25 - Place seats
// Place 3 seats around the table, facing the center. static let seatPoses: [TableVisualState.Pose2D] = [ .init(position: .init(x: 0, y: Double(GameMetrics.tableDimensions.z)), rotation: .degrees(0)), .init(position: .init(x: -Double(GameMetrics.tableDimensions.x), y: 0), rotation: .degrees(-90)), .init(position: .init(x: Double(GameMetrics.tableDimensions.x), y: 0), rotation: .degrees(90)) ]
-
5:40 - Define player pawns
// Define an object that describes a pawn for each player. struct PlayerPawn: EntityEquipment { let id: ID let entity: Entity var initialState: BaseEquipmentState init(id: ID, seat: PlayerSeat, pose: TableVisualState.Pose2D, entity: Entity) { self.id = id self.entity = entity initialState = .init(seatControl: .restricted([seat.id]), pose: pose, entity: entity) } }
-
6:55 - Define an object that describes a tile
// Define an object that describes a tile on the conveyor belt struct ConveyorTile: Equipment { enum Category: String { case red case green case grey } let id: ID let category: ConveyorTile.Category let initialState: BaseEquipmentState init(id: ID, boardID: EquipmentIdentifier, position: TableVisualState.Point2D, category: ConveyorTile.Category) { self.id = id self.category = category initialState = .init(parentID: boardID, pose: .init(position: position, rotation: .init()), boundingBox: .init(center: .zero, size: .init(x: 0.06, y: 0, z: 0.06)))
-
9:53 - Monitor interactions
// The view contains all the content in the game. RealityView { (content: inout RealityViewContent) in content.entities.append(loadedGame.renderer.root) }.tabletopGame(loadedGame.tabletop, parent: loadedGame.renderer.root) { _ in GameInteraction(game: loadedGame) } // Define an object that manages player interactions. struct GameInteraction: TabletopInteraction { func update(context: TabletopKit.TabletopInteractionContext, value: TabletopKit.TabletopInteractionValue) { switch value.phase { //... }
-
10:48 - Respond to interaction updates
// Respond to interaction updates. func update(context: TabletopKit.TabletopInteractionContext, value: TabletopKit.TabletopInteractionValue) { switch value.phase { //... case .ended: { guard let dst = value.proposedDestination.equipmentID else { return } context.addAction(.moveEquipment(matching: value.startingEquipmentID, childOf: dst)) } }
-
12:52 - Add a sound effect to the die roll
// Respond to interaction updates. func update(context: TabletopKit.TabletopInteractionContext, value: TabletopKit.TabletopInteractionValue) { switch value.gesturePhase { //... case .ended: { if let die = game.tabletop.equipment(of: Die.self, matching: value.startingEquipmentID) { if let audioLibraryComponent = die.entity.components[AudioLibraryComponent.self] { if let soundResource = audioLibraryComponent.resources["dieSoundShort.mp3"] { die.entity.playAudio(soundResource) } } } } } }
-
14:44 - Set up multiplayer with SharePlay
// Set up multiplayer using SharePlay. // Provide a button to begin SharePlay. import GroupActivities func shareplayButton() -> some View { Button("SharePlay", systemImage: "shareplay") { Task {try! await Activity().activate() } } } // After joining the SharePlay session, start multiplayer. sessionTask = Task.detached { @MainActor in for await session in Activity.sessions() { tabletopGame.coordinateWithSession(session) } }
-
-
正在查找特定内容?在上方输入一个主题,就能直接跳转到相应的精彩内容。
提交你查询的内容时出现错误。请检查互联网连接,然后再试一次。