idk
This commit is contained in:
parent
4fde9cf8f0
commit
3fcd1b0385
|
@ -1,35 +1,39 @@
|
|||
import { EventEmitter, GameRunner, Renderer } from '@freeblox/engine';
|
||||
import { EditorViewport } from './viewport';
|
||||
import {
|
||||
EnvironmentComponent,
|
||||
MouseComponent,
|
||||
ViewportComponent,
|
||||
EventEmitter,
|
||||
GameRunner,
|
||||
Renderer,
|
||||
} from '@freeblox/engine';
|
||||
import { EditorEvents } from '../types/events';
|
||||
import { EditorWorkspace } from './workspace';
|
||||
import { EditorMouse } from './mouse';
|
||||
import { EditorEnvironment } from './environment';
|
||||
import { WorkspaceComponent } from './workspace';
|
||||
|
||||
export class Editor extends GameRunner {
|
||||
public lastTick = performance.now();
|
||||
public events = new EventEmitter<EditorEvents>();
|
||||
public render!: Renderer;
|
||||
public element!: HTMLElement;
|
||||
public viewport!: EditorViewport;
|
||||
public workspace!: EditorWorkspace;
|
||||
public mouse!: EditorMouse;
|
||||
public environment!: EditorEnvironment;
|
||||
public viewport!: ViewportComponent;
|
||||
public workspace!: WorkspaceComponent;
|
||||
public mouse!: MouseComponent;
|
||||
public environment!: EnvironmentComponent;
|
||||
public running = false;
|
||||
|
||||
override mount(element: HTMLElement) {
|
||||
this.element = element;
|
||||
this.render = new Renderer(element);
|
||||
|
||||
this.viewport = new EditorViewport(this.render, this.events);
|
||||
this.viewport = new ViewportComponent(this.render, this.events);
|
||||
this.viewport.initialize();
|
||||
|
||||
this.workspace = new EditorWorkspace(this.render, this.events);
|
||||
this.workspace = new WorkspaceComponent(this.render, this.events);
|
||||
this.workspace.initialize();
|
||||
|
||||
this.mouse = new EditorMouse(this.render, this.events);
|
||||
this.mouse = new MouseComponent(this.render, this.events);
|
||||
this.mouse.initialize();
|
||||
|
||||
this.environment = new EditorEnvironment(this.render, this.events);
|
||||
this.environment = new EnvironmentComponent(this.render, this.events);
|
||||
this.environment.initialize();
|
||||
|
||||
this.start();
|
||||
|
|
|
@ -1,28 +0,0 @@
|
|||
import { EngineComponent, EventEmitter, Renderer } from '@freeblox/engine';
|
||||
import { EditorEvents } from '../types/events';
|
||||
import { AmbientLight, DirectionalLight } from 'three';
|
||||
|
||||
export class EditorEnvironment extends EngineComponent {
|
||||
public ambient!: AmbientLight;
|
||||
public directional!: DirectionalLight;
|
||||
|
||||
constructor(
|
||||
protected renderer: Renderer,
|
||||
protected events: EventEmitter<EditorEvents>
|
||||
) {
|
||||
super(renderer, events);
|
||||
}
|
||||
|
||||
initialize(): void {
|
||||
this.ambient = new AmbientLight(0x8a8a8a, 1.0);
|
||||
this.directional = new DirectionalLight(0xffffff, 1);
|
||||
this.directional.position.set(1, 1, 1);
|
||||
|
||||
this.renderer.scene.add(this.ambient);
|
||||
this.renderer.scene.add(this.directional);
|
||||
}
|
||||
|
||||
update(delta: number): void {}
|
||||
|
||||
cleanUp(): void {}
|
||||
}
|
|
@ -1,28 +1,27 @@
|
|||
import { EngineComponent, EventEmitter, Renderer } from '@freeblox/engine';
|
||||
import {
|
||||
Brick,
|
||||
Cylinder,
|
||||
EngineComponent,
|
||||
EventEmitter,
|
||||
GameObject,
|
||||
MouseButtonEvent,
|
||||
Renderer,
|
||||
Sphere,
|
||||
} from '@freeblox/engine';
|
||||
import {
|
||||
AxesHelper,
|
||||
BoxGeometry,
|
||||
BoxHelper,
|
||||
Color,
|
||||
Euler,
|
||||
GridHelper,
|
||||
Material,
|
||||
Mesh,
|
||||
MeshPhongMaterial,
|
||||
Object3D,
|
||||
Vector3,
|
||||
} from 'three';
|
||||
import {
|
||||
EditorEvents,
|
||||
MouseButtonEvent,
|
||||
MouseMoveEvent,
|
||||
SelectEvent,
|
||||
TransformModeEvent,
|
||||
} from '../types/events';
|
||||
import { EditorEvents, SelectEvent, TransformModeEvent } from '../types/events';
|
||||
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js';
|
||||
import { TransformControls } from 'three/examples/jsm/controls/TransformControls.js';
|
||||
|
||||
export class EditorWorkspace extends EngineComponent {
|
||||
export class WorkspaceComponent extends EngineComponent {
|
||||
public background = new Object3D();
|
||||
public world = new Object3D();
|
||||
public helpers = new Object3D();
|
||||
|
@ -70,9 +69,13 @@ export class EditorWorkspace extends EngineComponent {
|
|||
this.helpers.name = '_helper';
|
||||
scene.add(this.background, this.world, this.helpers);
|
||||
|
||||
const test = new Mesh(new BoxGeometry(), new MeshPhongMaterial());
|
||||
const test = new Brick();
|
||||
test.position.set(2, 2, 2);
|
||||
this.world.add(test);
|
||||
const test2 = new Cylinder();
|
||||
test2.position.set(0, 2, 2);
|
||||
const test3 = new Sphere();
|
||||
test3.position.set(0, 2, 0);
|
||||
this.world.add(test, test2, test3);
|
||||
}
|
||||
|
||||
private removeFromScene(scene: Object3D) {
|
||||
|
@ -81,16 +84,26 @@ export class EditorWorkspace extends EngineComponent {
|
|||
|
||||
private initializeSelector() {
|
||||
let moved = false;
|
||||
let clicked = false;
|
||||
let casterDebounce: ReturnType<typeof setTimeout> | undefined;
|
||||
|
||||
const mouseDownEventHandler = () => {
|
||||
moved = false;
|
||||
clicked = true;
|
||||
};
|
||||
|
||||
const mouseMoveEventHandler = () => {
|
||||
moved = true;
|
||||
if (casterDebounce || !clicked) return;
|
||||
// Prevent miniscule mouse movement when clicking from preventing a selection
|
||||
casterDebounce = setTimeout(() => {
|
||||
moved = true;
|
||||
}, 100);
|
||||
};
|
||||
|
||||
const mouseUpEventHandler = (event: MouseButtonEvent) => {
|
||||
clearTimeout(casterDebounce);
|
||||
casterDebounce = undefined;
|
||||
clicked = false;
|
||||
if (moved) return;
|
||||
if (!event.target?.object) {
|
||||
if (!this.selection.length) return;
|
||||
|
@ -106,7 +119,13 @@ export class EditorWorkspace extends EngineComponent {
|
|||
return;
|
||||
}
|
||||
|
||||
const object = event.target!.object;
|
||||
let object = event.target!.object;
|
||||
if (
|
||||
!(object instanceof GameObject) &&
|
||||
object.parent instanceof GameObject
|
||||
) {
|
||||
object = object.parent;
|
||||
}
|
||||
if (this.selection.includes(object)) {
|
||||
if (event.control) {
|
||||
const index = this.selection.indexOf(object);
|
||||
|
|
|
@ -1,25 +1,5 @@
|
|||
import { EngineEvents } from '@freeblox/engine';
|
||||
import { Euler, Intersection, Object3D, Vector2, Vector3 } from 'three';
|
||||
|
||||
export interface MousePositionEvent {
|
||||
position: Vector2;
|
||||
positionGL: Vector2;
|
||||
}
|
||||
|
||||
export interface MouseMoveEvent extends MousePositionEvent {
|
||||
offset: Vector2;
|
||||
offsetGL: Vector2;
|
||||
helper?: boolean;
|
||||
}
|
||||
|
||||
export interface MouseButtonEvent extends MousePositionEvent {
|
||||
button: number;
|
||||
helper?: boolean;
|
||||
target?: Intersection<Object3D>;
|
||||
shift?: boolean;
|
||||
control?: boolean;
|
||||
alt?: boolean;
|
||||
}
|
||||
import { Euler, Object3D, Vector3 } from 'three';
|
||||
|
||||
export interface TransformEvent {
|
||||
object: Object3D;
|
||||
|
@ -52,10 +32,6 @@ export interface SelectEvent {
|
|||
}
|
||||
|
||||
export type Events = {
|
||||
error: (error: Error) => void;
|
||||
mouseDown: (event: MouseButtonEvent) => void;
|
||||
mouseUp: (event: MouseButtonEvent) => void;
|
||||
mouseMove: (event: MouseMoveEvent) => void;
|
||||
transformStart: (event: TransformEvent) => void;
|
||||
transformChange: (event: TransformCompleteEvent) => void;
|
||||
transformEnd: (event: TransformEvent) => void;
|
||||
|
|
|
@ -0,0 +1,58 @@
|
|||
import { AmbientLight, Color, DirectionalLight } from 'three';
|
||||
import { EngineEvents, EnvironmentEvent } from '../types/events';
|
||||
import { EngineComponent } from '../types/engine-component';
|
||||
import { Renderer } from '../core/renderer';
|
||||
import { EventEmitter } from '../utils/events';
|
||||
|
||||
export class EnvironmentComponent extends EngineComponent {
|
||||
public ambient!: AmbientLight;
|
||||
public directional!: DirectionalLight;
|
||||
private handlerCleanUp?: Function;
|
||||
|
||||
constructor(
|
||||
protected renderer: Renderer,
|
||||
protected events: EventEmitter<EngineEvents>
|
||||
) {
|
||||
super(renderer, events);
|
||||
}
|
||||
|
||||
initialize(): void {
|
||||
this.renderer.renderer.setClearColor(0x00aaff);
|
||||
|
||||
this.ambient = new AmbientLight(0x8a8a8a, 1.0);
|
||||
this.directional = new DirectionalLight(0xffffff, 1);
|
||||
this.directional.position.set(1, 1, 1);
|
||||
|
||||
this.renderer.scene.add(this.ambient);
|
||||
this.renderer.scene.add(this.directional);
|
||||
}
|
||||
|
||||
update(delta: number): void {
|
||||
this.handlerCleanUp = this.initializeEvents();
|
||||
}
|
||||
|
||||
cleanUp(): void {
|
||||
this.renderer.scene.remove(this.ambient);
|
||||
this.renderer.scene.remove(this.directional);
|
||||
this.handlerCleanUp?.call(this);
|
||||
}
|
||||
|
||||
private initializeEvents() {
|
||||
const setEnvironmentEvent = (event: EnvironmentEvent) => {
|
||||
if (event.sunColor) this.directional.color = new Color(event.sunColor);
|
||||
if (event.sunPosition) this.directional.position.copy(event.sunPosition);
|
||||
if (event.sunStrength) this.directional.intensity = event.sunStrength;
|
||||
if (event.ambientColor)
|
||||
this.ambient.color = new Color(event.ambientColor);
|
||||
if (event.ambientStrength) this.ambient.intensity = event.ambientStrength;
|
||||
if (event.clearColor)
|
||||
this.renderer.renderer.setClearColor(event.clearColor);
|
||||
};
|
||||
|
||||
this.events.addListener('setEnvironment', setEnvironmentEvent);
|
||||
|
||||
return () => {
|
||||
this.events.removeEventListener('setEnvironment', setEnvironmentEvent);
|
||||
};
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
export * from './environment';
|
||||
export * from './viewport';
|
||||
export * from './mouse';
|
|
@ -1,12 +1,13 @@
|
|||
import { EngineComponent, EventEmitter, Renderer } from '@freeblox/engine';
|
||||
import { EditorEvents, SelectEvent } from '../types/events';
|
||||
import { Object3D, Raycaster, Vector2 } from 'three';
|
||||
import { EngineComponent } from '../types/engine-component';
|
||||
import { Renderer } from '../core/renderer';
|
||||
import { EngineEvents } from '../types/events';
|
||||
import { EventEmitter } from '../utils/events';
|
||||
|
||||
type MouseMap = [boolean, boolean, boolean];
|
||||
type EventMap = [string, Function];
|
||||
|
||||
export class EditorMouse extends EngineComponent {
|
||||
private helpers!: Object3D;
|
||||
export class MouseComponent extends EngineComponent {
|
||||
private world!: Object3D;
|
||||
|
||||
private mouseButtons: MouseMap = [false, false, false];
|
||||
|
@ -22,7 +23,7 @@ export class EditorMouse extends EngineComponent {
|
|||
|
||||
constructor(
|
||||
protected renderer: Renderer,
|
||||
protected events: EventEmitter<EditorEvents>
|
||||
protected events: EventEmitter<EngineEvents>
|
||||
) {
|
||||
super(renderer, events);
|
||||
}
|
||||
|
@ -32,7 +33,6 @@ export class EditorMouse extends EngineComponent {
|
|||
}
|
||||
|
||||
initialize(): void {
|
||||
this.helpers = this.renderer.scene.getObjectByName('_helpers')!;
|
||||
this.world = this.renderer.scene.getObjectByName('_world')!;
|
||||
|
||||
const mouseDown = (ev: MouseEvent) => {
|
||||
|
@ -57,6 +57,9 @@ export class EditorMouse extends EngineComponent {
|
|||
positionGL: this.mousePositionGL,
|
||||
button: ev.button,
|
||||
target: object,
|
||||
shift: ev.shiftKey,
|
||||
control: ev.ctrlKey,
|
||||
alt: ev.altKey,
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -103,11 +106,4 @@ export class EditorMouse extends EngineComponent {
|
|||
this.canvas.removeEventListener(event, handler as EventListener);
|
||||
}
|
||||
}
|
||||
|
||||
// private realMousePos(vec: Vector2, x: number, y: number) {
|
||||
// const rect = this.renderer.renderer.domElement.getBoundingClientRect();
|
||||
// const scaleX = this.renderer.renderer.domElement.width / rect.width;
|
||||
// const scaleY = this.renderer.renderer.domElement.height / rect.height;
|
||||
// vec.set((x - rect.left) * scaleX, (y - rect.top) * scaleY);
|
||||
// }
|
||||
}
|
|
@ -1,11 +1,13 @@
|
|||
import { EngineComponent, EventEmitter, Renderer } from '@freeblox/engine';
|
||||
import { Object3D } from 'three';
|
||||
import { EditorEvents } from '../types/events';
|
||||
import { EngineEvents } from '../types/events';
|
||||
import { EngineComponent } from '../types/engine-component';
|
||||
import { Renderer } from '../core/renderer';
|
||||
import { EventEmitter } from '../utils/events';
|
||||
|
||||
export class EditorViewport extends EngineComponent {
|
||||
export class ViewportComponent extends EngineComponent {
|
||||
constructor(
|
||||
protected render: Renderer,
|
||||
protected events: EventEmitter<EditorEvents>
|
||||
protected events: EventEmitter<EngineEvents>
|
||||
) {
|
||||
super(render, events);
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
import {
|
||||
BufferGeometry,
|
||||
Color,
|
||||
ColorRepresentation,
|
||||
Material,
|
||||
Mesh,
|
||||
MeshPhongMaterial,
|
||||
} from 'three';
|
||||
import { GameObject3D } from '../types/game-object';
|
||||
import { Property } from '../types/property';
|
||||
import { gameObjectFactory } from './factory';
|
||||
|
||||
export class Brick extends GameObject3D {
|
||||
public objectType = Brick.name;
|
||||
protected material = new MeshPhongMaterial();
|
||||
protected mesh: Mesh = new Mesh(this.geometry, this.material);
|
||||
|
||||
constructor(
|
||||
protected geometry: BufferGeometry = gameObjectFactory.boxGeometry
|
||||
) {
|
||||
super();
|
||||
this.editorProperties.color = new Property('color', Color, true, []);
|
||||
this.editorProperties.transparency = new Property(
|
||||
'transparency',
|
||||
Number,
|
||||
true,
|
||||
[]
|
||||
);
|
||||
this.add(this.mesh);
|
||||
}
|
||||
|
||||
get color() {
|
||||
return this.material.color;
|
||||
}
|
||||
set color(color: ColorRepresentation) {
|
||||
this.material.color = new Color(color);
|
||||
}
|
||||
|
||||
get transparency() {
|
||||
return 1 - this.material.opacity;
|
||||
}
|
||||
set transparency(value: number) {
|
||||
this.material.transparent = value != 0;
|
||||
this.material.opacity = 1 - value;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
import { Mesh, Color } from 'three';
|
||||
import { Property } from '../types/property';
|
||||
import { Brick } from './brick.object';
|
||||
import { gameObjectFactory } from './factory';
|
||||
|
||||
export class Cylinder extends Brick {
|
||||
public objectType = Cylinder.name;
|
||||
protected mesh = new Mesh(this.geometry, this.material);
|
||||
|
||||
constructor() {
|
||||
super(gameObjectFactory.cylinderGeometry);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
import { BoxGeometry, CylinderGeometry, SphereGeometry } from 'three';
|
||||
|
||||
class GameObjectFactory {
|
||||
public boxGeometry = new BoxGeometry();
|
||||
public sphereGeometry = new SphereGeometry(0.5);
|
||||
public cylinderGeometry = new CylinderGeometry(0.5, 0.5);
|
||||
}
|
||||
|
||||
export const gameObjectFactory = new GameObjectFactory();
|
||||
Object.freeze(gameObjectFactory);
|
|
@ -0,0 +1,3 @@
|
|||
export * from './brick.object';
|
||||
export * from './cylinder.object';
|
||||
export * from './sphere.object';
|
|
@ -0,0 +1,13 @@
|
|||
import { Mesh, Color } from 'three';
|
||||
import { Property } from '../types/property';
|
||||
import { Brick } from './brick.object';
|
||||
import { gameObjectFactory } from './factory';
|
||||
|
||||
export class Sphere extends Brick {
|
||||
public objectType = Sphere.name;
|
||||
protected mesh = new Mesh(this.geometry, this.material);
|
||||
|
||||
constructor() {
|
||||
super(gameObjectFactory.sphereGeometry);
|
||||
}
|
||||
}
|
|
@ -1,3 +1,5 @@
|
|||
export * from './core';
|
||||
export * from './utils';
|
||||
export * from './types';
|
||||
export * from './components';
|
||||
export * from './gameobjects';
|
||||
|
|
|
@ -1,3 +1,44 @@
|
|||
import {
|
||||
Vector2,
|
||||
Intersection,
|
||||
Object3D,
|
||||
ColorRepresentation,
|
||||
Vector3,
|
||||
} from 'three';
|
||||
|
||||
export interface MousePositionEvent {
|
||||
position: Vector2;
|
||||
positionGL: Vector2;
|
||||
}
|
||||
|
||||
export interface MouseMoveEvent extends MousePositionEvent {
|
||||
offset: Vector2;
|
||||
offsetGL: Vector2;
|
||||
helper?: boolean;
|
||||
}
|
||||
|
||||
export interface MouseButtonEvent extends MousePositionEvent {
|
||||
button: number;
|
||||
helper?: boolean;
|
||||
target?: Intersection<Object3D>;
|
||||
shift?: boolean;
|
||||
control?: boolean;
|
||||
alt?: boolean;
|
||||
}
|
||||
|
||||
export interface EnvironmentEvent {
|
||||
sunColor?: ColorRepresentation;
|
||||
sunPosition?: Vector3;
|
||||
sunStrength?: number;
|
||||
ambientColor?: ColorRepresentation;
|
||||
ambientStrength?: number;
|
||||
clearColor?: ColorRepresentation;
|
||||
}
|
||||
|
||||
export type EngineEvents = {
|
||||
error: (error: Error) => void;
|
||||
mouseDown: (event: MouseButtonEvent) => void;
|
||||
mouseUp: (event: MouseButtonEvent) => void;
|
||||
mouseMove: (event: MouseMoveEvent) => void;
|
||||
setEnvironment: (event: EnvironmentEvent) => void;
|
||||
};
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
import { Euler, Object3D, Vector3 } from 'three';
|
||||
import { Property } from './property';
|
||||
|
||||
export class GameObject extends Object3D {
|
||||
public objectType = 'GameObject';
|
||||
public editorProperties: { [x: string]: Property } = {
|
||||
name: new Property('name', String, true, []),
|
||||
};
|
||||
}
|
||||
|
||||
export class GameObject3D extends GameObject {
|
||||
public objectType = 'GameObject3D';
|
||||
public editorProperties: { [x: string]: Property } = {
|
||||
name: new Property('name', String, true, []),
|
||||
position: new Property('position', Vector3, true, []),
|
||||
scale: new Property('scale', Vector3, true, []),
|
||||
rotation: new Property('rotation', Euler, true, []),
|
||||
};
|
||||
}
|
|
@ -1,3 +1,4 @@
|
|||
export * from './game-runner';
|
||||
export * from './events';
|
||||
export * from './engine-component';
|
||||
export * from './game-object';
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
export class Property {
|
||||
constructor(
|
||||
public name: string,
|
||||
public type: any,
|
||||
public exposed = true,
|
||||
public validators: Function[] = []
|
||||
) {}
|
||||
}
|
Loading…
Reference in New Issue