Skip to content

XrInputSource#elementEntity holds the ElementComponent, not the Entity its docs and type promise #9660

Open

Description

@willeastcott

XrInputSource#elementEntity is documented as the "entity with Element component at which this input source is hovering" and typed Entity|null, but ElementInput stores the hovered ElementComponent in it. Code that follows the docs or the TypeScript type breaks at runtime: elementEntity.name is undefined and elementEntity.getPosition() throws. Only a null check works either way.

Where

  • The docs and type:
    /**
    * If {@link elementInput} is true, this property will hold entity with Element
    * component at which this input source is hovering, or null if not hovering over any element.
    *
    * @type {Entity|null}
    */
    get elementEntity() {
    return this._elementEntity;
    }
    , emitted as get elementEntity(): Entity | null in playcanvas.d.ts
  • The assignment:
    inputSource._elementEntity = element || null;
    . element comes from _getTargetElementByRay, which returns one of the ElementComponents registered with addElement (
    addElement(element) {
    if (this._elements.indexOf(element) === -1) {
    this._elements.push(element);
    }
    }
    ).

Both date from #1988 (2020), which documented the property as a pc.Entity.

Repro

On the null device, with the fake WebXR session from test/framework/xr/fake-webxr.mjs, I set up a world-space screen with one useInput image element (button), an ElementInput, and a controller whose ray points at the element. After one XR frame:

Check Result
inputSource.elementEntity instanceof Entity false
inputSource.elementEntity === button.element true
inputSource.elementEntity.entity === button true
inputSource.elementEntity.name undefined
inputSource.elementEntity.getPosition() TypeError: ... getPosition is not a function

In a browser, any XR session with world-space UI shows the same:

app.xr.input.on('selectstart', (inputSource) => {
    console.log(inputSource.elementEntity); // an ElementComponent while over UI
});

Nothing in the engine, its examples or scripts/esm reads the property. The user manual repeats the documented contract on UI in XR ("The entity of the element that this input source points at") and Input Sources ("read its elementEntity for the entity of the element it points at").

Fix

There are two options:

  • Store element.entity, which matches the name, the docs, the type and the manual. This changes the value for anyone relying on the component today (their elementEntity.entity would become undefined), so it needs a release note.
  • Keep the value and change the docs and type to ElementComponent|null. The name would stay misleading, and the manual would need updating.

A test that points an input source's ray at an element and checks elementEntity would pin either choice.

Found in passing while auditing the XR scripts in scripts/esm/xr.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    area: xrXR related issue

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions