Lab 044 – Component inheritance?
Exploring some oddness with RealityKit components.
Have you noticed that some components seem to be inherited when placed on a parent entity? First, let’s look at scene graph.
StandParentExample has three child entities. These all have colliders, but only the base has the Input Target component.

The second collection of entities is organized a little differently. The stand with the Input Target component does not have children. Instead, the children are organized under a transform node.

We’ll also add a HoverEffectComponent to each base.
standParentExample.components.set(HoverEffectComponent())
standWithoutChildren.components.set(HoverEffectComponent())We’ll end up with two different results.
Hover: On the right, when we hover over the base, only the base shows the hover effect. On the left, the hover effect is applied to the parent and all children. This looks a bit odd to me.
Input: When we drag the base on the left, the children move with it. Child entities always move with their parents. We haven’t placed the Input Target component on the children, but we can drag them independently of the parent. This is also very odd.
My solution to this oddness is to organize my graph like the example on the right. When I need some sort of “drag bar” equivalent, I’ll make a new entity. I’ll add input and hover effects to it, and place it alone in the scene graph. When I need to move some other entities with it, I’ll sync the transforms in the gesture (or may be with a system in more complex use cases).
DragGesture()
.targetedToEntity(rightExample)
.onChanged { value in
value.entity.position = value.convert(value.location3D, from: .local, to: value.entity.parent!)
rightSyncExample.transform = value.entity.transform
}Have you noticed any other components that get inherited like this?
Hover and input examples with two slightly different entity hierarchies
Full Lab Code
struct Lab044: View {
@State var leftExample = Entity()
@State var rightExample = Entity()
@State var rightSyncExample = Entity()
var body: some View {
RealityView { content, attachments in
guard let scene = try? await Entity(named: "InputOddness", in: realityKitContentBundle) else { return }
content.add(scene)
guard let standParentExample = scene.findEntity(named: "StandParentExample") ,
let standWithoutChildren = scene.findEntity(named: "StandWithoutChildren"),
let transformParentExample = scene.findEntity(named: "TransformParentExample")
else { return }
standParentExample.components.set(HoverEffectComponent())
leftExample = standParentExample
standWithoutChildren.components.set(HoverEffectComponent())
rightExample = standWithoutChildren
rightSyncExample = transformParentExample
} update: { content, attachments in
} attachments: {
Attachment(id: "AttachmentContent") {
Text("")
}
}
.gesture(dragGestureLeft)
.gesture(dragGestureRight)
}
var dragGestureLeft: some Gesture {
DragGesture()
.targetedToEntity(leftExample)
.onChanged { value in
value.entity.position = value.convert(value.location3D, from: .local, to: value.entity.parent!)
}
}
var dragGestureRight: some Gesture {
DragGesture()
.targetedToEntity(rightExample)
.onChanged { value in
value.entity.position = value.convert(value.location3D, from: .local, to: value.entity.parent!)
rightSyncExample.transform = value.entity.transform
}
}
}Support our work so we can continue to bring you new examples and articles.
Download the Xcode project with this and many more labs from Step Into Vision.

Follow Step Into Vision