133 lines
3.5 KiB
TypeScript
133 lines
3.5 KiB
TypeScript
import { ObjectProperty } from 'src/types/property.decorator';
|
|
import { SerializedObject } from 'src/types/serialized';
|
|
import { readMetadataOf } from 'src/utils/read-metadata';
|
|
import { Color, Euler, Object3D, Vector3 } from 'three';
|
|
|
|
export class GameObject extends Object3D {
|
|
public objectType = 'GameObject';
|
|
public virtual = false;
|
|
|
|
@ObjectProperty()
|
|
public override uuid!: string;
|
|
|
|
@ObjectProperty()
|
|
public override name = '';
|
|
|
|
@ObjectProperty()
|
|
public override visible = true;
|
|
|
|
@ObjectProperty()
|
|
public archivable = true;
|
|
|
|
constructor() {
|
|
super();
|
|
this.name = this.objectType;
|
|
}
|
|
|
|
private get excludedProperties() {
|
|
return readMetadataOf<string>(this, 'excludedProperties');
|
|
}
|
|
|
|
/**
|
|
* The exposed properties for this game object, used for the editor
|
|
*/
|
|
get properties() {
|
|
const exclude = this.excludedProperties;
|
|
const properties = readMetadataOf<string>(this, 'properties');
|
|
return properties.filter((item) => !exclude.includes(item));
|
|
}
|
|
|
|
/**
|
|
* Serialize GameObject for exporting
|
|
*/
|
|
serialize(skipChildren = false) {
|
|
const object: SerializedObject = {
|
|
name: this.name,
|
|
objectType: this.objectType,
|
|
children: !skipChildren
|
|
? this.children
|
|
.filter(
|
|
(entry) =>
|
|
entry instanceof GameObject && entry.archivable !== false,
|
|
)
|
|
.map((entry) => (entry as GameObject).serialize())
|
|
: undefined,
|
|
visible: this.visible,
|
|
};
|
|
|
|
const keys = this.properties.map((property) => property);
|
|
|
|
Object.assign(
|
|
object,
|
|
keys.reduce<{ [x: string]: unknown }>((obj, key) => {
|
|
const indexable = this as Record<string, unknown>;
|
|
const value = (indexable[key] as any)?.toArray
|
|
? (indexable[key] as any).toArray()
|
|
: indexable[key];
|
|
|
|
return {
|
|
...obj,
|
|
[key]: value,
|
|
};
|
|
}, {}),
|
|
);
|
|
|
|
return object;
|
|
}
|
|
|
|
override copy(object: Object3D, recursive = true) {
|
|
super.copy(object as any, recursive);
|
|
this.properties
|
|
.map((property) => property)
|
|
.filter((key) => !['position', 'rotation', 'scale', 'uuid'].includes(key))
|
|
.forEach((key) => this.setOwnProperty(key, (object as any)[key]));
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* This function can be used to modify any property of the object by key.
|
|
* @param key Key to set
|
|
* @param value Value to set
|
|
*/
|
|
public setOwnProperty(key: keyof GameObject, value: unknown): void;
|
|
public setOwnProperty(key: string, value: unknown): void;
|
|
public setOwnProperty(key: string, value: unknown) {
|
|
const indexable = this as any;
|
|
if (indexable[key]?.fromArray && Array.isArray(value)) {
|
|
indexable[key].fromArray(value);
|
|
} else if (indexable[key]?.isColor) {
|
|
indexable[key] = new Color(value as string);
|
|
} else if (indexable[key]?.copy) {
|
|
indexable[key].copy(value);
|
|
} else {
|
|
indexable[key] = value;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Deserialize a serialized object into properties on this object.
|
|
* @param input Serialized information
|
|
*/
|
|
deserialize(input: SerializedObject) {
|
|
Object.keys(input)
|
|
.filter((key) => !['children', 'objectType'].includes(key))
|
|
.forEach((key) => this.setOwnProperty(key, input[key]));
|
|
}
|
|
}
|
|
|
|
export class GameObject3D extends GameObject {
|
|
public objectType = 'GameObject3D';
|
|
|
|
@ObjectProperty()
|
|
public locked = false;
|
|
|
|
@ObjectProperty()
|
|
public override position!: Vector3;
|
|
|
|
@ObjectProperty()
|
|
public override scale!: Vector3;
|
|
|
|
@ObjectProperty()
|
|
public override rotation!: Euler;
|
|
}
|