diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..f59dd0e --- /dev/null +++ b/.editorconfig @@ -0,0 +1,11 @@ +root = true + +[*] +charset = utf-8 +end_of_line = lf +indent_size = 2 +indent_style = space +insert_final_newline = true +max_line_length = 160 +tab_width = 2 +trim_trailing_whitespace = true diff --git a/index.html b/index.html index 0765a27..5746392 100644 --- a/index.html +++ b/index.html @@ -1,134 +1,143 @@ - - - - The Legend of SimonDev - - - - - - - - -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Statistics
-
-
Strength -
How strong you are, affects how much damage you do. So blah blah if you're doing stuff then its stronger or whatever, the damage is up. This is text to show the tooltip.
-
-
0
-
-
-
Wisdomness -
Wisdom is the guage of something to do with wisdom in the game because wisdom is important and wisdom is wise to wisdoming.
-
-
0
-
-
-
Benchpress -
Gotta have a good bench to be a warrior or something.
-
-
0
-
-
-
Curl -
The ultimate expression of strength, this affects literally everything in your life.
-
-
0
-
-
-
XP -
How much xp you've accumulated by killing things for xp. Get enough and you'll gain a level or something.
-
-
0
-
-
-
-
-
-
-
-
-
-
-
-
-
Inventory
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- - + + + + The Legend of SimonDev + + + + + + + + + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Statistics
+
+
Strength +
How strong you are, affects how much damage you do. So blah blah if you're doing stuff then its stronger or whatever, the damage is up. This is text to show the tooltip.
+
+
0
+
+
+
Wisdomness +
Wisdom is the guage of something to do with wisdom in the game because wisdom is important and wisdom is wise to wisdoming.
+
+
0
+
+
+
Benchpress +
Gotta have a good bench to be a warrior or something.
+
+
0
+
+
+
Curl +
The ultimate expression of strength, this affects literally everything in your life.
+
+
0
+
+
+
XP +
How much xp you've accumulated by killing things for xp. Get enough and you'll gain a level or something.
+
+
0
+
+
+
+
+
+
+
+
+
+
+
+
+
Inventory
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ + diff --git a/src/attacker-controller.js b/src/attacker-controller.js index 9e220ef..591dd85 100644 --- a/src/attacker-controller.js +++ b/src/attacker-controller.js @@ -1,4 +1,4 @@ -import * as THREE from 'https://cdn.jsdelivr.net/npm/three@0.118/build/three.module.js'; +import * as THREE from 'three'; import {entity} from './entity.js'; @@ -46,7 +46,7 @@ export const attack_controller = (() => { if (c.entity == this._parent) { return false; } - + const h = c.entity.GetComponent('HealthComponent'); if (!h) { return false; @@ -65,7 +65,7 @@ export const attack_controller = (() => { const forward = new THREE.Vector3(0, 0, 1); forward.applyQuaternion(this._parent._rotation); forward.normalize(); - + let damage = this.GetComponent('HealthComponent')._params.strength; if (item) { damage *= item.Params.damage; @@ -88,4 +88,4 @@ export const attack_controller = (() => { return { AttackController: AttackController, }; -})(); \ No newline at end of file +})(); diff --git a/src/entity.js b/src/entity.js index cb983db..73d773f 100644 --- a/src/entity.js +++ b/src/entity.js @@ -1,4 +1,4 @@ -import * as THREE from 'https://cdn.jsdelivr.net/npm/three@0.118/build/three.module.js'; +import * as THREE from 'three'; export const entity = (() => { @@ -120,4 +120,4 @@ export const entity = (() => { Component: Component, }; -})(); \ No newline at end of file +})(); diff --git a/src/equip-weapon-component.js b/src/equip-weapon-component.js index 2e53400..c5fc49d 100644 --- a/src/equip-weapon-component.js +++ b/src/equip-weapon-component.js @@ -1,6 +1,6 @@ import {entity} from './entity.js'; -import {FBXLoader} from 'https://cdn.jsdelivr.net/npm/three@0.118.1/examples/jsm/loaders/FBXLoader.js'; +import {FBXLoader} from 'three/FBXLoader'; export const equip_weapon_component = (() => { @@ -87,4 +87,4 @@ export const equip_weapon_component = (() => { return { EquipWeapon: EquipWeapon, }; -})(); \ No newline at end of file +})(); diff --git a/src/gltf-component.js b/src/gltf-component.js index dff5bac..b8449ca 100644 --- a/src/gltf-component.js +++ b/src/gltf-component.js @@ -1,236 +1,236 @@ -import * as THREE from 'https://cdn.jsdelivr.net/npm/three@0.118/build/three.module.js'; - -import {GLTFLoader} from 'https://cdn.jsdelivr.net/npm/three@0.118.1/examples/jsm/loaders/GLTFLoader.js'; -import {FBXLoader} from 'https://cdn.jsdelivr.net/npm/three@0.118.1/examples/jsm/loaders/FBXLoader.js'; - -import {entity} from './entity.js'; - - -export const gltf_component = (() => { - - class StaticModelComponent extends entity.Component { - constructor(params) { - super(); - this._Init(params); - } - - _Init(params) { - this._params = params; - - this._LoadModels(); - } - - InitComponent() { - this._RegisterHandler('update.position', (m) => { this._OnPosition(m); }); - } - - _OnPosition(m) { - if (this._target) { - this._target.position.copy(m.value); - } - } - - _LoadModels() { - if (this._params.resourceName.endsWith('glb') || this._params.resourceName.endsWith('gltf')) { - this._LoadGLB(); - } else if (this._params.resourceName.endsWith('fbx')) { - this._LoadFBX(); - } - } - - _OnLoaded(obj) { - this._target = obj; - this._params.scene.add(this._target); - - this._target.scale.setScalar(this._params.scale); - this._target.position.copy(this._parent._position); - - let texture = null; - if (this._params.resourceTexture) { - const texLoader = new THREE.TextureLoader(); - texture = texLoader.load(this._params.resourceTexture); - texture.encoding = THREE.sRGBEncoding; - } - - this._target.traverse(c => { - let materials = c.material; - if (!(c.material instanceof Array)) { - materials = [c.material]; - } - - for (let m of materials) { - if (m) { - if (texture) { - m.map = texture; - } - if (this._params.specular) { - m.specular = this._params.specular; - } - if (this._params.emissive) { - m.emissive = this._params.emissive; - } - } - } - if (this._params.receiveShadow != undefined) { - c.receiveShadow = this._params.receiveShadow; - } - if (this._params.castShadow != undefined) { - c.castShadow = this._params.castShadow; - } - if (this._params.visible != undefined) { - c.visible = this._params.visible; - } - }); - } - - _LoadGLB() { - const loader = new GLTFLoader(); - loader.setPath(this._params.resourcePath); - loader.load(this._params.resourceName, (glb) => { - this._OnLoaded(glb.scene); - }); - } - - _LoadFBX() { - const loader = new FBXLoader(); - loader.setPath(this._params.resourcePath); - loader.load(this._params.resourceName, (fbx) => { - this._OnLoaded(fbx); - }); - } - - Update(timeInSeconds) { - } - }; - - - class AnimatedModelComponent extends entity.Component { - constructor(params) { - super(); - this._Init(params); - } - - InitComponent() { - this._RegisterHandler('update.position', (m) => { this._OnPosition(m); }); - } - - _OnPosition(m) { - if (this._target) { - this._target.position.copy(m.value); - this._target.position.y = 0.35; - } - } - - _Init(params) { - this._params = params; - - this._LoadModels(); - } - - _LoadModels() { - if (this._params.resourceName.endsWith('glb') || this._params.resourceName.endsWith('gltf')) { - this._LoadGLB(); - } else if (this._params.resourceName.endsWith('fbx')) { - this._LoadFBX(); - } - } - - _OnLoaded(obj, animations) { - this._target = obj; - this._params.scene.add(this._target); - - this._target.scale.setScalar(this._params.scale); - this._target.position.copy(this._parent._position); - - this.Broadcast({ - topic: 'update.position', - value: this._parent._position, - }); - - let texture = null; - if (this._params.resourceTexture) { - const texLoader = new THREE.TextureLoader(); - texture = texLoader.load(this._params.resourceTexture); - texture.encoding = THREE.sRGBEncoding; - } - - this._target.traverse(c => { - let materials = c.material; - if (!(c.material instanceof Array)) { - materials = [c.material]; - } - - for (let m of materials) { - if (m) { - if (texture) { - m.map = texture; - } - if (this._params.specular) { - m.specular = this._params.specular; - } - if (this._params.emissive) { - m.emissive = this._params.emissive; - } - } - } - if (this._params.receiveShadow != undefined) { - c.receiveShadow = this._params.receiveShadow; - } - if (this._params.castShadow != undefined) { - c.castShadow = this._params.castShadow; - } - if (this._params.visible != undefined) { - c.visible = this._params.visible; - } - }); - - const _OnLoad = (anim) => { - const clip = anim.animations[0]; - const action = this._mixer.clipAction(clip); - - action.play(); - }; - - const loader = new FBXLoader(); - loader.setPath(this._params.resourcePath); - loader.load(this._params.resourceAnimation, (a) => { _OnLoad(a); }); - - this._mixer = new THREE.AnimationMixer(this._target); - - this._parent._mesh = this._target; - this.Broadcast({ - topic: 'load.character', - model: this._target, - }); - } - - _LoadGLB() { - const loader = new GLTFLoader(); - loader.setPath(this._params.resourcePath); - loader.load(this._params.resourceName, (glb) => { - this._OnLoaded(glb.scene, glb.animations); - }); - } - - _LoadFBX() { - const loader = new FBXLoader(); - loader.setPath(this._params.resourcePath); - loader.load(this._params.resourceName, (fbx) => { - this._OnLoaded(fbx); - }); - } - - Update(timeInSeconds) { - if (this._mixer) { - this._mixer.update(timeInSeconds); - } - } - }; - - - return { - StaticModelComponent: StaticModelComponent, - AnimatedModelComponent: AnimatedModelComponent, - }; - -})(); \ No newline at end of file +import * as THREE from 'three'; + +import { GLTFLoader } from 'three/GLTFLoader'; +import { FBXLoader } from 'three/FBXLoader'; + +import { entity } from './entity.js'; + +export const gltf_component = (() => { + + class StaticModelComponent extends entity.Component { + constructor(params) { + super(); + this._Init(params); + } + + _Init(params) { + this._params = params; + + this._LoadModels(); + } + + InitComponent() { + this._RegisterHandler('update.position', (m) => { + this._OnPosition(m); + }); + } + + _OnPosition(m) { + if (this._target) { + this._target.position.copy(m.value); + } + } + + _LoadModels() { + if (this._params.resourceName.endsWith('glb') || this._params.resourceName.endsWith('gltf')) { + this._LoadGLB(); + } else if (this._params.resourceName.endsWith('fbx')) { + this._LoadFBX(); + } + } + + _OnLoaded(obj) { + this._target = obj; + this._params.scene.add(this._target); + + this._target.scale.setScalar(this._params.scale); + this._target.position.copy(this._parent._position); + + let texture = null; + if (this._params.resourceTexture) { + const texLoader = new THREE.TextureLoader(); + texture = texLoader.load(this._params.resourceTexture); + texture.encoding = THREE.sRGBEncoding; + } + + this._target.traverse(c => { + let materials = c.material; + if (!(c.material instanceof Array)) { + materials = [c.material]; + } + + for (let m of materials) { + if (m) { + if (texture) { + m.map = texture; + } + if (this._params.specular) { + m.specular = this._params.specular; + } + if (this._params.emissive) { + m.emissive = this._params.emissive; + } + } + } + if (this._params.receiveShadow != undefined) { + c.receiveShadow = this._params.receiveShadow; + } + if (this._params.castShadow != undefined) { + c.castShadow = this._params.castShadow; + } + if (this._params.visible != undefined) { + c.visible = this._params.visible; + } + }); + } + + _LoadGLB() { + const loader = new GLTFLoader(); + loader.setPath(this._params.resourcePath); + loader.load(this._params.resourceName, (glb) => { + this._OnLoaded(glb.scene); + }); + } + + _LoadFBX() { + const loader = new FBXLoader(); + loader.setPath(this._params.resourcePath); + loader.load(this._params.resourceName, (fbx) => { + this._OnLoaded(fbx); + }); + } + + Update(timeInSeconds) { + } + } + + class AnimatedModelComponent extends entity.Component { + constructor(params) { + super(); + this._Init(params); + } + + InitComponent() { + this._RegisterHandler('update.position', (m) => { + this._OnPosition(m); + }); + } + + _OnPosition(m) { + if (this._target) { + this._target.position.copy(m.value); + this._target.position.y = 0.35; + } + } + + _Init(params) { + this._params = params; + + this._LoadModels(); + } + + _LoadModels() { + if (this._params.resourceName.endsWith('glb') || this._params.resourceName.endsWith('gltf')) { + this._LoadGLB(); + } else if (this._params.resourceName.endsWith('fbx')) { + this._LoadFBX(); + } + } + + _OnLoaded(obj, animations) { + this._target = obj; + this._params.scene.add(this._target); + + this._target.scale.setScalar(this._params.scale); + this._target.position.copy(this._parent._position); + + this.Broadcast({ + topic: 'update.position', + value: this._parent._position, + }); + + let texture = null; + if (this._params.resourceTexture) { + const texLoader = new THREE.TextureLoader(); + texture = texLoader.load(this._params.resourceTexture); + texture.encoding = THREE.sRGBEncoding; + } + + this._target.traverse(c => { + let materials = c.material; + if (!(c.material instanceof Array)) { + materials = [c.material]; + } + + for (let m of materials) { + if (m) { + if (texture) { + m.map = texture; + } + if (this._params.specular) { + m.specular = this._params.specular; + } + if (this._params.emissive) { + m.emissive = this._params.emissive; + } + } + } + if (this._params.receiveShadow != undefined) { + c.receiveShadow = this._params.receiveShadow; + } + if (this._params.castShadow != undefined) { + c.castShadow = this._params.castShadow; + } + if (this._params.visible != undefined) { + c.visible = this._params.visible; + } + }); + + if (Array.isArray(animations) && animations.length > 0) { + setTimeout(() => { + this._mixer = new THREE.AnimationMixer(this._target); + const clip = animations[0]; + const action = this._mixer.clipAction(clip); + + action.play(); + }); + } + + this._parent._mesh = this._target; + this.Broadcast({ + topic: 'load.character', + model: this._target, + }); + } + + _LoadGLB() { + const loader = new GLTFLoader(); + loader.setPath(this._params.resourcePath); + loader.load(this._params.resourceName, (glb) => { + this._OnLoaded(glb.scene, glb.animations); + }); + } + + _LoadFBX() { + const loader = new FBXLoader(); + loader.setPath(this._params.resourcePath); + loader.load(this._params.resourceName, (fbx) => { + loader.load(this._params.resourceAnimation, (a) => { + this._OnLoaded(fbx, a.animations); + }); + }); + } + + Update(timeInSeconds) { + if (this._mixer) { + this._mixer.update(timeInSeconds); + } + } + } + + return { + StaticModelComponent: StaticModelComponent, + AnimatedModelComponent: AnimatedModelComponent, + }; + +})(); diff --git a/src/health-bar.js b/src/health-bar.js index 62ca31d..e665005 100644 --- a/src/health-bar.js +++ b/src/health-bar.js @@ -1,4 +1,4 @@ -import * as THREE from 'https://cdn.jsdelivr.net/npm/three@0.118.1/build/three.module.js'; +import * as THREE from 'three'; import {entity} from './entity.js'; import {math} from './math.js'; @@ -6,7 +6,7 @@ import {math} from './math.js'; export const health_bar = (() => { - const _VS = `#version 300 es + const _VS = ` varying vec2 vUV; void main() { @@ -16,7 +16,7 @@ void main() { } `; - const _PS = `#version 300 es + const _PS = ` uniform vec3 colour; uniform float health; @@ -54,6 +54,7 @@ class HealthBar extends entity.Component { depthTest: false, depthWrite: false, side: THREE.DoubleSide, + glslVersion: THREE.GLSL3, }); this._geometry = new THREE.BufferGeometry(); @@ -75,7 +76,7 @@ class HealthBar extends entity.Component { _OnHealth(msg) { const healthPercent = (msg.health / msg.maxHealth); - + this._realHealth = healthPercent; } @@ -134,4 +135,4 @@ class HealthBar extends entity.Component { return { HealthBar: HealthBar, }; -})(); \ No newline at end of file +})(); diff --git a/src/level-up-component.js b/src/level-up-component.js index c3f8b4e..1bd4d0f 100644 --- a/src/level-up-component.js +++ b/src/level-up-component.js @@ -1,4 +1,4 @@ -import * as THREE from 'https://cdn.jsdelivr.net/npm/three@0.118.1/build/three.module.js'; +import * as THREE from 'three'; import {particle_system} from "./particle-system.js"; import {entity} from "./entity.js"; @@ -35,11 +35,11 @@ export const level_up_component = (() => { this._particles._alphaSpline.AddPoint(0.1, 1.0); this._particles._alphaSpline.AddPoint(0.7, 1.0); this._particles._alphaSpline.AddPoint(1.0, 0.0); - + this._particles._colourSpline.AddPoint(0.0, new THREE.Color(0x00FF00)); this._particles._colourSpline.AddPoint(0.5, new THREE.Color(0x40C040)); this._particles._colourSpline.AddPoint(1.0, new THREE.Color(0xFF4040)); - + this._particles._sizeSpline.AddPoint(0.0, 0.05); this._particles._sizeSpline.AddPoint(0.5, 0.25); this._particles._sizeSpline.AddPoint(1.0, 0.0); @@ -48,7 +48,7 @@ export const level_up_component = (() => { InitComponent() { this._particles.AddParticles(this._parent._position, 300); } - + Update(timeElapsed) { this._particles.Step(timeElapsed); if (this._particles._particles.length == 0) { @@ -56,9 +56,9 @@ export const level_up_component = (() => { } } } - + return { LevelUpComponent: LevelUpComponent, LevelUpComponentSpawner: LevelUpComponentSpawner, }; -})(); \ No newline at end of file +})(); diff --git a/src/main.js b/src/main.js index a129afb..c3f730c 100644 --- a/src/main.js +++ b/src/main.js @@ -1,427 +1,426 @@ -import * as THREE from 'https://cdn.jsdelivr.net/npm/three@0.118.1/build/three.module.js'; - -import {third_person_camera} from './third-person-camera.js'; -import {entity_manager} from './entity-manager.js'; -import {player_entity} from './player-entity.js' -import {entity} from './entity.js'; -import {gltf_component} from './gltf-component.js'; -import {health_component} from './health-component.js'; -import {player_input} from './player-input.js'; -import {npc_entity} from './npc-entity.js'; -import {math} from './math.js'; -import {spatial_hash_grid} from './spatial-hash-grid.js'; -import {ui_controller} from './ui-controller.js'; -import {health_bar} from './health-bar.js'; -import {level_up_component} from './level-up-component.js'; -import {quest_component} from './quest-component.js'; -import {spatial_grid_controller} from './spatial-grid-controller.js'; -import {inventory_controller} from './inventory-controller.js'; -import {equip_weapon_component} from './equip-weapon-component.js'; -import {attack_controller} from './attacker-controller.js'; - - -const _VS = ` -varying vec3 vWorldPosition; - -void main() { - vec4 worldPosition = modelMatrix * vec4( position, 1.0 ); - vWorldPosition = worldPosition.xyz; - - gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 ); -}`; - - -const _FS = ` -uniform vec3 topColor; -uniform vec3 bottomColor; -uniform float offset; -uniform float exponent; - -varying vec3 vWorldPosition; - -void main() { - float h = normalize( vWorldPosition + offset ).y; - gl_FragColor = vec4( mix( bottomColor, topColor, max( pow( max( h , 0.0), exponent ), 0.0 ) ), 1.0 ); -}`; - - - -class HackNSlashDemo { - constructor() { - this._Initialize(); - } - - _Initialize() { - this._threejs = new THREE.WebGLRenderer({ - antialias: true, - }); - this._threejs.outputEncoding = THREE.sRGBEncoding; - this._threejs.gammaFactor = 2.2; - this._threejs.shadowMap.enabled = true; - this._threejs.shadowMap.type = THREE.PCFSoftShadowMap; - this._threejs.setPixelRatio(window.devicePixelRatio); - this._threejs.setSize(window.innerWidth, window.innerHeight); - this._threejs.domElement.id = 'threejs'; - - document.getElementById('container').appendChild(this._threejs.domElement); - - window.addEventListener('resize', () => { - this._OnWindowResize(); - }, false); - - const fov = 60; - const aspect = 1920 / 1080; - const near = 1.0; - const far = 10000.0; - this._camera = new THREE.PerspectiveCamera(fov, aspect, near, far); - this._camera.position.set(25, 10, 25); - - this._scene = new THREE.Scene(); - this._scene.background = new THREE.Color(0xFFFFFF); - this._scene.fog = new THREE.FogExp2(0x89b2eb, 0.002); - - let light = new THREE.DirectionalLight(0xFFFFFF, 1.0); - light.position.set(-10, 500, 10); - light.target.position.set(0, 0, 0); - light.castShadow = true; - light.shadow.bias = -0.001; - light.shadow.mapSize.width = 4096; - light.shadow.mapSize.height = 4096; - light.shadow.camera.near = 0.1; - light.shadow.camera.far = 1000.0; - light.shadow.camera.left = 100; - light.shadow.camera.right = -100; - light.shadow.camera.top = 100; - light.shadow.camera.bottom = -100; - this._scene.add(light); - - this._sun = light; - - const plane = new THREE.Mesh( - new THREE.PlaneGeometry(5000, 5000, 10, 10), - new THREE.MeshStandardMaterial({ - color: 0x1e601c, - })); - plane.castShadow = false; - plane.receiveShadow = true; - plane.rotation.x = -Math.PI / 2; - this._scene.add(plane); - - this._entityManager = new entity_manager.EntityManager(); - this._grid = new spatial_hash_grid.SpatialHashGrid( - [[-1000, -1000], [1000, 1000]], [100, 100]); - - this._LoadControllers(); - this._LoadPlayer(); - this._LoadFoliage(); - this._LoadClouds(); - this._LoadSky(); - - this._previousRAF = null; - this._RAF(); - } - - _LoadControllers() { - const ui = new entity.Entity(); - ui.AddComponent(new ui_controller.UIController()); - this._entityManager.Add(ui, 'ui'); - } - - _LoadSky() { - const hemiLight = new THREE.HemisphereLight(0xFFFFFF, 0xFFFFFFF, 0.6); - hemiLight.color.setHSL(0.6, 1, 0.6); - hemiLight.groundColor.setHSL(0.095, 1, 0.75); - this._scene.add(hemiLight); - - const uniforms = { - "topColor": { value: new THREE.Color(0x0077ff) }, - "bottomColor": { value: new THREE.Color(0xffffff) }, - "offset": { value: 33 }, - "exponent": { value: 0.6 } - }; - uniforms["topColor"].value.copy(hemiLight.color); - - this._scene.fog.color.copy(uniforms["bottomColor"].value); - - const skyGeo = new THREE.SphereBufferGeometry(1000, 32, 15); - const skyMat = new THREE.ShaderMaterial({ - uniforms: uniforms, - vertexShader: _VS, - fragmentShader: _FS, - side: THREE.BackSide - }); - - const sky = new THREE.Mesh(skyGeo, skyMat); - this._scene.add(sky); - } - - _LoadClouds() { - for (let i = 0; i < 20; ++i) { - const index = math.rand_int(1, 3); - const pos = new THREE.Vector3( - (Math.random() * 2.0 - 1.0) * 500, - 100, - (Math.random() * 2.0 - 1.0) * 500); - - const e = new entity.Entity(); - e.AddComponent(new gltf_component.StaticModelComponent({ - scene: this._scene, - resourcePath: './resources/nature2/GLTF/', - resourceName: 'Cloud' + index + '.glb', - position: pos, - scale: Math.random() * 5 + 10, - emissive: new THREE.Color(0x808080), - })); - e.SetPosition(pos); - this._entityManager.Add(e); - e.SetActive(false); - } - } - - _LoadFoliage() { - for (let i = 0; i < 100; ++i) { - const names = [ - 'CommonTree_Dead', 'CommonTree', - 'BirchTree', 'BirchTree_Dead', - 'Willow', 'Willow_Dead', - 'PineTree', - ]; - const name = names[math.rand_int(0, names.length - 1)]; - const index = math.rand_int(1, 5); - - const pos = new THREE.Vector3( - (Math.random() * 2.0 - 1.0) * 500, - 0, - (Math.random() * 2.0 - 1.0) * 500); - - const e = new entity.Entity(); - e.AddComponent(new gltf_component.StaticModelComponent({ - scene: this._scene, - resourcePath: './resources/nature/FBX/', - resourceName: name + '_' + index + '.fbx', - scale: 0.25, - emissive: new THREE.Color(0x000000), - specular: new THREE.Color(0x000000), - receiveShadow: true, - castShadow: true, - })); - e.AddComponent( - new spatial_grid_controller.SpatialGridController({grid: this._grid})); - e.SetPosition(pos); - this._entityManager.Add(e); - e.SetActive(false); - } - } - - _LoadPlayer() { - const params = { - camera: this._camera, - scene: this._scene, - }; - - const levelUpSpawner = new entity.Entity(); - levelUpSpawner.AddComponent(new level_up_component.LevelUpComponentSpawner({ - camera: this._camera, - scene: this._scene, - })); - this._entityManager.Add(levelUpSpawner, 'level-up-spawner'); - - const axe = new entity.Entity(); - axe.AddComponent(new inventory_controller.InventoryItem({ - type: 'weapon', - damage: 3, - renderParams: { - name: 'Axe', - scale: 0.25, - icon: 'war-axe-64.png', - }, - })); - this._entityManager.Add(axe); - - const sword = new entity.Entity(); - sword.AddComponent(new inventory_controller.InventoryItem({ - type: 'weapon', - damage: 3, - renderParams: { - name: 'Sword', - scale: 0.25, - icon: 'pointy-sword-64.png', - }, - })); - this._entityManager.Add(sword); - - const girl = new entity.Entity(); - girl.AddComponent(new gltf_component.AnimatedModelComponent({ - scene: this._scene, - resourcePath: './resources/girl/', - resourceName: 'peasant_girl.fbx', - resourceAnimation: 'Standing Idle.fbx', - scale: 0.035, - receiveShadow: true, - castShadow: true, - })); - girl.AddComponent(new spatial_grid_controller.SpatialGridController({ - grid: this._grid, - })); - girl.AddComponent(new player_input.PickableComponent()); - girl.AddComponent(new quest_component.QuestComponent()); - girl.SetPosition(new THREE.Vector3(30, 0, 0)); - this._entityManager.Add(girl); - - const player = new entity.Entity(); - player.AddComponent(new player_input.BasicCharacterControllerInput(params)); - player.AddComponent(new player_entity.BasicCharacterController(params)); - player.AddComponent( - new equip_weapon_component.EquipWeapon({anchor: 'RightHandIndex1'})); - player.AddComponent(new inventory_controller.InventoryController(params)); - player.AddComponent(new health_component.HealthComponent({ - updateUI: true, - health: 100, - maxHealth: 100, - strength: 50, - wisdomness: 5, - benchpress: 20, - curl: 100, - experience: 0, - level: 1, - })); - player.AddComponent( - new spatial_grid_controller.SpatialGridController({grid: this._grid})); - player.AddComponent(new attack_controller.AttackController({timing: 0.7})); - this._entityManager.Add(player, 'player'); - - player.Broadcast({ - topic: 'inventory.add', - value: axe.Name, - added: false, - }); - - player.Broadcast({ - topic: 'inventory.add', - value: sword.Name, - added: false, - }); - - player.Broadcast({ - topic: 'inventory.equip', - value: sword.Name, - added: false, - }); - - const camera = new entity.Entity(); - camera.AddComponent( - new third_person_camera.ThirdPersonCamera({ - camera: this._camera, - target: this._entityManager.Get('player')})); - this._entityManager.Add(camera, 'player-camera'); - - for (let i = 0; i < 50; ++i) { - const monsters = [ - { - resourceName: 'Ghost.fbx', - resourceTexture: 'Ghost_Texture.png', - }, - { - resourceName: 'Alien.fbx', - resourceTexture: 'Alien_Texture.png', - }, - { - resourceName: 'Skull.fbx', - resourceTexture: 'Skull_Texture.png', - }, - { - resourceName: 'GreenDemon.fbx', - resourceTexture: 'GreenDemon_Texture.png', - }, - { - resourceName: 'Cyclops.fbx', - resourceTexture: 'Cyclops_Texture.png', - }, - { - resourceName: 'Cactus.fbx', - resourceTexture: 'Cactus_Texture.png', - }, - ]; - const m = monsters[math.rand_int(0, monsters.length - 1)]; - - const npc = new entity.Entity(); - npc.AddComponent(new npc_entity.NPCController({ - camera: this._camera, - scene: this._scene, - resourceName: m.resourceName, - resourceTexture: m.resourceTexture, - })); - npc.AddComponent( - new health_component.HealthComponent({ - health: 50, - maxHealth: 50, - strength: 2, - wisdomness: 2, - benchpress: 3, - curl: 1, - experience: 0, - level: 1, - camera: this._camera, - scene: this._scene, - })); - npc.AddComponent( - new spatial_grid_controller.SpatialGridController({grid: this._grid})); - npc.AddComponent(new health_bar.HealthBar({ - parent: this._scene, - camera: this._camera, - })); - npc.AddComponent(new attack_controller.AttackController({timing: 0.35})); - npc.SetPosition(new THREE.Vector3( - (Math.random() * 2 - 1) * 500, - 0, - (Math.random() * 2 - 1) * 500)); - this._entityManager.Add(npc); - } - } - - _OnWindowResize() { - this._camera.aspect = window.innerWidth / window.innerHeight; - this._camera.updateProjectionMatrix(); - this._threejs.setSize(window.innerWidth, window.innerHeight); - } - - _UpdateSun() { - const player = this._entityManager.Get('player'); - const pos = player._position; - - this._sun.position.copy(pos); - this._sun.position.add(new THREE.Vector3(-10, 500, -10)); - this._sun.target.position.copy(pos); - this._sun.updateMatrixWorld(); - this._sun.target.updateMatrixWorld(); - } - - _RAF() { - requestAnimationFrame((t) => { - if (this._previousRAF === null) { - this._previousRAF = t; - } - - this._RAF(); - - this._threejs.render(this._scene, this._camera); - this._Step(t - this._previousRAF); - this._previousRAF = t; - }); - } - - _Step(timeElapsed) { - const timeElapsedS = Math.min(1.0 / 30.0, timeElapsed * 0.001); - - this._UpdateSun(); - - this._entityManager.Update(timeElapsedS); - } -} - - -let _APP = null; - -window.addEventListener('DOMContentLoaded', () => { - _APP = new HackNSlashDemo(); -}); +import * as THREE from 'three'; +//import * as THREE from 'https://cdn.jsdelivr.net/npm/three @0.118.1/build/three.module.js'; + +import { third_person_camera } from './third-person-camera.js'; +import { entity_manager } from './entity-manager.js'; +import { player_entity } from './player-entity.js'; +import { entity } from './entity.js'; +import { gltf_component } from './gltf-component.js'; +import { health_component } from './health-component.js'; +import { player_input } from './player-input.js'; +import { npc_entity } from './npc-entity.js'; +import { math } from './math.js'; +import { spatial_hash_grid } from './spatial-hash-grid.js'; +import { ui_controller } from './ui-controller.js'; +import { health_bar } from './health-bar.js'; +import { level_up_component } from './level-up-component.js'; +import { quest_component } from './quest-component.js'; +import { spatial_grid_controller } from './spatial-grid-controller.js'; +import { inventory_controller } from './inventory-controller.js'; +import { equip_weapon_component } from './equip-weapon-component.js'; +import { attack_controller } from './attacker-controller.js'; + +const _VS = ` +varying vec3 vWorldPosition; + +void main() { + vec4 worldPosition = modelMatrix * vec4( position, 1.0 ); + vWorldPosition = worldPosition.xyz; + + gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 ); +}`; + +const _FS = ` +uniform vec3 topColor; +uniform vec3 bottomColor; +uniform float offset; +uniform float exponent; + +varying vec3 vWorldPosition; + +void main() { + float h = normalize( vWorldPosition + offset ).y; + gl_FragColor = vec4( mix( bottomColor, topColor, max( pow( max( h , 0.0), exponent ), 0.0 ) ), 1.0 ); +}`; + +class HackNSlashDemo { + constructor() { + this._Initialize(); + } + + _Initialize() { + this._threejs = new THREE.WebGLRenderer({ + antialias: true, + }); + this._threejs.outputEncoding = THREE.sRGBEncoding; + // THREE.WebGLRenderer: .gammaFactor has been removed + // this._threejs.gammaFactor = 2.2; + this._threejs.colorSpace = THREE.sRGBColorSpace; + this._threejs.shadowMap.enabled = true; + this._threejs.shadowMap.type = THREE.PCFSoftShadowMap; + this._threejs.setPixelRatio(window.devicePixelRatio); + this._threejs.setSize(window.innerWidth, window.innerHeight); + this._threejs.domElement.id = 'threejs'; + + document.getElementById('container').appendChild(this._threejs.domElement); + + window.addEventListener('resize', () => { + this._OnWindowResize(); + }, false); + + const fov = 60; + const aspect = 1920 / 1080; + const near = 1.0; + const far = 10000.0; + this._camera = new THREE.PerspectiveCamera(fov, aspect, near, far); + this._camera.position.set(25, 10, 25); + + this._scene = new THREE.Scene(); + this._scene.background = new THREE.Color(0xFFFFFF); + this._scene.fog = new THREE.FogExp2(0x89b2eb, 0.002); + + let light = new THREE.DirectionalLight(0xFFFFFF, 1.0); + light.position.set(-10, 500, 10); + light.target.position.set(0, 0, 0); + light.castShadow = true; + light.shadow.bias = -0.001; + light.shadow.mapSize.width = 4096; + light.shadow.mapSize.height = 4096; + light.shadow.camera.near = 0.1; + light.shadow.camera.far = 1000.0; + light.shadow.camera.left = 100; + light.shadow.camera.right = -100; + light.shadow.camera.top = 100; + light.shadow.camera.bottom = -100; + this._scene.add(light); + + this._sun = light; + + const plane = new THREE.Mesh( + new THREE.PlaneGeometry(5000, 5000, 10, 10), + new THREE.MeshStandardMaterial({ + color: 0x1e601c, + })); + plane.castShadow = false; + plane.receiveShadow = true; + plane.rotation.x = -Math.PI / 2; + this._scene.add(plane); + + this._entityManager = new entity_manager.EntityManager(); + this._grid = new spatial_hash_grid.SpatialHashGrid( + [[-1000, -1000], [1000, 1000]], [100, 100]); + + this._LoadControllers(); + this._LoadPlayer(); + this._LoadFoliage(); + this._LoadClouds(); + this._LoadSky(); + + this._previousRAF = null; + this._RAF(); + } + + _LoadControllers() { + const ui = new entity.Entity(); + ui.AddComponent(new ui_controller.UIController()); + this._entityManager.Add(ui, 'ui'); + } + + _LoadSky() { + const hemiLight = new THREE.HemisphereLight(0xFFFFFF, 0xFFFFFFF, 0.6); + hemiLight.color.setHSL(0.6, 1, 0.6); + hemiLight.groundColor.setHSL(0.095, 1, 0.75); + this._scene.add(hemiLight); + + const uniforms = { + 'topColor': {value: new THREE.Color(0x0077ff)}, + 'bottomColor': {value: new THREE.Color(0xffffff)}, + 'offset': {value: 33}, + 'exponent': {value: 0.6}, + }; + uniforms['topColor'].value.copy(hemiLight.color); + + this._scene.fog.color.copy(uniforms['bottomColor'].value); + + const skyGeo = new THREE.SphereGeometry(1000, 32, 15); + const skyMat = new THREE.ShaderMaterial({ + uniforms: uniforms, + vertexShader: _VS, + fragmentShader: _FS, + side: THREE.BackSide, + }); + + const sky = new THREE.Mesh(skyGeo, skyMat); + this._scene.add(sky); + } + + _LoadClouds() { + for (let i = 0; i < 20; ++i) { + const index = math.rand_int(1, 3); + const pos = new THREE.Vector3( + (Math.random() * 2.0 - 1.0) * 500, + 100, + (Math.random() * 2.0 - 1.0) * 500); + + const e = new entity.Entity(); + e.AddComponent(new gltf_component.StaticModelComponent({ + scene: this._scene, + resourcePath: './resources/nature2/GLTF/', + resourceName: 'Cloud' + index + '.glb', + position: pos, + scale: Math.random() * 5 + 10, + emissive: new THREE.Color(0x808080), + })); + e.SetPosition(pos); + this._entityManager.Add(e); + e.SetActive(false); + } + } + + _LoadFoliage() { + for (let i = 0; i < 100; ++i) { + const names = [ + 'CommonTree_Dead', 'CommonTree', + 'BirchTree', 'BirchTree_Dead', + 'Willow', 'Willow_Dead', + 'PineTree', + ]; + const name = names[math.rand_int(0, names.length - 1)]; + const index = math.rand_int(1, 5); + + const pos = new THREE.Vector3( + (Math.random() * 2.0 - 1.0) * 500, + 0, + (Math.random() * 2.0 - 1.0) * 500); + + const e = new entity.Entity(); + e.AddComponent(new gltf_component.StaticModelComponent({ + scene: this._scene, + resourcePath: './resources/nature/FBX/', + resourceName: name + '_' + index + '.fbx', + scale: 0.25, + emissive: new THREE.Color(0x000000), + specular: new THREE.Color(0x000000), + receiveShadow: true, + castShadow: true, + })); + e.AddComponent( + new spatial_grid_controller.SpatialGridController({grid: this._grid})); + e.SetPosition(pos); + this._entityManager.Add(e); + e.SetActive(false); + } + } + + _LoadPlayer() { + const params = { + camera: this._camera, + scene: this._scene, + }; + + const levelUpSpawner = new entity.Entity(); + levelUpSpawner.AddComponent(new level_up_component.LevelUpComponentSpawner({ + camera: this._camera, + scene: this._scene, + })); + this._entityManager.Add(levelUpSpawner, 'level-up-spawner'); + + const axe = new entity.Entity(); + axe.AddComponent(new inventory_controller.InventoryItem({ + type: 'weapon', + damage: 3, + renderParams: { + name: 'Axe', + scale: 0.25, + icon: 'war-axe-64.png', + }, + })); + this._entityManager.Add(axe); + + const sword = new entity.Entity(); + sword.AddComponent(new inventory_controller.InventoryItem({ + type: 'weapon', + damage: 3, + renderParams: { + name: 'Sword', + scale: 0.25, + icon: 'pointy-sword-64.png', + }, + })); + this._entityManager.Add(sword); + + const girl = new entity.Entity(); + girl.AddComponent(new gltf_component.AnimatedModelComponent({ + scene: this._scene, + resourcePath: './resources/girl/', + resourceName: 'peasant_girl.fbx', + resourceAnimation: 'Standing Idle.fbx', + scale: 0.035, + receiveShadow: true, + castShadow: true, + })); + girl.AddComponent(new spatial_grid_controller.SpatialGridController({ + grid: this._grid, + })); + girl.AddComponent(new player_input.PickableComponent()); + girl.AddComponent(new quest_component.QuestComponent()); + girl.SetPosition(new THREE.Vector3(30, 0, 0)); + this._entityManager.Add(girl); + + const player = new entity.Entity(); + player.AddComponent(new player_input.BasicCharacterControllerInput(params)); + player.AddComponent(new player_entity.BasicCharacterController(params)); + player.AddComponent( + new equip_weapon_component.EquipWeapon({anchor: 'RightHandIndex1'})); + player.AddComponent(new inventory_controller.InventoryController(params)); + player.AddComponent(new health_component.HealthComponent({ + updateUI: true, + health: 100, + maxHealth: 100, + strength: 50, + wisdomness: 5, + benchpress: 20, + curl: 100, + experience: 0, + level: 1, + })); + player.AddComponent( + new spatial_grid_controller.SpatialGridController({grid: this._grid})); + player.AddComponent(new attack_controller.AttackController({timing: 0.7})); + this._entityManager.Add(player, 'player'); + + player.Broadcast({ + topic: 'inventory.add', + value: axe.Name, + added: false, + }); + + player.Broadcast({ + topic: 'inventory.add', + value: sword.Name, + added: false, + }); + + player.Broadcast({ + topic: 'inventory.equip', + value: sword.Name, + added: false, + }); + + const camera = new entity.Entity(); + camera.AddComponent( + new third_person_camera.ThirdPersonCamera({ + camera: this._camera, + target: this._entityManager.Get('player'), + })); + this._entityManager.Add(camera, 'player-camera'); + + for (let i = 0; i < 50; ++i) { + const monsters = [ + { + resourceName: 'Ghost.fbx', + resourceTexture: 'Ghost_Texture.png', + }, + { + resourceName: 'Alien.fbx', + resourceTexture: 'Alien_Texture.png', + }, + { + resourceName: 'Skull.fbx', + resourceTexture: 'Skull_Texture.png', + }, + { + resourceName: 'GreenDemon.fbx', + resourceTexture: 'GreenDemon_Texture.png', + }, + { + resourceName: 'Cyclops.fbx', + resourceTexture: 'Cyclops_Texture.png', + }, + { + resourceName: 'Cactus.fbx', + resourceTexture: 'Cactus_Texture.png', + }, + ]; + const m = monsters[math.rand_int(0, monsters.length - 1)]; + + const npc = new entity.Entity(); + npc.AddComponent(new npc_entity.NPCController({ + camera: this._camera, + scene: this._scene, + resourceName: m.resourceName, + resourceTexture: m.resourceTexture, + })); + npc.AddComponent( + new health_component.HealthComponent({ + health: 50, + maxHealth: 50, + strength: 2, + wisdomness: 2, + benchpress: 3, + curl: 1, + experience: 0, + level: 1, + camera: this._camera, + scene: this._scene, + })); + npc.AddComponent( + new spatial_grid_controller.SpatialGridController({grid: this._grid})); + npc.AddComponent(new health_bar.HealthBar({ + parent: this._scene, + camera: this._camera, + })); + npc.AddComponent(new attack_controller.AttackController({timing: 0.35})); + npc.SetPosition(new THREE.Vector3( + (Math.random() * 2 - 1) * 500, + 0, + (Math.random() * 2 - 1) * 500)); + this._entityManager.Add(npc); + } + } + + _OnWindowResize() { + this._camera.aspect = window.innerWidth / window.innerHeight; + this._camera.updateProjectionMatrix(); + this._threejs.setSize(window.innerWidth, window.innerHeight); + } + + _UpdateSun() { + const player = this._entityManager.Get('player'); + const pos = player._position; + + this._sun.position.copy(pos); + this._sun.position.add(new THREE.Vector3(-10, 500, -10)); + this._sun.target.position.copy(pos); + this._sun.updateMatrixWorld(); + this._sun.target.updateMatrixWorld(); + } + + _RAF() { + requestAnimationFrame((t) => { + if (this._previousRAF === null) { + this._previousRAF = t; + } + + this._RAF(); + + this._threejs.render(this._scene, this._camera); + this._Step(t - this._previousRAF); + this._previousRAF = t; + }); + } + + _Step(timeElapsed) { + const timeElapsedS = Math.min(1.0 / 30.0, timeElapsed * 0.001); + + this._UpdateSun(); + + this._entityManager.Update(timeElapsedS); + } +} + +let _APP = null; + +window.addEventListener('DOMContentLoaded', () => { + _APP = new HackNSlashDemo(); +}); diff --git a/src/npc-entity.js b/src/npc-entity.js index cdc25c1..c70a4d8 100644 --- a/src/npc-entity.js +++ b/src/npc-entity.js @@ -1,6 +1,6 @@ -import * as THREE from 'https://cdn.jsdelivr.net/npm/three@0.118/build/three.module.js'; +import * as THREE from 'three'; -import {FBXLoader} from 'https://cdn.jsdelivr.net/npm/three@0.118.1/examples/jsm/loaders/FBXLoader.js'; +import {FBXLoader} from 'three/FBXLoader'; import {finite_state_machine} from './finite-state-machine.js'; import {entity} from './entity.js'; @@ -9,10 +9,10 @@ import {player_state} from './player-state.js'; export const npc_entity = (() => { - + class AIInput { constructor() { - this._Init(); + this._Init(); } _Init() { @@ -224,14 +224,14 @@ export const npc_entity = (() => { frameDecceleration.multiplyScalar(timeInSeconds); frameDecceleration.z = Math.sign(frameDecceleration.z) * Math.min( Math.abs(frameDecceleration.z), Math.abs(velocity.z)); - + velocity.add(frameDecceleration); const controlObject = this._target; const _Q = new THREE.Quaternion(); const _A = new THREE.Vector3(); const _R = controlObject.quaternion.clone(); - + this._input._keys.forward = false; const acc = this._acceleration; @@ -248,23 +248,23 @@ export const npc_entity = (() => { dirToPlayer, new THREE.Vector3(0, 1, 0)); _R.setFromRotationMatrix(m); - + controlObject.quaternion.copy(_R); - + const oldPosition = new THREE.Vector3(); oldPosition.copy(controlObject.position); - + const forward = new THREE.Vector3(0, 0, 1); forward.applyQuaternion(controlObject.quaternion); forward.normalize(); - + const sideways = new THREE.Vector3(1, 0, 0); sideways.applyQuaternion(controlObject.quaternion); sideways.normalize(); - + sideways.multiplyScalar(velocity.x * timeInSeconds); forward.multiplyScalar(velocity.z * timeInSeconds); - + const pos = controlObject.position.clone(); pos.add(forward); pos.add(sideways); @@ -278,7 +278,7 @@ export const npc_entity = (() => { controlObject.position.copy(pos); this._position.copy(pos); - + this._parent.SetPosition(this._position); this._parent.SetQuaternion(this._target.quaternion); } @@ -303,7 +303,7 @@ export const npc_entity = (() => { time: this._stateMachine._currentState._action.time, }); } - + if (this._mixer) { this._mixer.update(timeInSeconds); } @@ -314,4 +314,4 @@ export const npc_entity = (() => { NPCController: NPCController, }; -})(); \ No newline at end of file +})(); diff --git a/src/particle-system.js b/src/particle-system.js index c91ea69..ee6833b 100644 --- a/src/particle-system.js +++ b/src/particle-system.js @@ -1,4 +1,4 @@ -import * as THREE from 'https://cdn.jsdelivr.net/npm/three@0.118.1/build/three.module.js'; +import * as THREE from 'three'; export const particle_system = (() => { @@ -21,7 +21,7 @@ export const particle_system = (() => { vAngle = vec2(cos(angle), sin(angle)); vColour = colour; }`; - + const _FS = ` uniform sampler2D diffuseTexture; @@ -33,42 +33,42 @@ export const particle_system = (() => { vec2 coords = (gl_PointCoord - 0.5) * mat2(vAngle.x, vAngle.y, -vAngle.y, vAngle.x) + 0.5; gl_FragColor = texture2D(diffuseTexture, coords) * vColour; }`; - - + + class LinearSpline { constructor(lerp) { this._points = []; this._lerp = lerp; } - + AddPoint(t, d) { this._points.push([t, d]); } - + Get(t) { let p1 = 0; - + for (let i = 0; i < this._points.length; i++) { if (this._points[i][0] >= t) { break; } p1 = i; } - + const p2 = Math.min(this._points.length - 1, p1 + 1); - + if (p1 == p2) { return this._points[p1][1]; } - + return this._lerp( (t - this._points[p1][0]) / ( this._points[p2][0] - this._points[p1][0]), this._points[p1][1], this._points[p2][1]); } } - - + + class ParticleSystem { constructor(params) { const uniforms = { @@ -79,7 +79,7 @@ export const particle_system = (() => { value: window.innerHeight / (2.0 * Math.tan(0.5 * 60.0 * Math.PI / 180.0)) } }; - + this._material = new THREE.ShaderMaterial({ uniforms: uniforms, vertexShader: _VS, @@ -90,36 +90,36 @@ export const particle_system = (() => { transparent: true, vertexColors: true }); - + this._camera = params.camera; this._particles = []; - + this._geometry = new THREE.BufferGeometry(); this._geometry.setAttribute('position', new THREE.Float32BufferAttribute([], 3)); this._geometry.setAttribute('size', new THREE.Float32BufferAttribute([], 1)); this._geometry.setAttribute('colour', new THREE.Float32BufferAttribute([], 4)); this._geometry.setAttribute('angle', new THREE.Float32BufferAttribute([], 1)); - + this._points = new THREE.Points(this._geometry, this._material); - + params.parent.add(this._points); - + this._alphaSpline = new LinearSpline((t, a, b) => { return a + t * (b - a); }); - + this._colourSpline = new LinearSpline((t, a, b) => { const c = a.clone(); return c.lerp(b, t); }); - + this._sizeSpline = new LinearSpline((t, a, b) => { return a + t * (b - a); }); - + this._UpdateGeometry(); } - + AddParticles(origin, n) { for (let i = 0; i < n; i++) { const life = (Math.random() * 0.75 + 0.25) * 3.0; @@ -141,20 +141,20 @@ export const particle_system = (() => { }); } } - + _UpdateGeometry() { const positions = []; const sizes = []; const colours = []; const angles = []; - + for (let p of this._particles) { positions.push(p.position.x, p.position.y, p.position.z); colours.push(p.colour.r, p.colour.g, p.colour.b, p.alpha); sizes.push(p.currentSize); angles.push(p.rotation); } - + this._geometry.setAttribute( 'position', new THREE.Float32BufferAttribute(positions, 3)); this._geometry.setAttribute( @@ -163,32 +163,32 @@ export const particle_system = (() => { 'colour', new THREE.Float32BufferAttribute(colours, 4)); this._geometry.setAttribute( 'angle', new THREE.Float32BufferAttribute(angles, 1)); - + this._geometry.attributes.position.needsUpdate = true; this._geometry.attributes.size.needsUpdate = true; this._geometry.attributes.colour.needsUpdate = true; this._geometry.attributes.angle.needsUpdate = true; } - + _UpdateParticles(timeElapsed) { for (let p of this._particles) { p.life -= timeElapsed; } - + this._particles = this._particles.filter(p => { return p.life > 0.0; }); - + for (let p of this._particles) { const t = 1.0 - p.life / p.maxLife; - + p.rotation += timeElapsed * 0.5; p.alpha = this._alphaSpline.Get(t); p.currentSize = p.size * this._sizeSpline.Get(t); p.colour.copy(this._colourSpline.Get(t)); - + p.position.add(p.velocity.clone().multiplyScalar(timeElapsed)); - + const drag = p.velocity.clone(); drag.multiplyScalar(timeElapsed * 2.0); drag.x = Math.sign(p.velocity.x) * Math.min(Math.abs(drag.x), Math.abs(p.velocity.x)); @@ -196,23 +196,23 @@ export const particle_system = (() => { drag.z = Math.sign(p.velocity.z) * Math.min(Math.abs(drag.z), Math.abs(p.velocity.z)); p.velocity.sub(drag); } - + this._particles.sort((a, b) => { const d1 = this._camera.position.distanceTo(a.position); const d2 = this._camera.position.distanceTo(b.position); - + if (d1 > d2) { return -1; } - + if (d1 < d2) { return 1; } - + return 0; }); } - + Step(timeElapsed) { this._UpdateParticles(timeElapsed); this._UpdateGeometry(); @@ -222,4 +222,4 @@ export const particle_system = (() => { return { ParticleSystem: ParticleSystem, }; -})(); \ No newline at end of file +})(); diff --git a/src/player-entity.js b/src/player-entity.js index bb69c52..b017174 100644 --- a/src/player-entity.js +++ b/src/player-entity.js @@ -1,6 +1,6 @@ -import * as THREE from 'https://cdn.jsdelivr.net/npm/three@0.118.1/build/three.module.js'; +import * as THREE from 'three'; -import {FBXLoader} from 'https://cdn.jsdelivr.net/npm/three@0.118.1/examples/jsm/loaders/FBXLoader.js'; +import {FBXLoader} from 'three/FBXLoader'; import {entity} from './entity.js'; import {finite_state_machine} from './finite-state-machine.js'; @@ -15,7 +15,7 @@ export const player_entity = (() => { this._proxy = proxy; this._Init(); } - + _Init() { this._AddState('idle', player_state.IdleState); this._AddState('walk', player_state.WalkState); @@ -24,12 +24,12 @@ export const player_entity = (() => { this._AddState('death', player_state.DeathState); } }; - + class BasicCharacterControllerProxy { constructor(animations) { this._animations = animations; } - + get animations() { return this._animations; } @@ -48,11 +48,11 @@ export const player_entity = (() => { this._acceleration = new THREE.Vector3(1, 0.125, 50.0); this._velocity = new THREE.Vector3(0, 0, 0); this._position = new THREE.Vector3(); - + this._animations = {}; this._stateMachine = new CharacterFSM( new BasicCharacterControllerProxy(this._animations)); - + this._LoadModels(); } @@ -71,7 +71,7 @@ export const player_entity = (() => { this._target = fbx; this._target.scale.setScalar(0.035); this._params.scene.add(this._target); - + this._bones = {}; for (let b of this._target.children[1].skeleton.bones) { @@ -97,7 +97,7 @@ export const player_entity = (() => { const _OnLoad = (animName, anim) => { const clip = anim.animations[0]; const action = this._mixer.clipAction(clip); - + this._animations[animName] = { clip: clip, action: action, @@ -108,7 +108,7 @@ export const player_entity = (() => { this._manager.onLoad = () => { this._stateMachine.SetState('idle'); }; - + const loader = new FBXLoader(this._manager); loader.setPath('./resources/guard/'); loader.load('Sword And Shield Idle.fbx', (a) => { _OnLoad('idle', a); }); @@ -171,7 +171,7 @@ export const player_entity = (() => { currentState.Name != 'idle') { return; } - + const velocity = this._velocity; const frameDecceleration = new THREE.Vector3( velocity.x * this._decceleration.x, @@ -181,19 +181,19 @@ export const player_entity = (() => { frameDecceleration.multiplyScalar(timeInSeconds); frameDecceleration.z = Math.sign(frameDecceleration.z) * Math.min( Math.abs(frameDecceleration.z), Math.abs(velocity.z)); - + velocity.add(frameDecceleration); - + const controlObject = this._target; const _Q = new THREE.Quaternion(); const _A = new THREE.Vector3(); const _R = controlObject.quaternion.clone(); - + const acc = this._acceleration.clone(); if (input._keys.shift) { acc.multiplyScalar(2.0); } - + if (input._keys.forward) { velocity.z += acc.z * timeInSeconds; } @@ -210,23 +210,23 @@ export const player_entity = (() => { _Q.setFromAxisAngle(_A, 4.0 * -Math.PI * timeInSeconds * this._acceleration.y); _R.multiply(_Q); } - + controlObject.quaternion.copy(_R); - + const oldPosition = new THREE.Vector3(); oldPosition.copy(controlObject.position); - + const forward = new THREE.Vector3(0, 0, 1); forward.applyQuaternion(controlObject.quaternion); forward.normalize(); - + const sideways = new THREE.Vector3(1, 0, 0); sideways.applyQuaternion(controlObject.quaternion); sideways.normalize(); - + sideways.multiplyScalar(velocity.x * timeInSeconds); forward.multiplyScalar(velocity.z * timeInSeconds); - + const pos = controlObject.position.clone(); pos.add(forward); pos.add(sideways); @@ -238,15 +238,15 @@ export const player_entity = (() => { controlObject.position.copy(pos); this._position.copy(pos); - + this._parent.SetPosition(this._position); this._parent.SetQuaternion(this._target.quaternion); } }; - + return { BasicCharacterControllerProxy: BasicCharacterControllerProxy, BasicCharacterController: BasicCharacterController, }; -})(); \ No newline at end of file +})(); diff --git a/src/player-input.js b/src/player-input.js index bd53b83..3b62759 100644 --- a/src/player-input.js +++ b/src/player-input.js @@ -1,4 +1,4 @@ -import * as THREE from 'https://cdn.jsdelivr.net/npm/three@0.118/build/three.module.js'; +import * as THREE from 'three'; import {entity} from "./entity.js"; @@ -20,7 +20,7 @@ export const player_input = (() => { this._params = params; this._Init(); } - + _Init() { this._keys = { forward: false, @@ -35,7 +35,7 @@ export const player_input = (() => { document.addEventListener('keyup', (e) => this._onKeyUp(e), false); document.addEventListener('mouseup', (e) => this._onMouseUp(e), false); } - + _onMouseUp(event) { const rect = document.getElementById('threejs').getBoundingClientRect(); const pos = { @@ -96,7 +96,7 @@ export const player_input = (() => { break; } } - + _onKeyUp(event) { switch(event.keyCode) { case 87: // w @@ -126,4 +126,4 @@ export const player_input = (() => { PickableComponent: PickableComponent, }; -})(); \ No newline at end of file +})(); diff --git a/src/player-state.js b/src/player-state.js index 9b3cbac..6a7abc7 100644 --- a/src/player-state.js +++ b/src/player-state.js @@ -1,4 +1,4 @@ -import * as THREE from 'https://cdn.jsdelivr.net/npm/three@0.118/build/three.module.js'; +import * as THREE from 'three'; export const player_state = (() => { @@ -7,7 +7,7 @@ export const player_state = (() => { constructor(parent) { this._parent = parent; } - + Enter() {} Exit() {} Update() {} @@ -16,21 +16,21 @@ export const player_state = (() => { class DeathState extends State { constructor(parent) { super(parent); - + this._action = null; } - + get Name() { return 'death'; } - + Enter(prevState) { this._action = this._parent._proxy._animations['death'].action; - + if (prevState) { const prevAction = this._parent._proxy._animations[prevState.Name].action; - - this._action.reset(); + + this._action.reset(); this._action.setLoop(THREE.LoopOnce, 1); this._action.clampWhenFinished = true; this._action.crossFadeFrom(prevAction, 0.2, true); @@ -39,38 +39,38 @@ export const player_state = (() => { this._action.play(); } } - + Exit() { } - + Update(_) { } }; - + class AttackState extends State { constructor(parent) { super(parent); - + this._action = null; - + this._FinishedCallback = () => { this._Finished(); } } - + get Name() { return 'attack'; } - + Enter(prevState) { this._action = this._parent._proxy._animations['attack'].action; const mixer = this._action.getMixer(); mixer.addEventListener('finished', this._FinishedCallback); - + if (prevState) { const prevAction = this._parent._proxy._animations[prevState.Name].action; - - this._action.reset(); + + this._action.reset(); this._action.setLoop(THREE.LoopOnce, 1); this._action.clampWhenFinished = true; this._action.crossFadeFrom(prevAction, 0.2, true); @@ -79,42 +79,42 @@ export const player_state = (() => { this._action.play(); } } - + _Finished() { this._Cleanup(); this._parent.SetState('idle'); } - + _Cleanup() { if (this._action) { this._action.getMixer().removeEventListener('finished', this._FinishedCallback); } } - + Exit() { this._Cleanup(); } - + Update(_) { } }; - + class WalkState extends State { constructor(parent) { super(parent); } - + get Name() { return 'walk'; } - + Enter(prevState) { const curAction = this._parent._proxy._animations['walk'].action; if (prevState) { const prevAction = this._parent._proxy._animations[prevState.Name].action; - + curAction.enabled = true; - + if (prevState.Name == 'run') { const ratio = curAction.getClip().duration / prevAction.getClip().duration; curAction.time = prevAction.time * ratio; @@ -123,17 +123,17 @@ export const player_state = (() => { curAction.setEffectiveTimeScale(1.0); curAction.setEffectiveWeight(1.0); } - + curAction.crossFadeFrom(prevAction, 0.1, true); curAction.play(); } else { curAction.play(); } } - + Exit() { } - + Update(timeElapsed, input) { if (input._keys.forward || input._keys.backward) { if (input._keys.shift) { @@ -141,28 +141,28 @@ export const player_state = (() => { } return; } - + this._parent.SetState('idle'); } }; - - + + class RunState extends State { constructor(parent) { super(parent); } - + get Name() { return 'run'; } - + Enter(prevState) { const curAction = this._parent._proxy._animations['run'].action; if (prevState) { const prevAction = this._parent._proxy._animations[prevState.Name].action; - + curAction.enabled = true; - + if (prevState.Name == 'walk') { const ratio = curAction.getClip().duration / prevAction.getClip().duration; curAction.time = prevAction.time * ratio; @@ -171,17 +171,17 @@ export const player_state = (() => { curAction.setEffectiveTimeScale(1.0); curAction.setEffectiveWeight(1.0); } - + curAction.crossFadeFrom(prevAction, 0.1, true); curAction.play(); } else { curAction.play(); } } - + Exit() { } - + Update(timeElapsed, input) { if (input._keys.forward || input._keys.backward) { if (!input._keys.shift) { @@ -189,21 +189,21 @@ export const player_state = (() => { } return; } - + this._parent.SetState('idle'); } }; - - + + class IdleState extends State { constructor(parent) { super(parent); } - + get Name() { return 'idle'; } - + Enter(prevState) { const idleAction = this._parent._proxy._animations['idle'].action; if (prevState) { @@ -218,10 +218,10 @@ export const player_state = (() => { idleAction.play(); } } - + Exit() { } - + Update(_, input) { if (input._keys.forward || input._keys.backward) { this._parent.SetState('walk'); @@ -240,4 +240,4 @@ export const player_state = (() => { DeathState: DeathState, }; -})(); \ No newline at end of file +})(); diff --git a/src/third-person-camera.js b/src/third-person-camera.js index d0d6317..0b3d83e 100644 --- a/src/third-person-camera.js +++ b/src/third-person-camera.js @@ -1,9 +1,9 @@ -import * as THREE from 'https://cdn.jsdelivr.net/npm/three@0.118/build/three.module.js'; +import * as THREE from 'three'; import {entity} from './entity.js'; export const third_person_camera = (() => { - + class ThirdPersonCamera extends entity.Component { constructor(params) { super(); @@ -49,4 +49,4 @@ export const third_person_camera = (() => { ThirdPersonCamera: ThirdPersonCamera }; -})(); \ No newline at end of file +})();