UNPKG

@needle-tools/engine

Version:

Needle Engine is a web-based runtime for 3D apps. It runs on your machine for development with great integrations into editors like Unity or Blender - and can be deployed onto any device! It is flexible, extensible and networking and XR are built-in

341 lines (340 loc) • 19.2 kB
/// <reference types="webxr" /> import { Euler, Object3D, Quaternion, Scene, Vector3 } from "three"; import { HideFlags, type IInstantiateOptions } from "../engine/engine_gameobject.js"; import { SyncInstantiateOptions } from "../engine/engine_networking_instantiate.js"; import { Context, FrameEvent } from "../engine/engine_setup.js"; import type { Collision, ComponentInit, Constructor, ConstructorConcrete, GuidsMap, ICollider, IComponent, IGameObject, SourceIdentifier } from "../engine/engine_types.js"; import type { INeedleXRSessionEventReceiver, NeedleXRControllerEventArgs, NeedleXREventArgs } from "../engine/engine_xr.js"; import { type IPointerEventHandler, PointerEventData } from "./ui/PointerEvents.js"; /** * All {@type Object3D} types that are loaded in Needle Engine do automatically receive the GameObject extensions like `addComponent` etc. * Many of the GameObject methods can be imported directly via `@needle-tools/engine` as well: * ```typescript * import { addComponent } from "@needle-tools/engine"; * ``` */ export declare abstract class GameObject extends Object3D implements Object3D, IGameObject { abstract activeSelf: boolean; /** @deprecated use `addComponent` */ abstract addNewComponent<T extends IComponent>(type: ConstructorConcrete<T>, init?: ComponentInit<T>): T; /** creates a new component on this gameObject */ abstract addComponent<T extends IComponent>(comp: T | ConstructorConcrete<T>, init?: ComponentInit<T>): T; abstract removeComponent<T extends IComponent>(comp: T): T; abstract getOrAddComponent<T>(typeName: ConstructorConcrete<T> | null): T; abstract getComponent<T>(type: Constructor<T>): T | null; abstract getComponents<T>(type: Constructor<T>, arr?: T[]): Array<T>; abstract getComponentInChildren<T>(type: Constructor<T>): T | null; abstract getComponentsInChildren<T>(type: Constructor<T>, arr?: T[]): Array<T>; abstract getComponentInParent<T>(type: Constructor<T>): T | null; abstract getComponentsInParent<T>(type: Constructor<T>, arr?: T[]): Array<T>; abstract get worldPosition(): Vector3; abstract set worldPosition(val: Vector3); abstract set worldQuaternion(val: Quaternion); abstract get worldQuaternion(): Quaternion; abstract set worldRotation(val: Vector3); abstract get worldRotation(): Vector3; abstract set worldScale(val: Vector3); abstract get worldScale(): Vector3; abstract get worldForward(): Vector3; abstract get worldRight(): Vector3; abstract get worldUp(): Vector3; guid: string | undefined; abstract destroy(): any; static isDestroyed(go: Object3D): boolean; static setActive(go: Object3D, active: boolean, processStart?: boolean): void; /** If the object is active (same as go.visible) */ static isActiveSelf(go: Object3D): boolean; /** If the object is active in the hierarchy (e.g. if any parent is invisible or not in the scene it will be false) * @param go object to check */ static isActiveInHierarchy(go: Object3D): boolean; static markAsInstancedRendered(go: Object3D, instanced: boolean): void; static isUsingInstancing(instance: Object3D): boolean; /** Run a callback for all components of the provided type on the provided object and its children (if recursive is true) * @param instance object to run the method on * @param cb callback to run on each component, "return undefined;" to continue and "return <anything>;" to break the loop * @param recursive if true, the method will be run on all children as well * @returns the last return value of the callback */ static foreachComponent(instance: Object3D, cb: (comp: Component) => any, recursive?: boolean): any; /** Creates a new instance of the provided object. The new instance will be created on all connected clients * @param instance object to instantiate * @param opts options for the instantiation */ static instantiateSynced(instance: GameObject | Object3D | null, opts: SyncInstantiateOptions): GameObject | null; /** Creates a new instance of the provided object (like cloning it including all components and children) * @param instance object to instantiate * @param opts options for the instantiation (e.g. with what parent, position, etc.) */ static instantiate(instance: GameObject | Object3D, opts?: IInstantiateOptions | null): GameObject; /** Destroys a object on all connected clients (if you are in a networked session) * @param instance object to destroy */ static destroySynced(instance: Object3D | Component, context?: Context, recursive?: boolean): void; /** Destroys a object * @param instance object to destroy * @param recursive if true, all children will be destroyed as well. true by default */ static destroy(instance: Object3D | Component, recursive?: boolean): void; /** * Add an object to parent and also ensure all components are being registered */ static add(instance: Object3D | null | undefined, parent: Object3D, context?: Context): void; /** * Removes the object from its parent and deactivates all of its components */ static remove(instance: Object3D | null | undefined): void; /** Invokes a method on all components including children (if a method with that name exists) */ static invokeOnChildren(go: Object3D | null | undefined, functionName: string, ...args: any): void; /** Invokes a method on all components that have a method matching the provided name * @param go object to invoke the method on all components * @param functionName name of the method to invoke */ static invoke(go: Object3D | null | undefined, functionName: string, children?: boolean, ...args: any): void; /** @deprecated use `addComponent` */ static addNewComponent<T extends IComponent>(go: IGameObject | Object3D, type: T | ConstructorConcrete<T>, init?: ComponentInit<T>, callAwake?: boolean): T; /** * Add a new component (or move an existing component) to the provided object * @param go object to add the component to * @param instanceOrType if an instance is provided it will be moved to the new object, if a type is provided a new instance will be created and moved to the new object * @param init optional init object to initialize the component with * @param callAwake if true, the component will be added and awake will be called immediately */ static addComponent<T extends IComponent>(go: IGameObject | Object3D, instanceOrType: T | ConstructorConcrete<T>, init?: ComponentInit<T>, opts?: { callAwake: boolean; }): T; /** * Moves a component to a new object * @param go component to move the component to * @param instance component to move to the GO */ static moveComponent<T extends IComponent>(go: IGameObject | Object3D, instance: T | ConstructorConcrete<T>): T; /** Removes a component from its object * @param instance component to remove */ static removeComponent<T extends IComponent>(instance: T): T; static getOrAddComponent<T extends IComponent>(go: IGameObject | Object3D, typeName: ConstructorConcrete<T>): T; /** Gets a component on the provided object */ static getComponent<T extends IComponent>(go: IGameObject | Object3D | null, typeName: Constructor<T> | null): T | null; static getComponents<T extends IComponent>(go: IGameObject | Object3D | null, typeName: Constructor<T>, arr?: T[] | null): T[]; static findByGuid(guid: string, hierarchy: Object3D): GameObject | Component | null | undefined; static findObjectOfType<T extends IComponent>(typeName: Constructor<T>, context?: Context | Object3D, includeInactive?: boolean): T | null; static findObjectsOfType<T extends IComponent>(typeName: Constructor<T>, context?: Context | Object3D): Array<T>; static getComponentInChildren<T extends IComponent>(go: IGameObject | Object3D, typeName: Constructor<T>): T | null; static getComponentsInChildren<T extends IComponent>(go: IGameObject | Object3D, typeName: Constructor<T>, arr?: T[] | null): Array<T>; static getComponentInParent<T extends IComponent>(go: IGameObject | Object3D, typeName: Constructor<T>): T | null; static getComponentsInParent<T extends IComponent>(go: IGameObject | Object3D, typeName: Constructor<T>, arr?: Array<T> | null): Array<T>; static getAllComponents(go: IGameObject | Object3D): Component[]; static iterateComponents(go: IGameObject | Object3D): Generator<any, void, unknown>; } /** * Needle Engine component base class. Component's are the main building blocks of the Needle Engine. * Derive from {@link Behaviour} to implement your own using the provided lifecycle methods. * Components can be added to any {@link Object3D} using {@link addComponent} or {@link GameObject.addComponent}. * * The most common lifecycle methods are {@link update}, {@link awake}, {@link start}, {@link onEnable}, {@link onDisable} and {@link onDestroy}. * * XR specific callbacks include {@link onEnterXR}, {@link onLeaveXR}, {@link onUpdateXR}, {@link onXRControllerAdded} and {@link onXRControllerRemoved}. * * To receive pointer events implement {@link onPointerDown}, {@link onPointerUp}, {@link onPointerEnter}, {@link onPointerExit} and {@link onPointerMove}. * * @example * ```typescript * import { Behaviour } from "@needle-tools/engine"; * export class MyComponent extends Behaviour { * start() { * console.log("Hello World"); * } * update() { * console.log("Frame", this.context.time.frame); * } * } * ``` * * @group Components */ export declare abstract class Component implements IComponent, EventTarget, Partial<INeedleXRSessionEventReceiver>, Partial<IPointerEventHandler> { /** @internal */ get isComponent(): boolean; private __context; /** Use the context to get access to many Needle Engine features and use physics, timing, access the camera or scene */ get context(): Context; set context(context: Context); /** shorthand for `this.context.scene` * @returns the scene of the context */ get scene(): Scene; /** @returns the layer of the gameObject this component is attached to */ get layer(): number; /** @returns the name of the gameObject this component is attached to */ get name(): string; private __name?; set name(str: string); /** @returns the tag of the gameObject this component is attached to */ get tag(): string; set tag(str: string); /** Is the gameObject marked as static */ get static(): boolean; set static(value: boolean); get hideFlags(): HideFlags; /** @returns true if the object is enabled and active in the hierarchy */ get activeAndEnabled(): boolean; private get __isActive(); private get __isActiveInHierarchy(); private set __isActiveInHierarchy(value); /** the object this component is attached to. Note that this is a threejs Object3D with some additional features */ gameObject: GameObject; /** the unique identifier for this component */ guid: string; /** holds the source identifier this object was created with/from (e.g. if it was part of a glTF file the sourceId holds the url to the glTF) */ sourceId?: SourceIdentifier; /** called on a component with a map of old to new guids (e.g. when instantiate generated new guids and e.g. timeline track bindings needs to remape them) */ resolveGuids?(guidsMap: GuidsMap): void; /** called once when the component becomes active for the first time (once per component) * This is the first callback to be called */ awake(): void; /** called every time when the component gets enabled (this is invoked after awake and before start) * or when it becomes active in the hierarchy (e.g. if a parent object or this.gameObject gets set to visible) */ onEnable(): void; /** called every time the component gets disabled or if a parent object (or this.gameObject) gets set to invisible */ onDisable(): void; /** Called when the component gets destroyed */ onDestroy(): void; /** called when you decorate fields with the @validate() decorator * @param prop the name of the field that was changed */ onValidate?(prop?: string): void; /** Called for all scripts when the context gets paused or unpaused */ onPausedChanged?(isPaused: boolean, wasPaused: boolean): void; /** called at the beginning of a frame (once per component) */ start?(): void; /** first callback in a frame (called every frame when implemented) */ earlyUpdate?(): void; /** regular callback in a frame (called every frame when implemented) */ update?(): void; /** late callback in a frame (called every frame when implemented) */ lateUpdate?(): void; /** called before the scene gets rendered in the main update loop */ onBeforeRender?(frame: XRFrame | null): void; /** called after the scene was rendered */ onAfterRender?(): void; onCollisionEnter?(col: Collision): any; onCollisionExit?(col: Collision): any; onCollisionStay?(col: Collision): any; onTriggerEnter?(col: ICollider): any; onTriggerStay?(col: ICollider): any; onTriggerExit?(col: ICollider): any; /** Optional callback, you can implement this to only get callbacks for VR or AR sessions if necessary. * @returns true if the mode is supported (if false the mode is not supported by this component and it will not receive XR callbacks for this mode) */ supportsXR?(mode: XRSessionMode): boolean; /** Called before the XR session is requested. Use this callback if you want to modify the session init features */ onBeforeXR?(mode: XRSessionMode, args: XRSessionInit): void; /** Callback when this component joins a xr session (or becomes active in a running XR session) */ onEnterXR?(args: NeedleXREventArgs): void; /** Callback when a xr session updates (while it is still active in XR session) */ onUpdateXR?(args: NeedleXREventArgs): void; /** Callback when this component exists a xr session (or when it becomes inactive in a running XR session) */ onLeaveXR?(args: NeedleXREventArgs): void; /** Callback when a controller is connected/added while in a XR session * OR when the component joins a running XR session that has already connected controllers * OR when the component becomes active during a running XR session that has already connected controllers */ onXRControllerAdded?(args: NeedleXRControllerEventArgs): void; /** callback when a controller is removed while in a XR session * OR when the component becomes inactive during a running XR session */ onXRControllerRemoved?(args: NeedleXRControllerEventArgs): void; onPointerEnter?(args: PointerEventData): any; onPointerMove?(args: PointerEventData): any; onPointerExit?(args: PointerEventData): any; onPointerDown?(args: PointerEventData): any; onPointerUp?(args: PointerEventData): any; onPointerClick?(args: PointerEventData): any; /** starts a coroutine (javascript generator function) * `yield` will wait for the next frame: * - Use `yield WaitForSeconds(1)` to wait for 1 second. * - Use `yield WaitForFrames(10)` to wait for 10 frames. * - Use `yield new Promise(...)` to wait for a promise to resolve. * @param routine generator function to start * @param evt event to register the coroutine for (default: FrameEvent.Update). Note that all coroutine FrameEvent callbacks are invoked after the matching regular component callbacks. For example `FrameEvent.Update` will be called after regular component `update()` methods) * @returns the generator function (use it to stop the coroutine with `stopCoroutine`) * @example * ```ts * onEnable() { this.startCoroutine(this.myCoroutine()); } * private *myCoroutine() { * while(this.activeAndEnabled) { * console.log("Hello World", this.context.time.frame); * // wait for 5 frames * for(let i = 0; i < 5; i++) yield; * } * } * ``` */ startCoroutine(routine: Generator, evt?: FrameEvent): Generator; /** * Stop a coroutine that was previously started with `startCoroutine` * @param routine the routine to be stopped * @param evt the frame event to unregister the routine from (default: FrameEvent.Update) */ stopCoroutine(routine: Generator, evt?: FrameEvent): void; /** @returns true if this component was destroyed (`this.destroy()`) or the whole object this component was part of */ get destroyed(): boolean; /** * Destroys this component (and removes it from the object) */ destroy(): void; /** @internal */ protected __didAwake: boolean; /** @internal */ private __didStart; /** @internal */ protected __didEnable: boolean; /** @internal */ protected __isEnabled: boolean | undefined; /** @internal */ private __destroyed; /** @internal */ get __internalDidAwakeAndStart(): boolean; /** @internal */ constructor(init?: ComponentInit<Component>); /** @internal */ __internalNewInstanceCreated(init?: ComponentInit<this>): this; _internalInit(init?: ComponentInit<this>): void; /** @internal */ __internalAwake(): void; /** @internal */ __internalStart(): void; /** @internal */ __internalEnable(isAddingToScene?: boolean): boolean; /** @internal */ __internalDisable(isRemovingFromScene?: boolean): void; /** @internal */ __internalDestroy(): void; get enabled(): boolean; set enabled(val: boolean); get worldPosition(): Vector3; set worldPosition(val: Vector3); setWorldPosition(x: number, y: number, z: number): void; get worldQuaternion(): Quaternion; set worldQuaternion(val: Quaternion); setWorldQuaternion(x: number, y: number, z: number, w: number): void; get worldEuler(): Euler; set worldEuler(val: Euler); get worldRotation(): Vector3; set worldRotation(val: Vector3); setWorldRotation(x: number, y: number, z: number, degrees?: boolean): void; private static _forward; /** Forward (0,0,-1) vector in world space */ get forward(): Vector3; private static _right; /** Right (1,0,0) vector in world space */ get right(): Vector3; private static _up; /** Up (0,1,0) vector in world space */ get up(): Vector3; private _eventListeners; addEventListener<T extends Event>(type: string, listener: (evt: T) => any): void; removeEventListener<T extends Event>(type: string, listener: (arg: T) => any): void; dispatchEvent(evt: Event): boolean; } export { Component as Behaviour };