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 {gltf_component_alpha} from './gltf-component-alpha.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 );
}`;
var raycaster, mouse, camera, scene;
class HackNSlashDemo {
constructor() {
this._Initialize();
}
_Initialize() {
window.addEventListener('resize', () => {
this._OnWindowResize();
}, false);
const fov = 45;
const aspect = window.innerWidth / window.innerHeight;
const near = 1.0;
const far = 10000.0;
this._camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
this._camera.position.set(0, 0, 0);
this._scene = new THREE.Scene();
this._scene.background = new THREE.Color(0xFFFFFF);
this._scene.fog = new THREE.FogExp2(0x89b2eb, 0.002);
camera = this._camera;
scene = this._scene;
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;
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);
this._camera.aspect = window.innerWidth / window.innerHeight;
this._camera.updateProjectionMatrix();
this._threejs.setSize(window.innerWidth, window.innerHeight);
const plane = new THREE.Mesh(
new THREE.PlaneGeometry(5000, 5000, 10, 10),
new THREE.MeshStandardMaterial({
color: 0x000000,
}));
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]], [10, 10]);
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(0x131313, 0x131313, 0.6);
hemiLight.color.setHSL(0, 1, 0);
hemiLight.groundColor.setHSL(0, 0, 25);
this._scene.add(hemiLight);
const uniforms = {
"topColor": { value: new THREE.Color(0x131313) },
"bottomColor": { value: new THREE.Color(0x000000) },
"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);
// new model
const girl2 = new entity.Entity();
girl2.AddComponent(new gltf_component_alpha.StaticModelComponent({
scene: this._scene,
resourcePath: './resources/girl/',
resourceName: 'scene.gltf' ,
scale: 0.0135,
receiveShadow: true,
castShadow: true,
}));
girl2.AddComponent(new spatial_grid_controller.SpatialGridController({
grid: this._grid,
}));
girl2.AddComponent(new player_input.PickableComponent());
girl2.AddComponent(new quest_component.QuestComponent());
girl2.SetPosition(new THREE.Vector3(-30, 5.5, 0));
this._entityManager.Add(girl2);
$(document).on('click tap touchstart', function () {
event.preventDefault();
mouse = new THREE.Vector2();
mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
raycaster.setFromCamera(mouse, camera);
var intersects = raycaster.intersectObjects(scene.children, true);
console.log(intersects);
console.log('yes');
});
// new model
const girl3 = new entity.Entity();
girl3.AddComponent(new gltf_component.StaticModelComponent({
scene: this._scene,
resourcePath: './resources/girl/',
resourceName: 'scene.gltf' ,
scale: 0.0135,
receiveShadow: true,
castShadow: true,
}));
girl3.AddComponent(new spatial_grid_controller.SpatialGridController({
grid: this._grid,
}));
girl3.AddComponent(new player_input.PickableComponent());
girl3.AddComponent(new quest_component.QuestComponent());
girl3.SetPosition(new THREE.Vector3(0, 5.8, -30));
this._entityManager.Add(girl2);
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 < 8; ++i) {
const monsters = [
{
resourceName: 'npc3.fbx',
resourceTexture: 'file1-file4.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: 1.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();
});