-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathBasicSystem.tsx
More file actions
150 lines (125 loc) · 4.45 KB
/
BasicSystem.tsx
File metadata and controls
150 lines (125 loc) · 4.45 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
import React, { useEffect } from 'react'
import { isClient } from '@ir-engine/common/src/utils/getEnvironment'
import {
Engine,
EntityUUID,
SimulationSystemGroup,
UUIDComponent,
defineSystem,
getComponent,
setComponent
} from '@ir-engine/ecs'
import { ECSState } from '@ir-engine/ecs/src/ECSState'
import { PrimitiveGeometryComponent } from '@ir-engine/engine/src/scene/components/PrimitiveGeometryComponent'
import { GeometryTypeEnum } from '@ir-engine/engine/src/scene/constants/GeometryTypeEnum'
import {
defineAction,
defineState,
dispatchAction,
getMutableState,
getState,
none,
useHookstate
} from '@ir-engine/hyperflux'
import { NetworkState, NetworkTopics, WorldNetworkAction } from '@ir-engine/network'
import { NameComponent } from '@ir-engine/spatial/src/common/NameComponent'
import { Physics } from '@ir-engine/spatial/src/physics/classes/Physics'
import { ColliderComponent } from '@ir-engine/spatial/src/physics/components/ColliderComponent'
import { RigidBodyComponent } from '@ir-engine/spatial/src/physics/components/RigidBodyComponent'
import { VisibleComponent } from '@ir-engine/spatial/src/renderer/components/VisibleComponent'
import { SpawnObjectActions } from '@ir-engine/spatial/src/transform/SpawnObjectActions'
import { TransformComponent } from '@ir-engine/spatial/src/transform/components/TransformComponent'
import { Vector3 } from 'three'
/**
* Basic actions to spawn and destroy objects
* This extends and naturally utilizes the functionality in EntityNetworkState
*/
const BasicActions = {
spawnAction: defineAction(
SpawnObjectActions.spawnObject.extend({
type: 'ee.basic.SPAWN_OBJECT',
$topic: NetworkTopics.world
})
)
}
/**
* Global state that tracks locally spawned or destroyed artifacts by using action receptors
*/
const BasicState = defineState({
name: 'ee.basic.BasicState',
initial: {} as Record<EntityUUID, {}>,
receptors: {
onSpawnAction: BasicActions.spawnAction.receive((action) => {
const state = getMutableState(BasicState)
state[action.entityUUID].merge({})
}),
onDestroyObject: WorldNetworkAction.destroyEntity.receive((action) => {
const state = getMutableState(BasicState)
state[action.entityUUID].set(none)
})
},
/**
* Observe spawn events and create a sub-reactor for each entry in the basic state
*/
reactor: () => {
const basicState = useHookstate(getMutableState(BasicState))
return (
<>
{basicState.keys.map((entityUUID: EntityUUID) => (
<BasicObject key={entityUUID} entityUUID={entityUUID} />
))}
</>
)
}
})
/**
* A reactor such that each basic state record has an associated a visual artifact
*/
const BasicObject = ({ entityUUID }: { entityUUID: EntityUUID }) => {
/** Entity creation and destruction is handled by EntityNetworkState */
const entity = UUIDComponent.useEntityByUUID(entityUUID)
useEffect(() => {
if (!entity) return
setComponent(entity, TransformComponent, { scale: new Vector3(0.1, 0.1, 0.1) })
setComponent(entity, VisibleComponent)
setComponent(entity, NameComponent, entityUUID)
setComponent(entity, PrimitiveGeometryComponent, { geometryType: GeometryTypeEnum.SphereGeometry })
setComponent(entity, RigidBodyComponent, { type: 'dynamic' })
setComponent(entity, ColliderComponent, { shape: 'sphere' })
if (isClient) return
const angle = Math.random() * Math.PI * 2
const direction = new Vector3(Math.sin(angle), 0, Math.cos(angle))
const velocity = 0.025 + Math.random() * 0.01
const world = Physics.getWorld(entity)!
Physics.applyImpulse(world, entity, direction.multiplyScalar(velocity))
}, [entity])
return null
}
let counter = 0
const spawnRate = 3
/**
* Spawn a new basic entity every 3 seconds
*/
const execute = () => {
/** Only run this on the server */
if (isClient || !NetworkState.worldNetwork) return
const { deltaSeconds, elapsedSeconds } = getState(ECSState)
counter += deltaSeconds
if (counter < spawnRate) return
counter = 0
const entityUUID = `basic-${elapsedSeconds}` as EntityUUID
const action = BasicActions.spawnAction({
parentUUID: getComponent(Engine.instance.originEntity, UUIDComponent),
entityUUID,
position: new Vector3(Math.random(), 1, Math.random())
})
dispatchAction(action)
}
/**
* System to register the execute function
*/
export const BasicSystem = defineSystem({
uuid: 'ee.basic.system',
execute,
insert: { with: SimulationSystemGroup }
})