├── .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 | 
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
--------------------------------------------------------------------------------