123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128 |
- import * as THREE from 'https://cdn.jsdelivr.net/npm/[email protected]/build/three.module.js';
- import {OrbitControls} from 'https://cdn.jsdelivr.net/npm/[email protected]/examples/jsm/controls/OrbitControls.js';
- import {FBXLoader} from 'https://cdn.jsdelivr.net/npm/[email protected]/examples/jsm/loaders/FBXLoader.js';
- import 'https://cdn.jsdelivr.net/npm/[email protected]/dist/socket.io.js';
- const _CHARACTER_MODELS = {
- zombie: {
- base: 'mremireh_o_desbiens.fbx',
- path: './resources/characters/zombie/',
- animations: {
- idle: 'idle.fbx',
- walk: 'walk.fbx',
- run: 'run.fbx',
- dance: 'dance.fbx',
- },
- nameOffset: 25,
- },
- guard: {
- base: 'castle_guard_01.fbx',
- path: './resources/characters/guard/',
- animations: {
- idle: 'Sword And Shield Idle.fbx',
- walk: 'Sword And Shield Walk.fbx',
- run: 'Sword And Shield Run.fbx',
- dance: 'Macarena Dance.fbx',
- },
- nameOffset: 20,
- }
- }
- class FloatingName {
- constructor(params) {
- this.params_ = params;
- this.Init_();
- }
- Destroy() {
- this.element_ = null;
- }
- Init_() {
- const modelData = _CHARACTER_MODELS[this.params_.desc.character.class];
- this.element_ = document.createElement('canvas');
- this.context2d_ = this.element_.getContext('2d');
- this.context2d_.canvas.width = 256;
- this.context2d_.canvas.height = 128;
- this.context2d_.fillStyle = '#FFF';
- this.context2d_.font = "18pt Helvetica";
- this.context2d_.shadowOffsetX = 3;
- this.context2d_.shadowOffsetY = 3;
- this.context2d_.shadowColor = "rgba(0,0,0,0.3)";
- this.context2d_.shadowBlur = 4;
- this.context2d_.textAlign = 'center';
- this.context2d_.fillText(this.params_.desc.account.name, 128, 64);
- const map = new THREE.CanvasTexture(this.context2d_.canvas);
- this.sprite_ = new THREE.Sprite(
- new THREE.SpriteMaterial({map: map, color: 0xffffff}));
- this.sprite_.scale.set(20, 10, 1)
- this.sprite_.position.y += modelData.nameOffset;
- this.params_.parent.add(this.sprite_);
- }
- };
- class OurLoadingManager {
- constructor(loader) {
- this.loader_ = loader;
- this.files_ = new Set();
- this.onLoad = () => {};
- }
- load(file, cb) {
- this.files_.add(file);
- this.loader_.load(file, (result) => {
- this.files_.delete(file);
- cb(result);
- if (this.files_.size == 0) {
- this.onLoad();
- }
- });
- }
- };
- class BasicCharacterControllerProxy {
- constructor(animations) {
- this.animations_ = animations;
- }
- get animations() {
- return this.animations_;
- }
- };
- class AnimatedMesh {
- constructor(params) {
- this.params_ = params;
- this.group_ = new THREE.Group();
- this.params_.scene.add(this.group_);
- this.target_ = null;
- this.animations_ = {};
- this.mixer_ = null;
- this.onLoad = () => {};
- this.Load_();
- }
- Destroy() {
- if (this.target_) {
- this.target_.traverse(c => {
- if (c.material) {
- c.material.dispose();
- }
- if (c.geometry) {
- c.geometry.dispose();
- }
- });
- }
- this.params_.scene.remove(this.group_);
- }
- get position() {
- return this.group_.position;
- }
- get quaternion() {
- return this.group_.quaternion;
- }
- Load_() {
- const modelData = _CHARACTER_MODELS[this.params_.desc.character.class];
- const loader = new FBXLoader();
- loader.setPath(modelData.path);
- loader.load(modelData.base, (fbx) => {
- fbx.scale.setScalar(0.1);
- fbx.traverse(c => {
- c.castShadow = true;
- });
- this.target_ = fbx;
- this.group_.add(this.target_);
- this.mixer_ = new THREE.AnimationMixer(this.target_);
- const _OnLoad = (animName, anim) => {
- const clip = anim.animations[0];
- const action = this.mixer_.clipAction(clip);
-
- this.animations_[animName] = {
- clip: clip,
- action: action,
- };
- };
- // LoadingManager seems to be broken when you attempt to load multiple
- // resources multiple times, only first onLoad is called.
- // So roll our own.
- const loader = new FBXLoader();
- loader.setPath(modelData.path);
- this.manager_ = new OurLoadingManager(loader);
- this.manager_.load(
- modelData.animations.idle,
- (a) => { _OnLoad('idle', a); });
- this.manager_.load(
- modelData.animations.walk,
- (a) => { _OnLoad('walk', a); });
- this.manager_.load(
- modelData.animations.run,
- (a) => { _OnLoad('run', a); });
- this.manager_.load(
- modelData.animations.dance,
- (a) => { _OnLoad('dance', a); });
- this.manager_.onLoad = () => {
- this.onLoad();
- };
- });
- }
- Update(timeElapsed) {
- if (this.mixer_) {
- this.mixer_.update(timeElapsed);
- }
- }
- };
- class BasicCharacterController {
- constructor(params) {
- this._Init(params);
- }
- _Init(params) {
- this.params_ = params;
- this.decceleration_ = new THREE.Vector3(-0.0005, -0.0001, -5.0);
- this.acceleration_ = new THREE.Vector3(1, 0.25, 50.0);
- this.velocity_ = new THREE.Vector3(0, 0, 0);
- this.position_ = new THREE.Vector3();
- this.quaternion_ = new THREE.Quaternion();
- this.loaded_ = false;
- this._input = new BasicCharacterControllerInput();
- this.target_ = new AnimatedMesh({
- scene: params.scene,
- desc: params.desc,
- });
- this.target_.onLoad = () => {
- this.loaded_ = true;
- this.stateMachine_.SetState('idle');
- }
- this.stateMachine_ = new CharacterFSM(
- new BasicCharacterControllerProxy(this.target_.animations_));
- }
- get IsLoaded() {
- return this.loaded_;
- }
- get Position() {
- return this.position_;
- }
- get Rotation() {
- return this.quaternion_;
- }
- SetTransform(p, q) {
- this.position_.copy(p);
- this.quaternion_.copy(q);
- this.target_.group_.position.copy(this.position_);
- this.target_.group_.quaternion.copy(this.quaternion_);
- }
- CreateTransformPacket() {
- return [
- this.stateMachine_.currentState_.Name,
- this.position_.toArray(),
- this.quaternion_.toArray(),
- ];
- }
- Update(timeInSeconds) {
- if (!this.stateMachine_.currentState_) {
- return;
- }
- this.stateMachine_.Update(timeInSeconds, this._input);
- const velocity = this.velocity_;
- const frameDecceleration = new THREE.Vector3(
- velocity.x * this.decceleration_.x,
- velocity.y * this.decceleration_.y,
- velocity.z * this.decceleration_.z
- );
- 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 (this._input._keys.shift) {
- acc.multiplyScalar(2.0);
- }
- if (this.stateMachine_.currentState_.Name == 'dance') {
- acc.multiplyScalar(0.0);
- }
- if (this._input._keys.forward) {
- velocity.z += acc.z * timeInSeconds;
- }
- if (this._input._keys.backward) {
- velocity.z -= acc.z * timeInSeconds;
- }
- if (this._input._keys.left) {
- _A.set(0, 1, 0);
- _Q.setFromAxisAngle(_A, 4.0 * Math.PI * timeInSeconds * this.acceleration_.y);
- _R.multiply(_Q);
- }
- if (this._input._keys.right) {
- _A.set(0, 1, 0);
- _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);
- controlObject.position.add(forward);
- controlObject.position.add(sideways);
- this.position_.copy(controlObject.position);
- this.quaternion_.copy(controlObject.quaternion);
- this.target_.Update(timeInSeconds);
- }
- };
- class BasicCharacterControllerInput {
- constructor() {
- this._Init();
- }
- _Init() {
- this._keys = {
- forward: false,
- backward: false,
- left: false,
- right: false,
- space: false,
- shift: false,
- };
- document.addEventListener('keydown', (e) => this.OnKeyDown_(e), false);
- document.addEventListener('keyup', (e) => this._onKeyUp(e), false);
- }
- OnKeyDown_(event) {
- if (event.currentTarget.activeElement != document.body) {
- return;
- }
- switch (event.keyCode) {
- case 87: // w
- this._keys.forward = true;
- break;
- case 65: // a
- this._keys.left = true;
- break;
- case 83: // s
- this._keys.backward = true;
- break;
- case 68: // d
- this._keys.right = true;
- break;
- case 32: // SPACE
- this._keys.space = true;
- break;
- case 16: // SHIFT
- this._keys.shift = true;
- break;
- }
- }
- _onKeyUp(event) {
- if (event.currentTarget.activeElement != document.body) {
- return;
- }
- switch(event.keyCode) {
- case 87: // w
- this._keys.forward = false;
- break;
- case 65: // a
- this._keys.left = false;
- break;
- case 83: // s
- this._keys.backward = false;
- break;
- case 68: // d
- this._keys.right = false;
- break;
- case 32: // SPACE
- this._keys.space = false;
- break;
- case 16: // SHIFT
- this._keys.shift = false;
- break;
- }
- }
- };
- class FiniteStateMachine {
- constructor() {
- this._states = {};
- this.currentState_ = null;
- }
- _AddState(name, type) {
- this._states[name] = type;
- }
- SetState(name) {
- const prevState = this.currentState_;
-
- if (prevState) {
- if (prevState.Name == name) {
- return;
- }
- prevState.Exit();
- }
- const state = new this._states[name](this);
- this.currentState_ = state;
- state.Enter(prevState);
- }
- Update(timeElapsed, input) {
- if (this.currentState_) {
- this.currentState_.Update(timeElapsed, input);
- }
- }
- };
- class CharacterFSM extends FiniteStateMachine {
- constructor(proxy) {
- super();
- this._proxy = proxy;
- this._Init();
- }
- _Init() {
- this._AddState('idle', IdleState);
- this._AddState('walk', WalkState);
- this._AddState('run', RunState);
- this._AddState('dance', DanceState);
- }
- };
- class State {
- constructor(parent) {
- this._parent = parent;
- }
- Enter() {}
- Exit() {}
- Update() {}
- };
- class DanceState extends State {
- constructor(parent) {
- super(parent);
- this._FinishedCallback = () => {
- this._Finished();
- }
- }
- get Name() {
- return 'dance';
- }
- Enter(prevState) {
- const curAction = this._parent._proxy.animations_['dance'].action;
- const mixer = curAction.getMixer();
- mixer.addEventListener('finished', this._FinishedCallback);
- if (prevState) {
- const prevAction = this._parent._proxy.animations_[prevState.Name].action;
- curAction.reset();
- curAction.setLoop(THREE.LoopOnce, 1);
- curAction.clampWhenFinished = true;
- curAction.crossFadeFrom(prevAction, 0.2, true);
- curAction.play();
- } else {
- curAction.play();
- }
- }
- _Finished() {
- this._Cleanup();
- this._parent.SetState('idle');
- }
- _Cleanup() {
- const action = this._parent._proxy.animations_['dance'].action;
-
- action.getMixer().removeEventListener('finished', this._CleanupCallback);
- }
- 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;
- } else {
- curAction.time = 0.0;
- curAction.setEffectiveTimeScale(1.0);
- curAction.setEffectiveWeight(1.0);
- }
- curAction.crossFadeFrom(prevAction, 0.5, true);
- curAction.play();
- } else {
- curAction.play();
- }
- }
- Exit() {
- }
- Update(timeElapsed, input) {
- if (!input) {
- return;
- }
- if (input._keys.forward || input._keys.backward) {
- if (input._keys.shift) {
- this._parent.SetState('run');
- }
- 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;
- } else {
- curAction.time = 0.0;
- curAction.setEffectiveTimeScale(1.0);
- curAction.setEffectiveWeight(1.0);
- }
- curAction.crossFadeFrom(prevAction, 0.5, true);
- curAction.play();
- } else {
- curAction.play();
- }
- }
- Exit() {
- }
- Update(timeElapsed, input) {
- if (!input) {
- return;
- }
- if (input._keys.forward || input._keys.backward) {
- if (!input._keys.shift) {
- this._parent.SetState('walk');
- }
- 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) {
- const prevAction = this._parent._proxy.animations_[prevState.Name].action;
- idleAction.time = 0.0;
- idleAction.enabled = true;
- idleAction.setEffectiveTimeScale(1.0);
- idleAction.setEffectiveWeight(1.0);
- idleAction.crossFadeFrom(prevAction, 0.5, true);
- idleAction.play();
- } else {
- idleAction.play();
- }
- }
- Exit() {
- }
- Update(_, input) {
- if (!input) {
- return;
- }
- if (input._keys.forward || input._keys.backward) {
- this._parent.SetState('walk');
- } else if (input._keys.space) {
- this._parent.SetState('dance');
- }
- }
- };
- class ThirdPersonCamera {
- constructor(params) {
- this.params_ = params;
- this._camera = params.camera;
- this._currentPosition = new THREE.Vector3();
- this._currentLookat = new THREE.Vector3();
- }
- _CalculateIdealOffset() {
- const idealOffset = new THREE.Vector3(-15, 20, -30);
- idealOffset.applyQuaternion(this.params_.target.Rotation);
- idealOffset.add(this.params_.target.Position);
- return idealOffset;
- }
- _CalculateIdealLookat() {
- const idealLookat = new THREE.Vector3(0, 10, 50);
- idealLookat.applyQuaternion(this.params_.target.Rotation);
- idealLookat.add(this.params_.target.Position);
- return idealLookat;
- }
- Update(timeElapsed) {
- const idealOffset = this._CalculateIdealOffset();
- const idealLookat = this._CalculateIdealLookat();
- // const t = 0.05;
- // const t = 4.0 * timeElapsed;
- const t = 1.0 - Math.pow(0.001, timeElapsed);
- this._currentPosition.lerp(idealOffset, t);
- this._currentLookat.lerp(idealLookat, t);
- this._camera.position.copy(this._currentPosition);
- this._camera.lookAt(this._currentLookat);
- }
- }
- class PlayerEntity {
- constructor(params) {
- this.params_ = params;
- this.Init_();
- }
- Init_() {
- }
- CreateFromDesc(desc) {
- const params = {
- camera: this.params_.camera,
- scene: this.params_.scene,
- desc: desc,
- };
- this.controls_ = new BasicCharacterController(params);
- this.thirdPersonCamera_ = new ThirdPersonCamera({
- camera: this.params_.camera,
- target: this.controls_,
- });
- this.updateTimer_ = 0.0;
- }
- UpdateTransform(data) {
- const s = data[0];
- const p = data[1];
- const q = data[2];
- this.controls_.SetTransform(
- new THREE.Vector3(...p),
- new THREE.Quaternion(...q)
- );
- }
- Update(timeElapsed) {
- this.controls_.Update(timeElapsed);
- this.thirdPersonCamera_.Update(timeElapsed);
- this.SendTransform_(timeElapsed);
- }
- SendTransform_(timeElapsed) {
- this.updateTimer_ -= timeElapsed;
- if (this.updateTimer_ <= 0.0 && this.controls_.IsLoaded) {
- this.updateTimer_ = 0.1;
- this.params_.socket.emit(
- 'world.update',
- this.controls_.CreateTransformPacket(),
- );
- }
- }
- };
- class NetworkCharacterController {
- constructor(params) {
- this._Init(params);
- }
- Destroy() {
- this.name_.Destroy();
- this.name_ = null;
- this.target_.Destroy();
- this.target_ = null;
- }
- _Init(params) {
- this.params_ = params;
- this.target_ = new AnimatedMesh({
- scene: params.scene,
- desc: params.desc,
- });
- this.target_.onLoad = () => {
- this.stateMachine_ = new CharacterFSM(
- new BasicCharacterControllerProxy(this.target_.animations_));
- this.stateMachine_.SetState('idle');
- }
- this.name_ = new FloatingName({
- parent: this.target_.group_,
- desc: params.desc,
- });
- }
- get position() {
- return this.target_.position;
- }
- get quaternion() {
- return this.target_.quaternion;
- }
- SetState(s) {
- if (!this.stateMachine_) {
- return;
- }
- this.stateMachine_.SetState(s);
- }
- Update(timeInSeconds) {
- if (!this.stateMachine_) {
- return;
- }
- this.stateMachine_.Update(timeInSeconds, null);
- this.target_.Update(timeInSeconds);
- }
- };
- class NetworkEntity {
- constructor(params) {
- this.params_ = params;
- this.transformUpdates_ = [];
- this.targetFrame_ = null;
- this.lastFrame_ = null;
- this.Init_();
- }
- Destroy() {
- this.controller_.Destroy();
- }
- Init_() {
- }
- CreateFromDesc(desc, transform) {
- this.controller_ = new NetworkCharacterController({
- scene: this.params_.scene,
- desc: desc,
- });
- this.controller_.position.set(...transform[1]);
- this.controller_.quaternion.set(...transform[2]);
- this.targetFrame_ = {time: 0.1, transform: transform};
- }
- UpdateTransform(data) {
- this.transformUpdates_.push({time: 0.1, transform: data});
- }
- Update(timeElapsed) {
- this.controller_.Update(timeElapsed);
- this.ApplyLCT_(timeElapsed);
- }
- ApplyLCT_(timeElapsed) {
- if (this.transformUpdates_.length == 0) {
- return;
- }
- for (let i = 0; i < this.transformUpdates_.length; ++i) {
- this.transformUpdates_[i].time -= timeElapsed;
- }
- while (this.transformUpdates_.length > 0 &&
- this.transformUpdates_[0].time <= 0.0) {
- this.lastFrame_ = {
- transform: [
- this.targetFrame_.transform[0],
- this.controller_.position.toArray(),
- this.controller_.quaternion.toArray()
- ]
- };
- this.targetFrame_ = this.transformUpdates_.shift();
- this.targetFrame_.time = 0.0;
- }
- if (this.targetFrame_ && this.lastFrame_) {
- this.targetFrame_.time += timeElapsed;
- const p1 = new THREE.Vector3(...this.lastFrame_.transform[1]);
- const p2 = new THREE.Vector3(...this.targetFrame_.transform[1]);
- const q1 = new THREE.Quaternion(...this.lastFrame_.transform[2]);
- const q2 = new THREE.Quaternion(...this.targetFrame_.transform[2]);
- this.controller_.position.copy(p1);
- this.controller_.quaternion.copy(q1);
- const t = Math.max(Math.min(this.targetFrame_.time / 0.1, 1.0), 0.0);
- this.controller_.position.lerp(p2, t);
- this.controller_.quaternion.slerp(q2, t);
- this.controller_.SetState(this.lastFrame_.transform[0]);
- }
- }
- }
- class Chatbox {
- constructor(params) {
- this.params_ = params;
- this.OnChat = () => {};
- this.Init_();
- }
- Init_() {
- this.element_ = document.getElementById('chat-input');
- this.element_.addEventListener(
- 'keydown', (e) => this.OnKeyDown_(e), false);
- }
- OnKeyDown_(evt) {
- if (evt.keyCode === 13) {
- evt.preventDefault();
- const msg = this.element_.value;
- if (msg != '') {
- this.OnChat(msg);
- }
- this.element_.value = '';
- }
- }
- AddMessage(msg) {
- const e = document.createElement('div');
- e.className = 'chat-text';
- e.innerText = '[' + msg.name + ']: ' + msg.text;
- const chatElement = document.getElementById('chat-ui-text-area');
- chatElement.insertBefore(e, document.getElementById('chat-input'));
- }
- };
- class BasicMMODemo {
- 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);
- 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 = 1000.0;
- this.camera_ = new THREE.PerspectiveCamera(fov, aspect, near, far);
- this.camera_.position.set(75, 20, 0);
- this.scene_ = new THREE.Scene();
- let light = new THREE.DirectionalLight(0xFFFFFF, 1.0);
- light.position.set(20, 100, 10);
- light.target.position.set(0, 0, 0);
- light.castShadow = true;
- light.shadow.bias = -0.001;
- light.shadow.mapSize.width = 2048;
- light.shadow.mapSize.height = 2048;
- light.shadow.camera.near = 0.1;
- light.shadow.camera.far = 500.0;
- light.shadow.camera.near = 0.5;
- light.shadow.camera.far = 500.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);
- light = new THREE.AmbientLight(0x101010);
- this.scene_.add(light);
- const controls = new OrbitControls(
- this.camera_, this.threejs_.domElement);
- controls.target.set(0, 20, 0);
- controls.update();
- const loader = new THREE.CubeTextureLoader();
- const texture = loader.load([
- './resources/posx.jpg',
- './resources/negx.jpg',
- './resources/posy.jpg',
- './resources/negy.jpg',
- './resources/posz.jpg',
- './resources/negz.jpg',
- ]);
- texture.encoding = THREE.sRGBEncoding;
- this.scene_.background = texture;
- const plane = new THREE.Mesh(
- new THREE.PlaneGeometry(100, 100, 10, 10),
- new THREE.MeshStandardMaterial({
- color: 0x808080,
- }));
- plane.castShadow = false;
- plane.receiveShadow = true;
- plane.rotation.x = -Math.PI / 2;
- this.scene_.add(plane);
- this.SetupSocket_();
- this.entities_ = {};
- this.chatbox_ = new Chatbox();
- this.chatbox_.OnChat = (txt) => { this.OnChat_(txt); };
- this.previousRAF_ = null;
- this.RAF_();
- }
- GenerateRandomName_() {
- const names1 = [
- 'Aspiring', 'Nameless', 'Cautionary', 'Excited',
- 'Modest', 'Maniacal', 'Caffeinated', 'Sleepy',
- 'Passionate', 'Masochistic', 'Aging', 'Pedantic',
- 'Talkative',
- ];
- const names2 = [
- 'Coder', 'Mute', 'Giraffe', 'Snowman',
- 'Machinist', 'Fondler', 'Typist',
- 'Noodler', 'Arborist', 'Peeper', 'Ghost',
- ];
- const n1 = names1[
- Math.floor(Math.random() * names1.length)];
- const n2 = names2[
- Math.floor(Math.random() * names2.length)];
- return n1 + ' ' + n2;
- }
- SetupSocket_() {
- this.socket_ = io('ws://localhost:3000', {
- reconnection: false,
- transports: ['websocket'],
- });
- this.socket_.on("connect", () => {
- console.log(this.socket_.id);
- const randomName = this.GenerateRandomName_();
- this.socket_.emit('login.commit', randomName);
- });
- this.socket_.on("disconnect", () => {
- console.log('DISCONNECTED: ' + this.socket_.id); // undefined
- });
- this.socket_.onAny((e, d) => {
- this.OnMessage_(e, d);
- });
- }
- OnChat_(txt) {
- this.socket_.emit('chat.msg', txt);
- }
- OnMessage_(e, d) {
- if (e == 'world.player') {
- this.playerID_ = d.id;
- const e = new PlayerEntity({
- scene: this.scene_,
- camera: this.camera_,
- socket: this.socket_
- });
- e.CreateFromDesc(d.desc);
- e.UpdateTransform(d.transform);
- this.entities_[d.id] = e;
- console.log('entering world: ' + d.id);
- } else if (e == 'world.update') {
- const updates = d;
- const alive = {};
- alive[this.playerID_] = this.entities_[this.playerID_];
- for (let u of updates) {
- if ('desc' in u) {
- const e = new NetworkEntity({scene: this.scene_});
- e.CreateFromDesc(u.desc, u.transform);
- this.entities_[u.id] = e;
- } else {
- this.entities_[u.id].UpdateTransform(u.transform);
- }
- alive[u.id] = this.entities_[u.id];
- }
- const dead = [];
- for (let k in this.entities_) {
- if (!(k in alive)) {
- dead.push(this.entities_[k]);
- }
- }
- this.entities_ = alive;
- for (let i = 0; i < dead.length; ++i) {
- dead[i].Destroy();
- }
- } else if (e == 'chat.message') {
- this.chatbox_.AddMessage(d);
- }
- }
- OnWindowResize_() {
- this.camera_.aspect = window.innerWidth / window.innerHeight;
- this.camera_.updateProjectionMatrix();
- this.threejs_.setSize(window.innerWidth, window.innerHeight);
- }
- RAF_() {
- requestAnimationFrame((t) => {
- if (this.previousRAF_ == null) {
- this.previousRAF_ = t;
- }
- this.Update_((t - this.previousRAF_) * 0.001);
- this.threejs_.render(this.scene_, this.camera_);
- this.previousRAF_ = t;
- this.RAF_();
- });
- }
- Update_(timeElapsed) {
- for (let k in this.entities_) {
- this.entities_[k].Update(timeElapsed);
- }
- }
- }
- let _APP = null;
- window.addEventListener('DOMContentLoaded', () => {
- _APP = new BasicMMODemo();
- });
|