@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
TypeScript
/// <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 };