Using needleEngine 4.3.2-beta.4, unity 2022.3.43f1 and Node 18.20.3. iâm having an issue with GameObject.findObjectOfType, using it with an NPN def class like this:
_camController = GameObject.findObjectOfType(CameraController);
Iâm getting these 2 errors:
Type âIComponent | nullâ is not assignable to type âCameraController | nullâ.
Type âIComponentâ is missing the following properties from type âCameraControllerâ: viewPositions, _onEnterView, selectView, tweenToGameObject, and 24 more.
Argument of type âtypeof CameraControllerâ is not assignable to parameter of type âConstructorâ.
Types of construct signatures are incompatible.
Type ânew (init?: Partial<NoInternalNeedleEngineState<FilterStartingWith<FilterTypes<Component, Function | null | undefined>, â">>> | undefined) => CameraControllerâ is not assignable to type âabstract new (âŠargs: any[]) => IComponentâ.
Construct signature return types âCameraControllerâ and âIComponentâ are incompatible.
The types of âgameObject.addNewComponentâ are incompatible between these types.
Type '(type: ConstructorConcrete, init?: Partial<NoInternalNeedleEngineState<FilterStartingWith<FilterTypes<T, Function | null | undefined>, "â>>> | undefined) => Tâ is not assignable to type â(type: Constructor, init?: Partial<NoInternalNeedleEngineState<FilterStartingWith<FilterTypes<T, Function | null | undefined>, â_â>>> | undefined) => Tâ.
Types of parameters âtypeâ and âtypeâ are incompatible.
Type âConstructorâ is not assignable to type âConstructorConcreteâ.
Cannot assign an abstract constructor type to a non-abstract constructor type.
It works without forcing the implementation but i gotta use @ts-ignore
The issue youâre facing seems to be related to TypeScriptâs type system and how it interprets the types involved in your usage of GameObject.findObjectOfType.
Plan
Ensure youâre using the correct import statement for findObjectOfType.
Create a custom type guard to safely assert that the found object is indeed a CameraController.
Use this type guard to avoid requiring @ts-ignore.
Code
Hereâs how you can implement it:
import { GameObject, IComponent } from "@needle-tools/engine";
import { CameraController } from "./path/to/CameraController"; // Adjust the import path accordingly
// Type guard to check if the object is a CameraController
function isCameraController(object: IComponent | null): object is CameraController {
return object !== null && (object as CameraController).viewPositions !== undefined; // Check for a specific property from CameraController
}
// Usage
const foundObject = GameObject.findObjectOfType(CameraController);
if (isCameraController(foundObject)) {
_camController = foundObject; // Now TypeScript knows this is a CameraController
} else {
_camController = null; // Handle the null case appropriately
}
Explanation
Type Guard: The isCameraController function checks if the object is not null and has a property specific to CameraController. This allows TypeScript to infer the correct type when you set _camController.
Error Handling: By checking the type before assignment, you can avoid the need for @ts-ignore.
With this approach, you maintain type safety without suppressing the TypeScript errors. If you have further questions or need additional help, feel free to ask!
1 replies left - Get a PRO license for more AI replies. thread_0PSVH3OMd55mukDjPcK1gPzE Reply to this message to continue the conversation
can you share a bit of the code that youâre using and which CameraController youâre using? It sounds like this type is not a Needle Engine component and can thus not be search for using this function. Make sure you pass in a component type (deriving from Component or Behaviour in Needle Engine).
As you can see next the camera controller is getting extended as behaviour, it takes the camera where the gameObject is, we control its position in unity by putting empty objects with the world transform needed to point the camera to another object in the scene. This script was made from scratch and we began to use it as a dependency importing it from the folder âcamera-Systemsâ, we used it like this for another project a month ago and it worked just fine, but it wasnât in the version mentioned before.
Hereâs the code:
import { Tween, Easing } from "@tweenjs/tween.js";
import { Quaternion, Vector3 } from "three";
/*
# CHANGE LOG:
# unreleased
- converts positions and rotation from local to world space before tweening.
# v2.0.0
- function tweenToGameObject uses a single tween to move the camera to a target position and rotation.
# v1.0.0
- function tweenToGameObject uses 2 tweens to move the camera to a target position and rotation.
*/
export class CameraController extends Behaviour {
//Lista de posiciones.
@serializable(GameObject)
viewPositions: GameObject[] = [];
private _onEnterView: Function[] = [];
private _combinedTween?: Tween<{position: Vector3, rotation: Quaternion}> = undefined;
start(): void {
// console.log(`Posiciones de la camara: ${this.viewPositions.length}`);
//Fijamos la posicion y rotacion inicial de la camara.
if (this.viewPositions.length > 0) {
//Convertimos la posicion y rotacion en valores globales.
const position = new Vector3();
const rotation = new Quaternion();
const viewTransform = this.viewPositions[0];
viewTransform.getWorldPosition(position);
viewTransform.getWorldQuaternion(rotation);
this.gameObject.position.set(position.x, position.y, position.z);
this.gameObject.quaternion.set(rotation.x, rotation.y, rotation.z, rotation.w);
}
//Evaluar si esto merece estar en esta parte.
this._onEnterView = [
() => {},
() => {
// console.log("Vista 1");
},
() => {
// console.log("Vista 2"); //Esta es la del video.
//Buscar el componente del video y darle play manualmente (para evitar lo del renderizado).
},
];
}
update(): void {
if(this._combinedTween?.isPlaying())
this._combinedTween?.update();
}
/**
* Sets a tween that moves the camera to a predefined view position.
* @param id The id of the view to select.
* @returns nothing.
*/
selectView(id: number) : void {
// console.log("Seleccionando vista: " + id);
if (this.viewPositions.length == 0) {
console.info(`El id (${id}) de la vista no existe. No hay posiciones de camara definidas.`);
return;
}
if (id < 0 || id >= this.viewPositions.length) {
console.error(`El id (${id}) de la vista esta fuera de rango.`);
return;
}
//Cada view tiene asociado una posicion.
if (this.viewPositions.length > 0) {
this.tweenToGameObject(this.viewPositions[id]);
}
//Llamamos a la funcion asociada a la vista.
const ev = this._onEnterView[id];
if(ev) ev();
}
tweenToGameObject(target: GameObject) {
//Convertimos la posicion y rotacion en world space.
const targetTransform = target;
const targetWorldPosition = new Vector3();
const targetWorldRotation = new Quaternion();
targetTransform.getWorldPosition(targetWorldPosition);
targetTransform.getWorldQuaternion(targetWorldRotation);
this._combinedTween = new Tween({position: this.gameObject.position, rotation: this.gameObject.quaternion})
.to({ position: targetWorldPosition, rotation: targetWorldRotation }, 1000)
.easing(Easing.Cubic.InOut)
.onUpdate(() => {
this.gameObject.position.set(this.gameObject.position.x, this.gameObject.position.y, this.gameObject.position.z);
this.gameObject.quaternion.set(this.gameObject.quaternion.x, this.gameObject.quaternion.y, this.gameObject.quaternion.z, this.gameObject.quaternion.w);
})
.start();
// Could be: Activar y reactivar un componente look at, al comienzo y al final de la animacion.
}
/* onLeaveXR(){
this.selectView(0);
}*/
} ```
Thank you for providing more context about your CameraController. Given that you are extending Behaviour from Needle Engine and using the viewPositions array, I can see how the issue might relate to the interaction between TypeScriptâs type definitions and your class structure.
Troubleshooting the Type Issue
Check Type Inheritance: Ensure that CameraController properly extends Behaviour. Check that your imports are correctly pointing to the expected versions of the classes.
Ensure âIComponentâ Compliance: Confirm that your CameraController class implements all necessary properties/functions that IComponent expects. If it is missing any, TypeScript will raise errors.
Version Compatibility: Since you mentioned this worked in a previous project with a different version of Needle Engine, there might be breaking changes in the beta version youâre using. Reviewing the changelog for the version (4.3.2-beta.4) could provide insight into any updates that may affect your implementation.
Suggestions
You can also refine your type check using TypeScript features to narrow down the errors:
function isCameraController(object: IComponent | null): object is CameraController {
return object !== null && object instanceof CameraController;
}
Usage Example
Hereâs how you can use this modified type guard with your existing code:
const foundObject = GameObject.findObjectOfType(CameraController);
if (isCameraController(foundObject)) {
_camController = foundObject;
} else {
console.error('CameraController not found or is of incorrect type');
_camController = null;
}
Conclusion
If these suggestions donât solve the problem, double-check any updates or migrations to Needle Engine that could affect the type definitions or other breaking changes. If you continue to face issues, feel free to share the complete error messages or any additional details that might help.
If you need further assistance or have specific questions about parts of your code, let me know!
1 replies left - Get a PRO license for more AI replies. thread_0PSVH3OMd55mukDjPcK1gPzE Reply to this message to continue the conversation
Hi, it looks like youâre missing imports from Needle Engine
import { Behaviour, serializable, GameObject } from "@needle-tools/engine"
Which (code) editor are you using? You should normally get lots of typescript errors in vscode for things like these. Make sure to donât have any errors in your code