Commit c9ca18e9 authored by wildfirecode's avatar wildfirecode

1

parents
{"ver":"1.0.1","uuid":"d79519a3-915b-4a9f-9303-a15b642cfe24","subMetas":{},"isGroup":true}
{
"name": "main",
"root": {
"components": [
{
"script": "components/base/Transform"
}
],
"children": [
{
"name": "MainStage",
"uuid": "20181212032053",
"components": [
{
"script": "components/base/Transform",
"properties": {}
},
{
"script": "components/other/CameraController"
},
{
"script": "./scripts/HelloScilla",
"properties": {
"label": "entity|797fad3f-17ed-4a9e-841f-a6b91aed37fa",
"name": "Tom",
"logo": "entity|6f148871-0515-4ef8-9c0c-d3ed7baa0a11"
}
}
],
"children": [
{
"name": "Image",
"components": [
{
"script": "components/base/Transform",
"properties": {
"position": {
"y": -150,
"_type_": "scilla/support/Vector2D"
}
}
},
{
"script": "components/renderer/TextureRenderer",
"properties": {
"texture": "res|8ad59445-0ff2-4382-bb1c-9f7a07845e48"
}
},
{
"script": "components/animation/Wave",
"properties": {
"loop": 1,
"waveMethod": "rotate",
"autoPlay": false,
"duration": 400
}
}
],
"uuid": "6f148871-0515-4ef8-9c0c-d3ed7baa0a11"
},
{
"name": "Label",
"components": [
{
"script": "components/base/Transform",
"properties": {}
},
{
"script": "components/renderer/TextRenderer",
"properties": {
"fillColor": "rgba(255, 255, 255, 1)",
"text": "Tap Button"
}
}
],
"uuid": "797fad3f-17ed-4a9e-841f-a6b91aed37fa"
},
{
"name": "Button",
"components": [
{
"script": "components/base/Transform",
"properties": {
"position": {
"y": 80,
"_type_": "scilla/support/Vector2D"
}
}
},
{
"script": "components/renderer/RectRenderer",
"properties": {
"fillColor": "rgba(0, 192, 255, 1)",
"width": 150,
"height": 60,
"cornerRadius": 10
}
},
{
"script": "components/animation/TouchZoom",
"properties": {
"easeName": "backOut"
}
},
{
"script": "components/ui/Button",
"properties": {
"onClick": [
{
"entity": "entity|20181212032053",
"component": 1,
"method": "tapMe"
}
]
}
}
],
"children": [
{
"name": "label",
"components": [
{
"script": "components/base/Transform"
},
{
"script": "components/renderer/TextRenderer",
"properties": {
"text": "button",
"fillColor": "rgba(255, 255, 255, 1)"
}
}
],
"uuid": "4f7d630d-026c-4c1a-bf40-19a5cbecadb6"
}
],
"uuid": "cd518011-9d11-4376-af30-f64cef2a08cd"
}
]
}
]
},
"entity-cache": [
"797fad3f-17ed-4a9e-841f-a6b91aed37fa",
"6f148871-0515-4ef8-9c0c-d3ed7baa0a11",
"20181212032053"
],
"resource-groups": {
"preload": [
{
"uuid": "8ad59445-0ff2-4382-bb1c-9f7a07845e48",
"url": "singles/logo.png"
}
]
}
}
\ No newline at end of file
{"ver":"1.0.1","uuid":"1f50815f-bf2f-4cf6-8432-f56f3aa834ef","subMetas":{},"type":"scene"}
{"ver":"1.0.1","uuid":"def65e96-eed7-44b3-9804-e76dea9e5062","subMetas":{},"isGroup":true}
/**
* Created by rockyl on 2019-01-03.
*
* 砖块动画单体
*/
import {Entity,} from "scilla";
import TextRenderer from 'components/renderer/TextRenderer'
import Wave from 'components/animation/Wave'
import ScillaComponent from 'components/base/ScillaComponent';
export default class HelloScilla extends ScillaComponent {
name: string = 'scilla';
logo: Entity;
label: Entity;
private labelRenderer: TextRenderer;
private logoAnimation: Wave;
onAwake() {
super.onAwake();
this.labelRenderer = this.label.getComponent(TextRenderer);
this.logoAnimation = this.logo.getComponent(Wave);
}
tapMe(){
this.labelRenderer.text = 'Hello ' + this.name;
this.logoAnimation.play();
}
}
{"ver":"1.0.1","uuid":"bd9a9589-4961-44b9-ae8c-263297eb9a35","subMetas":{},"type":"script"}
{"ver":"1.0.1","uuid":"a67a10bf-16e9-47b7-8f10-ee7dcdeb2551","subMetas":{},"isGroup":true}
{
"ver": "1.0.1",
"uuid": "8ad59445-0ff2-4382-bb1c-9f7a07845e48",
"subMetas": {
"logo": {
"ver": "1.0.1",
"uuid": "c4c4d4b8-5178-4468-9460-c95435abefb8",
"rawTextureUuid": "8ad59445-0ff2-4382-bb1c-9f7a07845e48",
"type": "texture"
}
},
"type": "texture",
"imagePath": "/Users/rockyl/WorkSpaces/scilla/hello-scilla/assets/singles/logo.png"
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>new-kickball</title>
<meta name="viewport"
content="width=device-width,initial-scale=1, minimum-scale=1, maximum-scale=1, user-scalable=no"/>
<meta name="apple-mobile-web-app-capable" content="yes"/>
<meta name="full-screen" content="true"/>
<meta name="screen-orientation" content="portrait"/>
<meta name="x5-fullscreen" content="true"/>
<meta name="360-fullscreen" content="true"/>
<style>
html, body {
padding: 0;
margin: 0;
border: 0;
height: 100%;
background-color: #282C34;
}
</style>
</head>
<body>
<div id="gameContainer" style="width: 100%;height: 100%;overflow: hidden;"></div>
<script src="debug/bundle.js"></script>
<script>
setTimeout(function(){
var options = window['inputOptions'] || {};
window['new-kickball'].startup(document.getElementById('gameContainer'), options);
}, 100);
</script>
</body>
</html>
{
"name": "new-kickball",
"engineConfig": {
"fps": 60,
"designWidth": 750,
"designHeight": 1334,
"scaleMode": "showAll",
"modifyCanvasSize": false,
"resPath": ""
},
"customConfig": {
"scene": {
"scenes": {
"main": "scenes/main.scene"
},
"entryScene": "main"
},
"webServiceUrl": "http://localhost:4001"
}
}
{
"code": "0000000000",
"data": {
"creditsConf": {
"creditsUp": 100,
"creditsType": "virtual",
"creditsDown": 50,
"prize": [
{
"img": "adsfsadf",
"credits": 20,
"id": 4,
"title": "0.3"
},
{
"img": "sadfasdf",
"credits": 150,
"id": 3,
"title": "1.5倍"
},
{
"img": "sadfasdf",
"credits": 100,
"id": 2,
"title": "1倍"
},
{
"img": "sadfasdf",
"credits": 50,
"id": 1,
"title": "0.5倍"
}
]
},
"floating": {
"jsTest": "//yun1.duiba.com.cn/h5/showCouponPrize/4.0.0/index_201710191434.js",
"cssTest": "//yun1.duiba.com.cn/h5/showCouponPrize/4.0.0/index_201710191440.css"
},
"options": [
{
"hidden": false,
"prizeType": "thanks",
"name": "谢谢参与",
"description": "",
"logo": "//yun1.duiba.com.cn/upload/uP99F1462438316972.png",
"id": 15581
},
{
"hidden": false,
"prizeType": "lucky",
"name": "幸运福袋",
"description": "",
"logo": "//yun1.duiba.com.cn/webapp/img/luckynewn.png",
"id": 15582
},
{
"itemId": 47861,
"scoreArea": "",
"hidden": false,
"prizeType": "alipay",
"name": "支付宝1",
"description": "",
"logo": "//yun1.duiba.com.cn/developer/img/activityTool/slotMachine/alipay.png",
"id": 15585
}
],
"rule": "adsfasdf",
"type": "hdtool",
"element": {
"isCreditsTypeOpen": false,
"myCreditsLong": 999999632167,
"freeLimit": -1,
"success": false,
"myCredits": "999999632167",
"needCredits": "100",
"freeEmpty": true,
"needCreditsLong": 100,
"status": 1
}
},
"success": true,
"desc": "OK",
"timestamp": 1548832971636
}
\ No newline at end of file
{
"success": true,
"code": "0000000000",
"desc": "OK",
"timestamp": 1550564744291,
"data": {
"skincontent": "f2fcc331f44c98883f3a5b4868d7d7f4",
"throughInfo": [
{
"step": 3,
"prizeType": 1,
"description": null,
"img": ""
},
{
"step": 4,
"prizeType": 1,
"description": null,
"img": ""
},
{
"step": 5,
"prizeType": 2,
"description": null,
"img": ""
},
{
"step": 6,
"prizeType": 1,
"description": null,
"img": ""
},
{
"step": 7,
"prizeType": 1,
"description": null,
"img": ""
},
{
"step": 9,
"prizeType": 2,
"description": null,
"img": ""
},
{
"step": 10,
"prizeType": 1,
"description": null,
"img": ""
},
{
"step": 11,
"prizeType": 1,
"description": null,
"img": ""
},
{
"step": 13,
"prizeType": 1,
"description": null,
"img": ""
},
{
"step": 15,
"prizeType": 1,
"description": null,
"img": ""
},
{
"step": 16,
"prizeType": 1,
"description": null,
"img": ""
},
{
"step": 18,
"prizeType": 1,
"description": null,
"img": ""
},
{
"step": 19,
"prizeType": 1,
"description": null,
"img": ""
},
{
"step": 21,
"prizeType": 1,
"description": null,
"img": ""
},
{
"step": 22,
"prizeType": 1,
"description": null,
"img": ""
},
{
"step": 24,
"prizeType": 1,
"description": null,
"img": ""
},
{
"step": 27,
"prizeType": 4,
"description": null,
"img": ""
}
]
}
}
\ No newline at end of file
{
"success":true,
"code":"0000000000",
"desc":"OK",
"timestamp":1548915321930,
"data":1
}
\ No newline at end of file
{"success":true,"code":"0000000000","desc":"OK","timestamp":1548915321930,"data":123456}
{
"success": true,
"code": "0000000000",
"desc": "OK",
"timestamp": 1550569853824,
"data": {
"prizeType": "alipay",
"facePrice": "100",
"title": "1"
}
}
\ No newline at end of file
{
"success":true,
"code": 1,
"desc":"L(*ythj",
"timestamp":1548923950498
}
\ No newline at end of file
{"success":true,"code":"0000000000","desc":"OK","timestamp":1548923950498,"data":{"element":{"success":false,"isCreditsTypeOpen":false,"needCredits":"100","myCredits":"999999630434","myCreditsLong":999999630434,"needCreditsLong":100,"freeLimit":-1,"status":1,"freeEmpty":true},"lottery":{"id":null,"type":"thanks","imgUrl":null,"link":null,"title":null,"itemId":null,"appItemId":null,"bonus":null,"bonusMin":null,"bonusMax":null,"needAccount":null,"appLucky":null,"tip":null,"useBtnText":null,"validate":null,"couponCode":null,"couponKey":null,"stInfoDpmImg":null,"stInfoDpmClose":null,"stInfoDpmGoUse":null,"showUse":null,"openUrl":null,"iosDownloadUrl":null,"androidDownloadUrl":null,"isDownloadUrl":null,"confirm":null,"phaseNumber":null,"happyCode":null,"appHidden":true,"zybangJson":null},"exposure":null,"creditsInfo":{"activityId":82567,"prizeId":4,"orderNum":null,"developerBizId":"3029576","score":null,"recordStatus":1,"errorMsg":null},"againTag":null}}
{
"success":true,
"code":"0000000000",
"desc":"OK",
"timestamp":1548915321930,
"data":1
}
\ No newline at end of file
{
"success": true,
"code": "0000000000",
"desc": "OK",
"timestamp": 1550570639368,
"data": {
"orderId": "883006813674240289",
"submitToken": "d895deb9118f4b938d0b70a3dd2ace19",
"credits": "999999491765",
"unitName": "金币",
"consumerCredits": 999999491765
}
}
\ No newline at end of file
{
"success":true,
"code":"0000000000",
"desc":"OK",
"timestamp":1548915321930,
"data":123456
}
{
"success": true,
"code": "0000000000",
"desc": "OK",
"timestamp": 1550646190489,
"data": {
"score": 100,
"maxScore": 100
}
}
\ No newline at end of file
{
"success": true,
"code": 1,
"desc": "Hl7&L",
"timestamp": "1548915321930",
"data": "123123123"
}
\ No newline at end of file
{
"success": true,
"code": "0000000000",
"desc": "OK",
"timestamp": 1551066205001,
"data": {
"resurrectionStatus": true,
"resurrectionCount": 2,
"resurrectionCredits": 300
}
}
\ No newline at end of file
{
"success": true,
"code": 0,
"desc": "ok",
"timestamp": "1519442544000",
"data": {
"valiDate": "2019-04-11 11:11:11",
"description": "xxx",
"title": "title",
"img": "//yun1.duiba.com.cn/upload/uP99F1462438316972.png"
}
}
\ No newline at end of file
{
"success":true,
"code":"0000000000",
"desc":"OK",
"timestamp":1548915321930,
"data":1
}
\ No newline at end of file
{
"success": true,
"code": "0000000000",
"desc": "OK",
"timestamp": 1550647892216,
"data": "扣积分成功"
}
\ No newline at end of file
{
"success": true,
"code": "0000000000",
"desc": "OK",
"timestamp": 1550568405622,
"data": {
"needPrize": true,
"lastThrough": null,
"currentLocation": 6,
"prizeType": 5,
"retreat": null,
"forward": null,
"url": null,
"plginOrderId": null,
"point": 5
}
}
\ No newline at end of file
{
"success": true,
"code": "0000000000",
"desc": "OK",
"timestamp": 1552025592298,
"data": {
"element": null,
"rule": null,
"questions": [
{
"id": 1,
"type": "text",
"name": "题目1",
"options": [
{
"optionId": 1,
"option": "1"
},
{
"optionId": 2,
"option": "2"
},
{
"optionId": 3,
"option": "3"
},
{
"optionId": 4,
"option": "4"
}
]
},
{
"id": 3,
"type": "text",
"name": "题目3",
"options": [
{
"optionId": 1,
"option": "1"
},
{
"optionId": 2,
"option": "2"
},
{
"optionId": 3,
"option": "3"
},
{
"optionId": 4,
"option": "4"
}
]
}
]
}
}
\ No newline at end of file
{
"systemParams": "darwin-x64-64",
"modulesFolders": [
"node_modules"
],
"flags": [],
"linkedModules": [],
"topLevelPatterns": [
"scilla-components@git+http://gitlab2.dui88.com/laoqifeng/scilla-components#dev",
"scilla-launcher@git+http://gitlab2.dui88.com/laoqifeng/scilla-launcher#dev",
"scilla@git+http://gitlab2.dui88.com/laoqifeng/scilla-core#dev"
],
"lockfileEntries": {
"scilla-components@git+http://gitlab2.dui88.com/laoqifeng/scilla-components#dev": "git+http://gitlab2.dui88.com/laoqifeng/scilla-components#910560011a227b35f82a6b565848043a5e0dd532",
"scilla-launcher@git+http://gitlab2.dui88.com/laoqifeng/scilla-launcher#dev": "git+http://gitlab2.dui88.com/laoqifeng/scilla-launcher#8881f38cf3d72c38585f2655b7559ca892973fea",
"scilla@git+http://gitlab2.dui88.com/laoqifeng/scilla-core#dev": "git+http://gitlab2.dui88.com/laoqifeng/scilla-core#8542e7689d9e80310987b9856bd5d4cf9f43787e"
},
"files": [],
"artifacts": {}
}
\ No newline at end of file
# Created by .ignore support plugin (hsz.mobi)
### Node template
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# Runtime data
pids
*.pid
*.seed
*.pid.lock
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
# nyc test coverage
.nyc_output
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# Bower dependency directory (https://bower.io/)
bower_components
# node-waf configuration
.lock-wscript
# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release
# Dependency directories
node_modules/
jspm_packages/
# TypeScript v1 declaration files
typings/
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
*.tgz
# Yarn Integrity file
.yarn-integrity
# dotenv environment variables file
.env
# parcel-bundler cache (https://parceljs.org/)
.cache
# next.js build output
.next
# nuxt.js build output
.nuxt
# vuepress build output
.vuepress/dist
# Serverless directories
.serverless
/.rpt2_cache/
/**
* Created by rockyl on 2019-03-19.
*/
const glob = require('glob');
const fs = require('fs');
let files = glob.sync('src/**/!(index|registerAllComponents).ts');
let fileContent = `import {registerDef} from "scilla"
`;
const imports = [];
const contents = [];
for(let file of files){
let requirePath = '.' + file.replace('src', '').replace('.ts', '');
let fullClassName = file.replace('src', 'components').replace('.ts', '');
let shortClassName = fullClassName.substr(fullClassName.lastIndexOf('/') + 1);
imports.push(`import ${shortClassName} from '${requirePath}';`);
contents.push(` registerDef('${fullClassName}', ${shortClassName});`);
}
fileContent += imports.join('\n') + `
export function registerAllComponents(){
` + contents.join('\n') + '\n}';
fs.writeFileSync('src/registerAllComponents.ts', fileContent);
\ No newline at end of file
{
"name": "scilla-components",
"version": "1.0.2",
"main": "./dist/index.js",
"types": "./types/index.d.ts",
"license": "MIT",
"scripts": {
},
"devDependencies": {
"glob": "^7.1.3",
"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.3.4000"
}
}
/**
* Created by rockyl on 2018/11/16.
*/
const resolve = require('rollup-plugin-node-resolve');
const commonjs = require('rollup-plugin-commonjs');
const typescript = require('rollup-plugin-typescript2');
const {uglify} = require('rollup-plugin-uglify');
const name = 'scilla-components';
export default {
input: 'src/index.ts',
output: {
file: `dist/${name}.js`,
format: 'umd',
name,
//sourcemap: true,
},
plugins: [
resolve({
browser: true,
}),
typescript({
typescript: require('typescript'),
tslib: require('tslib'),
declaration: false,
}),
commonjs(),
//uglify({}),
],
external: ['scilla']
};
<?xml version="1.0" encoding="UTF-8"?>
<module type="WEB_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>
\ No newline at end of file
/**
* Created by rockyl on 2019-01-04.
*
* 透明渐变组件
*/
import Translation from "./Translation";
export default class Fade extends Translation {
fromAlpha = 0;
toAlpha = 1;
protected getFromProp(): any {
return {
alpha: this.fromAlpha
};
}
protected getToProp(): any {
return {
alpha: this.toAlpha
};
}
}
/**
* Created by rockyl on 2018-11-27.
*
* 触摸缩放交互效果组件
*/
import {createTween, createVector2D, ease, Ease, Tween, Vector2D,} from "scilla";
import {InteractComponent} from "../base";
export default class TouchZoom extends InteractComponent {
scaleOffset: Vector2D = createVector2D(0.1, 0.1);
duration: number = 200;
easeName: Ease = Ease.backOut;
private _zoomIn: Tween;
private _zoomOut: Tween;
private _touchBegin: boolean;
onAwake() {
super.onAwake();
if (!this._zoomIn) {
const {scaleOffset, duration, transform} = this;
const easeFunc = ease[this.easeName];
const scaleFrom = transform.scale.clone();
const scaleTo = transform.scale.clone().add(scaleOffset);
this._zoomIn = createTween(this, transform, false, {autoPlay: false, fields: ['x', 'y']})
.to({scale: scaleTo}, duration, easeFunc);
this._zoomOut = createTween(this, transform, false, {autoPlay: false, fields: ['x', 'y']})
.to({scale: scaleFrom}, duration, easeFunc);
}
}
onTouchBegin(e) {
super.onTouchOver(e);
if (this.interactable) {
this._touchBegin = true;
this._zoomIn.play(true);
}
}
onGlobalTouchEnd(e): boolean {
super.onGlobalTouchEnd(e);
if (this._touchBegin) {
this._touchBegin = false;
this._zoomOut.play(true);
}
return false;
}
}
/**
* Created by rockyl on 2019-01-04.
*
* 缩放组件
*/
import {createTween, Tween, Ease, ease, ScillaEvent} from "scilla";
import ScillaComponent from "../base/ScillaComponent";
export default class Translation extends ScillaComponent {
duration: number = 1000;
autoPlay = false;
easeName: Ease = Ease.linear;
delay = 0;
loop = -1;
onLoopComplete = new ScillaEvent();
onComplete = new ScillaEvent();
private _tween: Tween;
onAwake() {
super.onAwake();
if (this.autoPlay) {
this.play();
}
}
play() {
const easeFunc = ease[this.easeName];
this._tween = createTween(this, this.transform, false, {autoPlay: true, loop: this.loop, onLoopComplete: this._onLoopComplete, onComplete: this._onComplete})
.set(this.getFromProp(), true)
.wait(this.delay)
.to(this.getToProp(), this.duration, easeFunc);
//this._tween.play(false, this.delay);
}
stop() {
this._tween.stop();
}
protected getFromProp(){
return {};
}
protected getToProp(){
return {};
}
private _onLoopComplete=()=>{
this.onLoopComplete.invoke();
}
private _onComplete=()=>{
this.onComplete.invoke();
}
}
/**
* Created by rockyl on 2018/11/5.
*
* 波动组件
*/
import {raw, ScillaEvent, decorators, utils} from "scilla";
import ScillaComponent from "../base/ScillaComponent";
const PI2 = Math.PI * 2;
const {dirtyFieldTrigger} = decorators;
const oldPropFields = {
position: ['x', 'y'],
scale: ['x', 'y'],
alpha: 'alpha',
rotation: 'rotation',
};
export default class Wave extends ScillaComponent {
duration: number = 1000;
@dirtyFieldTrigger
waveMethod: WaveMethod;
waveParams: raw;
loop: number = -1;
autoPlay: boolean = true;
onComplete: ScillaEvent = new ScillaEvent();
onLoopComplete: ScillaEvent = new ScillaEvent();
private _playing;
private _waveAlgorithm;
private _startTime;
private _oldProps: any = {};
private _loopCounting;
get waveAlgorithm(){
return this._waveAlgorithm;
}
set waveAlgorithm(v: Function){
this._waveAlgorithm = v;
}
protected onModify(value, key, oldValue) {
super.onModify(value, key, oldValue);
switch(key){
case 'waveMethod':
this._waveAlgorithm = waveLibs[this.waveMethod];
break;
}
}
onAwake() {
super.onAwake();
this._startTime = 0;
utils.copyProp(this._oldProps, this.transform, oldPropFields);
if (this.autoPlay) {
this.play();
}
}
onUpdate(t) {
super.onUpdate(t);
if (this._playing) {
if (!this._startTime) {
this._startTime = t;
}
const {duration, waveParams, _waveAlgorithm, transform, transform: {position, scale}, _oldProps} = this;
let pass = (t - this._startTime) % duration;
let r = pass / duration * PI2;
let loopCounting = Math.floor((t - this._startTime) / duration);
if(loopCounting != this._loopCounting){
this._loopCounting = loopCounting;
if(this.onLoopEnd()){
r = PI2;
}
}
let params = waveParams || [];
let props = _waveAlgorithm(...params, r);
if (props.hasOwnProperty('x')) {
position.x = (props.x || 0) + _oldProps.position.x;
}
if (props.hasOwnProperty('y')) {
position.y = (props.y || 0) + _oldProps.position.y;
}
if (props.hasOwnProperty('sx')) {
scale.x = props.sx;
}
if (props.hasOwnProperty('sy')) {
scale.y = props.sy;
}
if (props.hasOwnProperty('r')) {
transform.rotation = props.r;
}
}
}
private onLoopEnd(){
if (this.loop < 0) {
this.onLoopComplete.invoke();
} else if (this._loopCounting < this.loop) {
this.onLoopComplete.invoke();
} else {
this._playing = false;
this.onComplete.invoke();
return true;
}
}
play() {
this._loopCounting = 0;
this._playing = true;
this._startTime = 0;
}
/**
* 停止动画
* @param revert 是否恢复初始状态
*/
stop(revert = false) {
this._playing = false;
if(revert){
for(let key in this._oldProps){
let prop = this._oldProps[key];
if(typeof prop === 'object'){
utils.injectProp(this.transform[key], prop);
}else{
this.transform[key] = prop;
}
}
}
}
}
export enum WaveMethod {
/**
* 公转
*/
round = 'round',
/**
* 自转
*/
rotate = 'rotate',
/**
* 缩放
*/
zoom = 'zoom',
/**
* 透明渐变
*/
fade = 'fade',
/**
* 横向波动
*/
cosWave = 'cosWave',
/**
* 纵向波动
*/
sinWave = 'sinWave',
/**
* 抖动
*/
shake = 'shake',
/**
* 呼吸
*/
breath = 'breath',
}
const {cos, sin, PI} = Math;
const waveLibs = {
round: function (h: number, t: number): any {
return {x: cos(t) * h, y: sin(t) * h};
},
cosWave: function (h: number, t: number): any {
return {x: cos(t) * h, y: 0};
},
sinWave: function (h: number, t: number): any {
h = h || 1;
return {x: 0, y: sin(t) * h};
},
rotate: function (t: number): any {
return {r: 360 * t / PI / 2};
},
shake: function (angle: number, count: number, t: number): any {
return {r: sin(t * count) * angle};
},
breath: function (scale: number = 0.1, t: number): any {
return {sx: sin(t) * scale + 1, sy: -sin(t + PI / 4) * scale + 1};
},
zoom: function (scale: number = 0.1, t: number): any {
return {sx: sin(t) * scale + 1, sy: sin(t) * scale + 1};
},
fade: function (base = 1, t: number): any {
return {alpha: (sin(t) + 1) * 0.5 + base};
},
};
/**
* Created by rockyl on 2019-01-04.
*
* 缩放组件
*/
import {Vector2D} from "scilla";
import Translation from "./Translation";
export default class Zoom extends Translation {
fromScale = new Vector2D(0, 0);
toScale = new Vector2D(1, 1);
protected getFromProp(): any {
return {
scale: this.fromScale ? this.fromScale.toObj() : null
};
}
protected getToProp(): any {
return {
scale: this.toScale ? this.toScale.toObj() : null
};
}
}
/**
* Created by rockyl on 2019-01-10.
*/
export {default as TouchZoom} from './TouchZoom'
export {default as Translation} from './Translation'
export {default as Fade} from './Fade'
export {default as Zoom} from './Zoom'
export {default as Wave} from './Wave'
/**
* Created by rockyl on 2018/11/7.
*/
import {Matrix, decorators} from "scilla";
import Renderer from "../renderer/Renderer";
import ScillaComponent from "./ScillaComponent";
const {dirtyFieldTrigger} = decorators;
/**
* 可交互组件
*/
export default class InteractComponent extends ScillaComponent {
/**
* 是否可交互
*/
@dirtyFieldTrigger
interactable = true;
/**
* 触摸中断
*/
touchInterrupt: boolean = false;
protected invertMatrix = Matrix.create();
protected localPos: any = {};
protected isOut = true;
private _touchBeginFlag: boolean;
constructor() {
super();
}
onModify(value, key, oldValue) {
super.onModify(value, key, oldValue);
if (key === 'interactable') {
if(this.entity){
this.onInteractableChanged(value);
}
}
}
onInteractableChanged(interactable){
}
_dealGlobalTouchBegin(e): boolean {
let interrupt = super._dealGlobalTouchBegin(e);
const hitOn = this.hitTest(e);
if (hitOn) {
this._touchBeginFlag = true;
this.onTouchBegin(e);
this._dealTouchOver(e);
}
return hitOn && (interrupt || this.touchInterrupt);
}
_dealGlobalTouchMove(e): boolean {
let interrupt = super._dealGlobalTouchMove(e);
const hitOn = this.hitTest(e);
if (hitOn) {
this._dealTouchOver(e);
this.onTouchMove(e);
} else {
this._dealTouchOut(e);
}
return hitOn && (interrupt || this.touchInterrupt);
}
_dealGlobalTouchEnd(e): boolean {
let interrupt = super._dealGlobalTouchEnd(e);
const hitOn = this.hitTest(e);
if (hitOn) {
this.onTouchEnd(e);
if(this._touchBeginFlag){
this.onTouchTap(e);
this._touchBeginFlag = false;
}
}
this.isOut = true;
return hitOn && (interrupt || this.touchInterrupt);
}
_dealTouchOver(e) {
if (this.isOut) {
this.isOut = false;
this.onTouchOver(e);
}
}
_dealTouchOut(e) {
if (!this.isOut) {
this.isOut = true;
this.onTouchOut(e);
}
}
onTouchBegin(e) {
//console.log('onTouchBegin', e);
}
onTouchMove(e) {
//console.log('onTouchMove', e);
}
onTouchOver(e) {
//console.log('onTouchOver', e);
}
onTouchOut(e) {
//console.log('onTouchOut', e);
}
onTouchEnd(e) {
//console.log('onTouchEnd', e);
}
onTouchTap(e) {
//console.log('onTouchTap', e);
}
/**
* 碰撞检测
* @param e
*/
hitTest(e): boolean {
const matrix = this.transform.getMatrix(false, true, true);
matrix.transformPoint(e.x, e.y, this.localPos);
let result = false;
const renderers = this.getComponents(Renderer);
for (let renderer of renderers) {
if (renderer.hitTest(this.localPos.x, this.localPos.y)) {
if (!renderer['isUsedToMask']) {
result = true;
break
}
} else if (renderer['isUsedToMask']) {
return false
}
}
return result;
}
}
/**
* Created by rockyl on 2019-04-17.
*/
import {Component} from 'scilla'
import Transform from "./Transform";
export default class ScillaComponent extends Component{
get transform():Transform {
return <Transform>this.entity.components[0]; //约定第0个组件为Transform组件
}
/**
* 根据组件名称获取指定类的组件列表
* @param name
*/
getComponentsByName<T extends Component>(name: string): T[] {
return this.entity.getComponentsByName<T>(name);
}
/**
* 获取指定类的组件列表
* @param clazz
*/
getComponents<T extends Component>(clazz: new()=> T): T[] {
return this.entity.getComponents<T>(clazz);
}
/**
* 获取指定类的组件
* @param name
*/
getComponentByName<T extends Component>(name: string): T {
return this.entity.getComponentByName<T>(name);
}
/**
* 获取指定类的组件
* @param clazz
*/
getComponent<T extends Component>(clazz: new()=> T): T {
return this.entity.getComponent<T>(clazz);
}
}
/**
* Created by rockyl on 2018-12-13.
*
* 触摸中断组件
*/
import InteractComponent from "./InteractComponent";
export default class TouchInterrupt extends InteractComponent {
touchInterrupt: boolean = true;
}
/**
* Created by rockyl on 2018/11/5.
*/
import {Vector2D, Matrix, decorators} from "scilla";
import Renderer from "../renderer/Renderer";
import ScillaComponent from "./ScillaComponent";
const {dirtyFieldDetector, dirtyFieldTrigger} = decorators;
/**
* 矩阵处理顺序
* SCALE_ROTATE: 先缩放后旋转
* ROTATE_SCALE: 先旋转后缩放
*/
export enum MATRIX_ORDER {
SCALE_ROTATE,
ROTATE_SCALE,
}
/**
* 矩阵转换组件
* 缩放、旋转、位移
*/
export default class Transform extends ScillaComponent {
protected localPos: any = {};
onVector2DModify = (value, key, oldValue) => {
this.makeDirty(value, key, oldValue);
};
/**
* 坐标
*/
@dirtyFieldTrigger
position: Vector2D = new Vector2D(0, 0);
/**
* 全局坐标
*/
private _globalPosition: Vector2D = new Vector2D(0, 0);
/**
* 节点透明度
*/
@dirtyFieldTrigger
alpha: number = 1;
/**
* 节点渲染透明度
*/
private _renderAlpha: number;
get renderAlpha(): number {
return this._renderAlpha;
}
/**
* 影响子节点
*/
@dirtyFieldTrigger
affectChildren: boolean = true;
/**
* 尺寸
* 对于不同的子类渲染都有不同的效果
*/
private _width: number = NaN;
private _height: number = NaN;
/**
* 缩放
*/
@dirtyFieldTrigger
scale: Vector2D = new Vector2D(1, 1);
/**
* 轴距
*/
@dirtyFieldTrigger
pivot: Vector2D = new Vector2D(0.5, 0.5);
/**
* 旋转
*/
@dirtyFieldDetector
rotation = 0;
private order: MATRIX_ORDER = MATRIX_ORDER.SCALE_ROTATE;
protected _localMatrix: Matrix = Matrix.create();
protected _globalMatrix: Matrix = Matrix.create();
protected _globalInvertMatrix: Matrix = Matrix.create();
protected _globalPivotMatrix: Matrix = Matrix.create();
protected dirty: boolean;
get width(): number {
const renderer = this.getComponent(Renderer);
return renderer ? renderer.bounds.width : (isNaN(this._width) ? 0 : this._width);
}
get explicitWidth(): number {
return this._width;
}
set width(value: number) {
if (this._width != value) {
this._width = value;
this.makeDirty(value, 'width');
}
}
get height(): number {
const renderer = this.getComponent(Renderer);
return renderer ? renderer.bounds.height : (isNaN(this._height) ? 0 : this._height);
}
get explicitHeight(): number {
return this._height;
}
set height(value: number) {
if (this._height != value) {
this._height = value;
this.makeDirty(value, 'height');
}
}
/**
* 获取全局坐标
*/
get globalPosition() {
this._globalPosition.setXY(this._globalMatrix.tx, this._globalMatrix.ty);
return this._globalPosition;
}
/**
* 获取全局角度
*/
get globalRotation() {
return this._globalMatrix.rotation * 180 / Math.PI;
}
/**
* 全局坐标转本地坐标
* @param position
*/
globalPositionToLocal(position) {
const matrix = this.getMatrix(false, true, true);
matrix.transformPoint(position.x, position.y, this.localPos);
return this.localPos;
}
makeDirty(value, key, oldValue?) {
this.dirty = true;
switch (key) {
case 'width':
case 'height':
const renderers = this.getComponents(Renderer);
for (let renderer of renderers) {
renderer.makeDirty();
}
break;
}
}
/**
* @inheritDoc
*/
onModify(value, key, oldValue) {
super.onModify(value, key, oldValue);
this.makeDirty(value, key, oldValue);
switch (key) {
case 'position':
case 'scale':
//case 'size':
value.onChange = this.onVector2DModify;
break;
}
}
/**
* 更新本地矩阵
*/
protected updateLocalMatrix() {
const {
position: {x, y},
scale: {x: sx, y: sy}, rotation,
} = this;
const matrix = this._localMatrix;
matrix.identity();
if (this.order === MATRIX_ORDER.SCALE_ROTATE) {
matrix.scale(sx, sy);
matrix.rotate(rotation * Math.PI / 180);
} else {
matrix.rotate(rotation * Math.PI / 180);
matrix.scale(sx, sy);
}
matrix.translate(
x,
y,
);
}
/**
* 更新全局矩阵
*/
protected updateGlobalMatrix() {
const {
entity, _globalMatrix, _localMatrix, _globalPivotMatrix,
pivot: {x: px, y: py},
width, height,
} = this;
_globalMatrix.copyFrom(_localMatrix);
if (entity.parent) {
const parentTransform: Transform = <Transform>entity.parent.getComponent(Transform);
if (parentTransform) {
this._renderAlpha = parentTransform._renderAlpha * this.alpha;
_globalMatrix.concat(parentTransform.getMatrix(false, false));
} else {
this._renderAlpha = this.alpha;
}
} else {
this._renderAlpha = this.alpha;
}
if(this.entity.name === 'Miner'){
console.log();
}
_globalPivotMatrix.copyFrom(_globalMatrix);
const {a, d} = _globalMatrix;
_globalPivotMatrix.translate(
-(px - 0.5) * width * a,
-(py - 0.5) * height * d,
);
}
/**
* 获取矩阵
*/
getMatrix(withPivot: boolean = false, invert: boolean = false, affectChildren = false): Matrix {
let matrix;
if (this.affectChildren || affectChildren) {
matrix = withPivot ? this._globalPivotMatrix : this._globalMatrix;
if (invert) {
const invertMatrix = this._globalInvertMatrix;
invertMatrix.copyFrom(matrix);
invertMatrix.invert();
return invertMatrix;
}
} else {
matrix = this.entity.parent.getComponent(Transform).getMatrix(withPivot, invert);
}
return matrix;
}
onUpdate(t) {
if (this.dirty) {
this.updateLocalMatrix();
this.dirty = false;
}
this.updateGlobalMatrix();
super.onUpdate(t);
}
onEditorUpdate(t) {
this.onUpdate(t);
}
}
/**
* Created by rockyl on 2019-01-10.
*/
export {default as InteractComponent} from './InteractComponent'
export {default as TouchInterrupt} from './TouchInterrupt'
export {default as Transform} from './Transform'
export {default as ScillaComponent} from './ScillaComponent'
/**
* Created by rockyl on 2019-01-24.
*/
export * from './animation';
export * from './base';
export * from './other';
export * from './renderer';
export * from './ui';
export * from './registerAllComponents'
\ No newline at end of file
/**
* Created by rockyl on 2018/11/15.
*
*/
import {Entity, createVector2D, Vector2D, math, engine} from "scilla";
import Transform from "../base/Transform";
import ScillaComponent from "../base/ScillaComponent";
/**
* 相机控制组件
*/
export default class CameraController extends ScillaComponent {
viewportAnchor: Vector2D = createVector2D(0.5, 0.5);
target: Entity;
maxScale = 1.2;
once: boolean = true;
private targetPosition: Vector2D;
private followPosition: Vector2D;
private _stageSize;
onAwake() {
super.onAwake();
const {target,} = this;
if (target) {
this.targetPosition = target.getComponent(Transform).position;
}
this.followPosition = createVector2D();
if(this.once){
this.updateViewport();
}
}
get stageSize(){
if(!this._stageSize){
this._stageSize = engine.renderContext.stageSize;
}
return this._stageSize;
}
onUpdate(t) {
super.onUpdate(t);
if(!this.once){
this.updateViewport();
}
this.followTarget();
}
onEditorUpdate(t){
this.updateViewport();
}
updateViewport() {
if (this.viewportAnchor) {
const {width, height} = this.stageSize;
const {x, y} = this.viewportAnchor;
const {x: sx, y: sy} = this.transform.scale;
this.transform.position.setXY(width * x * sx, height * y * sy);
}
}
followTarget() {
if (!this.targetPosition) {
return;
}
const {transform: {scale, position}, stageSize: {width, height}, targetPosition: {x, y, length}, maxScale} = this;
const newScale = maxScale - length * maxScale / 2048;
scale.setXY(newScale, newScale);
this.followPosition.setXY(width / 2, height / 2).subtract(this.targetPosition);
position.copyFrom(math.lerpObj(position, this.followPosition, 0.1, ['x', 'y']));
}
}
/**
* Created by rockyl on 2018-12-17.
*
* 内容组件尺寸自适应组件
*/
import {Size} from "scilla";
import Transform from "../base/Transform";
import ScillaComponent from "../base/ScillaComponent";
export default class ContentSizeFitter extends ScillaComponent {
private _measureSize: Size = new Size();
afterUpdate() {
super.afterUpdate();
const measureSize = this._measureSize;
measureSize.set(0, 0);
for(let child of this.entity.children){
const transform = child.getComponent(Transform);
if(transform){
const {width, height, pivot} = transform;
measureSize.width += width;
measureSize.height += height;
}
}
this.transform.width = measureSize.width;
this.transform.height = measureSize.height;
}
}
/**
* Created by rockyl on 2018/11/15.
*
*/
import {engine} from 'scilla';
import ScillaComponent from "../base/ScillaComponent";
/**
* 全舞台尺寸组件
*/
export default class FullStageSize extends ScillaComponent {
once: boolean = true;
applyWidth: boolean = true;
applyHeight: boolean = true;
private _stageSize;
get stageSize(){
if(!this._stageSize){
this._stageSize = engine.renderContext.stageSize;
}
return this._stageSize;
}
onCreate() {
super.onCreate();
}
onAwake() {
super.onAwake();
this.execute();
}
onUpdate(t) {
super.onUpdate(t);
if(!this.once){
this.execute();
}
}
onEditorUpdate(t) {
super.onEditorUpdate(t);
this.execute();
}
execute() {
const {width, height} = this.stageSize;
if(this.applyWidth){
this.transform.width = width;
}
if(this.applyHeight){
this.transform.height = height;
}
}
}
/**
* Created by rockyl on 2018-12-05.
*
*/
import Renderer from "../renderer/Renderer";
import Transform from "../base/Transform";
import ScillaComponent from "../base/ScillaComponent";
/**
* 相对布局组件
*/
export default class RelativeLayout extends ScillaComponent {
left: number = NaN;
right: number = NaN;
top: number = NaN;
bottom: number = NaN;
horizontalCenter: number = NaN;
verticalCenter: number = NaN;
once: boolean = true;
onCreate() {
super.onCreate();
}
onAwake() {
super.onAwake();
this.adjust();
}
onUpdate(t) {
super.onUpdate(t);
if (!this.once) {
this.adjust();
}
}
onEditorUpdate(t){
this.adjust();
}
onSleep() {
super.onSleep();
}
onDestroy() {
super.onDestroy();
}
adjust = () => {
const {
entity, entity: {parent}, transform, transform: {position, pivot: {x: ax, y: ay},},
left, right, top, bottom, horizontalCenter, verticalCenter
} = this;
const hasLeft = !isNaN(left);
const hasRight = !isNaN(right);
const hasTop = !isNaN(top);
const hasBottom = !isNaN(bottom);
const hasHorizontalCenter = !isNaN(horizontalCenter);
const hasVerticalCenter = !isNaN(verticalCenter);
const parentRenderers = parent.getComponents(Renderer);
for (let parentRenderer of parentRenderers) {
parentRenderer.measureBounds();
}
const parentTransform:Transform = parent.getComponent(Transform);
let pWidth, pHeight;
if(parentRenderers.length > 0){
const parentBounds = parentRenderers[0].bounds;
pWidth = parentBounds.width;
pHeight = parentBounds.height;
}else{
pWidth = parentTransform.explicitWidth;
pHeight = parentTransform.explicitHeight;
}
const {x: pax, y: pay} = parentTransform.pivot;
const renderers = entity.getComponents(Renderer);
for (let renderer of renderers) {
renderer.measureBounds();
}
let {width, height, } = transform;
let {x, y} = position;
let widthModified = false, heightModified = false;
//adjust
{
if (hasHorizontalCenter) {
x = (pWidth - width) / 2 - pWidth * pax + width * ax;
} else if (hasLeft) {
if (hasRight) {
widthModified = true;
width = pWidth - right - left;
x = (left - right) / 2 - (0.5 - ax) * width;
} else {
x = left - pWidth * pax + width * ax;
}
} else if (hasRight) {
x = -right + pWidth * (1 - pax) - width * (1 - ax);
}
if (hasVerticalCenter) {
y = (pHeight - height) / 2 - pHeight * pay + height * ay;
} else if (hasTop) {
if (hasBottom) {
heightModified = true;
height = pHeight - bottom - top;
y = (top - bottom) / 2 - (0.5 - ay) * height;
} else {
y = top - pHeight * pay + height * ay;
}
} else if (hasBottom) {
y = -bottom + pHeight * (1 - pay) - height * (1 - ay);
}
}
position.x = x;
position.y = y;
if(widthModified){
transform.width = width;
}
if(heightModified){
transform.height = height;
}
if(widthModified || heightModified){
for (let renderer of renderers) {
renderer.measureBounds();
}
}
}
}
/**
* Created by rockyl on 2019-01-10.
*/
export {default as CameraController} from './CameraController'
export {default as ContentSizeFitter} from './ContentSizeFitter'
export {default as RelativeLayout} from './RelativeLayout'
export {default as FullStageSize} from './FullStageSize'
import {registerDef} from "scilla"
import Fade from './animation/Fade';
import TouchZoom from './animation/TouchZoom';
import Translation from './animation/Translation';
import Wave from './animation/Wave';
import Zoom from './animation/Zoom';
import InteractComponent from './base/InteractComponent';
import ScillaComponent from './base/ScillaComponent';
import TouchInterrupt from './base/TouchInterrupt';
import Transform from './base/Transform';
import CameraController from './other/CameraController';
import ContentSizeFitter from './other/ContentSizeFitter';
import FullStageSize from './other/FullStageSize';
import RelativeLayout from './other/RelativeLayout';
import CircleRenderer from './renderer/CircleRenderer';
import FrameAnimationRenderer from './renderer/FrameAnimationRenderer';
import GraphicRenderer from './renderer/GraphicRenderer';
import LineRenderer from './renderer/LineRenderer';
import RectRenderer from './renderer/RectRenderer';
import Renderer from './renderer/Renderer';
import TextRenderer from './renderer/TextRenderer';
import TextureRenderer from './renderer/TextureRenderer';
import Button from './ui/Button';
import ProgressBar from './ui/ProgressBar';
import ScrollView from './ui/ScrollView';
export function registerAllComponents(){
registerDef('components/animation/Fade', Fade);
registerDef('components/animation/TouchZoom', TouchZoom);
registerDef('components/animation/Translation', Translation);
registerDef('components/animation/Wave', Wave);
registerDef('components/animation/Zoom', Zoom);
registerDef('components/base/InteractComponent', InteractComponent);
registerDef('components/base/ScillaComponent', ScillaComponent);
registerDef('components/base/TouchInterrupt', TouchInterrupt);
registerDef('components/base/Transform', Transform);
registerDef('components/other/CameraController', CameraController);
registerDef('components/other/ContentSizeFitter', ContentSizeFitter);
registerDef('components/other/FullStageSize', FullStageSize);
registerDef('components/other/RelativeLayout', RelativeLayout);
registerDef('components/renderer/CircleRenderer', CircleRenderer);
registerDef('components/renderer/FrameAnimationRenderer', FrameAnimationRenderer);
registerDef('components/renderer/GraphicRenderer', GraphicRenderer);
registerDef('components/renderer/LineRenderer', LineRenderer);
registerDef('components/renderer/RectRenderer', RectRenderer);
registerDef('components/renderer/Renderer', Renderer);
registerDef('components/renderer/TextRenderer', TextRenderer);
registerDef('components/renderer/TextureRenderer', TextureRenderer);
registerDef('components/ui/Button', Button);
registerDef('components/ui/ProgressBar', ProgressBar);
registerDef('components/ui/ScrollView', ScrollView);
}
\ No newline at end of file
/**
* Created by rockyl on 2018/11/6.
*/
import GraphicRenderer from "./GraphicRenderer";
import {decorators} from "scilla";
const {dirtyFieldDetector} = decorators;
/**
* 圆形渲染组件
*/
export default class CircleRenderer extends GraphicRenderer {
/**
* 半径
*/
@dirtyFieldDetector
radius = 50;
/**
* 开始角度
*/
@dirtyFieldDetector
startAngle: number = 0;
/**
* 结束角度
*/
@dirtyFieldDetector
endAngle: number = 360;
/**
* 是否回归到圆心
*/
@dirtyFieldDetector
backToCenter: boolean = true;
protected getRenderSize(): any {
const {radius} = this;
return {width: radius * 2, height: radius * 2};
}
/**
* @inheritDoc
*/
protected draw() {
const {currentCanvasContext, bounds: {width, height}, startAngle, endAngle, backToCenter, _margin, _useCacheMode} = this;
let offset = _useCacheMode ? _margin : 0;
const radius = Math.min(width, height) / 2;
const pos = offset + radius;
if(startAngle == 0 && endAngle == 360){
currentCanvasContext.arc(pos, pos, radius, 0, 2 * Math.PI);
}else{
if(backToCenter){
currentCanvasContext.moveTo(pos, pos);
}
currentCanvasContext.arc(pos, pos, radius, startAngle * Math.PI / 180, endAngle * Math.PI / 180);
if(backToCenter){
currentCanvasContext.lineTo(pos, pos);
}
}
super.draw();
}
}
/**
* Created by rockyl on 2018-11-30.
*
* 帧动画组件
*
* todo 倒置播放
*/
import Renderer from "./Renderer";
import {FrameAnimation, ScillaEvent} from "scilla";
/**
* 帧动画渲染组件
*/
export default class FrameAnimationRenderer extends Renderer {
/**
* 帧动画资源
*/
public frameAnimation: FrameAnimation;
/**
* 是否自动播放
*/
public autoPlay: boolean = false;
/**
* 帧率
* 不设置就读取动画文件的帧率
*/
public fps: number = NaN;
public onComplete: ScillaEvent = new ScillaEvent();
public onLoopComplete: ScillaEvent = new ScillaEvent();
private _playing;
private _startTime;
private _startFrame;
private _endFrame;
private _currentFrameIndex;
private _startFlag;
private _loop;
private _loopCounting;
private _lastLabel;
/**
* @inheritDoc
*/
onAwake() {
super.onAwake();
if(this.autoPlay){
this.play(0, -1);
}
}
/**
* @inheritDoc
*/
onUpdate(t) {
if (this._playing) {
const {frameAnimation, _startFrame, _endFrame, fps} = this;
if (this._startFlag) {
this._startFlag = false;
this._startTime = t;
this._loopCounting ++;
}
const mFPS = isNaN(fps) ? frameAnimation.fps : fps;
const passTime = t - this._startTime;
const passFrameCount = Math.floor(passTime / (1000 / mFPS));
const passFrameInRegion = passFrameCount % (_endFrame - _startFrame + 1);
this._currentFrameIndex = _startFrame + passFrameInRegion;
if(passFrameInRegion == 0 && passFrameCount > 0){
this._currentFrameIndex = _endFrame;
this.onLoopEnd();
}
}
super.onUpdate(t);
}
/**
* @inheritDoc
*/
onSleep() {
super.onSleep();
}
/**
* 当一遍播放结束时
*/
onLoopEnd(){
if (this._loop < 0) {
this._startFlag = true;
this.onLoopComplete.invoke(this._lastLabel);
} else if (this._loopCounting < this._loop) {
this._startFlag = true;
this.onLoopComplete.invoke(this._lastLabel);
} else {
this._playing = false;
this.onComplete.invoke(this._lastLabel);
}
}
/**
* 播放
* @param frame
* @param loop
* @param force
*/
play(frame: number | string = 0, loop: number = 0, force = true) {
this._loop = loop;
this._loopCounting = 0;
if (!this.frameAnimation) {
return;
}
let startFrame = 0, endFrame = this.frameAnimation.frameCount - 1;
if (typeof frame == 'string') {
this._lastLabel = frame;
const label = this.frameAnimation.getLabel(frame);
if (label) {
startFrame = label.frame - 1;
endFrame = label.end - 1;
}
} else {
this._lastLabel = null;
startFrame = frame;
}
this._startFrame = startFrame;
this._endFrame = endFrame;
this._currentFrameIndex = this._startFrame;
this._startFlag = true;
this._playing = true;
}
/**
* 停止
*/
stop() {
this._playing = false;
}
/**
* @inheritDoc
*/
protected draw() {
super.draw();
if (!this.frameAnimation) {
return;
}
const {currentCanvasContext, frameAnimation, _currentFrameIndex, bounds} = this;
const {texture, data} = frameAnimation.getFrame(_currentFrameIndex);
if (texture) {
const {img, bounds: {x, y, width: textureWidth, height: textureHeight}} = texture;
bounds.setTo(data.x, data.y, textureWidth, textureHeight);
currentCanvasContext.drawImage(img, x, y, textureWidth, textureHeight, data.x, data.y, textureWidth, textureHeight);
}
}
}
/**
* Created by rockyl on 2018/11/6.
*
* todo 如果isUsedToMask,就禁用缓存
*/
import Renderer from "./Renderer";
import {color, decorators} from "scilla";
const {dirtyFieldDetector} = decorators;
/**
* 图形渲染组件
*/
export default class GraphicRenderer extends Renderer {
/**
* 填充颜色
*/
@dirtyFieldDetector
fillColor: color = '#42bce4';
/**
* 边框颜色
*/
@dirtyFieldDetector
borderColor: color = '#0899d0';
/**
* 边框宽度
*/
@dirtyFieldDetector
borderWidth = 0;
/**
* 是否为mask
*/
@dirtyFieldDetector
isMask = false;
/**
* 是否显示mask
*/
@dirtyFieldDetector
maskVisible = false;
protected getUseCacheMode(){
return this._useCacheMode && !this.isMask;
}
/**
* 获取图形尺寸
*/
protected getRenderSize(): any {
return {width: 0, height: 0};
}
/**
* @inheritDoc
*/
protected beforeDraw() {
super.beforeDraw();
this.applyStyle();
this.currentCanvasContext.beginPath();
}
/**
* @inheritDoc
*/
protected draw() {
super.draw();
if (this.isMask) {
this._context.clip();
this.maskVisible && this.fillAndStoke()
} else {
this.fillAndStoke()
}
}
/**
* 应用渲染样式
*/
protected applyStyle() {
const {currentCanvasContext, fillColor, borderColor, borderWidth} = this;
currentCanvasContext.fillStyle = fillColor;
if (borderWidth > 0) {
currentCanvasContext.strokeStyle = borderColor;
currentCanvasContext.lineWidth = borderWidth;
}
}
/**
* 绘制
*/
protected fillAndStoke() {
const {currentCanvasContext, borderWidth} = this;
currentCanvasContext.fill();
if (borderWidth > 0) {
currentCanvasContext.stroke();
}
}
/**
* @inheritDoc
*/
protected drawClip() {
this.isMask && this.currentCanvasContext.save();
}
/**
* @inheritDoc
*/
afterUpdate() {
this.isMask && this.currentCanvasContext.restore();
}
afterEditorUpdate(){
this.afterUpdate();
}
measureBounds() {
if (!this.dirty) {
return;
}
this._margin = this.borderWidth;
const {bounds, transform: {explicitWidth: tWidth, explicitHeight: tHeight}} = this;
const {width: sWidth, height: sHeight} = this.getRenderSize();
bounds.width = isNaN(tWidth) ? sWidth : tWidth;
bounds.height = isNaN(tHeight) ? sHeight : tHeight;
super.measureBounds();
}
}
/**
* Created by rockyl on 2019-05-23.
*
* Html渲染器
*/
import {engine, decorators, color} from "scilla";
import ScillaComponent from "../base/ScillaComponent";
const {dirtyFieldDetector} = decorators;
const floatLayerName = 'floatLayer';
function getFloatLayer(){
let floatLayer:HTMLElement = <HTMLElement>engine.canvasElement.nextElementSibling;
if(!floatLayer || floatLayer.id !== floatLayerName){
floatLayer = document.createElement('div');
floatLayer.id = floatLayerName;
floatLayer.style.position = 'absolute';
floatLayer.style.overflowY = 'auto';
engine.canvasElement.parentElement.append(floatLayer)
}
return floatLayer;
}
function showFloatLayer(){
let floatLayer = getFloatLayer();
floatLayer.style.display = 'inherit';
}
function hideFloatLayer(){
let floatLayer = getFloatLayer();
floatLayer.style.display = 'none';
}
export default class HtmlRenderer extends ScillaComponent {
@dirtyFieldDetector
htmlText: string;
@dirtyFieldDetector
fontSize = 14;
@dirtyFieldDetector
color: color = '#000';
onAwake() {
super.onAwake();
showFloatLayer();
}
onSleep() {
super.onSleep();
hideFloatLayer();
}
onUpdate(t) {
super.onUpdate(t);
let floatLayer = getFloatLayer();
let style = floatLayer.style;
if(this['dirty']){
this['dirty'] = false;
floatLayer.innerHTML = this.htmlText;
style.fontSize = this.fontSize + 'px';
style.color = this.color;
}
if(this.htmlText){
const {globalPosition: {x, y}, width, height} = this.transform;
const {x: px, y: py} = engine.canvasPosToPagePos(x, y);
const {x: pWidth, y: pHeight} = engine.canvasPosToPagePos(width, height);
if(style.left !== (px - pWidth / 2) + 'px'){
style.left = (px - pWidth / 2) + 'px';
}
if(style.top !== (py - pHeight / 2) + 'px'){
style.top = (py - pHeight / 2) + 'px';
}
if(style.width !== pWidth + 'px'){
style.width = pWidth + 'px';
}
if(style.height !== pHeight + 'px'){
style.height = pHeight + 'px';
}
}
}
}
/**
* Created by rockyl on 2018/11/6.
*/
import GraphicRenderer from "./GraphicRenderer";
/**
* 线段渲染组件
*/
export default class LineRenderer extends GraphicRenderer {
x0: number = 0;
y0: number = 0;
x1: number = 0;
y1: number = 0;
/**
* @inheritDoc
*/
draw() {
super.draw();
const {currentCanvasContext, x0, y0, x1, y1} = this;
currentCanvasContext.moveTo(x0, y0);
currentCanvasContext.lineTo(x1, y1);
}
/**
* @inheritDoc
*/
measureBounds() {
const {bounds} = this;
bounds.width = 0;
bounds.height = 0;
super.measureBounds();
}
}
/**
* Created by rockyl on 2018/11/6.
*/
import GraphicRenderer from "./GraphicRenderer";
import {decorators} from "scilla"
const {dirtyFieldDetector} = decorators;
/**
* (圆角)矩形渲染器
*/
export default class RectRenderer extends GraphicRenderer {
@dirtyFieldDetector
width = 100;
@dirtyFieldDetector
height = 100;
@dirtyFieldDetector
cornerRadius = 0;
protected getRenderSize(): any {
const {width, height} = this;
return {width, height};
}
/**
* @inheritDoc
*/
protected draw() {
const {PI} = Math;
const {currentCanvasContext, cornerRadius: r, bounds: {width, height}, _margin, _useCacheMode} = this;
let offset = _useCacheMode ? _margin : 0;
if (r) {
currentCanvasContext.moveTo(offset + r, offset + 0);
currentCanvasContext.lineTo(offset + width - r, offset + 0);
currentCanvasContext.arc(offset + width - r, offset + r, r, PI * 3 / 2, PI * 2);
currentCanvasContext.lineTo(offset + width, offset + height - r);
currentCanvasContext.arc(offset + width - r, offset + height - r, r, 0, PI / 2);
currentCanvasContext.lineTo(offset + r, offset + height);
currentCanvasContext.arc(offset + r, offset + height - r, r, PI / 2, PI);
currentCanvasContext.lineTo(offset + 0, offset + r);
currentCanvasContext.arc(offset + r, offset + r, r, PI, PI * 3 / 2);
} else {
currentCanvasContext.rect(offset, offset, width, height);
}
super.draw();
}
}
/**
* Created by rockyl on 2018/11/6.
*/
import {createCanvas, Bounds, Vector2D, math, decorators, EngineConfig, engine} from "scilla";
import ScillaComponent from "../base/ScillaComponent";
const {dirtyFieldTrigger} = decorators;
/**
* 渲染组件基类
*/
export default class Renderer extends ScillaComponent {
protected onVector2DModify = () => {
this.makeDirty();
};
private _debugDrawColor: string;
protected dirty: boolean = true;
/**
* 是否使用缓存模式
*/
protected _useCacheMode: boolean = false;
/**
* 透明度
*/
alpha: number = 1;
//锚点:在各子render里面加,从绘制上改,将同时更改位置原点,旋转原点,缩放原点,以0到1比例形式(现用此方案)
//在该render上改transform;更改旋转和缩放原点,不改变位置原点,默认中心为位置原点,以真实数值形式
@dirtyFieldTrigger
anchor: Vector2D = new Vector2D(0.5, 0.5);
/**
* 边界
*/
bounds = new Bounds();
protected cacheCanvas = null;
/**
* 缓存用的渲染上下文
*/
protected cacheCanvasContext;
/**
* 锚点实际偏移
*/
protected _anchorOffset: Vector2D = new Vector2D();
//渲染上下文
protected _context;
/**
* 扩展尺寸
*/
protected _margin: number = 0;
get useCacheMode() {
return this.getUseCacheMode();
}
set useCacheMode(value) {
this._useCacheMode = value;
}
private get context(){
if(!this._context){
this._context = engine.renderContext.context;
}
return this._context;
}
onCreate() {
super.onCreate();
this._debugDrawColor = `hsl(${math.makeRandomInt(360)}, ${math.makeRandomInt(100)}%, 60%)`;
}
protected getUseCacheMode() {
return this._useCacheMode;
}
/**
* 获取渲染上下文
* 如果缓存上下文存在,则返回缓存上下文
*/
protected get currentCanvasContext() {
return this.cacheCanvasContext || this.context;
}
makeDirty() {
this.dirty = true;
}
/**
* @inheritDoc
*/
protected onModify(value, key, oldValue) {
super.onModify(value, key, oldValue);
this.makeDirty();
switch (key) {
case 'anchor':
value.onChange = this.onVector2DModify;
break;
}
}
onAwake() {
super.onAwake();
if (!this.transform) {
console.warn('renderer need a transform component');
}
}
/**
* @inheritDoc
*/
onUpdate(t) {
if (this.dirty) {
if (this.useCacheMode) {
this.readyCacheCanvas();
}
this.measureBounds();
if (this.useCacheMode) {
this.updateCacheCanvas();
}
}
this.transformToLocal();
this.render();
if (EngineConfig.drawRenderRect) {
const {context, _debugDrawColor, bounds: {width, height}, _anchorOffset: {x, y}, transform: {pivot: {x: px, y: py}}} = this;
context.globalAlpha = 0.9;
context.strokeStyle = _debugDrawColor;
context.fillStyle = _debugDrawColor;
context.beginPath();
context.rect(0, 0, width, height);
context.stroke();
context.beginPath();
context.arc(width * px, height * py, 3, 0, 2 * Math.PI);
context.fill();
}
}
onEditorUpdate(t){
this.onUpdate(t);
}
/**
* 准备缓存渲染上下文
*/
protected readyCacheCanvas() {
let canvas = this.cacheCanvas;
if (!canvas) {
canvas = this.cacheCanvas = createCanvas();
this.cacheCanvasContext = canvas.getContext('2d');
}
}
/**
* 更新缓存属性
*/
protected updateCacheCanvas() {
let canvas = this.cacheCanvas;
const {width, height} = this.bounds;
canvas.width = width + this._margin * 2;
canvas.height = height + this._margin * 2;
}
/**
* 渲染过程
*/
protected render() {
this.beforeDraw();
this.drawClip();
if (this.dirty) {
if(this.useCacheMode){
this.draw();
}
this.dirty = false;
}
if (this.useCacheMode) {
this.drawCache();
} else {
this.draw();
}
}
/**
* 画之前
*/
protected beforeDraw() {
this.applyAlpha();
}
/**
* 执行矩阵转换
*/
protected transformToLocal() {
const {transform, _anchorOffset: {x: ax, y: ay}} = this;
if (transform && transform.enabled) {
const {a, b, c, d, tx, ty} = transform.getMatrix(false, false, true);
const offX = ax * a + ay * c;
const offY = ax * b + ay * d;
this.context.setTransform(a, b, c, d, tx - offX, ty - offY);
} else {
this.context.setTransform(1, 0, 0, 1, -ax, -ay);
}
}
/**
* 应用透明度
*/
protected applyAlpha() {
this.context.globalAlpha = this.alpha * this.transform.renderAlpha;
}
/**
* 绘制缓存
*/
protected drawCache() {
if (this.cacheCanvas.width > 0 && this.cacheCanvas.height > 0) {
this.context.drawImage(this.cacheCanvas, -this._margin, -this._margin);
}
}
/**
* 画遮罩
*/
protected drawClip() {
}
/**
* 画
*/
protected draw() {
}
/**
* 测量边界
*/
measureBounds() {
const {anchor: {x, y}, bounds, bounds: {width, height}} = this;
const anchorOffsetX = this._anchorOffset.x = width * x;
const anchorOffsetY = this._anchorOffset.y = height * y;
bounds.x = -anchorOffsetX;
bounds.y = -anchorOffsetY;
}
/**
* 碰撞检测
* @param x
* @param y
*/
hitTest(x, y) {
return this.bounds.contains(x, y);
}
}
This diff is collapsed.
/**
* Created by rockyl on 2018/11/6.
*/
import Renderer from "./Renderer";
import {Texture, decorators} from "scilla";
const {dirtyFieldDetector} = decorators;
export enum FillMode {
/**
* 正常
*/
NORMAL,
/**
* 裁切
*/
SLICED,
/**
* 瓦片
*/
TILED,
}
/**
* 纹理渲染组件
*/
export default class TextureRenderer extends Renderer {
/**
* 纹理资源
*/
@dirtyFieldDetector
texture: Texture;
/**
* 填充模式
*/
@dirtyFieldDetector
fillMode: FillMode = FillMode.NORMAL;
/**
* 滤镜数组
*/
@dirtyFieldDetector
filters = [];
private get hasFilters() {
return this.filters && this.filters.length > 0;
}
/**
* 异步资源
* @param promise
*/
private set async_texture(promise: Promise<Texture>) {
if(!promise){
return;
}
promise.then(
(texture) => {
this.texture = texture;
}
)
}
/**
* @inheritDoc
*/
draw() {
super.draw();
this.drawImage();
this.applyFilters();
/*const {context, texture, hasFilters} = this;
if (texture && hasFilters) {
const {bounds: {width: textureWidth, height: textureHeight}} = texture;
//筛选阴影滤镜Shadow
let s = this;
let cf = s.filters;
let cfLen = cf.length;
let fId = -1;
if (cfLen) {
for (let i = 0; i < cfLen; i++) {
if (s.filters[i].type == "Shadow") {
fId = i;
break;
}
}
}
if (fId >= 0) {
let ctx: any = context;
ctx.shadowBlur = cf[fId].blur;
ctx.shadowColor = cf[fId].color;
ctx.shadowOffsetX = cf[fId].offsetX;
ctx.shadowOffsetY = cf[fId].offsetY;
ctx.drawImage(this.cacheCanvas, 0, 0, textureWidth, textureHeight);
ctx.shadowBlur = 0;
ctx.shadowOffsetX = 0;
ctx.shadowOffsetY = 0;
} else {
context.drawImage(this.cacheCanvas, 0, 0, textureWidth, textureHeight);
}
// context.drawImage(texture.img, x, y, textureWidth, textureHeight, -width * this.anchor.x, -height * this.anchor.y, width, height);
}*/
}
/**
* 应用滤镜
*/
applyFilters() {
if (!this.hasFilters) return;
const {texture, filters, currentCanvasContext} = this;
const {bounds: {width: textureWidth, height: textureHeight}} = texture;
let imageData = currentCanvasContext.getImageData(0, 0, textureWidth, textureHeight);
for (const filter of filters) {
filter.drawFilter(imageData);
}
currentCanvasContext.putImageData(imageData, 0, 0);
}
/**
* 根据模式绘制图片
*/
drawImage() {
if (!this.texture) {
return;
}
const {texture, fillMode, currentCanvasContext, bounds: {width, height}} = this;
const {bounds: {x, y, width: textureWidth, height: textureHeight}} = texture;
switch (fillMode) {
case FillMode.NORMAL:
texture.drawToCanvas(currentCanvasContext);
break;
case FillMode.SLICED:
break;
case FillMode.TILED:
const textureCanvas = texture.getCacheCanvas();
const pattern = currentCanvasContext.createPattern(textureCanvas, 'repeat');
currentCanvasContext.rect(0, 0, width, height);
currentCanvasContext.fillStyle = pattern;
currentCanvasContext.fill();
break;
}
}
/**
* @inheritDoc
*/
measureBounds() {
if (!this.dirty) {
return;
}
const {bounds, transform: {explicitWidth: tWidth, explicitHeight: tHeight}} = this;
if (this.texture) {
const {width: textureWidth, height: textureHeight} = this.texture;
bounds.width = isNaN(tWidth) ? textureWidth : tWidth;
bounds.height = isNaN(tHeight) ? textureHeight : tHeight;
} else {
bounds.width = isNaN(tWidth) ? 0 : tWidth;
bounds.height = isNaN(tHeight) ? 0 : tHeight;
}
super.measureBounds();
}
}
/**
* Created by rockyl on 2019-01-10.
*/
export {default as CircleRenderer} from './CircleRenderer'
export {default as FrameAnimationRenderer} from './FrameAnimationRenderer'
export {default as GraphicRenderer} from './GraphicRenderer'
export {default as LineRenderer} from './LineRenderer'
export {default as RectRenderer} from './RectRenderer'
export {default as Renderer} from './Renderer'
export {default as TextRenderer} from './TextRenderer'
export {default as TextureRenderer} from './TextureRenderer'
export {default as HtmlRenderer} from './HtmlRenderer'
/**
* Created by rockyl on 2018/11/23.
*
* 按钮
*/
import {ScillaEvent, Texture, Entity, color, decorators} from "scilla";
import {InteractComponent} from "../base";
import {TextureRenderer} from "../renderer";
import TextRenderer from "../renderer/TextRenderer";
const {dirtyFieldDetector} = decorators;
enum STATUS {
UP,
DOWN,
DISABLED,
}
export default class Button extends InteractComponent {
@dirtyFieldDetector
upRes: Texture;
@dirtyFieldDetector
downRes: Texture;
@dirtyFieldDetector
disabledRes: Texture;
@dirtyFieldDetector
Label: Entity;
@dirtyFieldDetector
upLabelColor: color;
@dirtyFieldDetector
downLabelColor: color;
@dirtyFieldDetector
disabledLabelColor: color;
onClick: ScillaEvent = new ScillaEvent();
touchInterrupt = true;
private _bgRenderer: TextureRenderer;
private _touchBeginWithSelf: boolean;
private _touchOut: boolean;
private _label: TextRenderer;
onInteractableChanged(interactable) {
const interactComponents = this.getComponents(InteractComponent);
for (let interactComponent of interactComponents) {
if (interactComponent !== this) {
interactComponent.interactable = interactable;
}
}
this.changeTexture();
}
onAwake() {
super.onAwake();
if(!this._bgRenderer){
this._bgRenderer = this.getComponent(TextureRenderer);
this._label = this.Label && this.Label.getComponent(TextRenderer);
this.changeTexture(STATUS.UP);
}
}
onUpdate(t) {
super.onUpdate(t);
if(this['dirty']){
this.changeTexture();
this['dirty'] = false;
}
}
onTouchBegin(e) {
super.onTouchBegin(e);
this._touchBeginWithSelf = true;
this.changeTexture(STATUS.DOWN);
}
onTouchOver(e) {
super.onTouchOver(e);
if (this._touchBeginWithSelf) {
this._touchBeginWithSelf = true;
this.changeTexture(STATUS.DOWN);
}
this._touchOut = false;
}
onTouchOut(e) {
super.onTouchOut(e);
if (this._touchBeginWithSelf) {
this.changeTexture(STATUS.UP);
}
this._touchOut = true;
}
onGlobalTouchEnd(e) {
if (this._touchBeginWithSelf && !this._touchOut) {
this.onClick.invoke();
}
this._touchBeginWithSelf = false;
this.changeTexture(STATUS.UP);
return super.onGlobalTouchEnd(e);
}
changeTexture(status?: STATUS) {
if (!this._bgRenderer) {
return;
}
let res, labelColor;
switch(status){
case STATUS.UP:
res = this.upRes;
labelColor = this.upLabelColor;
break;
case STATUS.DOWN:
res = this.downRes;
labelColor = this.downLabelColor;
break;
case STATUS.DISABLED:
res = this.disabledRes;
labelColor = this.disabledLabelColor;
break;
}
let currentRes = res || this.upRes;
let currentColor = labelColor || this.upLabelColor;
if (this.interactable) {
this._bgRenderer.texture = currentRes;
if(this._label){
this._label.fillColor = currentColor;
}
} else {
this._bgRenderer.texture = this.disabledRes;
if(this._label){
this._label.fillColor = this.disabledLabelColor;
}
}
}
}
/**
* Created by rockyl on 2018-12-26.
*
* 进度条
*/
import {Entity, decorators, createTween, ease} from "scilla";
import RectRenderer from "../renderer/RectRenderer";
import Transform from "../base/Transform";
import TextRenderer from "../renderer/TextRenderer";
import ScillaComponent from "../base/ScillaComponent";
const {dirtyFieldTrigger} = decorators;
function renderLabelFuncSample(value, maximum, minimum){
return Math.floor(value / (maximum - minimum) * 100) + '%';
}
export default class ProgressBar extends ScillaComponent {
viewport: Entity;
thumb: Entity;
widget: Entity;
label: Entity;
@dirtyFieldTrigger
value: number = 0;
@dirtyFieldTrigger
minimum: number = 0;
@dirtyFieldTrigger
maximum: number = 0;
@dirtyFieldTrigger
snapInterval: number = 1;
@dirtyFieldTrigger
renderLabelFunc: Function;
@dirtyFieldTrigger
fixWithRange: boolean = true;
private _mask: RectRenderer;
private _widgetTransform: Transform;
private _label: TextRenderer;
private _thumbSize: any;
onCreate() {
super.onCreate();
this.renderLabelFunc = renderLabelFuncSample;
}
onAwake() {
super.onAwake();
this._mask = this.viewport.getComponent(RectRenderer);
this._mask.width = 0;
if(this.widget){
this._widgetTransform = this.widget.getComponent(Transform);
}
this._label = this.label.getComponent(TextRenderer);
this.callOnNextTick(this.updateThumbSize);
}
private updateThumbSize=()=>{
const {width, height} = this.thumb.getComponent(Transform);
this._thumbSize = {width, height};
this.update();
};
onModify(value, key, oldValue) {
super.onModify(value, key, oldValue);
if(oldValue === undefined){
return;
}
this.callOnNextTick(this.update);
}
private update(){
const {minimum, maximum, _thumbSize} = this;
if(!_thumbSize){
return ;
}
const range = maximum - minimum;
let value = Math.max(minimum, Math.min(maximum, this.value));
const percentage = (value - minimum) / range;
const width = percentage * _thumbSize.width;
//this._mask.width = width;
createTween(this, this._mask, true)
.to({width}, 300, ease.cubicOut);
if(this._widgetTransform){
this._widgetTransform.position.x = width;
}
let renderValue = this.fixWithRange ? Math.max(minimum, Math.min(maximum, this.value)) : this.value;
this.value = value;
if(this._label){
let text = this.renderLabelFunc(renderValue, this.maximum, this.minimum);
if(typeof text == 'string'){
this._label.text = text;
this._label.textFlow = null;
}else{
this._label.textFlow = text;
this._label.updateTextFlow();
}
}
}
}
/**
* Created by rockyl on 2018-12-13.
*
* 滚动视图组件
*/
import {Entity, Size, createTween, createVector2D, Vector2D, ease} from "scilla";
import InteractComponent from "../base/InteractComponent";
import Transform from "../base/Transform";
export enum LockingType {
NOSET,
HORIZON,
VERTICAL,
}
export default class ScrollView extends InteractComponent {
viewport: Entity;
content: Entity;
lockingType: LockingType = LockingType.NOSET;
private _beginPos: any;
private _lastPos: Vector2D = createVector2D();
private _viewportTransform: Transform;
private _contentTransform: Transform;
private _posOffset: any;
private _posRange: Size;
private _speed: Vector2D = createVector2D();
onAwake() {
super.onAwake();
this._contentTransform = this.content.getComponent(Transform);
this._viewportTransform = this.viewport.getComponent(Transform);
this.callOnNextTick(this.updatePosOffset);
}
updatePosOffset = ()=>{
const {position: {x: x, y: y}} = this._contentTransform;
this._posOffset = {x, y};
//console.log(this._posOffset);
}
updatePosRange = () => {
const {width: pWidth, height: pHeight} = this._viewportTransform;
const {width, height} = this._contentTransform;
this._posRange = new Size(pWidth - width, pHeight - height);
//console.log(this._posRange);
};
onTouchBegin(e) {
super.onTouchBegin(e);
this.updatePosRange();
const {x: tx, y: ty} = e;
const {_contentTransform: {position: {x: cx, y: cy}}} = this;
this._beginPos = {
tx,
ty,
cx,
cy,
};
this._lastPos.setXY(tx, ty);
}
onGlobalTouchMove(e): boolean {
super.onGlobalTouchMove(e);
if (!this._beginPos) {
return;
}
const {
_beginPos: {tx, ty, cx, cy},
_posOffset: {x: offX, y: offY},
_contentTransform: {position},
lockingType,
} = this;
const {x, y} = e;
let px = x - tx + cx;
let py = y - ty + cy;
const {width: rWidth, height: rHeight} = this._posRange;
const halfWidth = Math.abs( rWidth / 2);
const paddingX = halfWidth - Math.abs(offX - halfWidth - px);
if(paddingX < 0){
px += paddingX * 0.8 * (x - tx > 0 ? 1 : -1);
}
const halfHeight = Math.abs( rHeight / 2);
const paddingY = halfHeight - Math.abs(offY - halfHeight - py);
if(paddingY < 0){
py += paddingY * 0.8 * (y - ty > 0 ? 1 : -1);
}
switch (lockingType) {
case LockingType.HORIZON:
position.y = py;
break;
case LockingType.VERTICAL:
position.x = px;
break;
default:
position.setXY(px, py);
}
this._speed.copyFrom(this._lastPos.subtract({x, y}));
this._lastPos.setXY(x, y);
}
onGlobalTouchEnd(e): boolean {
super.onGlobalTouchEnd(e);
if (!this._beginPos) {
return;
}
this._beginPos = null;
const {x: offX, y: offY} = this._posOffset;
const {width: rWidth, height: rHeight} = this._posRange;
const {position, position: {x, y}} = this._contentTransform;
const tx = Math.min(Math.max(offX + rWidth, x), offX);
const ty = Math.min(Math.max(offY + rHeight, y), offY);
const targetPos = createVector2D(tx, ty);
const duration = Math.min(500, Math.max(targetPos.distance(position), 200));
createTween(this, this._contentTransform, true, {fields: ['x', 'y']})
.to({position: targetPos}, duration, ease.cubicOut);
}
}
/**
* Created by rockyl on 2019-01-10.
*/
export {default as Button} from './Button'
export {default as ProgressBar} from './ProgressBar'
export {default as ScrollView} from './ScrollView'
{
"compilerOptions": {
"target": "es5",
"outDir": "dist",
"experimentalDecorators": true,
"sourceMap": true,
"declarationDir": "types",
"declaration": true,
"lib": [
"es5",
"es6",
"dom",
"es2015.promise"
],
"baseUrl": "./",
"paths": {
"scilla": ["node_modules/scilla/src"]
}
},
"include": [
"src"
]
}
\ No newline at end of file
This diff is collapsed.
# Created by .ignore support plugin (hsz.mobi)
### Node template
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# Runtime data
pids
*.pid
*.seed
*.pid.lock
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
# nyc test coverage
.nyc_output
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# Bower dependency directory (https://bower.io/)
bower_components
# node-waf configuration
.lock-wscript
# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release
# Dependency directories
node_modules/
jspm_packages/
# TypeScript v1 declaration files
typings/
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
*.tgz
# Yarn Integrity file
.yarn-integrity
# dotenv environment variables file
.env
# parcel-bundler cache (https://parceljs.org/)
.cache
# next.js build output
.next
# nuxt.js build output
.nuxt
# vuepress build output
.vuepress/dist
# Serverless directories
.serverless
/.rpt2_cache/
/dist/
{
"name": "scilla-launcher",
"version": "1.0.1",
"main": "./dist/index.js",
"types": "./types/index.d.ts",
"license": "MIT",
"devDependencies": {
"glob": "^7.1.3",
"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.3.4000"
}
}
/**
* Created by rockyl on 2018/11/16.
*/
const resolve = require('rollup-plugin-node-resolve');
const commonjs = require('rollup-plugin-commonjs');
const typescript = require('rollup-plugin-typescript2');
const {uglify} = require('rollup-plugin-uglify');
const name = 'scilla-launcher';
export default {
input: 'src/index.ts',
output: {
file: `dist/${name}.js`,
format: 'umd',
name,
//sourcemap: true,
},
plugins: [
resolve({
browser: true,
}),
typescript({
typescript: require('typescript'),
tslib: require('tslib'),
declaration: false,
}),
commonjs(),
//uglify({}),
],
external: ['scilla']
};
<?xml version="1.0" encoding="UTF-8"?>
<module type="WEB_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$/../scilla-launcher" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>
\ No newline at end of file
/**
* Created by rockyl on 2018-12-03.
*/
import {Entity, ScillaEngine, setupScene} from "scilla";
/**
* 场景
*/
export default class Scene {
private _engine: ScillaEngine;
private _name: string;
private _resourceGroups: any = {
preload: [],
delay: [],
};
private _config: any;
private _root: Entity;
constructor(engine: ScillaEngine) {
this._engine = engine;
}
get root(): Entity {
return this._root;
}
/**
* 初始化
* @param config
*/
initByConfig(config: any) {
this._config = config;
this._name = config.name;
const resourceGroups = config['resource-groups'];
for (let key in resourceGroups) {
this._resourceGroups[key] = resourceGroups[key];
}
}
setup(root: Entity) {
this._root = root;
const assetsManager = this._engine.assetsManager;
setupScene(this._config, root, assetsManager.getRes.bind(assetsManager));
}
/**
* 加载资源组
* @param name
* @param replaceConfig
* @param progress
*/
async loadResGroup(name, replaceConfig?, progress?) {
await this._engine.assetsManager.loadResItems(this._resourceGroups[name], replaceConfig, progress);
}
}
/**
* Created by rockyl on 2018-12-04.
*/
import {engine, utils, cleanEntity} from "scilla";
import Scene from './Scene'
export {default as Scene} from './Scene'
export default class ScillaLauncher{
private currentScene: Scene;
private resUUIDs: string[];
/**
* 启动引擎
* @param containerElement
* @param options
* @param onProgress
*/
async launch(containerElement, options:any = {}, onProgress: Function) {
const resPath = options.resPath || '';
const manifest = await engine.assetsManager.loadJson(resPath + 'manifest.json');
engine.assetsManager.setResPath(resPath + 'assets/');
let engineConfig:any = {};
utils.injectProp(engineConfig, manifest.engineConfig);
utils.injectProp(engineConfig, options.engineConfig);
let customConfig:any = {};
utils.injectProp(customConfig, manifest.customConfig);
utils.injectProp(customConfig, options.customConfig);
let dataCenterConfig:any = {};
utils.injectProp(dataCenterConfig, manifest.dataCenterConfig);
utils.injectProp(dataCenterConfig, options.dataCenterConfig);
let canvas = document.createElement('canvas');
containerElement.appendChild(canvas);
engineConfig.canvas = canvas;
engine.setup(engineConfig, customConfig, dataCenterConfig);
let entryScene = options.scene || customConfig.scene.entryScene;
await this.launchScene(entryScene, options.resReplaceConfigs, onProgress)
}
/**
* 启动场景
* @param sceneNameOrPath
* @param resReplaceConfigs
* @param progress
*/
async launchScene(sceneNameOrPath, resReplaceConfigs?, progress?) {
const sceneConfig = engine.customConfig.scene;
let sceneFile = sceneConfig.scenes[sceneNameOrPath];
if(!sceneFile){
sceneFile = sceneNameOrPath;
}
const scene = await this.loadScene(sceneFile, 'scene_' + sceneFile);
this.resUUIDs = engine.assetsManager.getAllResUuids();
const replaceConfig = resReplaceConfigs && resReplaceConfigs[sceneFile];
await scene.loadResGroup('preload', replaceConfig, progress);
if(this.currentScene){
this.unmountScene(this.currentScene);
}
this.currentScene = scene;
this.mountScene(scene);
scene.loadResGroup('delay', null, progress);
}
/**
* 装载场景
* @param scene
*/
private mountScene(scene){
engine.pause();
scene.setup(engine.root);
engine.start();
}
/**
* 卸载场景
* @param scene
*/
private unmountScene(scene){
engine.pause();
cleanEntity(scene.root);
engine.assetsManager.destroyRes(this.resUUIDs);
}
/**
* 加载场景资源
* @param url url
* @param uuid 唯一名
* @param cache 是否缓存
* @param config
* @return Promise<any> 资源
*/
private async loadScene(url, uuid?, cache = false, config?) {
const sceneConfig = await engine.assetsManager.loadJson5(url);
const scene = new Scene(engine);
scene.initByConfig(sceneConfig);
return scene;
}
}
{
"compilerOptions": {
"target": "es5",
"outDir": "dist",
"experimentalDecorators": true,
"sourceMap": true,
"declarationDir": "types",
"declaration": true,
"lib": [
"es5",
"es6",
"dom",
"es2015.promise"
],
"baseUrl": "./",
"paths": {
"scilla": ["node_modules/scilla/src"]
}
},
"include": [
"src"
]
}
\ No newline at end of file
This diff is collapsed.
# Created by .ignore support plugin (hsz.mobi)
### Node template
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# Runtime data
pids
*.pid
*.seed
*.pid.lock
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
# nyc test coverage
.nyc_output
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# Bower dependency directory (https://bower.io/)
bower_components
# node-waf configuration
.lock-wscript
# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release
# Dependency directories
node_modules/
jspm_packages/
# TypeScript v1 declaration files
typings/
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
*.tgz
# Yarn Integrity file
.yarn-integrity
# dotenv environment variables file
.env
# parcel-bundler cache (https://parceljs.org/)
.cache
# next.js build output
.next
# nuxt.js build output
.nuxt
# vuepress build output
.vuepress/dist
# Serverless directories
.serverless
/.rpt2_cache/
/**
* 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);
})
}
}
This diff is collapsed.
This diff is collapsed.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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