Question about customComponent.set

I’m adding a custom component at runtime and I’m trying to determine if the data that is in these brackets are schema data or data data. I want to know so I can know if it is read only or editable. I’m hoping it is data data. which would be accessed by the state machine in dataAttribute.

Can someone clarify this?

Also, when defining data in a custom component, I have been initializing the data in the add: event and then editing the data in a state machine. Can someone confirm that I can access the data with component.data.myVar in the add, tick, etc events but for the state machine I have to access it by dataAttribute.cursor(myEid). I am not getting an error warning but I haven’t completed my code so I haven’t experienced runtime.

Thanks for your help.

Schema properties are passed into the brackets. A Component’s Data is not accessible outside the component that defines the data. It’s similar to A-Frame.

Defining the data in add or onEnter, in a StateMachine, is the correct approach. Typically when access the data I either use dataAttribute.get or dataAttribute.set.

This is giving me some problems at runtime. trying to make a door animate itself and open. The door has a component and when it is clicked it creates an object and attaches an animation component to it that is supposed to target the door. I’m intending to pass the door’s eid to the animation component on creation. To this end, I have schema: { target: ecs.eid } and then my constructor says

const interactionManager = world.createEntity()
UpdateAnimation.set(world, interactionManager, {target: component.eid})

Here is my animation manager component:
// Animation update component
const UpdateAnimation = ecs.registerComponent({
name: ‘UpdateAnimation’,
schema: {
target: ecs.eid,
},
tick: (world, component) => {
const targetObj = world.three.entityToObject.get(component.target)
if (targetObj.mixer) {
const {mixer} = targetObj
mixer.update(mixer.clock.getDelta())
}
},
})

Studio is saying that property target does not exist.

Your approach looks correct on the surface however I haven’t tried it. You might find it easier to simply mutate the GLTFModel component on the entity so it plays a different animationClip.

I’m just trying to think my way through this. Can I create an entity out of thin air without an object in my navigator already? Can I only programmatically create entities when they already exist? I’m thinking if the entity didn’t get created then it’s id can’t be passed to target. I’m new to this program, I don’t have a lot of experience with js. I know Lua pretty well from working with other platforms so there are probably a lot of things that you take for granted that I don’t know.

I’m studying the GltfModel to see if I can make it do what I need to do, my door model is from the web and it has one animation that both opens and then closes the door. I need to make it open and close as separate actions. click to open, click to close. I’ll report when/if I get it working with GltfModel

Can you send me the door model? I’ll make an example for you.

const entity = world.createEntity()

entity is an eid. In order for you to call that function however you need to write a custom component which needs to be attached to some existing entity in the scene. There isn’t a way to run code that’s not attached to an entity in some way.

I’m not sure how, I tried to send it in a message on this board and it wouldn’t let me attach a glb file. Is there a way I can share the whole project with you? I guess I can stick it in a google drive folder and share it that way.

Land your changes and share your project with the support workspace and I’ll take a look. :slight_smile:

1 Like

After taking a look at your project here are my tips:

  1. Edit your model in Blender or similar so that there’s two animation clips: Open and Closed.
  2. Use a State Machine like this one to accomplish the door interaction.
import * as ecs from '@8thwall/ecs'

ecs.registerComponent({
  name: 'Door',
  schema: {
  },
  schemaDefaults: {
  },
  data: {
    canInteract: ecs.boolean,
  },
  stateMachine: ({world, eid, dataAttribute}) => {
    ecs.defineState('closed')
      .initial()
      .onEnter(() => {
        ecs.GltfModel.set(world, eid, {
          animationClip: 'Close',
          paused: true,
          time: 0,
          timeScale: 1,
          loop: false,
        })
      })
      .onEvent(ecs.input.SCREEN_TOUCH_START, 'opening')

    ecs.defineState('opening')
      .onEnter(() => {
        ecs.GltfModel.set(world, eid, {
          animationClip: 'Open',
          paused: false,
        })
      })
      .wait(3200, 'open')

    ecs.defineState('open')
      .onEnter(() => {
        ecs.GltfModel.set(world, eid, {
          animationClip: 'Open',
          paused: true,
        })
      })
      .onEvent(ecs.input.SCREEN_TOUCH_START, 'closing')

    ecs.defineState('closing')
      .onEnter(() => {
        ecs.GltfModel.set(world, eid, {
          animationClip: 'Close',
          paused: false,
        })
      })
      .wait(3200, 'closed')
  },
  add: (world, component) => {
  },
  tick: (world, component) => {
  },
  remove: (world, component) => {
  },
})

The most important step here is to separate out your animations into multiple clips in a 3D software so you can reduce the amount of logic needed to track both animation state and interaction state.