Delete framework dir
parent
ac172e4cd4
commit
4d32146eb3
|
@ -1,12 +0,0 @@
|
||||||
import EventEmitter from 'eventemitter3';
|
|
||||||
import { Queue } from './queue';
|
|
||||||
import { AssetStorage } from './storage';
|
|
||||||
export declare class Downloader extends EventEmitter {
|
|
||||||
private storage;
|
|
||||||
private queue;
|
|
||||||
private basePath;
|
|
||||||
constructor(storage: AssetStorage, queue: Queue, basePath?: string);
|
|
||||||
setBasePath(path: string): void;
|
|
||||||
download(): Promise<any>;
|
|
||||||
downloadItem(path: string): Promise<any>;
|
|
||||||
}
|
|
|
@ -1,50 +0,0 @@
|
||||||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
||||||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
||||||
return new (P || (P = Promise))(function (resolve, reject) {
|
|
||||||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
||||||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
||||||
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
||||||
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
||||||
});
|
|
||||||
};
|
|
||||||
import EventEmitter from 'eventemitter3';
|
|
||||||
import { buildPath } from './utils';
|
|
||||||
export class Downloader extends EventEmitter {
|
|
||||||
constructor(storage, queue, basePath = '') {
|
|
||||||
super();
|
|
||||||
this.storage = storage;
|
|
||||||
this.queue = queue;
|
|
||||||
this.basePath = basePath;
|
|
||||||
}
|
|
||||||
setBasePath(path) {
|
|
||||||
this.basePath = this.basePath;
|
|
||||||
}
|
|
||||||
download() {
|
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
|
||||||
const downloaded = new Map();
|
|
||||||
let numDownloaded = 0;
|
|
||||||
while (this.queue.length() > 0) {
|
|
||||||
const path = this.queue.pop();
|
|
||||||
const item = yield this.downloadItem(buildPath(this.basePath, path));
|
|
||||||
downloaded.set(path, item);
|
|
||||||
numDownloaded++;
|
|
||||||
this.emit('download.progress', {
|
|
||||||
downloaded: numDownloaded,
|
|
||||||
remaining: this.queue.length()
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return downloaded;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
downloadItem(path) {
|
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
|
||||||
const inCache = yield this.storage.get(path);
|
|
||||||
if (inCache) {
|
|
||||||
return inCache;
|
|
||||||
}
|
|
||||||
const response = yield fetch(path);
|
|
||||||
this.storage.add(path, response);
|
|
||||||
return response;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,18 +0,0 @@
|
||||||
import EventEmitter from 'eventemitter3';
|
|
||||||
export declare class AssetManager extends EventEmitter {
|
|
||||||
private name;
|
|
||||||
private basePath;
|
|
||||||
private downloader;
|
|
||||||
private queue;
|
|
||||||
private storage;
|
|
||||||
private manifest;
|
|
||||||
constructor(name: string, basePath: string);
|
|
||||||
init(): Promise<boolean>;
|
|
||||||
setManifest(path: string): Promise<any>;
|
|
||||||
enqueue(path: string): void;
|
|
||||||
download(): Promise<any>;
|
|
||||||
downloadFromManifest(key: string): Promise<any>;
|
|
||||||
downloadFile(path: string): Promise<any>;
|
|
||||||
setBasePath(path: string): void;
|
|
||||||
clearCache(): void;
|
|
||||||
}
|
|
|
@ -1,71 +0,0 @@
|
||||||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
||||||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
||||||
return new (P || (P = Promise))(function (resolve, reject) {
|
|
||||||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
||||||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
||||||
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
||||||
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
||||||
});
|
|
||||||
};
|
|
||||||
import { Downloader } from './downloader';
|
|
||||||
import { Queue } from './queue';
|
|
||||||
import { Manifest } from './manifest';
|
|
||||||
import { AssetStorage } from './storage';
|
|
||||||
import EventEmitter from 'eventemitter3';
|
|
||||||
import { buildPath } from './utils';
|
|
||||||
export class AssetManager extends EventEmitter {
|
|
||||||
constructor(name, basePath) {
|
|
||||||
super();
|
|
||||||
this.name = name;
|
|
||||||
this.basePath = basePath;
|
|
||||||
this.queue = new Queue();
|
|
||||||
this.storage = new AssetStorage(name);
|
|
||||||
this.downloader = new Downloader(this.storage, this.queue, this.basePath);
|
|
||||||
console.log(`Asset manager initialized`);
|
|
||||||
}
|
|
||||||
init() {
|
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
|
||||||
yield this.storage.init();
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
setManifest(path) {
|
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
|
||||||
this.manifest = yield Manifest(`${this.basePath}/${path}`);
|
|
||||||
this.storage.setManifest(this.manifest);
|
|
||||||
return this.manifest;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
enqueue(path) {
|
|
||||||
this.queue.add(path);
|
|
||||||
}
|
|
||||||
download() {
|
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
|
||||||
const result = yield this.downloader.download();
|
|
||||||
return result;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
downloadFromManifest(key) {
|
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
|
||||||
const paths = this.manifest[key];
|
|
||||||
paths.forEach((path) => this.enqueue(path));
|
|
||||||
this.downloader.on('download.progress', (info) => this.emit('progress', info));
|
|
||||||
const files = yield this.downloader.download();
|
|
||||||
this.downloader.off('download.progress');
|
|
||||||
return files;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
downloadFile(path) {
|
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
|
||||||
const result = yield this.downloader.downloadItem(buildPath(this.basePath, path));
|
|
||||||
return result;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
setBasePath(path) {
|
|
||||||
this.basePath = this.basePath;
|
|
||||||
this.downloader.setBasePath(this.basePath);
|
|
||||||
}
|
|
||||||
clearCache() {
|
|
||||||
this.storage.clear();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,2 +0,0 @@
|
||||||
export declare function Manifest(manifestPath: string): Promise<any>;
|
|
||||||
export declare function CheckManifest(manifest: any): boolean;
|
|
|
@ -1,40 +0,0 @@
|
||||||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
||||||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
||||||
return new (P || (P = Promise))(function (resolve, reject) {
|
|
||||||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
||||||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
||||||
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
||||||
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
||||||
});
|
|
||||||
};
|
|
||||||
import * as yaml from 'yaml';
|
|
||||||
export function Manifest(manifestPath) {
|
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
|
||||||
try {
|
|
||||||
const response = yield fetch(manifestPath);
|
|
||||||
console.log(response);
|
|
||||||
const data = yield response.text();
|
|
||||||
console.log(`Parsing: `, data);
|
|
||||||
const manifest = yaml.parse(data);
|
|
||||||
return manifest;
|
|
||||||
}
|
|
||||||
catch (error) {
|
|
||||||
alert(`Error occured: ${error.toString()}`);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
export function CheckManifest(manifest) {
|
|
||||||
const prevManifestStr = localStorage.getItem('manifest');
|
|
||||||
if (!prevManifestStr) {
|
|
||||||
localStorage.setItem('manifest', JSON.stringify(manifest));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
const prevManifest = JSON.parse(prevManifestStr);
|
|
||||||
if (prevManifest.version === manifest.version) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
localStorage.setItem('manifest', manifest);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,8 +0,0 @@
|
||||||
export declare class Queue {
|
|
||||||
private items;
|
|
||||||
constructor();
|
|
||||||
add(file: string): string[];
|
|
||||||
remove(file: string): string[];
|
|
||||||
pop(): string;
|
|
||||||
length(): number;
|
|
||||||
}
|
|
|
@ -1,19 +0,0 @@
|
||||||
export class Queue {
|
|
||||||
constructor() {
|
|
||||||
this.items = [];
|
|
||||||
}
|
|
||||||
add(file) {
|
|
||||||
this.items.push(file);
|
|
||||||
return this.items;
|
|
||||||
}
|
|
||||||
remove(file) {
|
|
||||||
this.items = this.items.filter((item) => item !== file);
|
|
||||||
return this.items;
|
|
||||||
}
|
|
||||||
pop() {
|
|
||||||
return this.items.pop();
|
|
||||||
}
|
|
||||||
length() {
|
|
||||||
return this.items.length;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,11 +0,0 @@
|
||||||
export declare class AssetStorage {
|
|
||||||
private id;
|
|
||||||
private cache;
|
|
||||||
private manifest;
|
|
||||||
constructor(id: string);
|
|
||||||
init(): Promise<void>;
|
|
||||||
add(request: RequestInfo, response: Response): Promise<Boolean>;
|
|
||||||
get(request: RequestInfo): Promise<Response>;
|
|
||||||
setManifest(manifest: any): Promise<void>;
|
|
||||||
clear(): Promise<void>;
|
|
||||||
}
|
|
|
@ -1,48 +0,0 @@
|
||||||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
||||||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
||||||
return new (P || (P = Promise))(function (resolve, reject) {
|
|
||||||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
||||||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
||||||
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
||||||
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
||||||
});
|
|
||||||
};
|
|
||||||
import { CheckManifest } from './manifest';
|
|
||||||
export class AssetStorage {
|
|
||||||
constructor(id) {
|
|
||||||
this.id = id;
|
|
||||||
}
|
|
||||||
init() {
|
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
|
||||||
this.cache = yield caches.open(this.id);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
add(request, response) {
|
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
|
||||||
const result = yield this.cache.put(request, response);
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
get(request) {
|
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
|
||||||
const result = yield this.cache.match(request);
|
|
||||||
return result;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
setManifest(manifest) {
|
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
|
||||||
this.manifest = manifest;
|
|
||||||
if (!CheckManifest(this.manifest)) {
|
|
||||||
yield this.clear();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
clear() {
|
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
|
||||||
const keys = yield this.cache.keys();
|
|
||||||
keys.forEach((key) => __awaiter(this, void 0, void 0, function* () {
|
|
||||||
const result = yield this.cache.delete(key);
|
|
||||||
}));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1 +0,0 @@
|
||||||
export {};
|
|
|
@ -1,5 +0,0 @@
|
||||||
const yaml = require('yaml');
|
|
||||||
const fs = require('fs');
|
|
||||||
const data = fs.readFileSync('manifest.yaml');
|
|
||||||
const parsed = yaml.parse(data.toString());
|
|
||||||
console.log(parsed);
|
|
|
@ -1 +0,0 @@
|
||||||
export declare function buildPath(basePath: string, path: string): string;
|
|
|
@ -1,8 +0,0 @@
|
||||||
export function buildPath(basePath, path) {
|
|
||||||
if (!basePath) {
|
|
||||||
return path;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return `${basePath}/${path}`;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,12 +0,0 @@
|
||||||
export declare class BaseComponent {
|
|
||||||
id: number;
|
|
||||||
properties: any;
|
|
||||||
constructor();
|
|
||||||
clone(): BaseComponent;
|
|
||||||
}
|
|
||||||
export interface Component {
|
|
||||||
id: number;
|
|
||||||
properties: any;
|
|
||||||
clone(): BaseComponent;
|
|
||||||
new (): BaseComponent;
|
|
||||||
}
|
|
|
@ -1,11 +0,0 @@
|
||||||
export class BaseComponent {
|
|
||||||
constructor() {
|
|
||||||
this.id = 0;
|
|
||||||
this.properties = {};
|
|
||||||
}
|
|
||||||
clone() {
|
|
||||||
const comp = new BaseComponent();
|
|
||||||
comp.properties = this.properties;
|
|
||||||
return comp;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,19 +0,0 @@
|
||||||
import { BaseComponent, Component } from './component';
|
|
||||||
export declare class BaseEntity {
|
|
||||||
id: number;
|
|
||||||
components: Map<number, BaseComponent>;
|
|
||||||
constructor();
|
|
||||||
addComponent(component: Component): void;
|
|
||||||
removeComponent(component: BaseComponent): void;
|
|
||||||
getComponentIDs(): number[];
|
|
||||||
getComponent(component: BaseComponent): BaseComponent;
|
|
||||||
getComponentByID(id: number): BaseComponent;
|
|
||||||
}
|
|
||||||
export interface Entity {
|
|
||||||
new (): BaseComponent;
|
|
||||||
addComponent(component: Component): any;
|
|
||||||
removeComponent(component: BaseComponent): any;
|
|
||||||
getComponentIDs(): number[];
|
|
||||||
getComponent(component: BaseComponent): any;
|
|
||||||
getComponentByID(id: number): BaseComponent;
|
|
||||||
}
|
|
|
@ -1,23 +0,0 @@
|
||||||
export class BaseEntity {
|
|
||||||
constructor() {
|
|
||||||
this.components = new Map();
|
|
||||||
this.id = 0;
|
|
||||||
}
|
|
||||||
addComponent(component) {
|
|
||||||
let comp = new component();
|
|
||||||
comp.id = component.id;
|
|
||||||
this.components.set(component.id, comp);
|
|
||||||
}
|
|
||||||
removeComponent(component) {
|
|
||||||
this.components.delete(component.id);
|
|
||||||
}
|
|
||||||
getComponentIDs() {
|
|
||||||
return [...this.components.keys()];
|
|
||||||
}
|
|
||||||
getComponent(component) {
|
|
||||||
return this.components.get(component.id);
|
|
||||||
}
|
|
||||||
getComponentByID(id) {
|
|
||||||
return this.components.get(id);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,28 +0,0 @@
|
||||||
import { Component } from './component';
|
|
||||||
import { BaseEntity, Entity } from './entity';
|
|
||||||
import { EventBus } from '../event-bus';
|
|
||||||
import { Query } from './query';
|
|
||||||
import { System } from './system';
|
|
||||||
export declare class World {
|
|
||||||
entities: Array<BaseEntity>;
|
|
||||||
components: Map<number, Component>;
|
|
||||||
componentNamesToIDs: Map<string, number>;
|
|
||||||
systems: Set<System>;
|
|
||||||
nextEntityID: number;
|
|
||||||
nextComponentID: number;
|
|
||||||
nextQueryID: number;
|
|
||||||
queryCache: Array<Query>;
|
|
||||||
eventBus: EventBus;
|
|
||||||
constructor();
|
|
||||||
run(): void;
|
|
||||||
createSystem(systemExecutor: Function): void;
|
|
||||||
addSystem(system: System): void;
|
|
||||||
addEntity(entity: BaseEntity): void;
|
|
||||||
removeEntity(entityToRemove: BaseEntity): void;
|
|
||||||
createEntity(components: Array<Component>): BaseEntity;
|
|
||||||
extendEntity(entity: Entity, components: Array<Component>): BaseEntity;
|
|
||||||
createComponent(component: Component): Component;
|
|
||||||
query(include: Array<Component>, exclude: Array<Component>): Array<BaseEntity>;
|
|
||||||
createQuery(include: Array<Component>, exclude: Array<Component>): Query;
|
|
||||||
markQueriesDirty(): void;
|
|
||||||
}
|
|
|
@ -1,105 +0,0 @@
|
||||||
import { BaseEntity } from './entity';
|
|
||||||
import { EventBus } from '../event-bus';
|
|
||||||
import { Query } from './query';
|
|
||||||
import { System } from './system';
|
|
||||||
export class World {
|
|
||||||
constructor() {
|
|
||||||
this.nextEntityID = 0;
|
|
||||||
this.nextComponentID = 0;
|
|
||||||
this.nextQueryID = 0;
|
|
||||||
this.entities = new Array();
|
|
||||||
this.systems = new Set();
|
|
||||||
this.components = new Map();
|
|
||||||
this.componentNamesToIDs = new Map();
|
|
||||||
this.queryCache = new Array();
|
|
||||||
this.eventBus = new EventBus();
|
|
||||||
}
|
|
||||||
run() {
|
|
||||||
this.systems.forEach((system) => {
|
|
||||||
system.execute(this);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
createSystem(systemExecutor) {
|
|
||||||
const newSystem = new System(systemExecutor);
|
|
||||||
this.systems.add(newSystem);
|
|
||||||
}
|
|
||||||
addSystem(system) {
|
|
||||||
this.systems.add(system);
|
|
||||||
}
|
|
||||||
addEntity(entity) {
|
|
||||||
this.entities.push(entity);
|
|
||||||
this.markQueriesDirty();
|
|
||||||
}
|
|
||||||
removeEntity(entityToRemove) {
|
|
||||||
this.entities = this.entities.filter((entity) => entity !== entityToRemove);
|
|
||||||
this.markQueriesDirty();
|
|
||||||
}
|
|
||||||
createEntity(components) {
|
|
||||||
const newEntity = new BaseEntity();
|
|
||||||
newEntity.id = this.nextEntityID;
|
|
||||||
this.nextEntityID++;
|
|
||||||
components.forEach((component) => {
|
|
||||||
if (this.componentNamesToIDs.has(component.name)) {
|
|
||||||
component.id = this.componentNamesToIDs.get(component.name);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
this.componentNamesToIDs.set(component.name, this.nextComponentID);
|
|
||||||
component.id = this.nextComponentID;
|
|
||||||
this.nextComponentID++;
|
|
||||||
}
|
|
||||||
newEntity.addComponent(component);
|
|
||||||
});
|
|
||||||
this.entities.push(newEntity);
|
|
||||||
this.markQueriesDirty();
|
|
||||||
return newEntity;
|
|
||||||
}
|
|
||||||
extendEntity(entity, components) {
|
|
||||||
const toClone = this.entities.find((found) => entity.name === found.constructor.name);
|
|
||||||
const cloned = new BaseEntity();
|
|
||||||
cloned.id = this.nextEntityID;
|
|
||||||
this.nextEntityID++;
|
|
||||||
toClone.components.forEach((component) => {
|
|
||||||
cloned.addComponent(this.components.get(component.id));
|
|
||||||
});
|
|
||||||
components.forEach((component) => {
|
|
||||||
if (this.componentNamesToIDs.has(component.name)) {
|
|
||||||
component.id = this.componentNamesToIDs.get(component.name);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
this.componentNamesToIDs.set(component.name, this.nextComponentID);
|
|
||||||
component.id = this.nextComponentID;
|
|
||||||
this.nextComponentID++;
|
|
||||||
}
|
|
||||||
cloned.addComponent(component);
|
|
||||||
});
|
|
||||||
this.entities.push(cloned);
|
|
||||||
return cloned;
|
|
||||||
}
|
|
||||||
createComponent(component) {
|
|
||||||
const newComponent = component;
|
|
||||||
newComponent.id = this.nextComponentID;
|
|
||||||
this.nextComponentID++;
|
|
||||||
this.components.set(newComponent.id, newComponent);
|
|
||||||
this.componentNamesToIDs.set(component.name, component.id);
|
|
||||||
return newComponent;
|
|
||||||
}
|
|
||||||
query(include, exclude) {
|
|
||||||
const query = new Query(include, exclude, this);
|
|
||||||
const cache = this.queryCache.find((item) => item.include == include && item.exclude == exclude);
|
|
||||||
if (cache) {
|
|
||||||
return cache.execute();
|
|
||||||
}
|
|
||||||
this.queryCache.push(query);
|
|
||||||
return query.execute();
|
|
||||||
}
|
|
||||||
createQuery(include, exclude) {
|
|
||||||
const newQuery = new Query(include, exclude, this);
|
|
||||||
newQuery.id = this.nextQueryID;
|
|
||||||
this.nextQueryID++;
|
|
||||||
this.queryCache.push(newQuery);
|
|
||||||
return newQuery;
|
|
||||||
}
|
|
||||||
markQueriesDirty() {
|
|
||||||
this.queryCache.forEach((query) => (query.isDirty = true));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,15 +0,0 @@
|
||||||
import { World } from '.';
|
|
||||||
import { Component } from './component';
|
|
||||||
import { BaseEntity } from './entity';
|
|
||||||
export declare class Query {
|
|
||||||
include: Array<Component>;
|
|
||||||
exclude: Array<Component>;
|
|
||||||
world: World;
|
|
||||||
id: number;
|
|
||||||
private results;
|
|
||||||
isDirty: boolean;
|
|
||||||
includeComponentIds: number[];
|
|
||||||
excludeComponentIds: number[];
|
|
||||||
constructor(include: Array<Component>, exclude: Array<Component>, world: World);
|
|
||||||
execute(): Array<BaseEntity>;
|
|
||||||
}
|
|
|
@ -1,34 +0,0 @@
|
||||||
export class Query {
|
|
||||||
constructor(include, exclude, world) {
|
|
||||||
this.include = include;
|
|
||||||
this.exclude = exclude;
|
|
||||||
this.world = world;
|
|
||||||
this.isDirty = true;
|
|
||||||
this.results = new Array();
|
|
||||||
this.includeComponentIds = include.map((component) => component.id);
|
|
||||||
this.excludeComponentIds = exclude.map((component) => component.id);
|
|
||||||
this.id = 0;
|
|
||||||
}
|
|
||||||
execute() {
|
|
||||||
if (!this.isDirty && this.results) {
|
|
||||||
return this.results;
|
|
||||||
}
|
|
||||||
let filtered;
|
|
||||||
this.includeComponentIds = this.include.map((component) => this.world.componentNamesToIDs.get(component.name));
|
|
||||||
this.excludeComponentIds = this.exclude.map((component) => this.world.componentNamesToIDs.get(component.name));
|
|
||||||
const entities = this.world.entities.filter((entity) => {
|
|
||||||
let ids = entity.getComponentIDs();
|
|
||||||
// let includes = ids.map(id => this.includeComponentIds.includes(id)).includes(true);
|
|
||||||
let excludes = ids
|
|
||||||
.map((id) => this.excludeComponentIds.includes(id))
|
|
||||||
.includes(true);
|
|
||||||
let includes = ids.filter((id) => this.includeComponentIds.includes(id));
|
|
||||||
return includes.length === this.includeComponentIds.length && !excludes;
|
|
||||||
});
|
|
||||||
if (entities.length > 0) {
|
|
||||||
this.isDirty = false;
|
|
||||||
this.results = entities;
|
|
||||||
}
|
|
||||||
return entities;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,6 +0,0 @@
|
||||||
import { World } from '.';
|
|
||||||
export declare class System {
|
|
||||||
executor: Function;
|
|
||||||
constructor(executor: Function);
|
|
||||||
execute(world: World): void;
|
|
||||||
}
|
|
|
@ -1,10 +0,0 @@
|
||||||
export class System {
|
|
||||||
constructor(executor) {
|
|
||||||
this.executor = executor;
|
|
||||||
}
|
|
||||||
execute(world) {
|
|
||||||
if (this.executor) {
|
|
||||||
this.executor(world);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
File diff suppressed because one or more lines are too long
|
@ -1,11 +0,0 @@
|
||||||
export declare class EventBus {
|
|
||||||
private events;
|
|
||||||
constructor();
|
|
||||||
emit(id: string, data: any): void;
|
|
||||||
subscribe(id: string, subscriber: Function): void;
|
|
||||||
}
|
|
||||||
export declare class EventItem {
|
|
||||||
id: string;
|
|
||||||
subscribers: Function[];
|
|
||||||
constructor(id: string);
|
|
||||||
}
|
|
|
@ -1,30 +0,0 @@
|
||||||
export class EventBus {
|
|
||||||
constructor() {
|
|
||||||
this.events = new Map();
|
|
||||||
}
|
|
||||||
emit(id, data) {
|
|
||||||
let ev = this.events.get(id);
|
|
||||||
if (!ev) {
|
|
||||||
let ev = new EventItem(id);
|
|
||||||
this.events.set(id, ev);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
ev.subscribers.forEach((subscriber) => {
|
|
||||||
subscriber(data);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
subscribe(id, subscriber) {
|
|
||||||
let ev = this.events.get(id);
|
|
||||||
if (!ev) {
|
|
||||||
ev = new EventItem(id);
|
|
||||||
this.events.set(id, ev);
|
|
||||||
}
|
|
||||||
ev.subscribers.push(subscriber);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
export class EventItem {
|
|
||||||
constructor(id) {
|
|
||||||
this.id = id;
|
|
||||||
this.subscribers = [];
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,13 +0,0 @@
|
||||||
export declare class EventBus {
|
|
||||||
private events;
|
|
||||||
constructor();
|
|
||||||
emit(id: string, data?: any): void;
|
|
||||||
subscribe(id: string, subscriber: Function): void;
|
|
||||||
unsubscribe(id: string, subscriber: Function): void;
|
|
||||||
unsubscribeAll(id: string): void;
|
|
||||||
}
|
|
||||||
export declare class EventItem {
|
|
||||||
id: string;
|
|
||||||
subscribers: Function[];
|
|
||||||
constructor(id: string);
|
|
||||||
}
|
|
|
@ -1,44 +0,0 @@
|
||||||
export class EventBus {
|
|
||||||
constructor() {
|
|
||||||
this.events = new Map();
|
|
||||||
}
|
|
||||||
emit(id, data = {}) {
|
|
||||||
let ev = this.events.get(id);
|
|
||||||
if (!ev) {
|
|
||||||
let ev = new EventItem(id);
|
|
||||||
this.events.set(id, ev);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
ev.subscribers.forEach((subscriber) => {
|
|
||||||
subscriber(data);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
subscribe(id, subscriber) {
|
|
||||||
let ev = this.events.get(id);
|
|
||||||
if (!ev) {
|
|
||||||
ev = new EventItem(id);
|
|
||||||
this.events.set(id, ev);
|
|
||||||
}
|
|
||||||
ev.subscribers.push(subscriber);
|
|
||||||
}
|
|
||||||
unsubscribe(id, subscriber) {
|
|
||||||
if (this.events.has(id)) {
|
|
||||||
let ev = this.events.get(id);
|
|
||||||
ev.subscribers = ev.subscribers.filter((fn) => fn !== subscriber);
|
|
||||||
if (ev.subscribers.length < 1) {
|
|
||||||
this.events.delete(id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
unsubscribeAll(id) {
|
|
||||||
if (this.events.has(id)) {
|
|
||||||
this.events.delete(id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
export class EventItem {
|
|
||||||
constructor(id) {
|
|
||||||
this.id = id;
|
|
||||||
this.subscribers = [];
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,26 +0,0 @@
|
||||||
import { AssetManager } from '../asset-manager';
|
|
||||||
import { Input } from '../input';
|
|
||||||
import Resonator from '../resonator';
|
|
||||||
import { Scene } from '../scene/scene';
|
|
||||||
import { SceneManager } from '../scene/manager';
|
|
||||||
import { Scheduler } from '../scheduler';
|
|
||||||
import { TTS } from '../tts';
|
|
||||||
import { HTTPLoader } from '../resonator/loaders/http-loader';
|
|
||||||
import { EventBus } from '../event-bus';
|
|
||||||
import { World } from '../world';
|
|
||||||
export declare class Game extends EventBus {
|
|
||||||
assetLoader: HTTPLoader;
|
|
||||||
assetManager: AssetManager;
|
|
||||||
resonator: Resonator;
|
|
||||||
input: Input;
|
|
||||||
tts: TTS;
|
|
||||||
sceneManager: SceneManager;
|
|
||||||
scheduler: Scheduler;
|
|
||||||
world: World;
|
|
||||||
constructor();
|
|
||||||
init(): void;
|
|
||||||
start(): void;
|
|
||||||
addScene(scene: Scene): void;
|
|
||||||
addDefaultScene(scene: Scene): void;
|
|
||||||
setWorld(world: World): void;
|
|
||||||
}
|
|
|
@ -1,44 +0,0 @@
|
||||||
import { AssetManager } from '../asset-manager';
|
|
||||||
import { Input } from '../input';
|
|
||||||
import Resonator from '../resonator';
|
|
||||||
import { SceneManager } from '../scene/manager';
|
|
||||||
import { Scheduler } from '../scheduler';
|
|
||||||
import { TTS } from '../tts';
|
|
||||||
import { AriaOutput } from '../tts/outputs/aria';
|
|
||||||
import { HTTPLoader } from '../resonator/loaders/http-loader';
|
|
||||||
import { EventBus } from '../event-bus';
|
|
||||||
export class Game extends EventBus {
|
|
||||||
constructor() {
|
|
||||||
super();
|
|
||||||
this.init();
|
|
||||||
}
|
|
||||||
init() {
|
|
||||||
this.assetManager = new AssetManager('game', '');
|
|
||||||
this.assetLoader = new HTTPLoader();
|
|
||||||
this.resonator = new Resonator(this.assetLoader);
|
|
||||||
this.input = new Input(['keyboard'], document.body);
|
|
||||||
this.tts = new TTS(new AriaOutput());
|
|
||||||
this.sceneManager = new SceneManager();
|
|
||||||
this.scheduler = new Scheduler(60);
|
|
||||||
this.emit('ready');
|
|
||||||
}
|
|
||||||
start() {
|
|
||||||
this.scheduler.start();
|
|
||||||
this.scheduler.subscribe('update.logic', (dt) => {
|
|
||||||
this.sceneManager.currentScene.update(dt);
|
|
||||||
this.world.update(dt);
|
|
||||||
});
|
|
||||||
this.scheduler.subscribe('update.draw', (dt) => this.sceneManager.currentScene.updateDraw());
|
|
||||||
this.sceneManager.init();
|
|
||||||
}
|
|
||||||
addScene(scene) {
|
|
||||||
this.sceneManager.addScene(scene);
|
|
||||||
}
|
|
||||||
addDefaultScene(scene) {
|
|
||||||
this.sceneManager.addScene(scene);
|
|
||||||
this.sceneManager.setDefaultScene(scene);
|
|
||||||
}
|
|
||||||
setWorld(world) {
|
|
||||||
this.world = world;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,29 +0,0 @@
|
||||||
import { Scene } from '../../scene/scene';
|
|
||||||
import { World } from '../../ecs/index';
|
|
||||||
import { Game } from '..';
|
|
||||||
import { Component } from '../../ecs/component';
|
|
||||||
import { System } from '../../ecs/system';
|
|
||||||
import { Entity } from '../../ecs/entity';
|
|
||||||
import { Query } from '../../ecs/query';
|
|
||||||
import { SceneManager } from '../../scene/manager';
|
|
||||||
export declare class ECSScene implements Scene {
|
|
||||||
instance: Game;
|
|
||||||
id: string;
|
|
||||||
world: World;
|
|
||||||
running: boolean;
|
|
||||||
data: any;
|
|
||||||
constructor(instance: Game);
|
|
||||||
update(): void;
|
|
||||||
updateDraw(): boolean;
|
|
||||||
onActivate(manager: SceneManager): void;
|
|
||||||
onDeactivate(): void;
|
|
||||||
onSwitch(): void;
|
|
||||||
createEntity(components: Array<Component<any>>): Entity;
|
|
||||||
createComponent<T>(props: T): Component<T>;
|
|
||||||
createSystem(systemExecutor: Function): void;
|
|
||||||
addSystem(system: System): void;
|
|
||||||
addEntity(entity: Entity): void;
|
|
||||||
removeEntity(entity: Entity): void;
|
|
||||||
createQuery(include: Array<Component<any>>, exclude: Array<Component<any>>): Query;
|
|
||||||
extendEntity(entity: Entity, components: Array<Component<any>>): Entity;
|
|
||||||
}
|
|
|
@ -1,49 +0,0 @@
|
||||||
import { World } from '../../ecs/index';
|
|
||||||
export class ECSScene {
|
|
||||||
constructor(instance) {
|
|
||||||
this.instance = instance;
|
|
||||||
this.running = true;
|
|
||||||
this.id = 'ECSScene';
|
|
||||||
this.world = new World();
|
|
||||||
}
|
|
||||||
update() {
|
|
||||||
if (this.running)
|
|
||||||
this.world.run();
|
|
||||||
}
|
|
||||||
updateDraw() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
onActivate(manager) {
|
|
||||||
this.running = true;
|
|
||||||
}
|
|
||||||
onDeactivate() {
|
|
||||||
this.running = false;
|
|
||||||
}
|
|
||||||
onSwitch() {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
createEntity(components) {
|
|
||||||
return this.world.createEntity(components);
|
|
||||||
}
|
|
||||||
createComponent(props) {
|
|
||||||
return this.world.createComponent(props);
|
|
||||||
}
|
|
||||||
createSystem(systemExecutor) {
|
|
||||||
return this.world.createSystem(systemExecutor);
|
|
||||||
}
|
|
||||||
addSystem(system) {
|
|
||||||
return this.world.addSystem(system);
|
|
||||||
}
|
|
||||||
addEntity(entity) {
|
|
||||||
return this.world.addEntity(entity);
|
|
||||||
}
|
|
||||||
removeEntity(entity) {
|
|
||||||
return this.world.removeEntity(entity);
|
|
||||||
}
|
|
||||||
createQuery(include, exclude) {
|
|
||||||
return this.world.createQuery(include, exclude);
|
|
||||||
}
|
|
||||||
extendEntity(entity, components) {
|
|
||||||
return this.world.extendEntity(entity, components);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,7 +0,0 @@
|
||||||
export * from './asset-manager';
|
|
||||||
export * from './ecs';
|
|
||||||
export * from './event-bus';
|
|
||||||
export * from './input';
|
|
||||||
export * from './resonator';
|
|
||||||
export * from './tts';
|
|
||||||
export * from './ui';
|
|
|
@ -1,7 +0,0 @@
|
||||||
export * from './asset-manager';
|
|
||||||
export * from './ecs';
|
|
||||||
export * from './event-bus';
|
|
||||||
export * from './input';
|
|
||||||
export * from './resonator';
|
|
||||||
export * from './tts';
|
|
||||||
export * from './ui';
|
|
|
@ -1,13 +0,0 @@
|
||||||
import { BaseInput } from './inputs/base-input';
|
|
||||||
import { State } from './interfaces/state';
|
|
||||||
export declare class Input {
|
|
||||||
private InputIDs;
|
|
||||||
private element;
|
|
||||||
private inputs;
|
|
||||||
constructor(InputIDs: string[], element: HTMLElement);
|
|
||||||
private init;
|
|
||||||
addInput(id: string, input: BaseInput): this;
|
|
||||||
capture(preventDefault?: boolean): void;
|
|
||||||
release(): void;
|
|
||||||
getState(): State;
|
|
||||||
}
|
|
|
@ -1,34 +0,0 @@
|
||||||
import { createInput } from './input-factory';
|
|
||||||
export class Input {
|
|
||||||
constructor(InputIDs, element) {
|
|
||||||
this.InputIDs = InputIDs;
|
|
||||||
this.element = element;
|
|
||||||
this.inputs = new Map();
|
|
||||||
this.init();
|
|
||||||
}
|
|
||||||
init() {
|
|
||||||
this.InputIDs.forEach((inputID) => {
|
|
||||||
const thing = createInput(inputID);
|
|
||||||
const instance = new thing(this.element);
|
|
||||||
this.inputs.set(inputID, instance);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
addInput(id, input) {
|
|
||||||
this.inputs.set(id, input);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
capture(preventDefault = true) {
|
|
||||||
this.inputs.forEach((input) => input.capture(preventDefault));
|
|
||||||
}
|
|
||||||
release() {
|
|
||||||
this.inputs.forEach((input) => input.release());
|
|
||||||
}
|
|
||||||
getState() {
|
|
||||||
const state = {};
|
|
||||||
this.inputs.forEach((input, inputID) => {
|
|
||||||
if (input)
|
|
||||||
state[inputID] = input.getState();
|
|
||||||
});
|
|
||||||
return state;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1 +0,0 @@
|
||||||
export declare function createInput(key: string): any;
|
|
|
@ -1,14 +0,0 @@
|
||||||
import { Keyboard } from './inputs/keyboard';
|
|
||||||
import { Mouse } from './inputs/mouse';
|
|
||||||
export function createInput(key) {
|
|
||||||
switch (key) {
|
|
||||||
case 'keyboard':
|
|
||||||
return Keyboard;
|
|
||||||
break;
|
|
||||||
case 'mouse':
|
|
||||||
return Mouse;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,10 +0,0 @@
|
||||||
export declare class BaseInput {
|
|
||||||
protected element: HTMLElement;
|
|
||||||
protected active: boolean;
|
|
||||||
constructor(element: HTMLElement);
|
|
||||||
getState(): any;
|
|
||||||
capture(preventDefault: boolean): void;
|
|
||||||
release(): void;
|
|
||||||
}
|
|
||||||
export interface IBaseInput {
|
|
||||||
}
|
|
|
@ -1,12 +0,0 @@
|
||||||
export class BaseInput {
|
|
||||||
constructor(element) {
|
|
||||||
this.element = element;
|
|
||||||
}
|
|
||||||
getState() { }
|
|
||||||
capture(preventDefault) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
release() {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,6 +0,0 @@
|
||||||
import { BaseInput } from './base-input';
|
|
||||||
export declare class Joystick extends BaseInput {
|
|
||||||
constructor(element: HTMLElement);
|
|
||||||
}
|
|
||||||
export interface IJoystick {
|
|
||||||
}
|
|
|
@ -1,6 +0,0 @@
|
||||||
import { BaseInput } from './base-input';
|
|
||||||
export class Joystick extends BaseInput {
|
|
||||||
constructor(element) {
|
|
||||||
super(element);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,18 +0,0 @@
|
||||||
import { BaseInput } from './base-input';
|
|
||||||
export declare class Keyboard extends BaseInput {
|
|
||||||
private keysDown;
|
|
||||||
private keysJustPressed;
|
|
||||||
private keysJustReleased;
|
|
||||||
private preventDefault;
|
|
||||||
constructor(element: HTMLElement);
|
|
||||||
capture(preventDefault: boolean): void;
|
|
||||||
release(): void;
|
|
||||||
getState(): IKeyboard;
|
|
||||||
private handleKeyDown;
|
|
||||||
private handleKeyUp;
|
|
||||||
}
|
|
||||||
export interface IKeyboard {
|
|
||||||
keysDown: Map<number, boolean>;
|
|
||||||
keysJustPressed: Map<number, boolean>;
|
|
||||||
keysJustReleased: Map<number, boolean>;
|
|
||||||
}
|
|
|
@ -1,50 +0,0 @@
|
||||||
import { BaseInput } from './base-input';
|
|
||||||
export class Keyboard extends BaseInput {
|
|
||||||
constructor(element) {
|
|
||||||
super(element);
|
|
||||||
this.keysDown = new Map();
|
|
||||||
this.keysJustPressed = new Map();
|
|
||||||
this.keysJustReleased = new Map();
|
|
||||||
this.handleKeyDown = this.handleKeyDown.bind(this);
|
|
||||||
this.handleKeyUp = this.handleKeyUp.bind(this);
|
|
||||||
}
|
|
||||||
capture(preventDefault) {
|
|
||||||
this.active = true;
|
|
||||||
this.preventDefault = preventDefault;
|
|
||||||
this.element.addEventListener('keydown', this.handleKeyDown);
|
|
||||||
this.element.addEventListener('keyup', this.handleKeyUp);
|
|
||||||
}
|
|
||||||
release() {
|
|
||||||
this.active = false;
|
|
||||||
this.element.removeEventListener('keydown', this.handleKeyDown);
|
|
||||||
this.element.removeEventListener('keyup', this.handleKeyUp);
|
|
||||||
}
|
|
||||||
getState() {
|
|
||||||
const state = {
|
|
||||||
keysDown: new Map(this.keysDown),
|
|
||||||
keysJustPressed: new Map(this.keysJustPressed),
|
|
||||||
keysJustReleased: new Map(this.keysJustReleased)
|
|
||||||
};
|
|
||||||
this.keysJustPressed.clear();
|
|
||||||
this.keysJustReleased.clear();
|
|
||||||
return state;
|
|
||||||
}
|
|
||||||
handleKeyDown(event) {
|
|
||||||
if (this.active && this.preventDefault)
|
|
||||||
event.preventDefault();
|
|
||||||
if (this.keysDown.get(event.keyCode))
|
|
||||||
return;
|
|
||||||
this.keysDown.set(event.keyCode, true);
|
|
||||||
this.keysJustPressed.set(event.keyCode, true);
|
|
||||||
this.keysJustReleased.set(event.keyCode, false);
|
|
||||||
}
|
|
||||||
handleKeyUp(event) {
|
|
||||||
if (this.active && this.preventDefault)
|
|
||||||
event.preventDefault();
|
|
||||||
if (!this.keysDown.get(event.keyCode))
|
|
||||||
return;
|
|
||||||
this.keysDown.set(event.keyCode, false);
|
|
||||||
this.keysJustPressed.set(event.keyCode, false);
|
|
||||||
this.keysJustReleased.set(event.keyCode, true);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,34 +0,0 @@
|
||||||
import { BaseInput } from './base-input';
|
|
||||||
export declare class Mouse extends BaseInput {
|
|
||||||
private mousePosition;
|
|
||||||
private mouseDelta;
|
|
||||||
private mouseWheel;
|
|
||||||
private mouseButtons;
|
|
||||||
constructor(element: HTMLElement);
|
|
||||||
capture(): void;
|
|
||||||
release(): void;
|
|
||||||
getState(): IMouse;
|
|
||||||
private handleMouseDown;
|
|
||||||
private handleMouseMove;
|
|
||||||
private handleMouseUp;
|
|
||||||
private handlePointerChange;
|
|
||||||
}
|
|
||||||
export declare class Position {
|
|
||||||
x: number;
|
|
||||||
y: number;
|
|
||||||
}
|
|
||||||
export declare class MouseButtons {
|
|
||||||
keysDown: Map<number, boolean>;
|
|
||||||
keysJustPressed: Map<number, boolean>;
|
|
||||||
keysJustReleased: Map<number, boolean>;
|
|
||||||
}
|
|
||||||
export declare class Delta {
|
|
||||||
x: number;
|
|
||||||
y: number;
|
|
||||||
}
|
|
||||||
export interface IMouse {
|
|
||||||
mouseButtons: MouseButtons;
|
|
||||||
mousePosition: Position;
|
|
||||||
mouseWheel: Delta;
|
|
||||||
mouseDelta: Delta;
|
|
||||||
}
|
|
|
@ -1,87 +0,0 @@
|
||||||
import { BaseInput } from './base-input';
|
|
||||||
export class Mouse extends BaseInput {
|
|
||||||
constructor(element) {
|
|
||||||
super(element);
|
|
||||||
this.mousePosition = new Position();
|
|
||||||
this.mouseDelta = new Delta();
|
|
||||||
this.mouseWheel = new Delta();
|
|
||||||
this.mouseButtons = new MouseButtons();
|
|
||||||
}
|
|
||||||
capture() {
|
|
||||||
this.handleMouseDown = this.handleMouseDown.bind(this);
|
|
||||||
this.handleMouseMove = this.handleMouseMove.bind(this);
|
|
||||||
this.handleMouseUp = this.handleMouseUp.bind(this);
|
|
||||||
this.handlePointerChange = this.handlePointerChange.bind(this);
|
|
||||||
this.active = true;
|
|
||||||
this.element.addEventListener('mousedown', this.handleMouseDown);
|
|
||||||
this.element.addEventListener('mousemove', this.handleMouseMove);
|
|
||||||
this.element.addEventListener('mouseup', this.handleMouseUp);
|
|
||||||
document.addEventListener('pointerlockchange', this.handlePointerChange);
|
|
||||||
}
|
|
||||||
release() {
|
|
||||||
this.active = false;
|
|
||||||
this.element.removeEventListener('mousedown', this.handleMouseDown);
|
|
||||||
this.element.removeEventListener('mousemove', this.handleMouseMove);
|
|
||||||
this.element.removeEventListener('mouseup', this.handleMouseUp);
|
|
||||||
}
|
|
||||||
getState() {
|
|
||||||
const { mouseButtons, mouseDelta, mousePosition, mouseWheel } = this;
|
|
||||||
const state = {
|
|
||||||
mouseButtons: {
|
|
||||||
keysDown: new Map(this.mouseButtons.keysDown),
|
|
||||||
keysJustPressed: new Map(this.mouseButtons.keysJustPressed),
|
|
||||||
keysJustReleased: new Map(this.mouseButtons.keysJustReleased)
|
|
||||||
},
|
|
||||||
mouseDelta,
|
|
||||||
mousePosition,
|
|
||||||
mouseWheel
|
|
||||||
};
|
|
||||||
this.mouseButtons.keysJustPressed.clear();
|
|
||||||
this.mouseButtons.keysJustReleased.clear();
|
|
||||||
this.mouseDelta.x = 0;
|
|
||||||
this.mouseDelta.y = 0;
|
|
||||||
return state;
|
|
||||||
}
|
|
||||||
handleMouseDown(event) {
|
|
||||||
if (this.active)
|
|
||||||
event.preventDefault();
|
|
||||||
this.mouseButtons.keysDown.set(event.button, true);
|
|
||||||
this.mouseButtons.keysJustPressed.set(event.button, true);
|
|
||||||
this.mouseButtons.keysJustReleased.set(event.button, false);
|
|
||||||
}
|
|
||||||
handleMouseMove(event) {
|
|
||||||
if (this.active)
|
|
||||||
event.preventDefault();
|
|
||||||
this.mousePosition.x = event.clientX;
|
|
||||||
this.mousePosition.y = event.clientY;
|
|
||||||
this.mouseDelta.x = event.movementX;
|
|
||||||
this.mouseDelta.y = event.movementY;
|
|
||||||
}
|
|
||||||
handleMouseUp(event) {
|
|
||||||
if (this.active)
|
|
||||||
event.preventDefault();
|
|
||||||
this.mouseButtons.keysJustReleased.set(event.button, true);
|
|
||||||
this.mouseButtons.keysDown.set(event.button, false);
|
|
||||||
this.mouseButtons.keysJustPressed.set(event.button, false);
|
|
||||||
}
|
|
||||||
handlePointerChange() {
|
|
||||||
if (document.pointerLockElement !== this.element) {
|
|
||||||
this.element.addEventListener('click', () => {
|
|
||||||
this.element.requestPointerLock();
|
|
||||||
}, {
|
|
||||||
once: true
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
export class Position {
|
|
||||||
}
|
|
||||||
export class MouseButtons {
|
|
||||||
constructor() {
|
|
||||||
this.keysDown = new Map();
|
|
||||||
this.keysJustPressed = new Map();
|
|
||||||
this.keysJustReleased = new Map();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
export class Delta {
|
|
||||||
}
|
|
|
@ -1,4 +0,0 @@
|
||||||
import { IKeyboard } from '../inputs/keyboard';
|
|
||||||
export interface State {
|
|
||||||
keyboard?: IKeyboard;
|
|
||||||
}
|
|
|
@ -1 +0,0 @@
|
||||||
export {};
|
|
|
@ -1,122 +0,0 @@
|
||||||
export declare let KeyCodes: {
|
|
||||||
CANCEL: number;
|
|
||||||
HELP: number;
|
|
||||||
BACK_SPACE: number;
|
|
||||||
TAB: number;
|
|
||||||
CLEAR: number;
|
|
||||||
RETURN: number;
|
|
||||||
ENTER: number;
|
|
||||||
SHIFT: number;
|
|
||||||
CONTROL: number;
|
|
||||||
ALT: number;
|
|
||||||
PAUSE: number;
|
|
||||||
CAPS_LOCK: number;
|
|
||||||
ESCAPE: number;
|
|
||||||
SPACE: number;
|
|
||||||
PAGE_UP: number;
|
|
||||||
PAGE_DOWN: number;
|
|
||||||
END: number;
|
|
||||||
HOME: number;
|
|
||||||
LEFT: number;
|
|
||||||
UP: number;
|
|
||||||
RIGHT: number;
|
|
||||||
DOWN: number;
|
|
||||||
PRINTSCREEN: number;
|
|
||||||
INSERT: number;
|
|
||||||
DELETE: number;
|
|
||||||
0: number;
|
|
||||||
1: number;
|
|
||||||
2: number;
|
|
||||||
3: number;
|
|
||||||
4: number;
|
|
||||||
5: number;
|
|
||||||
6: number;
|
|
||||||
7: number;
|
|
||||||
8: number;
|
|
||||||
9: number;
|
|
||||||
SEMICOLON: number;
|
|
||||||
EQUALS: number;
|
|
||||||
A: number;
|
|
||||||
B: number;
|
|
||||||
C: number;
|
|
||||||
D: number;
|
|
||||||
E: number;
|
|
||||||
F: number;
|
|
||||||
G: number;
|
|
||||||
H: number;
|
|
||||||
I: number;
|
|
||||||
J: number;
|
|
||||||
K: number;
|
|
||||||
L: number;
|
|
||||||
M: number;
|
|
||||||
N: number;
|
|
||||||
O: number;
|
|
||||||
P: number;
|
|
||||||
Q: number;
|
|
||||||
R: number;
|
|
||||||
S: number;
|
|
||||||
T: number;
|
|
||||||
U: number;
|
|
||||||
V: number;
|
|
||||||
W: number;
|
|
||||||
X: number;
|
|
||||||
Y: number;
|
|
||||||
Z: number;
|
|
||||||
CONTEXT_MENU: number;
|
|
||||||
NUMPAD0: number;
|
|
||||||
NUMPAD1: number;
|
|
||||||
NUMPAD2: number;
|
|
||||||
NUMPAD3: number;
|
|
||||||
NUMPAD4: number;
|
|
||||||
NUMPAD5: number;
|
|
||||||
NUMPAD6: number;
|
|
||||||
NUMPAD7: number;
|
|
||||||
NUMPAD8: number;
|
|
||||||
NUMPAD9: number;
|
|
||||||
MULTIPLY: number;
|
|
||||||
ADD: number;
|
|
||||||
SEPARATOR: number;
|
|
||||||
SUBTRACT: number;
|
|
||||||
DECIMAL: number;
|
|
||||||
DIVIDE: number;
|
|
||||||
F1: number;
|
|
||||||
F2: number;
|
|
||||||
F3: number;
|
|
||||||
F4: number;
|
|
||||||
F5: number;
|
|
||||||
F6: number;
|
|
||||||
F7: number;
|
|
||||||
F8: number;
|
|
||||||
F9: number;
|
|
||||||
F10: number;
|
|
||||||
F11: number;
|
|
||||||
F12: number;
|
|
||||||
F13: number;
|
|
||||||
F14: number;
|
|
||||||
F15: number;
|
|
||||||
F16: number;
|
|
||||||
F17: number;
|
|
||||||
F18: number;
|
|
||||||
F19: number;
|
|
||||||
F20: number;
|
|
||||||
F21: number;
|
|
||||||
F22: number;
|
|
||||||
F23: number;
|
|
||||||
F24: number;
|
|
||||||
NUM_LOCK: number;
|
|
||||||
SCROLL_LOCK: number;
|
|
||||||
COMMA: number;
|
|
||||||
PERIOD: number;
|
|
||||||
SLASH: number;
|
|
||||||
BACK_QUOTE: number;
|
|
||||||
OPEN_BRACKET: number;
|
|
||||||
BACK_SLASH: number;
|
|
||||||
CLOSE_BRACKET: number;
|
|
||||||
QUOTE: number;
|
|
||||||
META: number;
|
|
||||||
};
|
|
||||||
export declare let MouseCodes: {
|
|
||||||
LEFT: number;
|
|
||||||
RIGHT: number;
|
|
||||||
MIDDLE: number;
|
|
||||||
};
|
|
|
@ -1,122 +0,0 @@
|
||||||
export let KeyCodes = {
|
|
||||||
CANCEL: 3,
|
|
||||||
HELP: 6,
|
|
||||||
BACK_SPACE: 8,
|
|
||||||
TAB: 9,
|
|
||||||
CLEAR: 12,
|
|
||||||
RETURN: 13,
|
|
||||||
ENTER: 14,
|
|
||||||
SHIFT: 16,
|
|
||||||
CONTROL: 17,
|
|
||||||
ALT: 18,
|
|
||||||
PAUSE: 19,
|
|
||||||
CAPS_LOCK: 20,
|
|
||||||
ESCAPE: 27,
|
|
||||||
SPACE: 32,
|
|
||||||
PAGE_UP: 33,
|
|
||||||
PAGE_DOWN: 34,
|
|
||||||
END: 35,
|
|
||||||
HOME: 36,
|
|
||||||
LEFT: 37,
|
|
||||||
UP: 38,
|
|
||||||
RIGHT: 39,
|
|
||||||
DOWN: 40,
|
|
||||||
PRINTSCREEN: 44,
|
|
||||||
INSERT: 45,
|
|
||||||
DELETE: 46,
|
|
||||||
0: 48,
|
|
||||||
1: 49,
|
|
||||||
2: 50,
|
|
||||||
3: 51,
|
|
||||||
4: 52,
|
|
||||||
5: 53,
|
|
||||||
6: 54,
|
|
||||||
7: 55,
|
|
||||||
8: 56,
|
|
||||||
9: 57,
|
|
||||||
SEMICOLON: 59,
|
|
||||||
EQUALS: 61,
|
|
||||||
A: 65,
|
|
||||||
B: 66,
|
|
||||||
C: 67,
|
|
||||||
D: 68,
|
|
||||||
E: 69,
|
|
||||||
F: 70,
|
|
||||||
G: 71,
|
|
||||||
H: 72,
|
|
||||||
I: 73,
|
|
||||||
J: 74,
|
|
||||||
K: 75,
|
|
||||||
L: 76,
|
|
||||||
M: 77,
|
|
||||||
N: 78,
|
|
||||||
O: 79,
|
|
||||||
P: 80,
|
|
||||||
Q: 81,
|
|
||||||
R: 82,
|
|
||||||
S: 83,
|
|
||||||
T: 84,
|
|
||||||
U: 85,
|
|
||||||
V: 86,
|
|
||||||
W: 87,
|
|
||||||
X: 88,
|
|
||||||
Y: 89,
|
|
||||||
Z: 90,
|
|
||||||
CONTEXT_MENU: 93,
|
|
||||||
NUMPAD0: 96,
|
|
||||||
NUMPAD1: 97,
|
|
||||||
NUMPAD2: 98,
|
|
||||||
NUMPAD3: 99,
|
|
||||||
NUMPAD4: 100,
|
|
||||||
NUMPAD5: 101,
|
|
||||||
NUMPAD6: 102,
|
|
||||||
NUMPAD7: 103,
|
|
||||||
NUMPAD8: 104,
|
|
||||||
NUMPAD9: 105,
|
|
||||||
MULTIPLY: 106,
|
|
||||||
ADD: 107,
|
|
||||||
SEPARATOR: 108,
|
|
||||||
SUBTRACT: 109,
|
|
||||||
DECIMAL: 110,
|
|
||||||
DIVIDE: 111,
|
|
||||||
F1: 112,
|
|
||||||
F2: 113,
|
|
||||||
F3: 114,
|
|
||||||
F4: 115,
|
|
||||||
F5: 116,
|
|
||||||
F6: 117,
|
|
||||||
F7: 118,
|
|
||||||
F8: 119,
|
|
||||||
F9: 120,
|
|
||||||
F10: 121,
|
|
||||||
F11: 122,
|
|
||||||
F12: 123,
|
|
||||||
F13: 124,
|
|
||||||
F14: 125,
|
|
||||||
F15: 126,
|
|
||||||
F16: 127,
|
|
||||||
F17: 128,
|
|
||||||
F18: 129,
|
|
||||||
F19: 130,
|
|
||||||
F20: 131,
|
|
||||||
F21: 132,
|
|
||||||
F22: 133,
|
|
||||||
F23: 134,
|
|
||||||
F24: 135,
|
|
||||||
NUM_LOCK: 144,
|
|
||||||
SCROLL_LOCK: 145,
|
|
||||||
COMMA: 188,
|
|
||||||
PERIOD: 190,
|
|
||||||
SLASH: 191,
|
|
||||||
BACK_QUOTE: 192,
|
|
||||||
OPEN_BRACKET: 219,
|
|
||||||
BACK_SLASH: 220,
|
|
||||||
CLOSE_BRACKET: 221,
|
|
||||||
QUOTE: 222,
|
|
||||||
META: 224
|
|
||||||
};
|
|
||||||
export let MouseCodes = {
|
|
||||||
LEFT: 0,
|
|
||||||
RIGHT: 1,
|
|
||||||
MIDDLE: 2
|
|
||||||
};
|
|
|
@ -1,33 +0,0 @@
|
||||||
{
|
|
||||||
"name": "audiogame-tools",
|
|
||||||
"version": "1.0.0",
|
|
||||||
"description": "",
|
|
||||||
"main": "index.js",
|
|
||||||
"scripts": {
|
|
||||||
"test": "echo \"Error: no test specified\" && exit 1",
|
|
||||||
"lint": "eslint . --ext .ts",
|
|
||||||
"format": "prettier --config .prettierrc engine/**/*.ts --write",
|
|
||||||
"compile:engine": "tsc",
|
|
||||||
"watch:engine": "tsc -w",
|
|
||||||
"bundle:engine": "webpack --config webpack.engine.js"
|
|
||||||
},
|
|
||||||
"keywords": [],
|
|
||||||
"author": "",
|
|
||||||
"license": "ISC",
|
|
||||||
"dependencies": {
|
|
||||||
"eventemitter3": "^4.0.7",
|
|
||||||
"yaml": "^1.10.0"
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
"@babel/core": "^7.12.3",
|
|
||||||
"@babel/preset-env": "^7.12.1",
|
|
||||||
"@typescript-eslint/eslint-plugin": "^4.7.0",
|
|
||||||
"@typescript-eslint/parser": "^4.7.0",
|
|
||||||
"eslint": "^7.13.0",
|
|
||||||
"prettier": "^2.1.2",
|
|
||||||
"ts-loader": "^8.0.11",
|
|
||||||
"typescript": "^4.0.5",
|
|
||||||
"webpack": "^5.4.0",
|
|
||||||
"webpack-cli": "^4.2.0"
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,2 +0,0 @@
|
||||||
import { PhysicsObject } from './object';
|
|
||||||
export declare function AABB(obj1: PhysicsObject, obj2: PhysicsObject): boolean;
|
|
|
@ -1,17 +0,0 @@
|
||||||
export function AABB(obj1, obj2) {
|
|
||||||
if (checkOverlap(obj1.position.x, obj1.dimensions.x, obj2.position.x, obj2.dimensions.x)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else if (checkOverlap(obj1.position.y, obj1.dimensions.y, obj2.position.y, obj2.dimensions.y)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else if (checkOverlap(obj1.position.z, obj1.dimensions.z, obj2.position.z, obj2.dimensions.z)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
function checkOverlap(x, w, yx, yw) {
|
|
||||||
if (x > yx || x < yx + yw || x + w > x || x + w < yx + yw) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,7 +0,0 @@
|
||||||
import { Vec3 } from './vec3';
|
|
||||||
export declare class PhysicsObject {
|
|
||||||
position: Vec3;
|
|
||||||
dimensions: Vec3;
|
|
||||||
velocity: Vec3;
|
|
||||||
affectedByGravity: boolean;
|
|
||||||
}
|
|
|
@ -1,2 +0,0 @@
|
||||||
export class PhysicsObject {
|
|
||||||
}
|
|
|
@ -1,39 +0,0 @@
|
||||||
import { PhysicsObject } from './object';
|
|
||||||
import { Vec3 } from './vec3';
|
|
||||||
export declare class Octree {
|
|
||||||
private dimensions;
|
|
||||||
private maxObjects;
|
|
||||||
private maxLevels;
|
|
||||||
root: OcTreeNode;
|
|
||||||
constructor(dimensions: Vec3, maxObjects?: number, maxLevels?: number);
|
|
||||||
insert(obj: PhysicsObject): void;
|
|
||||||
find(position: Vec3, dimensions: Vec3): PhysicsObject[];
|
|
||||||
}
|
|
||||||
export declare class OcTreeNode {
|
|
||||||
private position;
|
|
||||||
private dimensions;
|
|
||||||
private maxLevels;
|
|
||||||
private maxObjects;
|
|
||||||
private currentLevel;
|
|
||||||
objects: PhysicsObject[];
|
|
||||||
nodes: OcTreeNode[];
|
|
||||||
constructor(position: Vec3, dimensions: Vec3, maxLevels: number, maxObjects: number, currentLevel?: number);
|
|
||||||
insert(obj: PhysicsObject): any;
|
|
||||||
find(x: number, y: number, z: number, xw: number, yh: number, zd: number): PhysicsObject[];
|
|
||||||
split(): void;
|
|
||||||
private distributeObjectsToNodes;
|
|
||||||
getIndex(x: number, y: number, z: number): Direction;
|
|
||||||
getIndeciesForRect(x: number, y: number, z: number, xw: number, yh: number, zd: number): Direction[];
|
|
||||||
}
|
|
||||||
declare enum Direction {
|
|
||||||
AboveUpperLeft = 0,
|
|
||||||
AboveUpperRight = 1,
|
|
||||||
AboveLowerRight = 2,
|
|
||||||
AboveLowerLeft = 3,
|
|
||||||
BelowUpperLeft = 4,
|
|
||||||
BelowUpperRight = 5,
|
|
||||||
BelowLowerRight = 6,
|
|
||||||
BelowLowerLeft = 7,
|
|
||||||
Here = 8
|
|
||||||
}
|
|
||||||
export {};
|
|
|
@ -1,206 +0,0 @@
|
||||||
import { Vec3 } from './vec3';
|
|
||||||
export class Octree {
|
|
||||||
constructor(dimensions, maxObjects = 10, maxLevels = 10) {
|
|
||||||
this.dimensions = dimensions;
|
|
||||||
this.maxObjects = maxObjects;
|
|
||||||
this.maxLevels = maxLevels;
|
|
||||||
this.root = new OcTreeNode(new Vec3({
|
|
||||||
x: 0,
|
|
||||||
y: 0,
|
|
||||||
z: 0
|
|
||||||
}), this.dimensions, maxLevels, maxObjects, 0);
|
|
||||||
}
|
|
||||||
insert(obj) {
|
|
||||||
this.root.insert(obj);
|
|
||||||
}
|
|
||||||
find(position, dimensions) {
|
|
||||||
return this.root.find(position.x, position.y, position.z, dimensions.x, dimensions.y, dimensions.z);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
export class OcTreeNode {
|
|
||||||
constructor(position, dimensions, maxLevels, maxObjects, currentLevel = 0) {
|
|
||||||
this.position = position;
|
|
||||||
this.dimensions = dimensions;
|
|
||||||
this.maxLevels = maxLevels;
|
|
||||||
this.maxObjects = maxObjects;
|
|
||||||
this.currentLevel = currentLevel;
|
|
||||||
this.objects = [];
|
|
||||||
this.nodes = [];
|
|
||||||
}
|
|
||||||
insert(obj) {
|
|
||||||
const index = this.getIndex(obj.position.x, obj.position.y, obj.position.z);
|
|
||||||
if (index === Direction.Here) {
|
|
||||||
this.objects.push(obj);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return this.nodes[index].insert(obj);
|
|
||||||
}
|
|
||||||
if (this.objects.length > this.maxObjects &&
|
|
||||||
this.currentLevel < this.maxLevels) {
|
|
||||||
this.split();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
find(x, y, z, xw, yh, zd) {
|
|
||||||
if (this.nodes.length < 1) {
|
|
||||||
return this.objects;
|
|
||||||
}
|
|
||||||
const indecies = this.getIndeciesForRect(x, y, z, xw, yh, zd);
|
|
||||||
let results = [];
|
|
||||||
for (let i = 0; i < indecies.length - 1; i++) {
|
|
||||||
let res = this.nodes[indecies[i]].find(x, y, z, xw, yh, zd);
|
|
||||||
results.push([...res]);
|
|
||||||
}
|
|
||||||
return results;
|
|
||||||
}
|
|
||||||
split() {
|
|
||||||
const halfWidth = this.dimensions.x / 2;
|
|
||||||
const halfHeight = this.dimensions.y / 2;
|
|
||||||
const halfDepth = this.dimensions.z / 2;
|
|
||||||
this.nodes[Direction.AboveUpperLeft] = new OcTreeNode(new Vec3({
|
|
||||||
x: this.position.x,
|
|
||||||
y: this.position.y,
|
|
||||||
z: this.position.z + halfDepth
|
|
||||||
}), new Vec3({
|
|
||||||
x: halfWidth,
|
|
||||||
y: halfHeight,
|
|
||||||
z: halfDepth
|
|
||||||
}), this.maxLevels, this.maxObjects, this.currentLevel++);
|
|
||||||
this.nodes[Direction.AboveUpperRight] = new OcTreeNode(new Vec3({
|
|
||||||
x: this.position.x + halfWidth,
|
|
||||||
y: this.position.y,
|
|
||||||
z: this.position.z + halfDepth
|
|
||||||
}), new Vec3({
|
|
||||||
x: halfWidth,
|
|
||||||
y: halfHeight,
|
|
||||||
z: halfDepth
|
|
||||||
}), this.maxLevels, this.maxObjects, this.currentLevel++);
|
|
||||||
this.nodes[Direction.AboveLowerRight] = new OcTreeNode(new Vec3({
|
|
||||||
x: this.position.x + halfWidth,
|
|
||||||
y: this.position.y + halfHeight,
|
|
||||||
z: this.position.z + halfDepth
|
|
||||||
}), new Vec3({
|
|
||||||
x: halfWidth,
|
|
||||||
y: halfHeight,
|
|
||||||
z: halfDepth
|
|
||||||
}), this.maxLevels, this.maxObjects, this.currentLevel++);
|
|
||||||
this.nodes[Direction.AboveLowerLeft] = new OcTreeNode(new Vec3({
|
|
||||||
x: this.position.x,
|
|
||||||
y: this.position.y + halfHeight,
|
|
||||||
z: this.position.z + halfDepth
|
|
||||||
}), new Vec3({
|
|
||||||
x: halfWidth,
|
|
||||||
y: halfHeight,
|
|
||||||
z: halfDepth
|
|
||||||
}), this.maxLevels, this.maxObjects, this.currentLevel++);
|
|
||||||
this.nodes[Direction.BelowUpperLeft] = new OcTreeNode(new Vec3({
|
|
||||||
x: this.position.x,
|
|
||||||
y: this.position.y,
|
|
||||||
z: this.position.z
|
|
||||||
}), new Vec3({
|
|
||||||
x: halfWidth,
|
|
||||||
y: halfHeight,
|
|
||||||
z: halfDepth
|
|
||||||
}), this.maxLevels, this.maxObjects, this.currentLevel++);
|
|
||||||
this.nodes[Direction.BelowUpperRight] = new OcTreeNode(new Vec3({
|
|
||||||
x: this.position.x + halfWidth,
|
|
||||||
y: this.position.y,
|
|
||||||
z: this.position.z
|
|
||||||
}), new Vec3({
|
|
||||||
x: halfWidth,
|
|
||||||
y: halfHeight,
|
|
||||||
z: halfDepth
|
|
||||||
}), this.maxLevels, this.maxObjects, this.currentLevel++);
|
|
||||||
this.nodes[Direction.BelowLowerRight] = new OcTreeNode(new Vec3({
|
|
||||||
x: this.position.x + halfWidth,
|
|
||||||
y: this.position.y + halfHeight,
|
|
||||||
z: this.position.z
|
|
||||||
}), new Vec3({
|
|
||||||
x: halfWidth,
|
|
||||||
y: halfHeight,
|
|
||||||
z: halfDepth
|
|
||||||
}), this.maxLevels, this.maxObjects, this.currentLevel++);
|
|
||||||
this.nodes[Direction.BelowLowerLeft] = new OcTreeNode(new Vec3({
|
|
||||||
x: this.position.x,
|
|
||||||
y: this.position.y + halfHeight,
|
|
||||||
z: this.position.z
|
|
||||||
}), new Vec3({
|
|
||||||
x: halfWidth,
|
|
||||||
y: halfHeight,
|
|
||||||
z: halfDepth
|
|
||||||
}), this.maxLevels, this.maxObjects, this.currentLevel++);
|
|
||||||
this.distributeObjectsToNodes();
|
|
||||||
}
|
|
||||||
distributeObjectsToNodes() {
|
|
||||||
if (this.nodes.length < 8) {
|
|
||||||
this.split();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.objects.forEach((obj) => {
|
|
||||||
const direction = this.getIndex(obj.position.x, obj.position.y, obj.position.z);
|
|
||||||
this.nodes[direction].insert(obj);
|
|
||||||
});
|
|
||||||
this.objects = [];
|
|
||||||
}
|
|
||||||
getIndex(x, y, z) {
|
|
||||||
if (this.nodes.length === 0) {
|
|
||||||
return Direction.Here;
|
|
||||||
}
|
|
||||||
const halfWidth = this.dimensions.x / 2;
|
|
||||||
const halfHeight = this.dimensions.y / 2;
|
|
||||||
const halfDepth = this.dimensions.z / 2;
|
|
||||||
const isBelow = z < this.position.z + halfDepth;
|
|
||||||
const isLeft = x < this.position.x + halfWidth;
|
|
||||||
const isUpper = y > this.position.y + halfHeight;
|
|
||||||
if (isBelow) {
|
|
||||||
if (isLeft) {
|
|
||||||
if (isUpper)
|
|
||||||
return Direction.AboveUpperLeft;
|
|
||||||
else
|
|
||||||
return Direction.AboveLowerLeft;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (isUpper)
|
|
||||||
return Direction.AboveUpperRight;
|
|
||||||
else
|
|
||||||
return Direction.AboveLowerRight;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (isLeft) {
|
|
||||||
if (isUpper)
|
|
||||||
return Direction.BelowUpperLeft;
|
|
||||||
else
|
|
||||||
return Direction.BelowLowerLeft;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (isUpper)
|
|
||||||
return Direction.BelowUpperRight;
|
|
||||||
else
|
|
||||||
return Direction.BelowLowerRight;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
getIndeciesForRect(x, y, z, xw, yh, zd) {
|
|
||||||
if (!(x > this.position.x && x < this.position.x + this.dimensions.x) ||
|
|
||||||
!(y > this.position.y && y < this.position.y + this.dimensions.y) ||
|
|
||||||
!(z > this.position.z && z < this.position.z + this.dimensions.z)) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
let indecies = [];
|
|
||||||
indecies.push(this.getIndex(x, y, z));
|
|
||||||
indecies.push(this.getIndex(x + xw, y + yh, z + zd));
|
|
||||||
return indecies;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
var Direction;
|
|
||||||
(function (Direction) {
|
|
||||||
Direction[Direction["AboveUpperLeft"] = 0] = "AboveUpperLeft";
|
|
||||||
Direction[Direction["AboveUpperRight"] = 1] = "AboveUpperRight";
|
|
||||||
Direction[Direction["AboveLowerRight"] = 2] = "AboveLowerRight";
|
|
||||||
Direction[Direction["AboveLowerLeft"] = 3] = "AboveLowerLeft";
|
|
||||||
Direction[Direction["BelowUpperLeft"] = 4] = "BelowUpperLeft";
|
|
||||||
Direction[Direction["BelowUpperRight"] = 5] = "BelowUpperRight";
|
|
||||||
Direction[Direction["BelowLowerRight"] = 6] = "BelowLowerRight";
|
|
||||||
Direction[Direction["BelowLowerLeft"] = 7] = "BelowLowerLeft";
|
|
||||||
Direction[Direction["Here"] = 8] = "Here";
|
|
||||||
})(Direction || (Direction = {}));
|
|
|
@ -1,38 +0,0 @@
|
||||||
import { PhysicsObject } from "./object";
|
|
||||||
import { Vec3 } from "./vec3";
|
|
||||||
export declare class Octtree {
|
|
||||||
private dimensions;
|
|
||||||
private maxObjects;
|
|
||||||
private maxLevels;
|
|
||||||
root: OctTreeNode;
|
|
||||||
constructor(dimensions: Vec3, maxObjects?: number, maxLevels?: number);
|
|
||||||
insert(obj: PhysicsObject): void;
|
|
||||||
find(position: Vec3, dimensions: Vec3): PhysicsObject[];
|
|
||||||
}
|
|
||||||
export declare class OctTreeNode {
|
|
||||||
private position;
|
|
||||||
private dimensions;
|
|
||||||
private maxLevels;
|
|
||||||
private maxObjects;
|
|
||||||
objects: PhysicsObject[];
|
|
||||||
nodes: OctTreeNode[];
|
|
||||||
constructor(position: Vec3, dimensions: Vec3, maxLevels: number, maxObjects: number);
|
|
||||||
insert(obj: PhysicsObject): void;
|
|
||||||
find(position: Vec3, dimensions: Vec3): PhysicsObject[];
|
|
||||||
split(): void;
|
|
||||||
private distributeObjectsToNodes;
|
|
||||||
getIndex(x: number, y: number, z: number): Direction;
|
|
||||||
getIndeciesForRect(position: Vec3, dimensions: Vec3): Set<Direction>;
|
|
||||||
}
|
|
||||||
declare enum Direction {
|
|
||||||
AboveUpperLeft = 0,
|
|
||||||
AboveUpperRight = 1,
|
|
||||||
AboveLowerRight = 2,
|
|
||||||
AboveLowerLeft = 3,
|
|
||||||
BelowUpperLeft = 4,
|
|
||||||
BelowUpperRight = 5,
|
|
||||||
BelowLowerRight = 6,
|
|
||||||
BelowLowerLeft = 7,
|
|
||||||
Here = 8
|
|
||||||
}
|
|
||||||
export {};
|
|
|
@ -1,193 +0,0 @@
|
||||||
import { Vec3 } from "./vec3";
|
|
||||||
export class Octtree {
|
|
||||||
constructor(dimensions, maxObjects = 10, maxLevels = 10) {
|
|
||||||
this.dimensions = dimensions;
|
|
||||||
this.maxObjects = maxObjects;
|
|
||||||
this.maxLevels = maxLevels;
|
|
||||||
this.root = new OctTreeNode(new Vec3({
|
|
||||||
x: 0,
|
|
||||||
y: 0,
|
|
||||||
z: 0
|
|
||||||
}), this.dimensions, maxLevels, maxObjects);
|
|
||||||
}
|
|
||||||
insert(obj) {
|
|
||||||
this.root.insert(obj);
|
|
||||||
}
|
|
||||||
find(position, dimensions) {
|
|
||||||
return this.root.find(position, dimensions);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
export class OctTreeNode {
|
|
||||||
constructor(position, dimensions, maxLevels, maxObjects) {
|
|
||||||
this.position = position;
|
|
||||||
this.dimensions = dimensions;
|
|
||||||
this.maxLevels = maxLevels;
|
|
||||||
this.maxObjects = maxObjects;
|
|
||||||
this.objects = [];
|
|
||||||
this.nodes = [];
|
|
||||||
}
|
|
||||||
insert(obj) {
|
|
||||||
this.objects.push(obj);
|
|
||||||
if (this.objects.length > this.maxObjects) {
|
|
||||||
this.split();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
find(position, dimensions) {
|
|
||||||
if (!this.nodes.length) {
|
|
||||||
return this.objects;
|
|
||||||
}
|
|
||||||
const indecies = this.getIndeciesForRect(position, dimensions);
|
|
||||||
let results = [];
|
|
||||||
indecies.forEach((index) => {
|
|
||||||
let res = this.nodes[index].find(position, dimensions);
|
|
||||||
res.forEach((obj) => results.push(obj));
|
|
||||||
});
|
|
||||||
return results;
|
|
||||||
}
|
|
||||||
split() {
|
|
||||||
const halfWidth = this.dimensions.x / 2;
|
|
||||||
const halfHeight = this.dimensions.y / 2;
|
|
||||||
const halfDepth = this.dimensions.z / 2;
|
|
||||||
this.nodes[Direction.AboveUpperLeft] = new OctTreeNode(new Vec3({
|
|
||||||
x: this.position.x,
|
|
||||||
y: this.position.y,
|
|
||||||
z: this.position.z + halfDepth
|
|
||||||
}), new Vec3({
|
|
||||||
x: halfWidth,
|
|
||||||
y: halfHeight,
|
|
||||||
z: halfDepth
|
|
||||||
}), this.maxLevels, this.maxObjects);
|
|
||||||
this.nodes[Direction.AboveUpperRight] = new OctTreeNode(new Vec3({
|
|
||||||
x: this.position.x + halfWidth,
|
|
||||||
y: this.position.y,
|
|
||||||
z: this.position.z + halfDepth
|
|
||||||
}), new Vec3({
|
|
||||||
x: halfWidth,
|
|
||||||
y: halfHeight,
|
|
||||||
z: halfDepth
|
|
||||||
}), this.maxLevels, this.maxObjects);
|
|
||||||
this.nodes[Direction.AboveLowerRight] = new OctTreeNode(new Vec3({
|
|
||||||
x: this.position.x + halfWidth,
|
|
||||||
y: this.position.y + halfHeight,
|
|
||||||
z: this.position.z + halfDepth
|
|
||||||
}), new Vec3({
|
|
||||||
x: halfWidth,
|
|
||||||
y: halfHeight,
|
|
||||||
z: halfDepth
|
|
||||||
}), this.maxLevels, this.maxObjects);
|
|
||||||
this.nodes[Direction.AboveLowerLeft] = new OctTreeNode(new Vec3({
|
|
||||||
x: this.position.x,
|
|
||||||
y: this.position.y + halfHeight,
|
|
||||||
z: this.position.z + halfDepth
|
|
||||||
}), new Vec3({
|
|
||||||
x: halfWidth,
|
|
||||||
y: halfHeight,
|
|
||||||
z: halfDepth
|
|
||||||
}), this.maxLevels, this.maxObjects);
|
|
||||||
this.nodes[Direction.BelowUpperLeft] = new OctTreeNode(new Vec3({
|
|
||||||
x: this.position.x,
|
|
||||||
y: this.position.y,
|
|
||||||
z: this.position.z
|
|
||||||
}), new Vec3({
|
|
||||||
x: halfWidth,
|
|
||||||
y: halfHeight,
|
|
||||||
z: halfDepth
|
|
||||||
}), this.maxLevels, this.maxObjects);
|
|
||||||
this.nodes[Direction.BelowUpperRight] = new OctTreeNode(new Vec3({
|
|
||||||
x: this.position.x + halfWidth,
|
|
||||||
y: this.position.y,
|
|
||||||
z: this.position.z
|
|
||||||
}), new Vec3({
|
|
||||||
x: halfWidth,
|
|
||||||
y: halfHeight,
|
|
||||||
z: halfDepth
|
|
||||||
}), this.maxLevels, this.maxObjects);
|
|
||||||
this.nodes[Direction.BelowLowerRight] = new OctTreeNode(new Vec3({
|
|
||||||
x: this.position.x + halfWidth,
|
|
||||||
y: this.position.y + halfHeight,
|
|
||||||
z: this.position.z
|
|
||||||
}), new Vec3({
|
|
||||||
x: halfWidth,
|
|
||||||
y: halfHeight,
|
|
||||||
z: halfDepth
|
|
||||||
}), this.maxLevels, this.maxObjects);
|
|
||||||
this.nodes[Direction.BelowLowerLeft] = new OctTreeNode(new Vec3({
|
|
||||||
x: this.position.x,
|
|
||||||
y: this.position.y + halfHeight,
|
|
||||||
z: this.position.z
|
|
||||||
}), new Vec3({
|
|
||||||
x: halfWidth,
|
|
||||||
y: halfHeight,
|
|
||||||
z: halfDepth
|
|
||||||
}), this.maxLevels, this.maxObjects);
|
|
||||||
this.distributeObjectsToNodes();
|
|
||||||
}
|
|
||||||
distributeObjectsToNodes() {
|
|
||||||
if (this.nodes.length < 8) {
|
|
||||||
this.split();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.objects.forEach((obj) => {
|
|
||||||
const direction = this.getIndex(obj.position.x, obj.position.y, obj.position.z);
|
|
||||||
this.nodes[direction].insert(obj);
|
|
||||||
});
|
|
||||||
this.objects = [];
|
|
||||||
}
|
|
||||||
getIndex(x, y, z) {
|
|
||||||
if (this.nodes.length === 0) {
|
|
||||||
return Direction.Here;
|
|
||||||
}
|
|
||||||
const halfWidth = this.dimensions.x / 2;
|
|
||||||
const halfHeight = this.dimensions.y / 2;
|
|
||||||
const halfDepth = this.dimensions.z / 2;
|
|
||||||
const isBelow = (z < this.position.z + halfDepth);
|
|
||||||
const isLeft = (x < this.position.x + halfWidth);
|
|
||||||
const isUpper = (y > this.position.y + halfHeight);
|
|
||||||
if (isBelow) {
|
|
||||||
if (isLeft) {
|
|
||||||
if (isUpper)
|
|
||||||
return Direction.AboveUpperLeft;
|
|
||||||
else
|
|
||||||
return Direction.AboveLowerLeft;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (isUpper)
|
|
||||||
return Direction.AboveUpperRight;
|
|
||||||
else
|
|
||||||
return Direction.AboveLowerRight;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (isLeft) {
|
|
||||||
if (isUpper)
|
|
||||||
return Direction.BelowUpperLeft;
|
|
||||||
else
|
|
||||||
return Direction.BelowLowerLeft;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (isUpper)
|
|
||||||
return Direction.BelowUpperRight;
|
|
||||||
else
|
|
||||||
return Direction.BelowLowerRight;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
getIndeciesForRect(position, dimensions) {
|
|
||||||
let indecies = new Set();
|
|
||||||
indecies.add(this.getIndex(position.x, position.y, position.z));
|
|
||||||
indecies.add(this.getIndex(position.x + dimensions.x, position.y + dimensions.y, position.z + dimensions.z));
|
|
||||||
return indecies;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
var Direction;
|
|
||||||
(function (Direction) {
|
|
||||||
Direction[Direction["AboveUpperLeft"] = 0] = "AboveUpperLeft";
|
|
||||||
Direction[Direction["AboveUpperRight"] = 1] = "AboveUpperRight";
|
|
||||||
Direction[Direction["AboveLowerRight"] = 2] = "AboveLowerRight";
|
|
||||||
Direction[Direction["AboveLowerLeft"] = 3] = "AboveLowerLeft";
|
|
||||||
Direction[Direction["BelowUpperLeft"] = 4] = "BelowUpperLeft";
|
|
||||||
Direction[Direction["BelowUpperRight"] = 5] = "BelowUpperRight";
|
|
||||||
Direction[Direction["BelowLowerRight"] = 6] = "BelowLowerRight";
|
|
||||||
Direction[Direction["BelowLowerLeft"] = 7] = "BelowLowerLeft";
|
|
||||||
Direction[Direction["Here"] = 8] = "Here";
|
|
||||||
})(Direction || (Direction = {}));
|
|
|
@ -1,13 +0,0 @@
|
||||||
export declare class Vec3 {
|
|
||||||
x: number;
|
|
||||||
y: number;
|
|
||||||
z: number;
|
|
||||||
constructor(values?: {
|
|
||||||
x: number;
|
|
||||||
y: number;
|
|
||||||
z: number;
|
|
||||||
});
|
|
||||||
add(vector: Vec3): void;
|
|
||||||
multiply(vector: Vec3): void;
|
|
||||||
clone(): Vec3;
|
|
||||||
}
|
|
|
@ -1,28 +0,0 @@
|
||||||
export class Vec3 {
|
|
||||||
constructor(values = {
|
|
||||||
x: 0,
|
|
||||||
y: 0,
|
|
||||||
z: 0
|
|
||||||
}) {
|
|
||||||
this.x = values.x;
|
|
||||||
this.y = values.y;
|
|
||||||
this.z = values.z;
|
|
||||||
}
|
|
||||||
add(vector) {
|
|
||||||
this.x += vector.x;
|
|
||||||
this.y += vector.y;
|
|
||||||
this.z += vector.z;
|
|
||||||
}
|
|
||||||
multiply(vector) {
|
|
||||||
this.x *= vector.x;
|
|
||||||
this.y *= vector.y;
|
|
||||||
this.z *= vector.z;
|
|
||||||
}
|
|
||||||
clone() {
|
|
||||||
return new Vec3({
|
|
||||||
x: this.x,
|
|
||||||
y: this.y,
|
|
||||||
z: this.z
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,23 +0,0 @@
|
||||||
import { Octree } from './octree';
|
|
||||||
import { EventBus } from '../event-bus';
|
|
||||||
import { PhysicsObject } from './object';
|
|
||||||
import { Vec3 } from './vec3';
|
|
||||||
export declare class World extends EventBus {
|
|
||||||
objects: PhysicsObject[];
|
|
||||||
gravity: Vec3;
|
|
||||||
dimensions: Vec3;
|
|
||||||
octreeOptions: OctreeOptions;
|
|
||||||
constructor(dimensions: Vec3, octreeOptions: OctreeOptions);
|
|
||||||
setGravity(grav: Vec3): void;
|
|
||||||
addObject(obj: PhysicsObject): void;
|
|
||||||
removeObject(obj: PhysicsObject): void;
|
|
||||||
step(dt: number): void;
|
|
||||||
checkCollisions(obj: PhysicsObject, octree: Octree): void;
|
|
||||||
}
|
|
||||||
interface OctreeOptions {
|
|
||||||
position: Vec3;
|
|
||||||
dimensions: Vec3;
|
|
||||||
maxObjects: number;
|
|
||||||
maxLevels: number;
|
|
||||||
}
|
|
||||||
export {};
|
|
|
@ -1,54 +0,0 @@
|
||||||
import { Octree } from './octree';
|
|
||||||
import { EventBus } from '../event-bus';
|
|
||||||
import { Vec3 } from './vec3';
|
|
||||||
import { AABB } from './aabb';
|
|
||||||
export class World extends EventBus {
|
|
||||||
constructor(dimensions, octreeOptions) {
|
|
||||||
super();
|
|
||||||
if (!octreeOptions) {
|
|
||||||
this.octreeOptions = {
|
|
||||||
position: new Vec3({ x: 0, y: 0, z: 0 }),
|
|
||||||
dimensions: new Vec3(this.dimensions),
|
|
||||||
maxLevels: 50,
|
|
||||||
maxObjects: 50
|
|
||||||
};
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
this.octreeOptions = octreeOptions;
|
|
||||||
}
|
|
||||||
this.dimensions = dimensions;
|
|
||||||
this.objects = [];
|
|
||||||
}
|
|
||||||
setGravity(grav) {
|
|
||||||
this.gravity = grav;
|
|
||||||
}
|
|
||||||
addObject(obj) {
|
|
||||||
this.objects.push(obj);
|
|
||||||
}
|
|
||||||
removeObject(obj) {
|
|
||||||
this.objects = this.objects.filter((val) => val !== obj);
|
|
||||||
}
|
|
||||||
step(dt) {
|
|
||||||
const octree = new Octree(this.octreeOptions.dimensions, this.octreeOptions.maxObjects, this.octreeOptions.maxLevels);
|
|
||||||
this.objects.forEach((obj) => octree.insert(obj));
|
|
||||||
this.objects.forEach((obj) => {
|
|
||||||
let velocity = obj.velocity.clone();
|
|
||||||
velocity.multiply(new Vec3({ x: dt, y: dt, z: dt }));
|
|
||||||
let gravity = this.gravity.clone();
|
|
||||||
gravity.multiply(new Vec3({ x: dt, y: dt, z: dt }));
|
|
||||||
obj.position.add(velocity);
|
|
||||||
if (obj.affectedByGravity) {
|
|
||||||
obj.velocity.add(gravity);
|
|
||||||
}
|
|
||||||
this.checkCollisions(obj, octree);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
checkCollisions(obj, octree) {
|
|
||||||
const potentialCandidates = octree.find(obj.position, obj.dimensions);
|
|
||||||
potentialCandidates.forEach((candidate) => {
|
|
||||||
if (AABB(obj, candidate)) {
|
|
||||||
this.emit('collision', [obj, candidate]);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,11 +0,0 @@
|
||||||
export default class ResonatorAudioContext {
|
|
||||||
private context;
|
|
||||||
constructor();
|
|
||||||
getContext(): AudioContext;
|
|
||||||
createGain(): any;
|
|
||||||
getOutputDestination(): AudioNode;
|
|
||||||
createBufferSource(): AudioBufferSourceNode;
|
|
||||||
decodeAudioData(data: ArrayBuffer): Promise<AudioBuffer>;
|
|
||||||
createPanner(): any;
|
|
||||||
createMediaElementSource(element: HTMLMediaElement): MediaElementAudioSourceNode;
|
|
||||||
}
|
|
|
@ -1,39 +0,0 @@
|
||||||
// simple wrapper around the AudioContext
|
|
||||||
// eventually will be used to deal with cross browser issues
|
|
||||||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
||||||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
||||||
return new (P || (P = Promise))(function (resolve, reject) {
|
|
||||||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
||||||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
||||||
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
||||||
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
||||||
});
|
|
||||||
};
|
|
||||||
export default class ResonatorAudioContext {
|
|
||||||
constructor() {
|
|
||||||
this.context = new AudioContext();
|
|
||||||
}
|
|
||||||
getContext() {
|
|
||||||
return this.context;
|
|
||||||
}
|
|
||||||
createGain() {
|
|
||||||
return this.context.createGain();
|
|
||||||
}
|
|
||||||
getOutputDestination() {
|
|
||||||
return this.context.destination;
|
|
||||||
}
|
|
||||||
createBufferSource() {
|
|
||||||
return this.context.createBufferSource();
|
|
||||||
}
|
|
||||||
decodeAudioData(data) {
|
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
|
||||||
return yield this.context.decodeAudioData(data);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
createPanner() {
|
|
||||||
return this.context.createPanner();
|
|
||||||
}
|
|
||||||
createMediaElementSource(element) {
|
|
||||||
return this.context.createMediaElementSource(element);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,21 +0,0 @@
|
||||||
import ResonatorScene from './scenes/webaudio-scene';
|
|
||||||
import ResonatorAudioContext from './audio-context';
|
|
||||||
import BaseEffect from './effects/base-effect';
|
|
||||||
export default class AudioGraph {
|
|
||||||
private master;
|
|
||||||
private effectsBus;
|
|
||||||
private worldBus;
|
|
||||||
private secondaryBus;
|
|
||||||
private effects;
|
|
||||||
private scene;
|
|
||||||
private context;
|
|
||||||
private swapChannels;
|
|
||||||
private channelSplitter;
|
|
||||||
private channelMerger;
|
|
||||||
constructor(scene: ResonatorScene, context: ResonatorAudioContext, swapChannels?: boolean);
|
|
||||||
init(): void;
|
|
||||||
connectToMaster(input: any): void;
|
|
||||||
connectToUI(input: AudioNode): void;
|
|
||||||
applyEffect(effect: BaseEffect): void;
|
|
||||||
removeEffect(effect: BaseEffect): void;
|
|
||||||
}
|
|
|
@ -1,46 +0,0 @@
|
||||||
// this is the mixer that takes all the different outputs and mixes them into the 2 busses:
|
|
||||||
// WorldBus: The directional audio
|
|
||||||
// SecondaryBus: All the UI and things that are non directional
|
|
||||||
import EffectChain from './effect-chain';
|
|
||||||
export default class AudioGraph {
|
|
||||||
constructor(scene, context, swapChannels = false) {
|
|
||||||
this.scene = scene;
|
|
||||||
this.context = context;
|
|
||||||
this.swapChannels = swapChannels;
|
|
||||||
this.init();
|
|
||||||
}
|
|
||||||
init() {
|
|
||||||
this.effectsBus = this.context.createGain();
|
|
||||||
this.worldBus = this.context.createGain();
|
|
||||||
this.secondaryBus = this.context.createGain();
|
|
||||||
this.master = this.context.createGain();
|
|
||||||
this.scene.getOutput().connect(this.worldBus);
|
|
||||||
// this.worldBus.connect(this.master);
|
|
||||||
this.worldBus.connect(this.effectsBus);
|
|
||||||
this.effects = new EffectChain(this.context, this, this.effectsBus, this.master);
|
|
||||||
this.secondaryBus.connect(this.master);
|
|
||||||
if (this.swapChannels) {
|
|
||||||
this.channelSplitter = this.context.getContext().createChannelSplitter(2);
|
|
||||||
this.channelMerger = this.context.getContext().createChannelMerger(2);
|
|
||||||
this.master.connect(this.channelSplitter);
|
|
||||||
this.channelSplitter.connect(this.channelMerger, 0, 1);
|
|
||||||
this.channelSplitter.connect(this.channelMerger, 1, 0);
|
|
||||||
this.channelMerger.connect(this.context.getOutputDestination());
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
this.master.connect(this.context.getOutputDestination());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
connectToMaster(input) {
|
|
||||||
input.connect(this.master);
|
|
||||||
}
|
|
||||||
connectToUI(input) {
|
|
||||||
input.connect(this.secondaryBus);
|
|
||||||
}
|
|
||||||
applyEffect(effect) {
|
|
||||||
this.effects.applyEffect(effect);
|
|
||||||
}
|
|
||||||
removeEffect(effect) {
|
|
||||||
this.effects.removeEffect(effect);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,12 +0,0 @@
|
||||||
export default class DataPoolItem {
|
|
||||||
private name;
|
|
||||||
private data;
|
|
||||||
private decodedData;
|
|
||||||
constructor(name: string, data?: any, decodedData?: any);
|
|
||||||
getData(): any;
|
|
||||||
setData(data: any): void;
|
|
||||||
getDecodedData(): any;
|
|
||||||
setDecodedData(data: any): void;
|
|
||||||
getName(): string;
|
|
||||||
setName(name: string): void;
|
|
||||||
}
|
|
|
@ -1,26 +0,0 @@
|
||||||
// An item in the data pool
|
|
||||||
export default class DataPoolItem {
|
|
||||||
constructor(name, data = null, decodedData = null) {
|
|
||||||
this.name = name;
|
|
||||||
this.data = data;
|
|
||||||
this.decodedData = decodedData;
|
|
||||||
}
|
|
||||||
getData() {
|
|
||||||
return this.data;
|
|
||||||
}
|
|
||||||
setData(data) {
|
|
||||||
this.data = data;
|
|
||||||
}
|
|
||||||
getDecodedData() {
|
|
||||||
return this.decodedData;
|
|
||||||
}
|
|
||||||
setDecodedData(data) {
|
|
||||||
this.decodedData = this.decodedData;
|
|
||||||
}
|
|
||||||
getName() {
|
|
||||||
return this.name;
|
|
||||||
}
|
|
||||||
setName(name) {
|
|
||||||
this.name = name;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,12 +0,0 @@
|
||||||
import EventEmitter from 'eventemitter3';
|
|
||||||
import ResonatorAudioContext from './audio-context';
|
|
||||||
import { BaseLoader } from './loaders/base-loader';
|
|
||||||
export default class DataPool extends EventEmitter {
|
|
||||||
private loader;
|
|
||||||
private data;
|
|
||||||
private maxData;
|
|
||||||
private context;
|
|
||||||
constructor(context: ResonatorAudioContext, loader?: BaseLoader, maxData?: number);
|
|
||||||
get(path: string): Promise<AudioBuffer>;
|
|
||||||
clear(): void;
|
|
||||||
}
|
|
|
@ -1,48 +0,0 @@
|
||||||
// a data pool holds frequently played sounds in memory together with decoded audio data to no longer have to decode them from the cache when loaded again
|
|
||||||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
||||||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
||||||
return new (P || (P = Promise))(function (resolve, reject) {
|
|
||||||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
||||||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
||||||
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
||||||
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
||||||
});
|
|
||||||
};
|
|
||||||
import EventEmitter from 'eventemitter3';
|
|
||||||
import DataPoolItem from './data-pool-item';
|
|
||||||
import { HTTPLoader } from './loaders/http-loader';
|
|
||||||
export default class DataPool extends EventEmitter {
|
|
||||||
constructor(context, loader = new HTTPLoader(), maxData = 512) {
|
|
||||||
super();
|
|
||||||
this.loader = loader;
|
|
||||||
this.data = {};
|
|
||||||
this.maxData = maxData;
|
|
||||||
this.context = context;
|
|
||||||
}
|
|
||||||
get(path) {
|
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
|
||||||
if (this.data[path]) {
|
|
||||||
return this.data[path].getDecodedData();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
const buffer = yield this.loader.get(path);
|
|
||||||
const decoded = yield this.context.decodeAudioData(buffer);
|
|
||||||
const item = new DataPoolItem(path, buffer, decoded);
|
|
||||||
const length = Object.keys(this.data).length;
|
|
||||||
if (length < this.maxData) {
|
|
||||||
this.data[path] = item;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// TODO: figure out a more clever solution than just removing the first loaded data. Like tracking how much certain data is needed and prioritize them.
|
|
||||||
// const paths: string[] = Object.keys(this.data);
|
|
||||||
// delete this.data[paths[0]];
|
|
||||||
this.data[path] = item;
|
|
||||||
}
|
|
||||||
return item.getDecodedData();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
clear() {
|
|
||||||
this.data = {};
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,8 +0,0 @@
|
||||||
import ResonatorAudioContext from './audio-context';
|
|
||||||
export default class EffectBus {
|
|
||||||
private context;
|
|
||||||
private inputNode;
|
|
||||||
private channelMerger;
|
|
||||||
constructor(context: ResonatorAudioContext, input: AudioNode, output: AudioNode);
|
|
||||||
connect(node: AudioNode): void;
|
|
||||||
}
|
|
|
@ -1,12 +0,0 @@
|
||||||
// Currently unused, but eventually all the effect stuff will be moved from audio graph to here to make it easier to work on
|
|
||||||
export default class EffectBus {
|
|
||||||
constructor(context, input, output) {
|
|
||||||
this.context = context;
|
|
||||||
this.inputNode = input;
|
|
||||||
this.channelMerger = this.context.getContext().createChannelMerger(1);
|
|
||||||
this.inputNode.connect(this.channelMerger);
|
|
||||||
}
|
|
||||||
connect(node) {
|
|
||||||
this.channelMerger.connect(node);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,14 +0,0 @@
|
||||||
import ResonatorAudioContext from './audio-context';
|
|
||||||
import AudioGraph from './audio-graph';
|
|
||||||
import BaseEffect from './effects/base-effect';
|
|
||||||
export default class EffectChain {
|
|
||||||
private context;
|
|
||||||
private graph;
|
|
||||||
private effects;
|
|
||||||
private inputNode;
|
|
||||||
private outputNode;
|
|
||||||
constructor(context: ResonatorAudioContext, graph: AudioGraph, input: AudioNode, output: AudioNode);
|
|
||||||
applyEffect(effect: BaseEffect): void;
|
|
||||||
removeEffect(effect: BaseEffect): void;
|
|
||||||
private updateConnections;
|
|
||||||
}
|
|
|
@ -1,45 +0,0 @@
|
||||||
// A chain of effects that connect to the effect bus
|
|
||||||
export default class EffectChain {
|
|
||||||
constructor(context, graph, input, output) {
|
|
||||||
this.effects = [];
|
|
||||||
this.context = context;
|
|
||||||
this.graph = graph;
|
|
||||||
this.inputNode = input;
|
|
||||||
this.outputNode = output;
|
|
||||||
this.updateConnections();
|
|
||||||
}
|
|
||||||
applyEffect(effect) {
|
|
||||||
this.effects.push(effect);
|
|
||||||
this.updateConnections();
|
|
||||||
}
|
|
||||||
removeEffect(effect) {
|
|
||||||
this.effects.forEach((currEffect) => {
|
|
||||||
if (effect === currEffect) {
|
|
||||||
currEffect.disconnect();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
this.effects = this.effects.filter((currEffect) => effect !== currEffect);
|
|
||||||
this.updateConnections();
|
|
||||||
}
|
|
||||||
updateConnections() {
|
|
||||||
if (this.effects.length == 0) {
|
|
||||||
this.inputNode.connect(this.outputNode);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
let current = null;
|
|
||||||
let previous = null;
|
|
||||||
this.effects.forEach((effect) => {
|
|
||||||
current = effect;
|
|
||||||
if (previous) {
|
|
||||||
current.connectInput(previous.getOutput());
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
current.connectInput(this.inputNode);
|
|
||||||
}
|
|
||||||
previous = current;
|
|
||||||
});
|
|
||||||
if (current) {
|
|
||||||
current.connectOutput(this.outputNode);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,15 +0,0 @@
|
||||||
import ResonatorAudioContext from '../audio-context';
|
|
||||||
import AudioGraph from '../audio-graph';
|
|
||||||
export default class BaseEffect {
|
|
||||||
protected ready: boolean;
|
|
||||||
protected effectNode: any;
|
|
||||||
protected effectParams: any;
|
|
||||||
protected context: ResonatorAudioContext;
|
|
||||||
protected graph: AudioGraph;
|
|
||||||
protected inputNode: AudioNode;
|
|
||||||
constructor(context: ResonatorAudioContext, graph: AudioGraph, params: any);
|
|
||||||
connectOutput(node: AudioNode): void;
|
|
||||||
connectInput(node: AudioNode): void;
|
|
||||||
getOutput(): AudioNode;
|
|
||||||
disconnect(): void;
|
|
||||||
}
|
|
|
@ -1,23 +0,0 @@
|
||||||
export default class BaseEffect {
|
|
||||||
constructor(context, graph, params) {
|
|
||||||
this.graph = graph;
|
|
||||||
this.context = context;
|
|
||||||
this.effectParams = params;
|
|
||||||
}
|
|
||||||
connectOutput(node) {
|
|
||||||
this.effectNode.connect(node);
|
|
||||||
}
|
|
||||||
connectInput(node) {
|
|
||||||
this.inputNode = node;
|
|
||||||
if (this.effectNode) {
|
|
||||||
this.inputNode.connect(this.effectNode);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
getOutput() {
|
|
||||||
return this.effectNode;
|
|
||||||
}
|
|
||||||
disconnect() {
|
|
||||||
this.inputNode.disconnect();
|
|
||||||
this.effectNode.disconnect();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,10 +0,0 @@
|
||||||
import BaseEffect from './base-effect';
|
|
||||||
import ResonatorAudioContext from '../audio-context';
|
|
||||||
import AudioGraph from '../audio-graph';
|
|
||||||
export default class Convolver extends BaseEffect {
|
|
||||||
private buffer;
|
|
||||||
private channelSplitter;
|
|
||||||
private channelMerger;
|
|
||||||
constructor(context: ResonatorAudioContext, graph: AudioGraph, params: any);
|
|
||||||
connectInput(node: AudioNode): void;
|
|
||||||
}
|
|
|
@ -1,20 +0,0 @@
|
||||||
import BaseEffect from './base-effect';
|
|
||||||
export default class Convolver extends BaseEffect {
|
|
||||||
constructor(context, graph, params) {
|
|
||||||
super(context, graph, params);
|
|
||||||
console.log(`Creating convolver`);
|
|
||||||
this.effectNode = this.context.getContext().createConvolver();
|
|
||||||
this.effectNode.buffer = this.effectParams.buffer;
|
|
||||||
}
|
|
||||||
connectInput(node) {
|
|
||||||
this.channelSplitter = this.context.getContext().createChannelSplitter(2);
|
|
||||||
this.channelMerger = this.context.getContext().createChannelMerger(2);
|
|
||||||
this.channelSplitter.connect(this.channelMerger, 0, 0);
|
|
||||||
this.channelSplitter.connect(this.channelMerger, 1, 0);
|
|
||||||
this.channelSplitter.connect(this.channelMerger, 0, 1);
|
|
||||||
this.channelSplitter.connect(this.channelMerger, 1, 1);
|
|
||||||
node.connect(this.channelSplitter);
|
|
||||||
this.channelMerger.connect(this.effectNode);
|
|
||||||
this.inputNode = node;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,22 +0,0 @@
|
||||||
import AudioSource from './sources/audio-source';
|
|
||||||
import { BaseLoader } from './loaders/base-loader';
|
|
||||||
import { BaseSource } from './sources/base-source';
|
|
||||||
import { SourceType } from './sources/source-type';
|
|
||||||
import { StreamingSource } from './sources/streaming-source';
|
|
||||||
export default class Resonator {
|
|
||||||
private loader;
|
|
||||||
private context;
|
|
||||||
private scene;
|
|
||||||
private graph;
|
|
||||||
private dataPool;
|
|
||||||
private environmentImpulse;
|
|
||||||
constructor(loader?: BaseLoader);
|
|
||||||
load(path: string, type?: SourceType): Promise<BaseSource>;
|
|
||||||
loadImmediate(path: string, type?: SourceType): AudioSource;
|
|
||||||
stream(path: string, type?: SourceType): StreamingSource;
|
|
||||||
private createSource;
|
|
||||||
setEnvironmentImpulse(file: string): Promise<void>;
|
|
||||||
setListenerPosition(x: number, y: number, z: number): void;
|
|
||||||
setListenerOrientation(forward: any, up: any): void;
|
|
||||||
clearDataPool(): void;
|
|
||||||
}
|
|
|
@ -1,78 +0,0 @@
|
||||||
// the main module for Resonator
|
|
||||||
// API, etc.
|
|
||||||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
||||||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
||||||
return new (P || (P = Promise))(function (resolve, reject) {
|
|
||||||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
||||||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
||||||
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
||||||
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
||||||
});
|
|
||||||
};
|
|
||||||
import ResonatorAudioContext from './audio-context';
|
|
||||||
import ResonatorScene from './scenes/webaudio-scene';
|
|
||||||
import AudioGraph from './audio-graph';
|
|
||||||
import AudioSource from './sources/audio-source';
|
|
||||||
import DataPool from './data-pool';
|
|
||||||
import Convolver from './effects/convolver';
|
|
||||||
import { HTTPLoader } from './loaders/http-loader';
|
|
||||||
import { SourceType } from './sources/source-type';
|
|
||||||
import { StreamingSource } from './sources/streaming-source';
|
|
||||||
export default class Resonator {
|
|
||||||
constructor(loader = new HTTPLoader()) {
|
|
||||||
this.loader = loader;
|
|
||||||
this.environmentImpulse = null;
|
|
||||||
this.context = new ResonatorAudioContext();
|
|
||||||
this.scene = new ResonatorScene(this.context);
|
|
||||||
this.graph = new AudioGraph(this.scene, this.context, false);
|
|
||||||
this.dataPool = new DataPool(this.context, this.loader);
|
|
||||||
}
|
|
||||||
load(path, type = SourceType.WorldSource) {
|
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
|
||||||
const data = yield this.dataPool.get(path);
|
|
||||||
const source = this.createSource(type, data);
|
|
||||||
return source;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
loadImmediate(path, type = SourceType.WorldSource) {
|
|
||||||
const source = new AudioSource(this.graph, this.scene, this.context, null, type);
|
|
||||||
this.dataPool.get(path).then((data) => {
|
|
||||||
source.setBuffer(data);
|
|
||||||
});
|
|
||||||
return source;
|
|
||||||
}
|
|
||||||
stream(path, type = SourceType.MasterSource) {
|
|
||||||
const element = new Audio(path);
|
|
||||||
element.crossOrigin = 'anonymous';
|
|
||||||
element.volume = 1;
|
|
||||||
const source = new StreamingSource(this.graph, this.scene, this.context, element, type);
|
|
||||||
return source;
|
|
||||||
}
|
|
||||||
createSource(type, data) {
|
|
||||||
return new AudioSource(this.graph, this.scene, this.context, data);
|
|
||||||
}
|
|
||||||
setEnvironmentImpulse(file) {
|
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
|
||||||
if (this.environmentImpulse) {
|
|
||||||
this.graph.removeEffect(this.environmentImpulse);
|
|
||||||
}
|
|
||||||
if (file === null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const buffer = yield this.dataPool.get(file);
|
|
||||||
this.environmentImpulse = new Convolver(this.context, this.graph, {
|
|
||||||
buffer
|
|
||||||
});
|
|
||||||
this.graph.applyEffect(this.environmentImpulse);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
setListenerPosition(x, y, z) {
|
|
||||||
this.scene.setListenerPosition(x, y, z);
|
|
||||||
}
|
|
||||||
setListenerOrientation(forward, up) {
|
|
||||||
this.scene.setListenerOrientation(forward, up);
|
|
||||||
}
|
|
||||||
clearDataPool() {
|
|
||||||
this.dataPool.clear();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,10 +0,0 @@
|
||||||
import { AssetManager } from '../../asset-manager';
|
|
||||||
import { BaseLoader } from './base-loader';
|
|
||||||
export declare class AssetLoader implements BaseLoader {
|
|
||||||
private name;
|
|
||||||
private manager;
|
|
||||||
private assetManager;
|
|
||||||
constructor(name: string, manager?: AssetManager);
|
|
||||||
init(): Promise<void>;
|
|
||||||
get(path: string): Promise<ArrayBuffer>;
|
|
||||||
}
|
|
|
@ -1,36 +0,0 @@
|
||||||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
||||||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
||||||
return new (P || (P = Promise))(function (resolve, reject) {
|
|
||||||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
||||||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
||||||
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
||||||
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
||||||
});
|
|
||||||
};
|
|
||||||
// TODO fix path when actually properly linking the packages together
|
|
||||||
import { AssetManager } from '../../asset-manager';
|
|
||||||
export class AssetLoader {
|
|
||||||
constructor(name, manager = null) {
|
|
||||||
this.name = name;
|
|
||||||
this.manager = manager;
|
|
||||||
if (manager) {
|
|
||||||
this.assetManager = manager;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
this.assetManager = new AssetManager(name, '');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
init() {
|
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
|
||||||
yield this.assetManager.init();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
get(path) {
|
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
|
||||||
const result = yield this.assetManager.downloadFile(path);
|
|
||||||
console.log(result);
|
|
||||||
const buffer = yield result.arrayBuffer();
|
|
||||||
return buffer;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,3 +0,0 @@
|
||||||
export interface BaseLoader {
|
|
||||||
get(path: string): Promise<ArrayBuffer>;
|
|
||||||
}
|
|
|
@ -1 +0,0 @@
|
||||||
export {};
|
|
|
@ -1,4 +0,0 @@
|
||||||
import { BaseLoader } from './base-loader';
|
|
||||||
export declare class HTTPLoader implements BaseLoader {
|
|
||||||
get(path: string): Promise<ArrayBuffer>;
|
|
||||||
}
|
|
|
@ -1,18 +0,0 @@
|
||||||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
||||||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
||||||
return new (P || (P = Promise))(function (resolve, reject) {
|
|
||||||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
||||||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
||||||
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
||||||
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
||||||
});
|
|
||||||
};
|
|
||||||
export class HTTPLoader {
|
|
||||||
get(path) {
|
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
|
||||||
const result = yield fetch(path);
|
|
||||||
const buffer = yield result.arrayBuffer();
|
|
||||||
return buffer;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,14 +0,0 @@
|
||||||
import ResonatorAudioContext from '../audio-context';
|
|
||||||
import EventEmitter from 'eventemitter3';
|
|
||||||
export default class Scene extends EventEmitter {
|
|
||||||
scene: any;
|
|
||||||
context: ResonatorAudioContext;
|
|
||||||
listener: AudioListener;
|
|
||||||
constructor(context: ResonatorAudioContext);
|
|
||||||
init(): void;
|
|
||||||
createSource(): any;
|
|
||||||
getOutput(): any;
|
|
||||||
getInput(): any;
|
|
||||||
setListenerPosition(x: number, y: number, z: number): void;
|
|
||||||
setListenerOrientation(forward: any, rawup: any): void;
|
|
||||||
}
|
|
|
@ -1,40 +0,0 @@
|
||||||
// The code that deals with 3d audio
|
|
||||||
import ResonanceAudio from '../vendor/resonance-es6/main';
|
|
||||||
import EventEmitter from 'eventemitter3';
|
|
||||||
import vec3 from '../../tsm/vec3';
|
|
||||||
export default class Scene extends EventEmitter {
|
|
||||||
constructor(context) {
|
|
||||||
super();
|
|
||||||
this.context = context;
|
|
||||||
this.scene = new ResonanceAudio(this.context.getContext(), {
|
|
||||||
ambisonicOrder: 3
|
|
||||||
});
|
|
||||||
this.listener = this.context.getContext().listener;
|
|
||||||
this.init();
|
|
||||||
}
|
|
||||||
init() {
|
|
||||||
// this.scene.output.connect(this.context.getOutputDestination());
|
|
||||||
}
|
|
||||||
createSource() {
|
|
||||||
const source = this.scene.createSource();
|
|
||||||
return Object.assign(Object.assign({}, source), { getInput: () => source.input });
|
|
||||||
}
|
|
||||||
getOutput() {
|
|
||||||
return this.scene.output;
|
|
||||||
}
|
|
||||||
getInput() {
|
|
||||||
return this.scene.input;
|
|
||||||
}
|
|
||||||
setListenerPosition(x, y, z) {
|
|
||||||
this.scene.setListenerPosition(x, y, z);
|
|
||||||
}
|
|
||||||
setListenerOrientation(forward, rawup) {
|
|
||||||
let fwd = new vec3([forward.x, forward.y, forward.z]);
|
|
||||||
let up = fwd.copy();
|
|
||||||
vec3.cross(up, new vec3([rawup.x, rawup.y, rawup.z]), up);
|
|
||||||
vec3.cross(up, fwd, up);
|
|
||||||
fwd.normalize();
|
|
||||||
up.normalize();
|
|
||||||
this.scene.setListenerOrientation(forward.x, forward.y, forward.z, rawup.x, rawup.y, rawup.z);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,14 +0,0 @@
|
||||||
import ResonatorAudioContext from '../audio-context';
|
|
||||||
import EventEmitter from 'eventemitter3';
|
|
||||||
export default class ResonatorScene extends EventEmitter {
|
|
||||||
scene: GainNode;
|
|
||||||
context: ResonatorAudioContext;
|
|
||||||
listener: AudioListener;
|
|
||||||
constructor(context: ResonatorAudioContext);
|
|
||||||
init(): void;
|
|
||||||
createSource(): any;
|
|
||||||
getOutput(): any;
|
|
||||||
getInput(): any;
|
|
||||||
setListenerPosition(x: number, y: number, z: number): void;
|
|
||||||
setListenerOrientation(forward: any, rawup: any): void;
|
|
||||||
}
|
|
|
@ -1,42 +0,0 @@
|
||||||
// The code that deals with 3d audio
|
|
||||||
import EventEmitter from 'eventemitter3';
|
|
||||||
import vec3 from '../../tsm/vec3';
|
|
||||||
export default class ResonatorScene extends EventEmitter {
|
|
||||||
constructor(context) {
|
|
||||||
super();
|
|
||||||
this.context = context;
|
|
||||||
this.scene = this.context.getContext().createGain();
|
|
||||||
this.listener = this.context.getContext().listener;
|
|
||||||
this.init();
|
|
||||||
}
|
|
||||||
init() {
|
|
||||||
// this.scene.output.connect(this.context.getOutputDestination());
|
|
||||||
}
|
|
||||||
createSource() {
|
|
||||||
const node = this.context.getContext().createPanner();
|
|
||||||
node.panningModel = 'HRTF';
|
|
||||||
node.distanceModel = 'linear';
|
|
||||||
node.maxDistance = 20;
|
|
||||||
node.refDistance = 2;
|
|
||||||
node.connect(this.scene);
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
getOutput() {
|
|
||||||
return this.scene;
|
|
||||||
}
|
|
||||||
getInput() {
|
|
||||||
return this.scene;
|
|
||||||
}
|
|
||||||
setListenerPosition(x, y, z) {
|
|
||||||
this.listener.setPosition(x, y, z);
|
|
||||||
}
|
|
||||||
setListenerOrientation(forward, rawup) {
|
|
||||||
let fwd = new vec3([forward.x, forward.y, forward.z]);
|
|
||||||
let up = fwd.copy();
|
|
||||||
vec3.cross(up, new vec3([rawup.x, rawup.y, rawup.z]), up);
|
|
||||||
vec3.cross(up, fwd, up);
|
|
||||||
fwd.normalize();
|
|
||||||
up.normalize();
|
|
||||||
this.listener.setOrientation(fwd.x, fwd.y, fwd.z, up.x, up.y, up.z);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,37 +0,0 @@
|
||||||
import ResonatorAudioContext from '../audio-context';
|
|
||||||
import AudioGraph from '../audio-graph';
|
|
||||||
import ResonatorScene from '../scenes/webaudio-scene';
|
|
||||||
import { BaseSource } from './base-source';
|
|
||||||
import { SourceType } from './source-type';
|
|
||||||
export default class AudioSource implements BaseSource {
|
|
||||||
playing: boolean;
|
|
||||||
looping: boolean;
|
|
||||||
private node;
|
|
||||||
private sceneNode;
|
|
||||||
private buffer;
|
|
||||||
private context;
|
|
||||||
private graph;
|
|
||||||
private scene;
|
|
||||||
private playOnLoad;
|
|
||||||
private position;
|
|
||||||
private playbackRate;
|
|
||||||
private volume;
|
|
||||||
private gain;
|
|
||||||
private type;
|
|
||||||
constructor(graph: AudioGraph, scene: ResonatorScene, context: ResonatorAudioContext, buffer?: AudioBuffer, type?: SourceType);
|
|
||||||
init(): void;
|
|
||||||
getBuffer(): AudioBuffer;
|
|
||||||
setBuffer(data: AudioBuffer): void;
|
|
||||||
play(when?: number, offset?: number, duration?: number): void;
|
|
||||||
setPosition(x: number, y: number, z: number): void;
|
|
||||||
setPlaybackRate(rate: number): void;
|
|
||||||
getPlaybackRate(): number;
|
|
||||||
setVolume(volume: number): void;
|
|
||||||
getVolume(): number;
|
|
||||||
private createConnections;
|
|
||||||
stop(): void;
|
|
||||||
destroy(): void;
|
|
||||||
loop(value: boolean): void;
|
|
||||||
fadeOut(time: number): void;
|
|
||||||
fadeIn(time: number): void;
|
|
||||||
}
|
|
|
@ -1,148 +0,0 @@
|
||||||
// an audio source
|
|
||||||
// This is the actual sound
|
|
||||||
import { SourceType } from './source-type';
|
|
||||||
export default class AudioSource {
|
|
||||||
constructor(graph, scene, context, buffer = null, type = SourceType.WorldSource) {
|
|
||||||
this.position = {
|
|
||||||
x: 0,
|
|
||||||
y: 0,
|
|
||||||
z: 0
|
|
||||||
};
|
|
||||||
this.buffer = buffer;
|
|
||||||
this.context = context;
|
|
||||||
this.scene = scene;
|
|
||||||
this.graph = graph;
|
|
||||||
this.type = type;
|
|
||||||
this.playbackRate = 1;
|
|
||||||
this.volume = 1;
|
|
||||||
this.init();
|
|
||||||
}
|
|
||||||
init() {
|
|
||||||
this.gain = this.context.createGain();
|
|
||||||
// bind methods so we can add and removve them from event listeners
|
|
||||||
this.stop = this.stop.bind(this);
|
|
||||||
}
|
|
||||||
getBuffer() {
|
|
||||||
return this.buffer;
|
|
||||||
}
|
|
||||||
setBuffer(data) {
|
|
||||||
this.buffer = data;
|
|
||||||
if (this.playOnLoad) {
|
|
||||||
this.play();
|
|
||||||
this.playOnLoad = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
play(when = 0, offset = 0, duration = this.buffer ? this.buffer.duration : 0) {
|
|
||||||
if (this.playing && this.node) {
|
|
||||||
this.stop();
|
|
||||||
}
|
|
||||||
if (!this.buffer) {
|
|
||||||
this.playOnLoad = true;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!this.node) {
|
|
||||||
this.node = this.context.createBufferSource();
|
|
||||||
this.node.buffer = this.buffer;
|
|
||||||
this.createConnections();
|
|
||||||
}
|
|
||||||
if (this.node) {
|
|
||||||
this.node.playbackRate.value = this.playbackRate;
|
|
||||||
this.node.start(when, offset, duration);
|
|
||||||
this.node.loop = this.looping;
|
|
||||||
this.playing = true;
|
|
||||||
if (this.sceneNode) {
|
|
||||||
this.sceneNode.setPosition(this.position.x, this.position.y, this.position.z);
|
|
||||||
}
|
|
||||||
this.node.addEventListener('ended', this.stop);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
setPosition(x, y, z) {
|
|
||||||
this.position = {
|
|
||||||
x,
|
|
||||||
y,
|
|
||||||
z
|
|
||||||
};
|
|
||||||
if (this.sceneNode)
|
|
||||||
this.sceneNode.setPosition(x, y, z);
|
|
||||||
}
|
|
||||||
setPlaybackRate(rate) {
|
|
||||||
this.playbackRate = rate;
|
|
||||||
if (this.node)
|
|
||||||
this.node.playbackRate.value = rate;
|
|
||||||
}
|
|
||||||
getPlaybackRate() {
|
|
||||||
return this.playbackRate;
|
|
||||||
}
|
|
||||||
setVolume(volume) {
|
|
||||||
this.volume = volume;
|
|
||||||
if (this.gain)
|
|
||||||
this.gain.gain.value = volume;
|
|
||||||
}
|
|
||||||
getVolume() {
|
|
||||||
return this.volume;
|
|
||||||
}
|
|
||||||
createConnections() {
|
|
||||||
switch (this.type) {
|
|
||||||
case SourceType.WorldSource:
|
|
||||||
if (!this.sceneNode) {
|
|
||||||
this.sceneNode = this.scene.createSource();
|
|
||||||
}
|
|
||||||
this.node.connect(this.gain);
|
|
||||||
this.gain.connect(this.sceneNode);
|
|
||||||
break;
|
|
||||||
case SourceType.UISource:
|
|
||||||
this.node.connect(this.gain);
|
|
||||||
this.graph.connectToUI(this.gain);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
this.node.connect(this.gain);
|
|
||||||
this.graph.connectToMaster(this.gain);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
stop() {
|
|
||||||
this.playing = false;
|
|
||||||
if (this.node) {
|
|
||||||
this.node.removeEventListener('ended', this.stop);
|
|
||||||
this.node.stop();
|
|
||||||
this.node.disconnect();
|
|
||||||
this.node = null;
|
|
||||||
this.playing = false;
|
|
||||||
if (this.sceneNode) {
|
|
||||||
this.sceneNode.disconnect();
|
|
||||||
this.sceneNode = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
destroy() {
|
|
||||||
this.stop();
|
|
||||||
// set all refs to null to encourage gc
|
|
||||||
this.node = null;
|
|
||||||
this.sceneNode = null;
|
|
||||||
this.buffer = null;
|
|
||||||
this.context = null;
|
|
||||||
this.graph = null;
|
|
||||||
this.scene = null;
|
|
||||||
}
|
|
||||||
loop(value) {
|
|
||||||
this.looping = value;
|
|
||||||
if (this.node) {
|
|
||||||
this.node.loop = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fadeOut(time) {
|
|
||||||
this.gain.gain.setValueAtTime(this.getVolume(), this.context.getContext().currentTime);
|
|
||||||
if (!this.node) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.gain.gain.exponentialRampToValueAtTime(0.0001, this.context.getContext().currentTime + time);
|
|
||||||
setTimeout(() => this.stop(), time * 1000);
|
|
||||||
}
|
|
||||||
fadeIn(time) {
|
|
||||||
this.gain.gain.setValueAtTime(0.0001, this.context.getContext().currentTime);
|
|
||||||
if (!this.node) {
|
|
||||||
this.play();
|
|
||||||
}
|
|
||||||
this.gain.gain.exponentialRampToValueAtTime(this.volume, this.context.getContext().currentTime + time);
|
|
||||||
}
|
|
||||||
}
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue