@@ -14,14 +14,15 @@ import {
1414} from '@ir-engine/ecs'
1515import { LoopAnimationComponent } from '@ir-engine/engine/src/avatar/components/LoopAnimationComponent'
1616import { GLTFComponent } from '@ir-engine/engine/src/gltf/GLTFComponent'
17- import { NodeIDComponent } from '@ir-engine/engine/src/gltf/NodeIDComponent'
17+ import { NodeID , NodeIDComponent } from '@ir-engine/engine/src/gltf/NodeIDComponent'
1818import {
1919 InteractableComponent ,
2020 XRUIActivationType
2121} from '@ir-engine/engine/src/interaction/components/InteractableComponent'
2222import { ImageComponent } from '@ir-engine/engine/src/scene/components/ImageComponent'
2323import { LinkComponent } from '@ir-engine/engine/src/scene/components/LinkComponent'
2424import { MediaComponent } from '@ir-engine/engine/src/scene/components/MediaComponent'
25+ import { ObservableComponent } from '@ir-engine/engine/src/scene/components/ObservableComponent'
2526import { ParticleSystemComponent } from '@ir-engine/engine/src/scene/components/ParticleSystemComponent'
2627import { PrimitiveGeometryComponent } from '@ir-engine/engine/src/scene/components/PrimitiveGeometryComponent'
2728import { SDFComponent } from '@ir-engine/engine/src/scene/components/SDFComponent'
@@ -39,16 +40,22 @@ import { useHookstate } from '@ir-engine/hyperflux'
3940import { TransformComponent } from '@ir-engine/spatial'
4041import { CallbackComponent } from '@ir-engine/spatial/src/common/CallbackComponent'
4142import { NameComponent } from '@ir-engine/spatial/src/common/NameComponent'
42- import { Q_IDENTITY , Q_Y_180 } from '@ir-engine/spatial/src/common/constants/MathConstants'
43+ import { PI , Q_IDENTITY , Q_Y_180 , Vector3_Up } from '@ir-engine/spatial/src/common/constants/MathConstants'
4344import { InputComponent } from '@ir-engine/spatial/src/input/components/InputComponent'
44- import { setVisibleComponent } from '@ir-engine/spatial/src/renderer/components/VisibleComponent'
45+ import { VisibleComponent , setVisibleComponent } from '@ir-engine/spatial/src/renderer/components/VisibleComponent'
4546import { ObjectLayerMasks } from '@ir-engine/spatial/src/renderer/constants/ObjectLayers'
47+ import {
48+ MaterialInstanceComponent ,
49+ MaterialStateComponent
50+ } from '@ir-engine/spatial/src/renderer/materials/MaterialComponent'
4651import React , { useEffect } from 'react'
47- import { MathUtils } from 'three'
52+ import { MathUtils , MeshLambertMaterial , Quaternion , Vector3 } from 'three'
4853import { useAvatars } from '../../engine/TestUtils'
4954import { useExampleEntity } from '../utils/common/entityUtils'
5055import ComponentNamesUI from './ComponentNamesUI'
5156
57+ const BehaviorComponent = ObservableComponent
58+
5259export const metadata = {
5360 title : 'Components Examples' ,
5461 description : 'Components examples'
@@ -442,6 +449,157 @@ export const subComponentExamples = [
442449 onLoad ( entity )
443450 } , [ callback ] )
444451
452+ return null
453+ }
454+ } ,
455+ {
456+ name : 'Behavior' ,
457+ description : 'Add arbitrary behaviors to objects' ,
458+ Reactor : ( props : { parent : Entity ; onLoad : ( entity : Entity ) => void } ) => {
459+ const { parent, onLoad } = props
460+ const doorEntity = useExampleEntity ( parent )
461+ const buttonEntity = useExampleEntity ( parent )
462+ const pedastalEntity = useExampleEntity ( parent )
463+
464+ useEffect ( ( ) => {
465+ setComponent ( doorEntity , TransformComponent , { position : new Vector3 ( 6.5 , 0 , 2.5 ) } )
466+ setComponent ( doorEntity , NameComponent , 'Door' )
467+ setComponent ( doorEntity , GLTFComponent , {
468+ src : config . client . fileServer + '/projects/ir-engine/ir-development-test-suite/assets/GLTF/basic_door.glb'
469+ } )
470+ setComponent ( doorEntity , VisibleComponent )
471+
472+ setComponent ( pedastalEntity , TransformComponent , { position : new Vector3 ( 0 , 0.5 , 0 ) } )
473+ setComponent ( pedastalEntity , PrimitiveGeometryComponent , {
474+ geometryType : GeometryTypeEnum . BoxGeometry ,
475+ geometryParams : {
476+ width : 1 ,
477+ height : 1 ,
478+ depth : 1 ,
479+ widthSegments : 1 ,
480+ heightSegments : 1 ,
481+ depthSegments : 1
482+ }
483+ } )
484+ setComponent ( pedastalEntity , NameComponent , 'Pedestal' )
485+ const lightpurpleHex = 0x9b59b6
486+ setComponent ( pedastalEntity , MaterialStateComponent , {
487+ material : new MeshLambertMaterial ( { color : lightpurpleHex } )
488+ } )
489+ setComponent ( pedastalEntity , MaterialInstanceComponent , { uuid : [ getComponent ( pedastalEntity , UUIDComponent ) ] } )
490+ setComponent ( pedastalEntity , VisibleComponent , true )
491+
492+ setComponent ( buttonEntity , TransformComponent , {
493+ position : new Vector3 ( 0 , 1.025 , 0 )
494+ } )
495+ setComponent ( buttonEntity , PrimitiveGeometryComponent , {
496+ geometryType : GeometryTypeEnum . BoxGeometry ,
497+ geometryParams : {
498+ width : 0.2 ,
499+ height : 0.05 ,
500+ depth : 0.2 ,
501+ widthSegments : 1 ,
502+ heightSegments : 1 ,
503+ depthSegments : 1
504+ }
505+ } )
506+ setComponent ( buttonEntity , NameComponent , 'Button' )
507+ setComponent ( buttonEntity , MaterialStateComponent , { material : new MeshLambertMaterial ( { color : 'red' } ) } )
508+ setComponent ( buttonEntity , MaterialInstanceComponent , { uuid : [ getComponent ( buttonEntity , UUIDComponent ) ] } )
509+ setComponent ( buttonEntity , VisibleComponent , true )
510+
511+ setComponent ( buttonEntity , InputComponent , { highlight : true , grow : true } )
512+ setComponent ( buttonEntity , InteractableComponent , {
513+ label : '' ,
514+ clickInteract : true ,
515+ uiActivationType : XRUIActivationType . proximity ,
516+ activationDistance : 2 ,
517+ highlighted : true ,
518+ callbacks : [
519+ {
520+ callbackID : 'Button Click Callback' ,
521+ target : getComponent ( buttonEntity , NodeIDComponent )
522+ } ,
523+ {
524+ callbackID : 'Button Click Callback 2' ,
525+ target : getComponent ( buttonEntity , NodeIDComponent )
526+ }
527+ ]
528+ } )
529+
530+ const doorNodeID = '5' as NodeID // the door inside the door model
531+ const Q_Y_120 = new Quaternion ( ) . setFromAxisAngle ( Vector3_Up , PI * ( 120 / 180 ) )
532+
533+ setComponent ( buttonEntity , BehaviorComponent , {
534+ observers : [
535+ {
536+ conditions : [
537+ {
538+ type : 'callback' ,
539+ nodeID : getComponent ( buttonEntity , NodeIDComponent ) ,
540+ callback : 'Button Click Callback'
541+ } ,
542+ // ensure door is not already open by getting the rotation
543+ {
544+ type : 'entity' ,
545+ nodeID : doorNodeID ,
546+ sourceNodeID : getComponent ( doorEntity , NodeIDComponent ) ,
547+ component : TransformComponent . jsonID ,
548+ property : 'rotation.y' ,
549+ value : 0 ,
550+ condition : 'equal'
551+ }
552+ ] ,
553+ effects : [
554+ {
555+ type : 'transition' ,
556+ nodeID : doorNodeID ,
557+ sourceNodeID : getComponent ( doorEntity , NodeIDComponent ) ,
558+ jsonID : TransformComponent . jsonID ,
559+ propertyPath : 'rotation' ,
560+ value : Q_Y_120 ,
561+ duration : 1000 ,
562+ easing : Easing . exponential . inOut . path
563+ }
564+ ] ,
565+ networked : true
566+ } ,
567+ {
568+ conditions : [
569+ {
570+ type : 'callback' ,
571+ nodeID : getComponent ( buttonEntity , NodeIDComponent ) ,
572+ callback : 'Button Click Callback 2'
573+ } ,
574+ // ensure door is not already closed by getting the rotation
575+ {
576+ type : 'entity' ,
577+ nodeID : doorNodeID ,
578+ sourceNodeID : getComponent ( doorEntity , NodeIDComponent ) ,
579+ component : TransformComponent . jsonID ,
580+ property : 'rotation.y' ,
581+ value : 0 ,
582+ condition : 'notEqual'
583+ }
584+ ] ,
585+ effects : [
586+ {
587+ type : 'transition' ,
588+ nodeID : doorNodeID ,
589+ sourceNodeID : getComponent ( doorEntity , NodeIDComponent ) ,
590+ jsonID : TransformComponent . jsonID ,
591+ propertyPath : 'rotation' ,
592+ value : Q_IDENTITY ,
593+ duration : 1000 ,
594+ easing : Easing . exponential . inOut . path
595+ }
596+ ] ,
597+ networked : true
598+ }
599+ ]
600+ } )
601+ } , [ ] )
602+
445603 return null
446604 }
447605 }
@@ -494,6 +652,8 @@ export const ComponentExamples = (props: {
494652 const xrui = useHookstate ( { entity : UndefinedEntity } )
495653
496654 useEffect ( ( ) => {
655+ if ( ! xrui . entity . value ) return
656+
497657 const componentNamesUIEntity = createEntity ( )
498658 setComponent ( componentNamesUIEntity , UUIDComponent , generateEntityUUID ( ) )
499659 setComponent ( componentNamesUIEntity , EntityTreeComponent , { parentEntity : sceneEntity } )
@@ -504,7 +664,7 @@ export const ComponentExamples = (props: {
504664 return ( ) => {
505665 removeEntity ( componentNamesUIEntity )
506666 }
507- } , [ Reactor ] )
667+ } , [ Reactor , xrui . entity . value ] )
508668
509669 return < Reactor parent = { sceneEntity } onLoad = { xrui . entity . set } />
510670}
0 commit comments