From ea2896bb7435131538fdc58a2735b1579baa3f91 Mon Sep 17 00:00:00 2001 From: Daan Vanden Bosch Date: Wed, 29 May 2019 14:46:29 +0200 Subject: [PATCH] All code now conforms to typical TypeScript conventions. --- src/actions.ts | 32 +-- src/rendering/Renderer.ts | 430 ++++++++++++++++---------------- src/ui/ApplicationComponent.tsx | 8 +- src/ui/Area3DComponent.tsx | 36 +-- src/ui/EntityInfoComponent.tsx | 90 +++---- src/ui/QuestInfoComponent.tsx | 48 ++-- 6 files changed, 323 insertions(+), 321 deletions(-) diff --git a/src/actions.ts b/src/actions.ts index f1a6d1cb..18f4cf47 100644 --- a/src/actions.ts +++ b/src/actions.ts @@ -8,11 +8,11 @@ import { createObjectMesh, createNpcMesh } from './rendering/entities'; import { createModelMesh } from './rendering/models'; import { VisibleQuestEntity } from './domain'; -export function entity_selected(entity?: VisibleQuestEntity) { +export function entitySelected(entity?: VisibleQuestEntity) { applicationState.selectedEntity = entity; } -export function load_file(file: File) { +export function loadFile(file: File) { const reader = new FileReader(); reader.addEventListener('loadend', async () => { @@ -24,12 +24,12 @@ export function load_file(file: File) { if (file.name.endsWith('.nj')) { // Reset application state, then set the current model. // Might want to do this in a MobX transaction. - reset_model_and_quest_state(); + resetModelAndQuestState(); applicationState.currentModel = createModelMesh(parseNj(new ArrayBufferCursor(reader.result, true))); } else if (file.name.endsWith('.xj')) { // Reset application state, then set the current model. // Might want to do this in a MobX transaction. - reset_model_and_quest_state(); + resetModelAndQuestState(); applicationState.currentModel = createModelMesh(parseXj(new ArrayBufferCursor(reader.result, true))); } else { const quest = parseQuest(new ArrayBufferCursor(reader.result, true)); @@ -37,7 +37,7 @@ export function load_file(file: File) { if (quest) { // Reset application state, then set current quest and area in the correct order. // Might want to do this in a MobX transaction. - reset_model_and_quest_state(); + resetModelAndQuestState(); applicationState.currentQuest = quest; if (quest.areaVariants.length) { @@ -76,29 +76,29 @@ export function load_file(file: File) { reader.readAsArrayBuffer(file); } -export function current_area_id_changed(area_id?: number) { +export function currentAreaIdChanged(areaId?: number) { applicationState.selectedEntity = undefined; - if (area_id == null) { + if (areaId == null) { applicationState.currentArea = undefined; } else if (applicationState.currentQuest) { - const area_variant = applicationState.currentQuest.areaVariants.find( - variant => variant.area.id === area_id); - applicationState.currentArea = area_variant && area_variant.area; + const areaVariant = applicationState.currentQuest.areaVariants.find( + variant => variant.area.id === areaId); + applicationState.currentArea = areaVariant && areaVariant.area; } } -export function save_current_quest_to_file(file_name: string) { +export function saveCurrentQuestToFile(fileName: string) { if (applicationState.currentQuest) { - const cursor = writeQuestQst(applicationState.currentQuest, file_name); + const cursor = writeQuestQst(applicationState.currentQuest, fileName); - if (!file_name.endsWith('.qst')) { - file_name += '.qst'; + if (!fileName.endsWith('.qst')) { + fileName += '.qst'; } const a = document.createElement('a'); a.href = URL.createObjectURL(new Blob([cursor.buffer])); - a.download = file_name; + a.download = fileName; document.body.appendChild(a); a.click(); URL.revokeObjectURL(a.href); @@ -106,7 +106,7 @@ export function save_current_quest_to_file(file_name: string) { } } -function reset_model_and_quest_state() { +function resetModelAndQuestState() { applicationState.currentQuest = undefined; applicationState.currentArea = undefined; applicationState.selectedEntity = undefined; diff --git a/src/rendering/Renderer.ts b/src/rendering/Renderer.ts index 29230b21..17b0bdaf 100644 --- a/src/rendering/Renderer.ts +++ b/src/rendering/Renderer.ts @@ -29,16 +29,14 @@ import { const OrbitControls = OrbitControlsCreator(THREE); -interface QuestRendererParams { - on_select: (visible_quest_entity: VisibleQuestEntity | undefined) => void; -}; +type OnSelectCallback = (visibleQuestEntity: VisibleQuestEntity | undefined) => void; -interface IntersectionData { +interface PickEntityResult { object: Mesh; entity: VisibleQuestEntity; - grab_offset: Vector3; - drag_adjust: Vector3; - drag_y: number; + grabOffset: Vector3; + dragAdjust: Vector3; + dragY: number; manipulating: boolean; } @@ -46,84 +44,84 @@ interface IntersectionData { * Renders one quest area at a time. */ export class Renderer { - private _renderer = new WebGLRenderer({ antialias: true }); - private _camera: PerspectiveCamera; - private _controls: any; - private _raycaster = new Raycaster(); - private _scene = new Scene(); - private _quest?: Quest; - private _quest_entities_loaded = false; - private _area?: Area; - private _objs: Map = new Map(); // Objs grouped by area id - private _npcs: Map = new Map(); // Npcs grouped by area id - private _collision_geometry = new Object3D(); - private _render_geometry = new Object3D(); - private _obj_geometry = new Object3D(); - private _npc_geometry = new Object3D(); - private _on_select?: (visible_quest_entity: VisibleQuestEntity | undefined) => void; - private _hovered_data?: IntersectionData; - private _selected_data?: IntersectionData; - private _model?: Object3D; + private renderer = new WebGLRenderer({ antialias: true }); + private camera: PerspectiveCamera; + private controls: any; + private raycaster = new Raycaster(); + private scene = new Scene(); + private quest?: Quest; + private questEntitiesLoaded = false; + private area?: Area; + private objs: Map = new Map(); // Objs grouped by area id + private npcs: Map = new Map(); // Npcs grouped by area id + private collisionGeometry = new Object3D(); + private renderGeometry = new Object3D(); + private objGeometry = new Object3D(); + private npcGeometry = new Object3D(); + private onSelect?: OnSelectCallback; + private hoveredData?: PickEntityResult; + private selectedData?: PickEntityResult; + private model?: Object3D; - constructor({ on_select }: QuestRendererParams) { - this._on_select = on_select; + constructor({ onSelect }: { onSelect: OnSelectCallback }) { + this.onSelect = onSelect; - this._renderer.domElement.addEventListener( - 'mousedown', this._on_mouse_down); - this._renderer.domElement.addEventListener( - 'mouseup', this._on_mouse_up); - this._renderer.domElement.addEventListener( - 'mousemove', this._on_mouse_move); + this.renderer.domElement.addEventListener( + 'mousedown', this.onMouseDown); + this.renderer.domElement.addEventListener( + 'mouseup', this.onMouseUp); + this.renderer.domElement.addEventListener( + 'mousemove', this.onMouseMove); - this._camera = new PerspectiveCamera(75, 1, 0.1, 5000); - this._controls = new OrbitControls( - this._camera, this._renderer.domElement); - this._controls.mouseButtons.ORBIT = MOUSE.RIGHT; - this._controls.mouseButtons.PAN = MOUSE.LEFT; + this.camera = new PerspectiveCamera(75, 1, 0.1, 5000); + this.controls = new OrbitControls( + this.camera, this.renderer.domElement); + this.controls.mouseButtons.ORBIT = MOUSE.RIGHT; + this.controls.mouseButtons.PAN = MOUSE.LEFT; - this._scene.background = new Color(0x151C21); - this._scene.add(new HemisphereLight(0xffffff, 0x505050, 1)); - this._scene.add(this._obj_geometry); - this._scene.add(this._npc_geometry); + this.scene.background = new Color(0x151C21); + this.scene.add(new HemisphereLight(0xffffff, 0x505050, 1)); + this.scene.add(this.objGeometry); + this.scene.add(this.npcGeometry); - requestAnimationFrame(this._render_loop); + requestAnimationFrame(this.renderLoop); } - get dom_element(): HTMLElement { - return this._renderer.domElement; + get domElement(): HTMLElement { + return this.renderer.domElement; } - set_size(width: number, height: number) { - this._renderer.setSize(width, height); - this._camera.aspect = width / height; - this._camera.updateProjectionMatrix(); + setSize(width: number, height: number) { + this.renderer.setSize(width, height); + this.camera.aspect = width / height; + this.camera.updateProjectionMatrix(); } - set_quest_and_area(quest?: Quest, area?: Area) { + setQuestAndArea(quest?: Quest, area?: Area) { let update = false; - if (this._area !== area) { - this._area = area; + if (this.area !== area) { + this.area = area; update = true; } - if (this._quest !== quest) { - this._quest = quest; + if (this.quest !== quest) { + this.quest = quest; - this._objs.clear(); - this._npcs.clear(); + this.objs.clear(); + this.npcs.clear(); if (quest) { for (const obj of quest.objects) { - const array = this._objs.get(obj.areaId) || []; + const array = this.objs.get(obj.areaId) || []; array.push(obj); - this._objs.set(obj.areaId, array); + this.objs.set(obj.areaId, array); } for (const npc of quest.npcs) { - const array = this._npcs.get(npc.areaId) || []; + const array = this.npcs.get(npc.areaId) || []; array.push(npc); - this._npcs.set(npc.areaId, array); + this.npcs.set(npc.areaId, array); } } @@ -131,179 +129,179 @@ export class Renderer { } if (update) { - this._update_geometry(); + this.updateGeometry(); } } /** * Renders a generic Object3D. */ - set_model(model?: Object3D) { - if (this._model !== model) { - if (this._model) { - this._scene.remove(this._model); + setModel(model?: Object3D) { + if (this.model !== model) { + if (this.model) { + this.scene.remove(this.model); } if (model) { - this.set_quest_and_area(undefined, undefined); - this._scene.add(model); - this._reset_camera(); + this.setQuestAndArea(undefined, undefined); + this.scene.add(model); + this.resetCamera(); } - this._model = model; + this.model = model; } } - private _update_geometry() { - this._scene.remove(this._obj_geometry); - this._scene.remove(this._npc_geometry); - this._obj_geometry = new Object3D(); - this._npc_geometry = new Object3D(); - this._scene.add(this._obj_geometry); - this._scene.add(this._npc_geometry); - this._quest_entities_loaded = false; + private updateGeometry() { + this.scene.remove(this.objGeometry); + this.scene.remove(this.npcGeometry); + this.objGeometry = new Object3D(); + this.npcGeometry = new Object3D(); + this.scene.add(this.objGeometry); + this.scene.add(this.npcGeometry); + this.questEntitiesLoaded = false; - this._scene.remove(this._collision_geometry); + this.scene.remove(this.collisionGeometry); - if (this._quest && this._area) { - const episode = this._quest.episode; - const area_id = this._area.id; - const variant = this._quest.areaVariants.find(v => v.area.id === area_id); - const variant_id = (variant && variant.id) || 0; + if (this.quest && this.area) { + const episode = this.quest.episode; + const areaId = this.area.id; + const variant = this.quest.areaVariants.find(v => v.area.id === areaId); + const variantId = (variant && variant.id) || 0; - getAreaCollisionGeometry(episode, area_id, variant_id).then(geometry => { - if (this._quest && this._area) { - this.set_model(undefined); - this._scene.remove(this._collision_geometry); + getAreaCollisionGeometry(episode, areaId, variantId).then(geometry => { + if (this.quest && this.area) { + this.setModel(undefined); + this.scene.remove(this.collisionGeometry); - this._reset_camera(); + this.resetCamera(); - this._collision_geometry = geometry; - this._scene.add(geometry); + this.collisionGeometry = geometry; + this.scene.add(geometry); } }); - getAreaRenderGeometry(episode, area_id, variant_id).then(geometry => { - if (this._quest && this._area) { - this._render_geometry = geometry; + getAreaRenderGeometry(episode, areaId, variantId).then(geometry => { + if (this.quest && this.area) { + this.renderGeometry = geometry; } }); } } - private _reset_camera() { - this._controls.reset(); - this._camera.position.set(0, 800, 700); - this._camera.lookAt(new Vector3(0, 0, 0)); + private resetCamera() { + this.controls.reset(); + this.camera.position.set(0, 800, 700); + this.camera.lookAt(new Vector3(0, 0, 0)); } - private _render_loop = () => { - this._controls.update(); - this._add_loaded_entities(); - this._renderer.render(this._scene, this._camera); - requestAnimationFrame(this._render_loop); + private renderLoop = () => { + this.controls.update(); + this.addLoadedEntities(); + this.renderer.render(this.scene, this.camera); + requestAnimationFrame(this.renderLoop); } - private _add_loaded_entities() { - if (this._quest && this._area && !this._quest_entities_loaded) { + private addLoadedEntities() { + if (this.quest && this.area && !this.questEntitiesLoaded) { let loaded = true; - for (const object of this._quest.objects) { - if (object.areaId === this._area.id) { + for (const object of this.quest.objects) { + if (object.areaId === this.area.id) { if (object.object3d) { - this._obj_geometry.add(object.object3d); + this.objGeometry.add(object.object3d); } else { loaded = false; } } } - for (const npc of this._quest.npcs) { - if (npc.areaId === this._area.id) { + for (const npc of this.quest.npcs) { + if (npc.areaId === this.area.id) { if (npc.object3d) { - this._npc_geometry.add(npc.object3d); + this.npcGeometry.add(npc.object3d); } else { loaded = false; } } } - this._quest_entities_loaded = loaded; + this.questEntitiesLoaded = loaded; } } - private _on_mouse_down = (e: MouseEvent) => { - const old_selected_data = this._selected_data; - const data = this._pick_entity( - this._pointer_pos_to_device_coords(e)); + private onMouseDown = (e: MouseEvent) => { + const oldSelectedData = this.selectedData; + const data = this.pickEntity( + this.pointerPosToDeviceCoords(e)); // Did we pick a different object than the previously hovered over 3D object? - if (this._hovered_data && (!data || data.object !== this._hovered_data.object)) { - (this._hovered_data.object.material as MeshLambertMaterial).color.set( - this._get_color(this._hovered_data.entity, 'normal')); + if (this.hoveredData && (!data || data.object !== this.hoveredData.object)) { + (this.hoveredData.object.material as MeshLambertMaterial).color.set( + this.getColor(this.hoveredData.entity, 'normal')); } // Did we pick a different object than the previously selected 3D object? - if (this._selected_data && (!data || data.object !== this._selected_data.object)) { - (this._selected_data.object.material as MeshLambertMaterial).color.set( - this._get_color(this._selected_data.entity, 'normal')); - this._selected_data.manipulating = false; + if (this.selectedData && (!data || data.object !== this.selectedData.object)) { + (this.selectedData.object.material as MeshLambertMaterial).color.set( + this.getColor(this.selectedData.entity, 'normal')); + this.selectedData.manipulating = false; } if (data) { // User selected an entity. - (data.object.material as MeshLambertMaterial).color.set(this._get_color(data.entity, 'selected')); + (data.object.material as MeshLambertMaterial).color.set(this.getColor(data.entity, 'selected')); data.manipulating = true; - this._hovered_data = data; - this._selected_data = data; - this._controls.enabled = false; + this.hoveredData = data; + this.selectedData = data; + this.controls.enabled = false; } else { // User clicked on terrain or outside of area. - this._hovered_data = undefined; - this._selected_data = undefined; - this._controls.enabled = true; + this.hoveredData = undefined; + this.selectedData = undefined; + this.controls.enabled = true; } - const selection_changed = old_selected_data && data - ? old_selected_data.object !== data.object - : old_selected_data !== data; + const selectionChanged = oldSelectedData && data + ? oldSelectedData.object !== data.object + : oldSelectedData !== data; - if (selection_changed && this._on_select) { - this._on_select(data && data.entity); + if (selectionChanged && this.onSelect) { + this.onSelect(data && data.entity); } } - private _on_mouse_up = () => { - if (this._selected_data) { - this._selected_data.manipulating = false; - this._controls.enabled = true; + private onMouseUp = () => { + if (this.selectedData) { + this.selectedData.manipulating = false; + this.controls.enabled = true; } } - private _on_mouse_move = (e: MouseEvent) => { - const pointer_pos = this._pointer_pos_to_device_coords(e); + private onMouseMove = (e: MouseEvent) => { + const pointerPos = this.pointerPosToDeviceCoords(e); - if (this._selected_data && this._selected_data.manipulating) { + if (this.selectedData && this.selectedData.manipulating) { if (e.button === 0) { // User is dragging a selected entity. - const data = this._selected_data; + const data = this.selectedData; if (e.shiftKey) { // Vertical movement. // We intersect with a plane that's oriented toward the camera and that's coplanar with the point where the entity was grabbed. - this._raycaster.setFromCamera(pointer_pos, this._camera); - const ray = this._raycaster.ray; - const negative_world_dir = this._camera.getWorldDirection(new Vector3()).negate(); + this.raycaster.setFromCamera(pointerPos, this.camera); + const ray = this.raycaster.ray; + const negativeWorldDir = this.camera.getWorldDirection(new Vector3()).negate(); const plane = new Plane().setFromNormalAndCoplanarPoint( - new Vector3(negative_world_dir.x, 0, negative_world_dir.z).normalize(), - data.object.position.sub(data.grab_offset)); - const intersection_point = new Vector3(); + new Vector3(negativeWorldDir.x, 0, negativeWorldDir.z).normalize(), + data.object.position.sub(data.grabOffset)); + const intersectionPoint = new Vector3(); - if (ray.intersectPlane(plane, intersection_point)) { - const y = intersection_point.y + data.grab_offset.y; - const y_delta = y - data.entity.position.y; - data.drag_y += y_delta; - data.drag_adjust.y -= y_delta; + if (ray.intersectPlane(plane, intersectionPoint)) { + const y = intersectionPoint.y + data.grabOffset.y; + const yDelta = y - data.entity.position.y; + data.dragY += yDelta; + data.dragAdjust.y -= yDelta; data.entity.position = new Vec3( data.entity.position.x, y, @@ -313,12 +311,12 @@ export class Renderer { } else { // Horizontal movement accross terrain. // Cast ray adjusted for dragging entities. - const { intersection: terrain, section } = this._pick_terrain(pointer_pos, data); + const { intersection: terrain, section } = this.pickTerrain(pointerPos, data); if (terrain) { data.entity.position = new Vec3( terrain.point.x, - terrain.point.y + data.drag_y, + terrain.point.y + data.dragY, terrain.point.z ); @@ -327,19 +325,19 @@ export class Renderer { } } else { // If the cursor is not over any terrain, we translate the entity accross the horizontal plane in which the entity's origin lies. - this._raycaster.setFromCamera(pointer_pos, this._camera); - const ray = this._raycaster.ray; - // ray.origin.add(data.drag_adjust); + this.raycaster.setFromCamera(pointerPos, this.camera); + const ray = this.raycaster.ray; + // ray.origin.add(data.dragAdjust); const plane = new Plane( new Vector3(0, 1, 0), - -data.entity.position.y + data.grab_offset.y); - const intersection_point = new Vector3(); + -data.entity.position.y + data.grabOffset.y); + const intersectionPoint = new Vector3(); - if (ray.intersectPlane(plane, intersection_point)) { + if (ray.intersectPlane(plane, intersectionPoint)) { data.entity.position = new Vec3( - intersection_point.x + data.grab_offset.x, + intersectionPoint.x + data.grabOffset.x, data.entity.position.y, - intersection_point.z + data.grab_offset.z + intersectionPoint.z + data.grabOffset.z ); } } @@ -347,95 +345,99 @@ export class Renderer { } } else { // User is hovering. - const old_data = this._hovered_data; - const data = this._pick_entity(pointer_pos); + const oldData = this.hoveredData; + const data = this.pickEntity(pointerPos); - if (old_data && (!data || data.object !== old_data.object)) { - if (!this._selected_data || old_data.object !== this._selected_data.object) { - (old_data.object.material as MeshLambertMaterial).color.set( - this._get_color(old_data.entity, 'normal')); + if (oldData && (!data || data.object !== oldData.object)) { + if (!this.selectedData || oldData.object !== this.selectedData.object) { + (oldData.object.material as MeshLambertMaterial).color.set( + this.getColor(oldData.entity, 'normal')); } - this._hovered_data = undefined; + this.hoveredData = undefined; } - if (data && (!old_data || data.object !== old_data.object)) { - if (!this._selected_data || data.object !== this._selected_data.object) { + if (data && (!oldData || data.object !== oldData.object)) { + if (!this.selectedData || data.object !== this.selectedData.object) { (data.object.material as MeshLambertMaterial).color.set( - this._get_color(data.entity, 'hover')); + this.getColor(data.entity, 'hover')); } - this._hovered_data = data; + this.hoveredData = data; } } } - private _pointer_pos_to_device_coords(e: MouseEvent) { + private pointerPosToDeviceCoords(e: MouseEvent) { const coords = new Vector2(); - this._renderer.getSize(coords); + this.renderer.getSize(coords); coords.width = e.offsetX / coords.width * 2 - 1; coords.height = e.offsetY / coords.height * -2 + 1; return coords; } /** - * @param pointer_pos - pointer coordinates in normalized device space + * @param pointerPos - pointer coordinates in normalized device space */ - private _pick_entity(pointer_pos: Vector2): IntersectionData | undefined { + private pickEntity(pointerPos: Vector2): PickEntityResult | undefined { // Find the nearest object and NPC under the pointer. - this._raycaster.setFromCamera(pointer_pos, this._camera); - const [nearest_object] = this._raycaster.intersectObjects( - this._obj_geometry.children); - const [nearest_npc] = this._raycaster.intersectObjects( - this._npc_geometry.children); + this.raycaster.setFromCamera(pointerPos, this.camera); + const [nearestObject] = this.raycaster.intersectObjects( + this.objGeometry.children + ); + const [nearestNpc] = this.raycaster.intersectObjects( + this.npcGeometry.children + ); - if (!nearest_object && !nearest_npc) { + if (!nearestObject && !nearestNpc) { return; } - const object_dist = nearest_object ? nearest_object.distance : Infinity; - const npc_dist = nearest_npc ? nearest_npc.distance : Infinity; - const intersection = object_dist < npc_dist ? nearest_object : nearest_npc; + const objectDist = nearestObject ? nearestObject.distance : Infinity; + const npcDist = nearestNpc ? nearestNpc.distance : Infinity; + const intersection = objectDist < npcDist ? nearestObject : nearestNpc; const entity = intersection.object.userData.entity; // Vector that points from the grabbing point to the model's origin. - const grab_offset = intersection.object.position + const grabOffset = intersection.object.position .clone() .sub(intersection.point); // Vector that points from the grabbing point to the terrain point directly under the model's origin. - const drag_adjust = grab_offset.clone(); + const dragAdjust = grabOffset.clone(); // Distance to terrain. - let drag_y = 0; + let dragY = 0; // Find vertical distance to terrain. - this._raycaster.set( - intersection.object.position, new Vector3(0, -1, 0)); - const [terrain] = this._raycaster.intersectObjects( - this._collision_geometry.children, true); + this.raycaster.set( + intersection.object.position, new Vector3(0, -1, 0) + ); + const [terrain] = this.raycaster.intersectObjects( + this.collisionGeometry.children, true + ); if (terrain) { - drag_adjust.sub(new Vector3(0, terrain.distance, 0)); - drag_y += terrain.distance; + dragAdjust.sub(new Vector3(0, terrain.distance, 0)); + dragY += terrain.distance; } return { object: intersection.object as Mesh, entity, - grab_offset, - drag_adjust, - drag_y, + grabOffset: grabOffset, + dragAdjust: dragAdjust, + dragY: dragY, manipulating: false }; } /** - * @param pointer_pos - pointer coordinates in normalized device space + * @param pointerPos - pointer coordinates in normalized device space */ - private _pick_terrain(pointer_pos: Vector2, data: any): { intersection?: Intersection, section?: Section } { - this._raycaster.setFromCamera(pointer_pos, this._camera); - this._raycaster.ray.origin.add(data.drag_adjust); - const terrains = this._raycaster.intersectObjects( - this._collision_geometry.children, true); + private pickTerrain(pointerPos: Vector2, data: PickEntityResult): { intersection?: Intersection, section?: Section } { + this.raycaster.setFromCamera(pointerPos, this.camera); + this.raycaster.ray.origin.add(data.dragAdjust); + const terrains = this.raycaster.intersectObjects( + this.collisionGeometry.children, true); // Don't allow entities to be placed on very steep terrain. // E.g. walls. @@ -443,15 +445,15 @@ export class Renderer { for (const terrain of terrains) { if (terrain.face!.normal.y > 0.75) { // Find section ID. - this._raycaster.set( + this.raycaster.set( terrain.point.clone().setY(1000), new Vector3(0, -1, 0)); - const render_terrains = this._raycaster - .intersectObjects(this._render_geometry.children, true) + const renderTerrains = this.raycaster + .intersectObjects(this.renderGeometry.children, true) .filter(rt => rt.object.userData.section.id >= 0); return { intersection: terrain, - section: render_terrains[0] && render_terrains[0].object.userData.section + section: renderTerrains[0] && renderTerrains[0].object.userData.section }; } } @@ -459,14 +461,14 @@ export class Renderer { return {}; } - private _get_color(entity: VisibleQuestEntity, type: 'normal' | 'hover' | 'selected') { - const is_npc = entity instanceof QuestNpc; + private getColor(entity: VisibleQuestEntity, type: 'normal' | 'hover' | 'selected') { + const isNpc = entity instanceof QuestNpc; switch (type) { default: - case 'normal': return is_npc ? NPC_COLOR : OBJECT_COLOR; - case 'hover': return is_npc ? NPC_HOVER_COLOR : OBJECT_HOVER_COLOR; - case 'selected': return is_npc ? NPC_SELECTED_COLOR : OBJECT_SELECTED_COLOR; + case 'normal': return isNpc ? NPC_COLOR : OBJECT_COLOR; + case 'hover': return isNpc ? NPC_HOVER_COLOR : OBJECT_HOVER_COLOR; + case 'selected': return isNpc ? NPC_SELECTED_COLOR : OBJECT_SELECTED_COLOR; } } } diff --git a/src/ui/ApplicationComponent.tsx b/src/ui/ApplicationComponent.tsx index e206cec3..11acf8f8 100644 --- a/src/ui/ApplicationComponent.tsx +++ b/src/ui/ApplicationComponent.tsx @@ -2,7 +2,7 @@ import React, { ChangeEvent, KeyboardEvent } from 'react'; import { observer } from 'mobx-react'; import { Button, Dialog, Intent } from '@blueprintjs/core'; import { applicationState } from '../store'; -import { current_area_id_changed, load_file, save_current_quest_to_file } from '../actions'; +import { currentAreaIdChanged, loadFile, saveCurrentQuestToFile } from '../actions'; import { Area3DComponent } from './Area3DComponent'; import { EntityInfoComponent } from './EntityInfoComponent'; import { QuestInfoComponent } from './QuestInfoComponent'; @@ -117,14 +117,14 @@ export class ApplicationComponent extends React.Component<{}, { this.setState({ filename: file.name }); - load_file(file); + loadFile(file); } } } private _on_area_select_change = (e: ChangeEvent) => { const area_id = parseInt(e.currentTarget.value, 10); - current_area_id_changed(area_id); + currentAreaIdChanged(area_id); } private _on_save_as_click = () => { @@ -148,7 +148,7 @@ export class ApplicationComponent extends React.Component<{}, { } private _on_save_dialog_save_click = () => { - save_current_quest_to_file(this.state.save_dialog_filename); + saveCurrentQuestToFile(this.state.save_dialog_filename); this.setState({ save_dialog_open: false }); } diff --git a/src/ui/Area3DComponent.tsx b/src/ui/Area3DComponent.tsx index 40a239ca..511a1978 100644 --- a/src/ui/Area3DComponent.tsx +++ b/src/ui/Area3DComponent.tsx @@ -1,6 +1,6 @@ import React from 'react'; import { Object3D } from 'three'; -import { entity_selected } from '../actions'; +import { entitySelected } from '../actions'; import { Renderer } from '../rendering/Renderer'; import { Area, Quest, VisibleQuestEntity } from '../domain'; @@ -11,34 +11,34 @@ interface Props { } export class Area3DComponent extends React.Component { - private _renderer: Renderer; + private renderer: Renderer; constructor(props: Props) { super(props); - // _renderer has to be assigned here so that it happens after _on_select is assigned. - this._renderer = new Renderer({ - on_select: this._on_select + // renderer has to be assigned here so that it happens after onSelect is assigned. + this.renderer = new Renderer({ + onSelect: this.onSelect }); } render() { - return
; + return
; } componentDidMount() { - window.addEventListener('resize', this._on_resize); + window.addEventListener('resize', this.onResize); } componentWillUnmount() { - window.removeEventListener('resize', this._on_resize); + window.removeEventListener('resize', this.onResize); } componentWillReceiveProps({ quest, area, model }: Props) { if (model) { - this._renderer.set_model(model); + this.renderer.setModel(model); } else { - this._renderer.set_quest_and_area(quest, area); + this.renderer.setQuestAndArea(quest, area); } } @@ -46,17 +46,17 @@ export class Area3DComponent extends React.Component { return false; } - private _modify_dom = (div: HTMLDivElement) => { - this._renderer.set_size(div.clientWidth, div.clientHeight); - div.appendChild(this._renderer.dom_element); + private modifyDom = (div: HTMLDivElement) => { + this.renderer.setSize(div.clientWidth, div.clientHeight); + div.appendChild(this.renderer.domElement); } - private _on_select = (entity?: VisibleQuestEntity) => { - entity_selected(entity); + private onSelect = (entity?: VisibleQuestEntity) => { + entitySelected(entity); } - private _on_resize = () => { - const wrapper_div = this._renderer.dom_element.parentNode as HTMLDivElement; - this._renderer.set_size(wrapper_div.clientWidth, wrapper_div.clientHeight); + private onResize = () => { + const wrapperDiv = this.renderer.domElement.parentNode as HTMLDivElement; + this.renderer.setSize(wrapperDiv.clientWidth, wrapperDiv.clientHeight); } } diff --git a/src/ui/EntityInfoComponent.tsx b/src/ui/EntityInfoComponent.tsx index 2e9ed544..4ac97114 100644 --- a/src/ui/EntityInfoComponent.tsx +++ b/src/ui/EntityInfoComponent.tsx @@ -4,14 +4,14 @@ import { NumericInput } from '@blueprintjs/core'; import { VisibleQuestEntity, QuestObject, QuestNpc } from '../domain'; import './EntityInfoComponent.css'; -const container_style: CSSProperties = { +const containerStyle: CSSProperties = { width: 200, padding: 10, display: 'flex', flexDirection: 'column' }; -const table_style: CSSProperties = { +const tableStyle: CSSProperties = { borderCollapse: 'collapse' }; @@ -27,7 +27,7 @@ export class EntityInfoComponent extends React.Component { y: null, z: null, }, - section_position: { + sectionPosition: { x: null, y: null, z: null, @@ -36,7 +36,7 @@ export class EntityInfoComponent extends React.Component { componentWillReceiveProps({ entity }: Props) { if (this.props.entity !== entity) { - this._clear_position_state(); + this.clearPositionState(); } } @@ -44,7 +44,7 @@ export class EntityInfoComponent extends React.Component { const entity = this.props.entity; if (entity) { - const section_id = entity.section ? entity.section.id : entity.sectionId; + const sectionId = entity.section ? entity.section.id : entity.sectionId; let name = null; if (entity instanceof QuestObject) { @@ -62,12 +62,12 @@ export class EntityInfoComponent extends React.Component { } return ( -
- +
+
{name} - + @@ -76,9 +76,9 @@ export class EntityInfoComponent extends React.Component { @@ -90,9 +90,9 @@ export class EntityInfoComponent extends React.Component { @@ -102,18 +102,18 @@ export class EntityInfoComponent extends React.Component { ); } else { - return
; + return
; } } - private _coord_row(pos_type: string, coord: string) { + private coordRow(posType: string, coord: string) { if (this.props.entity) { const entity = this.props.entity; - const value_str = (this.state as any)[pos_type][coord]; - const value = value_str - ? value_str + const valueStr = (this.state as any)[posType][coord]; + const value = valueStr + ? valueStr // Do multiplication, rounding, division and || with zero to avoid numbers close to zero flickering between 0 and -0. - : (Math.round((entity as any)[pos_type][coord] * 10000) / 10000 || 0).toFixed(4); + : (Math.round((entity as any)[posType][coord] * 10000) / 10000 || 0).toFixed(4); return (
@@ -122,8 +122,8 @@ export class EntityInfoComponent extends React.Component { value={value} className="pt-fill EntityInfoComponent-coord" buttonPosition="none" - onValueChange={(this._pos_change as any)[pos_type][coord]} - onBlur={this._coord_input_blurred} /> + onValueChange={(this.posChange as any)[posType][coord]} + onBlur={this.coordInputBlurred} /> ); @@ -132,61 +132,61 @@ export class EntityInfoComponent extends React.Component { } } - private _pos_change = { + private posChange = { position: { - x: (value: number, value_str: string) => { - this._pos_changed('position', 'x', value, value_str); + x: (value: number, valueStr: string) => { + this.posChanged('position', 'x', value, valueStr); }, - y: (value: number, value_str: string) => { - this._pos_changed('position', 'y', value, value_str); + y: (value: number, valueStr: string) => { + this.posChanged('position', 'y', value, valueStr); }, - z: (value: number, value_str: string) => { - this._pos_changed('position', 'z', value, value_str); + z: (value: number, valueStr: string) => { + this.posChanged('position', 'z', value, valueStr); } }, - section_position: { - x: (value: number, value_str: string) => { - this._pos_changed('section_position', 'x', value, value_str); + sectionPosition: { + x: (value: number, valueStr: string) => { + this.posChanged('sectionPosition', 'x', value, valueStr); }, - y: (value: number, value_str: string) => { - this._pos_changed('section_position', 'y', value, value_str); + y: (value: number, valueStr: string) => { + this.posChanged('sectionPosition', 'y', value, valueStr); }, - z: (value: number, value_str: string) => { - this._pos_changed('section_position', 'z', value, value_str); + z: (value: number, valueStr: string) => { + this.posChanged('sectionPosition', 'z', value, valueStr); } } }; - private _pos_changed(pos_type: string, coord: string, value: number, value_str: string) { + private posChanged(posType: string, coord: string, value: number, valueStr: string) { if (!isNaN(value)) { const entity = this.props.entity as any; if (entity) { - const v = entity[pos_type].clone(); + const v = entity[posType].clone(); v[coord] = value; - entity[pos_type] = v; + entity[posType] = v; } } this.setState({ - [pos_type]: { - [coord]: value_str + [posType]: { + [coord]: valueStr } }); } - private _coord_input_blurred = () => { - this._clear_position_state(); + private coordInputBlurred = () => { + this.clearPositionState(); } - private _clear_position_state() { + private clearPositionState() { this.setState({ position: { x: null, y: null, z: null, }, - section_position: { + sectionPosition: { x: null, y: null, z: null, diff --git a/src/ui/QuestInfoComponent.tsx b/src/ui/QuestInfoComponent.tsx index 3214fa67..7fbb9871 100644 --- a/src/ui/QuestInfoComponent.tsx +++ b/src/ui/QuestInfoComponent.tsx @@ -1,92 +1,92 @@ import React, { CSSProperties } from 'react'; import { NpcType, Quest } from '../domain'; -const container_style: CSSProperties = { +const containerStyle: CSSProperties = { width: 280, padding: 10, display: 'flex', flexDirection: 'column' }; -const table_style: CSSProperties = { +const tableStyle: CSSProperties = { borderCollapse: 'collapse', width: '100%' }; -const table_header_style: CSSProperties = { +const tableHeaderStyle: CSSProperties = { textAlign: 'right', paddingRight: 5 }; -const description_style: CSSProperties = { +const descriptionStyle: CSSProperties = { whiteSpace: 'pre-wrap', margin: '3px 0 3px 0' }; -const npc_counts_container_style: CSSProperties = { +const npcCountsContainerStyle: CSSProperties = { overflow: 'auto' }; export function QuestInfoComponent({ quest }: { quest?: Quest }) { if (quest) { const episode = quest.episode === 4 ? 'IV' : (quest.episode === 2 ? 'II' : 'I'); - const npc_counts = new Map(); + const npcCounts = new Map(); for (const npc of quest.npcs) { - const val = npc_counts.get(npc.type) || 0; - npc_counts.set(npc.type, val + 1); + const val = npcCounts.get(npc.type) || 0; + npcCounts.set(npc.type, val + 1); } - const extra_canadines = (npc_counts.get(NpcType.Canane) || 0) * 8; + const extraCanadines = (npcCounts.get(NpcType.Canane) || 0) * 8; // Sort by type ID. - const sorted_npc_counts = [...npc_counts].sort((a, b) => a[0].id - b[0].id); + const sortedNpcCounts = [...npcCounts].sort((a, b) => a[0].id - b[0].id); - const npc_count_rows = sorted_npc_counts.map(([npc_type, count]) => { - const extra = npc_type === NpcType.Canadine ? extra_canadines : 0; + const npcCountRows = sortedNpcCounts.map(([npcType, count]) => { + const extra = npcType === NpcType.Canadine ? extraCanadines : 0; return ( - - + + ); }); return ( -
-
Section: {section_id}Section: {sectionId}
World position: - {this._coord_row('position', 'x')} - {this._coord_row('position', 'y')} - {this._coord_row('position', 'z')} + {this.coordRow('position', 'x')} + {this.coordRow('position', 'y')} + {this.coordRow('position', 'z')}
- {this._coord_row('section_position', 'x')} - {this._coord_row('section_position', 'y')} - {this._coord_row('section_position', 'z')} + {this.coordRow('sectionPosition', 'x')} + {this.coordRow('sectionPosition', 'y')} + {this.coordRow('sectionPosition', 'z')}
{coord.toUpperCase()}:
{npc_type.name}:
{npcType.name}: {count + extra}
+
+
- + - +
Name:{quest.name}Name:{quest.name}
Episode:{episode}Episode:{episode}
-
{quest.shortDescription}
+
{quest.shortDescription}
-
{quest.longDescription}
+
{quest.longDescription}
-
- +
+
- {npc_count_rows} + {npcCountRows}
NPC Counts
); } else { - return
; + return
; } }