Commit 1ff9736f authored by Stepheno's avatar Stepheno

Merge branch 'master' of gitlab2.dui88.com:laoqifeng/scilla-core into feature/190417-data-center

parents 0b3683a9 b807e097
/**
* Created by rockyl on 2018/11/23.
*/
import {Entity, traverse, traversePostorder} from "./Entity";
import {injectProp} from "../tools/utils";
import {setupContext as setupInteractContext} from "./context/InteractContext";
import {clear, ScaleMode, setupContext as setupRenderContext} from "./context/RenderContext";
import './requestAnimationFrame';
/**
* 创建引擎实例
* @param options
*/
export function createEngineInstance(options?) {
let instance = new ScillaEngine();
instance.setup(options);
}
/**
* 引擎类
*/
class ScillaEngine {
/**
* 默认配置
*/
options: any = {
fps: 60,
designWidth: 750,
designHeight: 1334,
scaleMode: ScaleMode.FIXED_WIDTH,
touchEnabled: true,
};
_flush: number = 0;
_currentFlush: number = 0;
tsStart: number;
tsLast: number;
lastFPS: number = 0;
private readonly root: Entity;
constructor() {
this.root = new Entity('root');
this.root._restrict();
}
setup(options?){
injectProp(this.options, options);
const {canvas, designWidth, designHeight, scaleMode, modifyCanvasSize, touchEnabled} = options;
let canvasElement = typeof canvas == 'object' ? canvas : document.getElementById(canvas);
setupInteractContext({
canvas: canvasElement,
touchHandler: {
onTouchBegin: this.onTouchBegin.bind(this),
onTouchMove: this.onTouchMove.bind(this),
onTouchEnd: this.onTouchEnd.bind(this),
},
touchEnabled,
});
setupRenderContext({
canvas: canvasElement,
designWidth,
designHeight,
scaleMode,
modifyCanvasSize,
});
}
/**
* 开始引擎
*/
start() {
this.root.enabled = true;
this.tsStart = Date.now();
this.startTick();
}
/**
* 暂停引擎
*/
pause() {
this.root.enabled = false;
this.stopTick();
}
/**
* 获取节点路径
* @param entity
*/
getEntityPath(entity?: Entity): string {
let path = '';
let current = entity || this.root;
while (current.parent) {
path = current.parent.children.indexOf(current) + (path.length > 0 ? '|' : '') + path;
current = current.parent;
}
return path;
}
/**
* 根据节点路径获取节点
* @param path
*/
getEntityByPath(path?: string): Entity {
let target = this.root;
if (path.length > 0) {
let arr = path.split('|');
for (let item of arr) {
target = target.children[item];
if (!target) {
target = null;
break;
}
}
}
return target;
}
/**
* 获取当前帧率
*/
get fps() {
return this.lastFPS;
}
/**
* 开始时钟
*/
private startTick() {
this._flush = 60 / this.options.fps - 1 >> 0;
if (this._flush < 0) {
this._flush = 0;
}
requestAnimationFrame(this.flush);
}
/**
* 停止时钟
*/
private stopTick() {
}
/**
* 时钟触发
*/
private flush(tsNow): void {
if (this._flush == 0) {
this.onFrameTick(tsNow);
} else {
if (this._currentFlush == 0) {
this.onFrameTick(tsNow);
this._currentFlush = this._flush;
} else {
this._currentFlush--;
}
}
requestAnimationFrame(this.flush);
}
nextTicks = [];
nextTick(func, tickCount = 1) {
this.nextTicks.push({func, tickCount});
}
private onFrameTick(tsNow) {
clear();
this.lastFPS = Math.floor(1000 / (tsNow - this.tsLast));
this.tsLast = tsNow;
const ts = tsNow - this.tsStart;
traverse(this.root, function (child) {
if (!child.isFree && child.enabled) {
child.onUpdate(ts);
} else {
return true;
}
}, -1, true, function (current) {
current.afterUpdate();
});
//const tsPass = Date.now() - tsNow;
for (let i = 0, li = this.nextTicks.length; i < li; i++) {
const item = this.nextTicks[i];
item.tickCount--;
if (item.tickCount <= 0) {
item.func(ts);
this.nextTicks.splice(i, 1);
i--;
li--;
}
}
}
/**
* 代理出来的onTouchBegin方法
* @param event
*/
private onTouchBegin(event) {
traversePostorder(this.root, function (child) {
return child.onInteract(0, event);
})
}
/**
* 代理出来的onTouchMove方法
* @param event
*/
private onTouchMove(event) {
traversePostorder(this.root, function (child) {
return child.onInteract(1, event);
})
}
/**
* 代理出来的onTouchEnd方法
* @param event
*/
private onTouchEnd(event) {
traversePostorder(this.root, function (child) {
return child.onInteract(2, event);
})
}
}
{
"name": "scilla-core",
"version": "1.0.0",
"name": "scilla",
"version": "1.0.1",
"main": "./dist/index.js",
"types": "./types/index.d.ts",
"license": "MIT",
"scripts": {
"build": "rollup -c"
},
"dependencies": {
"tslib": "^1.9.3"
},
"scripts": {},
"devDependencies": {
"rollup": "^0.66.6",
"rollup-plugin-commonjs": "^9.2.0",
"rollup-plugin-node-resolve": "^3.4.0",
"rollup-plugin-typescript2": "^0.18.0",
"rollup-plugin-uglify": "^6.0.0",
"rollup-plugin-commonjs": "^9.2.2",
"rollup-plugin-node-resolve": "^4.0.1",
"rollup-plugin-typescript2": "^0.20.1",
"rollup-plugin-uglify": "^6.0.2",
"tslib": "^1.9.3",
"typescript": "^3.1.6"
"typescript": "^3.3.4000"
}
}
# scilla
## game engine for HTML5
\ No newline at end of file
......@@ -7,13 +7,14 @@ const commonjs = require('rollup-plugin-commonjs');
const typescript = require('rollup-plugin-typescript2');
const {uglify} = require('rollup-plugin-uglify');
const name = 'scilla';
export default {
input: 'src/index.ts',
output: {
file: 'dist/bundle.js',
file: `dist/${name}.js`,
format: 'umd',
name: 'scilla',
//sourcemap: true,
name,
},
plugins: [
resolve({
......@@ -22,7 +23,7 @@ export default {
typescript({
typescript: require('typescript'),
tslib: require('tslib'),
useTsconfigDeclarationDir: true,
declaration: false,
}),
commonjs(),
//uglify({}),
......
/**
* 一些重定义的类型
*/
/**
* 颜色
*/
export type color = string;
/**
* 资源
*/
export type resource = any;
/**
* 原数据
*/
export type raw = any;
export type dynamic = string;
\ No newline at end of file
/**
* 动态数据
*/
export type dynamic = string;
/**
* 常用框类型
*/
export interface Frame{
x?: number;
y?: number;
w?: number;
h?: number;
}
......@@ -13,6 +13,7 @@ import {EngineConfig} from "../engine-config";
let resCache = {};
let resPath = '';
let resCacheProxy;
const resLoaderType = {
'.json': loadJson,
......@@ -32,7 +33,7 @@ const resLoaderType = {
* 设置资源根路径
* @param path
*/
export function setResPath(path) {
export function setResPath(path: string) {
resPath = path;
}
......@@ -79,12 +80,12 @@ export function loadResItems(items: Array<any | string>, progress?: (percentage:
* @param url url
* @param uuid
* @param type 类型(json|text|arraybuffer|blob)
* @param cache
* @param config
* @param cache 是否缓存
* @param config 资源配置
* @param options 请求配置
* @return Promise<any> 资源
*/
export async function loadAny(url, uuid?, cache = true, config?, options = {}, type = 'arraybuffer'): Promise<any> {
export async function loadAny(url: string, uuid?: string, cache: boolean = true, config?: any, options = {}, type = 'arraybuffer'): Promise<any> {
let response = await fetch(resolveUrl(url), options);
let result;
......@@ -111,10 +112,10 @@ export async function loadAny(url, uuid?, cache = true, config?, options = {}, t
* @param url url
* @param uuid 唯一名
* @param cache 是否缓存
* @param config
* @param config 资源配置
* @return Promise<any> 资源
*/
export function loadTxt(url, uuid?, cache = true, config?): Promise<string> {
export function loadTxt(url: string, uuid?: string, cache: boolean = true, config?: any): Promise<string> {
let p = loadAny(url, uuid, cache, config, undefined, 'text');
if (cache) {
p.then(data => {
......@@ -131,10 +132,10 @@ export function loadTxt(url, uuid?, cache = true, config?): Promise<string> {
* @param url url
* @param uuid 唯一名
* @param cache 是否缓存
* @param config
* @param config 资源配置
* @return Promise<any> 资源
*/
export function loadJson(url, uuid?, cache = true, config?): Promise<any> {
export function loadJson(url: string, uuid?: string, cache: boolean = true, config?: any): Promise<any> {
let p = loadAny(url, uuid, cache, config, undefined, 'json');
if (cache) {
p.then(data => {
......@@ -151,10 +152,10 @@ export function loadJson(url, uuid?, cache = true, config?): Promise<any> {
* @param url url
* @param uuid 唯一名
* @param cache 是否缓存
* @param config
* @param config 资源配置
* @return Promise<any> 资源
*/
export async function loadJson5(url, uuid?, cache = true, config?): Promise<any> {
export async function loadJson5(url: string, uuid?: string, cache: boolean = true, config?: any): Promise<any> {
let txt = await loadTxt(url, uuid);
const jsonData = window['eval'](`(${txt})`);
cacheRes(jsonData, url, uuid);
......@@ -166,10 +167,10 @@ export async function loadJson5(url, uuid?, cache = true, config?): Promise<any>
* @param url url
* @param uuid 唯一名
* @param cache 是否缓存
* @param config
* @param config 资源配置
* @return Promise<any> 资源
*/
export function loadSheet(url, uuid?, cache = true, config?): Promise<Sheet> {
export function loadSheet(url: string, uuid?: string, cache: boolean = true, config?: any): Promise<Sheet> {
let pngFile = url.substring(0, url.lastIndexOf('.')) + '.png';
return Promise.all([
loadJson(url, null, false),
......@@ -206,14 +207,15 @@ export function loadSheet(url, uuid?, cache = true, config?): Promise<Sheet> {
/**
* 加载散列的图集
* @param url
* @param uuid
* @param cache
* @param config
* @param url url
* @param uuid 唯一名
* @param cache 是否缓存
* @param config 资源配置
* @return Promise<any> 资源
*/
export async function loadSheetDisperse(url, uuid?, cache = true, config?): Promise<Sheet> {
for(let {name, uuid} of config.textures){
let subUrl = url.replace('-disperse', '') + '/' + name + '.png';
export async function loadSheetDisperse(url: string, uuid?: string, cache: boolean = true, config?: any): Promise<Sheet> {
for (let {name, uuid} of config.textures) {
let subUrl = url.replace('-disperse', '') + '/' + name;
await loadTexture(subUrl, uuid);
}
......@@ -225,10 +227,10 @@ export async function loadSheetDisperse(url, uuid?, cache = true, config?): Prom
* @param url url
* @param uuid 唯一名
* @param cache 是否缓存
* @param config
* @param config 资源配置
* @return Promise<any> 资源
*/
export function loadFont(url, uuid?, cache = true, config?): Promise<Sheet> {
export function loadFont(url: string, uuid?: string, cache: boolean = true, config?: any): Promise<Sheet> {
return loadSheet(url, null, false).then(
sheet => {
if (cache) {
......@@ -256,10 +258,10 @@ function findAnimConfig(animations, name) {
* @param url url
* @param uuid 唯一名
* @param cache 是否缓存
* @param config
* @param config 资源配置
* @return Promise<any> 资源
*/
export function loadAnim(url, uuid?, cache = true, config?): Promise<FrameAnimation[]> {
export function loadAnim(url: string, uuid?: string, cache: boolean = true, config?: any): Promise<FrameAnimation[]> {
let pngFile = url.substring(0, url.lastIndexOf('.')) + '.png';
return Promise.all([
loadJson(url, null, false),
......@@ -295,10 +297,10 @@ export function loadAnim(url, uuid?, cache = true, config?): Promise<FrameAnimat
* @param url url
* @param uuid 唯一名
* @param cache 是否缓存
* @param config
* @param config 资源配置
* @return Promise<any> 资源
*/
export function loadImage(url, uuid?, cache = true, config?): Promise<any> {
export function loadImage(url: string, uuid?: string, cache: boolean = true, config?: any): Promise<any> {
return new Promise((resolve, reject) => {
let img = new Image();
if (EngineConfig.imgCrossOrigin) {
......@@ -319,10 +321,10 @@ export function loadImage(url, uuid?, cache = true, config?): Promise<any> {
* @param url url
* @param uuid 唯一名
* @param cache 是否缓存
* @param config
* @param config 资源配置
* @return Promise<any> 资源
*/
export async function loadImageFromBlob(url, uuid?, cache = true, config?): Promise<any> {
export async function loadImageFromBlob(url: string, uuid?: string, cache: boolean = true, config?: any): Promise<any> {
try {
const imgBlob = await loadAny(url, uuid, false, config, undefined, 'blob');
return await blobToImage(imgBlob);
......@@ -336,10 +338,10 @@ export async function loadImageFromBlob(url, uuid?, cache = true, config?): Prom
* @param url url
* @param uuid 唯一名
* @param cache 是否缓存
* @param config
* @param config 资源配置
* @return Promise<any> 资源
*/
export async function loadTexture(url, uuid?, cache = true, config?): Promise<Texture> {
export async function loadTexture(url: string, uuid?: string, cache: boolean = true, config?: any): Promise<Texture> {
const img: any = await loadImage(url, uuid, false);
const texture = createTexture(img);
if (cache) {
......@@ -353,10 +355,10 @@ export async function loadTexture(url, uuid?, cache = true, config?): Promise<Te
* @param url url
* @param uuid 唯一名
* @param cache 是否缓存
* @param config
* @param config 资源配置
* @return Promise<any> 资源
*/
export async function loadTextureFromBlob(url, uuid?, cache = true, config?): Promise<Texture> {
export async function loadTextureFromBlob(url: string, uuid?: string, cache: boolean = true, config?: any): Promise<Texture> {
const img: any = await loadImageFromBlob(url, uuid, false);
const texture = createTexture(img);
if (cache) {
......@@ -370,7 +372,7 @@ export async function loadTextureFromBlob(url, uuid?, cache = true, config?): Pr
* @param url url
* @return string 处理后的url
*/
function resolveUrl(url): string {
function resolveUrl(url: string): string {
if (url.indexOf('//') === 0 || url.indexOf('http:') === 0 || url.indexOf('https:') === 0) {
return url;
}
......@@ -382,7 +384,7 @@ function resolveUrl(url): string {
* @param ext
* @param url
*/
function getLoader(ext, url) {
function getLoader(ext: string, url: string): Function {
ext = ext || url.substr(url.lastIndexOf('.'));
return resLoaderType[ext] || loadAny;
}
......@@ -391,7 +393,7 @@ function getLoader(ext, url) {
* 根据url推断名称,只是获取短文件名
* @param url
*/
function getUUIDFromUrl(url) {
function getUUIDFromUrl(url): string {
return url.substring(url.lastIndexOf('/') + 1, url.lastIndexOf('.'))
}
......@@ -401,7 +403,7 @@ function getUUIDFromUrl(url) {
* @param url
* @param uuid
*/
export function cacheRes(res, url, uuid?) {
export function cacheRes(res, url: string, uuid?: string) {
uuid = uuid || getUUIDFromUrl(url);
resCache[uuid] = res;
}
......@@ -411,7 +413,7 @@ export function cacheRes(res, url, uuid?) {
* @param ext 需加载的文件后缀
* @param loader 加载方法,返回携带最终资源的Promise
*/
export function addLoader(ext, loader) {
export function addLoader(ext: string, loader: Function) {
resLoaderType[ext] = loader;
}
......@@ -419,15 +421,22 @@ export function addLoader(ext, loader) {
* 获取资源
* @param uuid
*/
export function getRes(uuid) {
export function getRes(uuid: string) {
if (resCacheProxy) {
return resCacheProxy(uuid);
}
return resCache[uuid];
}
export function setResCacheProxy(proxyFunc: Function) {
resCacheProxy = proxyFunc;
}
/**
* 销毁资源
* @param uuidOrUuids
*/
export function destroyRes(uuidOrUuids) {
export function destroyRes(uuidOrUuids: string | Array<string>) {
if (Array.isArray(uuidOrUuids)) {
while (uuidOrUuids.length > 0) {
delete resCache[uuidOrUuids.pop()];
......@@ -440,7 +449,7 @@ export function destroyRes(uuidOrUuids) {
/**
* 销毁全部资源
*/
export function destroyAllRes() {
export function destroyAllRes(): any {
for (let key in resCache) {
destroyRes(key);
}
......@@ -449,7 +458,7 @@ export function destroyAllRes() {
/**
* 获取所有uuid值
*/
export function getAllResUuids() {
export function getAllResUuids(): string[] {
return Object.keys(resCache);
}
......
......@@ -3,7 +3,7 @@
*/
import HashObject from "./HashObject";
import {Entity, } from "./Entity";
import {Entity,} from "./Entity";
import {EngineConfig} from "../engine-config";
const interactiveMap = [
......@@ -15,7 +15,7 @@ const interactiveMap = [
/**
* 组件基类
*/
export class ScillaComponent extends HashObject {
export class Component extends HashObject {
/**
* 所依附的实体
*/
......@@ -37,10 +37,12 @@ export class ScillaComponent extends HashObject {
if (this._enabled !== value) {
this._enabled = value;
if (this.entity && this.entity.isActive) {
if (this._enabled) {
this.onEnable();
} else {
this.onDisable();
if(!EngineConfig.editorMode){
if (this._enabled) {
this.onEnable();
} else {
this.onDisable();
}
}
}
}
......@@ -52,7 +54,9 @@ export class ScillaComponent extends HashObject {
*/
_setup(entity: Entity) {
this.entity = entity;
this.onCreate();
if(!EngineConfig.editorMode){
this.onCreate();
}
}
/**
......@@ -60,7 +64,9 @@ export class ScillaComponent extends HashObject {
*/
_unSetup() {
this.entity = null;
this.onDestroy();
if(!EngineConfig.editorMode){
this.onDestroy();
}
}
/**
......@@ -70,6 +76,12 @@ export class ScillaComponent extends HashObject {
}
$onAwake(){
if(!EngineConfig.editorMode){
this.onAwake();
}
}
/**
* 当组件被唤醒时
*/
......@@ -80,38 +92,48 @@ export class ScillaComponent extends HashObject {
/**
* 当组件生效时
*/
onEnable(){
onEnable() {
}
/**
* 当组件失效时
*/
onDisable(){
onDisable() {
}
$onUpdate(t) {
this.onUpdate(t);
if(!this._firstUpdate){
if (!this._firstUpdate) {
this.invokeDelayCallback(t);
}
this._firstUpdate = false;
}
private invokeDelayCallback(t){
const removed = [];
$onEditorUpdate(t) {
this.onEditorUpdate(t);
}
$afterUpdate(){
this.afterUpdate();
}
$afterEditorUpdate() {
this.afterEditorUpdate();
}
private invokeDelayCallback(t) {
for (let i = 0, li = this.delayCallbacks.length; i < li; i++) {
let {callback, once} = this.delayCallbacks[i];
if(once){
removed.push(i);
if (once) {
this.delayCallbacks.splice(i, 1);
i--;
li--;
}
callback.call(this, t);
}
for(let item of removed){
this.delayCallbacks.splice(item, 1);
}
}
/**
......@@ -122,6 +144,10 @@ export class ScillaComponent extends HashObject {
}
onEditorUpdate(t) {
}
/**
* 当子节点的时钟更新结束后
*/
......@@ -129,6 +155,16 @@ export class ScillaComponent extends HashObject {
}
afterEditorUpdate(){
}
$onSleep() {
if(!EngineConfig.editorMode){
this.onSleep();
}
}
/**
* 当组件沉睡时
*/
......@@ -149,14 +185,14 @@ export class ScillaComponent extends HashObject {
* @param key
* @param oldValue
*/
protected onModify(value, key, oldValue){
protected onModify(value, key, oldValue) {
}
private getDelayCallback(callback){
private getDelayCallback(callback) {
let result;
for(let item of this.delayCallbacks){
if(item.callback == callback){
for (let item of this.delayCallbacks) {
if (item.callback == callback) {
result = item;
break;
}
......@@ -176,10 +212,10 @@ export class ScillaComponent extends HashObject {
}
}
cancelOnNextTick(callback){
cancelOnNextTick(callback) {
const item = this.getDelayCallback(callback);
const index = this.delayCallbacks.indexOf(item);
if(index >= 0){
if (index >= 0) {
this.delayCallbacks.splice(index, 1);
}
}
......@@ -192,21 +228,21 @@ export class ScillaComponent extends HashObject {
onInteract(type, event) {
try {
const hitOn = this[interactiveMap[type]](event);
return hitOn && this['touchInterrupt'];
return hitOn;
} catch (e) {
console.warn(e);
}
}
_dealGlobalTouchBegin(e) {
_dealGlobalTouchBegin(e): boolean {
return this.onGlobalTouchBegin(e);
}
_dealGlobalTouchMove(e) {
_dealGlobalTouchMove(e): boolean {
return this.onGlobalTouchMove(e);
}
_dealGlobalTouchEnd(e) {
_dealGlobalTouchEnd(e): boolean {
return this.onGlobalTouchEnd(e);
}
......@@ -214,28 +250,24 @@ export class ScillaComponent extends HashObject {
* 当全局触摸开始
* @param e
*/
onGlobalTouchBegin(e) {
onGlobalTouchBegin(e): boolean {
return false;
}
/**
* 当全触摸移动
* @param e
*/
onGlobalTouchMove(e) {
onGlobalTouchMove(e): boolean {
return false;
}
/**
* 当全触摸结束
* @param e
*/
onGlobalTouchEnd(e) {
}
get transform(){
return this.entity.getComponent('components/base/Transform');
onGlobalTouchEnd(e): boolean {
return false;
}
/**
......
......@@ -3,7 +3,7 @@
*/
import HashObject from "./HashObject";
import {ScillaComponent} from "./ScillaComponent";
import {Component} from "./Component";
import {EngineConfig} from "../engine-config";
/**
......@@ -27,7 +27,7 @@ export function traverse(target: Entity, hitChild: (child: Entity, ...params) =>
interrupt = true;
continue;
}
if(child.children.length > 0){
if (child.children.length > 0) {
traverse(child, hitChild, level - 1, false, fullCallback, ...params);
}
}
......@@ -52,7 +52,7 @@ export function traversePostorder(target: Entity, hitChild: (child: Entity, ...p
for (let i = target.children.length - 1; i >= 0; i--) {
const child = target.children[i];
if(traversePostorder(child, hitChild, level - 1, false, fullCallback, ...params)){
if (traversePostorder(child, hitChild, level - 1, false, fullCallback, ...params)) {
return true;
}
if (hitChild(child, ...params)) {
......@@ -101,9 +101,9 @@ export class Entity extends HashObject {
protected _enabled: boolean = EngineConfig.entityEnabled;
protected _parent: Entity = null;
protected _children: Entity[] = [];
protected _components: ScillaComponent[] = [];
protected _components: Component[] = [];
constructor(name?, uuid?) {
constructor(name?: string, uuid?: string) {
super();
if (name) {
......@@ -136,7 +136,7 @@ export class Entity extends HashObject {
}
}
_invokeEnabledState(enabled) {
_invokeEnabledState(enabled: boolean) {
if (this._enabled && enabled) {
this.onEnable();
} else if (!this._enabled && !enabled) {
......@@ -144,18 +144,18 @@ export class Entity extends HashObject {
}
}
get isParentActive() {
get isParentActive(): boolean {
return this._parent && this._parent.enabled && !this._parent.isFree;
}
get isActive() {
get isActive(): boolean {
return this.isParentActive && this._enabled;
}
/**
* 是否游离状态
*/
get isFree() {
get isFree(): boolean {
return this._isFree;
}
......@@ -166,7 +166,7 @@ export class Entity extends HashObject {
this._isFree = true;
let that = this;
traverse(this, function(child: Entity) {
traverse(this, function (child: Entity) {
/*if (child.isParentActive) {
that._invokeEnabledState(false);
}*/
......@@ -182,7 +182,7 @@ export class Entity extends HashObject {
this._isFree = false;
let that = this;
traverse(this, function(child: Entity) {
traverse(this, function (child: Entity) {
/*if (child.isParentActive) {
that._invokeEnabledState(true);
}*/
......@@ -196,7 +196,7 @@ export class Entity extends HashObject {
/**
* 获取父节点
*/
get parent() {
get parent(): Entity {
return this._parent;
}
......@@ -204,7 +204,7 @@ export class Entity extends HashObject {
* 是否含有子节点
* @param child
*/
containsChild(child: Entity) {
containsChild(child: Entity): boolean {
return this.getChildIndex(child) >= 0;
}
......@@ -291,7 +291,7 @@ export class Entity extends HashObject {
* 移除指定索引的节点
* @param index
*/
removeChildAt(index) {
removeChildAt(index: number) {
const child = this._children[index];
this._onChildRemoved(child);
......@@ -302,7 +302,7 @@ export class Entity extends HashObject {
* 根据节点获取索引
* @param child
*/
getChildIndex(child: Entity) {
getChildIndex(child: Entity): number {
return this._children.indexOf(child)
}
......@@ -310,10 +310,25 @@ export class Entity extends HashObject {
* 获取指定索引的节点
* @param index
*/
getChildByIndex(index) {
getChildByIndex(index): Entity {
return this._children[index];
}
/**
* 获取指定名字的节点
* @param name
*/
getChildrenByName(name): Entity[] {
let children = [];
for (let child of this._children) {
if (child.name === name) {
children.push(child);
}
}
return children;
}
/**
* 移除所有子节点
*/
......@@ -326,7 +341,7 @@ export class Entity extends HashObject {
/**
* 获取所有子节点
*/
get children() {
get children(): Entity[] {
return this._children;
}
......@@ -336,7 +351,7 @@ export class Entity extends HashObject {
* 增加组件
* @param component
*/
addComponent(component: ScillaComponent) {
addComponent(component: Component) {
this.onAddComponent(component);
this._components.push(component);
}
......@@ -346,7 +361,7 @@ export class Entity extends HashObject {
* @param component
* @param index
*/
addComponentAt(component: ScillaComponent, index) {
addComponentAt(component: Component, index: number) {
const currentIndex = this._components.indexOf(component);
if (currentIndex == index) {
return;
......@@ -363,7 +378,7 @@ export class Entity extends HashObject {
* 移除组件
* @param component
*/
removeComponent(component: ScillaComponent) {
removeComponent(component: Component) {
this.onRemoveComponent(component);
const index = this._components.indexOf(component);
if (index >= 0) {
......@@ -380,28 +395,46 @@ export class Entity extends HashObject {
}
}
/**
* 根据组件名称获取指定类的组件列表
* @param name
*/
getComponentsByName<T extends Component>(name: string): T[] {
return <T[]>this._components.filter((value: Component) => {
return value.constructor['__class__'] === name;
});
}
/**
* 获取指定类的组件列表
* @param clazz
*/
getComponents(clazz: any): any[] {
return this._components.filter((component: any) => {
return typeof clazz === 'string' ? component.constructor.__class__ === clazz : component instanceof clazz;
getComponents<T extends Component>(clazz: new()=> T): T[] {
return <T[]>this._components.filter((component: Component) => {
return component instanceof clazz;
});
}
/**
* 获取指定类的组件
* @param name
*/
getComponentByName<T extends Component>(name: string): T {
return this.getComponentsByName<T>(name)[0];
}
/**
* 获取指定类的组件
* @param clazz
*/
getComponent(clazz: any) {
return this.getComponents(clazz)[0];
getComponent<T extends Component>(clazz: new()=> T): T {
return this.getComponents<T>(clazz)[0];
}
/**
* 获取所有组件
*/
get components() {
get components(): Component[] {
return this._components;
}
......@@ -425,7 +458,7 @@ export class Entity extends HashObject {
onEnable() {
this.forEachComponent(comp => {
if (comp.enabled) {
return comp.onAwake();
return comp.$onAwake();
}
});
}
......@@ -436,19 +469,23 @@ export class Entity extends HashObject {
onDisable() {
this.forEachComponent(comp => {
if (comp.enabled) {
return comp.onSleep();
return comp.$onSleep();
}
});
}
/**
* 当始终更新时
* 当时钟更新时
* @param t
*/
onUpdate(t) {
this.forEachComponent(comp => {
if (comp.enabled) {
return comp.$onUpdate(t);
if (EngineConfig.editorMode) {
return comp.$onEditorUpdate(t);
} else {
return comp.$onUpdate(t);
}
}
});
}
......@@ -458,8 +495,12 @@ export class Entity extends HashObject {
*/
afterUpdate() {
this.forEachComponent(comp => {
if(comp.enabled){
return comp.afterUpdate();
if (comp.enabled) {
if (EngineConfig.editorMode) {
return comp.$afterEditorUpdate();
} else {
return comp.$afterUpdate();
}
}
});
}
......@@ -491,7 +532,7 @@ export class Entity extends HashObject {
* 当添加组件时
* @param component
*/
onAddComponent(component: ScillaComponent) {
onAddComponent(component: Component) {
component._setup(this);
if (EngineConfig.awakeComponentWhenAdded) {
this.awakeComponent(component);
......@@ -504,7 +545,7 @@ export class Entity extends HashObject {
*/
awakeComponent(component) {
if (!this._isFree && this._enabled) {
component.onAwake();
component.$onAwake();
}
}
......@@ -512,7 +553,7 @@ export class Entity extends HashObject {
* 当移除组件时
* @param component
*/
onRemoveComponent(component: ScillaComponent) {
onRemoveComponent(component: Component) {
if (EngineConfig.sleepComponentWhenRemoved) {
this.sleepComponent(component);
}
......@@ -523,9 +564,9 @@ export class Entity extends HashObject {
* 睡眠组件
* @param component
*/
sleepComponent(component) {
sleepComponent(component: Component) {
if (!this._isFree && this._enabled) {
component.onSleep();
component.$onSleep();
}
}
......@@ -536,7 +577,7 @@ export class Entity extends HashObject {
* @param level 深度,默认全部遍历
* @param params 参数
*/
broadcast(method, level = -1, ...params) {
broadcast(method: string, level = -1, ...params) {
traverse(this, this.invokeOnEntity, level, true, null, method, ...params)
}
......@@ -546,7 +587,7 @@ export class Entity extends HashObject {
* @param method 方法名
* @param params 参数
*/
bubbling(method, ...params) {
bubbling(method: string, ...params) {
bubbling(this, this.invokeOnEntity, false, method, ...params);
}
......@@ -556,7 +597,7 @@ export class Entity extends HashObject {
* @param method 方法名
* @param params 参数
*/
private invokeOnEntity = (hitEntity: Entity, method, ...params): boolean => {
private invokeOnEntity = (hitEntity: Entity, method: string, ...params): boolean => {
let hitBreak = false;
hitEntity.forEachComponent(comp => {
const m = comp[method];
......
......@@ -12,7 +12,7 @@ const textureMap = {};
* 获取一个帧动画资源
* @param name
*/
export function getFrameAnimation(name): FrameAnimation {
export function getFrameAnimation(name: string): FrameAnimation {
let animation: FrameAnimation = animationMap[name];
if (!animation) {
animation = animationMap[name] = new FrameAnimationImpl(name);
......@@ -27,7 +27,7 @@ export function getFrameAnimation(name): FrameAnimation {
* @param img
* @param data
*/
export function putFrameAnim(img, data) {
export function putFrameAnim(img: any, data: any) {
const {mc, res} = data;
let sheet: Sheet = new Sheet(img, res);
......@@ -46,7 +46,7 @@ export interface FrameAnimation {
* 填充帧数据
* @param name
*/
fillMcData(name);
fillMcData(name: string);
/**
* 获取帧率
......@@ -66,13 +66,13 @@ export interface FrameAnimation {
* 根据名字获取帧标签
* @param name
*/
getLabel(name): any;
getLabel(name: string): any;
/**
* 获取帧
* @param frameIndex
*/
getFrame(frameIndex): any;
getFrame(frameIndex: number): any;
/**
* 销毁自身
......@@ -87,7 +87,7 @@ export class FrameAnimationImpl implements FrameAnimation {
private readonly _name: string;
private _animData;
constructor(name) {
constructor(name: string) {
this._name = name;
}
......@@ -95,7 +95,7 @@ export class FrameAnimationImpl implements FrameAnimation {
return this._name;
}
fillMcData(name) {
fillMcData(name: string) {
const animData = animDataMap[name];
if (animData) {
this._animData = animData;
......@@ -116,7 +116,7 @@ export class FrameAnimationImpl implements FrameAnimation {
return this._animData.frames.length;
}
getLabel(name): any {
getLabel(name: string): any {
let result;
for (let label of this._animData.labels) {
if (label.name == name) {
......@@ -128,7 +128,7 @@ export class FrameAnimationImpl implements FrameAnimation {
return result;
}
getFrame(frameIndex): any {
getFrame(frameIndex: number): any {
const {_animData,} = this;
let texture, frameData;
......
......@@ -2,7 +2,7 @@
* Created by rockyl on 2018/11/5.
*/
let HASH_CODE_INK = 0;
let HASH_CODE_INK: number = 0;
function getHashCode() {
return ++HASH_CODE_INK;
......@@ -12,13 +12,13 @@ function getHashCode() {
* 哈希对象
*/
export default class HashObject {
_hashCode;
_hashCode: number;
constructor() {
this._hashCode = getHashCode();
}
get hashCode() {
get hashCode(): number {
return this._hashCode;
}
}
......@@ -4,6 +4,9 @@
import {Entity} from "./Entity";
import {loadResItems} from "../assets-manager";
/**
* 场景
*/
export class Scene {
name: string;
root: Entity;
......@@ -14,7 +17,11 @@ export class Scene {
config: any;
initByConfig(config){
/**
* 初始化
* @param config
*/
initByConfig(config: any){
this.config = config;
this.name = config.name;
......@@ -24,6 +31,11 @@ export class Scene {
}
}
/**
* 加载资源组
* @param name
* @param progress
*/
async loadResGroup(name, progress?){
await loadResItems(this.resourceGroups[name], progress);
}
......
......@@ -3,7 +3,8 @@
*/
import HashObject from "../core/HashObject";
import {createTexture} from "./Texture";
import Texture, {createTexture} from "./Texture";
import {Frame} from "../ReType";
/**
* 图集
......@@ -20,7 +21,7 @@ export class Sheet extends HashObject{
private _textureCache: any = {};
constructor(img?, frames?) {
constructor(img?, frames?: Frame) {
super();
if(img){
......@@ -45,7 +46,7 @@ export class Sheet extends HashObject{
* @param name
* @param force
*/
generateTexture(name, force = false) {
generateTexture(name: string, force = false): Texture {
const {img, frames, _textureCache} = this;
if (!force && _textureCache[name]) {
......@@ -62,7 +63,7 @@ export class Sheet extends HashObject{
* 是否有这个纹理
* @param name
*/
hasTexture(name) {
hasTexture(name): boolean {
return !!frames[name];
}
......@@ -70,7 +71,7 @@ export class Sheet extends HashObject{
* 获取纹理
* @param name
*/
getTexture(name) {
getTexture(name): Texture {
let texture = this._textureCache[name];
if (texture) {
return texture;
......@@ -82,7 +83,7 @@ export class Sheet extends HashObject{
/**
* 获取全部存在的纹理
*/
getAllTextures() {
getAllTextures(): Texture[] {
return this._textureCache;
}
......
......@@ -5,6 +5,7 @@
import Bounds from "../support/Bounds";
import HashObject from "../core/HashObject";
import {createCanvas} from "./context/RenderContext";
import {Frame} from "../ReType";
/**
* 纹理类
......@@ -25,7 +26,7 @@ export default class Texture extends HashObject {
* 设置图集中的坐标和尺寸
* @param frame
*/
setFrame(frame) {
setFrame(frame: Frame) {
let {x, y, w, h} = frame;
this.bounds.setTo(x, y, w, h);
}
......@@ -62,8 +63,8 @@ export default class Texture extends HashObject {
if (!canvas) {
canvas = this._cacheCanvas = createCanvas();
}
canvas.width = width;
canvas.height = height;
canvas.stageWidth = width;
canvas.stageHeight = height;
const context = canvas.getContext('2d');
this.drawToCanvas(context);
......@@ -99,7 +100,7 @@ export default class Texture extends HashObject {
/**
* 销毁缓存画布
*/
destroyCacheCanvas(){
destroyCacheCanvas() {
this._cacheCanvas = null;
}
}
......@@ -109,7 +110,7 @@ export default class Texture extends HashObject {
* @param img
* @param frame
*/
export function createTexture(img, frame?): Texture {
export function createTexture(img, frame?: Frame): Texture {
const texture = new Texture();
texture.setImg(img);
texture.setFrame(frame || {x: 0, y: 0, w: img.width, h: img.height});
......
This diff is collapsed.
......@@ -2,14 +2,14 @@
* Created by rockyl on 2018/11/5.
*/
export {ScillaComponent} from "./ScillaComponent";
export {Component} from "./Component";
export {Entity} from './Entity'
export {Scene} from './Scene'
export {ScillaEvent} from './ScillaEvent'
export {getContext, createCanvas, getStageSize, getStageScale, getStageCenter, shortcut, ScaleMode} from './context/RenderContext';
export {createCanvas, ScaleMode} from './context/RenderContext';
export {pagePosToCanvasPos, canvasPosToPagePos} from './context/InteractContext';
export * from './manager'
export {default as Texture, createTexture} from './Texture'
export * from './Sheet'
export * from './FrameAnimation'
\ No newline at end of file
export * from './FrameAnimation'
......@@ -5,14 +5,13 @@
import {Entity, traverse, traversePostorder} from "./Entity";
import {injectProp} from "../tools/utils";
import {setupContext as setupInteractContext} from "./context/InteractContext";
import {clear, ScaleMode, setupContext as setupRenderContext} from "./context/RenderContext";
import RenderContext, {ScaleMode} from "./context/RenderContext";
import './requestAnimationFrame';
/**
* 默认配置
*/
let options: any = {
export const engineConfig: any = {
fps: 60,
designWidth: 750,
designHeight: 1334,
......@@ -20,24 +19,33 @@ let options: any = {
touchEnabled: true,
};
/**
* 自定义参数
*/
export const customConfig: any = {};
let root: Entity;
let _flush = 0, _currentFlush = 0;
let tsStart, tsLast;
let lastFPS = 0;
let renderContext, interactContext;
/**
* 装配引擎
* @param _options
* @param _engineConfig
* @param _customConfig
*/
export function setup(_options?) {
injectProp(options, _options);
export function setup(_engineConfig?, _customConfig?) {
injectProp(engineConfig, _engineConfig);
injectProp(customConfig, _customConfig);
const {canvas, designWidth, designHeight, scaleMode, modifyCanvasSize, touchEnabled} = options;
const {canvas, designWidth, designHeight, scaleMode, modifyCanvasSize, touchEnabled} = engineConfig;
let canvasElement = typeof canvas == 'object' ? canvas : document.getElementById(canvas);
setupInteractContext({
interactContext = setupInteractContext({
canvas: canvasElement,
touchHandler: {
onTouchBegin,
......@@ -47,7 +55,8 @@ export function setup(_options?) {
touchEnabled,
});
setupRenderContext({
renderContext = new RenderContext();
renderContext.setup({
canvas: canvasElement,
designWidth,
designHeight,
......@@ -103,7 +112,7 @@ export function getEntityPath(entity?: Entity): string {
* 根据节点路径获取节点
* @param path
*/
export function getEntityByPath(path?: string): Entity{
export function getEntityByPath(path?: string): Entity {
let target = root;
if (path.length > 0) {
......@@ -126,11 +135,18 @@ export function getFPS() {
return lastFPS;
}
/**
* 获取渲染上下文
*/
export function getRenderContext(): RenderContext {
return renderContext;
}
/**
* 开始时钟
*/
function startTick() {
_flush = 60 / options.fps - 1 >> 0;
_flush = 60 / engineConfig.fps - 1 >> 0;
if (_flush < 0) {
_flush = 0;
}
......@@ -166,12 +182,18 @@ function flush(tsNow): void {
}
const nextTicks = [];
export function nextTick(func){
nextTicks.push(func);
/**
* 下一帧执行
* @param func
* @param tickCount
*/
export function nextTick(func, tickCount = 1) {
nextTicks.push({func, tickCount});
}
function onFrameTick(tsNow) {
clear();
renderContext.clear();
const tsNow2 = Date.now();
lastFPS = Math.floor(1000 / (tsNow - tsLast));
tsLast = tsNow;
......@@ -188,9 +210,17 @@ function onFrameTick(tsNow) {
});
//const tsPass = Date.now() - tsNow;
while(nextTicks.length > 0){
let func = nextTicks.shift();
func();
for (let i = 0, li = nextTicks.length; i < li; i++) {
const item = nextTicks[i];
item.tickCount--;
if (item.tickCount <= 0) {
item.func(ts);
nextTicks.splice(i, 1);
i--;
li--;
}
}
}
......
......@@ -4,7 +4,7 @@
import {cleanEntity, setupScene, } from "./interpreter";
import {addLoader, cacheRes, destroyRes, getAllResUuids, loadJson5} from "../assets-manager";
import {getRoot, pause, Scene, start} from "../core";
import {customConfig, getRoot, pause, Scene, start} from "../core";
export * from './interpreter'
......@@ -13,11 +13,17 @@ let resUUIDs;
/**
* 启动场景
* @param name
* @param sceneNameOrPath
* @param progress
*/
export async function launchScene(name, progress?) {
const scene = await loadScene(`scenes/${name}.scene`, 'scene_' + name);
export async function launchScene(sceneNameOrPath, progress?) {
const sceneConfig = customConfig.scene;
let sceneFile = sceneConfig.scenes[sceneNameOrPath];
if(!sceneFile){
sceneFile = sceneNameOrPath;
}
const scene = await loadScene(sceneFile, 'scene_' + sceneFile);
resUUIDs = getAllResUuids();
......
......@@ -6,13 +6,19 @@
import {Entity, Scene, ScillaEvent} from "../core";
import {getRes} from "../assets-manager";
import {EngineConfig} from "../engine-config";
let entityCache = {};
let entityCacheConfig;
const defMap = {};
let prefabID: number = 0;
export function registerDef(name, def) {
/**
* 注册组件
* @param name
* @param def
*/
export function registerDef(name: string, def) {
defMap[name] = def;
def.__class__ = name;
}
......@@ -87,7 +93,7 @@ function instantiateConfig(config, root?: Entity): Entity {
* @param root
* @param pid
*/
function setupEntity(config, root?: Entity, pid?): Entity {
function setupEntity(config, root?: Entity, pid?: number): Entity {
let entity: Entity = null;
if (config) {
let {name, uuid, children} = config;
......@@ -123,7 +129,7 @@ function setupEntity(config, root?: Entity, pid?): Entity {
* @param root
* @param includeSelf
*/
function setupComponent(config, root: Entity, includeSelf = false) {
function setupComponent(config, root: Entity, includeSelf: boolean = false) {
if (includeSelf) {
instantiateComponents(root, config);
}
......@@ -146,7 +152,7 @@ function setupComponent(config, root: Entity, includeSelf = false) {
* @param includeSelf
* @param pid
*/
function injectComponent(config, root: Entity, includeSelf = false, pid?) {
function injectComponent(config, root: Entity, includeSelf = false, pid?: number) {
if (includeSelf) {
injectComponents(root, config, pid);
}
......@@ -181,7 +187,7 @@ function instantiateComponents(entity: Entity, config: any) {
* @param config
* @param pid
*/
function injectComponents(entity: Entity, config: any, pid?) {
function injectComponents(entity: Entity, config: any, pid?: number) {
if (config.components) {
const components = entity.components;
for (let i = 0, li = config.components.length; i < li; i++) {
......@@ -192,7 +198,13 @@ function injectComponents(entity: Entity, config: any, pid?) {
}
}
export function injectComponentProperties(component, config, pid?){
/**
* 注入组件属性
* @param component
* @param config
* @param pid
*/
export function injectComponentProperties(component, config, pid?: number){
const {properties} = config;
if (properties) {
......@@ -224,15 +236,16 @@ export function instantiateComponent(entity: Entity, config: any) {
/**
* 根据名称获取定义
* @param name
* @param showWarn
*/
function getDefByName(name): any {
export function getDefByName(name: string, showWarn: boolean = true): any {
let def;
/*if (name.indexOf('/') >= 0) {//addition
name = name.substr(name.lastIndexOf('/') + 1);
}*/
def = defMap[name];
if (!def) {
if (!def && showWarn) {
console.warn('missing def:', name);
return;
}
......@@ -248,7 +261,7 @@ const skipKeys = ['_type_', '_constructor_'];
* @param propertiesConfig
* @param pid
*/
function injectProperties(node, propertiesConfig, pid?) {
function injectProperties(node, propertiesConfig, pid?: number) {
if (!node) {
console.warn('node is null.');
return;
......@@ -261,7 +274,9 @@ function injectProperties(node, propertiesConfig, pid?) {
let propertyOfInstance = node[key];
if (typeof propertyOfConfig === 'object') {
if (propertyOfInstance instanceof ScillaEvent) {
injectEvent(propertyOfInstance, propertyOfConfig, pid);
if(!EngineConfig.editorMode){
injectEvent(propertyOfInstance, propertyOfConfig, pid);
}
} else if (propertyOfConfig._type_ === 'raw') {
node[key] = propertyOfInstance = propertyOfConfig.data;
} else {
......@@ -276,7 +291,7 @@ function injectProperties(node, propertiesConfig, pid?) {
}
}
function injectObject(propertyOfInstance, propertyOfConfig, pid?) {
function injectObject(propertyOfInstance, propertyOfConfig, pid?: number) {
if (propertyOfInstance === undefined) {
if (propertyOfConfig._type_) {
let def = getDefByName(propertyOfConfig._type_);
......@@ -296,7 +311,7 @@ function injectObject(propertyOfInstance, propertyOfConfig, pid?) {
return propertyOfInstance;
}
function injectBaseType(node, key, propertyOfConfig, pid?) {
function injectBaseType(node, key, propertyOfConfig, pid?: number) {
let propertyValue;
if (typeof propertyOfConfig === 'string') {
propertyValue = getLink(propertyOfConfig, pid);
......@@ -304,7 +319,11 @@ function injectBaseType(node, key, propertyOfConfig, pid?) {
propertyValue = propertyOfConfig;
}
node[key] = propertyValue;
let keyAvatar = key;
if(propertyValue instanceof Promise){
keyAvatar = 'async_' + keyAvatar;
}
node[keyAvatar] = propertyValue;
}
function injectEvent(event: ScillaEvent, config, pid?) {
......@@ -324,7 +343,7 @@ function injectEvent(event: ScillaEvent, config, pid?) {
}
}
function getLink(str: string, pid?) {
function getLink(str: string, pid?: number) {
let result;
if (str.indexOf('res|') == 0) { //res uuid
const uuid = str.substr(4);
......@@ -338,6 +357,6 @@ function getLink(str: string, pid?) {
return result;
}
function transPrefabUUID(uuid, pid) {
function transPrefabUUID(uuid, pid: number) {
return pid ? pid + '_' + uuid : uuid;
}
......@@ -12,6 +12,7 @@ export const EngineConfig = {
sleepComponentWhenRemoved: true,
drawRenderRect: false,
imgCrossOrigin: true,
editorMode: false,
};
export function modifyEngineConfig(_options) {
......
......@@ -7,86 +7,116 @@
* 边界类
*/
export default class Bounds {
x;
y;
width;
height;
x: number;
y: number;
width: number;
height: number;
constructor(x = 0, y = 0, width = 0, height = 0) {
constructor(x: number = 0, y: number = 0, width: number = 0, height: number = 0) {
this.x = x;
this.y = y;
this.width = width;
this.height = height;
}
get left() {
get left(): number {
return this.x;
}
set left(v) {
set left(v: number) {
this.x = v;
}
get top() {
get top(): number {
return this.y;
}
set top(v) {
set top(v: number) {
this.y = v;
}
get right() {
get right(): number {
return this.x + this.width;
}
set right(v) {
set right(v: number) {
this.width = v - this.x;
}
get bottom() {
get bottom(): number {
return this.y + this.height;
}
set bottom(v) {
set bottom(v: number) {
this.height = v - this.y;
}
contains(x, y) {
/**
* 是否包含点
* @param x
* @param y
*/
contains(x: number, y: number): boolean {
return this.x <= x &&
this.x + this.width >= x &&
this.y <= y &&
this.y + this.height >= y;
}
setTo(x, y, width, height) {
/**
* 设置
* @param x
* @param y
* @param width
* @param height
*/
setTo(x: number, y: number, width: number, height: number) {
this.x = x;
this.y = y;
this.width = width;
this.height = height;
}
copyFrom(target) {
/**
* 复制一个边界
* @param target
*/
copyFrom(target: Bounds) {
this.x = target.x;
this.y = target.y;
this.width = target.width;
this.height = target.height;
}
clone() {
/**
* 克隆
*/
clone(): Bounds {
return new Bounds(this.x, this.y, this.width, this.height)
}
inflate(dx, dy) {
/**
* 扩展
* @param dx
* @param dy
*/
inflate(dx: number, dy: number) {
this.x -= dx;
this.width += 2 * dx;
this.y -= dy;
this.height += 2 * dy;
}
isEmpty() {
/**
* 是否是空边界
*/
isEmpty(): boolean {
return this.width <= 0 || this.height <= 0;
}
/**
* 置空
*/
setEmpty() {
this.x = 0;
this.y = 0;
......@@ -94,12 +124,20 @@ export default class Bounds {
this.height = 0;
}
intersects(toIntersect) {
/**
* 横切
* @param toIntersect
*/
intersects(toIntersect: Bounds): boolean {
return Math.max(this.x, toIntersect.x) <= Math.min(this.right, toIntersect.right)
&& Math.max(this.y, toIntersect.y) <= Math.min(this.bottom, toIntersect.bottom);
}
containsBounds(bounds) {
/**
* 是否包含另一个边界
* @param bounds
*/
containsBounds(bounds: Bounds): boolean {
let r1 = bounds.x + bounds.width;
let b1 = bounds.y + bounds.height;
let r2 = this.x + this.width;
......@@ -107,7 +145,11 @@ export default class Bounds {
return (bounds.x >= this.x) && (bounds.x < r2) && (bounds.y >= this.y) && (bounds.y < b2) && (r1 > this.x) && (r1 <= r2) && (b1 > this.y) && (b1 <= b2);
}
equals(toCompare) {
/**
* 判断是否相等
* @param toCompare
*/
equals(toCompare: Bounds): boolean {
if (this === toCompare) {
return true;
}
......@@ -115,7 +157,7 @@ export default class Bounds {
&& this.width === toCompare.width && this.height === toCompare.height;
}
toString() {
toString(): string {
const {x, y, width, height} = this;
return "(x=" + x + ", y=" + y + ", width=" + width + ", height=" + height + ")";
}
......
/**
* Created by rockyl on 2018-12-07.
*/
import {dirtyFieldTrigger} from "../tools/decorators";
const hsv2hsl = function(hue, sat, val) {
return [
hue,
(sat * val / ((hue = (2 - sat) * val) < 1 ? hue : 2 - hue)) || 0,
hue / 2
];
};
// Need to handle 1.0 as 100%, since once it is a number, there is no difference between it and 1
// <http://stackoverflow.com/questions/7422072/javascript-how-to-detect-number-as-a-decimal-including-1-0>
const isOnePointZero = function(n) {
return typeof n === 'string' && n.indexOf('.') !== -1 && parseFloat(n) === 1;
};
const isPercentage = function(n) {
return typeof n === 'string' && n.indexOf('%') !== -1;
};
// Take input from [0, n] and return it as [0, 1]
const bound01 = function(value, max) {
if (isOnePointZero(value)) value = '100%';
const processPercent = isPercentage(value);
value = Math.min(max, Math.max(0, parseFloat(value)));
// Automatically convert percentage into number
if (processPercent) {
value = Math.floor(value * max) / 100;
}
// Handle floating point rounding errors
if ((Math.abs(value - max) < 0.000001)) {
return 1;
}
// Convert into [0, 1] range if it isn't already
return (value % max) / parseFloat(max);
};
const INT_HEX_MAP = { 10: 'A', 11: 'B', 12: 'C', 13: 'D', 14: 'E', 15: 'F' };
const toHex = function({ r, g, b }) {
const hexOne = function(value) {
value = Math.min(Math.round(value), 255);
const high = Math.floor(value / 16);
const low = value % 16;
return '' + (INT_HEX_MAP[high] || high) + (INT_HEX_MAP[low] || low);
};
if (isNaN(r) || isNaN(g) || isNaN(b)) return '';
return '#' + hexOne(r) + hexOne(g) + hexOne(b);
};
const HEX_INT_MAP = { A: 10, B: 11, C: 12, D: 13, E: 14, F: 15 };
const parseHexChannel = function(hex) {
if (hex.length === 2) {
return (HEX_INT_MAP[hex[0].toUpperCase()] || +hex[0]) * 16 + (HEX_INT_MAP[hex[1].toUpperCase()] || +hex[1]);
}
return HEX_INT_MAP[hex[1].toUpperCase()] || +hex[1];
};
const hsl2hsv = function(hue, sat, light) {
sat = sat / 100;
light = light / 100;
let smin = sat;
const lmin = Math.max(light, 0.01);
let sv;
let v;
light *= 2;
sat *= (light <= 1) ? light : 2 - light;
smin *= lmin <= 1 ? lmin : 2 - lmin;
v = (light + sat) / 2;
sv = light === 0 ? (2 * smin) / (lmin + smin) : (2 * sat) / (light + sat);
return {
h: hue,
s: sv * 100,
v: v * 100
};
};
// `rgbToHsv`
// Converts an RGB color value to HSV
// *Assumes:* r, g, and b are contained in the set [0, 255] or [0, 1]
// *Returns:* { h, s, v } in [0,1]
const rgb2hsv = function(r, g, b) {
r = bound01(r, 255);
g = bound01(g, 255);
b = bound01(b, 255);
const max = Math.max(r, g, b);
const min = Math.min(r, g, b);
let h, s;
let v = max;
const d = max - min;
s = max === 0 ? 0 : d / max;
if (max === min) {
h = 0; // achromatic
} else {
switch (max) {
case r:
h = (g - b) / d + (g < b ? 6 : 0);
break;
case g:
h = (b - r) / d + 2;
break;
case b:
h = (r - g) / d + 4;
break;
}
h /= 6;
}
return { h: h * 360, s: s * 100, v: v * 100 };
};
// `hsvToRgb`
// Converts an HSV color value to RGB.
// *Assumes:* h is contained in [0, 1] or [0, 360] and s and v are contained in [0, 1] or [0, 100]
// *Returns:* { r, g, b } in the set [0, 255]
const hsv2rgb = function(h, s, v) {
h = bound01(h, 360) * 6;
s = bound01(s, 100);
v = bound01(v, 100);
const i = Math.floor(h);
const f = h - i;
const p = v * (1 - s);
const q = v * (1 - f * s);
const t = v * (1 - (1 - f) * s);
const mod = i % 6;
const r = [v, q, p, p, t, v][mod];
const g = [t, v, v, q, p, p][mod];
const b = [p, p, t, v, v, q][mod];
return {
r: Math.round(r * 255),
g: Math.round(g * 255),
b: Math.round(b * 255)
};
};
/**
* 颜色
*/
export default class Color {
enableAlpha;
format;
private _hue;
private _saturation;
private _value;
private _valueStr;
private _alpha;
constructor(value?) {
this._hue = 0;
this._saturation = 100;
this._value = 100;
this._alpha = 100;
this.enableAlpha = true;
this.format = 'hex';
if(value){
this.value = value;
}else{
this.value = '';
}
this.doOnChange();
}
get value(){
return this._valueStr;
}
set value(v){
this.fromString(v);
}
set(prop, value) {
if (arguments.length === 1 && typeof prop === 'object') {
for (let p in prop) {
if (prop.hasOwnProperty(p)) {
this.set(p, prop[p]);
}
}
return;
}
this['_' + prop] = value;
this.doOnChange();
}
get(prop) {
return this['_' + prop];
}
toRgb() {
return hsv2rgb(this._hue, this._saturation, this._value);
}
fromString(value) {
if (!value) {
this._hue = 0;
this._saturation = 100;
this._value = 100;
this.doOnChange();
return;
}
const fromHSV = (h, s, v) => {
this._hue = Math.max(0, Math.min(360, h));
this._saturation = Math.max(0, Math.min(100, s));
this._value = Math.max(0, Math.min(100, v));
this.doOnChange();
};
if (value.indexOf('hsl') !== -1) {
const parts = value.replace(/hsla|hsl|\(|\)/gm, '')
.split(/\s|,/g).filter((val) => val !== '').map((val, index) => index > 2 ? parseFloat(val) : parseInt(val, 10));
if (parts.length === 4) {
this._alpha = Math.floor(parseFloat(parts[3]) * 100);
} else if (parts.length === 3) {
this._alpha = 100;
}
if (parts.length >= 3) {
const { h, s, v } = hsl2hsv(parts[0], parts[1], parts[2]);
fromHSV(h, s, v);
}
} else if (value.indexOf('hsv') !== -1) {
const parts = value.replace(/hsva|hsv|\(|\)/gm, '')
.split(/\s|,/g).filter((val) => val !== '').map((val, index) => index > 2 ? parseFloat(val) : parseInt(val, 10));
if (parts.length === 4) {
this._alpha = Math.floor(parseFloat(parts[3]) * 100);
} else if (parts.length === 3) {
this._alpha = 100;
}
if (parts.length >= 3) {
fromHSV(parts[0], parts[1], parts[2]);
}
} else if (value.indexOf('rgb') !== -1) {
const parts = value.replace(/rgba|rgb|\(|\)/gm, '')
.split(/\s|,/g).filter((val) => val !== '').map((val, index) => index > 2 ? parseFloat(val) : parseInt(val, 10));
if (parts.length === 4) {
this._alpha = Math.floor(parseFloat(parts[3]) * 100);
} else if (parts.length === 3) {
this._alpha = 100;
}
if (parts.length >= 3) {
const { h, s, v } = rgb2hsv(parts[0], parts[1], parts[2]);
fromHSV(h, s, v);
}
} else if (value.indexOf('#') !== -1) {
const hex = value.replace('#', '').trim();
let r, g, b;
if (hex.length === 3) {
r = parseHexChannel(hex[0] + hex[0]);
g = parseHexChannel(hex[1] + hex[1]);
b = parseHexChannel(hex[2] + hex[2]);
} else if (hex.length === 6 || hex.length === 8) {
r = parseHexChannel(hex.substring(0, 2));
g = parseHexChannel(hex.substring(2, 4));
b = parseHexChannel(hex.substring(4, 6));
}
if (hex.length === 8) {
this._alpha = Math.floor(parseHexChannel(hex.substring(6)) / 255 * 100);
} else if (hex.length === 3 || hex.length === 6) {
this._alpha = 100;
}
const { h, s, v } = rgb2hsv(r, g, b);
fromHSV(h, s, v);
}
}
compare(color) {
return Math.abs(color._hue - this._hue) < 2 &&
Math.abs(color._saturation - this._saturation) < 1 &&
Math.abs(color._value - this._value) < 1 &&
Math.abs(color._alpha - this._alpha) < 1;
}
doOnChange() {
const { _hue, _saturation, _value, _alpha, format } = this;
if (this.enableAlpha) {
switch (format) {
case 'hsl':
const hsl = hsv2hsl(_hue, _saturation / 100, _value / 100);
this._valueStr = `hsla(${ _hue }, ${ Math.round(hsl[1] * 100) }%, ${ Math.round(hsl[2] * 100) }%, ${ _alpha / 100})`;
break;
case 'hsv':
this._valueStr = `hsva(${ _hue }, ${ Math.round(_saturation) }%, ${ Math.round(_value) }%, ${ _alpha / 100})`;
break;
default:
const { r, g, b } = hsv2rgb(_hue, _saturation, _value);
this._valueStr = `rgba(${r}, ${g}, ${b}, ${ _alpha / 100 })`;
}
} else {
switch (format) {
case 'hsl':
const hsl = hsv2hsl(_hue, _saturation / 100, _value / 100);
this._valueStr = `hsl(${ _hue }, ${ Math.round(hsl[1] * 100) }%, ${ Math.round(hsl[2] * 100) }%)`;
break;
case 'hsv':
this._valueStr = `hsv(${ _hue }, ${ Math.round(_saturation) }%, ${ Math.round(_value) }%)`;
break;
case 'rgb':
const { r, g, b } = hsv2rgb(_hue, _saturation, _value);
this._valueStr = `rgb(${r}, ${g}, ${b})`;
break;
default:
this._valueStr = toHex(hsv2rgb(_hue, _saturation, _value));
}
}
}
};
\ No newline at end of file
......@@ -87,11 +87,7 @@ function clearEvent(emitter, evt) {
}
/**
* Minimal `EventEmitter` interface that is molded against the Node.js
* `EventEmitter` interface.
*
* @constructor
* @public
* 事件发射器
*/
export default class EventEmitter{
_events;
......@@ -113,11 +109,7 @@ export default class EventEmitter{
}
/**
* Return an array listing the events for which the emitter has registered
* listeners.
*
* @returns {Array}
* @public
* 正在侦听的事件名
*/
eventNames() {
var names = []
......@@ -138,13 +130,9 @@ export default class EventEmitter{
}
/**
* Return the listeners registered for a given event.
*
* @param {(String|Symbol)} event The event name.
* @returns {Array} The registered listeners.
* @public
* 获取侦听者
* @param event
*/
listeners(event) {
var evt = prefix ? prefix + event : event
......@@ -161,11 +149,8 @@ export default class EventEmitter{
}
/**
* Return the number of listeners listening to a given event.
*
* @param {(String|Symbol)} event The event name.
* @returns {Number} The number of listeners.
* @public
* 获取侦听者数量
* @param event
*/
listenerCount(event) {
var evt = prefix ? prefix + event : event
......@@ -177,11 +162,13 @@ export default class EventEmitter{
}
/**
* Calls each of the listeners registered for a given event.
*
* @param {(String|Symbol)} event The event name.
* @returns {Boolean} `true` if the event had listeners, else `false`.
* @public
* 发送事件
* @param event
* @param a1
* @param a2
* @param a3
* @param a4
* @param a5
*/
emit(event, a1?, a2?, a3?, a4?, a5?) {
var evt = prefix ? prefix + event : event;
......@@ -236,40 +223,31 @@ export default class EventEmitter{
}
/**
* Add a listener for a given event.
*
* @param {(String|Symbol)} event The event name.
* @param {Function} fn The listener function.
* @param {*} [context=this] The context to invoke the listener with.
* @returns {EventEmitter} `this`.
* @public
* 侦听
* @param event
* @param fn
* @param context
*/
on(event, fn, context) {
return addListener(this, event, fn, context, false);
};
/**
* Add a one-time listener for a given event.
*
* @param {(String|Symbol)} event The event name.
* @param {Function} fn The listener function.
* @param {*} [context=this] The context to invoke the listener with.
* @returns {EventEmitter} `this`.
* @public
* 侦听一次
* @param event
* @param fn
* @param context
*/
once(event, fn, context) {
return addListener(this, event, fn, context, true);
}
/**
* Remove the listeners of a given event.
*
* @param {(String|Symbol)} event The event name.
* @param {Function} fn Only remove the listeners that match this function.
* @param {*} context Only remove the listeners that have this context.
* @param {Boolean} once Only remove one-time listeners.
* @returns {EventEmitter} `this`.
* @public
* 移除侦听
* @param event
* @param fn
* @param context
* @param once
*/
removeListener(event, fn, context, once) {
var evt = prefix ? prefix + event : event;
......@@ -312,11 +290,8 @@ export default class EventEmitter{
}
/**
* Remove all listeners, or those of the specified event.
*
* @param {(String|Symbol)} [event] The event name.
* @returns {EventEmitter} `this`.
* @public
* 移除全部侦听
* @param event
*/
removeAllListeners(event) {
var evt;
......
......@@ -2,6 +2,9 @@
* Created by rockyl on 2019-01-04.
*/
/**
* 本地存储
*/
export default class LocalStorage {
ID: string;
......@@ -9,18 +12,35 @@ export default class LocalStorage {
this.ID = ID;
}
getName(key: string, prefix: string = null): string {
private getName(key: string, prefix: string = null): string {
return (prefix || !this.ID || this.ID == '' ? prefix : this.ID) + '_' + key;
}
/**
* 获取数据
* @param key
* @param prefix
*/
getItem(key: string, prefix: string = null): string {
return localStorage.getItem(this.getName(key, prefix));
}
/**
* 设置数据
* @param key
* @param value
* @param prefix
*/
setItem(key: string, value: string, prefix: string = null) {
localStorage.setItem(this.getName(key, prefix), value);
}
/**
* 获取json数据对象
* @param key
* @param defaultObj
* @param prefix
*/
getItemObj(key: string, defaultObj: any = null, prefix: string = null): any {
let result: any;
try {
......@@ -34,7 +54,13 @@ export default class LocalStorage {
return result;
}
/**
* 设置json数据对象
* @param key
* @param itemObj
* @param prefix
*/
setItemObj(key: string, itemObj: any, prefix: string = null) {
this.setItem(key, JSON.stringify(itemObj), prefix);
}
}
\ No newline at end of file
}
......@@ -191,6 +191,13 @@ export default class Matrix {
}
}
/**
* 获取弧度
*/
get rotation(){
return Math.atan2(this.b, this.a);
}
/**
* 对矩阵应用缩放转换。x 轴乘以 sx,y 轴乘以 sy。
* scale() 方法将更改 Matrix 对象的 a 和 d 属性。
......
......@@ -3,7 +3,7 @@
*
*/
import {ScillaComponent} from "../core";
import {Component} from "../core";
import {lerp, lerpObj} from "../tools/math";
import {injectProp} from "../tools/utils";
import HashObject from "../core/HashObject";
......@@ -31,17 +31,18 @@ export interface TweenOptions {
/**
* 补间动画
* @param host
* @param target
* @param override
* @param options
* @param plugins
*/
export function createTween(target: ScillaComponent, override = false, options?: TweenOptions, plugins = []) {
export function createTween(host: any, target: any, override = false, options?: TweenOptions, plugins = []) {
if (override) {
killTweens(target);
}
const tween = new Tween(target, options);
const tween = new Tween(host, target, options);
addTween(target, tween);
return tween;
......@@ -51,7 +52,7 @@ export function createTween(target: ScillaComponent, override = false, options?:
* 移除对象上所有的Tween实例
* @param target
*/
export function killTweens(target: ScillaComponent) {
export function killTweens(target: any) {
let tweens: Tween[] = target['tweens'];
if (tweens) {
for (let tween of tweens) {
......@@ -71,7 +72,8 @@ function addTween(target, tween: Tween) {
}
export class Tween extends HashObject {
target: ScillaComponent;
host: any;
target: any;
loop: number;
queue = [];
......@@ -93,9 +95,10 @@ export class Tween extends HashObject {
ease: Function;
duration: number;
constructor(target: ScillaComponent, options?: TweenOptions, plugins = []) {
constructor(host: any, target: any, options?: TweenOptions, plugins = []) {
super();
this.host = host;
this.target = target;
this.loop = options ? options.loop : 0;
this.autoPlay = options ? (options.hasOwnProperty('autoPlay') ? options.autoPlay : true) : true;
......@@ -138,10 +141,10 @@ export class Tween extends HashObject {
}
target[key] = currentValue;
}
if (timeRatio >= 1) {
this._doNextAction();
}
if (timeRatio >= 1) {
this._doNextAction();
}
break;
case STATUS.DO_WAIT:
......@@ -221,7 +224,7 @@ export class Tween extends HashObject {
stop() {
this.status = STATUS.IDLE;
this.target.cancelOnNextTick(this.onUpdate);
this.host.cancelOnNextTick(this.onUpdate);
}
_set(props) {
......@@ -266,9 +269,9 @@ export class Tween extends HashObject {
if(resetLoopCounting){
this.loopCounting = 0;
}
this.target.callOnNextTick(this._readyStart);
this.host.callOnNextTick(this._readyStart);
this.target.callOnNextTick(this.onUpdate, false);
this.host.callOnNextTick(this.onUpdate, false);
}
_readyStart = (t) => {
......
......@@ -6,9 +6,9 @@
import {get, recycle, register} from "./ObjectPool";
const name = 'Vector2D';
register(name, function(){
register(name, function () {
return new Vector2D();
}, function(instance: Vector2D, x, y){
}, function (instance: Vector2D, x, y) {
instance.setXY(x, y);
});
......@@ -17,7 +17,7 @@ register(name, function(){
* @param x
* @param y
*/
export function createVector2D(x = 0, y = 0){
export function createVector2D(x = 0, y = 0) {
return get(name, x, y);
}
......@@ -25,7 +25,7 @@ export function createVector2D(x = 0, y = 0){
* 回收2D矢量
* @param target
*/
export function releaseVector2D(target){
export function releaseVector2D(target) {
recycle(name, target);
}
......@@ -33,14 +33,14 @@ export function releaseVector2D(target){
* 2D矢量
*/
export default class Vector2D {
_x;
_y;
_x: number;
_y: number;
onChange;
public static get zero(): Vector2D{
public static get zero(): Vector2D {
return zero;
}
constructor(x = 0, y = 0, onChange?) {
this.onChange = onChange;
......@@ -48,24 +48,26 @@ export default class Vector2D {
this._y = 0;
this.setXY(x, y);
}
get x(){
get x(): number {
return this._x;
}
set x(v){
if(this._x !== v){
set x(v: number) {
if (this._x !== v) {
const old = this._x;
this._x = v;
this.onChange && this.onChange(v, 'x', old);
}
}
get y(){
get y(): number {
return this._y;
}
set y(v){
if(this._y !== v){
set y(v: number) {
if (this._y !== v) {
const old = this._y;
this._y = v;
......@@ -73,35 +75,35 @@ export default class Vector2D {
}
}
setXY(x = 0, y = 0) {
setXY(x = 0, y = 0): Vector2D {
this.x = x;
this.y = y;
return this;
}
copyFrom(v2) {
copyFrom(v2): Vector2D {
this.x = v2.x;
this.y = v2.y;
return this;
}
clone() {
clone(): Vector2D {
return new Vector2D(this.x, this.y);
}
zero() {
zero(): Vector2D {
this.x = 0;
this.y = 0;
return this;
}
get isZero() {
get isZero(): boolean {
return this.x == 0 && this.y == 0;
}
normalize() {
normalize(): Vector2D {
let len = this.length;
if (len == 0) {
this.x = 1;
......@@ -112,102 +114,102 @@ export default class Vector2D {
return this;
}
get isNormalized() {
get isNormalized(): boolean {
return this.length == 1.0;
}
truncate(max) {
truncate(max): Vector2D {
this.length = Math.min(max, this.length);
return this;
}
reverse() {
reverse(): Vector2D {
this.x = -this.x;
this.y = -this.y;
return this;
}
dotProd(v2) {
dotProd(v2): number {
return this.x * v2.x + this.y * v2.y;
}
crossProd(v2) {
crossProd(v2): number {
return this.x * v2.y - this.y * v2.x;
}
distSQ(v2) {
distSQ(v2): number {
let dx = v2.x - this.x;
let dy = v2.y - this.y;
return dx * dx + dy * dy;
}
distance(v2) {
distance(v2): number {
return Math.sqrt(this.distSQ(v2));
}
add(v2) {
add(v2): Vector2D {
this.x += v2.x;
this.y += v2.y;
return this;
}
subtract(v2) {
subtract(v2): Vector2D {
this.x -= v2.x;
this.y -= v2.y;
return this;
}
multiply(value) {
multiply(value): Vector2D {
this.x *= value;
this.y *= value;
return this;
}
divide(value) {
divide(value): Vector2D {
this.x /= value;
this.y /= value;
return this;
}
set angle(value) {
set angle(value: number) {
this.radian = value * Math.PI / 180;
}
get angle() {
get angle(): number {
return this.radian * 180 / Math.PI;
}
set radian(value) {
set radian(value: number) {
let len = this.length;
this.setXY(Math.cos(value) * len, Math.sin(value) * len);
}
get radian() {
get radian(): number {
return Math.atan2(this.y, this.x);
}
equals(v2) {
equals(v2): boolean {
return this.x == v2.x && this.y == v2.y;
}
set length(value) {
set length(value: number) {
let a = this.radian;
this.setXY(Math.cos(a) * value, Math.sin(a) * value);
}
get length() {
get length(): number {
return Math.sqrt(this.lengthSQ);
}
get lengthSQ() {
get lengthSQ(): number {
return this.x * this.x + this.y * this.y;
}
get slope() {
get slope(): number {
return this.y / this.x;
}
toString() {
toString(): string {
return "[Vector2D (x:" + this.x + ", y:" + this.y + ")]";
}
......
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment