It may be because I have onTick running in multiple scripts simultaneously. Is there a best practice for this? Here are my 4 current scripts
Camera Controller
import * as ecs from '@8thwall/ecs' // This is how you access the ecs library.
ecs.registerComponent({
name: 'camera-controller',
schema: {
// Add data that can be configured on the component.
playerEntity: ecs.eid, // this is the Player
},
schemaDefaults: {
// Add defaults for the schema fields.
},
data: {
// Add data that cannot be configured outside of the component.
},
stateMachine: ({world, eid, dataAttribute, schemaAttribute}) => {
ecs.defineState('inGame').initial()
.onTick(() => {
const PlayerPositionY = ecs.Position.get(world,
schemaAttribute.cursor(eid).playerEntity).y
const cameraPosition = PlayerPositionY + 7
ecs.Position.mutate(world, eid, (cursor) => {
cursor.y = cameraPosition
})
})
},
add: (world, component) => {
// Runs when the component is added to the world.
},
tick: (world, component) => {
// Runs every frame.
},
remove: (world, component) => {
// Runs when the component is removed from the world.
},
})
Player Controller
import * as ecs from '@8thwall/ecs' // This is how you access the ecs library.
ecs.registerComponent({
name: 'player-controller',
schema: {
// Add data that can be configured on the component.
},
schemaDefaults: {
// Add defaults for the schema fields.
},
data: {
// Add data that cannot be configured outside of the component.
},
add: (world, component) => {
// Runs when the component is added to the world.
},
stateMachine: ({world, eid, dataAttribute, schemaAttribute}) => {
// Active state: When the expereince is active
ecs.defineState('Standing').initial()
ecs.defineState('Squating')
ecs.defineState('Jumping')
ecs.defineState('Falling')
ecs.defineState('Laying')
},
tick: (world, component) => {
// Runs every frame.
},
remove: (world, component) => {
// Runs when the component is removed from the world.
},
})
Jump Controller
import * as ecs from '@8thwall/ecs' // This is how you access the ecs library.
ecs.registerComponent({
name: 'jump-controller',
schema: {
jumpForce: ecs.f32, // this is the force we use to scale the jump power
// @label Z Rotation Starting Point (in Degrees)
zRotationStart: ecs.f32, // this is the starting z place of the rotation
// @label Z Rotation Finishing Point (in Degrees)
zRotationFinish: ecs.f32, // this is the starting z place of the rotation
// @label Z Rotation Duration (in seconds)
zRotationDuration: ecs.f32, // this is the starting z place of the rotation
inputController: ecs.eid, // this is the input controller entity
},
schemaDefaults: {
jumpForce: 20, // this is the default value of jump force
zRotationStart: 30, // this is the default value of jump force
zRotationFinish: 150, // this is the default value of jump force
zRotationDuration: 1.5, // this is the default value of jump force
},
data: {
movingLeft: ecs.boolean, // this is for the setting angle tick
rotationPerMilisecond: ecs.f32, // this is the amount we rotate by mer milisecond
previousZRotation: ecs.f32, // this is the previous z rotation
jumpZAngle: ecs.f32, // this is the value of the z jump angle after set
jumpForceFinal: ecs.f32, // this is the final jump force value
player: ecs.eid, // this is the player
},
stateMachine: ({world, eid, schemaAttribute, dataAttribute}) => {
const setValue = ecs.defineTrigger()
const SetAngle = () => {
dataAttribute.cursor(eid).jumpZAngle = dataAttribute.cursor(eid).previousZRotation
setValue.trigger()
}
const SetPower = () => {
dataAttribute.cursor(eid).jumpForceFinal = 1 * schemaAttribute.cursor(eid).jumpForce
setValue.trigger()
}
const ApplyForce = () => {
const horizontalForce = Math.cos(dataAttribute.cursor(eid).jumpZAngle *
(Math.PI / 180)) * dataAttribute.cursor(eid).jumpForceFinal
const verticalForce = Math.sin(dataAttribute.cursor(eid).jumpZAngle *
(Math.PI / 180)) * dataAttribute.cursor(eid).jumpForceFinal
ecs.physics.applyImpulse(world, dataAttribute.cursor(eid).player,
horizontalForce, verticalForce, 0)
}
ecs.defineState('idle')
ecs.defineState('settingAngle').initial()
.onTrigger(setValue, 'settingPower')
.listen(schemaAttribute.cursor(eid).inputController, 'Submit', SetAngle)
.onEnter(() => {
dataAttribute.cursor(eid).previousZRotation =
schemaAttribute.cursor(eid).zRotationStart
dataAttribute.cursor(eid).movingLeft = true
})
.onTick(() => {
const {delta} = world.time // Get the time delta for smooth movement
let newZRotation // this is the z rotation in degrees
if (dataAttribute.cursor(eid).movingLeft === true) {
newZRotation = dataAttribute.cursor(eid).previousZRotation +
(delta * dataAttribute.cursor(eid).rotationPerMilisecond)
if (newZRotation >= schemaAttribute.cursor(eid).zRotationFinish) {
dataAttribute.cursor(eid).movingLeft = false
}
} else {
newZRotation = dataAttribute.cursor(eid).previousZRotation -
(delta * dataAttribute.cursor(eid).rotationPerMilisecond)
if (newZRotation <= schemaAttribute.cursor(eid).zRotationStart) {
dataAttribute.cursor(eid).movingLeft = true
}
}
const newQuatRotaion = ecs.math.quat.zDegrees(newZRotation) // this is a Quaternion
ecs.Quaternion.set(world, eid, newQuatRotaion)
dataAttribute.cursor(eid).previousZRotation = newZRotation
})
ecs.defineState('settingPower')
.onTrigger(setValue, 'moving')
.listen(schemaAttribute.cursor(eid).inputController, 'Submit', SetPower)
ecs.defineState('moving')
.onEnter(() => {
ApplyForce()
})
.onTick(() => {
console.log(ecs.physics.getLinearVelocity(world, dataAttribute.cursor(eid).player).y)
})
},
add: (world, component) => {
component.data.movingLeft = true
const rotationDistance = component.schema.zRotationFinish - component.schema.zRotationStart
const actualDuration = component.schema.zRotationDuration * 1000
const rotationPerMilisecond = rotationDistance / actualDuration
component.data.rotationPerMilisecond = rotationPerMilisecond
component.data.player = world.getParent(component.eid)
},
tick: (world, component) => {
},
remove: (world, component) => {
},
})
Input Controller
import * as ecs from '@8thwall/ecs' // This is how you access the ecs library.
// Register the InputController component
ecs.registerComponent({
name: 'input-controller',
schema: {
// UI buttons for various actions
// submitButton: ecs.eid, // Entity ID for UI button submit
},
data: {
buttonClicked: ecs.boolean, //
},
// Define the state machine for handling input during different game phases
stateMachine: ({world, eid, dataAttribute, schemaAttribute}) => {
// Function to handle button input
const handleClick = (buttonName) => {
if (dataAttribute.cursor(eid).buttonClicked === false) {
world.events.dispatch(eid, buttonName) // Dispatch button Clicked event
dataAttribute.cursor(eid).buttonClicked = true
console.log(`clicked ${buttonName}`)
}
}
// Active state: When the expereince is active
ecs.defineState('inGame').initial()
.onTick(() => {
if (world.input.getAction('Submit')) handleClick('Submit')
else dataAttribute.cursor(eid).buttonClicked = false
})
// .listen(schemaAttribute.cursor(eid).submitButton,
// ecs.input.SCREEN_TOUCH_START, () => handleClick('Submit'))
},
})