├── .swiftpm └── xcode │ ├── package 2.xcworkspace │ └── contents.xcworkspacedata │ ├── package.xcworkspace │ ├── contents.xcworkspacedata │ └── xcuserdata │ │ └── grantjarvis.xcuserdatad │ │ └── UserInterfaceState.xcuserstate │ └── xcuserdata │ └── grantjarvis.xcuserdatad │ └── xcschemes │ └── xcschememanagement.plist ├── LICENSE ├── Package.swift ├── README.md ├── RealityKitCollisions-Example ├── RealityKit-Collisions-Example.xcodeproj │ ├── project.pbxproj │ └── project.xcworkspace │ │ └── contents.xcworkspacedata └── RealityKit-Collisions-Example │ ├── ARView.swift │ ├── Aliens.rcproject │ ├── Library │ │ └── ProjectLibrary │ │ │ ├── Contents.json │ │ │ └── Version.json │ ├── SceneThumbnails │ │ └── 4592144E-3CF4-4A12-AA68-CA11F89497EA.thumbnails │ │ │ ├── square │ │ │ └── wide │ └── com.apple.RCFoundation.Project │ ├── AppDelegate.swift │ ├── Assets.xcassets │ ├── AccentColor.colorset │ │ └── Contents.json │ ├── AppIcon.appiconset │ │ └── Contents.json │ ├── Contents.json │ └── launchBackground.colorset │ │ └── Contents.json │ ├── ContentView.swift │ ├── Info.plist │ ├── Model.swift │ └── Preview Content │ └── Preview Assets.xcassets │ └── Contents.json ├── Sources └── RealityCollisions │ └── CollisionFilters.swift └── media └── CollisionFilters.gif /.swiftpm/xcode/package 2.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.swiftpm/xcode/package.xcworkspace/xcuserdata/grantjarvis.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Reality-Dev/RealityKit-Collisions/268b81512e9c7a81bd72364f07176f3a4ce52799/.swiftpm/xcode/package.xcworkspace/xcuserdata/grantjarvis.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /.swiftpm/xcode/xcuserdata/grantjarvis.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | CollisionFiltersv.xcscheme_^#shared#^_ 8 | 9 | orderHint 10 | 0 11 | 12 | RealityCollisions.xcscheme_^#shared#^_ 13 | 14 | orderHint 15 | 0 16 | 17 | RealityKit-Collisions-Package.xcscheme_^#shared#^_ 18 | 19 | orderHint 20 | 0 21 | 22 | RealityKit-Collisions.xcscheme_^#shared#^_ 23 | 24 | orderHint 25 | 1 26 | 27 | RealityKitCollisions-Package.xcscheme_^#shared#^_ 28 | 29 | orderHint 30 | 0 31 | 32 | 33 | SuppressBuildableAutocreation 34 | 35 | RealityCollisions 36 | 37 | primary 38 | 39 | 40 | RealityKitCollisions 41 | 42 | primary 43 | 44 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Grant Jarvis 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version:5.9 2 | // The swift-tools-version declares the minimum version of Swift required to build this package. 3 | 4 | import PackageDescription 5 | 6 | let package = Package( 7 | name: "RealityCollisions", 8 | platforms: [.macOS(.v10_15), .iOS(.v15), .tvOS(.v13), .visionOS(.v1)], 9 | products: [ 10 | .library(name: "RealityCollisions", targets: ["RealityCollisions"]) 11 | ], 12 | dependencies: [.package(url: "https://github.com/Reality-Dev/RealityKit-Utilities", from: "1.1.01"),], 13 | targets: [ 14 | .target(name: "RealityCollisions", dependencies: [.product(name: "RKUtilities", package: "RealityKit-Utilities")]) 15 | ], 16 | swiftLanguageVersions: [.v5] 17 | ) 18 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # RealityKit-Collisions 2 | 3 | This is a convenience API for setting Collision Filters in RealityKit. 4 | 5 | 6 | ![RealityKitCollisions Example 1](media/CollisionFilters.gif) 7 | 8 | ## Discussion 9 | 10 | Collision Filters determine what group an entity belongs to, and what groups of entities it can collide with. 11 | This package creates a convenient way to generate and assign these groups, instead of just using a CollisionFilter of ".default" or ".sensor" which collide with everything. 12 | 13 | ## Minimum Requirements 14 | - Swift 5.2 15 | - iOS 13.0 (RealityKit) 16 | - Xcode 11 17 | 18 | ## Installation 19 | 20 | ### Swift Package Manager 21 | 22 | Add the URL of this repository to your Xcode 11+ Project. 23 | 24 | Go to File > Swift Packages > Add Package Dependency, and paste in this link: 25 | 26 | `https://github.com/Reality-Dev/RealityKit-Collisions` 27 | 28 | 29 | ## Example 30 | See the [Example](./RealityKit-Collisions-Example) for a full working example. 31 | 32 | In AR: Tap or swipe on the big rubber ball to watch it collide with only the green aliens and not the teammates. 33 | If you run this app on a LiDAR-enabled device, the entities will also collide with the scene mesh. 34 | 35 | 36 | 37 | 38 | ## Usage 39 | 40 | [This YouTube video](https://youtu.be/Pit-Dn8WvN8) is out of date and applies only to the versions of this package before 3.0.0 41 | 42 | - After installing, import `RealityKitCollisions` to your .swift file 43 | 44 | If you want to run code when collision events occur, [see this article](https://realitydev.medium.com/realitykit-easier-collision-groups-818b07508c4c) 45 | 46 | 47 | - To allow you to add your own custom collision groups you must first define them: 48 | Copy and paste this enum wherever you need it (inside of the scope that you will use this package in, or in the global scope) and replace the case names with the collision groups you want to have in your own app. You could make one like this if you wanted to have "teammates" and "aliens" groups: 49 | ``` swift 50 | public enum CollisionGroups: Int, CaseIterable { 51 | case teammates, aliens 52 | } 53 | ``` 54 | This works for up to 32 different groups. 55 | 56 | Next, call the "setNewCollisionFilter()" function for any entity that you want to use it on. 57 | Here is an example: 58 | 59 | ``` swift 60 | class ViewController: UIViewController { 61 | 62 | override func viewDidLoad() { 63 | super.viewDidLoad() 64 | 65 | aliensScene.alien1!.setNewCollisionFilter( 66 | belongsToGroup: CollisionGroups.aliens, 67 | andCanCollideWith: [.aliens, .bigRubbberBall, .ground]) 68 | } 69 | } 70 | ``` 71 | 72 | ^Now the "alien1" entity belongs to the group "aliens" and can collide with entities that have been explicitly placed inside of the "aliens," "bigRubbberBall," and "ground" groups. 73 | 74 | In order for Swift to infer the type of your collision groups enum, you must specify the type name of your custom collision groups enum at least once in the parameters of the function. 75 | i.e. This is why the above parameter was passed in this way: 76 | `belongsToGroup: CollisionGroups.aliens` 77 | and not this way: 78 | `belongsToGroup: .aliens`. 79 | Because this was written as `CollisionGroups.aliens`, swift now knows that `CollisionGroups` is the enum that defines your custom collision groups. 80 | Notice, for convenience, how the other input paramters do *not* have to specify the enum type: 81 | `andCanCollideWith: [.aliens, .bigRubbberBall, .ground]` 82 | 83 | ## Important: 84 | 85 | - Be sure to only define *ONE* collision groups enum. i.e. Creating multiple different enums and passing them to different calls of `.setNewCollisionFilter(belongsToGroup:, 86 | andCanCollideWith:)` will cause unexpected results. 87 | 88 | - Note: groups do not automatically collide with their own group. For example, one balloon does not automatically collide with another balloon unless the "balloons" group was specified as part of the "andCanCollideWith" array. 89 | 90 | - Note: an entity does not automatically belong to any group. For example, if you make a wall entity and name it "wall," you must still call `wall.setNewCollisionFilter(belongsToGroup: .walls, andCanCollideWith: [])` in order to add the wall entity to the "walls" group. 91 | 92 | - Note: If an entity does not already have a CollisionComponent, then `setNewCollisionFilter()` will automatically add one to the entity for you, recursively generating collision shapes for all descendants of the entity as well. 93 | 94 | 95 | ## To allow the entity to collide with the scene mesh on Lidar-enabled devices: 96 | ### Option A: 97 | // Call this method AFTER calling `setNewCollisionFilter()` if you intend on calling both methods. 98 | `myEnt.addCollisionWithLiDARMesh()` 99 | 100 | ### Option B: 101 | Include a group in your enum spelled exactly as "sceneMesh" like this: 102 | ``` swift 103 | public enum MyCustomCollisionGroups: Int, CaseIterable { 104 | case sceneMesh, teammates, aliens 105 | } 106 | ``` 107 | And then use that sceneMesh group in the `setNewCollisionFilter` method just like any other group, like this: 108 | ``` swift 109 | boxAnchor.steelBox!.setNewCollisionFilter(belongsToGroup: CollisionGroups.teammates, andCanCollideWith: [.sceneMesh, .aliens]) 110 | ``` 111 | Using either option, copy and paste the `runLiDARConfiguration()` function from the example project into your project and call it. 112 | This is how you check if the user is on a LiDAR-enabled device: 113 | ``` swift 114 | if ARWorldTrackingConfiguration.supportsSceneReconstruction(.mesh) { 115 | runLiDARConfiguration() 116 | } 117 | ``` 118 | 119 | 120 | 121 | `CollisionComponent.makeCollisionFilter` Does Not set a filter on an entity, but it returns a filter. This is useful when you want to use a custom shape and mode on your `CollisionComponent`. The returned filter is then inserted into the `CollisionComponent` initializer as the "filter:" parameter. 122 | Here is an example: 123 | ``` swift 124 | let newCollisionFilter = CollisionComponent.makeCollisionFilter(belongsToGroup: CollisionGroups.teammates, 125 | andCanCollideWith: [.aliens, .ground,.bigRubbberBall]) 126 | let newCollisionComponent = CollisionComponent(shapes: [ShapeResource.generateBox(size: .one)], 127 | mode: .trigger, 128 | filter: newCollisionFilter) 129 | myEntity.components[CollisionComponent.self] = newCollisionComponent 130 | ``` 131 | 132 | 133 | ## More 134 | 135 | If anything is unclear, please [send me a tweet](https://twitter.com/gmj4k) 136 | 137 | Please feel free to contribute by making a fork & pull request. 138 | -------------------------------------------------------------------------------- /RealityKitCollisions-Example/RealityKit-Collisions-Example.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 52; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 551479DC2A2960EF000EBB0D /* RealityCollisions in Frameworks */ = {isa = PBXBuildFile; productRef = 551479DB2A2960EF000EBB0D /* RealityCollisions */; }; 11 | 557CD32325FC07CE00DACC41 /* README.md in Resources */ = {isa = PBXBuildFile; fileRef = 557CD32225FC07CE00DACC41 /* README.md */; }; 12 | 55B500A025FAF13900EFBA47 /* Model.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55B5009725FAF13900EFBA47 /* Model.swift */; }; 13 | 55B500A125FAF13900EFBA47 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 55B5009825FAF13900EFBA47 /* Assets.xcassets */; }; 14 | 55B500A225FAF13900EFBA47 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 55B5009A25FAF13900EFBA47 /* Preview Assets.xcassets */; }; 15 | 55B500A425FAF13900EFBA47 /* ARView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55B5009C25FAF13900EFBA47 /* ARView.swift */; }; 16 | 55B500A525FAF13900EFBA47 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55B5009D25FAF13900EFBA47 /* AppDelegate.swift */; }; 17 | 55B500A625FAF13900EFBA47 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 55B5009E25FAF13900EFBA47 /* ContentView.swift */; }; 18 | 55B500B125FAF1C200EFBA47 /* Aliens.rcproject in Sources */ = {isa = PBXBuildFile; fileRef = 55B500B025FAF1C200EFBA47 /* Aliens.rcproject */; }; 19 | /* End PBXBuildFile section */ 20 | 21 | /* Begin PBXFileReference section */ 22 | 551479D72A295F32000EBB0D /* RealityKit-Collisions */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = "RealityKit-Collisions"; path = ..; sourceTree = ""; }; 23 | 557CD32225FC07CE00DACC41 /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; name = README.md; path = ../../README.md; sourceTree = ""; }; 24 | 55B5009725FAF13900EFBA47 /* Model.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Model.swift; sourceTree = ""; }; 25 | 55B5009825FAF13900EFBA47 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 26 | 55B5009A25FAF13900EFBA47 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; }; 27 | 55B5009C25FAF13900EFBA47 /* ARView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ARView.swift; sourceTree = ""; }; 28 | 55B5009D25FAF13900EFBA47 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 29 | 55B5009E25FAF13900EFBA47 /* ContentView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; }; 30 | 55B5009F25FAF13900EFBA47 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 31 | 55B500B025FAF1C200EFBA47 /* Aliens.rcproject */ = {isa = PBXFileReference; lastKnownFileType = file.rcproject; path = Aliens.rcproject; sourceTree = ""; }; 32 | 55BFE66525D2200F00E2BB8C /* RealityKit-Collisions-Example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "RealityKit-Collisions-Example.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 33 | /* End PBXFileReference section */ 34 | 35 | /* Begin PBXFrameworksBuildPhase section */ 36 | 55BFE66225D2200F00E2BB8C /* Frameworks */ = { 37 | isa = PBXFrameworksBuildPhase; 38 | buildActionMask = 2147483647; 39 | files = ( 40 | 551479DC2A2960EF000EBB0D /* RealityCollisions in Frameworks */, 41 | ); 42 | runOnlyForDeploymentPostprocessing = 0; 43 | }; 44 | /* End PBXFrameworksBuildPhase section */ 45 | 46 | /* Begin PBXGroup section */ 47 | 551479D62A295F32000EBB0D /* Packages */ = { 48 | isa = PBXGroup; 49 | children = ( 50 | 551479D72A295F32000EBB0D /* RealityKit-Collisions */, 51 | ); 52 | name = Packages; 53 | sourceTree = ""; 54 | }; 55 | 551479D82A295FAF000EBB0D /* Frameworks */ = { 56 | isa = PBXGroup; 57 | children = ( 58 | ); 59 | name = Frameworks; 60 | sourceTree = ""; 61 | }; 62 | 55B5009625FAF13900EFBA47 /* RealityKit-Collisions-Example */ = { 63 | isa = PBXGroup; 64 | children = ( 65 | 557CD32225FC07CE00DACC41 /* README.md */, 66 | 55B5009725FAF13900EFBA47 /* Model.swift */, 67 | 55B5009825FAF13900EFBA47 /* Assets.xcassets */, 68 | 55B5009C25FAF13900EFBA47 /* ARView.swift */, 69 | 55B500B025FAF1C200EFBA47 /* Aliens.rcproject */, 70 | 55B5009D25FAF13900EFBA47 /* AppDelegate.swift */, 71 | 55B5009E25FAF13900EFBA47 /* ContentView.swift */, 72 | 55B5009925FAF13900EFBA47 /* Preview Content */, 73 | 55B5009F25FAF13900EFBA47 /* Info.plist */, 74 | ); 75 | path = "RealityKit-Collisions-Example"; 76 | sourceTree = ""; 77 | }; 78 | 55B5009925FAF13900EFBA47 /* Preview Content */ = { 79 | isa = PBXGroup; 80 | children = ( 81 | 55B5009A25FAF13900EFBA47 /* Preview Assets.xcassets */, 82 | ); 83 | path = "Preview Content"; 84 | sourceTree = ""; 85 | }; 86 | 55BFE65C25D2200F00E2BB8C = { 87 | isa = PBXGroup; 88 | children = ( 89 | 551479D62A295F32000EBB0D /* Packages */, 90 | 55B5009625FAF13900EFBA47 /* RealityKit-Collisions-Example */, 91 | 55BFE66625D2200F00E2BB8C /* Products */, 92 | 551479D82A295FAF000EBB0D /* Frameworks */, 93 | ); 94 | sourceTree = ""; 95 | }; 96 | 55BFE66625D2200F00E2BB8C /* Products */ = { 97 | isa = PBXGroup; 98 | children = ( 99 | 55BFE66525D2200F00E2BB8C /* RealityKit-Collisions-Example.app */, 100 | ); 101 | name = Products; 102 | sourceTree = ""; 103 | }; 104 | /* End PBXGroup section */ 105 | 106 | /* Begin PBXNativeTarget section */ 107 | 55BFE66425D2200F00E2BB8C /* RealityKit-Collisions-Example */ = { 108 | isa = PBXNativeTarget; 109 | buildConfigurationList = 55BFE67625D2201000E2BB8C /* Build configuration list for PBXNativeTarget "RealityKit-Collisions-Example" */; 110 | buildPhases = ( 111 | 55BFE66125D2200F00E2BB8C /* Sources */, 112 | 55BFE66225D2200F00E2BB8C /* Frameworks */, 113 | 55BFE66325D2200F00E2BB8C /* Resources */, 114 | ); 115 | buildRules = ( 116 | ); 117 | dependencies = ( 118 | ); 119 | name = "RealityKit-Collisions-Example"; 120 | packageProductDependencies = ( 121 | 551479DB2A2960EF000EBB0D /* RealityCollisions */, 122 | ); 123 | productName = "Sound Localization"; 124 | productReference = 55BFE66525D2200F00E2BB8C /* RealityKit-Collisions-Example.app */; 125 | productType = "com.apple.product-type.application"; 126 | }; 127 | /* End PBXNativeTarget section */ 128 | 129 | /* Begin PBXProject section */ 130 | 55BFE65D25D2200F00E2BB8C /* Project object */ = { 131 | isa = PBXProject; 132 | attributes = { 133 | LastSwiftUpdateCheck = 1230; 134 | LastUpgradeCheck = 1230; 135 | TargetAttributes = { 136 | 55BFE66425D2200F00E2BB8C = { 137 | CreatedOnToolsVersion = 12.3; 138 | }; 139 | }; 140 | }; 141 | buildConfigurationList = 55BFE66025D2200F00E2BB8C /* Build configuration list for PBXProject "RealityKit-Collisions-Example" */; 142 | compatibilityVersion = "Xcode 9.3"; 143 | developmentRegion = en; 144 | hasScannedForEncodings = 0; 145 | knownRegions = ( 146 | en, 147 | Base, 148 | ); 149 | mainGroup = 55BFE65C25D2200F00E2BB8C; 150 | productRefGroup = 55BFE66625D2200F00E2BB8C /* Products */; 151 | projectDirPath = ""; 152 | projectRoot = ""; 153 | targets = ( 154 | 55BFE66425D2200F00E2BB8C /* RealityKit-Collisions-Example */, 155 | ); 156 | }; 157 | /* End PBXProject section */ 158 | 159 | /* Begin PBXResourcesBuildPhase section */ 160 | 55BFE66325D2200F00E2BB8C /* Resources */ = { 161 | isa = PBXResourcesBuildPhase; 162 | buildActionMask = 2147483647; 163 | files = ( 164 | 557CD32325FC07CE00DACC41 /* README.md in Resources */, 165 | 55B500A225FAF13900EFBA47 /* Preview Assets.xcassets in Resources */, 166 | 55B500A125FAF13900EFBA47 /* Assets.xcassets in Resources */, 167 | ); 168 | runOnlyForDeploymentPostprocessing = 0; 169 | }; 170 | /* End PBXResourcesBuildPhase section */ 171 | 172 | /* Begin PBXSourcesBuildPhase section */ 173 | 55BFE66125D2200F00E2BB8C /* Sources */ = { 174 | isa = PBXSourcesBuildPhase; 175 | buildActionMask = 2147483647; 176 | files = ( 177 | 55B500A525FAF13900EFBA47 /* AppDelegate.swift in Sources */, 178 | 55B500A025FAF13900EFBA47 /* Model.swift in Sources */, 179 | 55B500A625FAF13900EFBA47 /* ContentView.swift in Sources */, 180 | 55B500B125FAF1C200EFBA47 /* Aliens.rcproject in Sources */, 181 | 55B500A425FAF13900EFBA47 /* ARView.swift in Sources */, 182 | ); 183 | runOnlyForDeploymentPostprocessing = 0; 184 | }; 185 | /* End PBXSourcesBuildPhase section */ 186 | 187 | /* Begin XCBuildConfiguration section */ 188 | 55BFE67425D2201000E2BB8C /* Debug */ = { 189 | isa = XCBuildConfiguration; 190 | buildSettings = { 191 | ALWAYS_SEARCH_USER_PATHS = NO; 192 | CLANG_ANALYZER_NONNULL = YES; 193 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 194 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 195 | CLANG_CXX_LIBRARY = "libc++"; 196 | CLANG_ENABLE_MODULES = YES; 197 | CLANG_ENABLE_OBJC_ARC = YES; 198 | CLANG_ENABLE_OBJC_WEAK = YES; 199 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 200 | CLANG_WARN_BOOL_CONVERSION = YES; 201 | CLANG_WARN_COMMA = YES; 202 | CLANG_WARN_CONSTANT_CONVERSION = YES; 203 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 204 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 205 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 206 | CLANG_WARN_EMPTY_BODY = YES; 207 | CLANG_WARN_ENUM_CONVERSION = YES; 208 | CLANG_WARN_INFINITE_RECURSION = YES; 209 | CLANG_WARN_INT_CONVERSION = YES; 210 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 211 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 212 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 213 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 214 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 215 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 216 | CLANG_WARN_STRICT_PROTOTYPES = YES; 217 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 218 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 219 | CLANG_WARN_UNREACHABLE_CODE = YES; 220 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 221 | COPY_PHASE_STRIP = NO; 222 | DEBUG_INFORMATION_FORMAT = dwarf; 223 | ENABLE_STRICT_OBJC_MSGSEND = YES; 224 | ENABLE_TESTABILITY = YES; 225 | GCC_C_LANGUAGE_STANDARD = gnu11; 226 | GCC_DYNAMIC_NO_PIC = NO; 227 | GCC_NO_COMMON_BLOCKS = YES; 228 | GCC_OPTIMIZATION_LEVEL = 0; 229 | GCC_PREPROCESSOR_DEFINITIONS = ( 230 | "DEBUG=1", 231 | "$(inherited)", 232 | ); 233 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 234 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 235 | GCC_WARN_UNDECLARED_SELECTOR = YES; 236 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 237 | GCC_WARN_UNUSED_FUNCTION = YES; 238 | GCC_WARN_UNUSED_VARIABLE = YES; 239 | IPHONEOS_DEPLOYMENT_TARGET = 14.0; 240 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; 241 | MTL_FAST_MATH = YES; 242 | ONLY_ACTIVE_ARCH = YES; 243 | SDKROOT = iphoneos; 244 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 245 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 246 | }; 247 | name = Debug; 248 | }; 249 | 55BFE67525D2201000E2BB8C /* Release */ = { 250 | isa = XCBuildConfiguration; 251 | buildSettings = { 252 | ALWAYS_SEARCH_USER_PATHS = NO; 253 | CLANG_ANALYZER_NONNULL = YES; 254 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 255 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 256 | CLANG_CXX_LIBRARY = "libc++"; 257 | CLANG_ENABLE_MODULES = YES; 258 | CLANG_ENABLE_OBJC_ARC = YES; 259 | CLANG_ENABLE_OBJC_WEAK = YES; 260 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 261 | CLANG_WARN_BOOL_CONVERSION = YES; 262 | CLANG_WARN_COMMA = YES; 263 | CLANG_WARN_CONSTANT_CONVERSION = YES; 264 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 265 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 266 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 267 | CLANG_WARN_EMPTY_BODY = YES; 268 | CLANG_WARN_ENUM_CONVERSION = YES; 269 | CLANG_WARN_INFINITE_RECURSION = YES; 270 | CLANG_WARN_INT_CONVERSION = YES; 271 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 272 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 273 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 274 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 275 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 276 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 277 | CLANG_WARN_STRICT_PROTOTYPES = YES; 278 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 279 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 280 | CLANG_WARN_UNREACHABLE_CODE = YES; 281 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 282 | COPY_PHASE_STRIP = NO; 283 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 284 | ENABLE_NS_ASSERTIONS = NO; 285 | ENABLE_STRICT_OBJC_MSGSEND = YES; 286 | GCC_C_LANGUAGE_STANDARD = gnu11; 287 | GCC_NO_COMMON_BLOCKS = YES; 288 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 289 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 290 | GCC_WARN_UNDECLARED_SELECTOR = YES; 291 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 292 | GCC_WARN_UNUSED_FUNCTION = YES; 293 | GCC_WARN_UNUSED_VARIABLE = YES; 294 | IPHONEOS_DEPLOYMENT_TARGET = 14.0; 295 | MTL_ENABLE_DEBUG_INFO = NO; 296 | MTL_FAST_MATH = YES; 297 | SDKROOT = iphoneos; 298 | SWIFT_COMPILATION_MODE = wholemodule; 299 | SWIFT_OPTIMIZATION_LEVEL = "-O"; 300 | VALIDATE_PRODUCT = YES; 301 | }; 302 | name = Release; 303 | }; 304 | 55BFE67725D2201000E2BB8C /* Debug */ = { 305 | isa = XCBuildConfiguration; 306 | buildSettings = { 307 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 308 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; 309 | CODE_SIGN_STYLE = Automatic; 310 | DEVELOPMENT_ASSET_PATHS = "\"RealityKit-Collisions-Example/Preview Content\""; 311 | DEVELOPMENT_TEAM = 9792AFNZU9; 312 | ENABLE_PREVIEWS = YES; 313 | INFOPLIST_FILE = "$(SRCROOT)/RealityKit-Collisions-Example/Info.plist"; 314 | IPHONEOS_DEPLOYMENT_TARGET = 14.0; 315 | LD_RUNPATH_SEARCH_PATHS = ( 316 | "$(inherited)", 317 | "@executable_path/Frameworks", 318 | ); 319 | PRODUCT_BUNDLE_IDENTIFIER = pro.realityAcademy.RealityCollisions; 320 | PRODUCT_NAME = "$(TARGET_NAME)"; 321 | SWIFT_VERSION = 5.0; 322 | TARGETED_DEVICE_FAMILY = "1,2"; 323 | }; 324 | name = Debug; 325 | }; 326 | 55BFE67825D2201000E2BB8C /* Release */ = { 327 | isa = XCBuildConfiguration; 328 | buildSettings = { 329 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 330 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; 331 | CODE_SIGN_STYLE = Automatic; 332 | DEVELOPMENT_ASSET_PATHS = "\"RealityKit-Collisions-Example/Preview Content\""; 333 | DEVELOPMENT_TEAM = 9792AFNZU9; 334 | ENABLE_PREVIEWS = YES; 335 | INFOPLIST_FILE = "$(SRCROOT)/RealityKit-Collisions-Example/Info.plist"; 336 | IPHONEOS_DEPLOYMENT_TARGET = 14.0; 337 | LD_RUNPATH_SEARCH_PATHS = ( 338 | "$(inherited)", 339 | "@executable_path/Frameworks", 340 | ); 341 | PRODUCT_BUNDLE_IDENTIFIER = pro.realityAcademy.RealityCollisions; 342 | PRODUCT_NAME = "$(TARGET_NAME)"; 343 | SWIFT_VERSION = 5.0; 344 | TARGETED_DEVICE_FAMILY = "1,2"; 345 | }; 346 | name = Release; 347 | }; 348 | /* End XCBuildConfiguration section */ 349 | 350 | /* Begin XCConfigurationList section */ 351 | 55BFE66025D2200F00E2BB8C /* Build configuration list for PBXProject "RealityKit-Collisions-Example" */ = { 352 | isa = XCConfigurationList; 353 | buildConfigurations = ( 354 | 55BFE67425D2201000E2BB8C /* Debug */, 355 | 55BFE67525D2201000E2BB8C /* Release */, 356 | ); 357 | defaultConfigurationIsVisible = 0; 358 | defaultConfigurationName = Release; 359 | }; 360 | 55BFE67625D2201000E2BB8C /* Build configuration list for PBXNativeTarget "RealityKit-Collisions-Example" */ = { 361 | isa = XCConfigurationList; 362 | buildConfigurations = ( 363 | 55BFE67725D2201000E2BB8C /* Debug */, 364 | 55BFE67825D2201000E2BB8C /* Release */, 365 | ); 366 | defaultConfigurationIsVisible = 0; 367 | defaultConfigurationName = Release; 368 | }; 369 | /* End XCConfigurationList section */ 370 | 371 | /* Begin XCSwiftPackageProductDependency section */ 372 | 551479DB2A2960EF000EBB0D /* RealityCollisions */ = { 373 | isa = XCSwiftPackageProductDependency; 374 | productName = RealityCollisions; 375 | }; 376 | /* End XCSwiftPackageProductDependency section */ 377 | }; 378 | rootObject = 55BFE65D25D2200F00E2BB8C /* Project object */; 379 | } 380 | -------------------------------------------------------------------------------- /RealityKitCollisions-Example/RealityKit-Collisions-Example.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /RealityKitCollisions-Example/RealityKit-Collisions-Example/ARView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ARView.swift 3 | // Sound Localization 4 | // 5 | // Created by Grant Jarvis on 2/8/21. 6 | // 7 | 8 | import ARKit 9 | import RealityKit 10 | import Combine 11 | import RealityCollisions 12 | 13 | public enum CollisionGroups: Int, HasCollisionGroups { 14 | case teammates, aliens, bigRubbberBall, ground 15 | } 16 | 17 | class ARSUIView: ARView { 18 | 19 | var dataModel : DataModel 20 | 21 | var aliensScene : Aliens.Scene! 22 | 23 | var cameraAnchor = AnchorEntity(.camera) 24 | 25 | required init(frame frameRect: CGRect, dataModel: DataModel) { 26 | self.dataModel = dataModel 27 | super.init(frame: frameRect) 28 | self.session.delegate = self 29 | loadSceneAsyncronously() 30 | installSwipeGestures() 31 | self.scene.addAnchor(cameraAnchor) 32 | 33 | //If this device has LiDAR, then allow entities to collide with the LiDAR mesh. 34 | if ARWorldTrackingConfiguration.supportsSceneReconstruction(.mesh) { 35 | runLiDARConfiguration() 36 | } 37 | } 38 | 39 | func sceneDidLoad(){ 40 | 41 | guard let groundPlane = aliensScene.findEntity(named: "Ground Plane") else {return} 42 | 43 | groundPlane.setNewCollisionFilter(belongsToGroup: CollisionGroups.ground, andCanCollideWith: [.aliens, .bigRubbberBall, .teammates]) 44 | 45 | aliensScene.alien1!.setNewCollisionFilter( 46 | belongsToGroup: CollisionGroups.aliens, 47 | andCanCollideWith: [.aliens, .bigRubbberBall, .ground]) 48 | 49 | aliensScene.alien2!.setNewCollisionFilter(belongsToGroup: CollisionGroups.aliens, 50 | andCanCollideWith: [.aliens, .bigRubbberBall, .ground]) 51 | 52 | //--// 53 | //Teammates do Not get run over by the ball, but aliens do. 54 | aliensScene.teammate1!.setNewCollisionFilter(belongsToGroup: CollisionGroups.teammates, 55 | andCanCollideWith: [.ground]) 56 | 57 | aliensScene.teammate2!.setNewCollisionFilter(belongsToGroup: CollisionGroups.aliens, 58 | andCanCollideWith: [.ground]) 59 | 60 | //--// 61 | aliensScene.bigRubberBall!.setNewCollisionFilter(belongsToGroup: CollisionGroups.bigRubbberBall, 62 | andCanCollideWith: [.ground, .aliens]) 63 | 64 | addCollisionListening(onEntity: aliensScene.bigRubberBall as! Entity & HasCollision) 65 | 66 | //If this device has LiDAR, then allow entities to collide with the LiDAR mesh. 67 | if ARWorldTrackingConfiguration.supportsSceneReconstruction(.mesh) { 68 | //Add delay to give the device time to generate the mesh. 69 | DispatchQueue.main.asyncAfter(deadline: .now() + 5) { 70 | let sceneEntities = [self.aliensScene.alien1!, 71 | self.aliensScene.alien2!, 72 | self.aliensScene.teammate1!, 73 | self.aliensScene.teammate2!, 74 | self.aliensScene.bigRubberBall!] 75 | sceneEntities.forEach { sceneEntity in 76 | sceneEntity.addCollisionWithLiDARMesh() 77 | } 78 | } 79 | } 80 | } 81 | 82 | func installSwipeGestures(){ 83 | let directions : [UISwipeGestureRecognizer.Direction] = [ 84 | .up, .down, .left, .right] 85 | directions.forEach { direction in 86 | let swipeGestureRecognizer = UISwipeGestureRecognizer(target: self, action: #selector(swiped)) 87 | swipeGestureRecognizer.direction = direction 88 | self.addGestureRecognizer(swipeGestureRecognizer) 89 | } 90 | } 91 | 92 | @objc func swiped(_ recognizer: UISwipeGestureRecognizer){ 93 | guard let bigRubberBall = aliensScene.bigRubberBall as? (Entity & HasPhysics) else {return} 94 | var impulse = SIMD3() 95 | switch recognizer.direction { 96 | case .up: 97 | impulse = [0,0,-1000] 98 | case .down: 99 | impulse = [0,0,1000] 100 | case .left: 101 | impulse = [-1000,0,0] 102 | case .right: 103 | impulse = [1000,0,0] 104 | default: 105 | break 106 | } 107 | bigRubberBall.applyLinearImpulse(impulse, relativeTo: cameraAnchor) 108 | } 109 | 110 | var collisionSubscriptions = [Cancellable]() 111 | func addCollisionListening(onEntity entity: Entity & HasCollision) { 112 | collisionSubscriptions.append(self.scene.subscribe(to: CollisionEvents.Began.self, on: entity) { event in 113 | 114 | //Place code here for when the collision begins. 115 | print(event.entityA.name, "collided with", event.entityB.name) 116 | }) 117 | collisionSubscriptions.append(self.scene.subscribe(to: CollisionEvents.Ended.self, on: entity) { event in 118 | 119 | //Place code here for when the collision ends. 120 | }) 121 | } 122 | 123 | func runLiDARConfiguration(){ 124 | let configuration = ARWorldTrackingConfiguration() 125 | configuration.planeDetection = .horizontal 126 | configuration.sceneReconstruction = .mesh 127 | self.session.run(configuration) 128 | 129 | //Allows objects to bounce off of the sceneMesh. 130 | self.environment.sceneUnderstanding.options.insert(.physics) 131 | 132 | // Show colored mesh. 133 | //self.debugOptions.insert(.showSceneUnderstanding) 134 | } 135 | 136 | func loadSceneAsyncronously(){ 137 | // Load the scene from the Reality File, checking for any errors 138 | Aliens.loadSceneAsync {[weak self] result in 139 | switch result{ 140 | case .failure (let error): 141 | print("Unable to load the scene with error: ", 142 | error.localizedDescription) 143 | case .success(let sceneAnchor): 144 | //add the anchor to the scene 145 | print("Scene Loaded Asyncronously") 146 | self?.aliensScene = sceneAnchor 147 | self?.scene.addAnchor(sceneAnchor) 148 | self?.sceneDidLoad() 149 | } 150 | } 151 | } 152 | 153 | //required function. 154 | @objc required dynamic init?(coder decoder: NSCoder) { 155 | fatalError("init(coder:) has not been implemented") 156 | } 157 | 158 | @objc required dynamic init(frame frameRect: CGRect) { 159 | fatalError("init(frame:) has not been implemented") 160 | } 161 | } 162 | 163 | 164 | // MARK: - ARSessionDelegate 165 | 166 | extension ARSUIView: ARSessionDelegate { 167 | 168 | func session(_ session: ARSession, didAdd anchors: [ARAnchor]) { 169 | //Code here 170 | } 171 | 172 | func session(_ session: ARSession, didUpdate anchors: [ARAnchor]) { 173 | //Code here 174 | } 175 | 176 | func session(_ session: ARSession, didUpdate frame: ARFrame) { 177 | //Code here 178 | } 179 | } 180 | -------------------------------------------------------------------------------- /RealityKitCollisions-Example/RealityKit-Collisions-Example/Aliens.rcproject/Library/ProjectLibrary/Contents.json: -------------------------------------------------------------------------------- 1 | [ 2 | 3 | ] -------------------------------------------------------------------------------- /RealityKitCollisions-Example/RealityKit-Collisions-Example/Aliens.rcproject/Library/ProjectLibrary/Version.json: -------------------------------------------------------------------------------- 1 | { 2 | "LibraryID" : "E9C4B94C-E47C-40E7-A14D-56401E75EE96", 3 | "Version" : "1.0" 4 | } -------------------------------------------------------------------------------- /RealityKitCollisions-Example/RealityKit-Collisions-Example/Aliens.rcproject/SceneThumbnails/4592144E-3CF4-4A12-AA68-CA11F89497EA.thumbnails/square: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Reality-Dev/RealityKit-Collisions/268b81512e9c7a81bd72364f07176f3a4ce52799/RealityKitCollisions-Example/RealityKit-Collisions-Example/Aliens.rcproject/SceneThumbnails/4592144E-3CF4-4A12-AA68-CA11F89497EA.thumbnails/square -------------------------------------------------------------------------------- /RealityKitCollisions-Example/RealityKit-Collisions-Example/Aliens.rcproject/SceneThumbnails/4592144E-3CF4-4A12-AA68-CA11F89497EA.thumbnails/wide: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Reality-Dev/RealityKit-Collisions/268b81512e9c7a81bd72364f07176f3a4ce52799/RealityKitCollisions-Example/RealityKit-Collisions-Example/Aliens.rcproject/SceneThumbnails/4592144E-3CF4-4A12-AA68-CA11F89497EA.thumbnails/wide -------------------------------------------------------------------------------- /RealityKitCollisions-Example/RealityKit-Collisions-Example/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // Sound Localization 4 | // 5 | // Created by Grant Jarvis on 2/8/21. 6 | // 7 | 8 | import UIKit 9 | import SwiftUI 10 | 11 | @main 12 | class AppDelegate: UIResponder, UIApplicationDelegate { 13 | 14 | var window: UIWindow? 15 | 16 | 17 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { 18 | 19 | // Create the SwiftUI view that provides the window contents. 20 | let contentView = ContentView().environmentObject(DataModel.shared) 21 | 22 | // Use a UIHostingController as window root view controller. 23 | let window = UIWindow(frame: UIScreen.main.bounds) 24 | window.rootViewController = UIHostingController(rootView: contentView) 25 | self.window = window 26 | window.makeKeyAndVisible() 27 | return true 28 | } 29 | 30 | func applicationWillResignActive(_ application: UIApplication) { 31 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 32 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. 33 | } 34 | 35 | func applicationDidEnterBackground(_ application: UIApplication) { 36 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 37 | } 38 | 39 | func applicationWillEnterForeground(_ application: UIApplication) { 40 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background. 41 | } 42 | 43 | func applicationDidBecomeActive(_ application: UIApplication) { 44 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 45 | } 46 | 47 | 48 | } 49 | 50 | -------------------------------------------------------------------------------- /RealityKitCollisions-Example/RealityKit-Collisions-Example/Assets.xcassets/AccentColor.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "idiom" : "universal" 5 | } 6 | ], 7 | "info" : { 8 | "author" : "xcode", 9 | "version" : 1 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /RealityKitCollisions-Example/RealityKit-Collisions-Example/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "scale" : "2x", 6 | "size" : "20x20" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "scale" : "3x", 11 | "size" : "20x20" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "scale" : "2x", 16 | "size" : "29x29" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "scale" : "3x", 21 | "size" : "29x29" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "scale" : "2x", 26 | "size" : "40x40" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "scale" : "3x", 31 | "size" : "40x40" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "scale" : "2x", 36 | "size" : "60x60" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "scale" : "3x", 41 | "size" : "60x60" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "scale" : "1x", 46 | "size" : "20x20" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "scale" : "2x", 51 | "size" : "20x20" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "scale" : "1x", 56 | "size" : "29x29" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "scale" : "2x", 61 | "size" : "29x29" 62 | }, 63 | { 64 | "idiom" : "ipad", 65 | "scale" : "1x", 66 | "size" : "40x40" 67 | }, 68 | { 69 | "idiom" : "ipad", 70 | "scale" : "2x", 71 | "size" : "40x40" 72 | }, 73 | { 74 | "idiom" : "ipad", 75 | "scale" : "1x", 76 | "size" : "76x76" 77 | }, 78 | { 79 | "idiom" : "ipad", 80 | "scale" : "2x", 81 | "size" : "76x76" 82 | }, 83 | { 84 | "idiom" : "ipad", 85 | "scale" : "2x", 86 | "size" : "83.5x83.5" 87 | }, 88 | { 89 | "idiom" : "ios-marketing", 90 | "scale" : "1x", 91 | "size" : "1024x1024" 92 | } 93 | ], 94 | "info" : { 95 | "author" : "xcode", 96 | "version" : 1 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /RealityKitCollisions-Example/RealityKit-Collisions-Example/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /RealityKitCollisions-Example/RealityKit-Collisions-Example/Assets.xcassets/launchBackground.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "color" : { 5 | "color-space" : "srgb", 6 | "components" : { 7 | "alpha" : "1.000", 8 | "blue" : "1.000", 9 | "green" : "0.705", 10 | "red" : "0.177" 11 | } 12 | }, 13 | "idiom" : "universal" 14 | }, 15 | { 16 | "appearances" : [ 17 | { 18 | "appearance" : "luminosity", 19 | "value" : "dark" 20 | } 21 | ], 22 | "color" : { 23 | "color-space" : "srgb", 24 | "components" : { 25 | "alpha" : "1.000", 26 | "blue" : "0.799", 27 | "green" : "0.130", 28 | "red" : "0.294" 29 | } 30 | }, 31 | "idiom" : "universal" 32 | } 33 | ], 34 | "info" : { 35 | "author" : "xcode", 36 | "version" : 1 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /RealityKitCollisions-Example/RealityKit-Collisions-Example/ContentView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ContentView.swift 3 | // Sound Localization 4 | // 5 | // Created by Grant Jarvis on 2/8/21. 6 | // 7 | 8 | import SwiftUI 9 | import RealityKit 10 | 11 | struct ContentView : View { 12 | @EnvironmentObject var data: DataModel 13 | var body: some View { 14 | ZStack { 15 | ARViewContainer().edgesIgnoringSafeArea(.all) 16 | //UIContent goes here. 17 | } 18 | } 19 | } 20 | 21 | struct ARViewContainer: UIViewRepresentable { 22 | 23 | func makeUIView(context: Context) -> ARView { 24 | 25 | return DataModel.shared.arView 26 | 27 | } 28 | 29 | func updateUIView(_ uiView: ARView, context: Context) {} 30 | 31 | } 32 | 33 | #if DEBUG 34 | struct ContentView_Previews : PreviewProvider { 35 | static var previews: some View { 36 | ContentView().environmentObject(DataModel.shared) 37 | } 38 | } 39 | #endif 40 | -------------------------------------------------------------------------------- /RealityKitCollisions-Example/RealityKit-Collisions-Example/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE) 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | NSCameraUsageDescription 24 | The camera is required for AR experiences. 25 | UIApplicationSupportsIndirectInputEvents 26 | 27 | UILaunchScreen 28 | 29 | UIColorName 30 | launchBackground 31 | 32 | UIRequiredDeviceCapabilities 33 | 34 | armv7 35 | arkit 36 | 37 | UIStatusBarHidden 38 | 39 | UISupportedInterfaceOrientations 40 | 41 | UIInterfaceOrientationPortrait 42 | UIInterfaceOrientationLandscapeLeft 43 | UIInterfaceOrientationLandscapeRight 44 | 45 | UISupportedInterfaceOrientations~ipad 46 | 47 | UIInterfaceOrientationPortrait 48 | UIInterfaceOrientationPortraitUpsideDown 49 | UIInterfaceOrientationLandscapeLeft 50 | UIInterfaceOrientationLandscapeRight 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /RealityKitCollisions-Example/RealityKit-Collisions-Example/Model.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Model.swift 3 | // Drawing Test 4 | // 5 | // Created by Grant Jarvis on 1/30/21. 6 | // 7 | 8 | import Combine 9 | import RealityKit 10 | import SwiftUI 11 | 12 | final class DataModel: ObservableObject { 13 | static var shared = DataModel() 14 | 15 | 16 | @Published var showingAlert = false { 17 | didSet{ 18 | print("showingAlert:", showingAlert) 19 | } 20 | } 21 | @Published var arView : ARSUIView! 22 | 23 | 24 | 25 | 26 | init(){ 27 | arView = ARSUIView(frame: .zero, dataModel: self) 28 | } 29 | } 30 | 31 | -------------------------------------------------------------------------------- /RealityKitCollisions-Example/RealityKit-Collisions-Example/Preview Content/Preview Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /Sources/RealityCollisions/CollisionFilters.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Entity Extension.swift 3 | // CollisionFilters 4 | // 5 | // Created by Grant Jarvis on 8/19/20. 6 | // Copyright © 2020 Grant Jarvis. All rights reserved. 7 | // 8 | 9 | import RealityKit 10 | import RKUtilities 11 | 12 | public protocol HasCollisionGroups: RawRepresentable & CaseIterable where RawValue == Int {} 13 | 14 | @available(iOS 13.0, macOS 10.15, *) 15 | public extension Entity { 16 | 17 | /** 18 | Automatically sets the new filter on the current CollisionComponent, or adds a CollisionComponent with the new filter if there is not one. 19 | 20 | For any of your groups that include the word "scene" or "Scene," they will automatically be treated as the .sceneUnderstanding CollisionGroup, which refers to the scene mesh for Lidar-enabled devices. 21 | - Parameters: 22 | - myGroup: The group this entity belongs to. 23 | - canCollideWith: The other groups that this entity can collide with. 24 | */ 25 | func setNewCollisionFilter(belongsToGroup myGroup: CollisionGroupsEnum, 26 | andCanCollideWith otherGroups: Set) 27 | { 28 | 29 | let filter = CollisionComponent.makeCollisionFilter(belongsToGroup: myGroup, andCanCollideWith: otherGroups) 30 | 31 | var myCollisionComponent = getCollisionComp() 32 | 33 | myCollisionComponent?.filter = filter 34 | components[CollisionComponent.self] = myCollisionComponent 35 | } 36 | 37 | private func getCollisionComp() -> CollisionComponent? { 38 | func generateCollisionComp() -> CollisionComponent? { 39 | print(name, "did Not have a collision Component...generating it.") 40 | 41 | components.set(CollisionComponent(shapes: [])) 42 | //The method stores the shape in the entity’s CollisionComponent instance. 43 | //generates shapes for descendants as well. 44 | generateCollisionShapes(recursive: true) 45 | 46 | return component(forType: CollisionComponent.self) 47 | } 48 | let existingCollisionComp = component(forType: CollisionComponent.self) 49 | 50 | return existingCollisionComp ?? generateCollisionComp() 51 | } 52 | 53 | /** 54 | Allows the entity to collide with the scene mesh on Lidar-enabled devices 55 | 56 | Call this method AFTER calling setNewCollisionFilter() if you intend on calling both methods. 57 | */ 58 | func addCollisionWithLiDARMesh(){ 59 | var myCollisionComponent = getCollisionComp() 60 | 61 | guard #available(iOS 13.4, *) else { 62 | print("sceneUnderstanding only available on iOS 13.4 or newer") 63 | return 64 | } 65 | myCollisionComponent?.filter.mask.formUnion(.sceneUnderstanding) 66 | 67 | components[CollisionComponent.self] = myCollisionComponent 68 | } 69 | 70 | func removeCollisionsWith(otherGroups: Set) 71 | { 72 | guard var myCollisionComponent = component(forType: CollisionComponent.self) else {return} 73 | 74 | var mask = myCollisionComponent.filter.mask 75 | 76 | mask = mask.subtracting(CollisionComponent.makeNewMask(otherGroups: otherGroups)) 77 | 78 | myCollisionComponent.filter.mask = mask 79 | 80 | components.set(myCollisionComponent) 81 | } 82 | 83 | /// NOTE: You must give the Entity a `CollisionComponent` and a `CollisionGroup` to belong to BEFORE calling this method. Using`Entity.setNewCollisionFilter` will accomplish this. 84 | func addCollisionsWith(otherGroups: Set) 85 | { 86 | guard var myCollisionComponent = component(forType: CollisionComponent.self) else {return} 87 | 88 | var mask = myCollisionComponent.filter.mask 89 | 90 | mask = mask.union(CollisionComponent.makeNewMask(otherGroups: otherGroups)) 91 | 92 | myCollisionComponent.filter.mask = mask 93 | 94 | components.set(myCollisionComponent) 95 | } 96 | } 97 | 98 | public extension CollisionComponent { 99 | 100 | /** 101 | Returns a new CollisionFilter, but does Not set it on an 102 | 103 | This is useful for inserting into CollisionComponent initializer as the "filter:" parameter when more customization is needed, such as using a custom shape and mode. 104 | - Parameters: 105 | - myGroup: The group this filter belongs to. 106 | - canCollideWith: The other groups that this filter can collide with. 107 | */ 108 | static func makeCollisionFilter(belongsToGroup myGroup: CollisionGroupsEnum, andCanCollideWith otherGroups: Set) -> CollisionFilter 109 | { 110 | 111 | let group = makeNewGroup(category: myGroup) 112 | 113 | let mask = makeNewMask(otherGroups: otherGroups) 114 | 115 | let filter = CollisionFilter(group: group, mask: mask) 116 | 117 | return filter 118 | } 119 | 120 | 121 | static func makeNewGroup(category: CollisionGroupsEnum) -> CollisionGroup { 122 | let groupNumber = findGroupNumber(category: category) 123 | let newGroup = CollisionGroup.init(rawValue: groupNumber) 124 | return newGroup 125 | } 126 | 127 | static fileprivate func findGroupNumber(category: CollisionGroupsEnum) -> UInt32 { 128 | //This gives 2^integerIndex 129 | //Use only UInt32's that have only one "1" bit in them to make life easier. 130 | var groupNumber = UInt32(1 << category.rawValue) 131 | 132 | //support Scene Understanding. 133 | if String(describing: category) == "sceneMesh" { 134 | if #available(iOS 13.4, *) { 135 | groupNumber = CollisionGroup.sceneUnderstanding.rawValue 136 | //2147483648 137 | //The raw value for the .sceneUnderstanding CollisionGroup 138 | } else { 139 | print("sceneUnderstanding only available on iOS 13.4 or newer") 140 | } 141 | } 142 | return groupNumber 143 | } 144 | 145 | static func makeNewMask(otherGroups: Set) -> CollisionGroup { 146 | var mask = UInt32() 147 | for category in otherGroups { 148 | mask += findGroupNumber(category: category) 149 | } 150 | return CollisionGroup(rawValue: mask) 151 | } 152 | 153 | static func categoryFromGroupNumber(groupNumber: UInt32) -> CollisionGroupsEnum? { 154 | // Ensure the groupNumber has only one "1" bit (is a power of 2) 155 | guard groupNumber != 0 && groupNumber & (groupNumber - 1) == 0 else { 156 | return nil // Not a valid group number (not a power of 2) 157 | } 158 | 159 | let rawValue = groupNumber.trailingZeroBitCount 160 | return CollisionGroupsEnum(rawValue: rawValue) 161 | } 162 | 163 | struct CollidingGroups { 164 | public let groupA: T 165 | public let groupB: T 166 | } 167 | 168 | static func collisionGroup(of entity: Entity, collisionGroups: T.Type) -> T? { 169 | let collisionComponent = entity.component(forType: CollisionComponent.self) 170 | 171 | guard let groupRaw = collisionComponent?.filter.group.rawValue else {return nil} 172 | return CollisionComponent.categoryFromGroupNumber(groupNumber: groupRaw) 173 | } 174 | 175 | static func fetchCollisionGroups(from event: any CollisionEvent, 176 | of type: T.Type) -> CollidingGroups? { 177 | 178 | guard 179 | let groupA = collisionGroup(of: event.entityA, collisionGroups: T.self), 180 | let groupB = collisionGroup(of: event.entityB, collisionGroups: T.self) 181 | else {return nil} 182 | 183 | return CollidingGroups(groupA: groupA, groupB: groupB) 184 | } 185 | } 186 | 187 | public protocol CollisionEvent { 188 | var entityA: Entity {get} 189 | var entityB: Entity {get} 190 | } 191 | 192 | extension CollisionEvents.Began: CollisionEvent {} 193 | extension CollisionEvents.Updated: CollisionEvent {} 194 | extension CollisionEvents.Ended: CollisionEvent {} 195 | -------------------------------------------------------------------------------- /media/CollisionFilters.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Reality-Dev/RealityKit-Collisions/268b81512e9c7a81bd72364f07176f3a4ce52799/media/CollisionFilters.gif --------------------------------------------------------------------------------