@@ -1,3 +1,5 @@
|
|||||||
/source/node_modules
|
/source/node_modules
|
||||||
/demo/bin-debug
|
/demo/bin-debug
|
||||||
/demo/bin-release
|
/demo/bin-release
|
||||||
|
/.idea
|
||||||
|
/.vscode
|
||||||
|
|||||||
Vendored
-15
@@ -1,15 +0,0 @@
|
|||||||
{
|
|
||||||
// 使用 IntelliSense 了解相关属性。
|
|
||||||
// 悬停以查看现有属性的描述。
|
|
||||||
// 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387
|
|
||||||
"version": "0.2.0",
|
|
||||||
"configurations": [
|
|
||||||
{
|
|
||||||
"type": "pwa-chrome",
|
|
||||||
"request": "launch",
|
|
||||||
"name": "Launch Chrome against localhost",
|
|
||||||
"url": "http://localhost:8080",
|
|
||||||
"webRoot": "${workspaceFolder}"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
Generated
+2
@@ -0,0 +1,2 @@
|
|||||||
|
# Default ignored files
|
||||||
|
/workspace.xml
|
||||||
Generated
+8
@@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<module type="WEB_MODULE" version="4">
|
||||||
|
<component name="NewModuleRootManager">
|
||||||
|
<content url="file://$MODULE_DIR$" />
|
||||||
|
<orderEntry type="inheritedJdk" />
|
||||||
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
|
</component>
|
||||||
|
</module>
|
||||||
Generated
+6
@@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="JavaScriptSettings">
|
||||||
|
<option name="languageLevel" value="ES6" />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
Generated
+8
@@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="ProjectModuleManager">
|
||||||
|
<modules>
|
||||||
|
<module fileurl="file://$PROJECT_DIR$/.idea/demo.iml" filepath="$PROJECT_DIR$/.idea/demo.iml" />
|
||||||
|
</modules>
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
Generated
+6
@@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="VcsDirectoryMappings">
|
||||||
|
<mapping directory="$PROJECT_DIR$/.." vcs="Git" />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
Vendored
+1479
-1134
File diff suppressed because it is too large
Load Diff
+6762
-5364
File diff suppressed because it is too large
Load Diff
Vendored
+1
-1
File diff suppressed because one or more lines are too long
+1
-2
@@ -11,12 +11,11 @@
|
|||||||
"libs/long/long.js"
|
"libs/long/long.js"
|
||||||
],
|
],
|
||||||
"game": [
|
"game": [
|
||||||
"bin-debug/game/CoreEmitterType.js",
|
|
||||||
"bin-debug/AssetAdapter.js",
|
"bin-debug/AssetAdapter.js",
|
||||||
|
"bin-debug/LoadingUI.js",
|
||||||
"bin-debug/Main.js",
|
"bin-debug/Main.js",
|
||||||
"bin-debug/Platform.js",
|
"bin-debug/Platform.js",
|
||||||
"bin-debug/ThemeAdapter.js",
|
"bin-debug/ThemeAdapter.js",
|
||||||
"bin-debug/LoadingUI.js",
|
|
||||||
"bin-debug/game/MainScene.js",
|
"bin-debug/game/MainScene.js",
|
||||||
"bin-debug/game/PlayerController.js",
|
"bin-debug/game/PlayerController.js",
|
||||||
"bin-debug/game/SimplePooled.js",
|
"bin-debug/game/SimplePooled.js",
|
||||||
|
|||||||
+18
-64
@@ -27,71 +27,29 @@
|
|||||||
//
|
//
|
||||||
//////////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
class Main extends es.Core {
|
||||||
class Main extends eui.UILayer {
|
protected initialize() {
|
||||||
public static emitter: Emitter<CoreEmitterType>;
|
|
||||||
public static manager: SceneManager;
|
|
||||||
|
|
||||||
protected createChildren(): void {
|
|
||||||
super.createChildren();
|
|
||||||
|
|
||||||
egret.lifecycle.addLifecycleListener((context) => {
|
|
||||||
// custom lifecycle plugin
|
|
||||||
})
|
|
||||||
|
|
||||||
egret.lifecycle.onPause = () => {
|
|
||||||
egret.ticker.pause();
|
|
||||||
}
|
|
||||||
|
|
||||||
egret.lifecycle.onResume = () => {
|
|
||||||
egret.ticker.resume();
|
|
||||||
}
|
|
||||||
|
|
||||||
//inject the custom material parser
|
|
||||||
//注入自定义的素材解析器
|
|
||||||
let assetAdapter = new AssetAdapter();
|
|
||||||
egret.registerImplementation("eui.IAssetAdapter", assetAdapter);
|
|
||||||
egret.registerImplementation("eui.IThemeAdapter", new ThemeAdapter());
|
|
||||||
|
|
||||||
Main.manager = new SceneManager(this.stage);
|
|
||||||
Main.emitter = new Emitter<CoreEmitterType>();
|
|
||||||
this.addEventListener(egret.Event.ENTER_FRAME, this.updateFrame, this);
|
|
||||||
this.runGame();
|
this.runGame();
|
||||||
}
|
}
|
||||||
|
|
||||||
private updateFrame(evt: egret.Event){
|
private runGame() {
|
||||||
Main.emitter.emit(CoreEmitterType.Update, evt);
|
this.loadResource();
|
||||||
}
|
}
|
||||||
|
|
||||||
private async runGame() {
|
|
||||||
await this.loadResource();
|
|
||||||
this.createGameScene();
|
|
||||||
}
|
|
||||||
|
|
||||||
private async loadResource() {
|
private loadResource() {
|
||||||
try {
|
const loadingView = new LoadingUI();
|
||||||
const loadingView = new LoadingUI();
|
this.stage.addChild(loadingView);
|
||||||
this.stage.addChild(loadingView);
|
RES.loadConfig("resource/default.res.json", "resource/").then(()=>{
|
||||||
await RES.loadConfig("resource/default.res.json", "resource/");
|
RES.loadGroup("preload", 0, loadingView).then(()=>{
|
||||||
await this.loadTheme();
|
this.stage.removeChild(loadingView);
|
||||||
await RES.loadGroup("preload", 0, loadingView);
|
this.createGameScene();
|
||||||
this.stage.removeChild(loadingView);
|
}).catch(err => {
|
||||||
}
|
console.error(err);
|
||||||
catch (e) {
|
});
|
||||||
console.error(e);
|
}).catch(err =>{
|
||||||
}
|
console.error(err);
|
||||||
}
|
});
|
||||||
|
|
||||||
private loadTheme() {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
// load skin theme configuration file, you can manually modify the file. And replace the default skin.
|
|
||||||
//加载皮肤主题配置文件,可以手动修改这个文件。替换默认皮肤。
|
|
||||||
let theme = new eui.Theme("resource/default.thm.json", this.stage);
|
|
||||||
theme.addEventListener(eui.UIEvent.COMPLETE, () => {
|
|
||||||
resolve();
|
|
||||||
}, this);
|
|
||||||
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -99,10 +57,6 @@ class Main extends eui.UILayer {
|
|||||||
* Create scene interface
|
* Create scene interface
|
||||||
*/
|
*/
|
||||||
protected createGameScene(): void {
|
protected createGameScene(): void {
|
||||||
SceneManager.scene = new MainScene();
|
es.Core.scene = new scene.MainScene();
|
||||||
|
|
||||||
// Main.emitter.addObserver(CoreEmitterType.Update, ()=>{
|
|
||||||
// console.log("update emitter");
|
|
||||||
// });
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +0,0 @@
|
|||||||
enum CoreEmitterType {
|
|
||||||
Update,
|
|
||||||
}
|
|
||||||
+71
-76
@@ -1,95 +1,90 @@
|
|||||||
class MainScene extends Scene {
|
module scene {
|
||||||
constructor() {
|
export class MainScene extends es.Scene {
|
||||||
super();
|
constructor() {
|
||||||
|
super();
|
||||||
|
|
||||||
// this.addEntityProcessor(new SpawnerSystem(new Matcher()));
|
// this.addEntityProcessor(new SpawnerSystem(new Matcher()));
|
||||||
this.astarTest();
|
this.astarTest();
|
||||||
this.dijkstraTest();
|
this.dijkstraTest();
|
||||||
this.breadthfirstTest();
|
this.breadthfirstTest();
|
||||||
}
|
|
||||||
|
|
||||||
public async onStart() {
|
|
||||||
let sprite = new Sprite(RES.getRes("checkbox_select_disabled_png"));
|
|
||||||
let bg = this.createEntity("bg");
|
|
||||||
bg.addComponent(new SpriteRenderer()).setSprite(sprite).setColor(0xff0000);
|
|
||||||
bg.addComponent(new PlayerController());
|
|
||||||
bg.addComponent(new Mover());
|
|
||||||
bg.addComponent(new ScrollingSpriteRenderer(sprite));
|
|
||||||
bg.addComponent(new BoxCollider());
|
|
||||||
bg.position = new Vector2(Math.random() * 200, Math.random() * 200);
|
|
||||||
|
|
||||||
for (let i = 0; i < 20; i++) {
|
|
||||||
let sprite = new Sprite(RES.getRes("checkbox_select_disabled_png"));
|
|
||||||
let player2 = this.createEntity("player2");
|
|
||||||
player2.addComponent(new SpriteRenderer()).setSprite(sprite);
|
|
||||||
player2.position = new Vector2(Math.random() * 1000, Math.random() * 1000);
|
|
||||||
player2.addComponent(new BoxCollider());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.camera.follow(bg, CameraStyle.lockOn);
|
public async onStart() {
|
||||||
|
let sprite = new es.Sprite(RES.getRes("checkbox_select_disabled_png"));
|
||||||
|
let bg = this.createEntity("bg");
|
||||||
|
bg.addComponent(new es.SpriteRenderer()).setSprite(sprite).setColor(0xff0000);
|
||||||
|
bg.addComponent(new component.PlayerController());
|
||||||
|
bg.addComponent(new es.Mover());
|
||||||
|
bg.addComponent(new es.ScrollingSpriteRenderer(sprite));
|
||||||
|
bg.addComponent(new es.BoxCollider());
|
||||||
|
bg.position = new es.Vector2(Math.random() * 200, Math.random() * 200);
|
||||||
|
|
||||||
let pool = new ComponentPool<SimplePooled>(SimplePooled);
|
for (let i = 0; i < 1; i++) {
|
||||||
let c1 = pool.obtain();
|
let sprite = new es.Sprite(RES.getRes("checkbox_select_disabled_png"));
|
||||||
let c2 = pool.obtain();
|
let player2 = this.createEntity("player2");
|
||||||
pool.free(c1);
|
player2.addComponent(new es.SpriteRenderer()).setSprite(sprite);
|
||||||
let c1b = pool.obtain();
|
player2.position = new es.Vector2(Math.random() * 100, Math.random() * 100);
|
||||||
|
player2.addComponent(new es.BoxCollider());
|
||||||
|
}
|
||||||
|
|
||||||
console.log(c1 != c2);
|
this.camera.follow(bg, es.CameraStyle.lockOn);
|
||||||
console.log(c1 == c1b);
|
|
||||||
|
|
||||||
let button = new eui.Button();
|
let pool = new es.ComponentPool<component.SimplePooled>(component.SimplePooled);
|
||||||
button.label = "切换场景";
|
let c1 = pool.obtain();
|
||||||
this.addChild(button);
|
let c2 = pool.obtain();
|
||||||
button.addEventListener(egret.TouchEvent.TOUCH_TAP, () => {
|
pool.free(c1);
|
||||||
SceneManager.startSceneTransition(new FadeTransition(() => {
|
let c1b = pool.obtain();
|
||||||
return new MainScene();
|
|
||||||
}));
|
|
||||||
}, this);
|
|
||||||
|
|
||||||
Main.emitter.addObserver(CoreEmitterType.Update, this.handleFuncTest, this);
|
console.log(c1 != c2);
|
||||||
}
|
console.log(c1 == c1b);
|
||||||
|
|
||||||
/** 测试Emitter */
|
let button = new eui.Button();
|
||||||
private handleFuncTest(){
|
button.label = "切换场景";
|
||||||
Main.emitter.removeObserver(CoreEmitterType.Update, this.handleFuncTest);
|
this.addChild(button);
|
||||||
}
|
button.addEventListener(egret.TouchEvent.TOUCH_TAP, () => {
|
||||||
|
es.Core.startSceneTransition(new es.FadeTransition(() => {
|
||||||
|
return new MainScene();
|
||||||
|
}));
|
||||||
|
}, this);
|
||||||
|
}
|
||||||
|
|
||||||
public breadthfirstTest() {
|
public breadthfirstTest() {
|
||||||
let graph = new UnweightedGraph<string>();
|
let graph = new es.UnweightedGraph<string>();
|
||||||
|
|
||||||
graph.addEdgesForNode("a", ["b"]); // a->b
|
graph.addEdgesForNode("a", ["b"]); // a->b
|
||||||
graph.addEdgesForNode("b", ["a", "c", "d"]); // b->a b->c b->d
|
graph.addEdgesForNode("b", ["a", "c", "d"]); // b->a b->c b->d
|
||||||
graph.addEdgesForNode("c", ["a"]); // c->a
|
graph.addEdgesForNode("c", ["a"]); // c->a
|
||||||
graph.addEdgesForNode("d", ["e", "a"]); // d->e d->a
|
graph.addEdgesForNode("d", ["e", "a"]); // d->e d->a
|
||||||
graph.addEdgesForNode("e", ["b"]); // e->b
|
graph.addEdgesForNode("e", ["b"]); // e->b
|
||||||
|
|
||||||
// 计算从c到e的路径
|
// 计算从c到e的路径
|
||||||
let path = BreadthFirstPathfinder.search(graph, "c", "e");
|
let path = es.BreadthFirstPathfinder.search(graph, "c", "e");
|
||||||
console.log(path);
|
console.log(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
public dijkstraTest() {
|
public dijkstraTest() {
|
||||||
let graph = new WeightedGridGraph(20, 20);
|
let graph = new es.WeightedGridGraph(20, 20);
|
||||||
|
|
||||||
graph.weightedNodes.push(new Vector2(3, 3));
|
graph.weightedNodes.push(new es.Vector2(3, 3));
|
||||||
graph.weightedNodes.push(new Vector2(3, 4));
|
graph.weightedNodes.push(new es.Vector2(3, 4));
|
||||||
graph.weightedNodes.push(new Vector2(4, 3));
|
graph.weightedNodes.push(new es.Vector2(4, 3));
|
||||||
graph.weightedNodes.push(new Vector2(4, 4));
|
graph.weightedNodes.push(new es.Vector2(4, 4));
|
||||||
|
|
||||||
let path = graph.search(new Vector2(3, 4), new Vector2(15, 17));
|
let path = graph.search(new es.Vector2(3, 4), new es.Vector2(15, 17));
|
||||||
console.log(path);
|
console.log(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
public astarTest() {
|
public astarTest() {
|
||||||
let graph = new AstarGridGraph(30, 30);
|
let graph = new es.AstarGridGraph(30, 30);
|
||||||
|
|
||||||
// graph.weightedNodes.push(new Vector2(3, 3));
|
// graph.weightedNodes.push(new Vector2(3, 3));
|
||||||
// graph.weightedNodes.push(new Vector2(3, 4));
|
// graph.weightedNodes.push(new Vector2(3, 4));
|
||||||
// graph.weightedNodes.push(new Vector2(4, 3));
|
// graph.weightedNodes.push(new Vector2(4, 3));
|
||||||
// graph.weightedNodes.push(new Vector2(4, 4));
|
// graph.weightedNodes.push(new Vector2(4, 4));
|
||||||
|
|
||||||
let startTime = egret.getTimer();
|
let startTime = egret.getTimer();
|
||||||
let path = graph.search(new Vector2(1, 1), new Vector2(29, 29));
|
let path = graph.search(new es.Vector2(1, 1), new es.Vector2(29, 29));
|
||||||
console.log(egret.getTimer() - startTime);
|
console.log(egret.getTimer() - startTime);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,56 +1,66 @@
|
|||||||
class PlayerController extends Component {
|
module component {
|
||||||
private down: boolean = false;
|
import Component = es.Component;
|
||||||
private touchPoint: Vector2 = Vector2.zero;
|
import Vector2 = es.Vector2;
|
||||||
private mover: Mover;
|
import Mover = es.Mover;
|
||||||
private spriteRenderer: SpriteRenderer;
|
import SpriteRenderer = es.SpriteRenderer;
|
||||||
|
import Time = es.Time;
|
||||||
|
import Input = es.Input;
|
||||||
|
import CollisionResult = es.CollisionResult;
|
||||||
|
|
||||||
public onAddedToEntity(){
|
export class PlayerController extends Component {
|
||||||
this.entity.scene.stage.addEventListener(egret.TouchEvent.TOUCH_BEGIN, this.touchBegin, this);
|
private down: boolean = false;
|
||||||
this.entity.scene.stage.addEventListener(egret.TouchEvent.TOUCH_MOVE, this.touchBegin, this);
|
private touchPoint: Vector2 = Vector2.zero;
|
||||||
this.entity.scene.stage.addEventListener(egret.TouchEvent.TOUCH_END, this.touchEnd, this);
|
private mover: Mover;
|
||||||
}
|
private spriteRenderer: SpriteRenderer;
|
||||||
|
|
||||||
private touchBegin(evt: egret.TouchEvent){
|
public onAddedToEntity(){
|
||||||
this.down = true;
|
this.entity.scene.stage.addEventListener(egret.TouchEvent.TOUCH_BEGIN, this.touchBegin, this);
|
||||||
this.touchPoint = new Vector2(evt.stageX, evt.stageY);
|
this.entity.scene.stage.addEventListener(egret.TouchEvent.TOUCH_MOVE, this.touchBegin, this);
|
||||||
}
|
this.entity.scene.stage.addEventListener(egret.TouchEvent.TOUCH_END, this.touchEnd, this);
|
||||||
|
}
|
||||||
|
|
||||||
private touchEnd(evt: egret.TouchEvent){
|
private touchBegin(evt: egret.TouchEvent){
|
||||||
this.down = false;
|
this.down = true;
|
||||||
this.touchPoint = new Vector2(evt.stageX, evt.stageY);
|
this.touchPoint = new Vector2(evt.stageX, evt.stageY);
|
||||||
}
|
}
|
||||||
|
|
||||||
public update(){
|
private touchEnd(evt: egret.TouchEvent){
|
||||||
if (!this.mover)
|
this.down = false;
|
||||||
this.mover = this.entity.getComponent<Mover>(Mover);
|
this.touchPoint = new Vector2(evt.stageX, evt.stageY);
|
||||||
|
}
|
||||||
|
|
||||||
if (!this.spriteRenderer)
|
public update(){
|
||||||
this.spriteRenderer = this.entity.getComponent<SpriteRenderer>(SpriteRenderer);
|
if (!this.mover)
|
||||||
|
this.mover = this.entity.getComponent<Mover>(Mover);
|
||||||
|
|
||||||
if (!this.mover)
|
if (!this.spriteRenderer)
|
||||||
return;
|
this.spriteRenderer = this.entity.getComponent<SpriteRenderer>(SpriteRenderer);
|
||||||
|
|
||||||
if (!SpriteRenderer)
|
if (!this.mover)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (this.down){
|
if (!SpriteRenderer)
|
||||||
let camera = SceneManager.scene.camera;
|
return;
|
||||||
let moveLeft: number = 0;
|
|
||||||
let moveRight: number = 0;
|
if (this.down){
|
||||||
let speed = 100;
|
let moveLeft: number = 0;
|
||||||
let worldPos = Input.touchPosition;
|
let moveRight: number = 0;
|
||||||
if (worldPos.x < this.spriteRenderer.localPosition.x){
|
let speed = 100;
|
||||||
moveLeft = -1;
|
let worldPos = this.entity.scene.camera.mouseToWorldPoint();
|
||||||
} else if(worldPos.x > this.spriteRenderer.localPosition.x){
|
if (worldPos.x < this.spriteRenderer.transform.position.x){
|
||||||
moveLeft = 1;
|
moveLeft = -1;
|
||||||
|
} else if(worldPos.x > this.spriteRenderer.transform.position.x){
|
||||||
|
moveLeft = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (worldPos.y < this.spriteRenderer.transform.position.y){
|
||||||
|
moveRight = -1;
|
||||||
|
} else if(worldPos.y > this.spriteRenderer.transform.position.y){
|
||||||
|
moveRight = 1;
|
||||||
|
}
|
||||||
|
let collisionResult = new CollisionResult();
|
||||||
|
this.mover.move(new Vector2(moveLeft * speed * Time.deltaTime, moveRight * speed * Time.deltaTime), collisionResult);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (worldPos.y < this.spriteRenderer.localPosition.y){
|
|
||||||
moveRight = -1;
|
|
||||||
} else if(worldPos.y > this.spriteRenderer.localPosition.y){
|
|
||||||
moveRight = 1;
|
|
||||||
}
|
|
||||||
this.mover.move(new Vector2(moveLeft * speed * Time.deltaTime, moveRight * speed * Time.deltaTime));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,9 @@
|
|||||||
class SimplePooled extends PooledComponent {
|
module component {
|
||||||
public reset(){
|
import PooledComponent = es.PooledComponent;
|
||||||
|
|
||||||
|
export class SimplePooled extends PooledComponent {
|
||||||
|
public reset(){
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,35 +1,37 @@
|
|||||||
class SpawnComponent extends Component implements ITriggerListener {
|
module component {
|
||||||
public cooldown = -1;
|
export class SpawnComponent extends es.Component implements es.ITriggerListener {
|
||||||
public minInterval = 2;
|
public cooldown = -1;
|
||||||
public maxInterval = 60;
|
public minInterval = 2;
|
||||||
public enemyType = EnemyType.worm;
|
public maxInterval = 60;
|
||||||
public numSpawned = 0;
|
public enemyType = EnemyType.worm;
|
||||||
public numAlive = 0;
|
public numSpawned = 0;
|
||||||
|
public numAlive = 0;
|
||||||
|
|
||||||
constructor(enemyType: EnemyType) {
|
constructor(enemyType: EnemyType) {
|
||||||
super();
|
super();
|
||||||
this.enemyType = enemyType;
|
this.enemyType = enemyType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public initialize() {
|
||||||
|
// console.log("initialize");
|
||||||
|
}
|
||||||
|
|
||||||
|
public update() {
|
||||||
|
// console.log("update");
|
||||||
|
}
|
||||||
|
|
||||||
|
public onTriggerEnter(other: es.Collider, local: es.Collider){
|
||||||
|
if (other == local)
|
||||||
|
console.log("repeat collider");
|
||||||
|
console.log("enter collider");
|
||||||
|
}
|
||||||
|
|
||||||
|
public onTriggerExit(other: es.Collider, local: es.Collider){
|
||||||
|
console.log("exit collider");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public initialize() {
|
export enum EnemyType {
|
||||||
// console.log("initialize");
|
worm
|
||||||
}
|
|
||||||
|
|
||||||
public update() {
|
|
||||||
// console.log("update");
|
|
||||||
}
|
|
||||||
|
|
||||||
public onTriggerEnter(other: Collider, local: Collider){
|
|
||||||
if (other == local)
|
|
||||||
console.log("repeat collider")
|
|
||||||
console.log("enter collider");
|
|
||||||
}
|
|
||||||
|
|
||||||
public onTriggerExit(other: Collider, local: Collider){
|
|
||||||
console.log("exit collider");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enum EnemyType {
|
|
||||||
worm
|
|
||||||
}
|
|
||||||
@@ -1,34 +1,36 @@
|
|||||||
class SpawnerSystem extends EntityProcessingSystem {
|
module system {
|
||||||
constructor(matcher: Matcher){
|
export class SpawnerSystem extends es.EntityProcessingSystem {
|
||||||
super(matcher);
|
constructor(matcher: es.Matcher){
|
||||||
}
|
super(matcher);
|
||||||
|
|
||||||
public processEntity(entity: Entity){
|
|
||||||
let spawner = entity.getComponent<SpawnComponent>(SpawnComponent);
|
|
||||||
if (!spawner)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (spawner.numAlive <= 0)
|
|
||||||
spawner.enabled = true;
|
|
||||||
|
|
||||||
if (!spawner.enabled)
|
|
||||||
return;
|
|
||||||
|
|
||||||
console.log("cooldown", spawner.cooldown);
|
|
||||||
if (spawner.cooldown == -1){
|
|
||||||
spawner.cooldown = Math.random() * 60;
|
|
||||||
spawner.cooldown /= 4;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
spawner.cooldown -= Time.deltaTime;
|
public processEntity(entity: es.Entity){
|
||||||
if (spawner.cooldown <= 0){
|
let spawner = entity.getComponent<component.SpawnComponent>(component.SpawnComponent);
|
||||||
spawner.cooldown = Math.random() * 60;
|
if (!spawner)
|
||||||
// CreateEnemy
|
return;
|
||||||
spawner.numSpawned ++;
|
|
||||||
spawner.numAlive ++;
|
|
||||||
|
|
||||||
if (spawner.numAlive > 0)
|
if (spawner.numAlive <= 0)
|
||||||
spawner.enabled = false;
|
spawner.enabled = true;
|
||||||
|
|
||||||
|
if (!spawner.enabled)
|
||||||
|
return;
|
||||||
|
|
||||||
|
console.log("cooldown", spawner.cooldown);
|
||||||
|
if (spawner.cooldown == -1){
|
||||||
|
spawner.cooldown = Math.random() * 60;
|
||||||
|
spawner.cooldown /= 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
spawner.cooldown -= es.Time.deltaTime;
|
||||||
|
if (spawner.cooldown <= 0){
|
||||||
|
spawner.cooldown = Math.random() * 60;
|
||||||
|
// CreateEnemy
|
||||||
|
spawner.numSpawned ++;
|
||||||
|
spawner.numAlive ++;
|
||||||
|
|
||||||
|
if (spawner.numAlive > 0)
|
||||||
|
spawner.enabled = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2,6 +2,7 @@
|
|||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"target": "es5",
|
"target": "es5",
|
||||||
"outDir": "bin-debug",
|
"outDir": "bin-debug",
|
||||||
|
"sourceMap": true,
|
||||||
"experimentalDecorators": true,
|
"experimentalDecorators": true,
|
||||||
"emitDecoratorMetadata": true,
|
"emitDecoratorMetadata": true,
|
||||||
"lib": [
|
"lib": [
|
||||||
|
|||||||
Vendored
+1479
-1134
File diff suppressed because it is too large
Load Diff
+6762
-5364
File diff suppressed because it is too large
Load Diff
Vendored
+1
-1
File diff suppressed because one or more lines are too long
Vendored
+122
@@ -1008,7 +1008,129 @@ declare class Video {
|
|||||||
*/
|
*/
|
||||||
exitFullScreen(): Promise<void>;
|
exitFullScreen(): Promise<void>;
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* 相机对象
|
||||||
|
*/
|
||||||
|
declare class Camera {
|
||||||
|
/**
|
||||||
|
* 相机的左上角横坐标
|
||||||
|
*/
|
||||||
|
x: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 相机的左上角纵坐标
|
||||||
|
*/
|
||||||
|
y: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 相机的宽度
|
||||||
|
*/
|
||||||
|
width: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 相机的高度
|
||||||
|
*/
|
||||||
|
height: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 摄像头朝向
|
||||||
|
*/
|
||||||
|
devicePosition: "front" | "back";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 闪光灯状态
|
||||||
|
*/
|
||||||
|
flash: "auto" | "on" | "off";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 帧数据图像尺寸
|
||||||
|
*/
|
||||||
|
size: "small" | "medium" | "large";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 拍照,可指定质量,成功则返回图片
|
||||||
|
* @param quality 图片质量
|
||||||
|
*/
|
||||||
|
takePhoto(quality?: "high" | "normal" | "low"): Promise<{
|
||||||
|
/**
|
||||||
|
* 临时图片路径
|
||||||
|
*/
|
||||||
|
tempImagePath: string,
|
||||||
|
/**
|
||||||
|
* 图片宽度
|
||||||
|
*/
|
||||||
|
width: string,
|
||||||
|
/**
|
||||||
|
* 图片高度
|
||||||
|
*/
|
||||||
|
height: string
|
||||||
|
}>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 开始录像
|
||||||
|
*/
|
||||||
|
startRecord(): Promise<void>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 结束录像,成功则返回封面与视频
|
||||||
|
* @param compressed 是否压缩录制视频
|
||||||
|
*/
|
||||||
|
stopRecord(compressed: boolean): Promise<{
|
||||||
|
/**
|
||||||
|
* 临时视频路径
|
||||||
|
*/
|
||||||
|
tempThumbPath: string,
|
||||||
|
/**
|
||||||
|
* 临时封面路径
|
||||||
|
*/
|
||||||
|
tempVideoPath: string
|
||||||
|
}>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 监听用户不允许授权使用摄像头的情况
|
||||||
|
* @param callback 回调函数
|
||||||
|
*/
|
||||||
|
onAuthCancel(callback: () => void): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 监听摄像头非正常终止事件,如退出后台等情况
|
||||||
|
* @param callback 回调函数
|
||||||
|
*/
|
||||||
|
onStop(callback: () => void): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 监听摄像头实时帧数据
|
||||||
|
*/
|
||||||
|
onCameraFrame(callback: (res: {
|
||||||
|
/**
|
||||||
|
* 图像数据矩形的宽度
|
||||||
|
*/
|
||||||
|
width: number,
|
||||||
|
/**
|
||||||
|
* 图像数据矩形的高度
|
||||||
|
*/
|
||||||
|
height: number,
|
||||||
|
/**
|
||||||
|
* 图像像素点数据,一维数组,每四项表示一个像素点的 rgba
|
||||||
|
*/
|
||||||
|
data: ArrayBuffer
|
||||||
|
}) => void): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 开启监听帧数据
|
||||||
|
*/
|
||||||
|
listenFrameChange(): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 关闭监听帧数据
|
||||||
|
*/
|
||||||
|
closeFrameChange(): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 销毁相机
|
||||||
|
*/
|
||||||
|
destroy(): void;
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* banner 广告组件。banner 广告组件是一个原生组件,层级比上屏 Canvas 高,会覆盖在上屏 Canvas 上。banner 广告组件默认是隐藏的,需要调用 BannerAd.show() 将其显示。banner 广告会根据开发者设置的宽度进行等比缩放,缩放后的尺寸将通过 BannerAd.onResize() 事件中提供。
|
* banner 广告组件。banner 广告组件是一个原生组件,层级比上屏 Canvas 高,会覆盖在上屏 Canvas 上。banner 广告组件默认是隐藏的,需要调用 BannerAd.show() 将其显示。banner 广告会根据开发者设置的宽度进行等比缩放,缩放后的尺寸将通过 BannerAd.onResize() 事件中提供。
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -1,101 +1,103 @@
|
|||||||
///<reference path="./PriorityQueueNode.ts" />
|
///<reference path="./PriorityQueueNode.ts" />
|
||||||
/**
|
module es {
|
||||||
* 计算路径给定的IAstarGraph和开始/目标位置
|
|
||||||
*/
|
|
||||||
class AStarPathfinder {
|
|
||||||
/**
|
/**
|
||||||
* 尽可能从开始到目标找到一条路径。如果没有找到路径,则返回null。
|
* 计算路径给定的IAstarGraph和开始/目标位置
|
||||||
* @param graph
|
|
||||||
* @param start
|
|
||||||
* @param goal
|
|
||||||
*/
|
*/
|
||||||
public static search<T>(graph: IAstarGraph<T>, start: T, goal: T){
|
export class AStarPathfinder {
|
||||||
let foundPath = false;
|
/**
|
||||||
let cameFrom = new Map<T, T>();
|
* 尽可能从开始到目标找到一条路径。如果没有找到路径,则返回null。
|
||||||
cameFrom.set(start, start);
|
* @param graph
|
||||||
|
* @param start
|
||||||
|
* @param goal
|
||||||
|
*/
|
||||||
|
public static search<T>(graph: IAstarGraph<T>, start: T, goal: T){
|
||||||
|
let foundPath = false;
|
||||||
|
let cameFrom = new Map<T, T>();
|
||||||
|
cameFrom.set(start, start);
|
||||||
|
|
||||||
let costSoFar = new Map<T, number>();
|
let costSoFar = new Map<T, number>();
|
||||||
let frontier = new PriorityQueue<AStarNode<T>>(1000);
|
let frontier = new PriorityQueue<AStarNode<T>>(1000);
|
||||||
frontier.enqueue(new AStarNode<T>(start), 0);
|
frontier.enqueue(new AStarNode<T>(start), 0);
|
||||||
|
|
||||||
costSoFar.set(start, 0);
|
costSoFar.set(start, 0);
|
||||||
|
|
||||||
while (frontier.count > 0){
|
while (frontier.count > 0){
|
||||||
let current = frontier.dequeue();
|
let current = frontier.dequeue();
|
||||||
|
|
||||||
if (JSON.stringify(current.data) == JSON.stringify(goal)){
|
if (JSON.stringify(current.data) == JSON.stringify(goal)){
|
||||||
foundPath = true;
|
foundPath = true;
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
graph.getNeighbors(current.data).forEach(next => {
|
||||||
|
let newCost = costSoFar.get(current.data) + graph.cost(current.data, next);
|
||||||
|
if (!this.hasKey(costSoFar, next) || newCost < costSoFar.get(next)){
|
||||||
|
costSoFar.set(next, newCost);
|
||||||
|
let priority = newCost + graph.heuristic(next, goal);
|
||||||
|
frontier.enqueue(new AStarNode<T>(next), priority);
|
||||||
|
cameFrom.set(next, current.data);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
graph.getNeighbors(current.data).forEach(next => {
|
return foundPath ? this.recontructPath(cameFrom, start, goal) : null;
|
||||||
let newCost = costSoFar.get(current.data) + graph.cost(current.data, next);
|
|
||||||
if (!this.hasKey(costSoFar, next) || newCost < costSoFar.get(next)){
|
|
||||||
costSoFar.set(next, newCost);
|
|
||||||
let priority = newCost + graph.heuristic(next, goal);
|
|
||||||
frontier.enqueue(new AStarNode<T>(next), priority);
|
|
||||||
cameFrom.set(next, current.data);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return foundPath ? this.recontructPath(cameFrom, start, goal) : null;
|
private static hasKey<T>(map: Map<T, number>, compareKey: T){
|
||||||
}
|
let iterator = map.keys();
|
||||||
|
let r: IteratorResult<T>;
|
||||||
|
while (r = iterator.next() , !r.done) {
|
||||||
|
if (JSON.stringify(r.value) == JSON.stringify(compareKey))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
private static hasKey<T>(map: Map<T, number>, compareKey: T){
|
return false;
|
||||||
let iterator = map.keys();
|
|
||||||
let r: IteratorResult<T>;
|
|
||||||
while (r = iterator.next() , !r.done) {
|
|
||||||
if (JSON.stringify(r.value) == JSON.stringify(compareKey))
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
private static getKey<T>(map: Map<T, T>, compareKey: T){
|
||||||
}
|
let iterator = map.keys();
|
||||||
|
let valueIterator = map.values();
|
||||||
|
let r: IteratorResult<T>;
|
||||||
|
let v: IteratorResult<T>;
|
||||||
|
while (r = iterator.next(), v = valueIterator.next(), !r.done) {
|
||||||
|
if (JSON.stringify(r.value) == JSON.stringify(compareKey))
|
||||||
|
return v.value;
|
||||||
|
}
|
||||||
|
|
||||||
private static getKey<T>(map: Map<T, T>, compareKey: T){
|
return null;
|
||||||
let iterator = map.keys();
|
|
||||||
let valueIterator = map.values();
|
|
||||||
let r: IteratorResult<T>;
|
|
||||||
let v: IteratorResult<T>;
|
|
||||||
while (r = iterator.next(), v = valueIterator.next(), !r.done) {
|
|
||||||
if (JSON.stringify(r.value) == JSON.stringify(compareKey))
|
|
||||||
return v.value;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
/**
|
||||||
|
* 从cameFrom字典重新构造路径
|
||||||
|
* @param cameFrom
|
||||||
|
* @param start
|
||||||
|
* @param goal
|
||||||
|
*/
|
||||||
|
public static recontructPath<T>(cameFrom: Map<T, T>, start: T, goal: T): T[]{
|
||||||
|
let path = [];
|
||||||
|
let current = goal;
|
||||||
|
path.push(goal);
|
||||||
|
|
||||||
|
while (current != start){
|
||||||
|
current = this.getKey(cameFrom, current);
|
||||||
|
path.push(current);
|
||||||
|
}
|
||||||
|
|
||||||
|
path.reverse();
|
||||||
|
|
||||||
|
return path;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 从cameFrom字典重新构造路径
|
* 使用PriorityQueue需要的额外字段将原始数据封装在一个小类中
|
||||||
* @param cameFrom
|
|
||||||
* @param start
|
|
||||||
* @param goal
|
|
||||||
*/
|
*/
|
||||||
public static recontructPath<T>(cameFrom: Map<T, T>, start: T, goal: T): T[]{
|
export class AStarNode<T> extends PriorityQueueNode {
|
||||||
let path = [];
|
public data: T;
|
||||||
let current = goal;
|
|
||||||
path.push(goal);
|
|
||||||
|
|
||||||
while (current != start){
|
constructor(data: T){
|
||||||
current = this.getKey(cameFrom, current);
|
super();
|
||||||
path.push(current);
|
this.data = data;
|
||||||
}
|
}
|
||||||
|
|
||||||
path.reverse();
|
|
||||||
|
|
||||||
return path;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 使用PriorityQueue需要的额外字段将原始数据封装在一个小类中
|
|
||||||
*/
|
|
||||||
class AStarNode<T> extends PriorityQueueNode {
|
|
||||||
public data: T;
|
|
||||||
|
|
||||||
constructor(data: T){
|
|
||||||
super();
|
|
||||||
this.data = data;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,72 +1,74 @@
|
|||||||
/**
|
module es {
|
||||||
* 基本静态网格图与A*一起使用
|
|
||||||
* 将walls添加到walls HashSet,并将加权节点添加到weightedNodes
|
|
||||||
*/
|
|
||||||
class AstarGridGraph implements IAstarGraph<Vector2> {
|
|
||||||
public dirs: Vector2[] = [
|
|
||||||
new Vector2(1, 0),
|
|
||||||
new Vector2(0, -1),
|
|
||||||
new Vector2(-1, 0),
|
|
||||||
new Vector2(0, 1)
|
|
||||||
];
|
|
||||||
|
|
||||||
public walls: Vector2[] = [];
|
|
||||||
public weightedNodes: Vector2[] = [];
|
|
||||||
public defaultWeight: number = 1;
|
|
||||||
public weightedNodeWeight = 5;
|
|
||||||
|
|
||||||
private _width;
|
|
||||||
private _height;
|
|
||||||
private _neighbors: Vector2[] = new Array(4);
|
|
||||||
|
|
||||||
constructor(width: number, height: number){
|
|
||||||
this._width = width;
|
|
||||||
this._height = height;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 确保节点在网格图的边界内
|
* 基本静态网格图与A*一起使用
|
||||||
* @param node
|
* 将walls添加到walls HashSet,并将加权节点添加到weightedNodes
|
||||||
*/
|
*/
|
||||||
public isNodeInBounds(node: Vector2): boolean {
|
export class AstarGridGraph implements IAstarGraph<Vector2> {
|
||||||
return 0 <= node.x && node.x < this._width && 0 <= node.y && node.y < this._height;
|
public dirs: Vector2[] = [
|
||||||
|
new Vector2(1, 0),
|
||||||
|
new Vector2(0, -1),
|
||||||
|
new Vector2(-1, 0),
|
||||||
|
new Vector2(0, 1)
|
||||||
|
];
|
||||||
|
|
||||||
|
public walls: Vector2[] = [];
|
||||||
|
public weightedNodes: Vector2[] = [];
|
||||||
|
public defaultWeight: number = 1;
|
||||||
|
public weightedNodeWeight = 5;
|
||||||
|
|
||||||
|
private _width;
|
||||||
|
private _height;
|
||||||
|
private _neighbors: Vector2[] = new Array(4);
|
||||||
|
|
||||||
|
constructor(width: number, height: number){
|
||||||
|
this._width = width;
|
||||||
|
this._height = height;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 确保节点在网格图的边界内
|
||||||
|
* @param node
|
||||||
|
*/
|
||||||
|
public isNodeInBounds(node: Vector2): boolean {
|
||||||
|
return 0 <= node.x && node.x < this._width && 0 <= node.y && node.y < this._height;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查节点是否可以通过。walls是不可逾越的。
|
||||||
|
* @param node
|
||||||
|
*/
|
||||||
|
public isNodePassable(node: Vector2): boolean {
|
||||||
|
return !this.walls.firstOrDefault(wall => JSON.stringify(wall) == JSON.stringify(node));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 调用AStarPathfinder.search的快捷方式
|
||||||
|
* @param start
|
||||||
|
* @param goal
|
||||||
|
*/
|
||||||
|
public search(start: Vector2, goal: Vector2){
|
||||||
|
return AStarPathfinder.search(this, start, goal);
|
||||||
|
}
|
||||||
|
|
||||||
|
public getNeighbors(node: Vector2): Vector2[] {
|
||||||
|
this._neighbors.length = 0;
|
||||||
|
|
||||||
|
this.dirs.forEach(dir => {
|
||||||
|
let next = new Vector2(node.x + dir.x, node.y + dir.y);
|
||||||
|
if (this.isNodeInBounds(next) && this.isNodePassable(next))
|
||||||
|
this._neighbors.push(next);
|
||||||
|
});
|
||||||
|
|
||||||
|
return this._neighbors;
|
||||||
|
}
|
||||||
|
|
||||||
|
public cost(from: Vector2, to: Vector2): number {
|
||||||
|
return this.weightedNodes.find((p)=> JSON.stringify(p) == JSON.stringify(to)) ? this.weightedNodeWeight : this.defaultWeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
public heuristic(node: Vector2, goal: Vector2) {
|
||||||
|
return Math.abs(node.x - goal.x) + Math.abs(node.y - goal.y);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 检查节点是否可以通过。walls是不可逾越的。
|
|
||||||
* @param node
|
|
||||||
*/
|
|
||||||
public isNodePassable(node: Vector2): boolean {
|
|
||||||
return !this.walls.firstOrDefault(wall => JSON.stringify(wall) == JSON.stringify(node));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 调用AStarPathfinder.search的快捷方式
|
|
||||||
* @param start
|
|
||||||
* @param goal
|
|
||||||
*/
|
|
||||||
public search(start: Vector2, goal: Vector2){
|
|
||||||
return AStarPathfinder.search(this, start, goal);
|
|
||||||
}
|
|
||||||
|
|
||||||
public getNeighbors(node: Vector2): Vector2[] {
|
|
||||||
this._neighbors.length = 0;
|
|
||||||
|
|
||||||
this.dirs.forEach(dir => {
|
|
||||||
let next = new Vector2(node.x + dir.x, node.y + dir.y);
|
|
||||||
if (this.isNodeInBounds(next) && this.isNodePassable(next))
|
|
||||||
this._neighbors.push(next);
|
|
||||||
});
|
|
||||||
|
|
||||||
return this._neighbors;
|
|
||||||
}
|
|
||||||
|
|
||||||
public cost(from: Vector2, to: Vector2): number {
|
|
||||||
return this.weightedNodes.find((p)=> JSON.stringify(p) == JSON.stringify(to)) ? this.weightedNodeWeight : this.defaultWeight;
|
|
||||||
}
|
|
||||||
|
|
||||||
public heuristic(node: Vector2, goal: Vector2) {
|
|
||||||
return Math.abs(node.x - goal.x) + Math.abs(node.y - goal.y);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1,22 +1,24 @@
|
|||||||
/**
|
module es {
|
||||||
* graph的接口,可以提供给AstarPathfinder.search方法
|
|
||||||
*/
|
|
||||||
interface IAstarGraph<T> {
|
|
||||||
/**
|
/**
|
||||||
* getNeighbors方法应该返回从传入的节点可以到达的任何相邻节点
|
* graph的接口,可以提供给AstarPathfinder.search方法
|
||||||
* @param node
|
|
||||||
*/
|
*/
|
||||||
getNeighbors(node: T): Array<T>;
|
export interface IAstarGraph<T> {
|
||||||
/**
|
/**
|
||||||
* 计算从从from到to的成本
|
* getNeighbors方法应该返回从传入的节点可以到达的任何相邻节点
|
||||||
* @param from
|
* @param node
|
||||||
* @param to
|
*/
|
||||||
*/
|
getNeighbors(node: T): Array<T>;
|
||||||
cost(from: T, to: T): number;
|
/**
|
||||||
/**
|
* 计算从从from到to的成本
|
||||||
* 计算从node到to的启发式。参见WeightedGridGraph了解常用的Manhatten方法。
|
* @param from
|
||||||
* @param node
|
* @param to
|
||||||
* @param goal
|
*/
|
||||||
*/
|
cost(from: T, to: T): number;
|
||||||
heuristic(node: T, goal: T);
|
/**
|
||||||
|
* 计算从node到to的启发式。参见WeightedGridGraph了解常用的Manhatten方法。
|
||||||
|
* @param node
|
||||||
|
* @param goal
|
||||||
|
*/
|
||||||
|
heuristic(node: T, goal: T);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,234 +1,236 @@
|
|||||||
/**
|
module es {
|
||||||
* 使用堆实现最小优先级队列 O(1)复杂度
|
|
||||||
* 这种查找速度比使用字典快5-10倍
|
|
||||||
* 但是,由于IPriorityQueue.contains()是许多寻路算法中调用最多的方法,因此尽可能快地实现它对于我们的应用程序非常重要。
|
|
||||||
*/
|
|
||||||
class PriorityQueue<T extends PriorityQueueNode> {
|
|
||||||
private _numNodes: number;
|
|
||||||
private _nodes: T[];
|
|
||||||
private _numNodesEverEnqueued;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 实例化一个新的优先级队列
|
* 使用堆实现最小优先级队列 O(1)复杂度
|
||||||
* @param maxNodes 允许加入队列的最大节点(执行此操作将导致undefined的行为)
|
* 这种查找速度比使用字典快5-10倍
|
||||||
|
* 但是,由于IPriorityQueue.contains()是许多寻路算法中调用最多的方法,因此尽可能快地实现它对于我们的应用程序非常重要。
|
||||||
*/
|
*/
|
||||||
constructor(maxNodes: number) {
|
export class PriorityQueue<T extends PriorityQueueNode> {
|
||||||
this._numNodes = 0;
|
private _numNodes: number;
|
||||||
this._nodes = new Array(maxNodes + 1);
|
private _nodes: T[];
|
||||||
this._numNodesEverEnqueued = 0;
|
private _numNodesEverEnqueued;
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 从队列中删除每个节点。
|
* 实例化一个新的优先级队列
|
||||||
* O(n)复杂度 所有尽可能少调用该方法
|
* @param maxNodes 允许加入队列的最大节点(执行此操作将导致undefined的行为)
|
||||||
*/
|
*/
|
||||||
public clear() {
|
constructor(maxNodes: number) {
|
||||||
this._nodes.splice(1, this._numNodes);
|
this._numNodes = 0;
|
||||||
this._numNodes = 0;
|
this._nodes = new Array(maxNodes + 1);
|
||||||
}
|
this._numNodesEverEnqueued = 0;
|
||||||
|
|
||||||
/**
|
|
||||||
* 返回队列中的节点数。
|
|
||||||
* O(1)复杂度
|
|
||||||
*/
|
|
||||||
public get count() {
|
|
||||||
return this._numNodes;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 返回可同时进入此队列的最大项数。一旦你达到这个数字(即。一旦Count == MaxSize),尝试加入另一个项目将导致undefined的行为
|
|
||||||
* O(1)复杂度
|
|
||||||
*/
|
|
||||||
public get maxSize() {
|
|
||||||
return this._nodes.length - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 返回(在O(1)中)给定节点是否在队列中
|
|
||||||
* O (1)复杂度
|
|
||||||
* @param node
|
|
||||||
*/
|
|
||||||
public contains(node: T): boolean {
|
|
||||||
if (!node){
|
|
||||||
console.error("node cannot be null");
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (node.queueIndex < 0 || node.queueIndex >= this._nodes.length){
|
/**
|
||||||
console.error("node.QueueIndex has been corrupted. Did you change it manually? Or add this node to another queue?");
|
* 从队列中删除每个节点。
|
||||||
return false;
|
* O(n)复杂度 所有尽可能少调用该方法
|
||||||
|
*/
|
||||||
|
public clear() {
|
||||||
|
this._nodes.splice(1, this._numNodes);
|
||||||
|
this._numNodes = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (this._nodes[node.queueIndex] == node);
|
/**
|
||||||
}
|
* 返回队列中的节点数。
|
||||||
|
* O(1)复杂度
|
||||||
|
*/
|
||||||
|
public get count() {
|
||||||
|
return this._numNodes;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 将节点放入优先队列 较低的值放在前面 先入先出
|
* 返回可同时进入此队列的最大项数。一旦你达到这个数字(即。一旦Count == MaxSize),尝试加入另一个项目将导致undefined的行为
|
||||||
* 如果队列已满,则结果undefined。如果节点已经加入队列,则结果undefined。
|
* O(1)复杂度
|
||||||
* O(log n)
|
*/
|
||||||
* @param node
|
public get maxSize() {
|
||||||
* @param priority
|
return this._nodes.length - 1;
|
||||||
*/
|
}
|
||||||
public enqueue(node: T, priority: number) {
|
|
||||||
node.priority = priority;
|
|
||||||
this._numNodes++;
|
|
||||||
this._nodes[this._numNodes] = node;
|
|
||||||
node.queueIndex = this._numNodes;
|
|
||||||
node.insertionIndex = this._numNodesEverEnqueued++;
|
|
||||||
this.cascadeUp(this._nodes[this._numNodes]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 删除队列头(具有最小优先级的节点;按插入顺序断开连接),并返回它。如果队列为空,结果undefined
|
* 返回(在O(1)中)给定节点是否在队列中
|
||||||
* O(log n)
|
* O (1)复杂度
|
||||||
*/
|
* @param node
|
||||||
public dequeue(): T {
|
*/
|
||||||
let returnMe = this._nodes[1];
|
public contains(node: T): boolean {
|
||||||
this.remove(returnMe);
|
if (!node){
|
||||||
return returnMe;
|
console.error("node cannot be null");
|
||||||
}
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
if (node.queueIndex < 0 || node.queueIndex >= this._nodes.length){
|
||||||
* 从队列中删除一个节点。节点不需要是队列的头。如果节点不在队列中,则结果未定义。如果不确定,首先检查Contains()
|
console.error("node.QueueIndex has been corrupted. Did you change it manually? Or add this node to another queue?");
|
||||||
* O(log n)
|
return false;
|
||||||
* @param node
|
}
|
||||||
*/
|
|
||||||
public remove(node: T) {
|
return (this._nodes[node.queueIndex] == node);
|
||||||
if (node.queueIndex == this._numNodes) {
|
}
|
||||||
this._nodes[this._numNodes] = null;
|
|
||||||
|
/**
|
||||||
|
* 将节点放入优先队列 较低的值放在前面 先入先出
|
||||||
|
* 如果队列已满,则结果undefined。如果节点已经加入队列,则结果undefined。
|
||||||
|
* O(log n)
|
||||||
|
* @param node
|
||||||
|
* @param priority
|
||||||
|
*/
|
||||||
|
public enqueue(node: T, priority: number) {
|
||||||
|
node.priority = priority;
|
||||||
|
this._numNodes++;
|
||||||
|
this._nodes[this._numNodes] = node;
|
||||||
|
node.queueIndex = this._numNodes;
|
||||||
|
node.insertionIndex = this._numNodesEverEnqueued++;
|
||||||
|
this.cascadeUp(this._nodes[this._numNodes]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除队列头(具有最小优先级的节点;按插入顺序断开连接),并返回它。如果队列为空,结果undefined
|
||||||
|
* O(log n)
|
||||||
|
*/
|
||||||
|
public dequeue(): T {
|
||||||
|
let returnMe = this._nodes[1];
|
||||||
|
this.remove(returnMe);
|
||||||
|
return returnMe;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从队列中删除一个节点。节点不需要是队列的头。如果节点不在队列中,则结果未定义。如果不确定,首先检查Contains()
|
||||||
|
* O(log n)
|
||||||
|
* @param node
|
||||||
|
*/
|
||||||
|
public remove(node: T) {
|
||||||
|
if (node.queueIndex == this._numNodes) {
|
||||||
|
this._nodes[this._numNodes] = null;
|
||||||
|
this._numNodes--;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let formerLastNode = this._nodes[this._numNodes];
|
||||||
|
this.swap(node, formerLastNode);
|
||||||
|
delete this._nodes[this._numNodes];
|
||||||
this._numNodes--;
|
this._numNodes--;
|
||||||
return;
|
|
||||||
|
this.onNodeUpdated(formerLastNode);
|
||||||
}
|
}
|
||||||
|
|
||||||
let formerLastNode = this._nodes[this._numNodes];
|
/**
|
||||||
this.swap(node, formerLastNode);
|
* 检查以确保队列仍然处于有效状态。用于测试/调试队列。
|
||||||
delete this._nodes[this._numNodes];
|
*/
|
||||||
this._numNodes--;
|
public isValidQueue(): boolean {
|
||||||
|
for (let i = 1; i < this._nodes.length; i++) {
|
||||||
|
if (this._nodes[i]) {
|
||||||
|
let childLeftIndex = 2 * i;
|
||||||
|
if (childLeftIndex < this._nodes.length && this._nodes[childLeftIndex] &&
|
||||||
|
this.hasHigherPriority(this._nodes[childLeftIndex], this._nodes[i]))
|
||||||
|
return false;
|
||||||
|
|
||||||
this.onNodeUpdated(formerLastNode);
|
let childRightIndex = childLeftIndex + 1;
|
||||||
}
|
if (childRightIndex < this._nodes.length && this._nodes[childRightIndex] &&
|
||||||
|
this.hasHigherPriority(this._nodes[childRightIndex], this._nodes[i]))
|
||||||
/**
|
return false;
|
||||||
* 检查以确保队列仍然处于有效状态。用于测试/调试队列。
|
|
||||||
*/
|
|
||||||
public isValidQueue(): boolean {
|
|
||||||
for (let i = 1; i < this._nodes.length; i++) {
|
|
||||||
if (this._nodes[i]) {
|
|
||||||
let childLeftIndex = 2 * i;
|
|
||||||
if (childLeftIndex < this._nodes.length && this._nodes[childLeftIndex] &&
|
|
||||||
this.hasHigherPriority(this._nodes[childLeftIndex], this._nodes[i]))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
let childRightIndex = childLeftIndex + 1;
|
|
||||||
if (childRightIndex < this._nodes.length && this._nodes[childRightIndex] &&
|
|
||||||
this.hasHigherPriority(this._nodes[childRightIndex], this._nodes[i]))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private onNodeUpdated(node: T) {
|
|
||||||
// 将更新后的节点按适当的方式向上或向下冒泡
|
|
||||||
let parentIndex = Math.floor(node.queueIndex / 2);
|
|
||||||
let parentNode = this._nodes[parentIndex];
|
|
||||||
|
|
||||||
if (parentIndex > 0 && this.hasHigherPriority(node, parentNode)) {
|
|
||||||
this.cascadeUp(node);
|
|
||||||
} else {
|
|
||||||
// 注意,如果parentNode == node(即节点是根),则将调用CascadeDown。
|
|
||||||
this.cascadeDown(node);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private cascadeDown(node: T) {
|
|
||||||
// 又名Heapify-down
|
|
||||||
let newParent: T;
|
|
||||||
let finalQueueIndex = node.queueIndex;
|
|
||||||
while (true) {
|
|
||||||
newParent = node;
|
|
||||||
let childLeftIndex = 2 * finalQueueIndex;
|
|
||||||
|
|
||||||
// 检查左子节点的优先级是否高于当前节点
|
|
||||||
if (childLeftIndex > this._numNodes) {
|
|
||||||
// 这可以放在循环之外,但是我们必须检查newParent != node两次
|
|
||||||
node.queueIndex = finalQueueIndex;
|
|
||||||
this._nodes[finalQueueIndex] = node;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
let childLeft = this._nodes[childLeftIndex];
|
|
||||||
if (this.hasHigherPriority(childLeft, newParent)) {
|
|
||||||
newParent = childLeft;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 检查右子节点的优先级是否高于当前节点或左子节点
|
|
||||||
let childRightIndex = childLeftIndex + 1;
|
|
||||||
if (childRightIndex <= this._numNodes) {
|
|
||||||
let childRight = this._nodes[childRightIndex];
|
|
||||||
if (this.hasHigherPriority(childRight, newParent)) {
|
|
||||||
newParent = childRight;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 如果其中一个子节点具有更高(更小)的优先级,则交换并继续级联
|
return true;
|
||||||
if (newParent != node) {
|
}
|
||||||
// 将新的父节点移动到它的新索引
|
|
||||||
// 节点将被移动一次,这样做比调用Swap()少一个赋值操作。
|
|
||||||
this._nodes[finalQueueIndex] = newParent;
|
|
||||||
|
|
||||||
let temp = newParent.queueIndex;
|
private onNodeUpdated(node: T) {
|
||||||
newParent.queueIndex = finalQueueIndex;
|
// 将更新后的节点按适当的方式向上或向下冒泡
|
||||||
finalQueueIndex = temp;
|
let parentIndex = Math.floor(node.queueIndex / 2);
|
||||||
|
let parentNode = this._nodes[parentIndex];
|
||||||
|
|
||||||
|
if (parentIndex > 0 && this.hasHigherPriority(node, parentNode)) {
|
||||||
|
this.cascadeUp(node);
|
||||||
} else {
|
} else {
|
||||||
// 参见上面的笔记
|
// 注意,如果parentNode == node(即节点是根),则将调用CascadeDown。
|
||||||
node.queueIndex = finalQueueIndex;
|
this.cascadeDown(node);
|
||||||
this._nodes[finalQueueIndex] = node;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
private cascadeDown(node: T) {
|
||||||
* 当没有内联时,性能会稍微好一些
|
// 又名Heapify-down
|
||||||
* @param node
|
let newParent: T;
|
||||||
*/
|
let finalQueueIndex = node.queueIndex;
|
||||||
private cascadeUp(node: T) {
|
while (true) {
|
||||||
// 又名Heapify-up
|
newParent = node;
|
||||||
let parent = Math.floor(node.queueIndex / 2);
|
let childLeftIndex = 2 * finalQueueIndex;
|
||||||
while (parent >= 1) {
|
|
||||||
let parentNode = this._nodes[parent];
|
|
||||||
if (this.hasHigherPriority(parentNode, node))
|
|
||||||
break;
|
|
||||||
|
|
||||||
// 节点具有较低的优先级值,因此将其向上移动到堆中
|
// 检查左子节点的优先级是否高于当前节点
|
||||||
// 出于某种原因,使用Swap()比使用单独的操作更快,如CascadeDown()
|
if (childLeftIndex > this._numNodes) {
|
||||||
this.swap(node, parentNode);
|
// 这可以放在循环之外,但是我们必须检查newParent != node两次
|
||||||
|
node.queueIndex = finalQueueIndex;
|
||||||
|
this._nodes[finalQueueIndex] = node;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
parent = Math.floor(node.queueIndex / 2);
|
let childLeft = this._nodes[childLeftIndex];
|
||||||
|
if (this.hasHigherPriority(childLeft, newParent)) {
|
||||||
|
newParent = childLeft;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查右子节点的优先级是否高于当前节点或左子节点
|
||||||
|
let childRightIndex = childLeftIndex + 1;
|
||||||
|
if (childRightIndex <= this._numNodes) {
|
||||||
|
let childRight = this._nodes[childRightIndex];
|
||||||
|
if (this.hasHigherPriority(childRight, newParent)) {
|
||||||
|
newParent = childRight;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果其中一个子节点具有更高(更小)的优先级,则交换并继续级联
|
||||||
|
if (newParent != node) {
|
||||||
|
// 将新的父节点移动到它的新索引
|
||||||
|
// 节点将被移动一次,这样做比调用Swap()少一个赋值操作。
|
||||||
|
this._nodes[finalQueueIndex] = newParent;
|
||||||
|
|
||||||
|
let temp = newParent.queueIndex;
|
||||||
|
newParent.queueIndex = finalQueueIndex;
|
||||||
|
finalQueueIndex = temp;
|
||||||
|
} else {
|
||||||
|
// 参见上面的笔记
|
||||||
|
node.queueIndex = finalQueueIndex;
|
||||||
|
this._nodes[finalQueueIndex] = node;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 当没有内联时,性能会稍微好一些
|
||||||
|
* @param node
|
||||||
|
*/
|
||||||
|
private cascadeUp(node: T) {
|
||||||
|
// 又名Heapify-up
|
||||||
|
let parent = Math.floor(node.queueIndex / 2);
|
||||||
|
while (parent >= 1) {
|
||||||
|
let parentNode = this._nodes[parent];
|
||||||
|
if (this.hasHigherPriority(parentNode, node))
|
||||||
|
break;
|
||||||
|
|
||||||
|
// 节点具有较低的优先级值,因此将其向上移动到堆中
|
||||||
|
// 出于某种原因,使用Swap()比使用单独的操作更快,如CascadeDown()
|
||||||
|
this.swap(node, parentNode);
|
||||||
|
|
||||||
|
parent = Math.floor(node.queueIndex / 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private swap(node1: T, node2: T) {
|
||||||
|
// 交换节点
|
||||||
|
this._nodes[node1.queueIndex] = node2;
|
||||||
|
this._nodes[node2.queueIndex] = node1;
|
||||||
|
|
||||||
|
// 交换他们的indicies
|
||||||
|
let temp = node1.queueIndex;
|
||||||
|
node1.queueIndex = node2.queueIndex;
|
||||||
|
node2.queueIndex = temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 如果higher的优先级高于lower,则返回true,否则返回false。
|
||||||
|
* 注意,调用HasHigherPriority(节点,节点)(即。两个参数为同一个节点)将返回false
|
||||||
|
* @param higher
|
||||||
|
* @param lower
|
||||||
|
*/
|
||||||
|
private hasHigherPriority(higher: T, lower: T) {
|
||||||
|
return (higher.priority < lower.priority ||
|
||||||
|
(higher.priority == lower.priority && higher.insertionIndex < lower.insertionIndex));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private swap(node1: T, node2: T) {
|
|
||||||
// 交换节点
|
|
||||||
this._nodes[node1.queueIndex] = node2;
|
|
||||||
this._nodes[node2.queueIndex] = node1;
|
|
||||||
|
|
||||||
// 交换他们的indicies
|
|
||||||
let temp = node1.queueIndex;
|
|
||||||
node1.queueIndex = node2.queueIndex;
|
|
||||||
node2.queueIndex = temp;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 如果higher的优先级高于lower,则返回true,否则返回false。
|
|
||||||
* 注意,调用HasHigherPriority(节点,节点)(即。两个参数为同一个节点)将返回false
|
|
||||||
* @param higher
|
|
||||||
* @param lower
|
|
||||||
*/
|
|
||||||
private hasHigherPriority(higher: T, lower: T) {
|
|
||||||
return (higher.priority < lower.priority ||
|
|
||||||
(higher.priority == lower.priority && higher.insertionIndex < lower.insertionIndex));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -1,14 +1,16 @@
|
|||||||
class PriorityQueueNode {
|
module es {
|
||||||
/**
|
export class PriorityQueueNode {
|
||||||
* 插入此节点的优先级。在将节点添加到队列之前必须设置
|
/**
|
||||||
*/
|
* 插入此节点的优先级。在将节点添加到队列之前必须设置
|
||||||
public priority: number = 0;
|
*/
|
||||||
/**
|
public priority: number = 0;
|
||||||
* 由优先级队列使用-不要编辑此值。表示插入节点的顺序
|
/**
|
||||||
*/
|
* 由优先级队列使用-不要编辑此值。表示插入节点的顺序
|
||||||
public insertionIndex: number = 0;
|
*/
|
||||||
/**
|
public insertionIndex: number = 0;
|
||||||
* 由优先级队列使用-不要编辑此值。表示队列中的当前位置
|
/**
|
||||||
*/
|
* 由优先级队列使用-不要编辑此值。表示队列中的当前位置
|
||||||
public queueIndex: number = 0;
|
*/
|
||||||
|
public queueIndex: number = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,41 +1,43 @@
|
|||||||
/**
|
module es {
|
||||||
* 计算路径给定的IUnweightedGraph和开始/目标位置
|
/**
|
||||||
*/
|
* 计算路径给定的IUnweightedGraph和开始/目标位置
|
||||||
class BreadthFirstPathfinder {
|
*/
|
||||||
public static search<T>(graph: IUnweightedGraph<T>, start: T, goal: T): T[]{
|
export class BreadthFirstPathfinder {
|
||||||
let foundPath = false;
|
public static search<T>(graph: IUnweightedGraph<T>, start: T, goal: T): T[]{
|
||||||
let frontier = [];
|
let foundPath = false;
|
||||||
frontier.unshift(start);
|
let frontier = [];
|
||||||
|
frontier.unshift(start);
|
||||||
|
|
||||||
let cameFrom = new Map<T, T>();
|
let cameFrom = new Map<T, T>();
|
||||||
cameFrom.set(start, start);
|
cameFrom.set(start, start);
|
||||||
|
|
||||||
while (frontier.length > 0){
|
while (frontier.length > 0){
|
||||||
let current = frontier.shift();
|
let current = frontier.shift();
|
||||||
if (JSON.stringify(current) == JSON.stringify(goal)){
|
if (JSON.stringify(current) == JSON.stringify(goal)){
|
||||||
foundPath = true;
|
foundPath = true;
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
graph.getNeighbors(current).forEach(next => {
|
||||||
|
if (!this.hasKey(cameFrom, next)){
|
||||||
|
frontier.unshift(next);
|
||||||
|
cameFrom.set(next, current);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
graph.getNeighbors(current).forEach(next => {
|
return foundPath ? AStarPathfinder.recontructPath(cameFrom, start, goal) : null;
|
||||||
if (!this.hasKey(cameFrom, next)){
|
|
||||||
frontier.unshift(next);
|
|
||||||
cameFrom.set(next, current);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return foundPath ? AStarPathfinder.recontructPath(cameFrom, start, goal) : null;
|
private static hasKey<T>(map: Map<T, T>, compareKey: T){
|
||||||
}
|
let iterator = map.keys();
|
||||||
|
let r: IteratorResult<T>;
|
||||||
|
while (r = iterator.next() , !r.done) {
|
||||||
|
if (JSON.stringify(r.value) == JSON.stringify(compareKey))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
private static hasKey<T>(map: Map<T, T>, compareKey: T){
|
return false;
|
||||||
let iterator = map.keys();
|
|
||||||
let r: IteratorResult<T>;
|
|
||||||
while (r = iterator.next() , !r.done) {
|
|
||||||
if (JSON.stringify(r.value) == JSON.stringify(compareKey))
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,7 +1,9 @@
|
|||||||
interface IUnweightedGraph<T>{
|
module es {
|
||||||
/**
|
export interface IUnweightedGraph<T>{
|
||||||
* getNeighbors方法应该返回从传入的节点可以到达的任何相邻节点。
|
/**
|
||||||
* @param node
|
* getNeighbors方法应该返回从传入的节点可以到达的任何相邻节点。
|
||||||
*/
|
* @param node
|
||||||
getNeighbors(node: T): T[];
|
*/
|
||||||
|
getNeighbors(node: T): T[];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,16 +1,18 @@
|
|||||||
/**
|
module es {
|
||||||
* 一个未加权图的基本实现。所有的边都被缓存。这种类型的图最适合于非基于网格的图。
|
/**
|
||||||
* 作为边添加的任何节点都必须在边字典中有一个条目作为键。
|
* 一个未加权图的基本实现。所有的边都被缓存。这种类型的图最适合于非基于网格的图。
|
||||||
*/
|
* 作为边添加的任何节点都必须在边字典中有一个条目作为键。
|
||||||
class UnweightedGraph<T> implements IUnweightedGraph<T> {
|
*/
|
||||||
public edges: Map<T, T[]> = new Map<T, T[]>();
|
export class UnweightedGraph<T> implements IUnweightedGraph<T> {
|
||||||
|
public edges: Map<T, T[]> = new Map<T, T[]>();
|
||||||
|
|
||||||
public addEdgesForNode(node: T, edges: T[]){
|
public addEdgesForNode(node: T, edges: T[]){
|
||||||
this.edges.set(node, edges);
|
this.edges.set(node, edges);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public getNeighbors(node: T){
|
public getNeighbors(node: T){
|
||||||
return this.edges.get(node);
|
return this.edges.get(node);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,61 +1,63 @@
|
|||||||
///<reference path="../../../Math/Vector2.ts" />
|
///<reference path="../../../Math/Vector2.ts" />
|
||||||
/**
|
module es {
|
||||||
* 基本的未加权网格图形用于BreadthFirstPathfinder
|
/**
|
||||||
*/
|
* 基本的未加权网格图形用于BreadthFirstPathfinder
|
||||||
class UnweightedGridGraph implements IUnweightedGraph<Vector2> {
|
*/
|
||||||
private static readonly CARDINAL_DIRS: Vector2[] = [
|
export class UnweightedGridGraph implements IUnweightedGraph<Vector2> {
|
||||||
new Vector2(1, 0),
|
private static readonly CARDINAL_DIRS: Vector2[] = [
|
||||||
new Vector2(0, -1),
|
new Vector2(1, 0),
|
||||||
new Vector2(-1, 0),
|
new Vector2(0, -1),
|
||||||
new Vector2(0, -1)
|
new Vector2(-1, 0),
|
||||||
];
|
new Vector2(0, -1)
|
||||||
|
];
|
||||||
|
|
||||||
private static readonly COMPASS_DIRS = [
|
private static readonly COMPASS_DIRS = [
|
||||||
new Vector2(1, 0),
|
new Vector2(1, 0),
|
||||||
new Vector2(1, -1),
|
new Vector2(1, -1),
|
||||||
new Vector2(0, -1),
|
new Vector2(0, -1),
|
||||||
new Vector2(-1, -1),
|
new Vector2(-1, -1),
|
||||||
new Vector2(-1, 0),
|
new Vector2(-1, 0),
|
||||||
new Vector2(-1, 1),
|
new Vector2(-1, 1),
|
||||||
new Vector2(0, 1),
|
new Vector2(0, 1),
|
||||||
new Vector2(1, 1),
|
new Vector2(1, 1),
|
||||||
];
|
];
|
||||||
|
|
||||||
public walls: Vector2[] = [];
|
public walls: Vector2[] = [];
|
||||||
|
|
||||||
private _width: number;
|
private _width: number;
|
||||||
private _hegiht: number;
|
private _hegiht: number;
|
||||||
|
|
||||||
private _dirs: Vector2[];
|
private _dirs: Vector2[];
|
||||||
private _neighbors: Vector2[] = new Array(4);
|
private _neighbors: Vector2[] = new Array(4);
|
||||||
|
|
||||||
constructor(width: number, height: number, allowDiagonalSearch: boolean = false) {
|
constructor(width: number, height: number, allowDiagonalSearch: boolean = false) {
|
||||||
this._width = width;
|
this._width = width;
|
||||||
this._hegiht = height;
|
this._hegiht = height;
|
||||||
this._dirs = allowDiagonalSearch ? UnweightedGridGraph.COMPASS_DIRS : UnweightedGridGraph.CARDINAL_DIRS;
|
this._dirs = allowDiagonalSearch ? UnweightedGridGraph.COMPASS_DIRS : UnweightedGridGraph.CARDINAL_DIRS;
|
||||||
}
|
}
|
||||||
|
|
||||||
public isNodeInBounds(node: Vector2): boolean {
|
public isNodeInBounds(node: Vector2): boolean {
|
||||||
return 0 <= node.x && node.x < this._width && 0 <= node.y && node.y < this._hegiht;
|
return 0 <= node.x && node.x < this._width && 0 <= node.y && node.y < this._hegiht;
|
||||||
}
|
}
|
||||||
|
|
||||||
public isNodePassable(node: Vector2): boolean {
|
public isNodePassable(node: Vector2): boolean {
|
||||||
return !this.walls.firstOrDefault(wall => JSON.stringify(wall) == JSON.stringify(node));
|
return !this.walls.firstOrDefault(wall => JSON.stringify(wall) == JSON.stringify(node));
|
||||||
}
|
}
|
||||||
|
|
||||||
public getNeighbors(node: Vector2) {
|
public getNeighbors(node: Vector2) {
|
||||||
this._neighbors.length = 0;
|
this._neighbors.length = 0;
|
||||||
|
|
||||||
this._dirs.forEach(dir => {
|
this._dirs.forEach(dir => {
|
||||||
let next = new Vector2(node.x + dir.x, node.y + dir.y);
|
let next = new Vector2(node.x + dir.x, node.y + dir.y);
|
||||||
if (this.isNodeInBounds(next) && this.isNodePassable(next))
|
if (this.isNodeInBounds(next) && this.isNodePassable(next))
|
||||||
this._neighbors.push(next);
|
this._neighbors.push(next);
|
||||||
});
|
});
|
||||||
|
|
||||||
return this._neighbors;
|
return this._neighbors;
|
||||||
}
|
}
|
||||||
|
|
||||||
public search(start: Vector2, goal: Vector2): Vector2[] {
|
public search(start: Vector2, goal: Vector2): Vector2[] {
|
||||||
return BreadthFirstPathfinder.search(this, start, goal);
|
return BreadthFirstPathfinder.search(this, start, goal);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,14 +1,16 @@
|
|||||||
interface IWeightedGraph<T>{
|
module es {
|
||||||
/**
|
export interface IWeightedGraph<T>{
|
||||||
*
|
/**
|
||||||
* @param node
|
*
|
||||||
*/
|
* @param node
|
||||||
getNeighbors(node: T): T[];
|
*/
|
||||||
|
getNeighbors(node: T): T[];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param from
|
* @param from
|
||||||
* @param to
|
* @param to
|
||||||
*/
|
*/
|
||||||
cost(from: T, to: T): number;
|
cost(from: T, to: T): number;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,67 +1,69 @@
|
|||||||
///<reference path="../../../Math/Vector2.ts" />
|
///<reference path="../../../Math/Vector2.ts" />
|
||||||
/**
|
module es {
|
||||||
* 支持一种加权节点的基本网格图
|
/**
|
||||||
*/
|
* 支持一种加权节点的基本网格图
|
||||||
class WeightedGridGraph implements IWeightedGraph<Vector2> {
|
*/
|
||||||
public static readonly CARDINAL_DIRS = [
|
export class WeightedGridGraph implements IWeightedGraph<Vector2> {
|
||||||
new Vector2(1, 0),
|
public static readonly CARDINAL_DIRS = [
|
||||||
new Vector2(0, -1),
|
new Vector2(1, 0),
|
||||||
new Vector2(-1, 0),
|
new Vector2(0, -1),
|
||||||
new Vector2(0, 1)
|
new Vector2(-1, 0),
|
||||||
];
|
new Vector2(0, 1)
|
||||||
|
];
|
||||||
|
|
||||||
private static readonly COMPASS_DIRS = [
|
private static readonly COMPASS_DIRS = [
|
||||||
new Vector2(1, 0),
|
new Vector2(1, 0),
|
||||||
new Vector2(1, -1),
|
new Vector2(1, -1),
|
||||||
new Vector2(0, -1),
|
new Vector2(0, -1),
|
||||||
new Vector2(-1, -1),
|
new Vector2(-1, -1),
|
||||||
new Vector2(-1, 0),
|
new Vector2(-1, 0),
|
||||||
new Vector2(-1, 1),
|
new Vector2(-1, 1),
|
||||||
new Vector2(0, 1),
|
new Vector2(0, 1),
|
||||||
new Vector2(1, 1),
|
new Vector2(1, 1),
|
||||||
];
|
];
|
||||||
|
|
||||||
public walls: Vector2[] = [];
|
public walls: Vector2[] = [];
|
||||||
public weightedNodes: Vector2[] = [];
|
public weightedNodes: Vector2[] = [];
|
||||||
public defaultWeight = 1;
|
public defaultWeight = 1;
|
||||||
public weightedNodeWeight = 5;
|
public weightedNodeWeight = 5;
|
||||||
|
|
||||||
private _width: number;
|
private _width: number;
|
||||||
private _height: number;
|
private _height: number;
|
||||||
private _dirs: Vector2[];
|
private _dirs: Vector2[];
|
||||||
private _neighbors: Vector2[] = new Array(4);
|
private _neighbors: Vector2[] = new Array(4);
|
||||||
|
|
||||||
constructor(width: number, height: number, allowDiagonalSearch: boolean = false){
|
constructor(width: number, height: number, allowDiagonalSearch: boolean = false){
|
||||||
this._width = width;
|
this._width = width;
|
||||||
this._height = height;
|
this._height = height;
|
||||||
this._dirs = allowDiagonalSearch ? WeightedGridGraph.COMPASS_DIRS : WeightedGridGraph.CARDINAL_DIRS;
|
this._dirs = allowDiagonalSearch ? WeightedGridGraph.COMPASS_DIRS : WeightedGridGraph.CARDINAL_DIRS;
|
||||||
}
|
}
|
||||||
|
|
||||||
public isNodeInBounds(node: Vector2){
|
public isNodeInBounds(node: Vector2){
|
||||||
return 0 <= node.x && node.x < this._width && 0 <= node.y && node.y < this._height;
|
return 0 <= node.x && node.x < this._width && 0 <= node.y && node.y < this._height;
|
||||||
}
|
}
|
||||||
|
|
||||||
public isNodePassable(node: Vector2): boolean {
|
public isNodePassable(node: Vector2): boolean {
|
||||||
return !this.walls.firstOrDefault(wall => JSON.stringify(wall) == JSON.stringify(node));
|
return !this.walls.firstOrDefault(wall => JSON.stringify(wall) == JSON.stringify(node));
|
||||||
}
|
}
|
||||||
|
|
||||||
public search(start: Vector2, goal: Vector2){
|
public search(start: Vector2, goal: Vector2){
|
||||||
return WeightedPathfinder.search(this, start, goal);
|
return WeightedPathfinder.search(this, start, goal);
|
||||||
}
|
}
|
||||||
|
|
||||||
public getNeighbors(node: Vector2): Vector2[]{
|
public getNeighbors(node: Vector2): Vector2[]{
|
||||||
this._neighbors.length = 0;
|
this._neighbors.length = 0;
|
||||||
|
|
||||||
this._dirs.forEach(dir => {
|
this._dirs.forEach(dir => {
|
||||||
let next = new Vector2(node.x + dir.x, node.y + dir.y);
|
let next = new Vector2(node.x + dir.x, node.y + dir.y);
|
||||||
if (this.isNodeInBounds(next) && this.isNodePassable(next))
|
if (this.isNodeInBounds(next) && this.isNodePassable(next))
|
||||||
this._neighbors.push(next);
|
this._neighbors.push(next);
|
||||||
});
|
});
|
||||||
|
|
||||||
return this._neighbors;
|
return this._neighbors;
|
||||||
}
|
}
|
||||||
|
|
||||||
public cost(from: Vector2, to: Vector2): number{
|
public cost(from: Vector2, to: Vector2): number{
|
||||||
return this.weightedNodes.find(t => JSON.stringify(t) == JSON.stringify(to)) ? this.weightedNodeWeight : this.defaultWeight;
|
return this.weightedNodes.find(t => JSON.stringify(t) == JSON.stringify(to)) ? this.weightedNodeWeight : this.defaultWeight;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,83 +1,85 @@
|
|||||||
class WeightedNode<T> extends PriorityQueueNode {
|
module es {
|
||||||
public data: T;
|
export class WeightedNode<T> extends PriorityQueueNode {
|
||||||
|
public data: T;
|
||||||
|
|
||||||
constructor(data: T){
|
constructor(data: T){
|
||||||
super();
|
super();
|
||||||
this.data = data;
|
this.data = data;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
class WeightedPathfinder {
|
export class WeightedPathfinder {
|
||||||
public static search<T>(graph: IWeightedGraph<T>, start: T, goal: T){
|
public static search<T>(graph: IWeightedGraph<T>, start: T, goal: T){
|
||||||
let foundPath = false;
|
let foundPath = false;
|
||||||
|
|
||||||
let cameFrom = new Map<T, T>();
|
let cameFrom = new Map<T, T>();
|
||||||
cameFrom.set(start, start);
|
cameFrom.set(start, start);
|
||||||
|
|
||||||
let costSoFar = new Map<T, number>();
|
let costSoFar = new Map<T, number>();
|
||||||
let frontier = new PriorityQueue<WeightedNode<T>>(1000);
|
let frontier = new PriorityQueue<WeightedNode<T>>(1000);
|
||||||
frontier.enqueue(new WeightedNode<T>(start), 0);
|
frontier.enqueue(new WeightedNode<T>(start), 0);
|
||||||
|
|
||||||
costSoFar.set(start, 0);
|
costSoFar.set(start, 0);
|
||||||
|
|
||||||
while (frontier.count > 0){
|
while (frontier.count > 0){
|
||||||
let current = frontier.dequeue();
|
let current = frontier.dequeue();
|
||||||
|
|
||||||
if (JSON.stringify(current.data) == JSON.stringify(goal)){
|
if (JSON.stringify(current.data) == JSON.stringify(goal)){
|
||||||
foundPath = true;
|
foundPath = true;
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
graph.getNeighbors(current.data).forEach(next => {
|
||||||
|
let newCost = costSoFar.get(current.data) + graph.cost(current.data, next);
|
||||||
|
if (!this.hasKey(costSoFar, next) || newCost < costSoFar.get(next)){
|
||||||
|
costSoFar.set(next, newCost);
|
||||||
|
let priprity = newCost;
|
||||||
|
frontier.enqueue(new WeightedNode<T>(next), priprity);
|
||||||
|
cameFrom.set(next, current.data);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
graph.getNeighbors(current.data).forEach(next => {
|
return foundPath ? this.recontructPath(cameFrom, start, goal) : null;
|
||||||
let newCost = costSoFar.get(current.data) + graph.cost(current.data, next);
|
|
||||||
if (!this.hasKey(costSoFar, next) || newCost < costSoFar.get(next)){
|
|
||||||
costSoFar.set(next, newCost);
|
|
||||||
let priprity = newCost;
|
|
||||||
frontier.enqueue(new WeightedNode<T>(next), priprity);
|
|
||||||
cameFrom.set(next, current.data);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return foundPath ? this.recontructPath(cameFrom, start, goal) : null;
|
private static hasKey<T>(map: Map<T, number>, compareKey: T){
|
||||||
}
|
let iterator = map.keys();
|
||||||
|
let r: IteratorResult<T>;
|
||||||
|
while (r = iterator.next() , !r.done) {
|
||||||
|
if (JSON.stringify(r.value) == JSON.stringify(compareKey))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
private static hasKey<T>(map: Map<T, number>, compareKey: T){
|
return false;
|
||||||
let iterator = map.keys();
|
|
||||||
let r: IteratorResult<T>;
|
|
||||||
while (r = iterator.next() , !r.done) {
|
|
||||||
if (JSON.stringify(r.value) == JSON.stringify(compareKey))
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
private static getKey<T>(map: Map<T, T>, compareKey: T){
|
||||||
}
|
let iterator = map.keys();
|
||||||
|
let valueIterator = map.values();
|
||||||
|
let r: IteratorResult<T>;
|
||||||
|
let v: IteratorResult<T>;
|
||||||
|
while (r = iterator.next(), v = valueIterator.next(), !r.done) {
|
||||||
|
if (JSON.stringify(r.value) == JSON.stringify(compareKey))
|
||||||
|
return v.value;
|
||||||
|
}
|
||||||
|
|
||||||
private static getKey<T>(map: Map<T, T>, compareKey: T){
|
return null;
|
||||||
let iterator = map.keys();
|
|
||||||
let valueIterator = map.values();
|
|
||||||
let r: IteratorResult<T>;
|
|
||||||
let v: IteratorResult<T>;
|
|
||||||
while (r = iterator.next(), v = valueIterator.next(), !r.done) {
|
|
||||||
if (JSON.stringify(r.value) == JSON.stringify(compareKey))
|
|
||||||
return v.value;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
public static recontructPath<T>(cameFrom: Map<T, T>, start: T, goal: T): T[]{
|
||||||
}
|
let path = [];
|
||||||
|
let current = goal;
|
||||||
|
path.push(goal);
|
||||||
|
|
||||||
public static recontructPath<T>(cameFrom: Map<T, T>, start: T, goal: T): T[]{
|
while (current != start){
|
||||||
let path = [];
|
current = this.getKey(cameFrom, current);
|
||||||
let current = goal;
|
path.push(current);
|
||||||
path.push(goal);
|
}
|
||||||
|
|
||||||
while (current != start){
|
path.reverse();
|
||||||
current = this.getKey(cameFrom, current);
|
|
||||||
path.push(current);
|
return path;
|
||||||
}
|
}
|
||||||
|
|
||||||
path.reverse();
|
|
||||||
|
|
||||||
return path;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+17
-15
@@ -1,21 +1,23 @@
|
|||||||
class Debug {
|
module es {
|
||||||
private static _debugDrawItems: DebugDrawItem[] = [];
|
export class Debug {
|
||||||
|
private static _debugDrawItems: DebugDrawItem[] = [];
|
||||||
|
|
||||||
public static drawHollowRect(rectanle: Rectangle, color: number, duration = 0){
|
public static drawHollowRect(rectanle: Rectangle, color: number, duration = 0){
|
||||||
this._debugDrawItems.push(new DebugDrawItem(rectanle, color, duration));
|
this._debugDrawItems.push(new DebugDrawItem(rectanle, color, duration));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static render(){
|
public static render(){
|
||||||
if (this._debugDrawItems.length > 0){
|
if (this._debugDrawItems.length > 0){
|
||||||
let debugShape = new egret.Shape();
|
let debugShape = new egret.Shape();
|
||||||
if (SceneManager.scene){
|
if (Core.scene){
|
||||||
SceneManager.scene.addChild(debugShape);
|
Core.scene.addChild(debugShape);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (let i = this._debugDrawItems.length - 1; i >= 0; i --){
|
for (let i = this._debugDrawItems.length - 1; i >= 0; i --){
|
||||||
let item = this._debugDrawItems[i];
|
let item = this._debugDrawItems[i];
|
||||||
if (item.draw(debugShape))
|
if (item.draw(debugShape))
|
||||||
this._debugDrawItems.removeAt(i);
|
this._debugDrawItems.removeAt(i);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
class DebugDefaults {
|
module es {
|
||||||
public static verletParticle = 0xDC345E;
|
export class DebugDefaults {
|
||||||
public static verletConstraintEdge = 0x433E36;
|
public static verletParticle = 0xDC345E;
|
||||||
|
public static verletConstraintEdge = 0x433E36;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,46 +1,49 @@
|
|||||||
enum DebugDrawType {
|
module es {
|
||||||
line,
|
export enum DebugDrawType {
|
||||||
hollowRectangle,
|
line,
|
||||||
pixel,
|
hollowRectangle,
|
||||||
text
|
pixel,
|
||||||
}
|
text
|
||||||
|
|
||||||
class DebugDrawItem {
|
|
||||||
public rectangle: Rectangle;
|
|
||||||
public color: number;
|
|
||||||
public duration: number;
|
|
||||||
public drawType: DebugDrawType;
|
|
||||||
public text: string;
|
|
||||||
public start: Vector2;
|
|
||||||
public end: Vector2;
|
|
||||||
public x: number;
|
|
||||||
public y: number;
|
|
||||||
public size: number;
|
|
||||||
|
|
||||||
constructor(rectangle: Rectangle, color: number, duration: number){
|
|
||||||
this.rectangle = rectangle;
|
|
||||||
this.color = color;
|
|
||||||
this.duration = duration;
|
|
||||||
this.drawType = DebugDrawType.hollowRectangle;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public draw(shape: egret.Shape): boolean{
|
export class DebugDrawItem {
|
||||||
switch (this.drawType){
|
public rectangle: Rectangle;
|
||||||
case DebugDrawType.line:
|
public color: number;
|
||||||
DrawUtils.drawLine(shape, this.start, this.end, this.color);
|
public duration: number;
|
||||||
break;
|
public drawType: DebugDrawType;
|
||||||
case DebugDrawType.hollowRectangle:
|
public text: string;
|
||||||
DrawUtils.drawHollowRect(shape, this.rectangle, this.color);
|
public start: Vector2;
|
||||||
break;
|
public end: Vector2;
|
||||||
case DebugDrawType.pixel:
|
public x: number;
|
||||||
DrawUtils.drawPixel(shape, new Vector2(this.x, this.y), this.color, this.size);
|
public y: number;
|
||||||
break;
|
public size: number;
|
||||||
case DebugDrawType.text:
|
|
||||||
break;
|
constructor(rectangle: Rectangle, color: number, duration: number){
|
||||||
|
this.rectangle = rectangle;
|
||||||
|
this.color = color;
|
||||||
|
this.duration = duration;
|
||||||
|
this.drawType = DebugDrawType.hollowRectangle;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.duration -= Time.deltaTime;
|
public draw(shape: egret.Shape): boolean{
|
||||||
return this.duration < 0;
|
switch (this.drawType){
|
||||||
|
case DebugDrawType.line:
|
||||||
|
DrawUtils.drawLine(shape, this.start, this.end, this.color);
|
||||||
|
break;
|
||||||
|
case DebugDrawType.hollowRectangle:
|
||||||
|
DrawUtils.drawHollowRect(shape, this.rectangle, this.color);
|
||||||
|
break;
|
||||||
|
case DebugDrawType.pixel:
|
||||||
|
DrawUtils.drawPixel(shape, new Vector2(this.x, this.y), this.color, this.size);
|
||||||
|
break;
|
||||||
|
case DebugDrawType.text:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.duration -= Time.deltaTime;
|
||||||
|
return this.duration < 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+130
-89
@@ -1,96 +1,137 @@
|
|||||||
abstract class Component extends egret.DisplayObjectContainer {
|
module es {
|
||||||
public entity: Entity;
|
|
||||||
private _enabled: boolean = true;
|
|
||||||
public updateInterval: number = 1;
|
|
||||||
/** 允许用户为实体存入信息 */
|
|
||||||
public userData: any;
|
|
||||||
private _updateOrder = 0;
|
|
||||||
|
|
||||||
public get enabled(){
|
|
||||||
return this.entity ? this.entity.enabled && this._enabled : this._enabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
public set enabled(value: boolean){
|
|
||||||
this.setEnabled(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public get localPosition(){
|
|
||||||
return new Vector2(this.entity.x + this.x, this.entity.y + this.y);
|
|
||||||
}
|
|
||||||
|
|
||||||
public setEnabled(isEnabled: boolean){
|
|
||||||
if (this._enabled != isEnabled){
|
|
||||||
this._enabled = isEnabled;
|
|
||||||
|
|
||||||
if (this._enabled){
|
|
||||||
this.onEnabled();
|
|
||||||
}else{
|
|
||||||
this.onDisabled();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 更新此实体上组件的顺序 */
|
|
||||||
public get updateOrder(){
|
|
||||||
return this._updateOrder;
|
|
||||||
}
|
|
||||||
/** 更新此实体上组件的顺序 */
|
|
||||||
public set updateOrder(value: number){
|
|
||||||
this.setUpdateOrder(value);
|
|
||||||
}
|
|
||||||
public setUpdateOrder(updateOrder: number){
|
|
||||||
if (this._updateOrder != updateOrder){
|
|
||||||
this._updateOrder = updateOrder;
|
|
||||||
}
|
|
||||||
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public initialize(){
|
|
||||||
}
|
|
||||||
|
|
||||||
public onAddedToEntity(){
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public onRemovedFromEntity(){
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public onEnabled(){
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public onDisabled(){
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public debugRender(){
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public update(){
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 当实体的位置改变时调用。这允许组件知道它们由于父实体的移动而移动了。
|
* 执行顺序
|
||||||
* @param comp
|
* - onAddedToEntity
|
||||||
|
* - OnEnabled
|
||||||
|
*
|
||||||
|
* 删除执行顺序
|
||||||
|
* - onRemovedFromEntity
|
||||||
*/
|
*/
|
||||||
public onEntityTransformChanged(comp: TransformComponent){
|
export abstract class Component {
|
||||||
|
/**
|
||||||
|
* 此组件附加的实体
|
||||||
|
*/
|
||||||
|
public entity: Entity;
|
||||||
|
|
||||||
}
|
/**
|
||||||
|
* 快速访问 this.entity.transform
|
||||||
|
*/
|
||||||
|
public get transform(): Transform {
|
||||||
|
return this.entity.transform;
|
||||||
|
}
|
||||||
|
|
||||||
/** 内部使用 运行时不应该调用 */
|
/**
|
||||||
public registerComponent(){
|
* 如果组件和实体都已启用,则为。当启用该组件时,将调用该组件的生命周期方法。状态的改变会导致调用onEnabled/onDisable。
|
||||||
this.entity.componentBits.set(ComponentTypeManager.getIndexFor(this), false);
|
*/
|
||||||
this.entity.scene.entityProcessors.onComponentAdded(this.entity);
|
public get enabled() {
|
||||||
}
|
return this.entity ? this.entity.enabled && this._enabled : this._enabled;
|
||||||
|
}
|
||||||
|
|
||||||
public deregisterComponent(){
|
/**
|
||||||
this.entity.componentBits.set(ComponentTypeManager.getIndexFor(this));
|
* 如果组件和实体都已启用,则为。当启用该组件时,将调用该组件的生命周期方法。状态的改变会导致调用onEnabled/onDisable。
|
||||||
this.entity.scene.entityProcessors.onComponentRemoved(this.entity);
|
* @param value
|
||||||
|
*/
|
||||||
|
public set enabled(value: boolean) {
|
||||||
|
this.setEnabled(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 更新此实体上组件的顺序 */
|
||||||
|
public get updateOrder() {
|
||||||
|
return this._updateOrder;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 更新此实体上组件的顺序 */
|
||||||
|
public set updateOrder(value: number) {
|
||||||
|
this.setUpdateOrder(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新该组件的时间间隔。这与实体的更新间隔无关。
|
||||||
|
*/
|
||||||
|
public updateInterval: number = 1;
|
||||||
|
|
||||||
|
private _enabled: boolean = true;
|
||||||
|
private _updateOrder = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 当此组件已分配其实体,但尚未添加到实体的活动组件列表时调用。有用的东西,如物理组件,需要访问转换来修改碰撞体的属性。
|
||||||
|
*/
|
||||||
|
public initialize() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 在提交所有挂起的组件更改后,将该组件添加到场景时调用。此时,设置了实体字段和实体。场景也设定好了。
|
||||||
|
*/
|
||||||
|
public onAddedToEntity() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 当此组件从其实体中移除时调用。在这里做所有的清理工作。
|
||||||
|
*/
|
||||||
|
public onRemovedFromEntity() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 当实体的位置改变时调用。这允许组件知道它们由于父实体的移动而移动了。
|
||||||
|
* @param comp
|
||||||
|
*/
|
||||||
|
public onEntityTransformChanged(comp: transform.Component) {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public debugRender() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*当父实体或此组件启用时调用
|
||||||
|
*/
|
||||||
|
public onEnabled() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 禁用父实体或此组件时调用
|
||||||
|
*/
|
||||||
|
public onDisabled() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 当该组件启用时每帧进行调用
|
||||||
|
*/
|
||||||
|
public update() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public setEnabled(isEnabled: boolean) {
|
||||||
|
if (this._enabled != isEnabled) {
|
||||||
|
this._enabled = isEnabled;
|
||||||
|
|
||||||
|
if (this._enabled) {
|
||||||
|
this.onEnabled();
|
||||||
|
} else {
|
||||||
|
this.onDisabled();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public setUpdateOrder(updateOrder: number) {
|
||||||
|
if (this._updateOrder != updateOrder) {
|
||||||
|
this._updateOrder = updateOrder;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建此组件的克隆
|
||||||
|
*/
|
||||||
|
public clone(): Component {
|
||||||
|
let component = ObjectUtils.clone<Component>(this);
|
||||||
|
component.entity = null;
|
||||||
|
|
||||||
|
return component;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+458
-212
@@ -1,234 +1,480 @@
|
|||||||
class Camera extends Component {
|
module es {
|
||||||
private _zoom;
|
export enum CameraStyle {
|
||||||
private _origin: Vector2 = Vector2.zero;
|
lockOn,
|
||||||
|
cameraWindow,
|
||||||
private _minimumZoom = 0.3;
|
|
||||||
private _maximumZoom = 3;
|
|
||||||
|
|
||||||
private _position: Vector2 = Vector2.zero;
|
|
||||||
/**
|
|
||||||
* 如果相机模式为cameraWindow 则会进行缓动移动
|
|
||||||
* 该值为移动速度
|
|
||||||
*/
|
|
||||||
public followLerp = 0.1;
|
|
||||||
public deadzone: Rectangle = new Rectangle();
|
|
||||||
/** 锁定偏移量 默认中心 */
|
|
||||||
public focusOffset: Vector2 = new Vector2();
|
|
||||||
/** 是否地图锁定 如果锁定则需要设置mapSize属性 */
|
|
||||||
public mapLockEnabled: boolean = false;
|
|
||||||
/** 设置地图大小 默认从0 0左上角开始 只需要输入地图宽高 */
|
|
||||||
public mapSize: Vector2 = new Vector2();
|
|
||||||
/** 跟随的实体 设置后镜头将锁定目标为中心 */
|
|
||||||
public targetEntity: Entity;
|
|
||||||
private _worldSpaceDeadZone: Rectangle = new Rectangle();
|
|
||||||
private _desiredPositionDelta: Vector2 = new Vector2();
|
|
||||||
private _targetCollider: Collider;
|
|
||||||
/** 相机模式 */
|
|
||||||
public cameraStyle: CameraStyle = CameraStyle.lockOn;
|
|
||||||
|
|
||||||
public get zoom(){
|
|
||||||
if (this._zoom == 0)
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
if (this._zoom < 1)
|
|
||||||
return MathHelper.map(this._zoom, this._minimumZoom, 1, -1, 0);
|
|
||||||
|
|
||||||
return MathHelper.map(this._zoom, 1, this._maximumZoom, 0, 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public set zoom(value: number){
|
export class CameraInset {
|
||||||
this.setZoom(value);
|
public left: number = 0;
|
||||||
|
public right: number = 0;
|
||||||
|
public top: number = 0;
|
||||||
|
public bottom: number = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public get minimumZoom(){
|
export class Camera extends Component {
|
||||||
return this._minimumZoom;
|
/**
|
||||||
}
|
* 对entity.transform.position的快速访问
|
||||||
|
*/
|
||||||
public set minimumZoom(value: number){
|
public get position() {
|
||||||
this.setMinimumZoom(value);
|
return this.entity.transform.position;
|
||||||
}
|
|
||||||
|
|
||||||
public get maximumZoom(){
|
|
||||||
return this._maximumZoom;
|
|
||||||
}
|
|
||||||
|
|
||||||
public set maximumZoom(value: number){
|
|
||||||
this.setMaximumZoom(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public get origin(){
|
|
||||||
return this._origin;
|
|
||||||
}
|
|
||||||
|
|
||||||
public set origin(value: Vector2){
|
|
||||||
if (this._origin != value){
|
|
||||||
this._origin = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public get position(){
|
|
||||||
return this._position;
|
|
||||||
}
|
|
||||||
|
|
||||||
public set position(value: Vector2){
|
|
||||||
this._position = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public get x(){
|
|
||||||
return this._position.x;
|
|
||||||
}
|
|
||||||
public set x(value: number){
|
|
||||||
this._position.x = value;
|
|
||||||
}
|
|
||||||
public get y(){
|
|
||||||
return this._position.y;
|
|
||||||
}
|
|
||||||
public set y(value: number){
|
|
||||||
this._position.y = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
constructor() {
|
|
||||||
super();
|
|
||||||
|
|
||||||
this.width = SceneManager.stage.stageWidth;
|
|
||||||
this.height = SceneManager.stage.stageHeight;
|
|
||||||
this.setZoom(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
public onSceneSizeChanged(newWidth: number, newHeight: number){
|
|
||||||
let oldOrigin = this._origin;
|
|
||||||
this.origin = new Vector2(newWidth / 2, newHeight / 2);
|
|
||||||
|
|
||||||
this.entity.position = Vector2.add(this.entity.position, Vector2.subtract(this._origin, oldOrigin));
|
|
||||||
}
|
|
||||||
|
|
||||||
public setMinimumZoom(minZoom: number): Camera{
|
|
||||||
if (this._zoom < minZoom)
|
|
||||||
this._zoom = this.minimumZoom;
|
|
||||||
|
|
||||||
this._minimumZoom = minZoom;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public setMaximumZoom(maxZoom: number): Camera {
|
|
||||||
if (this._zoom > maxZoom)
|
|
||||||
this._zoom = maxZoom;
|
|
||||||
|
|
||||||
this._maximumZoom = maxZoom;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public setZoom(zoom: number): Camera{
|
|
||||||
let newZoom = MathHelper.clamp(zoom, -1, 1);
|
|
||||||
if (newZoom == 0){
|
|
||||||
this._zoom = 1;
|
|
||||||
} else if(newZoom < 0){
|
|
||||||
this._zoom = MathHelper.map(newZoom, -1, 0, this._minimumZoom, 1);
|
|
||||||
} else {
|
|
||||||
this._zoom = MathHelper.map(newZoom, 0, 1, 1, this._maximumZoom);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SceneManager.scene.scaleX = this._zoom;
|
/**
|
||||||
SceneManager.scene.scaleY = this._zoom;
|
* 对entity.transform.position的快速访问
|
||||||
return this;
|
* @param value
|
||||||
}
|
*/
|
||||||
|
public set position(value: Vector2) {
|
||||||
public setRotation(rotation: number): Camera {
|
this.entity.transform.position = value;
|
||||||
SceneManager.scene.rotation = rotation;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public setPosition(position: Vector2){
|
|
||||||
this.entity.position = position;
|
|
||||||
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public follow(targetEntity: Entity, cameraStyle: CameraStyle = CameraStyle.cameraWindow){
|
|
||||||
this.targetEntity = targetEntity;
|
|
||||||
this.cameraStyle = cameraStyle;
|
|
||||||
let cameraBounds = new Rectangle(0, 0, SceneManager.stage.stageWidth, SceneManager.stage.stageHeight);
|
|
||||||
|
|
||||||
switch (this.cameraStyle){
|
|
||||||
case CameraStyle.cameraWindow:
|
|
||||||
let w = cameraBounds.width / 6;
|
|
||||||
let h = cameraBounds.height / 3;
|
|
||||||
this.deadzone = new Rectangle((cameraBounds.width - w) / 2, (cameraBounds.height - h) / 2, w, h);
|
|
||||||
break;
|
|
||||||
case CameraStyle.lockOn:
|
|
||||||
this.deadzone = new Rectangle(cameraBounds.width / 2, cameraBounds.height / 2, 10, 10);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public update(){
|
/**
|
||||||
let cameraBounds = new Rectangle(0, 0, SceneManager.stage.stageWidth, SceneManager.stage.stageHeight);
|
* 对entity.transform.rotation的快速访问
|
||||||
let halfScreen = Vector2.multiply(new Vector2(cameraBounds.width, cameraBounds.height), new Vector2(0.5));
|
*/
|
||||||
this._worldSpaceDeadZone.x = this.position.x - halfScreen.x * SceneManager.scene.scaleX + this.deadzone.x + this.focusOffset.x;
|
public get rotation(): number {
|
||||||
this._worldSpaceDeadZone.y = this.position.y - halfScreen.y * SceneManager.scene.scaleY + this.deadzone.y + this.focusOffset.y;
|
return this.entity.transform.rotation;
|
||||||
this._worldSpaceDeadZone.width = this.deadzone.width;
|
|
||||||
this._worldSpaceDeadZone.height = this.deadzone.height;
|
|
||||||
|
|
||||||
if (this.targetEntity)
|
|
||||||
this.updateFollow();
|
|
||||||
|
|
||||||
this.position = Vector2.lerp(this.position, Vector2.add(this.position, this._desiredPositionDelta), this.followLerp);
|
|
||||||
this.entity.roundPosition();
|
|
||||||
|
|
||||||
if (this.mapLockEnabled){
|
|
||||||
this.position = this.clampToMapSize(this.position);
|
|
||||||
this.entity.roundPosition();
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private clampToMapSize(position: Vector2){
|
/**
|
||||||
let cameraBounds = new Rectangle(0, 0, SceneManager.stage.stageWidth, SceneManager.stage.stageHeight);
|
* 对entity.transform.rotation的快速访问
|
||||||
let halfScreen = Vector2.multiply(new Vector2(cameraBounds.width, cameraBounds.height), new Vector2(0.5));
|
* @param value
|
||||||
let cameraMax = new Vector2(this.mapSize.x - halfScreen.x, this.mapSize.y - halfScreen.y);
|
*/
|
||||||
|
public set rotation(value: number) {
|
||||||
|
this.entity.transform.rotation = value;
|
||||||
|
}
|
||||||
|
|
||||||
return Vector2.clamp(position, halfScreen, cameraMax);
|
/**
|
||||||
}
|
* 缩放值应该在-1和1之间、然后将该值从minimumZoom转换为maximumZoom。
|
||||||
|
* 允许你设置适当的最小/最大值,然后使用更直观的-1到1的映射来更改缩放
|
||||||
|
*/
|
||||||
|
public get zoom() {
|
||||||
|
if (this._zoom == 0)
|
||||||
|
return 1;
|
||||||
|
|
||||||
private updateFollow(){
|
if (this._zoom < 1)
|
||||||
this._desiredPositionDelta.x = this._desiredPositionDelta.y = 0;
|
return MathHelper.map(this._zoom, this._minimumZoom, 1, -1, 0);
|
||||||
|
|
||||||
if (this.cameraStyle == CameraStyle.lockOn){
|
return MathHelper.map(this._zoom, 1, this._maximumZoom, 0, 1);
|
||||||
let targetX = this.targetEntity.position.x;
|
}
|
||||||
let targetY = this.targetEntity.position.y;
|
|
||||||
|
|
||||||
if (this._worldSpaceDeadZone.x > targetX)
|
/**
|
||||||
this._desiredPositionDelta.x = targetX - this._worldSpaceDeadZone.x;
|
* 缩放值应该在-1和1之间、然后将该值从minimumZoom转换为maximumZoom。
|
||||||
else if(this._worldSpaceDeadZone.x < targetX)
|
* 允许你设置适当的最小/最大值,然后使用更直观的-1到1的映射来更改缩放
|
||||||
this._desiredPositionDelta.x = targetX - this._worldSpaceDeadZone.x;
|
* @param value
|
||||||
|
*/
|
||||||
|
public set zoom(value: number) {
|
||||||
|
this.setZoom(value);
|
||||||
|
}
|
||||||
|
|
||||||
if (this._worldSpaceDeadZone.y < targetY)
|
/**
|
||||||
this._desiredPositionDelta.y = targetY - this._worldSpaceDeadZone.y;
|
* 相机变焦可以达到的最小非缩放值(0-number.max)。默认为0.3
|
||||||
else if(this._worldSpaceDeadZone.y > targetY)
|
*/
|
||||||
this._desiredPositionDelta.y = targetY - this._worldSpaceDeadZone.y;
|
public get minimumZoom() {
|
||||||
} else {
|
return this._minimumZoom;
|
||||||
if (!this._targetCollider){
|
}
|
||||||
this._targetCollider = this.targetEntity.getComponent<Collider>(Collider);
|
|
||||||
if (!this._targetCollider)
|
/**
|
||||||
return;
|
* 相机变焦可以达到的最小非缩放值(0-number.max)。默认为0.3
|
||||||
|
* @param value
|
||||||
|
*/
|
||||||
|
public set minimumZoom(value: number) {
|
||||||
|
this.setMinimumZoom(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 相机变焦可以达到的最大非缩放值(0-number.max)。默认为3
|
||||||
|
*/
|
||||||
|
public get maximumZoom() {
|
||||||
|
return this._maximumZoom;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 相机变焦可以达到的最大非缩放值(0-number.max)。默认为3
|
||||||
|
* @param value
|
||||||
|
*/
|
||||||
|
public set maximumZoom(value: number) {
|
||||||
|
this.setMaximumZoom(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 相机的世界-空间边界
|
||||||
|
*/
|
||||||
|
public get bounds(){
|
||||||
|
if (this._areMatrixedDirty)
|
||||||
|
this.updateMatrixes();
|
||||||
|
|
||||||
|
if (this._areBoundsDirty){
|
||||||
|
// 旋转或非旋转的边界都需要左上角和右下角
|
||||||
|
let topLeft = this.screenToWorldPoint(new Vector2(this._inset.left, this._inset.top));
|
||||||
|
let bottomRight = this.screenToWorldPoint(new Vector2(Core.graphicsDevice.viewport.width - this._inset.right,
|
||||||
|
Core.graphicsDevice.viewport.height - this._inset.bottom));
|
||||||
|
|
||||||
|
if (this.entity.transform.rotation != 0){
|
||||||
|
// 特别注意旋转的边界。我们需要找到绝对的最小/最大值并从中创建边界
|
||||||
|
let topRight = this.screenToWorldPoint(new Vector2(Core.graphicsDevice.viewport.width - this._inset.right,
|
||||||
|
this._inset.top));
|
||||||
|
let bottomLeft = this.screenToWorldPoint(new Vector2(this._inset.left,
|
||||||
|
Core.graphicsDevice.viewport.height - this._inset.bottom));
|
||||||
|
|
||||||
|
let minX = Math.min(topLeft.x, bottomRight.x, topRight.x, bottomLeft.x);
|
||||||
|
let maxX = Math.max(topLeft.x, bottomRight.x, topRight.x, bottomLeft.x);
|
||||||
|
let minY = Math.min(topLeft.y, bottomRight.y, topRight.y, bottomLeft.y);
|
||||||
|
let maxY = Math.max(topLeft.y, bottomRight.y, topRight.y, bottomLeft.y);
|
||||||
|
|
||||||
|
this._bounds.location = new Vector2(minX, minY);
|
||||||
|
this._bounds.width = maxX - minX;
|
||||||
|
this._bounds.height = maxY - minY;
|
||||||
|
} else {
|
||||||
|
this._bounds.location = topLeft;
|
||||||
|
this._bounds.width = bottomRight.x - topLeft.x;
|
||||||
|
this._bounds.height = bottomRight.y - topLeft.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
this._areBoundsDirty = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
let targetBounds = this.targetEntity.getComponent<Collider>(Collider).bounds;
|
return this._bounds;
|
||||||
if (!this._worldSpaceDeadZone.containsRect(targetBounds)){
|
}
|
||||||
if (this._worldSpaceDeadZone.left > targetBounds.left)
|
|
||||||
this._desiredPositionDelta.x = targetBounds.left - this._worldSpaceDeadZone.left;
|
|
||||||
else if(this._worldSpaceDeadZone.right < targetBounds.right)
|
|
||||||
this._desiredPositionDelta.x = targetBounds.right - this._worldSpaceDeadZone.right;
|
|
||||||
|
|
||||||
if (this._worldSpaceDeadZone.bottom < targetBounds.bottom)
|
/**
|
||||||
this._desiredPositionDelta.y = targetBounds.bottom - this._worldSpaceDeadZone.bottom;
|
* 用于从世界坐标转换到屏幕
|
||||||
else if(this._worldSpaceDeadZone.top > targetBounds.top)
|
*/
|
||||||
this._desiredPositionDelta.y = targetBounds.top - this._worldSpaceDeadZone.top;
|
public get transformMatrix(): Matrix2D {
|
||||||
|
if (this._areMatrixedDirty)
|
||||||
|
this.updateMatrixes();
|
||||||
|
return this._transformMatrix;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用于从屏幕坐标到世界的转换
|
||||||
|
*/
|
||||||
|
public get inverseTransformMatrix(): Matrix2D {
|
||||||
|
if (this._areMatrixedDirty)
|
||||||
|
this.updateMatrixes();
|
||||||
|
return this._inverseTransformMatrix;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get origin() {
|
||||||
|
return this._origin;
|
||||||
|
}
|
||||||
|
|
||||||
|
public set origin(value: Vector2) {
|
||||||
|
if (this._origin != value) {
|
||||||
|
this._origin = value;
|
||||||
|
this._areMatrixedDirty = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public _zoom;
|
||||||
|
public _minimumZoom = 0.3;
|
||||||
|
public _maximumZoom = 3;
|
||||||
|
public _bounds: Rectangle = new Rectangle();
|
||||||
|
public _inset: CameraInset = new CameraInset();
|
||||||
|
public _transformMatrix: Matrix2D = new Matrix2D().identity();
|
||||||
|
public _inverseTransformMatrix: Matrix2D = new Matrix2D().identity();
|
||||||
|
public _origin: Vector2 = Vector2.zero;
|
||||||
|
|
||||||
|
public _areMatrixedDirty: boolean = true;
|
||||||
|
public _areBoundsDirty: boolean = true;
|
||||||
|
public _isProjectionMatrixDirty = true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 如果相机模式为cameraWindow 则会进行缓动移动
|
||||||
|
* 该值为移动速度
|
||||||
|
*/
|
||||||
|
public followLerp = 0.1;
|
||||||
|
/**
|
||||||
|
* 在cameraWindow模式下,宽度/高度被用做边界框,允许在不移动相机的情况下移动
|
||||||
|
* 在lockOn模式下,只使用deadZone的x/y值 你可以通过直接setCenteredDeadzone重写它来自定义deadZone
|
||||||
|
*/
|
||||||
|
public deadzone: Rectangle = new Rectangle();
|
||||||
|
/**
|
||||||
|
* 相机聚焦于屏幕中心的偏移
|
||||||
|
*/
|
||||||
|
public focusOffset: Vector2 = Vector2.zero;
|
||||||
|
/**
|
||||||
|
* 如果为true 相机位置则不会超出地图矩形(0, 0, mapwidth, mapheight)
|
||||||
|
*/
|
||||||
|
public mapLockEnabled: boolean = false;
|
||||||
|
/**
|
||||||
|
* 當前地圖映射的寬度和高度
|
||||||
|
*/
|
||||||
|
public mapSize: Vector2 = Vector2.zero;
|
||||||
|
|
||||||
|
public _targetEntity: Entity;
|
||||||
|
public _targetCollider: Collider;
|
||||||
|
public _desiredPositionDelta: Vector2 = new Vector2();
|
||||||
|
public _cameraStyle: CameraStyle;
|
||||||
|
public _worldSpaceDeadZone: Rectangle = new Rectangle();
|
||||||
|
|
||||||
|
constructor(targetEntity: Entity = null, cameraStyle: CameraStyle = CameraStyle.lockOn) {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this._targetEntity = targetEntity;
|
||||||
|
this._cameraStyle = cameraStyle;
|
||||||
|
this.setZoom(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 当场景渲染目标的大小发生变化时,我们会更新相机的原点并调整它的位置以保持它原来的位置
|
||||||
|
* @param newWidth
|
||||||
|
* @param newHeight
|
||||||
|
*/
|
||||||
|
public onSceneSizeChanged(newWidth: number, newHeight: number) {
|
||||||
|
let oldOrigin = this._origin;
|
||||||
|
this.origin = new Vector2(newWidth / 2, newHeight / 2);
|
||||||
|
|
||||||
|
this.entity.transform.position = Vector2.add(this.entity.transform.position, Vector2.subtract(this._origin, oldOrigin));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected updateMatrixes(){
|
||||||
|
if (!this._areMatrixedDirty)
|
||||||
|
return;
|
||||||
|
|
||||||
|
let tempMat: Matrix2D;
|
||||||
|
this._transformMatrix = Matrix2D.create().translate(-this.entity.transform.position.x, -this.entity.transform.position.y);
|
||||||
|
|
||||||
|
if (this._zoom != 1){
|
||||||
|
tempMat = Matrix2D.create().scale(this._zoom, this._zoom);
|
||||||
|
this._transformMatrix = this._transformMatrix.multiply(tempMat);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.entity.transform.rotation != 0){
|
||||||
|
tempMat = Matrix2D.create().rotate(this.entity.transform.rotation);
|
||||||
|
this._transformMatrix = this._transformMatrix.multiply(tempMat);
|
||||||
|
}
|
||||||
|
|
||||||
|
tempMat = Matrix2D.create().translate(this._origin.x, this._origin.y);
|
||||||
|
this._transformMatrix =this._transformMatrix.multiply(tempMat);
|
||||||
|
|
||||||
|
this._inverseTransformMatrix = this._transformMatrix.invert();
|
||||||
|
|
||||||
|
// 无论何时矩阵改变边界都是无效的
|
||||||
|
this._areBoundsDirty = true;
|
||||||
|
this._areMatrixedDirty = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置用于从视口边缘插入摄像机边界的量
|
||||||
|
* @param left
|
||||||
|
* @param right
|
||||||
|
* @param top
|
||||||
|
* @param bottom
|
||||||
|
*/
|
||||||
|
public setInset(left: number, right: number, top: number, bottom: number): Camera {
|
||||||
|
this._inset = new CameraInset();
|
||||||
|
this._inset.left = left;
|
||||||
|
this._inset.right = right;
|
||||||
|
this._inset.top = top;
|
||||||
|
this._inset.bottom = bottom;
|
||||||
|
this._areBoundsDirty = true;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 对entity.transform.setPosition快速访问
|
||||||
|
* @param position
|
||||||
|
*/
|
||||||
|
public setPosition(position: Vector2) {
|
||||||
|
this.entity.transform.setPosition(position.x, position.y);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 对entity.transform.setRotation的快速访问
|
||||||
|
* @param rotation
|
||||||
|
*/
|
||||||
|
public setRotation(rotation: number): Camera {
|
||||||
|
this.entity.transform.setRotation(rotation);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置缩放值,缩放值应该在-1到1之间。然后将该值从minimumZoom转换为maximumZoom
|
||||||
|
* 允许您设置适当的最小/最大值。使用更直观的-1到1的映射来更改缩放
|
||||||
|
* @param zoom
|
||||||
|
*/
|
||||||
|
public setZoom(zoom: number): Camera {
|
||||||
|
let newZoom = MathHelper.clamp(zoom, -1, 1);
|
||||||
|
if (newZoom == 0) {
|
||||||
|
this._zoom = 1;
|
||||||
|
} else if (newZoom < 0) {
|
||||||
|
this._zoom = MathHelper.map(newZoom, -1, 0, this._minimumZoom, 1);
|
||||||
|
} else {
|
||||||
|
this._zoom = MathHelper.map(newZoom, 0, 1, 1, this._maximumZoom);
|
||||||
|
}
|
||||||
|
this._areMatrixedDirty = true;
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 相机变焦可以达到的最小非缩放值(0-number.max) 默认为0.3
|
||||||
|
* @param minZoom
|
||||||
|
*/
|
||||||
|
public setMinimumZoom(minZoom: number): Camera {
|
||||||
|
if (minZoom <= 0) {
|
||||||
|
console.error("minimumZoom must be greater than zero");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this._zoom < minZoom)
|
||||||
|
this._zoom = this.minimumZoom;
|
||||||
|
|
||||||
|
this._minimumZoom = minZoom;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 相机变焦可以达到的最大非缩放值(0-number.max) 默认为3
|
||||||
|
* @param maxZoom
|
||||||
|
*/
|
||||||
|
public setMaximumZoom(maxZoom: number): Camera {
|
||||||
|
if (maxZoom <= 0) {
|
||||||
|
console.error("maximumZoom must be greater than zero");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this._zoom > maxZoom)
|
||||||
|
this._zoom = maxZoom;
|
||||||
|
|
||||||
|
this._maximumZoom = maxZoom;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public onEntityTransformChanged(comp: transform.Component) {
|
||||||
|
this._areMatrixedDirty = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public zoomIn(deltaZoom: number) {
|
||||||
|
this.zoom += deltaZoom;
|
||||||
|
}
|
||||||
|
|
||||||
|
public zoomOut(deltaZoom: number) {
|
||||||
|
this.zoom -= deltaZoom;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将一个点从世界坐标转换到屏幕
|
||||||
|
* @param worldPosition
|
||||||
|
*/
|
||||||
|
public worldToScreenPoint(worldPosition: Vector2): Vector2{
|
||||||
|
this.updateMatrixes();
|
||||||
|
worldPosition = Vector2.transform(worldPosition, this._transformMatrix);
|
||||||
|
return worldPosition;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将点从屏幕坐标转换为世界坐标
|
||||||
|
* @param screenPosition
|
||||||
|
*/
|
||||||
|
public screenToWorldPoint(screenPosition: Vector2): Vector2{
|
||||||
|
this.updateMatrixes();
|
||||||
|
screenPosition = Vector2.transform(screenPosition, this._inverseTransformMatrix);
|
||||||
|
return screenPosition;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 返回鼠标在世界空间中的位置
|
||||||
|
*/
|
||||||
|
public mouseToWorldPoint(): Vector2{
|
||||||
|
return this.screenToWorldPoint(Input.touchPosition);
|
||||||
|
}
|
||||||
|
|
||||||
|
public onAddedToEntity() {
|
||||||
|
this.follow(this._targetEntity, this._cameraStyle);
|
||||||
|
}
|
||||||
|
|
||||||
|
public update() {
|
||||||
|
let halfScreen = Vector2.multiply(new Vector2(this.bounds.width, this.bounds.height), new Vector2(0.5));
|
||||||
|
this._worldSpaceDeadZone.x = this.position.x - halfScreen.x * Core.scene.scaleX + this.deadzone.x + this.focusOffset.x;
|
||||||
|
this._worldSpaceDeadZone.y = this.position.y - halfScreen.y * Core.scene.scaleY + this.deadzone.y + this.focusOffset.y;
|
||||||
|
this._worldSpaceDeadZone.width = this.deadzone.width;
|
||||||
|
this._worldSpaceDeadZone.height = this.deadzone.height;
|
||||||
|
|
||||||
|
if (this._targetEntity)
|
||||||
|
this.updateFollow();
|
||||||
|
|
||||||
|
this.position = Vector2.lerp(this.position, Vector2.add(this.position, this._desiredPositionDelta), this.followLerp);
|
||||||
|
this.entity.transform.roundPosition();
|
||||||
|
|
||||||
|
if (this.mapLockEnabled) {
|
||||||
|
this.position = this.clampToMapSize(this.position);
|
||||||
|
this.entity.transform.roundPosition();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 固定相机 永远不会离开地图的可见区域
|
||||||
|
* @param position
|
||||||
|
*/
|
||||||
|
public clampToMapSize(position: Vector2) {
|
||||||
|
let halfScreen = Vector2.multiply(new Vector2(this.bounds.width, this.bounds.height), new Vector2(0.5));
|
||||||
|
let cameraMax = new Vector2(this.mapSize.x - halfScreen.x, this.mapSize.y - halfScreen.y);
|
||||||
|
|
||||||
|
return Vector2.clamp(position, halfScreen, cameraMax);
|
||||||
|
}
|
||||||
|
|
||||||
|
public updateFollow() {
|
||||||
|
this._desiredPositionDelta.x = this._desiredPositionDelta.y = 0;
|
||||||
|
|
||||||
|
if (this._cameraStyle == CameraStyle.lockOn) {
|
||||||
|
let targetX = this._targetEntity.transform.position.x;
|
||||||
|
let targetY = this._targetEntity.transform.position.y;
|
||||||
|
|
||||||
|
if (this._worldSpaceDeadZone.x > targetX)
|
||||||
|
this._desiredPositionDelta.x = targetX - this._worldSpaceDeadZone.x;
|
||||||
|
else if (this._worldSpaceDeadZone.x < targetX)
|
||||||
|
this._desiredPositionDelta.x = targetX - this._worldSpaceDeadZone.x;
|
||||||
|
|
||||||
|
if (this._worldSpaceDeadZone.y < targetY)
|
||||||
|
this._desiredPositionDelta.y = targetY - this._worldSpaceDeadZone.y;
|
||||||
|
else if (this._worldSpaceDeadZone.y > targetY)
|
||||||
|
this._desiredPositionDelta.y = targetY - this._worldSpaceDeadZone.y;
|
||||||
|
} else {
|
||||||
|
if (!this._targetCollider) {
|
||||||
|
this._targetCollider = this._targetEntity.getComponent<Collider>(Collider);
|
||||||
|
if (!this._targetCollider)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let targetBounds = this._targetEntity.getComponent<Collider>(Collider).bounds;
|
||||||
|
if (!this._worldSpaceDeadZone.containsRect(targetBounds)) {
|
||||||
|
if (this._worldSpaceDeadZone.left > targetBounds.left)
|
||||||
|
this._desiredPositionDelta.x = targetBounds.left - this._worldSpaceDeadZone.left;
|
||||||
|
else if (this._worldSpaceDeadZone.right < targetBounds.right)
|
||||||
|
this._desiredPositionDelta.x = targetBounds.right - this._worldSpaceDeadZone.right;
|
||||||
|
|
||||||
|
if (this._worldSpaceDeadZone.bottom < targetBounds.bottom)
|
||||||
|
this._desiredPositionDelta.y = targetBounds.bottom - this._worldSpaceDeadZone.bottom;
|
||||||
|
else if (this._worldSpaceDeadZone.top > targetBounds.top)
|
||||||
|
this._desiredPositionDelta.y = targetBounds.top - this._worldSpaceDeadZone.top;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public follow(targetEntity: Entity, cameraStyle: CameraStyle = CameraStyle.cameraWindow) {
|
||||||
|
this._targetEntity = targetEntity;
|
||||||
|
this._cameraStyle = cameraStyle;
|
||||||
|
|
||||||
|
switch (this._cameraStyle) {
|
||||||
|
case CameraStyle.cameraWindow:
|
||||||
|
let w = this.bounds.width / 6;
|
||||||
|
let h = this.bounds.height / 3;
|
||||||
|
this.deadzone = new Rectangle((this.bounds.width - w) / 2, (this.bounds.height - h) / 2, w, h);
|
||||||
|
break;
|
||||||
|
case CameraStyle.lockOn:
|
||||||
|
this.deadzone = new Rectangle(this.bounds.width / 2, this.bounds.height / 2, 10, 10);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 以给定的尺寸设置当前相机边界中心的死区
|
||||||
|
* @param width
|
||||||
|
* @param height
|
||||||
|
*/
|
||||||
|
public setCenteredDeadzone(width: number, height: number) {
|
||||||
|
this.deadzone = new Rectangle((this.bounds.width - width) / 2, (this.bounds.height - height) / 2, width, height);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enum CameraStyle {
|
|
||||||
lockOn,
|
|
||||||
cameraWindow,
|
|
||||||
}
|
|
||||||
@@ -1,22 +1,24 @@
|
|||||||
class ComponentPool<T extends PooledComponent>{
|
module es {
|
||||||
private _cache: T[];
|
export class ComponentPool<T extends PooledComponent>{
|
||||||
private _type: any;
|
private _cache: T[];
|
||||||
|
private _type: any;
|
||||||
|
|
||||||
constructor(typeClass: any){
|
constructor(typeClass: any){
|
||||||
this._type = typeClass;
|
this._type = typeClass;
|
||||||
this._cache = [];
|
this._cache = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
public obtain(): T{
|
public obtain(): T{
|
||||||
try {
|
try {
|
||||||
return this._cache.length > 0 ? this._cache.shift() : new this._type();
|
return this._cache.length > 0 ? this._cache.shift() : new this._type();
|
||||||
} catch(err){
|
} catch(err){
|
||||||
throw new Error(this._type + err);
|
throw new Error(this._type + err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public free(component: T){
|
||||||
|
component.reset();
|
||||||
|
this._cache.push(component);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public free(component: T){
|
|
||||||
component.reset();
|
|
||||||
this._cache.push(component);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
module es {
|
||||||
|
/**
|
||||||
|
* 用于比较组件更新排序
|
||||||
|
*/
|
||||||
|
export class IUpdatableComparer {
|
||||||
|
public compare(a: Component, b: Component){
|
||||||
|
return a.updateOrder - b.updateOrder;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,32 +1,24 @@
|
|||||||
///<reference path="./RenderableComponent.ts" />
|
///<reference path="./RenderableComponent.ts" />
|
||||||
class Mesh extends RenderableComponent {
|
module es {
|
||||||
private _mesh: egret.Mesh;
|
export class Mesh extends RenderableComponent {
|
||||||
|
private _mesh: egret.Mesh;
|
||||||
|
|
||||||
constructor(){
|
constructor(){
|
||||||
super();
|
super();
|
||||||
|
|
||||||
this._mesh = new egret.Mesh();
|
this._mesh = new egret.Mesh();
|
||||||
}
|
}
|
||||||
|
|
||||||
public setTexture(texture: egret.Texture): Mesh{
|
public setTexture(texture: egret.Texture): Mesh{
|
||||||
this._mesh.texture = texture;
|
this._mesh.texture = texture;
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public onAddedToEntity(){
|
public reset() {
|
||||||
this.addChild(this._mesh);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public onRemovedFromEntity(){
|
render(camera: es.Camera) {
|
||||||
this.removeChild(this._mesh);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public render(camera: Camera){
|
|
||||||
this.x = this.entity.position.x - camera.position.x + camera.origin.x;
|
|
||||||
this.y = this.entity.position.y - camera.position.y + camera.origin.y;
|
|
||||||
}
|
|
||||||
|
|
||||||
public reset() {
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,74 +1,85 @@
|
|||||||
///<reference path="./Collider.ts" />
|
///<reference path="./Collider.ts" />
|
||||||
class BoxCollider extends Collider {
|
module es {
|
||||||
public get width(){
|
export class BoxCollider extends Collider {
|
||||||
return (this.shape as Box).width;
|
public get width(){
|
||||||
}
|
return (this.shape as Box).width;
|
||||||
|
|
||||||
public set width(value: number){
|
|
||||||
this.setWidth(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 设置BoxCollider的宽度
|
|
||||||
* @param width
|
|
||||||
*/
|
|
||||||
public setWidth(width: number): BoxCollider{
|
|
||||||
this._colliderRequiresAutoSizing = false;
|
|
||||||
let box = this.shape as Box;
|
|
||||||
if (width != box.width){
|
|
||||||
// 更新框,改变边界,如果我们需要更新物理系统中的边界
|
|
||||||
box.updateBox(width, box.height);
|
|
||||||
if (this.entity && this._isParentEntityAddedToScene)
|
|
||||||
Physics.updateCollider(this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return this;
|
public set width(value: number){
|
||||||
}
|
this.setWidth(value);
|
||||||
|
|
||||||
public get height(){
|
|
||||||
return (this.shape as Box).height;
|
|
||||||
}
|
|
||||||
|
|
||||||
public set height(value: number){
|
|
||||||
this.setHeight(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 设置BoxCollider的高度
|
|
||||||
* @param height
|
|
||||||
*/
|
|
||||||
public setHeight(height: number){
|
|
||||||
this._colliderRequiresAutoSizing = false;
|
|
||||||
let box = this.shape as Box;
|
|
||||||
if (height != box.height){
|
|
||||||
// 更新框,改变边界,如果我们需要更新物理系统中的边界
|
|
||||||
box.updateBox(box.width, height);
|
|
||||||
if (this.entity && this._isParentEntityAddedToScene)
|
|
||||||
Physics.updateCollider(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 零参数构造函数要求RenderableComponent在实体上,这样碰撞器可以在实体被添加到场景时调整自身的大小。
|
|
||||||
*/
|
|
||||||
constructor(){
|
|
||||||
super();
|
|
||||||
|
|
||||||
// 我们在这里插入一个1x1框作为占位符,直到碰撞器在下一阵被添加到实体并可以获得更精确的自动调整大小数据
|
|
||||||
this.shape = new Box(1, 1);
|
|
||||||
this._colliderRequiresAutoSizing = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public setSize(width: number, height: number){
|
|
||||||
this._colliderRequiresAutoSizing = false;
|
|
||||||
let box = this.shape as Box;
|
|
||||||
if (width != box.width || height != box.height){
|
|
||||||
// 更新框,改变边界,如果我们需要更新物理系统中的边界
|
|
||||||
box.updateBox(width, height);
|
|
||||||
if (this.entity && this._isParentEntityAddedToScene)
|
|
||||||
Physics.updateCollider(this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return this;
|
public get height(){
|
||||||
|
return (this.shape as Box).height;
|
||||||
|
}
|
||||||
|
|
||||||
|
public set height(value: number){
|
||||||
|
this.setHeight(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 零参数构造函数要求RenderableComponent在实体上,这样碰撞器可以在实体被添加到场景时调整自身的大小。
|
||||||
|
*/
|
||||||
|
constructor(){
|
||||||
|
super();
|
||||||
|
|
||||||
|
// 我们在这里插入一个1x1框作为占位符,直到碰撞器在下一阵被添加到实体并可以获得更精确的自动调整大小数据
|
||||||
|
this.shape = new Box(1, 1);
|
||||||
|
this._colliderRequiresAutoSizing = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置BoxCollider的大小
|
||||||
|
* @param width
|
||||||
|
* @param height
|
||||||
|
*/
|
||||||
|
public setSize(width: number, height: number){
|
||||||
|
this._colliderRequiresAutoSizing = false;
|
||||||
|
let box = this.shape as Box;
|
||||||
|
if (width != box.width || height != box.height){
|
||||||
|
// 更新框,改变边界,如果我们需要更新物理系统中的边界
|
||||||
|
box.updateBox(width, height);
|
||||||
|
if (this.entity && this._isParentEntityAddedToScene)
|
||||||
|
Physics.updateCollider(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置BoxCollider的宽度
|
||||||
|
* @param width
|
||||||
|
*/
|
||||||
|
public setWidth(width: number): BoxCollider{
|
||||||
|
this._colliderRequiresAutoSizing = false;
|
||||||
|
let box = this.shape as Box;
|
||||||
|
if (width != box.width){
|
||||||
|
// 更新框,改变边界,如果我们需要更新物理系统中的边界
|
||||||
|
box.updateBox(width, box.height);
|
||||||
|
if (this.entity && this._isParentEntityAddedToScene)
|
||||||
|
Physics.updateCollider(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置BoxCollider的高度
|
||||||
|
* @param height
|
||||||
|
*/
|
||||||
|
public setHeight(height: number){
|
||||||
|
this._colliderRequiresAutoSizing = false;
|
||||||
|
let box = this.shape as Box;
|
||||||
|
if (height != box.height){
|
||||||
|
// 更新框,改变边界,如果我们需要更新物理系统中的边界
|
||||||
|
box.updateBox(box.width, height);
|
||||||
|
if (this.entity && this._isParentEntityAddedToScene)
|
||||||
|
Physics.updateCollider(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public toString(){
|
||||||
|
return `[BoxCollider: bounds: ${this.bounds}]`;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,41 +1,48 @@
|
|||||||
class CircleCollider extends Collider {
|
module es {
|
||||||
public get radius(): number{
|
export class CircleCollider extends Collider {
|
||||||
return (this.shape as Circle).radius;
|
public get radius(): number {
|
||||||
}
|
return (this.shape as Circle).radius;
|
||||||
public set radius(value: number){
|
|
||||||
this.setRadius(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 创建一个有半径的圆
|
|
||||||
*
|
|
||||||
* @param radius
|
|
||||||
*/
|
|
||||||
constructor(radius?: number){
|
|
||||||
super();
|
|
||||||
|
|
||||||
if (radius)
|
|
||||||
this._colliderRequiresAutoSizing = true;
|
|
||||||
// 我们在这里插入一个1px的圆圈作为占位符
|
|
||||||
// 直到碰撞器被添加到实体并可以获得更精确的自动调整大小数据的下一帧
|
|
||||||
this.shape = new Circle(radius ? radius : 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 设置圆的半径
|
|
||||||
* @param radius
|
|
||||||
*/
|
|
||||||
public setRadius(radius: number): CircleCollider{
|
|
||||||
this._colliderRequiresAutoSizing = false;
|
|
||||||
let circle = this.shape as Circle;
|
|
||||||
if (radius != circle.radius){
|
|
||||||
circle.radius = radius;
|
|
||||||
circle._originalRadius = radius;
|
|
||||||
|
|
||||||
if (this.entity && this._isParentEntityAddedToScene)
|
|
||||||
Physics.updateCollider(this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return this;
|
public set radius(value: number) {
|
||||||
|
this.setRadius(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建一个有半径的圆
|
||||||
|
*
|
||||||
|
* @param radius
|
||||||
|
*/
|
||||||
|
constructor(radius?: number) {
|
||||||
|
super();
|
||||||
|
|
||||||
|
if (radius)
|
||||||
|
this._colliderRequiresAutoSizing = true;
|
||||||
|
// 我们在这里插入一个1px的圆圈作为占位符
|
||||||
|
// 直到碰撞器被添加到实体并可以获得更精确的自动调整大小数据的下一帧
|
||||||
|
this.shape = new Circle(radius ? radius : 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置圆的半径
|
||||||
|
* @param radius
|
||||||
|
*/
|
||||||
|
public setRadius(radius: number): CircleCollider {
|
||||||
|
this._colliderRequiresAutoSizing = false;
|
||||||
|
let circle = this.shape as Circle;
|
||||||
|
if (radius != circle.radius) {
|
||||||
|
circle.radius = radius;
|
||||||
|
circle._originalRadius = radius;
|
||||||
|
|
||||||
|
if (this.entity && this._isParentEntityAddedToScene)
|
||||||
|
Physics.updateCollider(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public toString() {
|
||||||
|
return `[CircleCollider: bounds: ${this.bounds}, radius: ${(this.shape as Circle).radius}]`
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,161 +1,242 @@
|
|||||||
abstract class Collider extends Component {
|
module es {
|
||||||
/** 对撞机的基本形状 */
|
export abstract class Collider extends Component {
|
||||||
public shape: Shape;
|
/**
|
||||||
/** 在处理冲突时,physicsLayer可以用作过滤器。Flags类有帮助位掩码的方法。 */
|
* 对撞机的基本形状
|
||||||
public physicsLayer = 1 << 0;
|
*/
|
||||||
/** 如果这个碰撞器是一个触发器,它将不会引起碰撞,但它仍然会触发事件 */
|
public shape: Shape;
|
||||||
public isTrigger: boolean;
|
|
||||||
/**
|
|
||||||
* 这个对撞机在物理系统注册时的边界。
|
|
||||||
* 存储这个允许我们始终能够安全地从物理系统中移除对撞机,即使它在试图移除它之前已经被移动了。
|
|
||||||
*/
|
|
||||||
public registeredPhysicsBounds: Rectangle = new Rectangle();
|
|
||||||
/** 如果为true,碰撞器将根据附加的变换缩放和旋转 */
|
|
||||||
public shouldColliderScaleAndRotateWithTransform = true;
|
|
||||||
/** 默认为所有层。 */
|
|
||||||
public collidesWithLayers = Physics.allLayers;
|
|
||||||
|
|
||||||
public _localOffsetLength: number;
|
/**
|
||||||
/** 标记来跟踪我们的实体是否被添加到场景中 */
|
* 将localOffset添加到实体。获取碰撞器几何图形的最终位置。
|
||||||
protected _isParentEntityAddedToScene;
|
* 允许向一个实体添加多个碰撞器并分别定位,还允许你设置缩放/旋转
|
||||||
protected _colliderRequiresAutoSizing;
|
*/
|
||||||
protected _localOffset: Vector2 = new Vector2(0, 0);
|
public get localOffset(): Vector2 {
|
||||||
/** 标记来记录我们是否注册了物理系统 */
|
return this._localOffset;
|
||||||
protected _isColliderRegistered;
|
}
|
||||||
|
|
||||||
public get bounds(): Rectangle {
|
/**
|
||||||
this.shape.recalculateBounds(this);
|
* 将localOffset添加到实体。获取碰撞器几何图形的最终位置。
|
||||||
return this.shape.bounds;
|
* 允许向一个实体添加多个碰撞器并分别定位,还允许你设置缩放/旋转
|
||||||
}
|
* @param value
|
||||||
|
*/
|
||||||
|
public set localOffset(value: Vector2) {
|
||||||
|
this.setLocalOffset(value);
|
||||||
|
}
|
||||||
|
|
||||||
public get localOffset() {
|
/**
|
||||||
return this._localOffset;
|
* 镖师碰撞器的绝对位置
|
||||||
}
|
*/
|
||||||
|
public get absolutePosition(): Vector2 {
|
||||||
|
return Vector2.add(this.entity.transform.position, this._localOffset);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 将localOffset添加到实体。获取碰撞器的最终位置。这允许您向一个实体添加多个碰撞器并分别定位它们。
|
* 封装变换。如果碰撞器没和实体一起旋转 则返回transform.rotation
|
||||||
*/
|
*/
|
||||||
public set localOffset(value: Vector2) {
|
public get rotation(): number {
|
||||||
this.setLocalOffset(value);
|
if (this.shouldColliderScaleAndRotateWithTransform && this.entity)
|
||||||
}
|
return this.entity.transform.rotation;
|
||||||
|
|
||||||
public setLocalOffset(offset: Vector2) {
|
return 0;
|
||||||
if (this._localOffset != offset) {
|
}
|
||||||
this.unregisterColliderWithPhysicsSystem();
|
|
||||||
this._localOffset = offset;
|
/**
|
||||||
this._localOffsetLength = this._localOffset.length();
|
* 如果这个碰撞器是一个触发器,它将不会引起碰撞,但它仍然会触发事件
|
||||||
|
*/
|
||||||
|
public isTrigger: boolean;
|
||||||
|
/**
|
||||||
|
* 在处理冲突时,physicsLayer可以用作过滤器。Flags类有帮助位掩码的方法
|
||||||
|
*/
|
||||||
|
public physicsLayer = 1 << 0;
|
||||||
|
/**
|
||||||
|
* 碰撞器在使用移动器移动时应该碰撞的层
|
||||||
|
* 默认为所有层
|
||||||
|
*/
|
||||||
|
public collidesWithLayers = Physics.allLayers;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 如果为true,碰撞器将根据附加的变换缩放和旋转
|
||||||
|
*/
|
||||||
|
public shouldColliderScaleAndRotateWithTransform = true;
|
||||||
|
|
||||||
|
public get bounds(): Rectangle {
|
||||||
|
if (this._isPositionDirty || this._isRotationDirty){
|
||||||
|
this.shape.recalculateBounds(this);
|
||||||
|
this._isPositionDirty = this._isRotationDirty = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.shape.bounds;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 这个对撞机在物理系统注册时的边界。
|
||||||
|
* 存储这个允许我们始终能够安全地从物理系统中移除对撞机,即使它在试图移除它之前已经被移动了。
|
||||||
|
*/
|
||||||
|
public registeredPhysicsBounds: Rectangle = new Rectangle();
|
||||||
|
protected _colliderRequiresAutoSizing;
|
||||||
|
protected _localOffset: Vector2 = Vector2.zero;
|
||||||
|
public _localOffsetLength: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 标记来跟踪我们的实体是否被添加到场景中
|
||||||
|
*/
|
||||||
|
protected _isParentEntityAddedToScene;
|
||||||
|
/**
|
||||||
|
* 标记来记录我们是否注册了物理系统
|
||||||
|
*/
|
||||||
|
protected _isColliderRegistered;
|
||||||
|
|
||||||
|
public _isPositionDirty: boolean = true;
|
||||||
|
public _isRotationDirty: boolean = true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将localOffset添加到实体。获取碰撞器的最终位置。
|
||||||
|
* 这允许您向一个实体添加多个碰撞器并分别定位它们。
|
||||||
|
* @param offset
|
||||||
|
*/
|
||||||
|
public setLocalOffset(offset: Vector2): Collider {
|
||||||
|
if (this._localOffset != offset) {
|
||||||
|
this.unregisterColliderWithPhysicsSystem();
|
||||||
|
this._localOffset = offset;
|
||||||
|
this._localOffsetLength = this._localOffset.length();
|
||||||
|
this._isPositionDirty = true;
|
||||||
|
this.registerColliderWithPhysicsSystem();
|
||||||
|
}
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 如果为true,碰撞器将根据附加的变换缩放和旋转
|
||||||
|
* @param shouldColliderScaleAndRotationWithTransform
|
||||||
|
*/
|
||||||
|
public setShouldColliderScaleAndRotateWithTransform(shouldColliderScaleAndRotationWithTransform: boolean): Collider {
|
||||||
|
this.shouldColliderScaleAndRotateWithTransform = shouldColliderScaleAndRotationWithTransform;
|
||||||
|
this._isPositionDirty = this._isRotationDirty = true;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public onAddedToEntity() {
|
||||||
|
if (this._colliderRequiresAutoSizing) {
|
||||||
|
if (!(this instanceof BoxCollider || this instanceof CircleCollider)) {
|
||||||
|
console.error("Only box and circle colliders can be created automatically");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let renderable = this.entity.getComponent<RenderableComponent>(RenderableComponent);
|
||||||
|
if (renderable) {
|
||||||
|
let renderableBounds = renderable.bounds;
|
||||||
|
|
||||||
|
// 这里我们需要大小*反尺度,因为当我们自动调整碰撞器的大小时,它需要没有缩放的渲染
|
||||||
|
let width = renderableBounds.width / this.entity.scale.x;
|
||||||
|
let height = renderableBounds.height / this.entity.scale.y;
|
||||||
|
// 圆碰撞器需要特别注意原点
|
||||||
|
if (this instanceof CircleCollider) {
|
||||||
|
this.radius = Math.max(width, height) * 0.5;
|
||||||
|
} else {
|
||||||
|
this.width = width;
|
||||||
|
this.height = height;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取渲染的中心,将其转移到本地坐标,并使用它作为碰撞器的localOffset
|
||||||
|
this.localOffset = Vector2.subtract(renderableBounds.center, this.entity.transform.position);
|
||||||
|
} else {
|
||||||
|
console.warn("Collider has no shape and no RenderableComponent. Can't figure out how to size it.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this._isParentEntityAddedToScene = true;
|
||||||
this.registerColliderWithPhysicsSystem();
|
this.registerColliderWithPhysicsSystem();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
public onRemovedFromEntity() {
|
||||||
* 父实体会在不同的时间调用它(当添加到场景,启用,等等)
|
this.unregisterColliderWithPhysicsSystem();
|
||||||
*/
|
this._isParentEntityAddedToScene = false;
|
||||||
public registerColliderWithPhysicsSystem() {
|
|
||||||
// 如果在将我们添加到实体之前更改了origin等属性,则实体可以为null
|
|
||||||
if (this._isParentEntityAddedToScene && !this._isColliderRegistered) {
|
|
||||||
Physics.addCollider(this);
|
|
||||||
this._isColliderRegistered = true;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
public onEntityTransformChanged(comp: transform.Component) {
|
||||||
* 父实体会在不同的时候调用它(从场景中移除,禁用,等等)
|
switch (comp) {
|
||||||
*/
|
case transform.Component.position:
|
||||||
public unregisterColliderWithPhysicsSystem() {
|
this._isPositionDirty = true;
|
||||||
if (this._isParentEntityAddedToScene && this._isColliderRegistered) {
|
break;
|
||||||
Physics.removeCollider(this);
|
case transform.Component.scale:
|
||||||
}
|
this._isPositionDirty = true;
|
||||||
this._isColliderRegistered = false;
|
break;
|
||||||
}
|
case transform.Component.rotation:
|
||||||
|
this._isRotationDirty = true;
|
||||||
/**
|
break;
|
||||||
* 检查这个形状是否与物理系统中的其他对撞机重叠
|
|
||||||
* @param other
|
|
||||||
*/
|
|
||||||
public overlaps(other: Collider) {
|
|
||||||
return this.shape.overlaps(other.shape);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 检查这个与运动应用的碰撞器(移动向量)是否与碰撞器碰撞。如果是这样,将返回true,并且结果将填充碰撞数据。
|
|
||||||
* @param collider
|
|
||||||
* @param motion
|
|
||||||
*/
|
|
||||||
public collidesWith(collider: Collider, motion: Vector2) {
|
|
||||||
// 改变形状的位置,使它在移动后的位置,这样我们可以检查重叠
|
|
||||||
let oldPosition = this.shape.position;
|
|
||||||
this.shape.position = Vector2.add(this.shape.position, motion);
|
|
||||||
|
|
||||||
let result = this.shape.collidesWithShape(collider.shape);
|
|
||||||
if (result)
|
|
||||||
result.collider = collider;
|
|
||||||
|
|
||||||
// 将图形位置返回到检查前的位置
|
|
||||||
this.shape.position = oldPosition;
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public onAddedToEntity() {
|
|
||||||
if (this._colliderRequiresAutoSizing) {
|
|
||||||
if (!(this instanceof BoxCollider || this instanceof CircleCollider)) {
|
|
||||||
console.error("Only box and circle colliders can be created automatically");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let renderable = this.entity.getComponent<RenderableComponent>(RenderableComponent);
|
if (this._isColliderRegistered)
|
||||||
if (renderable) {
|
Physics.updateCollider(this);
|
||||||
let bounds = renderable.bounds;
|
}
|
||||||
|
|
||||||
// 这里我们需要大小*反尺度,因为当我们自动调整碰撞器的大小时,它需要没有缩放的渲染
|
public onEnabled() {
|
||||||
let width = bounds.width / this.entity.scale.x;
|
this.registerColliderWithPhysicsSystem();
|
||||||
let height = bounds.height / this.entity.scale.y;
|
this._isPositionDirty = this._isRotationDirty = true;
|
||||||
|
}
|
||||||
|
|
||||||
// 圆碰撞器需要特别注意原点
|
public onDisabled() {
|
||||||
if (this instanceof CircleCollider){
|
this.unregisterColliderWithPhysicsSystem();
|
||||||
let circleCollider = this as CircleCollider;
|
}
|
||||||
circleCollider.radius = Math.max(width, height) * 0.5;
|
|
||||||
|
|
||||||
this.localOffset = bounds.location;
|
/**
|
||||||
} else {
|
* 父实体会在不同的时间调用它(当添加到场景,启用,等等)
|
||||||
let boxCollider = this;
|
*/
|
||||||
boxCollider.width = width;
|
public registerColliderWithPhysicsSystem() {
|
||||||
boxCollider.height = height;
|
// 如果在将我们添加到实体之前更改了origin等属性,则实体可以为null
|
||||||
|
if (this._isParentEntityAddedToScene && !this._isColliderRegistered) {
|
||||||
this.localOffset = bounds.location;
|
Physics.addCollider(this);
|
||||||
}
|
this._isColliderRegistered = true;
|
||||||
} else {
|
|
||||||
console.warn("Collider has no shape and no RenderableComponent. Can't figure out how to size it.");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this._isParentEntityAddedToScene = true;
|
/**
|
||||||
this.registerColliderWithPhysicsSystem();
|
* 父实体会在不同的时候调用它(从场景中移除,禁用,等等)
|
||||||
}
|
*/
|
||||||
|
public unregisterColliderWithPhysicsSystem() {
|
||||||
|
if (this._isParentEntityAddedToScene && this._isColliderRegistered) {
|
||||||
|
Physics.removeCollider(this);
|
||||||
|
}
|
||||||
|
this._isColliderRegistered = false;
|
||||||
|
}
|
||||||
|
|
||||||
public onRemovedFromEntity() {
|
/**
|
||||||
this.unregisterColliderWithPhysicsSystem();
|
* 检查这个形状是否与物理系统中的其他对撞机重叠
|
||||||
this._isParentEntityAddedToScene = false;
|
* @param other
|
||||||
}
|
*/
|
||||||
|
public overlaps(other: Collider): boolean {
|
||||||
|
return this.shape.overlaps(other.shape);
|
||||||
|
}
|
||||||
|
|
||||||
public onEnabled() {
|
/**
|
||||||
this.registerColliderWithPhysicsSystem();
|
* 检查这个与运动应用的碰撞器(移动向量)是否与碰撞器碰撞。如果是这样,将返回true,并且结果将填充碰撞数据。
|
||||||
}
|
* @param collider
|
||||||
|
* @param motion
|
||||||
|
* @param result
|
||||||
|
*/
|
||||||
|
public collidesWith(collider: Collider, motion: Vector2, result: CollisionResult): boolean {
|
||||||
|
// 改变形状的位置,使它在移动后的位置,这样我们可以检查重叠
|
||||||
|
let oldPosition = this.entity.position;
|
||||||
|
this.entity.position = this.entity.position.add(motion);
|
||||||
|
|
||||||
public onDisabled() {
|
let didCollide = this.shape.collidesWithShape(collider.shape, result);
|
||||||
this.unregisterColliderWithPhysicsSystem();
|
if (didCollide)
|
||||||
}
|
result.collider = collider;
|
||||||
|
|
||||||
public onEntityTransformChanged(comp: TransformComponent) {
|
// 将图形位置返回到检查前的位置
|
||||||
if (this._isColliderRegistered)
|
this.entity.position = oldPosition;
|
||||||
Physics.updateCollider(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
public update(){
|
return didCollide;
|
||||||
let renderable = this.entity.getComponent<RenderableComponent>(RenderableComponent);
|
}
|
||||||
if (renderable){
|
|
||||||
this.$setX(renderable.x + this.localOffset.x);
|
public clone(): Component{
|
||||||
this.$setY(renderable.y + this.localOffset.y);
|
let collider = ObjectUtils.clone<Collider>(this);
|
||||||
|
collider.entity = null;
|
||||||
|
|
||||||
|
if (this.shape)
|
||||||
|
collider.shape = this.shape.clone();
|
||||||
|
|
||||||
|
return collider;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,24 +1,26 @@
|
|||||||
/**
|
module es {
|
||||||
* 多边形应该以顺时针方式定义
|
|
||||||
*/
|
|
||||||
class PolygonCollider extends Collider {
|
|
||||||
/**
|
/**
|
||||||
* 如果这些点没有居中,它们将以localOffset的差异为居中。
|
* 多边形应该以顺时针方式定义
|
||||||
* @param points
|
|
||||||
*/
|
*/
|
||||||
constructor(points: Vector2[]){
|
export class PolygonCollider extends Collider {
|
||||||
super();
|
/**
|
||||||
|
* 如果这些点没有居中,它们将以localOffset的差异为居中。
|
||||||
|
* @param points
|
||||||
|
*/
|
||||||
|
constructor(points: Vector2[]) {
|
||||||
|
super();
|
||||||
|
|
||||||
// 第一点和最后一点决不能相同。我们想要一个开放的多边形
|
// 第一点和最后一点决不能相同。我们想要一个开放的多边形
|
||||||
let isPolygonClosed = points[0] == points[points.length - 1];
|
let isPolygonClosed = points[0] == points[points.length - 1];
|
||||||
|
|
||||||
// 最后一个移除
|
// 最后一个移除
|
||||||
if (isPolygonClosed)
|
if (isPolygonClosed)
|
||||||
points.splice(points.length - 1, 1);
|
points.splice(points.length - 1, 1);
|
||||||
|
|
||||||
let center = Polygon.findPolygonCenter(points);
|
let center = Polygon.findPolygonCenter(points);
|
||||||
this.setLocalOffset(center);
|
this.setLocalOffset(center);
|
||||||
Polygon.recenterPolygonVerts(points);
|
Polygon.recenterPolygonVerts(points);
|
||||||
this.shape = new Polygon(points);
|
this.shape = new Polygon(points);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,23 @@
|
|||||||
interface ITriggerListener {
|
module es{
|
||||||
onTriggerEnter(other: Collider, local: Collider);
|
/**
|
||||||
onTriggerExit(other: Collider, local: Collider);
|
* 当添加到组件时,每当实体上的冲突器与另一个组件重叠/退出时,将调用这些方法。
|
||||||
|
* ITriggerListener方法将在实现接口的触发器实体上的任何组件上调用。
|
||||||
|
* 注意,这个接口只与Mover类一起工作
|
||||||
|
*/
|
||||||
|
export interface ITriggerListener {
|
||||||
|
/**
|
||||||
|
* 当碰撞器与触发碰撞器相交时调用。这是在触发碰撞器和触发碰撞器上调用的。
|
||||||
|
* 移动必须由Mover/ProjectileMover方法处理,以使其自动工作。
|
||||||
|
* @param other
|
||||||
|
* @param local
|
||||||
|
*/
|
||||||
|
onTriggerEnter(other: Collider, local: Collider);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 当另一个碰撞器离开触发碰撞器时调用
|
||||||
|
* @param other
|
||||||
|
* @param local
|
||||||
|
*/
|
||||||
|
onTriggerExit(other: Collider, local: Collider);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,93 +1,89 @@
|
|||||||
/**
|
module es {
|
||||||
* 辅助类说明了一种处理移动的方法,它考虑了包括触发器在内的所有冲突。
|
|
||||||
* ITriggerListener接口用于管理对移动过程中违反的任何触发器的回调。
|
|
||||||
* 一个物体只能通过移动器移动。要正确报告触发器的move方法。
|
|
||||||
*
|
|
||||||
* 请注意,多个移动者相互交互将多次调用ITriggerListener。
|
|
||||||
*/
|
|
||||||
class Mover extends Component {
|
|
||||||
private _triggerHelper: ColliderTriggerHelper;
|
|
||||||
|
|
||||||
public onAddedToEntity(){
|
|
||||||
this._triggerHelper = new ColliderTriggerHelper(this.entity);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 计算修改运动矢量的运动,以考虑移动时可能发生的碰撞
|
* 辅助类说明了一种处理移动的方法,它考虑了包括触发器在内的所有冲突。
|
||||||
* @param motion
|
* ITriggerListener接口用于管理对移动过程中违反的任何触发器的回调。
|
||||||
|
* 一个物体只能通过移动器移动。要正确报告触发器的move方法。
|
||||||
|
*
|
||||||
|
* 请注意,多个移动者相互交互将多次调用ITriggerListener。
|
||||||
*/
|
*/
|
||||||
public calculateMovement(motion: Vector2){
|
export class Mover extends Component {
|
||||||
let collisionResult = new CollisionResult();
|
private _triggerHelper: ColliderTriggerHelper;
|
||||||
|
|
||||||
if (!this.entity.getComponent(Collider) || !this._triggerHelper){
|
public onAddedToEntity(){
|
||||||
return null;
|
this._triggerHelper = new ColliderTriggerHelper(this.entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 移动所有的非触发碰撞器并获得最近的碰撞
|
/**
|
||||||
let colliders: Collider[] = this.entity.getComponents(Collider);
|
* 计算修改运动矢量的运动,以考虑移动时可能发生的碰撞
|
||||||
for (let i = 0; i < colliders.length; i ++){
|
* @param motion
|
||||||
let collider = colliders[i];
|
* @param collisionResult
|
||||||
|
*/
|
||||||
|
public calculateMovement(motion: Vector2, collisionResult: CollisionResult): boolean{
|
||||||
|
if (!this.entity.getComponent(Collider) || !this._triggerHelper){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// 不检测触发器 在我们移动后会重新访问它
|
// 移动所有的非触发碰撞器并获得最近的碰撞
|
||||||
if (collider.isTrigger)
|
let colliders: Collider[] = this.entity.getComponents(Collider);
|
||||||
continue;
|
for (let i = 0; i < colliders.length; i ++){
|
||||||
|
let collider = colliders[i];
|
||||||
|
|
||||||
// 获取我们在新位置可能发生碰撞的任何东西
|
// 不检测触发器 在我们移动后会重新访问它
|
||||||
let bounds = collider.bounds;
|
if (collider.isTrigger)
|
||||||
bounds.x += motion.x;
|
|
||||||
bounds.y += motion.y;
|
|
||||||
let boxcastResult = Physics.boxcastBroadphaseExcludingSelf(collider, bounds, collider.collidesWithLayers);
|
|
||||||
bounds = boxcastResult.bounds;
|
|
||||||
let neighbors = boxcastResult.tempHashSet;
|
|
||||||
|
|
||||||
for (let j = 0; j < neighbors.length; j ++){
|
|
||||||
let neighbor = neighbors[j];
|
|
||||||
// 不检测触发器
|
|
||||||
if (neighbor.isTrigger)
|
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
let _internalcollisionResult = collider.collidesWith(neighbor, motion);
|
// 获取我们在新位置可能发生碰撞的任何东西
|
||||||
if (_internalcollisionResult){
|
let bounds = collider.bounds;
|
||||||
// 如果碰撞 则退回之前的移动量
|
bounds.x += motion.x;
|
||||||
motion = Vector2.subtract(motion, _internalcollisionResult.minimumTranslationVector);
|
bounds.y += motion.y;
|
||||||
|
let neighbors = Physics.boxcastBroadphaseExcludingSelf(collider, bounds, collider.collidesWithLayers);
|
||||||
|
|
||||||
// 如果我们碰到多个对象,为了简单起见,只取第一个。
|
for (let j = 0; j < neighbors.length; j ++){
|
||||||
if (_internalcollisionResult.collider){
|
let neighbor = neighbors[j];
|
||||||
collisionResult = _internalcollisionResult;
|
// 不检测触发器
|
||||||
|
if (neighbor.isTrigger)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
let _internalcollisionResult: CollisionResult = new CollisionResult();
|
||||||
|
if (collider.collidesWith(neighbor, motion, _internalcollisionResult)){
|
||||||
|
// 如果碰撞 则退回之前的移动量
|
||||||
|
motion = motion.subtract(_internalcollisionResult.minimumTranslationVector);
|
||||||
|
|
||||||
|
// 如果我们碰到多个对象,为了简单起见,只取第一个。
|
||||||
|
if (_internalcollisionResult.collider != null){
|
||||||
|
collisionResult = _internalcollisionResult;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ListPool.free(colliders);
|
||||||
|
|
||||||
|
return collisionResult.collider != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
ListPool.free(colliders);
|
/**
|
||||||
|
* 将calculatemomovement应用到实体并更新triggerHelper
|
||||||
|
* @param motion
|
||||||
|
*/
|
||||||
|
public applyMovement(motion: Vector2){
|
||||||
|
// 移动实体到它的新位置,如果我们有一个碰撞,否则移动全部数量。当碰撞发生时,运动被更新
|
||||||
|
this.entity.position = Vector2.add(this.entity.position, motion);
|
||||||
|
|
||||||
return {collisionResult: collisionResult, motion: motion};
|
// 对所有是触发器的碰撞器与所有宽相位碰撞器进行重叠检查。任何重叠都会导致触发事件。
|
||||||
}
|
if (this._triggerHelper)
|
||||||
|
this._triggerHelper.update();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 将calculatemomovement应用到实体并更新triggerHelper
|
* 通过调用calculateMovement和applyMovement来移动考虑碰撞的实体;
|
||||||
* @param motion
|
* @param motion
|
||||||
*/
|
* @param collisionResult
|
||||||
public applyMovement(motion: Vector2){
|
*/
|
||||||
// 移动实体到它的新位置,如果我们有一个碰撞,否则移动全部数量。当碰撞发生时,运动被更新
|
public move(motion: Vector2, collisionResult: CollisionResult){
|
||||||
this.entity.position = Vector2.add(this.entity.position, motion);
|
this.calculateMovement(motion, collisionResult);
|
||||||
|
this.applyMovement(motion);
|
||||||
// 对所有是触发器的碰撞器与所有宽相位碰撞器进行重叠检查。任何重叠都会导致触发事件。
|
return collisionResult.collider != null;
|
||||||
if (this._triggerHelper)
|
}
|
||||||
this._triggerHelper.update();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 通过调用calculateMovement和applyMovement来移动考虑碰撞的实体;
|
|
||||||
* @param motion
|
|
||||||
*/
|
|
||||||
public move(motion: Vector2){
|
|
||||||
let movementResult = this.calculateMovement(motion);
|
|
||||||
let collisionResult = movementResult.collisionResult;
|
|
||||||
motion = movementResult.motion;
|
|
||||||
|
|
||||||
this.applyMovement(motion);
|
|
||||||
|
|
||||||
return collisionResult;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,56 +1,58 @@
|
|||||||
/**
|
module es {
|
||||||
* 只向itriggerlistener报告冲突的移动器
|
|
||||||
* 该对象将始终移动完整的距离
|
|
||||||
*/
|
|
||||||
class ProjectileMover extends Component {
|
|
||||||
private _tempTriggerList: ITriggerListener[] = [];
|
|
||||||
private _collider: Collider;
|
|
||||||
|
|
||||||
public onAddedToEntity(){
|
|
||||||
this._collider = this.entity.getComponent<Collider>(Collider);
|
|
||||||
if (!this._collider)
|
|
||||||
console.warn("ProjectileMover has no Collider. ProjectilMover requires a Collider!");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 移动考虑碰撞的实体
|
* 只向itriggerlistener报告冲突的移动器
|
||||||
* @param motion
|
* 该对象将始终移动完整的距离
|
||||||
*/
|
*/
|
||||||
public move(motion: Vector2): boolean{
|
export class ProjectileMover extends Component {
|
||||||
if (!this._collider)
|
private _tempTriggerList: ITriggerListener[] = [];
|
||||||
return false;
|
private _collider: Collider;
|
||||||
|
|
||||||
let didCollide = false;
|
public onAddedToEntity(){
|
||||||
|
this._collider = this.entity.getComponent<Collider>(Collider);
|
||||||
|
if (!this._collider)
|
||||||
|
console.warn("ProjectileMover has no Collider. ProjectilMover requires a Collider!");
|
||||||
|
}
|
||||||
|
|
||||||
// 获取我们在新位置可能发生碰撞的任何东西
|
/**
|
||||||
this.entity.position = Vector2.add(this.entity.position, motion);
|
* 移动考虑碰撞的实体
|
||||||
|
* @param motion
|
||||||
|
*/
|
||||||
|
public move(motion: Vector2): boolean{
|
||||||
|
if (!this._collider)
|
||||||
|
return false;
|
||||||
|
|
||||||
// 获取任何可能在新位置发生碰撞的东西
|
let didCollide = false;
|
||||||
let neighbors = Physics.boxcastBroadphase(this._collider.bounds, this._collider.collidesWithLayers);
|
|
||||||
for (let i = 0; i < neighbors.colliders.length; i ++){
|
// 获取我们在新位置可能发生碰撞的任何东西
|
||||||
let neighbor = neighbors.colliders[i];
|
this.entity.position = Vector2.add(this.entity.position, motion);
|
||||||
if (this._collider.overlaps(neighbor) && neighbor.enabled){
|
|
||||||
didCollide = true;
|
// 获取任何可能在新位置发生碰撞的东西
|
||||||
this.notifyTriggerListeners(this._collider, neighbor);
|
let neighbors = Physics.boxcastBroadphase(this._collider.bounds, this._collider.collidesWithLayers);
|
||||||
|
for (let i = 0; i < neighbors.length; i ++){
|
||||||
|
let neighbor = neighbors[i];
|
||||||
|
if (this._collider.overlaps(neighbor) && neighbor.enabled){
|
||||||
|
didCollide = true;
|
||||||
|
this.notifyTriggerListeners(this._collider, neighbor);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return didCollide;
|
||||||
}
|
}
|
||||||
|
|
||||||
return didCollide;
|
private notifyTriggerListeners(self: Collider, other: Collider){
|
||||||
}
|
// 通知我们重叠的碰撞器实体上的任何侦听器
|
||||||
|
other.entity.getComponents("ITriggerListener", this._tempTriggerList);
|
||||||
|
for (let i = 0; i < this._tempTriggerList.length; i ++){
|
||||||
|
this._tempTriggerList[i].onTriggerEnter(self, other);
|
||||||
|
}
|
||||||
|
this._tempTriggerList.length = 0;
|
||||||
|
|
||||||
private notifyTriggerListeners(self: Collider, other: Collider){
|
// 通知此实体上的任何侦听器
|
||||||
// 通知我们重叠的碰撞器实体上的任何侦听器
|
this.entity.getComponents("ITriggerListener", this._tempTriggerList);
|
||||||
other.entity.getComponents("ITriggerListener", this._tempTriggerList);
|
for (let i = 0; i < this._tempTriggerList.length; i ++){
|
||||||
for (let i = 0; i < this._tempTriggerList.length; i ++){
|
this._tempTriggerList[i].onTriggerEnter(other, self);
|
||||||
this._tempTriggerList[i].onTriggerEnter(self, other);
|
}
|
||||||
|
this._tempTriggerList.length = 0;
|
||||||
}
|
}
|
||||||
this._tempTriggerList.length = 0;
|
|
||||||
|
|
||||||
// 通知此实体上的任何侦听器
|
|
||||||
this.entity.getComponents("ITriggerListener", this._tempTriggerList);
|
|
||||||
for (let i = 0; i < this._tempTriggerList.length; i ++){
|
|
||||||
this._tempTriggerList[i].onTriggerEnter(other, self);
|
|
||||||
}
|
|
||||||
this._tempTriggerList.length = 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,6 @@
|
|||||||
/** 回收实例的组件类型。 */
|
module es {
|
||||||
abstract class PooledComponent extends Component {
|
/** 回收实例的组件类型。 */
|
||||||
public abstract reset();
|
export abstract class PooledComponent extends Component {
|
||||||
|
public abstract reset();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,56 +1,189 @@
|
|||||||
///<reference path="./PooledComponent.ts" />
|
///<reference path="./PooledComponent.ts" />
|
||||||
/**
|
module es {
|
||||||
* 所有可渲染组件的基类
|
/**
|
||||||
*/
|
* 所有可渲染组件的基类
|
||||||
abstract class RenderableComponent extends PooledComponent implements IRenderable {
|
*/
|
||||||
private _isVisible: boolean;
|
export abstract class RenderableComponent extends Component implements IRenderable {
|
||||||
protected _areBoundsDirty = true;
|
/**
|
||||||
protected _bounds: Rectangle = new Rectangle();
|
* 用于装载egret显示对象
|
||||||
protected _localOffset: Vector2 = Vector2.zero;
|
*/
|
||||||
|
public displayObject: egret.DisplayObject = new egret.DisplayObject();
|
||||||
|
/**
|
||||||
|
* renderableComponent的宽度
|
||||||
|
* 如果你不重写bounds属性则需要实现这个
|
||||||
|
*/
|
||||||
|
public get width() {
|
||||||
|
return this.bounds.width;
|
||||||
|
}
|
||||||
|
|
||||||
public color: number = 0x000000;
|
/**
|
||||||
|
* renderableComponent的高度
|
||||||
|
* 如果你不重写bounds属性则需要实现这个
|
||||||
|
*/
|
||||||
|
public get height() {
|
||||||
|
return this.bounds.height;
|
||||||
|
}
|
||||||
|
|
||||||
public get width(){
|
/**
|
||||||
return this.getWidth();
|
* 这个物体的AABB, 用于相机剔除
|
||||||
}
|
*/
|
||||||
|
public get bounds(): Rectangle {
|
||||||
|
if (this._areBoundsDirty){
|
||||||
|
this._bounds.calculateBounds(this.entity.transform.position, this._localOffset, Vector2.zero,
|
||||||
|
this.entity.transform.scale, this.entity.transform.rotation, this.width, this.height);
|
||||||
|
this._areBoundsDirty = false;
|
||||||
|
}
|
||||||
|
|
||||||
public get height(){
|
return this._bounds;
|
||||||
return this.getHeight();
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public get isVisible(){
|
/**
|
||||||
return this._isVisible;
|
* 较低的渲染层在前面,较高的在后面
|
||||||
}
|
*/
|
||||||
|
public get renderLayer(): number{
|
||||||
|
return this._renderLayer;
|
||||||
|
}
|
||||||
|
|
||||||
public set isVisible(value: boolean){
|
public set renderLayer(value: number){
|
||||||
this._isVisible = value;
|
|
||||||
|
|
||||||
if (this._isVisible)
|
}
|
||||||
this.onBecameVisible();
|
|
||||||
else
|
|
||||||
this.onBecameInvisible();
|
|
||||||
}
|
|
||||||
|
|
||||||
public get bounds(): Rectangle{
|
/**
|
||||||
return new Rectangle(this.getBounds().x, this.getBounds().y, this.getBounds().width, this.getBounds().height);
|
* 用于着色器处理精灵
|
||||||
}
|
*/
|
||||||
|
public color: number = 0x000000;
|
||||||
|
|
||||||
protected getWidth(){
|
/**
|
||||||
return this.bounds.width;
|
* 从父实体的偏移量。用于向需要特定定位的实体
|
||||||
}
|
*/
|
||||||
|
public get localOffset(): Vector2{
|
||||||
|
return this._localOffset;
|
||||||
|
}
|
||||||
|
|
||||||
protected getHeight(){
|
/**
|
||||||
return this.bounds.height;
|
* 从父实体的偏移量。用于向需要特定定位的实体
|
||||||
}
|
* @param value
|
||||||
|
*/
|
||||||
|
public set localOffset(value: Vector2){
|
||||||
|
this.setLocalOffset(value);
|
||||||
|
}
|
||||||
|
|
||||||
protected onBecameVisible(){}
|
/**
|
||||||
|
* 可渲染的可见性。状态的改变会调用onBecameVisible/onBecameInvisible方法
|
||||||
|
*/
|
||||||
|
public get isVisible() {
|
||||||
|
return this._isVisible;
|
||||||
|
}
|
||||||
|
|
||||||
protected onBecameInvisible(){}
|
/**
|
||||||
|
* 可渲染的可见性。状态的改变会调用onBecameVisible/onBecameInvisible方法
|
||||||
|
* @param value
|
||||||
|
*/
|
||||||
|
public set isVisible(value: boolean) {
|
||||||
|
if (this._isVisible != value){
|
||||||
|
this._isVisible = value;
|
||||||
|
|
||||||
public abstract render(camera: Camera);
|
if (this._isVisible)
|
||||||
|
this.onBecameVisible();
|
||||||
|
else
|
||||||
|
this.onBecameInvisible();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public isVisibleFromCamera(camera: Camera): boolean{
|
protected _localOffset: Vector2 = Vector2.zero;
|
||||||
this.isVisible = camera.getBounds().intersects(this.getBounds());
|
protected _renderLayer: number = 0;
|
||||||
return this.isVisible;
|
protected _bounds: Rectangle = new Rectangle();
|
||||||
|
private _isVisible: boolean;
|
||||||
|
protected _areBoundsDirty = true;
|
||||||
|
|
||||||
|
public onEntityTransformChanged(comp: transform.Component) {
|
||||||
|
this._areBoundsDirty = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 由渲染器调用。可以使用摄像机进行剔除
|
||||||
|
* @param camera
|
||||||
|
*/
|
||||||
|
public abstract render(camera: Camera);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 当renderableComponent进入相机框架时调用
|
||||||
|
* 如果渲染器不适用isVisibleFromCamera进行剔除检查 这些方法不会被调用
|
||||||
|
*/
|
||||||
|
protected onBecameVisible() {
|
||||||
|
this.displayObject.visible = this.isVisible;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 当renderableComponent离开相机框架时调用
|
||||||
|
* 如果渲染器不适用isVisibleFromCamera进行剔除检查 这些方法不会被调用
|
||||||
|
*/
|
||||||
|
protected onBecameInvisible() {
|
||||||
|
this.displayObject.visible = this.isVisible;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 如果renderableComponent的边界与camera.bounds相交 返回true
|
||||||
|
* 用于处理isVisible标志的状态开关
|
||||||
|
* 在渲染方法中使用这个方法来决定是否渲染
|
||||||
|
* @param camera
|
||||||
|
*/
|
||||||
|
public isVisibleFromCamera(camera: Camera): boolean {
|
||||||
|
this.isVisible = camera.bounds.intersects(this.bounds);
|
||||||
|
return this.isVisible;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 较低的渲染层在前面,较高的在后面
|
||||||
|
* @param renderLayer
|
||||||
|
*/
|
||||||
|
public setRenderLayer(renderLayer: number): RenderableComponent{
|
||||||
|
if (renderLayer != this._renderLayer){
|
||||||
|
let oldRenderLayer = this._renderLayer;
|
||||||
|
this._renderLayer = renderLayer;
|
||||||
|
|
||||||
|
// 如果该组件拥有一个实体,那么是由ComponentList管理,需要通知它改变了渲染层
|
||||||
|
if (this.entity && this.entity.scene)
|
||||||
|
this.entity.scene.renderableComponents.updateRenderableRenderLayer(this, oldRenderLayer, this._renderLayer);
|
||||||
|
}
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用于着色器处理精灵
|
||||||
|
* @param color
|
||||||
|
*/
|
||||||
|
public setColor(color: number): RenderableComponent{
|
||||||
|
this.color = color;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从父实体的偏移量。用于向需要特定定位的实体
|
||||||
|
* @param offset
|
||||||
|
*/
|
||||||
|
public setLocalOffset(offset: Vector2): RenderableComponent{
|
||||||
|
if (this._localOffset != offset){
|
||||||
|
this._localOffset = offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 进行状态同步
|
||||||
|
*/
|
||||||
|
public sync(camera: Camera){
|
||||||
|
this.displayObject.x = this.entity.position.x + this.localOffset.x - camera.position.x + camera.origin.x;
|
||||||
|
this.displayObject.y = this.entity.position.y + this.localOffset.y - camera.position.y + camera.origin.y;
|
||||||
|
this.displayObject.scaleX = this.entity.scale.x;
|
||||||
|
this.displayObject.scaleY = this.entity.scale.y;
|
||||||
|
this.displayObject.rotation = this.entity.rotation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public toString(){
|
||||||
|
return `[RenderableComponent] renderLayer: ${this.renderLayer}`;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,37 +1,37 @@
|
|||||||
///<reference path="./TiledSpriteRenderer.ts"/>
|
///<reference path="./TiledSpriteRenderer.ts"/>
|
||||||
class ScrollingSpriteRenderer extends TiledSpriteRenderer {
|
module es {
|
||||||
public scrollSpeedX = 15;
|
export class ScrollingSpriteRenderer extends TiledSpriteRenderer {
|
||||||
public scroolSpeedY = 0;
|
public scrollSpeedX = 15;
|
||||||
private _scrollX = 0;
|
public scroolSpeedY = 0;
|
||||||
private _scrollY = 0;
|
private _scrollX = 0;
|
||||||
|
private _scrollY = 0;
|
||||||
|
|
||||||
public update(){
|
public update(){
|
||||||
this._scrollX += this.scrollSpeedX * Time.deltaTime;
|
this._scrollX += this.scrollSpeedX * Time.deltaTime;
|
||||||
this._scrollY += this.scroolSpeedY * Time.deltaTime;
|
this._scrollY += this.scroolSpeedY * Time.deltaTime;
|
||||||
this.sourceRect.x = this._scrollX;
|
this.sourceRect.x = this._scrollX;
|
||||||
this.sourceRect.y = this._scrollY;
|
this.sourceRect.y = this._scrollY;
|
||||||
}
|
}
|
||||||
|
|
||||||
public render(camera: Camera) {
|
public render(camera: Camera) {
|
||||||
if (!this.sprite)
|
if (!this.sprite)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
super.render(camera);
|
super.render(camera);
|
||||||
|
|
||||||
let renderTexture = new egret.RenderTexture();
|
let renderTexture = new egret.RenderTexture();
|
||||||
let cacheBitmap = new egret.DisplayObjectContainer();
|
let cacheBitmap = new egret.DisplayObjectContainer();
|
||||||
cacheBitmap.removeChildren();
|
cacheBitmap.removeChildren();
|
||||||
cacheBitmap.addChild(this.leftTexture);
|
cacheBitmap.addChild(this.leftTexture);
|
||||||
cacheBitmap.addChild(this.rightTexture);
|
cacheBitmap.addChild(this.rightTexture);
|
||||||
|
|
||||||
this.leftTexture.x = this.sourceRect.x;
|
this.leftTexture.x = this.sourceRect.x;
|
||||||
this.rightTexture.x = this.sourceRect.x - this.sourceRect.width;
|
this.rightTexture.x = this.sourceRect.x - this.sourceRect.width;
|
||||||
this.leftTexture.y = this.sourceRect.y;
|
this.leftTexture.y = this.sourceRect.y;
|
||||||
this.rightTexture.y = this.sourceRect.y;
|
this.rightTexture.y = this.sourceRect.y;
|
||||||
|
|
||||||
cacheBitmap.cacheAsBitmap = true;
|
cacheBitmap.cacheAsBitmap = true;
|
||||||
renderTexture.drawToTexture(cacheBitmap, new egret.Rectangle(0, 0, this.sourceRect.width, this.sourceRect.height));
|
renderTexture.drawToTexture(cacheBitmap, new egret.Rectangle(0, 0, this.sourceRect.width, this.sourceRect.height));
|
||||||
|
}
|
||||||
this.bitmap.texture = renderTexture;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,24 +1,26 @@
|
|||||||
class Sprite {
|
module es {
|
||||||
public texture2D: egret.Texture;
|
export class Sprite {
|
||||||
public readonly sourceRect: Rectangle;
|
public texture2D: egret.Texture;
|
||||||
public readonly center: Vector2;
|
public readonly sourceRect: Rectangle;
|
||||||
public origin: Vector2;
|
public readonly center: Vector2;
|
||||||
public readonly uvs: Rectangle = new Rectangle();
|
public origin: Vector2;
|
||||||
|
public readonly uvs: Rectangle = new Rectangle();
|
||||||
|
|
||||||
constructor(texture: egret.Texture,
|
constructor(texture: egret.Texture,
|
||||||
sourceRect: Rectangle = new Rectangle(0, 0, texture.textureWidth, texture.textureHeight),
|
sourceRect: Rectangle = new Rectangle(0, 0, texture.textureWidth, texture.textureHeight),
|
||||||
origin: Vector2 = sourceRect.getHalfSize()) {
|
origin: Vector2 = sourceRect.getHalfSize()) {
|
||||||
this.texture2D = texture;
|
this.texture2D = texture;
|
||||||
this.sourceRect = sourceRect;
|
this.sourceRect = sourceRect;
|
||||||
this.center = new Vector2(sourceRect.width * 0.5, sourceRect.height * 0.5);
|
this.center = new Vector2(sourceRect.width * 0.5, sourceRect.height * 0.5);
|
||||||
this.origin = origin;
|
this.origin = origin;
|
||||||
|
|
||||||
let inverseTexW = 1 / texture.textureWidth;
|
let inverseTexW = 1 / texture.textureWidth;
|
||||||
let inverseTexH = 1 / texture.textureHeight
|
let inverseTexH = 1 / texture.textureHeight;
|
||||||
|
|
||||||
this.uvs.x = sourceRect.x * inverseTexW;
|
this.uvs.x = sourceRect.x * inverseTexW;
|
||||||
this.uvs.y = sourceRect.y * inverseTexH;
|
this.uvs.y = sourceRect.y * inverseTexH;
|
||||||
this.uvs.width = sourceRect.width * inverseTexW;
|
this.uvs.width = sourceRect.width * inverseTexW;
|
||||||
this.uvs.height = sourceRect.height * inverseTexH;
|
this.uvs.height = sourceRect.height * inverseTexH;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,9 +1,11 @@
|
|||||||
class SpriteAnimation {
|
module es {
|
||||||
public readonly sprites: Sprite[];
|
export class SpriteAnimation {
|
||||||
public readonly frameRate: number;
|
public readonly sprites: Sprite[];
|
||||||
|
public readonly frameRate: number;
|
||||||
|
|
||||||
constructor(sprites: Sprite[], frameRate: number){
|
constructor(sprites: Sprite[], frameRate: number){
|
||||||
this.sprites = sprites;
|
this.sprites = sprites;
|
||||||
this.frameRate = frameRate;
|
this.frameRate = frameRate;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,108 +1,84 @@
|
|||||||
///<reference path="./SpriteRenderer.ts" />
|
///<reference path="./SpriteRenderer.ts" />
|
||||||
class SpriteAnimator extends SpriteRenderer {
|
module es {
|
||||||
/** 在动画完成时触发,包括动画名称; */
|
export enum LoopMode {
|
||||||
public onAnimationCompletedEvent: Function;
|
/** 在一个循环序列[A][B][C][A][B][C][A][B][C]... */
|
||||||
/** 动画播放速度 */
|
loop,
|
||||||
public speed = 1;
|
/** [A][B][C]然后暂停,设置时间为0 [A] */
|
||||||
/** 动画的当前状态 */
|
once,
|
||||||
public animationState = State.none;
|
/** [A][B][C]。当它到达终点时,它会继续播放最后一帧,并且不会停止播放 */
|
||||||
/** 当前动画 */
|
clampForever,
|
||||||
public currentAnimation: SpriteAnimation;
|
/** 以一个乒乓循环的方式永远播放这个序列 [A][B][C][B][A][B][C][B]... */
|
||||||
/** 当前动画的名称 */
|
pingPong,
|
||||||
public currentAnimationName: string;
|
/** 将顺序向前播放一次,然后返回到开始[A][B][C][B][A],然后暂停并设置时间为0 */
|
||||||
/** 当前动画的精灵数组中当前帧的索引 */
|
pingPongOnce,
|
||||||
public currentFrame: number;
|
|
||||||
/** 检查当前动画是否正在运行 */
|
|
||||||
public get isRunning(): boolean{
|
|
||||||
return this.animationState == State.running;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 提供对可用动画列表的访问 */
|
export enum State {
|
||||||
public get animations(){
|
none,
|
||||||
return this._animations;
|
running,
|
||||||
}
|
paused,
|
||||||
private _animations: Map<string, SpriteAnimation> = new Map<string, SpriteAnimation>();
|
completed,
|
||||||
private _elapsedTime: number = 0;
|
|
||||||
private _loopMode: LoopMode;
|
|
||||||
|
|
||||||
constructor(sprite?: Sprite){
|
|
||||||
super();
|
|
||||||
|
|
||||||
if (sprite) this.setSprite(sprite);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
export class SpriteAnimator extends SpriteRenderer {
|
||||||
* 添加一个SpriteAnimation
|
/**
|
||||||
* @param name
|
* 在动画完成时触发,包括动画名称
|
||||||
* @param animation
|
*/
|
||||||
*/
|
public onAnimationCompletedEvent: (string) => {};
|
||||||
public addAnimation(name: string, animation: SpriteAnimation): SpriteAnimator{
|
/**
|
||||||
if (!this.sprite && animation.sprites.length > 0)
|
* 动画播放速度
|
||||||
this.setSprite(animation.sprites[0]);
|
*/
|
||||||
this._animations[name] = animation;
|
public speed = 1;
|
||||||
return this;
|
/**
|
||||||
}
|
* 动画的当前状态
|
||||||
|
*/
|
||||||
|
public animationState = State.none;
|
||||||
|
/**
|
||||||
|
* 当前动画
|
||||||
|
*/
|
||||||
|
public currentAnimation: SpriteAnimation;
|
||||||
|
/**
|
||||||
|
* 当前动画的名称
|
||||||
|
*/
|
||||||
|
public currentAnimationName: string;
|
||||||
|
/**
|
||||||
|
* 当前动画的精灵数组中当前帧的索引
|
||||||
|
*/
|
||||||
|
public currentFrame: number;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 以给定的名称放置动画。如果没有指定循环模式,则默认为循环
|
* 检查当前动画是否正在运行
|
||||||
* @param name
|
*/
|
||||||
* @param loopMode
|
public get isRunning(): boolean {
|
||||||
*/
|
return this.animationState == State.running;
|
||||||
public play(name: string, loopMode: LoopMode = null){
|
}
|
||||||
this.currentAnimation = this._animations[name];
|
|
||||||
this.currentAnimationName = name;
|
|
||||||
this.currentFrame = 0;
|
|
||||||
this.animationState = State.running;
|
|
||||||
|
|
||||||
this.sprite = this.currentAnimation.sprites[0];
|
/** 提供对可用动画列表的访问 */
|
||||||
this._elapsedTime = 0;
|
public get animations() {
|
||||||
this._loopMode = loopMode ? loopMode : LoopMode.loop;
|
return this._animations;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private _animations: Map<string, SpriteAnimation> = new Map<string, SpriteAnimation>();
|
||||||
* 检查动画是否正在播放(即动画是活动的)。它可能仍然处于暂停状态)
|
public _elapsedTime: number = 0;
|
||||||
* @param name
|
public _loopMode: LoopMode;
|
||||||
*/
|
|
||||||
public isAnimationActive(name: string): boolean{
|
|
||||||
return this.currentAnimation && this.currentAnimationName == name;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
constructor(sprite?: Sprite) {
|
||||||
* 暂停动画
|
super(sprite);
|
||||||
*/
|
}
|
||||||
public pause(){
|
|
||||||
this.animationState = State.paused;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
public update() {
|
||||||
* 继续动画
|
if (this.animationState != State.running || !this.currentAnimation) return;
|
||||||
*/
|
|
||||||
public unPause(){
|
|
||||||
this.animationState = State.running;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
let animation = this.currentAnimation;
|
||||||
* 停止当前动画并将其设为null
|
let secondsPerFrame = 1 / (animation.frameRate * this.speed);
|
||||||
*/
|
let iterationDuration = secondsPerFrame * animation.sprites.length;
|
||||||
public stop(){
|
|
||||||
this.currentAnimation = null;
|
|
||||||
this.currentAnimationName = null;
|
|
||||||
this.currentFrame = 0;
|
|
||||||
this.animationState = State.none;
|
|
||||||
}
|
|
||||||
|
|
||||||
public update(){
|
this._elapsedTime += Time.deltaTime;
|
||||||
if (this.animationState != State.running || !this.currentAnimation) return;
|
let time = Math.abs(this._elapsedTime);
|
||||||
|
|
||||||
let animation = this.currentAnimation;
|
// Once和PingPongOnce完成后重置为Time = 0
|
||||||
let secondsPerFrame = 1 / (animation.frameRate * this.speed);
|
if (this._loopMode == LoopMode.once && time > iterationDuration ||
|
||||||
let iterationDuration = secondsPerFrame * animation.sprites.length;
|
this._loopMode == LoopMode.pingPongOnce && time > iterationDuration * 2) {
|
||||||
|
|
||||||
this._elapsedTime += Time.deltaTime;
|
|
||||||
let time = Math.abs(this._elapsedTime);
|
|
||||||
|
|
||||||
if (this._loopMode == LoopMode.once && time > iterationDuration ||
|
|
||||||
this._loopMode == LoopMode.pingPongOnce && time > iterationDuration * 2){
|
|
||||||
this.animationState = State.completed;
|
this.animationState = State.completed;
|
||||||
this._elapsedTime = 0;
|
this._elapsedTime = 0;
|
||||||
this.currentFrame = 0;
|
this.currentFrame = 0;
|
||||||
@@ -113,34 +89,76 @@ class SpriteAnimator extends SpriteRenderer {
|
|||||||
// 弄清楚我们在哪个坐标系上
|
// 弄清楚我们在哪个坐标系上
|
||||||
let i = Math.floor(time / secondsPerFrame);
|
let i = Math.floor(time / secondsPerFrame);
|
||||||
let n = animation.sprites.length;
|
let n = animation.sprites.length;
|
||||||
if (n > 2 && (this._loopMode == LoopMode.pingPong || this._loopMode == LoopMode.pingPongOnce)){
|
if (n > 2 && (this._loopMode == LoopMode.pingPong || this._loopMode == LoopMode.pingPongOnce)) {
|
||||||
// pingpong
|
// pingpong
|
||||||
let maxIndex = n - 1;
|
let maxIndex = n - 1;
|
||||||
this.currentFrame = maxIndex - Math.abs(maxIndex - i % (maxIndex * 2));
|
this.currentFrame = maxIndex - Math.abs(maxIndex - i % (maxIndex * 2));
|
||||||
}else{
|
} else {
|
||||||
this.currentFrame = i % n;
|
this.currentFrame = i % n;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.sprite = animation.sprites[this.currentFrame];
|
this.sprite = animation.sprites[this.currentFrame];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 添加一个SpriteAnimation
|
||||||
|
* @param name
|
||||||
|
* @param animation
|
||||||
|
*/
|
||||||
|
public addAnimation(name: string, animation: SpriteAnimation): SpriteAnimator {
|
||||||
|
// 如果我们没有精灵,使用我们找到的第一帧
|
||||||
|
if (!this.sprite && animation.sprites.length > 0)
|
||||||
|
this.setSprite(animation.sprites[0]);
|
||||||
|
this._animations[name] = animation;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 以给定的名称放置动画。如果没有指定循环模式,则默认为循环
|
||||||
|
* @param name
|
||||||
|
* @param loopMode
|
||||||
|
*/
|
||||||
|
public play(name: string, loopMode: LoopMode = null) {
|
||||||
|
this.currentAnimation = this._animations[name];
|
||||||
|
this.currentAnimationName = name;
|
||||||
|
this.currentFrame = 0;
|
||||||
|
this.animationState = State.running;
|
||||||
|
|
||||||
|
this.sprite = this.currentAnimation.sprites[0];
|
||||||
|
this._elapsedTime = 0;
|
||||||
|
this._loopMode = loopMode ? loopMode : LoopMode.loop;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查动画是否正在播放(即动画是活动的)。它可能仍然处于暂停状态)
|
||||||
|
* @param name
|
||||||
|
*/
|
||||||
|
public isAnimationActive(name: string): boolean {
|
||||||
|
return this.currentAnimation && this.currentAnimationName == name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 暂停动画
|
||||||
|
*/
|
||||||
|
public pause() {
|
||||||
|
this.animationState = State.paused;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 继续动画
|
||||||
|
*/
|
||||||
|
public unPause() {
|
||||||
|
this.animationState = State.running;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 停止当前动画并将其设为null
|
||||||
|
*/
|
||||||
|
public stop() {
|
||||||
|
this.currentAnimation = null;
|
||||||
|
this.currentAnimationName = null;
|
||||||
|
this.currentFrame = 0;
|
||||||
|
this.animationState = State.none;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enum LoopMode {
|
|
||||||
/** 在一个循环序列[A][B][C][A][B][C][A][B][C]... */
|
|
||||||
loop,
|
|
||||||
/** [A][B][C]然后暂停,设置时间为0 [A] */
|
|
||||||
once,
|
|
||||||
/** [A][B][C]。当它到达终点时,它会继续播放最后一帧,并且不会停止播放 */
|
|
||||||
clampForever,
|
|
||||||
/** 以一个乒乓循环的方式永远播放这个序列 [A][B][C][B][A][B][C][B]... */
|
|
||||||
pingPong,
|
|
||||||
/** 将顺序向前播放一次,然后返回到开始[A][B][C][B][A],然后暂停并设置时间为0 */
|
|
||||||
pingPongOnce,
|
|
||||||
}
|
|
||||||
|
|
||||||
enum State {
|
|
||||||
none,
|
|
||||||
running,
|
|
||||||
paused,
|
|
||||||
completed,
|
|
||||||
}
|
|
||||||
@@ -1,62 +1,130 @@
|
|||||||
class SpriteRenderer extends RenderableComponent{
|
module es {
|
||||||
private _sprite: Sprite;
|
import Bitmap = egret.Bitmap;
|
||||||
protected bitmap: egret.Bitmap;
|
|
||||||
|
|
||||||
/** 应该由这个精灵显示的精灵 */
|
export class SpriteRenderer extends RenderableComponent {
|
||||||
public get sprite(): Sprite{
|
public get bounds() {
|
||||||
return this._sprite;
|
if (this._areBoundsDirty) {
|
||||||
}
|
if (this._sprite) {
|
||||||
/** 应该由这个精灵显示的精灵 */
|
this._bounds.calculateBounds(this.entity.transform.position, this._localOffset, this._origin,
|
||||||
public set sprite(value: Sprite){
|
this.entity.transform.scale, this.entity.transform.rotation, this._sprite.sourceRect.width,
|
||||||
this.setSprite(value);
|
this._sprite.sourceRect.height);
|
||||||
}
|
this._areBoundsDirty = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public setSprite(sprite: Sprite): SpriteRenderer{
|
return this._bounds;
|
||||||
this.removeChildren();
|
|
||||||
this._sprite = sprite;
|
|
||||||
if (this._sprite) {
|
|
||||||
this.anchorOffsetX = this._sprite.origin.x / this._sprite.sourceRect.width;
|
|
||||||
this.anchorOffsetY = this._sprite.origin.y / this._sprite.sourceRect.height;
|
|
||||||
}
|
}
|
||||||
this.bitmap = new egret.Bitmap(sprite.texture2D);
|
|
||||||
this.addChild(this.bitmap);
|
|
||||||
|
|
||||||
return this;
|
/**
|
||||||
}
|
* 精灵的原点。这是在设置精灵时自动设置的
|
||||||
|
*/
|
||||||
|
public get origin(): Vector2 {
|
||||||
|
return this._origin;
|
||||||
|
}
|
||||||
|
|
||||||
public setColor(color: number): SpriteRenderer{
|
/**
|
||||||
let colorMatrix = [
|
* 精灵的原点。这是在设置精灵时自动设置的
|
||||||
1, 0, 0, 0, 0,
|
* @param value
|
||||||
0, 1, 0, 0, 0,
|
*/
|
||||||
0, 0, 1, 0, 0,
|
public set origin(value: Vector2) {
|
||||||
0, 0, 0, 1, 0
|
this.setOrigin(value);
|
||||||
];
|
}
|
||||||
colorMatrix[0] = Math.floor(color / 256 / 256) / 255;
|
|
||||||
colorMatrix[6] = Math.floor(color / 256 % 256) / 255;
|
|
||||||
colorMatrix[12] = color % 256 / 255;
|
|
||||||
let colorFilter = new egret.ColorMatrixFilter(colorMatrix);
|
|
||||||
this.filters = [colorFilter];
|
|
||||||
|
|
||||||
return this;
|
/**
|
||||||
}
|
* 用归一化方法设置原点
|
||||||
|
* x/y 均为 0-1
|
||||||
|
*/
|
||||||
|
public get originNormalized(): Vector2 {
|
||||||
|
return new Vector2(this._origin.x / this.width * this.entity.transform.scale.x,
|
||||||
|
this._origin.y / this.height * this.entity.transform.scale.y);
|
||||||
|
}
|
||||||
|
|
||||||
public isVisibleFromCamera(camera: Camera): boolean{
|
/**
|
||||||
this.isVisible = new Rectangle(0, 0, this.stage.stageWidth, this.stage.stageHeight).intersects(this.bounds);
|
* 用归一化方法设置原点
|
||||||
this.visible = this.isVisible;
|
* x/y 均为 0-1
|
||||||
return this.isVisible;
|
* @param value
|
||||||
}
|
*/
|
||||||
|
public set originNormalized(value: Vector2) {
|
||||||
|
this.setOrigin(new Vector2(value.x * this.width / this.entity.transform.scale.x,
|
||||||
|
value.y * this.height / this.entity.transform.scale.y));
|
||||||
|
}
|
||||||
|
|
||||||
/** 渲染处理 在每个模块中处理各自的渲染逻辑 */
|
/**
|
||||||
public render(camera: Camera){
|
* 应该由这个精灵显示的精灵
|
||||||
this.x = -camera.position.x + camera.origin.x;
|
* 当设置时,精灵的原点也被设置为精灵的origin
|
||||||
this.y = -camera.position.y + camera.origin.y;
|
*/
|
||||||
}
|
public get sprite(): Sprite {
|
||||||
|
return this._sprite;
|
||||||
|
}
|
||||||
|
|
||||||
public onRemovedFromEntity(){
|
/**
|
||||||
if (this.parent)
|
* 应该由这个精灵显示的精灵
|
||||||
this.parent.removeChild(this);
|
* 当设置时,精灵的原点也被设置为精灵的origin
|
||||||
}
|
* @param value
|
||||||
|
*/
|
||||||
|
public set sprite(value: Sprite) {
|
||||||
|
this.setSprite(value);
|
||||||
|
}
|
||||||
|
|
||||||
public reset(){
|
protected _origin: Vector2;
|
||||||
|
protected _sprite: Sprite;
|
||||||
|
|
||||||
|
constructor(sprite: Sprite | egret.Texture = null) {
|
||||||
|
super();
|
||||||
|
if (sprite instanceof Sprite)
|
||||||
|
this.setSprite(sprite);
|
||||||
|
else if (sprite instanceof egret.Texture)
|
||||||
|
this.setSprite(new Sprite(sprite));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置精灵并更新精灵的原点以匹配sprite.origin
|
||||||
|
* @param sprite
|
||||||
|
*/
|
||||||
|
public setSprite(sprite: Sprite): SpriteRenderer {
|
||||||
|
this._sprite = sprite;
|
||||||
|
if (this._sprite) {
|
||||||
|
this._origin = this._sprite.origin;
|
||||||
|
this.displayObject.anchorOffsetX = this._origin.x;
|
||||||
|
this.displayObject.anchorOffsetY = this._origin.y;
|
||||||
|
}
|
||||||
|
this.displayObject = new Bitmap(sprite.texture2D);
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置可渲染的原点
|
||||||
|
* @param origin
|
||||||
|
*/
|
||||||
|
public setOrigin(origin: Vector2): SpriteRenderer {
|
||||||
|
if (this._origin != origin) {
|
||||||
|
this._origin = origin;
|
||||||
|
this.displayObject.anchorOffsetX = this._origin.x;
|
||||||
|
this.displayObject.anchorOffsetY = this._origin.y;
|
||||||
|
this._areBoundsDirty = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用归一化方法设置原点
|
||||||
|
* x/y 均为 0-1
|
||||||
|
* @param value
|
||||||
|
*/
|
||||||
|
public setOriginNormalized(value: Vector2): SpriteRenderer {
|
||||||
|
this.setOrigin(new Vector2(value.x * this.width / this.entity.transform.scale.x,
|
||||||
|
value.y * this.height / this.entity.transform.scale.y));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public render(camera: Camera) {
|
||||||
|
this.sync(camera);
|
||||||
|
|
||||||
|
this.displayObject.x = this.entity.position.x - this.origin.x + this.localOffset.x - camera.position.x + camera.origin.x;
|
||||||
|
this.displayObject.y = this.entity.position.y - this.origin.y + this.localOffset.y - camera.position.y + camera.origin.y;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,57 +1,57 @@
|
|||||||
///<reference path="./SpriteRenderer.ts" />
|
///<reference path="./SpriteRenderer.ts" />
|
||||||
/**
|
module es {
|
||||||
* 滚动由两张图片组合而成
|
/**
|
||||||
*/
|
* 滚动由两张图片组合而成
|
||||||
class TiledSpriteRenderer extends SpriteRenderer {
|
*/
|
||||||
protected sourceRect: Rectangle;
|
export class TiledSpriteRenderer extends SpriteRenderer {
|
||||||
protected leftTexture: egret.Bitmap;
|
protected sourceRect: Rectangle;
|
||||||
protected rightTexture: egret.Bitmap;
|
protected leftTexture: egret.Bitmap;
|
||||||
|
protected rightTexture: egret.Bitmap;
|
||||||
|
|
||||||
public get scrollX() {
|
public get scrollX() {
|
||||||
return this.sourceRect.x;
|
return this.sourceRect.x;
|
||||||
}
|
}
|
||||||
public set scrollX(value: number) {
|
public set scrollX(value: number) {
|
||||||
this.sourceRect.x = value;
|
this.sourceRect.x = value;
|
||||||
}
|
}
|
||||||
public get scrollY() {
|
public get scrollY() {
|
||||||
return this.sourceRect.y;
|
return this.sourceRect.y;
|
||||||
}
|
}
|
||||||
public set scrollY(value: number) {
|
public set scrollY(value: number) {
|
||||||
this.sourceRect.y = value;
|
this.sourceRect.y = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(sprite: Sprite) {
|
constructor(sprite: Sprite) {
|
||||||
super();
|
super(sprite);
|
||||||
|
|
||||||
this.leftTexture = new egret.Bitmap();
|
this.leftTexture = new egret.Bitmap();
|
||||||
this.rightTexture = new egret.Bitmap();
|
this.rightTexture = new egret.Bitmap();
|
||||||
this.leftTexture.texture = sprite.texture2D;
|
this.leftTexture.texture = sprite.texture2D;
|
||||||
this.rightTexture.texture = sprite.texture2D;
|
this.rightTexture.texture = sprite.texture2D;
|
||||||
|
|
||||||
this.setSprite(sprite);
|
this.setSprite(sprite);
|
||||||
this.sourceRect = sprite.sourceRect;
|
this.sourceRect = sprite.sourceRect;
|
||||||
}
|
}
|
||||||
|
|
||||||
public render(camera: Camera) {
|
public render(camera: es.Camera) {
|
||||||
if (!this.sprite)
|
if (!this.sprite)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
super.render(camera);
|
super.render(camera);
|
||||||
|
|
||||||
let renderTexture = new egret.RenderTexture();
|
let renderTexture = new egret.RenderTexture();
|
||||||
let cacheBitmap = new egret.DisplayObjectContainer();
|
let cacheBitmap = new egret.DisplayObjectContainer();
|
||||||
cacheBitmap.removeChildren();
|
cacheBitmap.removeChildren();
|
||||||
cacheBitmap.addChild(this.leftTexture);
|
cacheBitmap.addChild(this.leftTexture);
|
||||||
cacheBitmap.addChild(this.rightTexture);
|
cacheBitmap.addChild(this.rightTexture);
|
||||||
|
|
||||||
this.leftTexture.x = this.sourceRect.x;
|
this.leftTexture.x = this.sourceRect.x;
|
||||||
this.rightTexture.x = this.sourceRect.x - this.sourceRect.width;
|
this.rightTexture.x = this.sourceRect.x - this.sourceRect.width;
|
||||||
this.leftTexture.y = this.sourceRect.y;
|
this.leftTexture.y = this.sourceRect.y;
|
||||||
this.rightTexture.y = this.sourceRect.y;
|
this.rightTexture.y = this.sourceRect.y;
|
||||||
|
|
||||||
cacheBitmap.cacheAsBitmap = true;
|
cacheBitmap.cacheAsBitmap = true;
|
||||||
renderTexture.drawToTexture(cacheBitmap, new egret.Rectangle(0, 0, this.sourceRect.width, this.sourceRect.height));
|
renderTexture.drawToTexture(cacheBitmap, new egret.Rectangle(0, 0, this.sourceRect.width, this.sourceRect.height));
|
||||||
|
}
|
||||||
this.bitmap.texture = renderTexture;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,230 @@
|
|||||||
|
module es {
|
||||||
|
/**
|
||||||
|
* 全局核心类
|
||||||
|
*/
|
||||||
|
export class Core extends egret.DisplayObjectContainer {
|
||||||
|
/**
|
||||||
|
* 核心发射器。只发出核心级别的事件
|
||||||
|
*/
|
||||||
|
public static emitter: Emitter<CoreEvents>;
|
||||||
|
/**
|
||||||
|
* 全局访问图形设备
|
||||||
|
*/
|
||||||
|
public static graphicsDevice: GraphicsDevice;
|
||||||
|
/**
|
||||||
|
* 全局内容管理器加载任何应该停留在场景之间的资产
|
||||||
|
*/
|
||||||
|
public static content: ContentManager;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 提供对单例/游戏实例的访问
|
||||||
|
* @constructor
|
||||||
|
*/
|
||||||
|
public static get Instance(){
|
||||||
|
return this._instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 简化对内部类的全局内容实例的访问
|
||||||
|
*/
|
||||||
|
public static _instance: Core;
|
||||||
|
public _scene: Scene;
|
||||||
|
public _nextScene: Scene;
|
||||||
|
public _sceneTransition: SceneTransition;
|
||||||
|
/**
|
||||||
|
* 全局访问系统
|
||||||
|
*/
|
||||||
|
public _globalManagers: GlobalManager[] = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 当前活动的场景。注意,如果设置了该设置,在更新结束之前场景实际上不会改变
|
||||||
|
*/
|
||||||
|
public static get scene() {
|
||||||
|
if (!this._instance)
|
||||||
|
return null;
|
||||||
|
return this._instance._scene;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 当前活动的场景。注意,如果设置了该设置,在更新结束之前场景实际上不会改变
|
||||||
|
* @param value
|
||||||
|
*/
|
||||||
|
public static set scene(value: Scene) {
|
||||||
|
if (!value){
|
||||||
|
console.error("场景不能为空");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this._instance._scene == null) {
|
||||||
|
this._instance._scene = value;
|
||||||
|
this._instance.addChild(value);
|
||||||
|
this._instance._scene.begin();
|
||||||
|
Core.Instance.onSceneChanged();
|
||||||
|
} else {
|
||||||
|
this._instance._nextScene = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
Core._instance = this;
|
||||||
|
Core.emitter = new Emitter<CoreEvents>();
|
||||||
|
Core.content = new ContentManager();
|
||||||
|
|
||||||
|
this.addEventListener(egret.Event.ADDED_TO_STAGE, this.onAddToStage, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
private onAddToStage(){
|
||||||
|
Core.graphicsDevice = new GraphicsDevice();
|
||||||
|
|
||||||
|
this.addEventListener(egret.Event.RESIZE, this.onGraphicsDeviceReset, this);
|
||||||
|
this.addEventListener(egret.StageOrientationEvent.ORIENTATION_CHANGE, this.onOrientationChanged, this);
|
||||||
|
this.addEventListener(egret.Event.ENTER_FRAME, this.update, this);
|
||||||
|
|
||||||
|
Input.initialize();
|
||||||
|
this.initialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
public onOrientationChanged(){
|
||||||
|
Core.emitter.emit(CoreEvents.OrientationChanged);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 当屏幕大小发生改变时调用
|
||||||
|
*/
|
||||||
|
protected onGraphicsDeviceReset(){
|
||||||
|
Core.emitter.emit(CoreEvents.GraphicsDeviceReset);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected initialize(){
|
||||||
|
}
|
||||||
|
|
||||||
|
protected async update() {
|
||||||
|
// this.startDebugUpdate();
|
||||||
|
|
||||||
|
// 更新我们所有的系统管理器
|
||||||
|
Time.update(egret.getTimer());
|
||||||
|
|
||||||
|
if (this._scene) {
|
||||||
|
for (let i = this._globalManagers.length - 1; i >= 0; i--) {
|
||||||
|
if (this._globalManagers[i].enabled)
|
||||||
|
this._globalManagers[i].update();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 仔细阅读:
|
||||||
|
// 当场景转换发生时,我们不会更新场景
|
||||||
|
// -除非是不改变场景的场景转换(没有理由不更新)
|
||||||
|
// -或者它是一个已经切换到新场景的场景转换(新场景需要做它自己的事情)
|
||||||
|
if (!this._sceneTransition ||
|
||||||
|
(this._sceneTransition && (!this._sceneTransition.loadsNewScene || this._sceneTransition.isNewSceneLoaded))) {
|
||||||
|
this._scene.update();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this._nextScene) {
|
||||||
|
this.removeChild(this._scene);
|
||||||
|
this._scene.end();
|
||||||
|
|
||||||
|
this._scene = this._nextScene;
|
||||||
|
this._nextScene = null;
|
||||||
|
this.onSceneChanged();
|
||||||
|
|
||||||
|
this.addChild(this._scene);
|
||||||
|
await this._scene.begin();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// this.endDebugUpdate();
|
||||||
|
|
||||||
|
await this.draw();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async draw() {
|
||||||
|
if (this._sceneTransition){
|
||||||
|
this._sceneTransition.preRender();
|
||||||
|
|
||||||
|
// 如果我们有场景转换的特殊处理。我们要么渲染场景过渡,要么渲染场景
|
||||||
|
if (this._scene && !this._sceneTransition.hasPreviousSceneRender){
|
||||||
|
this._scene.render();
|
||||||
|
this._scene.postRender();
|
||||||
|
await this._sceneTransition.onBeginTransition();
|
||||||
|
} else if (this._sceneTransition) {
|
||||||
|
if (this._scene && this._sceneTransition.isNewSceneLoaded) {
|
||||||
|
this._scene.render();
|
||||||
|
this._scene.postRender();
|
||||||
|
}
|
||||||
|
|
||||||
|
this._sceneTransition.render();
|
||||||
|
}
|
||||||
|
} else if (this._scene) {
|
||||||
|
this._scene.render();
|
||||||
|
|
||||||
|
Debug.render();
|
||||||
|
|
||||||
|
// 如果我们没有一个活跃的场景转换,就像平常一样渲染
|
||||||
|
this._scene.postRender();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public startDebugUpdate(){
|
||||||
|
TimeRuler.Instance.startFrame();
|
||||||
|
TimeRuler.Instance.beginMark("update", 0x00FF00);
|
||||||
|
}
|
||||||
|
|
||||||
|
public endDebugUpdate(){
|
||||||
|
TimeRuler.Instance.endMark("update");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 在一个场景结束后,下一个场景开始之前调用
|
||||||
|
*/
|
||||||
|
public onSceneChanged(){
|
||||||
|
Core.emitter.emit(CoreEvents.SceneChanged);
|
||||||
|
Time.sceneChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 临时运行SceneTransition,允许一个场景过渡到另一个平滑的自定义效果。
|
||||||
|
* @param sceneTransition
|
||||||
|
*/
|
||||||
|
public static startSceneTransition<T extends SceneTransition>(sceneTransition: T): T {
|
||||||
|
if (this._instance._sceneTransition) {
|
||||||
|
console.warn("在前一个场景完成之前,不能开始一个新的场景转换。");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this._instance._sceneTransition = sceneTransition;
|
||||||
|
return sceneTransition;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 添加一个全局管理器对象,它的更新方法将调用场景前的每一帧。
|
||||||
|
* @param manager
|
||||||
|
*/
|
||||||
|
public static registerGlobalManager(manager: es.GlobalManager){
|
||||||
|
this._instance._globalManagers.push(manager);
|
||||||
|
manager.enabled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除全局管理器对象
|
||||||
|
* @param manager
|
||||||
|
*/
|
||||||
|
public static unregisterGlobalManager(manager: es.GlobalManager){
|
||||||
|
this._instance._globalManagers.remove(manager);
|
||||||
|
manager.enabled = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取类型为T的全局管理器
|
||||||
|
* @param type
|
||||||
|
*/
|
||||||
|
public static getGlobalManager<T extends es.GlobalManager>(type): T {
|
||||||
|
for (let i = 0; i < this._instance._globalManagers.length; i ++){
|
||||||
|
if (this._instance._globalManagers[i] instanceof type)
|
||||||
|
return this._instance._globalManagers[i] as T;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,16 @@
|
|||||||
enum CoreEvents{
|
module es {
|
||||||
/** 当场景发生变化时触发 */
|
export enum CoreEvents{
|
||||||
SceneChanged,
|
/**
|
||||||
|
* 在图形设备重置时触发。当这种情况发生时,任何渲染目标或其他内容的VRAM将被擦除,需要重新生成
|
||||||
|
*/
|
||||||
|
GraphicsDeviceReset,
|
||||||
|
/**
|
||||||
|
* 当场景发生变化时触发
|
||||||
|
*/
|
||||||
|
SceneChanged,
|
||||||
|
/**
|
||||||
|
* 当设备方向改变时触发
|
||||||
|
*/
|
||||||
|
OrientationChanged,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
+391
-193
@@ -1,237 +1,435 @@
|
|||||||
class Entity extends egret.DisplayObjectContainer {
|
module es {
|
||||||
private static _idGenerator: number;
|
export class Entity {
|
||||||
|
public static _idGenerator: number;
|
||||||
|
|
||||||
public name: string;
|
/**
|
||||||
public readonly id: number;
|
* 当前实体所属的场景
|
||||||
/** 当前实体所属的场景 */
|
*/
|
||||||
public scene: Scene;
|
public scene: Scene;
|
||||||
/** 当前附加到此实体的所有组件的列表 */
|
/**
|
||||||
public readonly components: ComponentList;
|
* 实体名称。用于在场景范围内搜索实体
|
||||||
private _updateOrder: number = 0;
|
*/
|
||||||
private _enabled: boolean = true;
|
public name: string;
|
||||||
public _isDestoryed: boolean;
|
/**
|
||||||
private _tag: number = 0;
|
* 此实体的唯一标识
|
||||||
|
*/
|
||||||
|
public readonly id: number;
|
||||||
|
/**
|
||||||
|
* 封装实体的位置/旋转/缩放,并允许设置一个高层结构
|
||||||
|
*/
|
||||||
|
public readonly transform: Transform;
|
||||||
|
/**
|
||||||
|
* 当前附加到此实体的所有组件的列表
|
||||||
|
*/
|
||||||
|
public readonly components: ComponentList;
|
||||||
|
|
||||||
public componentBits: BitSet;
|
/**
|
||||||
|
* 你可以随意使用。稍后可以使用它来查询场景中具有特定标记的所有实体
|
||||||
public get isDestoryed(){
|
*/
|
||||||
return this._isDestoryed;
|
public get tag(): number {
|
||||||
}
|
return this._tag;
|
||||||
|
|
||||||
public get position(){
|
|
||||||
return new Vector2(this.x, this.y);
|
|
||||||
}
|
|
||||||
|
|
||||||
public set position(value: Vector2){
|
|
||||||
this.$setX(value.x);
|
|
||||||
this.$setY(value.y);
|
|
||||||
this.onEntityTransformChanged(TransformComponent.position);
|
|
||||||
}
|
|
||||||
|
|
||||||
public get scale(){
|
|
||||||
return new Vector2(this.scaleX, this.scaleY);
|
|
||||||
}
|
|
||||||
|
|
||||||
public set scale(value: Vector2){
|
|
||||||
this.$setScaleX(value.x);
|
|
||||||
this.$setScaleY(value.y);
|
|
||||||
this.onEntityTransformChanged(TransformComponent.scale);
|
|
||||||
}
|
|
||||||
|
|
||||||
public set rotation(value: number){
|
|
||||||
this.$setRotation(value);
|
|
||||||
this.onEntityTransformChanged(TransformComponent.rotation);
|
|
||||||
}
|
|
||||||
|
|
||||||
public get rotation(){
|
|
||||||
return this.$getRotation();
|
|
||||||
}
|
|
||||||
|
|
||||||
public get enabled(){
|
|
||||||
return this._enabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
public set enabled(value: boolean){
|
|
||||||
this.setEnabled(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public setEnabled(isEnabled: boolean){
|
|
||||||
if (this._enabled != isEnabled){
|
|
||||||
this._enabled = isEnabled;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return this;
|
/**
|
||||||
}
|
* 你可以随意使用。稍后可以使用它来查询场景中具有特定标记的所有实体
|
||||||
|
* @param value
|
||||||
|
*/
|
||||||
|
public set tag(value: number) {
|
||||||
|
this.setTag(value);
|
||||||
|
}
|
||||||
|
|
||||||
public get tag(){
|
/**
|
||||||
return this._tag;
|
* 指定应该调用这个entity update方法的频率。1表示每一帧,2表示每一帧,以此类推
|
||||||
}
|
*/
|
||||||
|
public updateInterval: number = 1;
|
||||||
|
|
||||||
public set tag(value: number){
|
/**
|
||||||
this.setTag(value);
|
* 启用/禁用实体。当禁用碰撞器从物理系统和组件中移除时,方法将不会被调用
|
||||||
}
|
*/
|
||||||
|
public get enabled() {
|
||||||
|
return this._enabled;
|
||||||
|
}
|
||||||
|
|
||||||
public get stage(){
|
/**
|
||||||
if (!this.scene)
|
* 启用/禁用实体。当禁用碰撞器从物理系统和组件中移除时,方法将不会被调用
|
||||||
return null;
|
* @param value
|
||||||
|
*/
|
||||||
|
public set enabled(value: boolean) {
|
||||||
|
this.setEnabled(value);
|
||||||
|
}
|
||||||
|
|
||||||
return this.scene.stage;
|
/**
|
||||||
}
|
* 更新此实体的顺序。updateOrder还用于对scene.entities上的标签列表进行排序
|
||||||
|
*/
|
||||||
|
public get updateOrder() {
|
||||||
|
return this._updateOrder;
|
||||||
|
}
|
||||||
|
|
||||||
constructor(name: string){
|
/**
|
||||||
super();
|
* 更新此实体的顺序。updateOrder还用于对scene.entities上的标签列表进行排序
|
||||||
this.name = name;
|
* @param value
|
||||||
this.components = new ComponentList(this);
|
*/
|
||||||
this.id = Entity._idGenerator ++;
|
public set updateOrder(value: number) {
|
||||||
|
this.setUpdateOrder(value);
|
||||||
|
}
|
||||||
|
|
||||||
this.componentBits = new BitSet();
|
public _isDestroyed: boolean;
|
||||||
this.addEventListener(egret.Event.ADDED_TO_STAGE, this.onAddToStage, this);
|
/**
|
||||||
}
|
* 如果调用了destroy,那么在下一次处理实体之前这将一直为true
|
||||||
|
*/
|
||||||
|
public get isDestroyed() {
|
||||||
|
return this._isDestroyed;
|
||||||
|
}
|
||||||
|
|
||||||
private onAddToStage(){
|
public componentBits: BitSet;
|
||||||
this.onEntityTransformChanged(TransformComponent.position);
|
|
||||||
}
|
|
||||||
|
|
||||||
public get updateOrder(){
|
private _tag: number = 0;
|
||||||
return this._updateOrder;
|
private _enabled: boolean = true;
|
||||||
}
|
private _updateOrder: number = 0;
|
||||||
|
|
||||||
public set updateOrder(value: number){
|
public get parent(): Transform {
|
||||||
this.setUpdateOrder(value);
|
return this.transform.parent;
|
||||||
}
|
}
|
||||||
|
|
||||||
public roundPosition(){
|
public set parent(value: Transform) {
|
||||||
this.position = Vector2Ext.round(this.position);
|
this.transform.setParent(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public setUpdateOrder(updateOrder: number){
|
public get childCount() {
|
||||||
if (this._updateOrder != updateOrder){
|
return this.transform.childCount;
|
||||||
this._updateOrder = updateOrder;
|
}
|
||||||
if (this.scene){
|
|
||||||
|
|
||||||
|
public get position(): Vector2 {
|
||||||
|
return this.transform.position;
|
||||||
|
}
|
||||||
|
|
||||||
|
public set position(value: Vector2) {
|
||||||
|
this.transform.setPosition(value.x, value.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
public get localPosition(): Vector2 {
|
||||||
|
return this.transform.localPosition;
|
||||||
|
}
|
||||||
|
|
||||||
|
public set localPosition(value: Vector2){
|
||||||
|
this.transform.setLocalPosition(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public get rotation(): number {
|
||||||
|
return this.transform.rotation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public set rotation(value: number) {
|
||||||
|
this.transform.setRotation(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public get rotationDegrees(): number {
|
||||||
|
return this.transform.rotationDegrees;
|
||||||
|
}
|
||||||
|
|
||||||
|
public set rotationDegrees(value: number){
|
||||||
|
this.transform.setRotationDegrees(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public get localRotation(): number {
|
||||||
|
return this.transform.localRotation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public set localRotation(value: number){
|
||||||
|
this.transform.setLocalRotation(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public get localRotationDegrees(): number {
|
||||||
|
return this.transform.localRotationDegrees;
|
||||||
|
}
|
||||||
|
|
||||||
|
public set localRotationDegrees(value: number){
|
||||||
|
this.transform.setLocalRotationDegrees(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public get scale(): Vector2 {
|
||||||
|
return this.transform.scale;
|
||||||
|
}
|
||||||
|
|
||||||
|
public set scale(value: Vector2) {
|
||||||
|
this.transform.setScale(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public get localScale(): Vector2 {
|
||||||
|
return this.transform.localScale;
|
||||||
|
}
|
||||||
|
|
||||||
|
public set localScale(value: Vector2){
|
||||||
|
this.transform.setLocalScale(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public get worldInverseTransform(): Matrix2D {
|
||||||
|
return this.transform.worldInverseTransform;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get localToWorldTransform(): Matrix2D {
|
||||||
|
return this.transform.localToWorldTransform;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get worldToLocalTransform(): Matrix2D {
|
||||||
|
return this.transform.worldToLocalTransform;
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(name: string) {
|
||||||
|
this.components = new ComponentList(this);
|
||||||
|
this.transform = new Transform(this);
|
||||||
|
this.name = name;
|
||||||
|
this.id = Entity._idGenerator++;
|
||||||
|
|
||||||
|
this.componentBits = new BitSet();
|
||||||
|
}
|
||||||
|
|
||||||
|
public onTransformChanged(comp: transform.Component) {
|
||||||
|
// 通知我们的子项改变了位置
|
||||||
|
this.components.onEntityTransformChanged(comp);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置实体的标记
|
||||||
|
* @param tag
|
||||||
|
*/
|
||||||
|
public setTag(tag: number): Entity {
|
||||||
|
if (this._tag != tag) {
|
||||||
|
// 我们只有在已经有场景的情况下才会调用entityTagList。如果我们还没有场景,我们会被添加到entityTagList
|
||||||
|
if (this.scene)
|
||||||
|
this.scene.entities.removeFromTagList(this);
|
||||||
|
this._tag = tag;
|
||||||
|
if (this.scene)
|
||||||
|
this.scene.entities.addToTagList(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public setTag(tag: number): Entity{
|
/**
|
||||||
if (this._tag != tag){
|
* 设置实体的启用状态。当禁用碰撞器从物理系统和组件中移除时,方法将不会被调用
|
||||||
if (this.scene){
|
* @param isEnabled
|
||||||
this.scene.entities.removeFromTagList(this);
|
*/
|
||||||
|
public setEnabled(isEnabled: boolean) {
|
||||||
|
if (this._enabled != isEnabled) {
|
||||||
|
this._enabled = isEnabled;
|
||||||
|
|
||||||
|
if (this._enabled)
|
||||||
|
this.components.onEntityEnabled();
|
||||||
|
else
|
||||||
|
this.components.onEntityDisabled();
|
||||||
}
|
}
|
||||||
this._tag = tag;
|
|
||||||
if (this.scene){
|
return this;
|
||||||
this.scene.entities.addToTagList(this);
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置此实体的更新顺序。updateOrder还用于对scene.entities上的标签列表进行排序
|
||||||
|
* @param updateOrder
|
||||||
|
*/
|
||||||
|
public setUpdateOrder(updateOrder: number) {
|
||||||
|
if (this._updateOrder != updateOrder) {
|
||||||
|
this._updateOrder = updateOrder;
|
||||||
|
if (this.scene) {
|
||||||
|
this.scene.entities.markEntityListUnsorted();
|
||||||
|
this.scene.entities.markTagUnsorted(this.tag);
|
||||||
|
}
|
||||||
|
|
||||||
|
return this;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return this;
|
/**
|
||||||
}
|
* 从场景中删除实体并销毁所有子元素
|
||||||
|
*/
|
||||||
|
public destroy() {
|
||||||
|
this._isDestroyed = true;
|
||||||
|
this.scene.entities.remove(this);
|
||||||
|
this.transform.parent = null;
|
||||||
|
|
||||||
public attachToScene(newScene: Scene){
|
// 销毁所有子项
|
||||||
this.scene = newScene;
|
for (let i = this.transform.childCount - 1; i >= 0; i--) {
|
||||||
newScene.entities.add(this);
|
let child = this.transform.getChild(i);
|
||||||
this.components.registerAllComponents();
|
child.entity.destroy();
|
||||||
|
}
|
||||||
for (let i = 0; i < this.numChildren; i ++){
|
|
||||||
(this.getChildAt(i) as Component).entity.attachToScene(newScene);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public detachFromScene(){
|
|
||||||
this.scene.entities.remove(this);
|
|
||||||
this.components.deregisterAllComponents();
|
|
||||||
|
|
||||||
for (let i = 0; i < this.numChildren; i ++)
|
|
||||||
(this.getChildAt(i) as Component).entity.detachFromScene();
|
|
||||||
}
|
|
||||||
|
|
||||||
public addComponent<T extends Component>(component: T): T{
|
|
||||||
component.entity = this;
|
|
||||||
this.components.add(component);
|
|
||||||
this.addChild(component);
|
|
||||||
component.initialize();
|
|
||||||
return component;
|
|
||||||
}
|
|
||||||
|
|
||||||
public hasComponent<T extends Component>(type){
|
|
||||||
return this.components.getComponent<T>(type, false) != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public getOrCreateComponent<T extends Component>(type: T){
|
|
||||||
let comp = this.components.getComponent<T>(type, true);
|
|
||||||
if (!comp){
|
|
||||||
comp = this.addComponent<T>(type);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return comp;
|
/**
|
||||||
}
|
* 将实体从场景中分离。下面的生命周期方法将被调用在组件上:OnRemovedFromEntity
|
||||||
|
*/
|
||||||
|
public detachFromScene() {
|
||||||
|
this.scene.entities.remove(this);
|
||||||
|
this.components.deregisterAllComponents();
|
||||||
|
|
||||||
public getComponent<T extends Component>(type): T{
|
for (let i = 0; i < this.transform.childCount; i++)
|
||||||
return this.components.getComponent(type, false) as T;
|
this.transform.getChild(i).entity.detachFromScene();
|
||||||
}
|
|
||||||
|
|
||||||
public getComponents(typeName: string | any, componentList?){
|
|
||||||
return this.components.getComponents(typeName, componentList);
|
|
||||||
}
|
|
||||||
|
|
||||||
private onEntityTransformChanged(comp: TransformComponent){
|
|
||||||
this.components.onEntityTransformChanged(comp);
|
|
||||||
}
|
|
||||||
|
|
||||||
public removeComponentForType<T extends Component>(type){
|
|
||||||
let comp = this.getComponent<T>(type);
|
|
||||||
if (comp){
|
|
||||||
this.removeComponent(comp);
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
/**
|
||||||
}
|
* 将一个先前分离的实体附加到一个新的场景
|
||||||
|
* @param newScene
|
||||||
|
*/
|
||||||
|
public attachToScene(newScene: Scene) {
|
||||||
|
this.scene = newScene;
|
||||||
|
newScene.entities.add(this);
|
||||||
|
this.components.registerAllComponents();
|
||||||
|
|
||||||
public removeComponent(component: Component){
|
for (let i = 0; i < this.transform.childCount; i++) {
|
||||||
this.components.remove(component);
|
this.transform.getChild(i).entity.attachToScene(newScene);
|
||||||
}
|
}
|
||||||
|
|
||||||
public removeAllComponents(){
|
|
||||||
for (let i = 0; i < this.components.count; i ++){
|
|
||||||
this.removeComponent(this.components.buffer[i]);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public update(){
|
/**
|
||||||
this.components.update();
|
* 创建此实体的深层克隆。子类可以重写此方法来复制任何自定义字段。
|
||||||
}
|
* 当重写时,应该调用CopyFrom方法,它将为您克隆所有组件、碰撞器和转换子组件。
|
||||||
|
* 注意克隆的实体不会被添加到任何场景中!你必须自己添加它们!
|
||||||
|
* @param position
|
||||||
|
*/
|
||||||
|
public clone(position: Vector2 = new Vector2()): Entity {
|
||||||
|
let entity = new Entity(this.name + "(clone)");
|
||||||
|
entity.copyFrom(this);
|
||||||
|
entity.transform.position = position;
|
||||||
|
|
||||||
public onAddedToScene(){
|
return entity;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
/**
|
||||||
|
* 将实体的属性、组件和碰撞器复制到此实例
|
||||||
|
* @param entity
|
||||||
|
*/
|
||||||
|
protected copyFrom(entity: Entity) {
|
||||||
|
this.tag = entity.tag;
|
||||||
|
this.updateInterval = entity.updateInterval;
|
||||||
|
this.updateOrder = entity.updateOrder;
|
||||||
|
this.enabled = entity.enabled;
|
||||||
|
|
||||||
public onRemovedFromScene(){
|
this.transform.scale = entity.transform.scale;
|
||||||
if (this._isDestoryed)
|
this.transform.rotation = entity.transform.rotation;
|
||||||
this.components.removeAllComponents();
|
|
||||||
}
|
|
||||||
|
|
||||||
public destroy(){
|
for (let i = 0; i < entity.components.count; i++)
|
||||||
this._isDestoryed = true;
|
this.addComponent(entity.components.buffer[i].clone());
|
||||||
this.removeEventListener(egret.Event.ADDED_TO_STAGE, this.onAddToStage, this);
|
for (let i = 0; i < entity.components._componentsToAdd.length; i++)
|
||||||
|
this.addComponent(entity.components._componentsToAdd[i].clone());
|
||||||
|
|
||||||
this.scene.entities.remove(this);
|
for (let i = 0; i < entity.transform.childCount; i++) {
|
||||||
this.removeChildren();
|
let child = entity.transform.getChild(i).entity;
|
||||||
|
let childClone = child.clone();
|
||||||
|
childClone.transform.copyFrom(child.transform);
|
||||||
|
childClone.transform.parent = this.transform;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (this.parent)
|
/**
|
||||||
this.parent.removeChild(this);
|
* 在提交了所有挂起的实体更改后,将此实体添加到场景时调用
|
||||||
|
*/
|
||||||
|
public onAddedToScene() {
|
||||||
|
}
|
||||||
|
|
||||||
for (let i = this.numChildren - 1; i >= 0; i --){
|
/**
|
||||||
let child = this.getChildAt(i);
|
* 当此实体从场景中删除时调用
|
||||||
(child as Component).entity.destroy();
|
*/
|
||||||
|
public onRemovedFromScene() {
|
||||||
|
// 如果已经被销毁了,移走我们的组件。如果我们只是分离,我们需要保持我们的组件在实体上。
|
||||||
|
if (this._isDestroyed)
|
||||||
|
this.components.removeAllComponents();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 每帧进行调用进行更新组件
|
||||||
|
*/
|
||||||
|
public update() {
|
||||||
|
this.components.update();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将组件添加到组件列表中。返回组件。
|
||||||
|
* @param component
|
||||||
|
*/
|
||||||
|
public addComponent<T extends Component>(component: T): T {
|
||||||
|
component.entity = this;
|
||||||
|
this.components.add(component);
|
||||||
|
component.initialize();
|
||||||
|
return component;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取类型T的第一个组件并返回它。如果没有找到组件,则返回null。
|
||||||
|
* @param type
|
||||||
|
*/
|
||||||
|
public getComponent<T extends Component>(type): T {
|
||||||
|
return this.components.getComponent(type, false) as T;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查实体是否具有该组件
|
||||||
|
* @param type
|
||||||
|
*/
|
||||||
|
public hasComponent<T extends Component>(type) {
|
||||||
|
return this.components.getComponent<T>(type, false) != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取类型T的第一个组件并返回它。如果没有找到组件,将创建组件。
|
||||||
|
* @param type
|
||||||
|
*/
|
||||||
|
public getOrCreateComponent<T extends Component>(type: T) {
|
||||||
|
let comp = this.components.getComponent<T>(type, true);
|
||||||
|
if (!comp) {
|
||||||
|
comp = this.addComponent<T>(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
return comp;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取typeName类型的所有组件,但不使用列表分配
|
||||||
|
* @param typeName
|
||||||
|
* @param componentList
|
||||||
|
*/
|
||||||
|
public getComponents(typeName: string | any, componentList?) {
|
||||||
|
return this.components.getComponents(typeName, componentList);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从组件列表中删除组件
|
||||||
|
* @param component
|
||||||
|
*/
|
||||||
|
public removeComponent(component: Component) {
|
||||||
|
this.components.remove(component);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从组件列表中删除类型为T的第一个组件
|
||||||
|
* @param type
|
||||||
|
*/
|
||||||
|
public removeComponentForType<T extends Component>(type) {
|
||||||
|
let comp = this.getComponent<T>(type);
|
||||||
|
if (comp) {
|
||||||
|
this.removeComponent(comp);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从实体中删除所有组件
|
||||||
|
*/
|
||||||
|
public removeAllComponents() {
|
||||||
|
for (let i = 0; i < this.components.count; i++) {
|
||||||
|
this.removeComponent(this.components.buffer[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public compareTo(other: Entity): number {
|
||||||
|
let compare = this._updateOrder - other._updateOrder;
|
||||||
|
if (compare == 0)
|
||||||
|
compare = this.id - other.id;
|
||||||
|
return compare;
|
||||||
|
}
|
||||||
|
|
||||||
|
public toString(): string {
|
||||||
|
return `[Entity: name: ${this.name}, tag: ${this.tag}, enabled: ${this.enabled}, depth: ${this.updateOrder}]`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enum TransformComponent {
|
|
||||||
rotation,
|
|
||||||
scale,
|
|
||||||
position
|
|
||||||
}
|
|
||||||
+318
-181
@@ -1,213 +1,350 @@
|
|||||||
/** 场景 */
|
module es {
|
||||||
class Scene extends egret.DisplayObjectContainer {
|
/** 场景 */
|
||||||
public camera: Camera;
|
export class Scene extends egret.DisplayObjectContainer {
|
||||||
public readonly entities: EntityList;
|
/**
|
||||||
public readonly renderableComponents: RenderableComponentList;
|
* 默认场景摄像机
|
||||||
public readonly content: ContentManager;
|
*/
|
||||||
public enablePostProcessing = true;
|
public camera: Camera;
|
||||||
|
/**
|
||||||
|
* 场景特定内容管理器。使用它来加载仅由这个场景需要的任何资源。如果你有全局/多场景资源,你可以使用SceneManager.content。
|
||||||
|
* contentManager来加载它们,因为Nez不会卸载它们。
|
||||||
|
*/
|
||||||
|
public readonly content: ContentManager;
|
||||||
|
/**
|
||||||
|
* 全局切换后处理器
|
||||||
|
*/
|
||||||
|
public enablePostProcessing = true;
|
||||||
|
/**
|
||||||
|
* 这个场景中的实体列表
|
||||||
|
*/
|
||||||
|
public readonly entities: EntityList;
|
||||||
|
/**
|
||||||
|
* 管理当前在场景实体上的所有可呈现组件的列表
|
||||||
|
*/
|
||||||
|
public readonly renderableComponents: RenderableComponentList;
|
||||||
|
/**
|
||||||
|
* 管理所有实体处理器
|
||||||
|
*/
|
||||||
|
public readonly entityProcessors: EntityProcessorList;
|
||||||
|
|
||||||
private _renderers: Renderer[] = [];
|
public _renderers: Renderer[] = [];
|
||||||
private _postProcessors: PostProcessor[] = [];
|
public readonly _postProcessors: PostProcessor[] = [];
|
||||||
private _didSceneBegin;
|
public _didSceneBegin;
|
||||||
|
|
||||||
public readonly entityProcessors: EntityProcessorList;
|
/**
|
||||||
|
* 辅助器,创建一个场景与DefaultRenderer附加并准备使用
|
||||||
constructor() {
|
*/
|
||||||
super();
|
public static createWithDefaultRenderer(){
|
||||||
this.entityProcessors = new EntityProcessorList();
|
let scene = new Scene();
|
||||||
this.renderableComponents = new RenderableComponentList();
|
scene.addRenderer(new DefaultRenderer());
|
||||||
this.entities = new EntityList(this);
|
return scene;
|
||||||
this.content = new ContentManager();
|
|
||||||
this.width = SceneManager.stage.stageWidth;
|
|
||||||
this.height = SceneManager.stage.stageHeight;
|
|
||||||
|
|
||||||
this.addEventListener(egret.Event.ACTIVATE, this.onActive, this);
|
|
||||||
this.addEventListener(egret.Event.DEACTIVATE, this.onDeactive, this);
|
|
||||||
}
|
|
||||||
|
|
||||||
public createEntity(name: string) {
|
|
||||||
let entity = new Entity(name);
|
|
||||||
entity.position = new Vector2(0, 0);
|
|
||||||
return this.addEntity(entity);
|
|
||||||
}
|
|
||||||
|
|
||||||
public addEntity(entity: Entity) {
|
|
||||||
this.entities.add(entity);
|
|
||||||
entity.scene = this;
|
|
||||||
this.addChild(entity);
|
|
||||||
|
|
||||||
for (let i = 0; i < entity.numChildren; i++)
|
|
||||||
this.addEntity((entity.getChildAt(i) as Component).entity);
|
|
||||||
|
|
||||||
return entity;
|
|
||||||
}
|
|
||||||
|
|
||||||
public destroyAllEntities() {
|
|
||||||
for (let i = 0; i < this.entities.count; i++) {
|
|
||||||
this.entities.buffer[i].destroy();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public findEntity(name: string): Entity {
|
|
||||||
return this.entities.findEntity(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 在场景中添加一个EntitySystem处理器
|
|
||||||
* @param processor 处理器
|
|
||||||
*/
|
|
||||||
public addEntityProcessor(processor: EntitySystem) {
|
|
||||||
processor.scene = this;
|
|
||||||
this.entityProcessors.add(processor);
|
|
||||||
return processor;
|
|
||||||
}
|
|
||||||
|
|
||||||
public removeEntityProcessor(processor: EntitySystem) {
|
|
||||||
this.entityProcessors.remove(processor);
|
|
||||||
}
|
|
||||||
|
|
||||||
public getEntityProcessor<T extends EntitySystem>(): T {
|
|
||||||
return this.entityProcessors.getProcessor<T>();
|
|
||||||
}
|
|
||||||
|
|
||||||
public addRenderer<T extends Renderer>(renderer: T) {
|
|
||||||
this._renderers.push(renderer);
|
|
||||||
this._renderers.sort();
|
|
||||||
|
|
||||||
renderer.onAddedToScene(this);
|
|
||||||
|
|
||||||
return renderer;
|
|
||||||
}
|
|
||||||
|
|
||||||
public getRenderer<T extends Renderer>(type): T {
|
|
||||||
for (let i = 0; i < this._renderers.length; i++) {
|
|
||||||
if (this._renderers[i] instanceof type)
|
|
||||||
return this._renderers[i] as T;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
constructor() {
|
||||||
}
|
super();
|
||||||
|
this.entities = new EntityList(this);
|
||||||
|
this.renderableComponents = new RenderableComponentList();
|
||||||
|
this.content = new ContentManager();
|
||||||
|
|
||||||
public removeRenderer(renderer: Renderer) {
|
this.entityProcessors = new EntityProcessorList();
|
||||||
this._renderers.remove(renderer);
|
|
||||||
renderer.unload();
|
|
||||||
}
|
|
||||||
|
|
||||||
public begin() {
|
this.initialize();
|
||||||
if (SceneManager.sceneTransition){
|
|
||||||
SceneManager.stage.addChildAt(this, SceneManager.stage.numChildren - 1);
|
|
||||||
}else{
|
|
||||||
SceneManager.stage.addChild(this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this._renderers.length == 0) {
|
/**
|
||||||
this.addRenderer(new DefaultRenderer());
|
* 在场景子类中重写这个并在这里进行加载。在场景设置好之后,在调用begin之前,从构造器中调用。
|
||||||
console.warn("场景开始时没有渲染器 自动添加DefaultRenderer以保证能够正常渲染");
|
*/
|
||||||
}
|
public initialize(){}
|
||||||
/** 初始化默认相机 */
|
|
||||||
this.camera = this.createEntity("camera").getOrCreateComponent(new Camera());
|
|
||||||
|
|
||||||
Physics.reset();
|
/**
|
||||||
|
* 在场景子类中重写这个。当SceneManager将此场景设置为活动场景时,将调用此操作。
|
||||||
|
*/
|
||||||
|
public async onStart() {}
|
||||||
|
|
||||||
if (this.entityProcessors)
|
/**
|
||||||
this.entityProcessors.begin();
|
* 在场景子类中重写这个,并在这里做任何必要的卸载。当SceneManager从活动槽中删除此场景时调用。
|
||||||
|
*/
|
||||||
|
public unload() { }
|
||||||
|
|
||||||
this.camera.onSceneSizeChanged(this.stage.stageWidth, this.stage.stageHeight);
|
|
||||||
|
|
||||||
this._didSceneBegin = true;
|
/**
|
||||||
this.onStart();
|
* 在场景子类中重写这个,当该场景当获得焦点时调用
|
||||||
}
|
*/
|
||||||
|
public onActive() {}
|
||||||
|
|
||||||
public end() {
|
/**
|
||||||
this._didSceneBegin = false;
|
* 在场景子类中重写这个,当该场景当失去焦点时调用
|
||||||
|
*/
|
||||||
|
public onDeactive() {}
|
||||||
|
|
||||||
this.removeEventListener(egret.Event.DEACTIVATE, this.onDeactive, this);
|
public async begin() {
|
||||||
this.removeEventListener(egret.Event.ACTIVATE, this.onActive, this);
|
if (this._renderers.length == 0) {
|
||||||
|
this.addRenderer(new DefaultRenderer());
|
||||||
|
console.warn("场景开始时没有渲染器 自动添加DefaultRenderer以保证能够正常渲染");
|
||||||
|
}
|
||||||
|
|
||||||
for (let i = 0; i < this._renderers.length; i++) {
|
this.camera = this.createEntity("camera").getOrCreateComponent(new Camera());
|
||||||
this._renderers[i].unload();
|
|
||||||
|
Physics.reset();
|
||||||
|
|
||||||
|
if (this.entityProcessors)
|
||||||
|
this.entityProcessors.begin();
|
||||||
|
|
||||||
|
this.addEventListener(egret.Event.ACTIVATE, this.onActive, this);
|
||||||
|
this.addEventListener(egret.Event.DEACTIVATE, this.onDeactive, this);
|
||||||
|
this.camera.onSceneSizeChanged(this.stage.stageWidth, this.stage.stageHeight);
|
||||||
|
|
||||||
|
this._didSceneBegin = true;
|
||||||
|
this.onStart();
|
||||||
}
|
}
|
||||||
|
|
||||||
for (let i = 0; i < this._postProcessors.length; i++) {
|
public end() {
|
||||||
this._postProcessors[i].unload();
|
this._didSceneBegin = false;
|
||||||
}
|
|
||||||
|
|
||||||
this.entities.removeAllEntities();
|
this.removeEventListener(egret.Event.DEACTIVATE, this.onDeactive, this);
|
||||||
this.removeChildren();
|
this.removeEventListener(egret.Event.ACTIVATE, this.onActive, this);
|
||||||
|
|
||||||
Physics.clear();
|
for (let i = 0; i < this._renderers.length; i++) {
|
||||||
|
this._renderers[i].unload();
|
||||||
|
}
|
||||||
|
|
||||||
this.camera = null;
|
|
||||||
this.content.dispose();
|
|
||||||
|
|
||||||
if (this.entityProcessors)
|
|
||||||
this.entityProcessors.end();
|
|
||||||
|
|
||||||
this.unload();
|
|
||||||
|
|
||||||
if (this.parent)
|
|
||||||
this.parent.removeChild(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected async onStart() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 场景激活 */
|
|
||||||
protected onActive() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 场景失去焦点 */
|
|
||||||
protected onDeactive() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
protected unload() { }
|
|
||||||
|
|
||||||
public update() {
|
|
||||||
this.entities.updateLists();
|
|
||||||
|
|
||||||
if (this.entityProcessors)
|
|
||||||
this.entityProcessors.update()
|
|
||||||
|
|
||||||
this.entities.update();
|
|
||||||
|
|
||||||
if (this.entityProcessors)
|
|
||||||
this.entityProcessors.lateUpdate();
|
|
||||||
|
|
||||||
this.renderableComponents.updateList();
|
|
||||||
}
|
|
||||||
|
|
||||||
public postRender() {
|
|
||||||
let enabledCounter = 0;
|
|
||||||
if (this.enablePostProcessing) {
|
|
||||||
for (let i = 0; i < this._postProcessors.length; i++) {
|
for (let i = 0; i < this._postProcessors.length; i++) {
|
||||||
if (this._postProcessors[i].enable) {
|
this._postProcessors[i].unload();
|
||||||
let isEven = MathHelper.isEven(enabledCounter);
|
}
|
||||||
enabledCounter ++;
|
|
||||||
|
|
||||||
this._postProcessors[i].process();
|
this.entities.removeAllEntities();
|
||||||
|
this.removeChildren();
|
||||||
|
|
||||||
|
this.camera = null;
|
||||||
|
this.content.dispose();
|
||||||
|
|
||||||
|
if (this.entityProcessors)
|
||||||
|
this.entityProcessors.end();
|
||||||
|
|
||||||
|
if (this.parent)
|
||||||
|
this.parent.removeChild(this);
|
||||||
|
|
||||||
|
this.unload();
|
||||||
|
}
|
||||||
|
|
||||||
|
public update() {
|
||||||
|
// 更新我们的列表,以防它们有任何变化
|
||||||
|
this.entities.updateLists();
|
||||||
|
|
||||||
|
// 更新我们的实体解析器
|
||||||
|
if (this.entityProcessors)
|
||||||
|
this.entityProcessors.update();
|
||||||
|
|
||||||
|
// 更新我们的实体组
|
||||||
|
this.entities.update();
|
||||||
|
|
||||||
|
if (this.entityProcessors)
|
||||||
|
this.entityProcessors.lateUpdate();
|
||||||
|
|
||||||
|
// 我们在实体之后更新我们的呈现。如果添加了任何新的渲染,请进行更新
|
||||||
|
this.renderableComponents.updateList();
|
||||||
|
}
|
||||||
|
|
||||||
|
public render() {
|
||||||
|
if (this._renderers.length == 0){
|
||||||
|
console.error("there are no renderers in the scene!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let i = 0; i < this._renderers.length; i++) {
|
||||||
|
this._renderers[i].render(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 现在的任何后处理器都要完成它的处理
|
||||||
|
* 只有在SceneTransition请求渲染时,它才会有一个值。
|
||||||
|
*/
|
||||||
|
public postRender() {
|
||||||
|
if (this.enablePostProcessing) {
|
||||||
|
for (let i = 0; i < this._postProcessors.length; i++) {
|
||||||
|
if (this._postProcessors[i].enabled) {
|
||||||
|
this._postProcessors[i].process();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public render() {
|
/**
|
||||||
for (let i = 0; i < this._renderers.length; i++) {
|
* 为场景添加一个渲染器
|
||||||
this._renderers[i].render(this);
|
* @param renderer
|
||||||
}
|
*/
|
||||||
}
|
public addRenderer<T extends Renderer>(renderer: T) {
|
||||||
|
this._renderers.push(renderer);
|
||||||
|
this._renderers.sort();
|
||||||
|
|
||||||
public addPostProcessor<T extends PostProcessor>(postProcessor: T): T{
|
renderer.onAddedToScene(this);
|
||||||
this._postProcessors.push(postProcessor);
|
|
||||||
this._postProcessors.sort();
|
|
||||||
postProcessor.onAddedToScene(this);
|
|
||||||
|
|
||||||
if (this._didSceneBegin){
|
return renderer;
|
||||||
postProcessor.onSceneBackBufferSizeChanged(this.stage.stageWidth, this.stage.stageHeight);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return postProcessor;
|
/**
|
||||||
|
* 获取类型为T的第一个渲染器
|
||||||
|
* @param type
|
||||||
|
*/
|
||||||
|
public getRenderer<T extends Renderer>(type): T {
|
||||||
|
for (let i = 0; i < this._renderers.length; i++) {
|
||||||
|
if (this._renderers[i] instanceof type)
|
||||||
|
return this._renderers[i] as T;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从场景中移除渲染器
|
||||||
|
* @param renderer
|
||||||
|
*/
|
||||||
|
public removeRenderer(renderer: Renderer) {
|
||||||
|
if (!this._renderers.contains(renderer))
|
||||||
|
return;
|
||||||
|
this._renderers.remove(renderer);
|
||||||
|
renderer.unload();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 添加一个后处理器到场景。设置场景字段并调用后处理器。onAddedToScene使后处理器可以使用场景ContentManager加载资源。
|
||||||
|
* @param postProcessor
|
||||||
|
*/
|
||||||
|
public addPostProcessor<T extends PostProcessor>(postProcessor: T): T{
|
||||||
|
this._postProcessors.push(postProcessor);
|
||||||
|
this._postProcessors.sort();
|
||||||
|
postProcessor.onAddedToScene(this);
|
||||||
|
|
||||||
|
if (this._didSceneBegin){
|
||||||
|
postProcessor.onSceneBackBufferSizeChanged(this.stage.stageWidth, this.stage.stageHeight);
|
||||||
|
}
|
||||||
|
|
||||||
|
return postProcessor;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取类型为T的第一个后处理器
|
||||||
|
* @param type
|
||||||
|
*/
|
||||||
|
public getPostProcessor<T extends PostProcessor>(type): T{
|
||||||
|
for (let i = 0; i < this._postProcessors.length; i ++){
|
||||||
|
if (this._postProcessors[i] instanceof type)
|
||||||
|
return this._postProcessors[i] as T;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除一个后处理程序。注意,在删除时不会调用unload,因此如果不再需要PostProcessor,请确保调用unload来释放资源。
|
||||||
|
* @param postProcessor
|
||||||
|
*/
|
||||||
|
public removePostProcessor(postProcessor: PostProcessor){
|
||||||
|
if (!this._postProcessors.contains(postProcessor))
|
||||||
|
return;
|
||||||
|
|
||||||
|
this._postProcessors.remove(postProcessor);
|
||||||
|
postProcessor.unload();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将实体添加到此场景,并返回它
|
||||||
|
* @param name
|
||||||
|
*/
|
||||||
|
public createEntity(name: string) {
|
||||||
|
let entity = new Entity(name);
|
||||||
|
return this.addEntity(entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 在场景的实体列表中添加一个实体
|
||||||
|
* @param entity
|
||||||
|
*/
|
||||||
|
public addEntity(entity: Entity) {
|
||||||
|
if (this.entities.buffer.contains(entity))
|
||||||
|
console.warn(`You are attempting to add the same entity to a scene twice: ${entity}`);
|
||||||
|
this.entities.add(entity);
|
||||||
|
entity.scene = this;
|
||||||
|
|
||||||
|
for (let i = 0; i < entity.transform.childCount; i++)
|
||||||
|
this.addEntity(entity.transform.getChild(i).entity);
|
||||||
|
|
||||||
|
return entity;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从场景中删除所有实体
|
||||||
|
*/
|
||||||
|
public destroyAllEntities() {
|
||||||
|
for (let i = 0; i < this.entities.count; i++) {
|
||||||
|
this.entities.buffer[i].destroy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 搜索并返回第一个具有名称的实体
|
||||||
|
* @param name
|
||||||
|
*/
|
||||||
|
public findEntity(name: string): Entity {
|
||||||
|
return this.entities.findEntity(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 返回具有给定标记的所有实体
|
||||||
|
* @param tag
|
||||||
|
*/
|
||||||
|
public findEntitiesWithTag(tag: number): Entity[]{
|
||||||
|
return this.entities.entitiesWithTag(tag);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 返回类型为T的所有实体
|
||||||
|
* @param type
|
||||||
|
*/
|
||||||
|
public entitiesOfType<T extends Entity>(type): T[]{
|
||||||
|
return this.entities.entitiesOfType<T>(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 返回第一个启用加载的类型为T的组件
|
||||||
|
* @param type
|
||||||
|
*/
|
||||||
|
public findComponentOfType<T extends Component>(type): T {
|
||||||
|
return this.entities.findComponentOfType<T>(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 返回类型为T的所有已启用已加载组件的列表
|
||||||
|
* @param type
|
||||||
|
*/
|
||||||
|
public findComponentsOfType<T extends Component>(type): T[] {
|
||||||
|
return this.entities.findComponentsOfType<T>(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 在场景中添加一个EntitySystem处理器
|
||||||
|
* @param processor 处理器
|
||||||
|
*/
|
||||||
|
public addEntityProcessor(processor: EntitySystem) {
|
||||||
|
processor.scene = this;
|
||||||
|
this.entityProcessors.add(processor);
|
||||||
|
return processor;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从场景中删除EntitySystem处理器
|
||||||
|
* @param processor
|
||||||
|
*/
|
||||||
|
public removeEntityProcessor(processor: EntitySystem) {
|
||||||
|
this.entityProcessors.remove(processor);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取EntitySystem处理器
|
||||||
|
*/
|
||||||
|
public getEntityProcessor<T extends EntitySystem>(): T {
|
||||||
|
return this.entityProcessors.getProcessor<T>();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,131 +0,0 @@
|
|||||||
/** 运行时的场景管理。 */
|
|
||||||
class SceneManager {
|
|
||||||
private static _scene: Scene;
|
|
||||||
private static _nextScene: Scene;
|
|
||||||
public static sceneTransition: SceneTransition;
|
|
||||||
public static stage: egret.Stage;
|
|
||||||
/** 订阅此事件以在活动场景发生更改时得到通知。 */
|
|
||||||
public static activeSceneChanged: Function;
|
|
||||||
/** 核心发射器。只发出核心级别的事件 */
|
|
||||||
public static emitter: Emitter<CoreEvents>;
|
|
||||||
/** 全局内容管理器加载任何应该停留在场景之间的资产 */
|
|
||||||
public static content: ContentManager;
|
|
||||||
/** 简化对内部类的全局内容实例的访问 */
|
|
||||||
private static _instnace: SceneManager;
|
|
||||||
public static get Instance(){
|
|
||||||
return this._instnace;
|
|
||||||
}
|
|
||||||
|
|
||||||
constructor(stage: egret.Stage) {
|
|
||||||
stage.addEventListener(egret.Event.ENTER_FRAME, SceneManager.update, this);
|
|
||||||
|
|
||||||
SceneManager._instnace = this;
|
|
||||||
SceneManager.emitter = new Emitter<CoreEvents>();
|
|
||||||
SceneManager.content = new ContentManager();
|
|
||||||
|
|
||||||
SceneManager.stage = stage;
|
|
||||||
SceneManager.initialize(stage);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static get scene() {
|
|
||||||
return this._scene;
|
|
||||||
}
|
|
||||||
public static set scene(value: Scene) {
|
|
||||||
if (!value)
|
|
||||||
throw new Error("场景不能为空");
|
|
||||||
|
|
||||||
if (this._scene == null) {
|
|
||||||
this._scene = value;
|
|
||||||
this._scene.begin();
|
|
||||||
SceneManager.Instance.onSceneChanged();
|
|
||||||
} else {
|
|
||||||
this._nextScene = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.registerActiveSceneChanged(this._scene, this._nextScene);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static initialize(stage: egret.Stage) {
|
|
||||||
Input.initialize(stage);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static update() {
|
|
||||||
Time.update(egret.getTimer());
|
|
||||||
|
|
||||||
if (SceneManager._scene) {
|
|
||||||
for (let i = GlobalManager.globalManagers.length - 1; i >= 0; i--) {
|
|
||||||
if (GlobalManager.globalManagers[i].enabled)
|
|
||||||
GlobalManager.globalManagers[i].update();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!SceneManager.sceneTransition ||
|
|
||||||
(SceneManager.sceneTransition && (!SceneManager.sceneTransition.loadsNewScene || SceneManager.sceneTransition.isNewSceneLoaded))) {
|
|
||||||
SceneManager._scene.update();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (SceneManager._nextScene) {
|
|
||||||
SceneManager._scene.end();
|
|
||||||
|
|
||||||
SceneManager._scene = SceneManager._nextScene;
|
|
||||||
SceneManager._nextScene = null;
|
|
||||||
SceneManager._instnace.onSceneChanged();
|
|
||||||
|
|
||||||
SceneManager._scene.begin();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
SceneManager.render();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static render() {
|
|
||||||
if (this.sceneTransition){
|
|
||||||
this.sceneTransition.preRender();
|
|
||||||
|
|
||||||
if (this._scene && !this.sceneTransition.hasPreviousSceneRender){
|
|
||||||
this._scene.render();
|
|
||||||
this._scene.postRender();
|
|
||||||
this.sceneTransition.onBeginTransition();
|
|
||||||
} else if (this.sceneTransition) {
|
|
||||||
if (this._scene && this.sceneTransition.isNewSceneLoaded) {
|
|
||||||
this._scene.render();
|
|
||||||
this._scene.postRender();
|
|
||||||
}
|
|
||||||
|
|
||||||
this.sceneTransition.render();
|
|
||||||
}
|
|
||||||
} else if (this._scene) {
|
|
||||||
this._scene.render();
|
|
||||||
|
|
||||||
Debug.render();
|
|
||||||
|
|
||||||
this._scene.postRender();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 临时运行SceneTransition,允许一个场景过渡到另一个平滑的自定义效果。
|
|
||||||
* @param sceneTransition
|
|
||||||
*/
|
|
||||||
public static startSceneTransition<T extends SceneTransition>(sceneTransition: T): T {
|
|
||||||
if (this.sceneTransition) {
|
|
||||||
console.warn("在前一个场景完成之前,不能开始一个新的场景转换。");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.sceneTransition = sceneTransition;
|
|
||||||
return sceneTransition;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static registerActiveSceneChanged(current: Scene, next: Scene){
|
|
||||||
if (this.activeSceneChanged)
|
|
||||||
this.activeSceneChanged(current, next);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 在一个场景结束后,下一个场景开始之前调用
|
|
||||||
*/
|
|
||||||
public onSceneChanged(){
|
|
||||||
SceneManager.emitter.emit(CoreEvents.SceneChanged);
|
|
||||||
Time.sceneChanged();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,32 +1,34 @@
|
|||||||
///<reference path="./EntitySystem.ts" />
|
///<reference path="./EntitySystem.ts" />
|
||||||
/**
|
module es {
|
||||||
* 基本实体处理系统。将其用作处理具有特定组件的许多实体的基础
|
|
||||||
*/
|
|
||||||
abstract class EntityProcessingSystem extends EntitySystem {
|
|
||||||
constructor(matcher: Matcher) {
|
|
||||||
super(matcher);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 处理特定的实体
|
* 基本实体处理系统。将其用作处理具有特定组件的许多实体的基础
|
||||||
* @param entity
|
|
||||||
*/
|
*/
|
||||||
public abstract processEntity(entity: Entity);
|
export abstract class EntityProcessingSystem extends EntitySystem {
|
||||||
|
constructor(matcher: Matcher) {
|
||||||
|
super(matcher);
|
||||||
|
}
|
||||||
|
|
||||||
public lateProcessEntity(entity: Entity) {
|
|
||||||
|
|
||||||
}
|
/**
|
||||||
|
* 处理特定的实体
|
||||||
|
* @param entity
|
||||||
|
*/
|
||||||
|
public abstract processEntity(entity: Entity);
|
||||||
|
|
||||||
/**
|
public lateProcessEntity(entity: Entity) {
|
||||||
* 遍历这个系统的所有实体并逐个处理它们
|
|
||||||
* @param entities
|
|
||||||
*/
|
|
||||||
protected process(entities: Entity[]) {
|
|
||||||
entities.forEach(entity => this.processEntity(entity));
|
|
||||||
}
|
|
||||||
|
|
||||||
protected lateProcess(entities: Entity[]) {
|
}
|
||||||
entities.forEach(entity => this.lateProcessEntity(entity));
|
|
||||||
|
/**
|
||||||
|
* 遍历这个系统的所有实体并逐个处理它们
|
||||||
|
* @param entities
|
||||||
|
*/
|
||||||
|
protected process(entities: Entity[]) {
|
||||||
|
entities.forEach(entity => this.processEntity(entity));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected lateProcess(entities: Entity[]) {
|
||||||
|
entities.forEach(entity => this.lateProcessEntity(entity));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,79 +1,81 @@
|
|||||||
class EntitySystem {
|
module es {
|
||||||
private _scene: Scene;
|
export class EntitySystem {
|
||||||
private _entities: Entity[] = [];
|
private _scene: Scene;
|
||||||
private _matcher: Matcher;
|
private _entities: Entity[] = [];
|
||||||
|
private _matcher: Matcher;
|
||||||
|
|
||||||
public get matcher(){
|
public get matcher(){
|
||||||
return this._matcher;
|
return this._matcher;
|
||||||
}
|
}
|
||||||
|
|
||||||
public get scene(){
|
public get scene(){
|
||||||
return this._scene;
|
return this._scene;
|
||||||
}
|
}
|
||||||
|
|
||||||
public set scene(value: Scene){
|
public set scene(value: Scene){
|
||||||
this._scene = value;
|
this._scene = value;
|
||||||
this._entities = [];
|
this._entities = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(matcher?: Matcher){
|
constructor(matcher?: Matcher){
|
||||||
this._matcher = matcher ? matcher : Matcher.empty();
|
this._matcher = matcher ? matcher : Matcher.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
public initialize(){
|
public initialize(){
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public onChanged(entity: Entity){
|
public onChanged(entity: Entity){
|
||||||
let contains = this._entities.contains(entity);
|
let contains = this._entities.contains(entity);
|
||||||
let interest = this._matcher.IsIntersted(entity);
|
let interest = this._matcher.IsIntersted(entity);
|
||||||
|
|
||||||
if (interest && !contains)
|
if (interest && !contains)
|
||||||
this.add(entity);
|
this.add(entity);
|
||||||
else if(!interest && contains)
|
else if(!interest && contains)
|
||||||
this.remove(entity);
|
this.remove(entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
public add(entity: Entity){
|
public add(entity: Entity){
|
||||||
this._entities.push(entity);
|
this._entities.push(entity);
|
||||||
this.onAdded(entity);
|
this.onAdded(entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
public onAdded(entity: Entity){
|
public onAdded(entity: Entity){
|
||||||
}
|
}
|
||||||
|
|
||||||
public remove(entity: Entity){
|
public remove(entity: Entity){
|
||||||
this._entities.remove(entity);
|
this._entities.remove(entity);
|
||||||
this.onRemoved(entity);
|
this.onRemoved(entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
public onRemoved(entity: Entity){
|
public onRemoved(entity: Entity){
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public update(){
|
public update(){
|
||||||
this.begin();
|
this.begin();
|
||||||
this.process(this._entities);
|
this.process(this._entities);
|
||||||
}
|
}
|
||||||
|
|
||||||
public lateUpdate(){
|
public lateUpdate(){
|
||||||
this.lateProcess(this._entities);
|
this.lateProcess(this._entities);
|
||||||
this.end();
|
this.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected begin(){
|
protected begin(){
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected process(entities: Entity[]){
|
protected process(entities: Entity[]){
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected lateProcess(entities: Entity[]){
|
protected lateProcess(entities: Entity[]){
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected end(){
|
protected end(){
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,11 +1,13 @@
|
|||||||
abstract class PassiveSystem extends EntitySystem {
|
module es {
|
||||||
public onChanged(entity: Entity){
|
export abstract class PassiveSystem extends EntitySystem {
|
||||||
|
public onChanged(entity: Entity){
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected process(entities: Entity[]){
|
protected process(entities: Entity[]){
|
||||||
// 我们用我们自己的不考虑实体的基本实体系统来代替
|
// 我们用我们自己的不考虑实体的基本实体系统来代替
|
||||||
this.begin();
|
this.begin();
|
||||||
this.end();
|
this.end();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,15 +1,17 @@
|
|||||||
/** 用于协调其他系统的通用系统基类 */
|
/** 用于协调其他系统的通用系统基类 */
|
||||||
abstract class ProcessingSystem extends EntitySystem {
|
module es {
|
||||||
public onChanged(entity: Entity){
|
export abstract class ProcessingSystem extends EntitySystem {
|
||||||
|
public onChanged(entity: Entity){
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
protected process(entities: Entity[]){
|
||||||
|
this.begin();
|
||||||
|
this.processSystem();
|
||||||
|
this.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 处理我们的系统 每帧调用 */
|
||||||
|
public abstract processSystem();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected process(entities: Entity[]){
|
|
||||||
this.begin();
|
|
||||||
this.processSystem();
|
|
||||||
this.end();
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 处理我们的系统 每帧调用 */
|
|
||||||
public abstract processSystem();
|
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,504 @@
|
|||||||
|
module transform {
|
||||||
|
export enum Component {
|
||||||
|
position,
|
||||||
|
scale,
|
||||||
|
rotation,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module es {
|
||||||
|
import HashObject = egret.HashObject;
|
||||||
|
|
||||||
|
export enum DirtyType {
|
||||||
|
clean,
|
||||||
|
positionDirty,
|
||||||
|
scaleDirty,
|
||||||
|
rotationDirty,
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Transform extends HashObject {
|
||||||
|
/** 与此转换关联的实体 */
|
||||||
|
public readonly entity: Entity;
|
||||||
|
/**
|
||||||
|
* 获取此转换的父转换
|
||||||
|
*/
|
||||||
|
public get parent() {
|
||||||
|
return this._parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置此转换的父转换
|
||||||
|
* @param value
|
||||||
|
*/
|
||||||
|
public set parent(value: Transform) {
|
||||||
|
this.setParent(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 这个转换的所有子元素
|
||||||
|
*/
|
||||||
|
public get childCount() {
|
||||||
|
return this._children.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 变换在世界空间中的位置
|
||||||
|
*/
|
||||||
|
public get position(): Vector2 {
|
||||||
|
this.updateTransform();
|
||||||
|
if (this._positionDirty){
|
||||||
|
if (!this.parent){
|
||||||
|
this._position = this._localPosition;
|
||||||
|
}else{
|
||||||
|
this.parent.updateTransform();
|
||||||
|
this._position = Vector2Ext.transformR(this._localPosition, this.parent._worldTransform);
|
||||||
|
}
|
||||||
|
|
||||||
|
this._positionDirty = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this._position;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 变换在世界空间中的位置
|
||||||
|
* @param value
|
||||||
|
*/
|
||||||
|
public set position(value: Vector2){
|
||||||
|
this.setPosition(value.x, value.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 转换相对于父转换的位置。如果转换没有父元素,则与transform.position相同
|
||||||
|
*/
|
||||||
|
public get localPosition(): Vector2 {
|
||||||
|
this.updateTransform();
|
||||||
|
return this._localPosition;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 转换相对于父转换的位置。如果转换没有父元素,则与transform.position相同
|
||||||
|
* @param value
|
||||||
|
*/
|
||||||
|
public set localPosition(value: Vector2){
|
||||||
|
this.setLocalPosition(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 在世界空间中以弧度旋转的变换
|
||||||
|
*/
|
||||||
|
public get rotation(): number {
|
||||||
|
this.updateTransform();
|
||||||
|
return this._rotation;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 变换在世界空间的旋转度
|
||||||
|
*/
|
||||||
|
public get rotationDegrees(): number {
|
||||||
|
return MathHelper.toDegrees(this._rotation);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 变换在世界空间的旋转度
|
||||||
|
* @param value
|
||||||
|
*/
|
||||||
|
public set rotationDegrees(value: number){
|
||||||
|
this.setRotation(MathHelper.toRadians(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 变换在世界空间的旋转度
|
||||||
|
* @param value
|
||||||
|
*/
|
||||||
|
public set rotation(value: number){
|
||||||
|
this.setRotation(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 相对于父变换的旋转,变换的旋转。如果转换没有父元素,则与transform.rotation相同
|
||||||
|
*/
|
||||||
|
public get localRotation(): number {
|
||||||
|
this.updateTransform();
|
||||||
|
return this._localRotation;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 相对于父变换的旋转,变换的旋转。如果转换没有父元素,则与transform.rotation相同
|
||||||
|
* @param value
|
||||||
|
*/
|
||||||
|
public set localRotation(value: number){
|
||||||
|
this.setLocalRotation(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 旋转相对于父变换旋转的角度
|
||||||
|
*/
|
||||||
|
public get localRotationDegrees(): number {
|
||||||
|
return MathHelper.toDegrees(this._localRotation);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 旋转相对于父变换旋转的角度
|
||||||
|
* @param value
|
||||||
|
*/
|
||||||
|
public set localRotationDegrees(value: number){
|
||||||
|
this.localRotation = MathHelper.toRadians(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 变换在世界空间的缩放
|
||||||
|
*/
|
||||||
|
public get scale(): Vector2{
|
||||||
|
this.updateTransform();
|
||||||
|
return this._scale;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 变换在世界空间的缩放
|
||||||
|
* @param value
|
||||||
|
*/
|
||||||
|
public set scale(value: Vector2){
|
||||||
|
this.setScale(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 转换相对于父元素的比例。如果转换没有父元素,则与transform.scale相同
|
||||||
|
*/
|
||||||
|
public get localScale(): Vector2 {
|
||||||
|
this.updateTransform();
|
||||||
|
return this._localScale;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 转换相对于父元素的比例。如果转换没有父元素,则与transform.scale相同
|
||||||
|
* @param value
|
||||||
|
*/
|
||||||
|
public set localScale(value: Vector2){
|
||||||
|
this.setLocalScale(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public get worldInverseTransform(): Matrix2D {
|
||||||
|
this.updateTransform();
|
||||||
|
if (this._worldInverseDirty){
|
||||||
|
this._worldInverseTransform = this._worldTransform.invert();
|
||||||
|
this._worldInverseDirty = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this._worldInverseTransform;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get localToWorldTransform(): Matrix2D {
|
||||||
|
this.updateTransform();
|
||||||
|
return this._worldTransform;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get worldToLocalTransform(): Matrix2D {
|
||||||
|
if (this._worldToLocalDirty){
|
||||||
|
if (!this.parent){
|
||||||
|
this._worldToLocalTransform = Matrix2D.create().identity();
|
||||||
|
}else{
|
||||||
|
this.parent.updateTransform();
|
||||||
|
this._worldToLocalTransform = this.parent._worldTransform.invert();
|
||||||
|
}
|
||||||
|
|
||||||
|
this._worldToLocalDirty = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this._worldToLocalTransform;
|
||||||
|
}
|
||||||
|
|
||||||
|
public _parent: Transform;
|
||||||
|
public hierarchyDirty: DirtyType;
|
||||||
|
|
||||||
|
public _localDirty: boolean;
|
||||||
|
public _localPositionDirty: boolean;
|
||||||
|
public _localScaleDirty: boolean;
|
||||||
|
public _localRotationDirty: boolean;
|
||||||
|
public _positionDirty: boolean;
|
||||||
|
public _worldToLocalDirty: boolean;
|
||||||
|
public _worldInverseDirty: boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 值会根据位置、旋转和比例自动重新计算
|
||||||
|
*/
|
||||||
|
public _localTransform: Matrix2D = Matrix2D.create();
|
||||||
|
/**
|
||||||
|
* 值将自动从本地和父矩阵重新计算。
|
||||||
|
*/
|
||||||
|
public _worldTransform = Matrix2D.create().identity();
|
||||||
|
public _worldToLocalTransform = Matrix2D.create().identity();
|
||||||
|
public _worldInverseTransform = Matrix2D.create().identity();
|
||||||
|
|
||||||
|
public _rotationMatrix: Matrix2D = Matrix2D.create();
|
||||||
|
public _translationMatrix: Matrix2D = Matrix2D.create();
|
||||||
|
public _scaleMatrix: Matrix2D = Matrix2D.create();
|
||||||
|
|
||||||
|
public _position: Vector2 = Vector2.zero;
|
||||||
|
public _scale: Vector2 = Vector2.one;
|
||||||
|
public _rotation: number = 0;
|
||||||
|
|
||||||
|
public _localPosition: Vector2 = Vector2.zero;
|
||||||
|
public _localScale: Vector2 = Vector2.one;
|
||||||
|
public _localRotation: number = 0;
|
||||||
|
|
||||||
|
public _children: Transform[];
|
||||||
|
|
||||||
|
constructor(entity: Entity) {
|
||||||
|
super();
|
||||||
|
this.entity = entity;
|
||||||
|
this.scale = Vector2.one;
|
||||||
|
this._children = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 返回在索引处的转换子元素
|
||||||
|
* @param index
|
||||||
|
*/
|
||||||
|
public getChild(index: number): Transform {
|
||||||
|
return this._children[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置此转换的父转换
|
||||||
|
* @param parent
|
||||||
|
*/
|
||||||
|
public setParent(parent: Transform): Transform {
|
||||||
|
if (this._parent.equals(parent))
|
||||||
|
return this;
|
||||||
|
|
||||||
|
if (!this._parent) {
|
||||||
|
this._parent._children.remove(this);
|
||||||
|
this._parent._children.push(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
this._parent = parent;
|
||||||
|
this.setDirty(DirtyType.positionDirty);
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置转换在世界空间中的位置
|
||||||
|
* @param x
|
||||||
|
* @param y
|
||||||
|
*/
|
||||||
|
public setPosition(x: number, y: number): Transform {
|
||||||
|
let position = new Vector2(x, y);
|
||||||
|
if (position.equals(this._position))
|
||||||
|
return this;
|
||||||
|
|
||||||
|
this._position = position;
|
||||||
|
if (this.parent){
|
||||||
|
this.localPosition = Vector2Ext.transformR(this._position, this._worldToLocalTransform);
|
||||||
|
} else {
|
||||||
|
this.localPosition = position;
|
||||||
|
}
|
||||||
|
this._positionDirty = false;
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置转换相对于父转换的位置。如果转换没有父元素,则与transform.position相同
|
||||||
|
* @param localPosition
|
||||||
|
*/
|
||||||
|
public setLocalPosition(localPosition: Vector2): Transform {
|
||||||
|
if (localPosition.equals(this._localPosition))
|
||||||
|
return this;
|
||||||
|
|
||||||
|
this._localPosition = localPosition;
|
||||||
|
this._localDirty = this._positionDirty = this._localPositionDirty = this._localRotationDirty = this._localScaleDirty = true;
|
||||||
|
this.setDirty(DirtyType.positionDirty);
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置变换在世界空间的旋转度
|
||||||
|
* @param radians
|
||||||
|
*/
|
||||||
|
public setRotation(radians: number): Transform {
|
||||||
|
this._rotation = radians;
|
||||||
|
if (this.parent){
|
||||||
|
this.localRotation = this.parent.rotation + radians;
|
||||||
|
} else {
|
||||||
|
this.localRotation = radians;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置变换在世界空间的旋转度
|
||||||
|
* @param degrees
|
||||||
|
*/
|
||||||
|
public setRotationDegrees(degrees: number): Transform {
|
||||||
|
return this.setRotation(MathHelper.toRadians(degrees));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 旋转精灵的顶部,使其朝向位置
|
||||||
|
* @param pos
|
||||||
|
*/
|
||||||
|
public lookAt(pos: Vector2) {
|
||||||
|
let sign = this.position.x > pos.x ? -1 : 1;
|
||||||
|
let vectorToAlignTo = Vector2.normalize(Vector2.subtract(this.position, pos));
|
||||||
|
this.rotation = sign * Math.acos(Vector2.dot(vectorToAlignTo, Vector2.unitY));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 相对于父变换的旋转设置变换的旋转。如果转换没有父元素,则与transform.rotation相同
|
||||||
|
* @param radians
|
||||||
|
*/
|
||||||
|
public setLocalRotation(radians: number){
|
||||||
|
this._localRotation = radians;
|
||||||
|
this._localDirty = this._positionDirty = this._localPositionDirty = this._localRotationDirty = this._localScaleDirty = true;
|
||||||
|
this.setDirty(DirtyType.rotationDirty);
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 相对于父变换的旋转设置变换的旋转。如果转换没有父元素,则与transform.rotation相同
|
||||||
|
* @param degrees
|
||||||
|
*/
|
||||||
|
public setLocalRotationDegrees(degrees: number): Transform {
|
||||||
|
return this.setLocalRotation(MathHelper.toRadians(degrees));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置变换在世界空间中的缩放
|
||||||
|
* @param scale
|
||||||
|
*/
|
||||||
|
public setScale(scale: Vector2): Transform {
|
||||||
|
this._scale = scale;
|
||||||
|
if (this.parent){
|
||||||
|
this.localScale = Vector2.divide(scale, this.parent._scale);
|
||||||
|
}else{
|
||||||
|
this.localScale = scale;
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置转换相对于父对象的比例。如果转换没有父元素,则与transform.scale相同
|
||||||
|
* @param scale
|
||||||
|
*/
|
||||||
|
public setLocalScale(scale: Vector2): Transform {
|
||||||
|
this._localScale = scale;
|
||||||
|
this._localDirty = this._positionDirty = this._localScaleDirty = true;
|
||||||
|
this.setDirty(DirtyType.scaleDirty);
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 对精灵坐标进行四舍五入
|
||||||
|
*/
|
||||||
|
public roundPosition() {
|
||||||
|
this.position = this._position.round();
|
||||||
|
}
|
||||||
|
|
||||||
|
public updateTransform(){
|
||||||
|
if (this.hierarchyDirty != DirtyType.clean){
|
||||||
|
if (this.parent)
|
||||||
|
this.parent.updateTransform();
|
||||||
|
|
||||||
|
if (this._localDirty){
|
||||||
|
if (this._localPositionDirty){
|
||||||
|
this._translationMatrix = Matrix2D.create().translate(this._localPosition.x, this._localPosition.y);
|
||||||
|
this._localPositionDirty = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this._localRotationDirty){
|
||||||
|
this._rotationMatrix = Matrix2D.create().rotate(this._localRotation);
|
||||||
|
this._localRotationDirty = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this._localScaleDirty){
|
||||||
|
this._scaleMatrix = Matrix2D.create().scale(this._localScale.x, this._localScale.y);
|
||||||
|
this._localScaleDirty = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
this._localTransform = this._scaleMatrix.multiply(this._rotationMatrix);
|
||||||
|
this._localTransform = this._localTransform.multiply(this._translationMatrix);
|
||||||
|
|
||||||
|
if (!this.parent){
|
||||||
|
this._worldTransform = this._localTransform;
|
||||||
|
this._rotation = this._localRotation;
|
||||||
|
this._scale = this._localScale;
|
||||||
|
this._worldInverseDirty = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
this._localDirty = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.parent){
|
||||||
|
this._worldTransform = this._localTransform.multiply(this.parent._worldTransform);
|
||||||
|
|
||||||
|
this._rotation = this._localRotation + this.parent._rotation;
|
||||||
|
this._scale = Vector2.multiply(this.parent._scale, this._localScale);
|
||||||
|
this._worldInverseDirty = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
this._worldToLocalDirty = true;
|
||||||
|
this._positionDirty = true;
|
||||||
|
this.hierarchyDirty = DirtyType.clean;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public setDirty(dirtyFlagType: DirtyType){
|
||||||
|
if ((this.hierarchyDirty & dirtyFlagType) == 0){
|
||||||
|
this.hierarchyDirty |= dirtyFlagType;
|
||||||
|
|
||||||
|
switch (dirtyFlagType) {
|
||||||
|
case es.DirtyType.positionDirty:
|
||||||
|
this.entity.onTransformChanged(transform.Component.position);
|
||||||
|
break;
|
||||||
|
case es.DirtyType.rotationDirty:
|
||||||
|
this.entity.onTransformChanged(transform.Component.rotation);
|
||||||
|
break;
|
||||||
|
case es.DirtyType.scaleDirty:
|
||||||
|
this.entity.onTransformChanged(transform.Component.scale);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this._children)
|
||||||
|
this._children = [];
|
||||||
|
|
||||||
|
// 告诉子项发生了变换
|
||||||
|
for (let i = 0; i < this._children.length; i ++)
|
||||||
|
this._children[i].setDirty(dirtyFlagType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从另一个transform属性进行拷贝
|
||||||
|
* @param transform
|
||||||
|
*/
|
||||||
|
public copyFrom(transform: Transform) {
|
||||||
|
this._position = transform.position;
|
||||||
|
this._localPosition = transform._localPosition;
|
||||||
|
this._rotation = transform._rotation;
|
||||||
|
this._localRotation = transform._localRotation;
|
||||||
|
this._scale = transform._scale;
|
||||||
|
this._localScale = transform._localScale;
|
||||||
|
|
||||||
|
this.setDirty(DirtyType.positionDirty);
|
||||||
|
this.setDirty(DirtyType.rotationDirty);
|
||||||
|
this.setDirty(DirtyType.scaleDirty);
|
||||||
|
}
|
||||||
|
|
||||||
|
public toString(): string{
|
||||||
|
return `[Transform: parent: ${this.parent}, position: ${this.position}, rotation: ${this.rotation},
|
||||||
|
scale: ${this.scale}, localPosition: ${this._localPosition}, localRotation: ${this._localRotation},
|
||||||
|
localScale: ${this._localScale}]`;
|
||||||
|
}
|
||||||
|
|
||||||
|
public equals(other: Transform){
|
||||||
|
return other.hashCode == this.hashCode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+111
-109
@@ -1,133 +1,135 @@
|
|||||||
/**
|
module es {
|
||||||
* 这个类可以从两方面来考虑。你可以把它看成一个位向量或者一组非负整数。这个名字有点误导人。
|
/**
|
||||||
*
|
* 这个类可以从两方面来考虑。你可以把它看成一个位向量或者一组非负整数。这个名字有点误导人。
|
||||||
* 它是由一个位向量实现的,但同样可以把它看成是一个非负整数的集合;集合中的每个整数由对应索引处的集合位表示。该结构的大小由集合中的最大整数决定。
|
*
|
||||||
*/
|
* 它是由一个位向量实现的,但同样可以把它看成是一个非负整数的集合;集合中的每个整数由对应索引处的集合位表示。该结构的大小由集合中的最大整数决定。
|
||||||
class BitSet{
|
*/
|
||||||
private static LONG_MASK: number = 0x3f;
|
export class BitSet{
|
||||||
private _bits: number[];
|
private static LONG_MASK: number = 0x3f;
|
||||||
|
private _bits: number[];
|
||||||
|
|
||||||
constructor(nbits: number = 64){
|
constructor(nbits: number = 64){
|
||||||
let length = nbits >> 6;
|
let length = nbits >> 6;
|
||||||
if ((nbits & BitSet.LONG_MASK) != 0)
|
if ((nbits & BitSet.LONG_MASK) != 0)
|
||||||
length ++;
|
length ++;
|
||||||
|
|
||||||
this._bits = new Array(length);
|
this._bits = new Array(length);
|
||||||
}
|
}
|
||||||
|
|
||||||
public and(bs: BitSet){
|
public and(bs: BitSet){
|
||||||
let max = Math.min(this._bits.length, bs._bits.length);
|
let max = Math.min(this._bits.length, bs._bits.length);
|
||||||
let i;
|
let i;
|
||||||
for (let i = 0; i < max; ++i)
|
for (let i = 0; i < max; ++i)
|
||||||
this._bits[i] &= bs._bits[i];
|
this._bits[i] &= bs._bits[i];
|
||||||
|
|
||||||
while (i < this._bits.length)
|
while (i < this._bits.length)
|
||||||
this._bits[i ++] = 0;
|
this._bits[i ++] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public andNot(bs: BitSet){
|
public andNot(bs: BitSet){
|
||||||
let i = Math.min(this._bits.length, bs._bits.length);
|
let i = Math.min(this._bits.length, bs._bits.length);
|
||||||
while(--i >= 0)
|
while(--i >= 0)
|
||||||
this._bits[i] &= ~bs._bits[i];
|
this._bits[i] &= ~bs._bits[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
public cardinality(): number{
|
public cardinality(): number{
|
||||||
let card = 0;
|
let card = 0;
|
||||||
for (let i = this._bits.length - 1; i >= 0; i --){
|
for (let i = this._bits.length - 1; i >= 0; i --){
|
||||||
let a = this._bits[i];
|
let a = this._bits[i];
|
||||||
|
|
||||||
if (a == 0)
|
if (a == 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (a == -1){
|
if (a == -1){
|
||||||
card += 64;
|
card += 64;
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
a = ((a >> 1) & 0x5555555555555555) + (a & 0x5555555555555555);
|
||||||
|
a = ((a >> 2) & 0x3333333333333333) + (a & 0x3333333333333333);
|
||||||
|
let b = ((a >> 32) + a);
|
||||||
|
b = ((b >> 4) & 0x0f0f0f0f) + (b & 0x0f0f0f0f);
|
||||||
|
b = ((b >> 8) & 0x00ff00ff) + (b & 0x00ff00ff);
|
||||||
|
card += ((b >> 16) & 0x0000ffff) + (b & 0x0000ffff);
|
||||||
}
|
}
|
||||||
|
|
||||||
a = ((a >> 1) & 0x5555555555555555) + (a & 0x5555555555555555);
|
return card;
|
||||||
a = ((a >> 2) & 0x3333333333333333) + (a & 0x3333333333333333);
|
|
||||||
let b = ((a >> 32) + a);
|
|
||||||
b = ((b >> 4) & 0x0f0f0f0f) + (b & 0x0f0f0f0f);
|
|
||||||
b = ((b >> 8) & 0x00ff00ff) + (b & 0x00ff00ff);
|
|
||||||
card += ((b >> 16) & 0x0000ffff) + (b & 0x0000ffff);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return card;
|
public clear(pos?: number){
|
||||||
}
|
if (pos != undefined){
|
||||||
|
let offset = pos >> 6;
|
||||||
|
this.ensure(offset);
|
||||||
|
this._bits[offset] &= ~(1 << pos);
|
||||||
|
}else{
|
||||||
|
for (let i = 0; i < this._bits.length; i ++)
|
||||||
|
this._bits[i] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public clear(pos?: number){
|
private ensure(lastElt: number){
|
||||||
if (pos != undefined){
|
if (lastElt >= this._bits.length){
|
||||||
|
let nd = new Number[lastElt + 1];
|
||||||
|
nd = this._bits.copyWithin(0, 0, this._bits.length);
|
||||||
|
this._bits = nd;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public get(pos: number): boolean{
|
||||||
let offset = pos >> 6;
|
let offset = pos >> 6;
|
||||||
this.ensure(offset);
|
if (offset >= this._bits.length)
|
||||||
this._bits[offset] &= ~(1 << pos);
|
|
||||||
}else{
|
|
||||||
for (let i = 0; i < this._bits.length; i ++)
|
|
||||||
this._bits[i] = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private ensure(lastElt: number){
|
|
||||||
if (lastElt >= this._bits.length){
|
|
||||||
let nd = new Number[lastElt + 1];
|
|
||||||
nd = this._bits.copyWithin(0, 0, this._bits.length);
|
|
||||||
this._bits = nd;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public get(pos: number): boolean{
|
|
||||||
let offset = pos >> 6;
|
|
||||||
if (offset >= this._bits.length)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return (this._bits[offset] & (1 << pos)) != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public intersects(set: BitSet){
|
|
||||||
let i = Math.min(this._bits.length, set._bits.length);
|
|
||||||
while (--i >= 0){
|
|
||||||
if ((this._bits[i] & set._bits[i]) != 0)
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public isEmpty(): boolean{
|
|
||||||
for (let i = this._bits.length - 1; i >= 0; i --){
|
|
||||||
if (this._bits[i])
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
return (this._bits[offset] & (1 << pos)) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
public intersects(set: BitSet){
|
||||||
}
|
let i = Math.min(this._bits.length, set._bits.length);
|
||||||
|
while (--i >= 0){
|
||||||
|
if ((this._bits[i] & set._bits[i]) != 0)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
public nextSetBit(from: number){
|
return false;
|
||||||
let offset = from >> 6;
|
|
||||||
let mask = 1 << from;
|
|
||||||
while (offset < this._bits.length){
|
|
||||||
let h = this._bits[offset];
|
|
||||||
do {
|
|
||||||
if ((h & mask) != 0)
|
|
||||||
return from;
|
|
||||||
|
|
||||||
mask <<= 1;
|
|
||||||
from ++;
|
|
||||||
} while (mask != 0);
|
|
||||||
|
|
||||||
mask = 1;
|
|
||||||
offset ++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return -1;
|
public isEmpty(): boolean{
|
||||||
}
|
for (let i = this._bits.length - 1; i >= 0; i --){
|
||||||
|
if (this._bits[i])
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
public set(pos: number, value: boolean = true){
|
return true;
|
||||||
if (value){
|
}
|
||||||
let offset = pos >> 6;
|
|
||||||
this.ensure(offset);
|
public nextSetBit(from: number){
|
||||||
this._bits[offset] |= 1 << pos;
|
let offset = from >> 6;
|
||||||
}else{
|
let mask = 1 << from;
|
||||||
this.clear(pos);
|
while (offset < this._bits.length){
|
||||||
|
let h = this._bits[offset];
|
||||||
|
do {
|
||||||
|
if ((h & mask) != 0)
|
||||||
|
return from;
|
||||||
|
|
||||||
|
mask <<= 1;
|
||||||
|
from ++;
|
||||||
|
} while (mask != 0);
|
||||||
|
|
||||||
|
mask = 1;
|
||||||
|
offset ++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public set(pos: number, value: boolean = true){
|
||||||
|
if (value){
|
||||||
|
let offset = pos >> 6;
|
||||||
|
this.ensure(offset);
|
||||||
|
this._bits[offset] |= 1 << pos;
|
||||||
|
}else{
|
||||||
|
this.clear(pos);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,224 +1,271 @@
|
|||||||
class ComponentList {
|
///<reference path="../Components/IUpdatableComparer.ts" />
|
||||||
private _entity: Entity;
|
module es {
|
||||||
/** 添加到实体的组件列表 */
|
export class ComponentList {
|
||||||
private _components: Component[] = [];
|
/**
|
||||||
/** 添加到此框架的组件列表。用来对组件进行分组,这样我们就可以同时进行加工 */
|
* 组件列表的全局updateOrder排序
|
||||||
private _componentsToAdd: Component[] = [];
|
*/
|
||||||
/** 标记要删除此框架的组件列表。用来对组件进行分组,这样我们就可以同时进行加工 */
|
public static compareUpdatableOrder: IUpdatableComparer = new IUpdatableComparer();
|
||||||
private _componentsToRemove: Component[] = [];
|
public _entity: Entity;
|
||||||
private _tempBufferList: Component[] = [];
|
|
||||||
|
|
||||||
constructor(entity: Entity) {
|
/**
|
||||||
this._entity = entity;
|
* 添加到实体的组件列表
|
||||||
}
|
*/
|
||||||
|
public _components: Component[] = [];
|
||||||
|
/**
|
||||||
|
* 添加到此框架的组件列表。用来对组件进行分组,这样我们就可以同时进行加工
|
||||||
|
*/
|
||||||
|
public _componentsToAdd: Component[] = [];
|
||||||
|
/**
|
||||||
|
* 标记要删除此框架的组件列表。用来对组件进行分组,这样我们就可以同时进行加工
|
||||||
|
*/
|
||||||
|
public _componentsToRemove: Component[] = [];
|
||||||
|
public _tempBufferList: Component[] = [];
|
||||||
|
/**
|
||||||
|
* 用于确定是否需要对该框架中的组件进行排序的标志
|
||||||
|
*/
|
||||||
|
public _isComponentListUnsorted: boolean;
|
||||||
|
|
||||||
public get count() {
|
constructor(entity: Entity) {
|
||||||
return this._components.length;
|
this._entity = entity;
|
||||||
}
|
|
||||||
|
|
||||||
public get buffer() {
|
|
||||||
return this._components;
|
|
||||||
}
|
|
||||||
|
|
||||||
public add(component: Component) {
|
|
||||||
this._componentsToAdd.push(component);
|
|
||||||
}
|
|
||||||
|
|
||||||
public remove(component: Component) {
|
|
||||||
if (this._componentsToRemove.contains(component))
|
|
||||||
console.warn(`You are trying to remove a Component (${component}) that you already removed`)
|
|
||||||
|
|
||||||
// 这可能不是一个活动的组件,所以我们必须注意它是否还没有被处理,它可能正在同一帧中被删除
|
|
||||||
if (this._componentsToAdd.contains(component)) {
|
|
||||||
this._componentsToAdd.remove(component);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this._componentsToRemove.push(component);
|
public get count() {
|
||||||
}
|
return this._components.length;
|
||||||
|
|
||||||
/**
|
|
||||||
* 立即从组件列表中删除所有组件
|
|
||||||
*/
|
|
||||||
public removeAllComponents() {
|
|
||||||
for (let i = 0; i < this._components.length; i++) {
|
|
||||||
this.handleRemove(this._components[i]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this._components.length = 0;
|
public get buffer() {
|
||||||
this._componentsToAdd.length = 0;
|
return this._components;
|
||||||
this._componentsToRemove.length = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public deregisterAllComponents() {
|
|
||||||
for (let i = 0; i < this._components.length; i++) {
|
|
||||||
let component = this._components[i];
|
|
||||||
|
|
||||||
// 处理渲染层列表
|
|
||||||
if (component instanceof RenderableComponent)
|
|
||||||
this._entity.scene.renderableComponents.remove(component);
|
|
||||||
|
|
||||||
this._entity.componentBits.set(ComponentTypeManager.getIndexFor(component), false);
|
|
||||||
this._entity.scene.entityProcessors.onComponentRemoved(this._entity);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public registerAllComponents() {
|
public markEntityListUnsorted(){
|
||||||
for (let i = 0; i < this._components.length; i++) {
|
this._isComponentListUnsorted = true;
|
||||||
let component = this._components[i];
|
|
||||||
|
|
||||||
if (component instanceof RenderableComponent)
|
|
||||||
this._entity.scene.renderableComponents.add(component);
|
|
||||||
|
|
||||||
this._entity.componentBits.set(ComponentTypeManager.getIndexFor(component));
|
|
||||||
this._entity.scene.entityProcessors.onComponentAdded(this._entity);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
public add(component: Component) {
|
||||||
* 处理任何需要删除或添加的组件
|
this._componentsToAdd.push(component);
|
||||||
*/
|
}
|
||||||
public updateLists() {
|
|
||||||
if (this._componentsToRemove.length > 0) {
|
public remove(component: Component) {
|
||||||
for (let i = 0; i < this._componentsToRemove.length; i++) {
|
if (this._componentsToRemove.contains(component))
|
||||||
this.handleRemove(this._componentsToRemove[i]);
|
console.warn(`You are trying to remove a Component (${component}) that you already removed`);
|
||||||
this._components.remove(this._componentsToRemove[i]);
|
|
||||||
|
// 这可能不是一个活动的组件,所以我们必须注意它是否还没有被处理,它可能正在同一帧中被删除
|
||||||
|
if (this._componentsToAdd.contains(component)) {
|
||||||
|
this._componentsToAdd.remove(component);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this._componentsToRemove.push(component);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 立即从组件列表中删除所有组件
|
||||||
|
*/
|
||||||
|
public removeAllComponents() {
|
||||||
|
for (let i = 0; i < this._components.length; i++) {
|
||||||
|
this.handleRemove(this._components[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
this._components.length = 0;
|
||||||
|
this._componentsToAdd.length = 0;
|
||||||
this._componentsToRemove.length = 0;
|
this._componentsToRemove.length = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this._componentsToAdd.length > 0) {
|
public deregisterAllComponents() {
|
||||||
for (let i = 0, count = this._componentsToAdd.length; i < count; i++) {
|
for (let i = 0; i < this._components.length; i++) {
|
||||||
let component = this._componentsToAdd[i];
|
let component = this._components[i];
|
||||||
if (component instanceof RenderableComponent)
|
|
||||||
|
// 处理渲染层列表
|
||||||
|
if (component instanceof RenderableComponent){
|
||||||
|
this._entity.scene.removeChild(component.displayObject);
|
||||||
|
this._entity.scene.renderableComponents.remove(component);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
this._entity.componentBits.set(ComponentTypeManager.getIndexFor(component), false);
|
||||||
|
this._entity.scene.entityProcessors.onComponentRemoved(this._entity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public registerAllComponents() {
|
||||||
|
for (let i = 0; i < this._components.length; i++) {
|
||||||
|
let component = this._components[i];
|
||||||
|
|
||||||
|
if (component instanceof RenderableComponent){
|
||||||
|
this._entity.scene.addChild(component.displayObject);
|
||||||
this._entity.scene.renderableComponents.add(component);
|
this._entity.scene.renderableComponents.add(component);
|
||||||
|
}
|
||||||
|
|
||||||
this._entity.componentBits.set(ComponentTypeManager.getIndexFor(component));
|
this._entity.componentBits.set(ComponentTypeManager.getIndexFor(component));
|
||||||
this._entity.scene.entityProcessors.onComponentAdded(this._entity);
|
this._entity.scene.entityProcessors.onComponentAdded(this._entity);
|
||||||
|
|
||||||
this._components.push(component);
|
|
||||||
this._tempBufferList.push(component);
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 在调用onAddedToEntity之前清除,以防添加更多组件
|
/**
|
||||||
this._componentsToAdd.length = 0;
|
* 处理任何需要删除或添加的组件
|
||||||
|
*/
|
||||||
// 现在所有的组件都添加到了场景中,我们再次循环并调用onAddedToEntity/onEnabled
|
public updateLists() {
|
||||||
for (let i = 0; i < this._tempBufferList.length; i++) {
|
if (this._componentsToRemove.length > 0) {
|
||||||
let component = this._tempBufferList[i];
|
for (let i = 0; i < this._componentsToRemove.length; i++) {
|
||||||
component.onAddedToEntity();
|
this.handleRemove(this._componentsToRemove[i]);
|
||||||
|
this._components.remove(this._componentsToRemove[i]);
|
||||||
// enabled检查实体和组件
|
|
||||||
if (component.enabled) {
|
|
||||||
component.onEnabled();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this._componentsToRemove.length = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
this._tempBufferList.length = 0;
|
if (this._componentsToAdd.length > 0) {
|
||||||
}
|
for (let i = 0, count = this._componentsToAdd.length; i < count; i++) {
|
||||||
}
|
let component = this._componentsToAdd[i];
|
||||||
|
if (component instanceof RenderableComponent){
|
||||||
|
this._entity.scene.addChild(component.displayObject);
|
||||||
|
this._entity.scene.renderableComponents.add(component);
|
||||||
|
}
|
||||||
|
|
||||||
public onEntityTransformChanged(comp: TransformComponent) {
|
|
||||||
for (let i = 0; i < this._components.length; i++) {
|
this._entity.componentBits.set(ComponentTypeManager.getIndexFor(component));
|
||||||
if (this._components[i].enabled)
|
this._entity.scene.entityProcessors.onComponentAdded(this._entity);
|
||||||
this._components[i].onEntityTransformChanged(comp);
|
|
||||||
|
this._components.push(component);
|
||||||
|
this._tempBufferList.push(component);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 在调用onAddedToEntity之前清除,以防添加更多组件
|
||||||
|
this._componentsToAdd.length = 0;
|
||||||
|
this._isComponentListUnsorted = true;
|
||||||
|
|
||||||
|
// 现在所有的组件都添加到了场景中,我们再次循环并调用onAddedToEntity/onEnabled
|
||||||
|
for (let i = 0; i < this._tempBufferList.length; i++) {
|
||||||
|
let component = this._tempBufferList[i];
|
||||||
|
component.onAddedToEntity();
|
||||||
|
|
||||||
|
// enabled检查实体和组件
|
||||||
|
if (component.enabled) {
|
||||||
|
component.onEnabled();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this._tempBufferList.length = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this._isComponentListUnsorted){
|
||||||
|
this._components.sort(ComponentList.compareUpdatableOrder.compare);
|
||||||
|
this._isComponentListUnsorted = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (let i = 0; i < this._componentsToAdd.length; i++) {
|
public handleRemove(component: Component) {
|
||||||
if (this._componentsToAdd[i].enabled)
|
// 处理渲染层列表
|
||||||
this._componentsToAdd[i].onEntityTransformChanged(comp);
|
if (component instanceof RenderableComponent){
|
||||||
}
|
this._entity.scene.removeChild(component.displayObject);
|
||||||
}
|
this._entity.scene.renderableComponents.remove(component);
|
||||||
|
}
|
||||||
|
|
||||||
private handleRemove(component: Component) {
|
|
||||||
if (component instanceof RenderableComponent)
|
|
||||||
this._entity.scene.renderableComponents.remove(component);
|
|
||||||
|
|
||||||
this._entity.componentBits.set(ComponentTypeManager.getIndexFor(component), false);
|
this._entity.componentBits.set(ComponentTypeManager.getIndexFor(component), false);
|
||||||
this._entity.scene.entityProcessors.onComponentRemoved(this._entity);
|
this._entity.scene.entityProcessors.onComponentRemoved(this._entity);
|
||||||
|
|
||||||
component.onRemovedFromEntity();
|
component.onRemovedFromEntity();
|
||||||
component.entity = null;
|
component.entity = null;
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取类型T的第一个组件并返回它
|
|
||||||
* 可以选择跳过检查未初始化的组件(尚未调用onAddedToEntity方法的组件)
|
|
||||||
* 如果没有找到组件,则返回null。
|
|
||||||
* @param type
|
|
||||||
* @param onlyReturnInitializedComponents
|
|
||||||
*/
|
|
||||||
public getComponent<T extends Component>(type, onlyReturnInitializedComponents: boolean): T {
|
|
||||||
for (let i = 0; i < this._components.length; i++) {
|
|
||||||
let component = this._components[i];
|
|
||||||
if (component instanceof type)
|
|
||||||
return component as T;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 我们可以选择检查挂起的组件,以防addComponent和getComponent在同一个框架中被调用
|
|
||||||
if (!onlyReturnInitializedComponents) {
|
/**
|
||||||
for (let i = 0; i < this._componentsToAdd.length; i++) {
|
* 获取类型T的第一个组件并返回它
|
||||||
let component = this._componentsToAdd[i];
|
* 可以选择跳过检查未初始化的组件(尚未调用onAddedToEntity方法的组件)
|
||||||
|
* 如果没有找到组件,则返回null。
|
||||||
|
* @param type
|
||||||
|
* @param onlyReturnInitializedComponents
|
||||||
|
*/
|
||||||
|
public getComponent<T extends Component>(type, onlyReturnInitializedComponents: boolean): T {
|
||||||
|
for (let i = 0; i < this._components.length; i++) {
|
||||||
|
let component = this._components[i];
|
||||||
if (component instanceof type)
|
if (component instanceof type)
|
||||||
return component as T;
|
return component as T;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 我们可以选择检查挂起的组件,以防addComponent和getComponent在同一个框架中被调用
|
||||||
|
if (!onlyReturnInitializedComponents) {
|
||||||
|
for (let i = 0; i < this._componentsToAdd.length; i++) {
|
||||||
|
let component = this._componentsToAdd[i];
|
||||||
|
if (component instanceof type)
|
||||||
|
return component as T;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
/**
|
||||||
}
|
* 获取T类型的所有组件,但不使用列表分配
|
||||||
|
* @param typeName
|
||||||
|
* @param components
|
||||||
|
*/
|
||||||
|
public getComponents(typeName: string | any, components?) {
|
||||||
|
if (!components)
|
||||||
|
components = [];
|
||||||
|
|
||||||
/**
|
for (let i = 0; i < this._components.length; i++) {
|
||||||
* 获取T类型的所有组件,但不使用列表分配
|
let component = this._components[i];
|
||||||
* @param typeName
|
if (typeof (typeName) == "string") {
|
||||||
* @param components
|
if (egret.is(component, typeName)) {
|
||||||
*/
|
components.push(component);
|
||||||
public getComponents(typeName: string | any, components?) {
|
}
|
||||||
if (!components)
|
} else {
|
||||||
components = [];
|
if (component instanceof typeName) {
|
||||||
|
components.push(component);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (let i = 0; i < this._components.length; i++) {
|
for (let i = 0; i < this._componentsToAdd.length; i++) {
|
||||||
let component = this._components[i];
|
let component = this._componentsToAdd[i];
|
||||||
if (typeof (typeName) == "string") {
|
if (typeof (typeName) == "string") {
|
||||||
if (egret.is(component, typeName)) {
|
if (egret.is(component, typeName)) {
|
||||||
components.push(component);
|
components.push(component);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (component instanceof typeName) {
|
if (component instanceof typeName) {
|
||||||
components.push(component);
|
components.push(component);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return components;
|
||||||
|
}
|
||||||
|
|
||||||
|
public update() {
|
||||||
|
this.updateLists();
|
||||||
|
for (let i = 0; i < this._components.length; i++) {
|
||||||
|
let updatableComponent = this._components[i];
|
||||||
|
|
||||||
|
if (updatableComponent.enabled &&
|
||||||
|
(updatableComponent.updateInterval == 1 ||
|
||||||
|
Time.frameCount % updatableComponent.updateInterval == 0))
|
||||||
|
updatableComponent.update();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (let i = 0; i < this._componentsToAdd.length; i++) {
|
public onEntityTransformChanged(comp: transform.Component) {
|
||||||
let component = this._componentsToAdd[i];
|
for (let i = 0; i < this._components.length; i++) {
|
||||||
if (typeof (typeName) == "string") {
|
if (this._components[i].enabled)
|
||||||
if (egret.is(component, typeName)) {
|
this._components[i].onEntityTransformChanged(comp);
|
||||||
components.push(component);
|
}
|
||||||
}
|
|
||||||
} else {
|
for (let i = 0; i < this._componentsToAdd.length; i++) {
|
||||||
if (component instanceof typeName) {
|
if (this._componentsToAdd[i].enabled)
|
||||||
components.push(component);
|
this._componentsToAdd[i].onEntityTransformChanged(comp);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return components;
|
public onEntityEnabled() {
|
||||||
}
|
for (let i = 0; i < this._components.length; i++)
|
||||||
|
this._components[i].onEnabled();
|
||||||
|
}
|
||||||
|
|
||||||
public update() {
|
public onEntityDisabled() {
|
||||||
this.updateLists();
|
for (let i = 0; i < this._components.length; i++)
|
||||||
for (let i = 0; i < this._components.length; i++) {
|
this._components[i].onDisabled();
|
||||||
let updatable = this._components[i];
|
|
||||||
let updateableComponent;
|
|
||||||
if (updatable instanceof Component)
|
|
||||||
updateableComponent = updatable as Component;
|
|
||||||
|
|
||||||
if (updatable.enabled &&
|
|
||||||
updateableComponent.enabled &&
|
|
||||||
(updateableComponent.updateInterval == 1 ||
|
|
||||||
Time.frameCount % updateableComponent.updateInterval == 0))
|
|
||||||
updatable.update();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,18 +1,20 @@
|
|||||||
class ComponentTypeManager{
|
module es {
|
||||||
private static _componentTypesMask: Map<any, number> = new Map<any, number>();
|
export class ComponentTypeManager{
|
||||||
|
private static _componentTypesMask: Map<any, number> = new Map<any, number>();
|
||||||
|
|
||||||
public static add(type){
|
public static add(type){
|
||||||
if (!this._componentTypesMask.has(type))
|
if (!this._componentTypesMask.has(type))
|
||||||
this._componentTypesMask[type] = this._componentTypesMask.size;
|
this._componentTypesMask[type] = this._componentTypesMask.size;
|
||||||
}
|
|
||||||
|
|
||||||
public static getIndexFor(type){
|
|
||||||
let v = -1;
|
|
||||||
if (!this._componentTypesMask.has(type)){
|
|
||||||
this.add(type);
|
|
||||||
v = this._componentTypesMask.get(type);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return v;
|
public static getIndexFor(type){
|
||||||
|
let v = -1;
|
||||||
|
if (!this._componentTypesMask.has(type)){
|
||||||
|
this.add(type);
|
||||||
|
v = this._componentTypesMask.get(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
return v;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+267
-116
@@ -1,134 +1,285 @@
|
|||||||
class EntityList{
|
module es {
|
||||||
public scene: Scene;
|
export class EntityList{
|
||||||
private _entitiesToRemove: Entity[] = [];
|
public scene: Scene;
|
||||||
private _entitiesToAdded: Entity[] = [];
|
/**
|
||||||
private _tempEntityList: Entity[] = [];
|
* 添加到场景中的实体列表
|
||||||
private _entities: Entity[] = [];
|
*/
|
||||||
private _entityDict: Map<number, Entity[]> = new Map<number, Entity[]>();
|
public _entities: Entity[] = [];
|
||||||
private _unsortedTags: number[] = [];
|
/**
|
||||||
|
* 添加到此框架的实体列表。用于对实体进行分组,以便我们可以同时处理它们
|
||||||
|
*/
|
||||||
|
public _entitiesToAdded: Entity[] = [];
|
||||||
|
/**
|
||||||
|
* 标记要删除此框架的实体列表。用于对实体进行分组,以便我们可以同时处理它们
|
||||||
|
*/
|
||||||
|
public _entitiesToRemove: Entity[] = [];
|
||||||
|
/**
|
||||||
|
* 用于确定是否需要在此框架中对实体进行排序的标志
|
||||||
|
*/
|
||||||
|
public _isEntityListUnsorted: boolean;
|
||||||
|
/**
|
||||||
|
* 通过标签跟踪实体,便于检索
|
||||||
|
*/
|
||||||
|
public _entityDict: Map<number, Entity[]> = new Map<number, Entity[]>();
|
||||||
|
public _unsortedTags: number[] = [];
|
||||||
|
/**
|
||||||
|
* 在updateLists中用于双缓冲区,以便可以在其他地方修改原始列表
|
||||||
|
*/
|
||||||
|
public _tempEntityList: Entity[] = [];
|
||||||
|
|
||||||
constructor(scene: Scene){
|
constructor(scene: Scene){
|
||||||
this.scene = scene;
|
this.scene = scene;
|
||||||
}
|
|
||||||
|
|
||||||
public get count(){
|
|
||||||
return this._entities.length;
|
|
||||||
}
|
|
||||||
|
|
||||||
public get buffer(){
|
|
||||||
return this._entities;
|
|
||||||
}
|
|
||||||
|
|
||||||
public add(entity: Entity){
|
|
||||||
if (this._entitiesToAdded.indexOf(entity) == -1)
|
|
||||||
this._entitiesToAdded.push(entity);
|
|
||||||
}
|
|
||||||
|
|
||||||
public remove(entity: Entity){
|
|
||||||
if (this._entitiesToAdded.contains(entity)){
|
|
||||||
this._entitiesToAdded.remove(entity);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this._entitiesToRemove.contains(entity))
|
public get count(){
|
||||||
this._entitiesToRemove.push(entity);
|
return this._entities.length;
|
||||||
}
|
|
||||||
|
|
||||||
public findEntity(name: string){
|
|
||||||
for (let i = 0; i < this._entities.length; i ++){
|
|
||||||
if (this._entities[i].name == name)
|
|
||||||
return this._entities[i];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return this._entitiesToAdded.firstOrDefault(entity => entity.name == name);
|
public get buffer(){
|
||||||
}
|
return this._entities;
|
||||||
|
|
||||||
public getTagList(tag: number){
|
|
||||||
let list = this._entityDict.get(tag);
|
|
||||||
if (!list){
|
|
||||||
list = [];
|
|
||||||
this._entityDict.set(tag, list);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return this._entityDict.get(tag);
|
public markEntityListUnsorted(){
|
||||||
}
|
this._isEntityListUnsorted = true;
|
||||||
|
|
||||||
public addToTagList(entity: Entity){
|
|
||||||
let list = this.getTagList(entity.tag);
|
|
||||||
if (!list.contains(entity)){
|
|
||||||
list.push(entity);
|
|
||||||
this._unsortedTags.push(entity.tag);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public removeFromTagList(entity: Entity){
|
|
||||||
let list = this._entityDict.get(entity.tag);
|
|
||||||
if (list){
|
|
||||||
list.remove(entity);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public update(){
|
|
||||||
for (let i = 0; i < this._entities.length; i++){
|
|
||||||
let entity = this._entities[i];
|
|
||||||
if (entity.enabled)
|
|
||||||
entity.update();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public removeAllEntities(){
|
|
||||||
this._entitiesToAdded.length = 0;
|
|
||||||
|
|
||||||
this.updateLists();
|
|
||||||
|
|
||||||
for (let i = 0; i < this._entities.length; i ++){
|
|
||||||
this._entities[i]._isDestoryed = true;
|
|
||||||
this._entities[i].onRemovedFromScene();
|
|
||||||
this._entities[i].scene = null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this._entities.length = 0;
|
public markTagUnsorted(tag: number){
|
||||||
this._entityDict.clear();
|
this._unsortedTags.push(tag);
|
||||||
}
|
|
||||||
|
|
||||||
public updateLists(){
|
|
||||||
if (this._entitiesToRemove.length > 0){
|
|
||||||
let temp = this._entitiesToRemove;
|
|
||||||
this._entitiesToRemove = this._tempEntityList;
|
|
||||||
this._tempEntityList = temp;
|
|
||||||
this._tempEntityList.forEach(entity => {
|
|
||||||
this._entities.remove(entity);
|
|
||||||
entity.scene = null;
|
|
||||||
|
|
||||||
this.scene.entityProcessors.onEntityRemoved(entity);
|
|
||||||
});
|
|
||||||
|
|
||||||
this._tempEntityList.length = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this._entitiesToAdded.length > 0){
|
/**
|
||||||
let temp = this._entitiesToAdded;
|
* 将实体添加到列表中。所有生命周期方法将在下一帧中被调用。
|
||||||
this._entitiesToAdded = this._tempEntityList;
|
* @param entity
|
||||||
this._tempEntityList = temp;
|
*/
|
||||||
this._tempEntityList.forEach(entity => {
|
public add(entity: Entity){
|
||||||
if (!this._entities.contains(entity)){
|
if (this._entitiesToAdded.indexOf(entity) == -1)
|
||||||
this._entities.push(entity);
|
this._entitiesToAdded.push(entity);
|
||||||
entity.scene = this.scene;
|
|
||||||
|
|
||||||
this.scene.entityProcessors.onEntityAdded(entity)
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
this._tempEntityList.forEach(entity => entity.onAddedToScene());
|
|
||||||
this._tempEntityList.length = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this._unsortedTags.length > 0){
|
/**
|
||||||
this._unsortedTags.forEach(tag => {
|
* 从列表中删除一个实体。所有生命周期方法将在下一帧中被调用。
|
||||||
this._entityDict.get(tag).sort();
|
* @param entity
|
||||||
});
|
*/
|
||||||
|
public remove(entity: Entity){
|
||||||
|
if (!this._entitiesToRemove.contains(entity)){
|
||||||
|
console.warn(`You are trying to remove an entity (${entity.name}) that you already removed`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 防止在同一帧中添加或删除实体
|
||||||
|
if (this._entitiesToAdded.contains(entity)){
|
||||||
|
this._entitiesToAdded.remove(entity);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this._entitiesToRemove.contains(entity))
|
||||||
|
this._entitiesToRemove.push(entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从实体列表中删除所有实体
|
||||||
|
*/
|
||||||
|
public removeAllEntities(){
|
||||||
this._unsortedTags.length = 0;
|
this._unsortedTags.length = 0;
|
||||||
|
this._entitiesToAdded.length = 0;
|
||||||
|
this._isEntityListUnsorted = false;
|
||||||
|
|
||||||
|
// 为什么我们要在这里更新列表?主要用于处理场景切换前分离的实体。
|
||||||
|
// 它们仍然在_entitiesToRemove列表中,该列表将由更新列表处理。
|
||||||
|
this.updateLists();
|
||||||
|
|
||||||
|
for (let i = 0; i < this._entities.length; i ++){
|
||||||
|
this._entities[i]._isDestroyed = true;
|
||||||
|
this._entities[i].onRemovedFromScene();
|
||||||
|
this._entities[i].scene = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
this._entities.length = 0;
|
||||||
|
this._entityDict.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查该实体当前是否由此EntityList管理
|
||||||
|
* @param entity
|
||||||
|
*/
|
||||||
|
public contains(entity: Entity): boolean {
|
||||||
|
return this._entities.contains(entity) || this._entitiesToAdded.contains(entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
public getTagList(tag: number){
|
||||||
|
let list = this._entityDict.get(tag);
|
||||||
|
if (!list){
|
||||||
|
list = [];
|
||||||
|
this._entityDict.set(tag, list);
|
||||||
|
}
|
||||||
|
|
||||||
|
return this._entityDict.get(tag);
|
||||||
|
}
|
||||||
|
|
||||||
|
public addToTagList(entity: Entity){
|
||||||
|
let list = this.getTagList(entity.tag);
|
||||||
|
if (!list.contains(entity)){
|
||||||
|
list.push(entity);
|
||||||
|
this._unsortedTags.push(entity.tag);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public removeFromTagList(entity: Entity){
|
||||||
|
let list = this._entityDict.get(entity.tag);
|
||||||
|
if (list){
|
||||||
|
list.remove(entity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public update(){
|
||||||
|
for (let i = 0; i < this._entities.length; i++){
|
||||||
|
let entity = this._entities[i];
|
||||||
|
if (entity.enabled && (entity.updateInterval == 1 || Time.frameCount % entity.updateInterval == 0))
|
||||||
|
entity.update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public updateLists(){
|
||||||
|
if (this._entitiesToRemove.length > 0){
|
||||||
|
let temp = this._entitiesToRemove;
|
||||||
|
this._entitiesToRemove = this._tempEntityList;
|
||||||
|
this._tempEntityList = temp;
|
||||||
|
this._tempEntityList.forEach(entity => {
|
||||||
|
this.removeFromTagList(entity);
|
||||||
|
|
||||||
|
this._entities.remove(entity);
|
||||||
|
entity.onRemovedFromScene();
|
||||||
|
entity.scene = null;
|
||||||
|
|
||||||
|
this.scene.entityProcessors.onEntityRemoved(entity);
|
||||||
|
});
|
||||||
|
|
||||||
|
this._tempEntityList.length = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this._entitiesToAdded.length > 0){
|
||||||
|
let temp = this._entitiesToAdded;
|
||||||
|
this._entitiesToAdded = this._tempEntityList;
|
||||||
|
this._tempEntityList = temp;
|
||||||
|
this._tempEntityList.forEach(entity => {
|
||||||
|
if (!this._entities.contains(entity)){
|
||||||
|
this._entities.push(entity);
|
||||||
|
entity.scene = this.scene;
|
||||||
|
|
||||||
|
this.addToTagList(entity);
|
||||||
|
|
||||||
|
this.scene.entityProcessors.onEntityAdded(entity)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 现在所有实体都被添加到场景中,我们再次循环并调用onAddedToScene
|
||||||
|
this._tempEntityList.forEach(entity => entity.onAddedToScene());
|
||||||
|
this._tempEntityList.length = 0;
|
||||||
|
this._isEntityListUnsorted = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this._isEntityListUnsorted){
|
||||||
|
this._entities.sort();
|
||||||
|
this._isEntityListUnsorted = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this._unsortedTags.length > 0){
|
||||||
|
this._unsortedTags.forEach(tag => {
|
||||||
|
this._entityDict.get(tag).sort();
|
||||||
|
});
|
||||||
|
|
||||||
|
this._unsortedTags.length = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 返回找到的第一个实体的名称。如果没有找到,则返回null。
|
||||||
|
* @param name
|
||||||
|
*/
|
||||||
|
public findEntity(name: string){
|
||||||
|
for (let i = 0; i < this._entities.length; i ++){
|
||||||
|
if (this._entities[i].name == name)
|
||||||
|
return this._entities[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
return this._entitiesToAdded.firstOrDefault(entity => entity.name == name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 返回带有标记的所有实体的列表。如果没有实体具有标记,则返回一个空列表。可以通过ListPool.free将返回的列表放回池中。
|
||||||
|
* @param tag
|
||||||
|
*/
|
||||||
|
public entitiesWithTag(tag: number){
|
||||||
|
let list = this.getTagList(tag);
|
||||||
|
|
||||||
|
let returnList = ListPool.obtain<Entity>();
|
||||||
|
for (let i = 0; i < list.length; i ++)
|
||||||
|
returnList.push(list[i]);
|
||||||
|
|
||||||
|
return returnList;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 返回t类型的所有实体的列表。返回的列表可以通过ListPool.free放回池中。
|
||||||
|
* @param type
|
||||||
|
*/
|
||||||
|
public entitiesOfType<T extends Entity>(type): T[]{
|
||||||
|
let list = ListPool.obtain<T>();
|
||||||
|
for (let i = 0; i < this._entities.length; i ++){
|
||||||
|
if (this._entities[i] instanceof type)
|
||||||
|
list.push(this._entities[i] as T);
|
||||||
|
}
|
||||||
|
this._entitiesToAdded.forEach(entity => {
|
||||||
|
if (entity instanceof type)
|
||||||
|
list.push(entity as T);
|
||||||
|
});
|
||||||
|
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 返回在类型为T的场景中找到的第一个组件
|
||||||
|
* @param type
|
||||||
|
*/
|
||||||
|
public findComponentOfType<T extends Component>(type): T {
|
||||||
|
for (let i = 0; i < this._entities.length; i ++){
|
||||||
|
if (this._entities[i].enabled){
|
||||||
|
let comp = this._entities[i].getComponent<T>(type);
|
||||||
|
if (comp)
|
||||||
|
return comp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let i = 0; i < this._entitiesToAdded.length; i ++){
|
||||||
|
let entity = this._entitiesToAdded[i];
|
||||||
|
if (entity.enabled){
|
||||||
|
let comp = entity.getComponent<T>(type);
|
||||||
|
if (comp)
|
||||||
|
return comp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 返回在类型t的场景中找到的所有组件。返回的列表可以通过ListPool.free放回池中。
|
||||||
|
* @param type
|
||||||
|
*/
|
||||||
|
public findComponentsOfType<T extends Component>(type): T[]{
|
||||||
|
let comps = ListPool.obtain<T>();
|
||||||
|
for (let i = 0; i < this._entities.length; i ++){
|
||||||
|
if (this._entities[i].enabled)
|
||||||
|
this._entities[i].getComponents(type, comps);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let i = 0; i < this._entitiesToAdded.length; i ++){
|
||||||
|
let entity = this._entitiesToAdded[i];
|
||||||
|
if (entity.enabled)
|
||||||
|
entity.getComponents(type,comps);
|
||||||
|
}
|
||||||
|
|
||||||
|
return comps;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,69 +1,71 @@
|
|||||||
class EntityProcessorList {
|
module es {
|
||||||
private _processors: EntitySystem[] = [];
|
export class EntityProcessorList {
|
||||||
|
private _processors: EntitySystem[] = [];
|
||||||
|
|
||||||
public add(processor: EntitySystem){
|
public add(processor: EntitySystem){
|
||||||
this._processors.push(processor);
|
this._processors.push(processor);
|
||||||
}
|
|
||||||
|
|
||||||
public remove(processor: EntitySystem){
|
|
||||||
this._processors.remove(processor);
|
|
||||||
}
|
|
||||||
|
|
||||||
public onComponentAdded(entity: Entity){
|
|
||||||
this.notifyEntityChanged(entity);
|
|
||||||
}
|
|
||||||
|
|
||||||
public onComponentRemoved(entity: Entity){
|
|
||||||
this.notifyEntityChanged(entity);
|
|
||||||
}
|
|
||||||
|
|
||||||
public onEntityAdded(entity: Entity){
|
|
||||||
this.notifyEntityChanged(entity);
|
|
||||||
}
|
|
||||||
|
|
||||||
public onEntityRemoved(entity: Entity){
|
|
||||||
this.removeFromProcessors(entity);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected notifyEntityChanged(entity: Entity){
|
|
||||||
for (let i = 0; i < this._processors.length; i ++){
|
|
||||||
this._processors[i].onChanged(entity);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected removeFromProcessors(entity: Entity){
|
|
||||||
for (let i = 0; i < this._processors.length; i ++){
|
|
||||||
this._processors[i].remove(entity);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public begin(){
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public update(){
|
|
||||||
for (let i = 0; i < this._processors.length; i++){
|
|
||||||
this._processors[i].update();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public lateUpdate(){
|
|
||||||
for (let i = 0; i < this._processors.length; i ++){
|
|
||||||
this._processors[i].lateUpdate();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public end(){
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public getProcessor<T extends EntitySystem>(): T{
|
|
||||||
for (let i = 0; i < this._processors.length; i ++){
|
|
||||||
let processor = this._processors[i];
|
|
||||||
if (processor instanceof EntitySystem)
|
|
||||||
return processor as T;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
public remove(processor: EntitySystem){
|
||||||
|
this._processors.remove(processor);
|
||||||
|
}
|
||||||
|
|
||||||
|
public onComponentAdded(entity: Entity){
|
||||||
|
this.notifyEntityChanged(entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
public onComponentRemoved(entity: Entity){
|
||||||
|
this.notifyEntityChanged(entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
public onEntityAdded(entity: Entity){
|
||||||
|
this.notifyEntityChanged(entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
public onEntityRemoved(entity: Entity){
|
||||||
|
this.removeFromProcessors(entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected notifyEntityChanged(entity: Entity){
|
||||||
|
for (let i = 0; i < this._processors.length; i ++){
|
||||||
|
this._processors[i].onChanged(entity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected removeFromProcessors(entity: Entity){
|
||||||
|
for (let i = 0; i < this._processors.length; i ++){
|
||||||
|
this._processors[i].remove(entity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public begin(){
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public update(){
|
||||||
|
for (let i = 0; i < this._processors.length; i++){
|
||||||
|
this._processors[i].update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public lateUpdate(){
|
||||||
|
for (let i = 0; i < this._processors.length; i ++){
|
||||||
|
this._processors[i].lateUpdate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public end(){
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public getProcessor<T extends EntitySystem>(): T{
|
||||||
|
for (let i = 0; i < this._processors.length; i ++){
|
||||||
|
let processor = this._processors[i];
|
||||||
|
if (processor instanceof EntitySystem)
|
||||||
|
return processor as T;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,62 +1,64 @@
|
|||||||
class Matcher{
|
module es {
|
||||||
protected allSet = new BitSet();
|
export class Matcher{
|
||||||
protected exclusionSet = new BitSet();
|
protected allSet = new BitSet();
|
||||||
protected oneSet = new BitSet();
|
protected exclusionSet = new BitSet();
|
||||||
|
protected oneSet = new BitSet();
|
||||||
|
|
||||||
public static empty(){
|
public static empty(){
|
||||||
return new Matcher();
|
return new Matcher();
|
||||||
}
|
|
||||||
|
|
||||||
public getAllSet(){
|
|
||||||
return this.allSet;
|
|
||||||
}
|
|
||||||
|
|
||||||
public getExclusionSet(){
|
|
||||||
return this.exclusionSet;
|
|
||||||
}
|
|
||||||
|
|
||||||
public getOneSet(){
|
|
||||||
return this.oneSet;
|
|
||||||
}
|
|
||||||
|
|
||||||
public IsIntersted(e: Entity){
|
|
||||||
if (!this.allSet.isEmpty()){
|
|
||||||
for (let i = this.allSet.nextSetBit(0); i >= 0; i = this.allSet.nextSetBit(i + 1)){
|
|
||||||
if (!e.componentBits.get(i))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this.exclusionSet.isEmpty() && this.exclusionSet.intersects(e.componentBits))
|
public getAllSet(){
|
||||||
return false;
|
return this.allSet;
|
||||||
|
}
|
||||||
|
|
||||||
if (!this.oneSet.isEmpty() && !this.oneSet.intersects(e.componentBits))
|
public getExclusionSet(){
|
||||||
return false;
|
return this.exclusionSet;
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
public getOneSet(){
|
||||||
}
|
return this.oneSet;
|
||||||
|
}
|
||||||
|
|
||||||
public all(...types: any[]): Matcher{
|
public IsIntersted(e: Entity){
|
||||||
types.forEach(type => {
|
if (!this.allSet.isEmpty()){
|
||||||
this.allSet.set(ComponentTypeManager.getIndexFor(type));
|
for (let i = this.allSet.nextSetBit(0); i >= 0; i = this.allSet.nextSetBit(i + 1)){
|
||||||
});
|
if (!e.componentBits.get(i))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return this;
|
if (!this.exclusionSet.isEmpty() && this.exclusionSet.intersects(e.componentBits))
|
||||||
}
|
return false;
|
||||||
|
|
||||||
public exclude(...types: any[]){
|
if (!this.oneSet.isEmpty() && !this.oneSet.intersects(e.componentBits))
|
||||||
types.forEach(type => {
|
return false;
|
||||||
this.exclusionSet.set(ComponentTypeManager.getIndexFor(type));
|
|
||||||
});
|
|
||||||
|
|
||||||
return this;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public one(...types: any[]){
|
public all(...types: any[]): Matcher{
|
||||||
types.forEach(type => {
|
types.forEach(type => {
|
||||||
this.oneSet.set(ComponentTypeManager.getIndexFor(type));
|
this.allSet.set(ComponentTypeManager.getIndexFor(type));
|
||||||
});
|
});
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public exclude(...types: any[]){
|
||||||
|
types.forEach(type => {
|
||||||
|
this.exclusionSet.set(ComponentTypeManager.getIndexFor(type));
|
||||||
|
});
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public one(...types: any[]){
|
||||||
|
types.forEach(type => {
|
||||||
|
this.oneSet.set(ComponentTypeManager.getIndexFor(type));
|
||||||
|
});
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,22 +1,101 @@
|
|||||||
class RenderableComponentList {
|
///<reference path="../../Graphics/Renderers/IRenderable.ts" />
|
||||||
private _components: IRenderable[] = [];
|
module es {
|
||||||
public get count(){
|
export class RenderableComponentList {
|
||||||
return this._components.length;
|
/**
|
||||||
}
|
* IRenderable列表的全局updatePrder排序
|
||||||
|
*/
|
||||||
|
public static compareUpdatableOrder = new RenderableComparer();
|
||||||
|
/**
|
||||||
|
* 添加到实体的组件列表
|
||||||
|
*/
|
||||||
|
public _components: IRenderable[] = [];
|
||||||
|
/**
|
||||||
|
* 通过渲染层跟踪组件,便于检索
|
||||||
|
*/
|
||||||
|
public _componentsByRenderLayer: Map<number, IRenderable[]> = new Map<number, IRenderable[]>();
|
||||||
|
public _unsortedRenderLayers: number[] = [];
|
||||||
|
public _componentsNeedSort: boolean = true;
|
||||||
|
|
||||||
public get buffer(){
|
public get count() {
|
||||||
return this._components;
|
return this._components.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
public add(component: IRenderable){
|
public get buffer() {
|
||||||
this._components.push(component);
|
return this._components;
|
||||||
}
|
}
|
||||||
|
|
||||||
public remove(component: IRenderable){
|
public add(component: IRenderable) {
|
||||||
this._components.remove(component);
|
this._components.push(component);
|
||||||
}
|
this.addToRenderLayerList(component, component.renderLayer);
|
||||||
|
}
|
||||||
|
|
||||||
public updateList(){
|
public remove(component: IRenderable) {
|
||||||
|
this._components.remove(component);
|
||||||
|
this._componentsByRenderLayer.get(component.renderLayer).remove(component);
|
||||||
|
}
|
||||||
|
|
||||||
|
public updateRenderableRenderLayer(component: IRenderable, oldRenderLayer: number, newRenderLayer: number) {
|
||||||
|
// 需要注意的是,如果渲染层在组件update之前发生了改变
|
||||||
|
if (this._componentsByRenderLayer.has(oldRenderLayer) && this._componentsByRenderLayer.get(oldRenderLayer).contains(component)) {
|
||||||
|
this._componentsByRenderLayer.get(oldRenderLayer).remove(component);
|
||||||
|
this.addToRenderLayerList(component, newRenderLayer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将渲染层排序标志弄脏,让所有组件重新排序
|
||||||
|
* @param renderLayer
|
||||||
|
*/
|
||||||
|
public setRenderLayerNeedsComponentSort(renderLayer: number) {
|
||||||
|
if (!this._unsortedRenderLayers.contains(renderLayer))
|
||||||
|
this._unsortedRenderLayers.push(renderLayer);
|
||||||
|
this._componentsNeedSort = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public setNeedsComponentSort() {
|
||||||
|
this._componentsNeedSort = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public addToRenderLayerList(component: IRenderable, renderLayer: number) {
|
||||||
|
let list = this.componentsWithRenderLayer(renderLayer);
|
||||||
|
if (!list.contains(component)) {
|
||||||
|
console.warn("Component renderLayer list already contains this component");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
list.push(component);
|
||||||
|
if (!this._unsortedRenderLayers.contains(renderLayer))
|
||||||
|
this._unsortedRenderLayers.push(renderLayer);
|
||||||
|
this._componentsNeedSort = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 使用给定的渲染层获取所有组件。组件列表是预先排序的
|
||||||
|
* @param renderLayer
|
||||||
|
*/
|
||||||
|
public componentsWithRenderLayer(renderLayer: number): IRenderable[] {
|
||||||
|
if (!this._componentsByRenderLayer.get(renderLayer)) {
|
||||||
|
this._componentsByRenderLayer.set(renderLayer, []);
|
||||||
|
}
|
||||||
|
return this._componentsByRenderLayer.get(renderLayer);
|
||||||
|
}
|
||||||
|
|
||||||
|
public updateList() {
|
||||||
|
if (this._componentsNeedSort) {
|
||||||
|
this._components.sort(RenderableComponentList.compareUpdatableOrder.compare);
|
||||||
|
this._componentsNeedSort = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this._unsortedRenderLayers.length > 0) {
|
||||||
|
for (let i = 0, count = this._unsortedRenderLayers.length; i < count; i++) {
|
||||||
|
let renderLayerComponents = this._componentsByRenderLayer.get(this._unsortedRenderLayers[i]);
|
||||||
|
if (renderLayerComponents) {
|
||||||
|
renderLayerComponents.sort(RenderableComponentList.compareUpdatableOrder.compare);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this._unsortedRenderLayers.length = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,154 +1,156 @@
|
|||||||
/**
|
module es {
|
||||||
* 纹理帮助类
|
/**
|
||||||
*/
|
* 纹理帮助类
|
||||||
class TextureUtils {
|
*/
|
||||||
public static sharedCanvas: HTMLCanvasElement;
|
export class TextureUtils {
|
||||||
public static sharedContext: CanvasRenderingContext2D;
|
public static sharedCanvas: HTMLCanvasElement;
|
||||||
|
public static sharedContext: CanvasRenderingContext2D;
|
||||||
|
|
||||||
public static convertImageToCanvas(texture: egret.Texture, rect?: egret.Rectangle): HTMLCanvasElement{
|
public static convertImageToCanvas(texture: egret.Texture, rect?: egret.Rectangle): HTMLCanvasElement{
|
||||||
if (!this.sharedCanvas){
|
if (!this.sharedCanvas){
|
||||||
this.sharedCanvas = egret.sys.createCanvas();
|
this.sharedCanvas = egret.sys.createCanvas();
|
||||||
this.sharedContext = this.sharedCanvas.getContext("2d");
|
this.sharedContext = this.sharedCanvas.getContext("2d");
|
||||||
}
|
}
|
||||||
|
|
||||||
let w = texture.$getTextureWidth();
|
let w = texture.$getTextureWidth();
|
||||||
let h = texture.$getTextureHeight();
|
let h = texture.$getTextureHeight();
|
||||||
if (!rect){
|
if (!rect){
|
||||||
rect = egret.$TempRectangle;
|
rect = egret.$TempRectangle;
|
||||||
rect.x = 0;
|
rect.x = 0;
|
||||||
rect.y = 0;
|
rect.y = 0;
|
||||||
rect.width = w;
|
rect.width = w;
|
||||||
rect.height = h;
|
rect.height = h;
|
||||||
}
|
}
|
||||||
|
|
||||||
rect.x = Math.min(rect.x, w - 1);
|
rect.x = Math.min(rect.x, w - 1);
|
||||||
rect.y = Math.min(rect.y, h - 1);
|
rect.y = Math.min(rect.y, h - 1);
|
||||||
rect.width = Math.min(rect.width, w - rect.x);
|
rect.width = Math.min(rect.width, w - rect.x);
|
||||||
rect.height = Math.min(rect.height, h - rect.y);
|
rect.height = Math.min(rect.height, h - rect.y);
|
||||||
|
|
||||||
let iWidth = Math.floor(rect.width);
|
let iWidth = Math.floor(rect.width);
|
||||||
let iHeight = Math.floor(rect.height);
|
let iHeight = Math.floor(rect.height);
|
||||||
let surface = this.sharedCanvas;
|
let surface = this.sharedCanvas;
|
||||||
surface["style"]["width"] = iWidth + "px";
|
surface["style"]["width"] = iWidth + "px";
|
||||||
surface["style"]["height"] = iHeight + "px";
|
surface["style"]["height"] = iHeight + "px";
|
||||||
this.sharedCanvas.width = iWidth;
|
this.sharedCanvas.width = iWidth;
|
||||||
this.sharedCanvas.height = iHeight;
|
this.sharedCanvas.height = iHeight;
|
||||||
|
|
||||||
if (egret.Capabilities.renderMode == "webgl") {
|
if (egret.Capabilities.renderMode == "webgl") {
|
||||||
let renderTexture: egret.RenderTexture;
|
let renderTexture: egret.RenderTexture;
|
||||||
//webgl下非RenderTexture纹理先画到RenderTexture
|
//webgl下非RenderTexture纹理先画到RenderTexture
|
||||||
if (!(<egret.RenderTexture>texture).$renderBuffer) {
|
if (!(<egret.RenderTexture>texture).$renderBuffer) {
|
||||||
if (egret.sys.systemRenderer["renderClear"]) {
|
if (egret.sys.systemRenderer["renderClear"]) {
|
||||||
egret.sys.systemRenderer["renderClear"]();
|
egret.sys.systemRenderer["renderClear"]();
|
||||||
|
}
|
||||||
|
renderTexture = new egret.RenderTexture();
|
||||||
|
renderTexture.drawToTexture(new egret.Bitmap(texture));
|
||||||
}
|
}
|
||||||
renderTexture = new egret.RenderTexture();
|
else {
|
||||||
renderTexture.drawToTexture(new egret.Bitmap(texture));
|
renderTexture = <egret.RenderTexture>texture;
|
||||||
|
}
|
||||||
|
//从RenderTexture中读取像素数据,填入canvas
|
||||||
|
let pixels = renderTexture.$renderBuffer.getPixels(rect.x, rect.y, iWidth, iHeight);
|
||||||
|
let x = 0;
|
||||||
|
let y = 0;
|
||||||
|
for (let i = 0; i < pixels.length; i += 4) {
|
||||||
|
this.sharedContext.fillStyle =
|
||||||
|
'rgba(' + pixels[i]
|
||||||
|
+ ',' + pixels[i + 1]
|
||||||
|
+ ',' + pixels[i + 2]
|
||||||
|
+ ',' + (pixels[i + 3] / 255) + ')';
|
||||||
|
this.sharedContext.fillRect(x, y, 1, 1);
|
||||||
|
x++;
|
||||||
|
if (x == iWidth) {
|
||||||
|
x = 0;
|
||||||
|
y++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(<egret.RenderTexture>texture).$renderBuffer) {
|
||||||
|
renderTexture.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
return surface;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
renderTexture = <egret.RenderTexture>texture;
|
let bitmapData = texture;
|
||||||
|
let offsetX: number = Math.round(bitmapData.$offsetX);
|
||||||
|
let offsetY: number = Math.round(bitmapData.$offsetY);
|
||||||
|
let bitmapWidth: number = bitmapData.$bitmapWidth;
|
||||||
|
let bitmapHeight: number = bitmapData.$bitmapHeight;
|
||||||
|
let $TextureScaleFactor = Core._instance.stage.textureScaleFactor;
|
||||||
|
this.sharedContext.drawImage(bitmapData.$bitmapData.source, bitmapData.$bitmapX + rect.x / $TextureScaleFactor, bitmapData.$bitmapY + rect.y / $TextureScaleFactor,
|
||||||
|
bitmapWidth * rect.width / w, bitmapHeight * rect.height / h, offsetX, offsetY, rect.width, rect.height);
|
||||||
|
return surface;
|
||||||
}
|
}
|
||||||
//从RenderTexture中读取像素数据,填入canvas
|
|
||||||
let pixels = renderTexture.$renderBuffer.getPixels(rect.x, rect.y, iWidth, iHeight);
|
|
||||||
let x = 0;
|
|
||||||
let y = 0;
|
|
||||||
for (let i = 0; i < pixels.length; i += 4) {
|
|
||||||
this.sharedContext.fillStyle =
|
|
||||||
'rgba(' + pixels[i]
|
|
||||||
+ ',' + pixels[i + 1]
|
|
||||||
+ ',' + pixels[i + 2]
|
|
||||||
+ ',' + (pixels[i + 3] / 255) + ')';
|
|
||||||
this.sharedContext.fillRect(x, y, 1, 1);
|
|
||||||
x++;
|
|
||||||
if (x == iWidth) {
|
|
||||||
x = 0;
|
|
||||||
y++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(<egret.RenderTexture>texture).$renderBuffer) {
|
|
||||||
renderTexture.dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
return surface;
|
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
let bitmapData = texture;
|
|
||||||
let offsetX: number = Math.round(bitmapData.$offsetX);
|
|
||||||
let offsetY: number = Math.round(bitmapData.$offsetY);
|
|
||||||
let bitmapWidth: number = bitmapData.$bitmapWidth;
|
|
||||||
let bitmapHeight: number = bitmapData.$bitmapHeight;
|
|
||||||
let $TextureScaleFactor = SceneManager.stage.textureScaleFactor;
|
|
||||||
this.sharedContext.drawImage(bitmapData.$bitmapData.source, bitmapData.$bitmapX + rect.x / $TextureScaleFactor, bitmapData.$bitmapY + rect.y / $TextureScaleFactor,
|
|
||||||
bitmapWidth * rect.width / w, bitmapHeight * rect.height / h, offsetX, offsetY, rect.width, rect.height);
|
|
||||||
return surface;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static toDataURL(type: string, texture: egret.Texture, rect?: egret.Rectangle, encoderOptions?): string {
|
public static toDataURL(type: string, texture: egret.Texture, rect?: egret.Rectangle, encoderOptions?): string {
|
||||||
try {
|
try {
|
||||||
|
let surface = this.convertImageToCanvas(texture, rect);
|
||||||
|
let result = surface.toDataURL(type, encoderOptions);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
egret.$error(1033);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 有些杀毒软件认为 saveToFile 可能是一个病毒文件
|
||||||
|
* @param type
|
||||||
|
* @param texture
|
||||||
|
* @param filePath
|
||||||
|
* @param rect
|
||||||
|
* @param encoderOptions
|
||||||
|
*/
|
||||||
|
public static eliFoTevas(type: string, texture: egret.Texture, filePath: string, rect?: egret.Rectangle, encoderOptions?): void {
|
||||||
let surface = this.convertImageToCanvas(texture, rect);
|
let surface = this.convertImageToCanvas(texture, rect);
|
||||||
let result = surface.toDataURL(type, encoderOptions);
|
let result = (surface as any).toTempFilePathSync({
|
||||||
|
fileType: type.indexOf("png") >= 0 ? "png" : "jpg"
|
||||||
|
});
|
||||||
|
|
||||||
|
wx.getFileSystemManager().saveFile({
|
||||||
|
tempFilePath: result,
|
||||||
|
filePath: `${wx.env.USER_DATA_PATH}/${filePath}`,
|
||||||
|
success: function (res) {
|
||||||
|
//todo
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
catch (e) {
|
|
||||||
egret.$error(1033);
|
public static getPixel32(texture: egret.Texture, x: number, y: number): number[] {
|
||||||
|
egret.$warn(1041, "getPixel32", "getPixels");
|
||||||
|
return texture.getPixels(x, y);
|
||||||
}
|
}
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
public static getPixels(texture: egret.Texture, x: number, y: number, width: number = 1, height: number = 1): number[] {
|
||||||
* 有些杀毒软件认为 saveToFile 可能是一个病毒文件
|
//webgl环境下不需要转换成canvas获取像素信息
|
||||||
* @param type
|
if (egret.Capabilities.renderMode == "webgl") {
|
||||||
* @param texture
|
let renderTexture: egret.RenderTexture;
|
||||||
* @param filePath
|
//webgl下非RenderTexture纹理先画到RenderTexture
|
||||||
* @param rect
|
if (!(<egret.RenderTexture>texture).$renderBuffer) {
|
||||||
* @param encoderOptions
|
renderTexture = new egret.RenderTexture();
|
||||||
*/
|
renderTexture.drawToTexture(new egret.Bitmap(texture));
|
||||||
public static eliFoTevas(type: string, texture: egret.Texture, filePath: string, rect?: egret.Rectangle, encoderOptions?): void {
|
}
|
||||||
let surface = this.convertImageToCanvas(texture, rect);
|
else {
|
||||||
let result = (surface as any).toTempFilePathSync({
|
renderTexture = <egret.RenderTexture>texture;
|
||||||
fileType: type.indexOf("png") >= 0 ? "png" : "jpg"
|
}
|
||||||
});
|
//从RenderTexture中读取像素数据
|
||||||
|
let pixels = renderTexture.$renderBuffer.getPixels(x, y, width, height);
|
||||||
wx.getFileSystemManager().saveFile({
|
return pixels;
|
||||||
tempFilePath: result,
|
|
||||||
filePath: `${wx.env.USER_DATA_PATH}/${filePath}`,
|
|
||||||
success: function (res) {
|
|
||||||
//todo
|
|
||||||
}
|
}
|
||||||
})
|
try {
|
||||||
|
let surface = this.convertImageToCanvas(texture);
|
||||||
return result;
|
let result = this.sharedContext.getImageData(x, y, width, height).data;
|
||||||
}
|
return <number[]><any>result;
|
||||||
|
|
||||||
public static getPixel32(texture: egret.Texture, x: number, y: number): number[] {
|
|
||||||
egret.$warn(1041, "getPixel32", "getPixels");
|
|
||||||
return texture.getPixels(x, y);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static getPixels(texture: egret.Texture, x: number, y: number, width: number = 1, height: number = 1): number[] {
|
|
||||||
//webgl环境下不需要转换成canvas获取像素信息
|
|
||||||
if (egret.Capabilities.renderMode == "webgl") {
|
|
||||||
let renderTexture: egret.RenderTexture;
|
|
||||||
//webgl下非RenderTexture纹理先画到RenderTexture
|
|
||||||
if (!(<egret.RenderTexture>texture).$renderBuffer) {
|
|
||||||
renderTexture = new egret.RenderTexture();
|
|
||||||
renderTexture.drawToTexture(new egret.Bitmap(texture));
|
|
||||||
}
|
}
|
||||||
else {
|
catch (e) {
|
||||||
renderTexture = <egret.RenderTexture>texture;
|
egret.$error(1039);
|
||||||
}
|
}
|
||||||
//从RenderTexture中读取像素数据
|
|
||||||
let pixels = renderTexture.$renderBuffer.getPixels(x, y, width, height);
|
|
||||||
return pixels;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
let surface = this.convertImageToCanvas(texture);
|
|
||||||
let result = this.sharedContext.getImageData(x, y, width, height).data;
|
|
||||||
return <number[]><any>result;
|
|
||||||
}
|
|
||||||
catch (e) {
|
|
||||||
egret.$error(1039);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,38 +1,40 @@
|
|||||||
/** 提供帧定时信息 */
|
module es {
|
||||||
class Time {
|
/** 提供帧定时信息 */
|
||||||
/** deltaTime的未缩放版本。不受时间尺度的影响 */
|
export class Time {
|
||||||
public static unscaledDeltaTime;
|
/** deltaTime的未缩放版本。不受时间尺度的影响 */
|
||||||
/** 前一帧到当前帧的时间增量,按时间刻度进行缩放 */
|
public static unscaledDeltaTime;
|
||||||
public static deltaTime: number = 0;
|
/** 前一帧到当前帧的时间增量,按时间刻度进行缩放 */
|
||||||
/** 时间刻度缩放 */
|
public static deltaTime: number = 0;
|
||||||
public static timeScale = 1;
|
/** 时间刻度缩放 */
|
||||||
/** 已传递的帧总数 */
|
public static timeScale = 1;
|
||||||
public static frameCount = 0;
|
/** 已传递的帧总数 */
|
||||||
|
public static frameCount = 0;
|
||||||
|
|
||||||
private static _lastTime = 0;
|
private static _lastTime = 0;
|
||||||
/** 自场景加载以来的总时间 */
|
/** 自场景加载以来的总时间 */
|
||||||
public static _timeSinceSceneLoad;
|
public static _timeSinceSceneLoad;
|
||||||
|
|
||||||
public static update(currentTime: number){
|
public static update(currentTime: number){
|
||||||
let dt = (currentTime - this._lastTime) / 1000;
|
let dt = (currentTime - this._lastTime) / 1000;
|
||||||
this.deltaTime = dt * this.timeScale;
|
this.deltaTime = dt * this.timeScale;
|
||||||
this.unscaledDeltaTime = dt;
|
this.unscaledDeltaTime = dt;
|
||||||
this._timeSinceSceneLoad += dt;
|
this._timeSinceSceneLoad += dt;
|
||||||
this.frameCount ++;
|
this.frameCount ++;
|
||||||
|
|
||||||
this._lastTime = currentTime;
|
this._lastTime = currentTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static sceneChanged(){
|
public static sceneChanged(){
|
||||||
this._timeSinceSceneLoad = 0;
|
this._timeSinceSceneLoad = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 允许在间隔检查。只应该使用高于delta的间隔值,否则它将始终返回true。
|
* 允许在间隔检查。只应该使用高于delta的间隔值,否则它将始终返回true。
|
||||||
* @param interval
|
* @param interval
|
||||||
*/
|
*/
|
||||||
public static checkEvery(interval: number){
|
public static checkEvery(interval: number){
|
||||||
// 我们减去了delta,因为timeSinceSceneLoad已经包含了这个update ticks delta
|
// 我们减去了delta,因为timeSinceSceneLoad已经包含了这个update ticks delta
|
||||||
return (this._timeSinceSceneLoad / interval) > ((this._timeSinceSceneLoad - this.deltaTime) / interval);
|
return (this._timeSinceSceneLoad / interval) > ((this._timeSinceSceneLoad - this.deltaTime) / interval);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+54
-43
@@ -4,84 +4,100 @@ declare interface Array<T> {
|
|||||||
* @param predicate 表达式
|
* @param predicate 表达式
|
||||||
*/
|
*/
|
||||||
findIndex(predicate: Function): number;
|
findIndex(predicate: Function): number;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 是否存在满足表达式的数组元素
|
* 是否存在满足表达式的数组元素
|
||||||
* @param predicate 表达式
|
* @param predicate 表达式
|
||||||
*/
|
*/
|
||||||
any(predicate: Function): boolean;
|
any(predicate: Function): boolean;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取满足表达式的第一个或默认数组元素
|
* 获取满足表达式的第一个或默认数组元素
|
||||||
* @param predicate 表达式
|
* @param predicate 表达式
|
||||||
*/
|
*/
|
||||||
firstOrDefault(predicate: Function): T;
|
firstOrDefault(predicate: Function): T;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取满足表达式的第一个数组元素
|
* 获取满足表达式的第一个数组元素
|
||||||
* @param predicate 表达式
|
* @param predicate 表达式
|
||||||
*/
|
*/
|
||||||
find(predicate: Function): T;
|
find(predicate: Function): T;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 筛选满足表达式的数组元素
|
* 筛选满足表达式的数组元素
|
||||||
* @param predicate 表达式
|
* @param predicate 表达式
|
||||||
*/
|
*/
|
||||||
where(predicate: Function): Array<T>;
|
where(predicate: Function): Array<T>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取满足表达式的数组元素的计数
|
* 获取满足表达式的数组元素的计数
|
||||||
* @param predicate 表达式
|
* @param predicate 表达式
|
||||||
*/
|
*/
|
||||||
count(predicate: Function): number;
|
count(predicate: Function): number;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取满足表达式的数组元素的数组
|
* 获取满足表达式的数组元素的数组
|
||||||
* @param predicate 表达式
|
* @param predicate 表达式
|
||||||
*/
|
*/
|
||||||
findAll(predicate: Function): Array<T>;
|
findAll(predicate: Function): Array<T>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 是否有获取满足表达式的数组元素
|
* 是否有获取满足表达式的数组元素
|
||||||
* @param value 值
|
* @param value 值
|
||||||
*/
|
*/
|
||||||
contains(value): boolean;
|
contains(value): boolean;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 移除满足表达式的数组元素
|
* 移除满足表达式的数组元素
|
||||||
* @param predicate 表达式
|
* @param predicate 表达式
|
||||||
*/
|
*/
|
||||||
removeAll(predicate: Function): void;
|
removeAll(predicate: Function): void;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 移除数组元素
|
* 移除数组元素
|
||||||
* @param element 数组元素
|
* @param element 数组元素
|
||||||
*/
|
*/
|
||||||
remove(element: T): boolean;
|
remove(element: T): boolean;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 移除特定索引数组元素
|
* 移除特定索引数组元素
|
||||||
* @param index 索引
|
* @param index 索引
|
||||||
*/
|
*/
|
||||||
removeAt(index): void;
|
removeAt(index): void;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 移除范围数组元素
|
* 移除范围数组元素
|
||||||
* @param index 开始索引
|
* @param index 开始索引
|
||||||
* @param count 删除的个数
|
* @param count 删除的个数
|
||||||
*/
|
*/
|
||||||
removeRange(index, count): void;
|
removeRange(index, count): void;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取通过选择器转换的数组
|
* 获取通过选择器转换的数组
|
||||||
* @param selector 选择器
|
* @param selector 选择器
|
||||||
*/
|
*/
|
||||||
select(selector: Function): Array<T>;
|
select(selector: Function): Array<T>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 排序(升序)
|
* 排序(升序)
|
||||||
* @param keySelector key选择器
|
* @param keySelector key选择器
|
||||||
* @param comparer 比较器
|
* @param comparer 比较器
|
||||||
*/
|
*/
|
||||||
orderBy(keySelector: Function, comparer: Function): Array<T>;
|
orderBy(keySelector: Function, comparer: Function): Array<T>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 排序(降序)
|
* 排序(降序)
|
||||||
* @param keySelector key选择器
|
* @param keySelector key选择器
|
||||||
* @param comparer 比较器
|
* @param comparer 比较器
|
||||||
*/
|
*/
|
||||||
orderByDescending(keySelector: Function, comparer: Function): Array<T>;
|
orderByDescending(keySelector: Function, comparer: Function): Array<T>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 分组
|
* 分组
|
||||||
* @param keySelector key选择器
|
* @param keySelector key选择器
|
||||||
*/
|
*/
|
||||||
groupBy(keySelector: Function): Array<T>;
|
groupBy(keySelector: Function): Array<T>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 求和
|
* 求和
|
||||||
* @param selector 选择器
|
* @param selector 选择器
|
||||||
@@ -101,7 +117,7 @@ Array.prototype.findIndex = function (predicate) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return findIndex(this, predicate);
|
return findIndex(this, predicate);
|
||||||
}
|
};
|
||||||
|
|
||||||
Array.prototype.any = function (predicate) {
|
Array.prototype.any = function (predicate) {
|
||||||
function any(array, predicate) {
|
function any(array, predicate) {
|
||||||
@@ -109,7 +125,7 @@ Array.prototype.any = function (predicate) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return any(this, predicate);
|
return any(this, predicate);
|
||||||
}
|
};
|
||||||
|
|
||||||
Array.prototype.firstOrDefault = function (predicate) {
|
Array.prototype.firstOrDefault = function (predicate) {
|
||||||
function firstOrDefault(array, predicate) {
|
function firstOrDefault(array, predicate) {
|
||||||
@@ -118,7 +134,7 @@ Array.prototype.firstOrDefault = function (predicate) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return firstOrDefault(this, predicate);
|
return firstOrDefault(this, predicate);
|
||||||
}
|
};
|
||||||
|
|
||||||
Array.prototype.find = function (predicate) {
|
Array.prototype.find = function (predicate) {
|
||||||
function find(array, predicate) {
|
function find(array, predicate) {
|
||||||
@@ -126,7 +142,7 @@ Array.prototype.find = function (predicate) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return find(this, predicate);
|
return find(this, predicate);
|
||||||
}
|
};
|
||||||
|
|
||||||
Array.prototype.where = function (predicate) {
|
Array.prototype.where = function (predicate) {
|
||||||
function where(array, predicate) {
|
function where(array, predicate) {
|
||||||
@@ -138,8 +154,7 @@ Array.prototype.where = function (predicate) {
|
|||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}, []);
|
}, []);
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
let ret = [];
|
let ret = [];
|
||||||
for (let i = 0, len = array.length; i < len; i++) {
|
for (let i = 0, len = array.length; i < len; i++) {
|
||||||
let element = array[i];
|
let element = array[i];
|
||||||
@@ -153,7 +168,7 @@ Array.prototype.where = function (predicate) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return where(this, predicate);
|
return where(this, predicate);
|
||||||
}
|
};
|
||||||
|
|
||||||
Array.prototype.count = function (predicate) {
|
Array.prototype.count = function (predicate) {
|
||||||
function count(array, predicate) {
|
function count(array, predicate) {
|
||||||
@@ -161,7 +176,7 @@ Array.prototype.count = function (predicate) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return count(this, predicate);
|
return count(this, predicate);
|
||||||
}
|
};
|
||||||
|
|
||||||
Array.prototype.findAll = function (predicate) {
|
Array.prototype.findAll = function (predicate) {
|
||||||
function findAll(array, predicate) {
|
function findAll(array, predicate) {
|
||||||
@@ -169,7 +184,7 @@ Array.prototype.findAll = function (predicate) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return findAll(this, predicate);
|
return findAll(this, predicate);
|
||||||
}
|
};
|
||||||
|
|
||||||
Array.prototype.contains = function (value) {
|
Array.prototype.contains = function (value) {
|
||||||
function contains(array, value) {
|
function contains(array, value) {
|
||||||
@@ -183,7 +198,7 @@ Array.prototype.contains = function (value) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return contains(this, value);
|
return contains(this, value);
|
||||||
}
|
};
|
||||||
|
|
||||||
Array.prototype.removeAll = function (predicate) {
|
Array.prototype.removeAll = function (predicate) {
|
||||||
function removeAll(array, predicate) {
|
function removeAll(array, predicate) {
|
||||||
@@ -198,7 +213,7 @@ Array.prototype.removeAll = function (predicate) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
removeAll(this, predicate);
|
removeAll(this, predicate);
|
||||||
}
|
};
|
||||||
|
|
||||||
Array.prototype.remove = function (element) {
|
Array.prototype.remove = function (element) {
|
||||||
function remove(array, element) {
|
function remove(array, element) {
|
||||||
@@ -209,14 +224,13 @@ Array.prototype.remove = function (element) {
|
|||||||
if (index >= 0) {
|
if (index >= 0) {
|
||||||
array.splice(index, 1);
|
array.splice(index, 1);
|
||||||
return true;
|
return true;
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return remove(this, element);
|
return remove(this, element);
|
||||||
}
|
};
|
||||||
|
|
||||||
Array.prototype.removeAt = function (index) {
|
Array.prototype.removeAt = function (index) {
|
||||||
function removeAt(array, index) {
|
function removeAt(array, index) {
|
||||||
@@ -224,7 +238,7 @@ Array.prototype.removeAt = function (index) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return removeAt(this, index);
|
return removeAt(this, index);
|
||||||
}
|
};
|
||||||
|
|
||||||
Array.prototype.removeRange = function (index, count) {
|
Array.prototype.removeRange = function (index, count) {
|
||||||
function removeRange(array, index, count) {
|
function removeRange(array, index, count) {
|
||||||
@@ -232,7 +246,7 @@ Array.prototype.removeRange = function (index, count) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return removeRange(this, index, count);
|
return removeRange(this, index, count);
|
||||||
}
|
};
|
||||||
|
|
||||||
Array.prototype.select = function (selector) {
|
Array.prototype.select = function (selector) {
|
||||||
function select(array, selector) {
|
function select(array, selector) {
|
||||||
@@ -241,8 +255,7 @@ Array.prototype.select = function (selector) {
|
|||||||
ret.push(selector.call(arguments[2], element, index, array));
|
ret.push(selector.call(arguments[2], element, index, array));
|
||||||
return ret;
|
return ret;
|
||||||
}, []);
|
}, []);
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
let ret = [];
|
let ret = [];
|
||||||
for (let i = 0, len = array.length; i < len; i++) {
|
for (let i = 0, len = array.length; i < len; i++) {
|
||||||
ret.push(selector.call(arguments[2], array[i], i, array))
|
ret.push(selector.call(arguments[2], array[i], i, array))
|
||||||
@@ -253,17 +266,16 @@ Array.prototype.select = function (selector) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return select(this, selector);
|
return select(this, selector);
|
||||||
}
|
};
|
||||||
|
|
||||||
Array.prototype.orderBy = function (keySelector, comparer) {
|
Array.prototype.orderBy = function (keySelector, comparer) {
|
||||||
function orderBy(array, keySelector, comparer) {
|
function orderBy(array, keySelector, comparer) {
|
||||||
array.sort(function (x, y) {
|
array.sort(function (x, y) {
|
||||||
let v1 = keySelector(x)
|
let v1 = keySelector(x);
|
||||||
let v2 = keySelector(y)
|
let v2 = keySelector(y);
|
||||||
if (comparer) {
|
if (comparer) {
|
||||||
return comparer(v1, v2);
|
return comparer(v1, v2);
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
return (v1 > v2) ? 1 : -1;
|
return (v1 > v2) ? 1 : -1;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -272,17 +284,16 @@ Array.prototype.orderBy = function (keySelector, comparer) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return orderBy(this, keySelector, comparer);
|
return orderBy(this, keySelector, comparer);
|
||||||
}
|
};
|
||||||
|
|
||||||
Array.prototype.orderByDescending = function (keySelector, comparer) {
|
Array.prototype.orderByDescending = function (keySelector, comparer) {
|
||||||
function orderByDescending(array, keySelector, comparer) {
|
function orderByDescending(array, keySelector, comparer) {
|
||||||
array.sort(function (x, y) {
|
array.sort(function (x, y) {
|
||||||
let v1 = keySelector(x)
|
let v1 = keySelector(x);
|
||||||
let v2 = keySelector(y)
|
let v2 = keySelector(y);
|
||||||
if (comparer) {
|
if (comparer) {
|
||||||
return -comparer(v1, v2);
|
return -comparer(v1, v2);
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
return (v1 < v2) ? 1 : -1;
|
return (v1 < v2) ? 1 : -1;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -291,7 +302,7 @@ Array.prototype.orderByDescending = function (keySelector, comparer) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return orderByDescending(this, keySelector, comparer);
|
return orderByDescending(this, keySelector, comparer);
|
||||||
}
|
};
|
||||||
|
|
||||||
Array.prototype.groupBy = function (keySelector) {
|
Array.prototype.groupBy = function (keySelector) {
|
||||||
function groupBy(array, keySelector) {
|
function groupBy(array, keySelector) {
|
||||||
@@ -299,7 +310,9 @@ Array.prototype.groupBy = function (keySelector) {
|
|||||||
let keys = [];
|
let keys = [];
|
||||||
return array.reduce(function (groups, element, index) {
|
return array.reduce(function (groups, element, index) {
|
||||||
let key = JSON.stringify(keySelector.call(arguments[1], element, index, array))
|
let key = JSON.stringify(keySelector.call(arguments[1], element, index, array))
|
||||||
let index2 = keys.findIndex(function (x) { return x === key });
|
let index2 = keys.findIndex(function (x) {
|
||||||
|
return x === key;
|
||||||
|
});
|
||||||
|
|
||||||
if (index2 < 0) {
|
if (index2 < 0) {
|
||||||
index2 = keys.push(key) - 1;
|
index2 = keys.push(key) - 1;
|
||||||
@@ -312,13 +325,14 @@ Array.prototype.groupBy = function (keySelector) {
|
|||||||
groups[index2].push(element);
|
groups[index2].push(element);
|
||||||
return groups;
|
return groups;
|
||||||
}, []);
|
}, []);
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
let groups = [];
|
let groups = [];
|
||||||
let keys = [];
|
let keys = [];
|
||||||
for (let i = 0, len = array.length; i < len; i++) {
|
for (let i = 0, len = array.length; i < len; i++) {
|
||||||
let key = JSON.stringify(keySelector.call(arguments[1], array[i], i, array));
|
let key = JSON.stringify(keySelector.call(arguments[1], array[i], i, array));
|
||||||
let index = keys.findIndex(function (x) { return x === key });
|
let index = keys.findIndex(function (x) {
|
||||||
|
return x === key;
|
||||||
|
});
|
||||||
|
|
||||||
if (index < 0) {
|
if (index < 0) {
|
||||||
index = keys.push(key) - 1;
|
index = keys.push(key) - 1;
|
||||||
@@ -336,7 +350,7 @@ Array.prototype.groupBy = function (keySelector) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return groupBy(this, keySelector);
|
return groupBy(this, keySelector);
|
||||||
}
|
};
|
||||||
|
|
||||||
Array.prototype.sum = function (selector) {
|
Array.prototype.sum = function (selector) {
|
||||||
function sum(array, selector) {
|
function sum(array, selector) {
|
||||||
@@ -345,17 +359,14 @@ Array.prototype.sum = function (selector) {
|
|||||||
if (i == 0) {
|
if (i == 0) {
|
||||||
if (selector) {
|
if (selector) {
|
||||||
ret = selector.call(arguments[2], array[i], i, array);
|
ret = selector.call(arguments[2], array[i], i, array);
|
||||||
|
} else {
|
||||||
|
ret = array[i];
|
||||||
}
|
}
|
||||||
else {
|
} else {
|
||||||
ret = array[i]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (selector) {
|
if (selector) {
|
||||||
ret += selector.call(arguments[2], array[i], i, array);
|
ret += selector.call(arguments[2], array[i], i, array);
|
||||||
}
|
} else {
|
||||||
else {
|
ret += array[i];
|
||||||
ret += array[i]
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -364,4 +375,4 @@ Array.prototype.sum = function (selector) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return sum(this, selector);
|
return sum(this, selector);
|
||||||
}
|
};
|
||||||
@@ -1,72 +1,74 @@
|
|||||||
class GaussianBlurEffect extends egret.CustomFilter {
|
module es {
|
||||||
// private static blur_frag = "precision mediump float;\n" +
|
export class GaussianBlurEffect extends egret.CustomFilter {
|
||||||
// "uniform vec2 blur;\n" +
|
// private static blur_frag = "precision mediump float;\n" +
|
||||||
// "uniform sampler2D uSampler;\n" +
|
// "uniform vec2 blur;\n" +
|
||||||
// "varying vec2 vTextureCoord;\n" +
|
// "uniform sampler2D uSampler;\n" +
|
||||||
// "uniform vec2 uTextureSize;\n" +
|
// "varying vec2 vTextureCoord;\n" +
|
||||||
// "void main()\n" +
|
// "uniform vec2 uTextureSize;\n" +
|
||||||
// "{\n " +
|
// "void main()\n" +
|
||||||
// "const int sampleRadius = 5;\n" +
|
// "{\n " +
|
||||||
// "const int samples = sampleRadius * 2 + 1;\n" +
|
// "const int sampleRadius = 5;\n" +
|
||||||
// "vec2 blurUv = blur / uTextureSize;\n" +
|
// "const int samples = sampleRadius * 2 + 1;\n" +
|
||||||
// "vec4 color = vec4(0, 0, 0, 0);\n" +
|
// "vec2 blurUv = blur / uTextureSize;\n" +
|
||||||
// "vec2 uv = vec2(0.0, 0.0);\n" +
|
// "vec4 color = vec4(0, 0, 0, 0);\n" +
|
||||||
// "blurUv /= float(sampleRadius);\n" +
|
// "vec2 uv = vec2(0.0, 0.0);\n" +
|
||||||
|
// "blurUv /= float(sampleRadius);\n" +
|
||||||
|
|
||||||
// "for (int i = -sampleRadius; i <= sampleRadius; i++) {\n" +
|
// "for (int i = -sampleRadius; i <= sampleRadius; i++) {\n" +
|
||||||
// "uv.x = vTextureCoord.x + float(i) * blurUv.x;\n" +
|
// "uv.x = vTextureCoord.x + float(i) * blurUv.x;\n" +
|
||||||
// "uv.y = vTextureCoord.y + float(i) * blurUv.y;\n" +
|
// "uv.y = vTextureCoord.y + float(i) * blurUv.y;\n" +
|
||||||
// "color += texture2D(uSampler, uv);\n" +
|
// "color += texture2D(uSampler, uv);\n" +
|
||||||
// "}\n" +
|
// "}\n" +
|
||||||
|
|
||||||
// "color /= float(samples);\n" +
|
// "color /= float(samples);\n" +
|
||||||
// "gl_FragColor = color;\n" +
|
// "gl_FragColor = color;\n" +
|
||||||
// "}";
|
// "}";
|
||||||
|
|
||||||
private static blur_frag = "precision mediump float;\n" +
|
private static blur_frag = "precision mediump float;\n" +
|
||||||
"uniform sampler2D uSampler;\n" +
|
"uniform sampler2D uSampler;\n" +
|
||||||
"uniform float screenWidth;\n" +
|
"uniform float screenWidth;\n" +
|
||||||
"uniform float screenHeight;\n" +
|
"uniform float screenHeight;\n" +
|
||||||
|
|
||||||
"float normpdf(in float x, in float sigma)\n" +
|
"float normpdf(in float x, in float sigma)\n" +
|
||||||
"{\n" +
|
"{\n" +
|
||||||
"return 0.39894*exp(-0.5*x*x/(sigma*sigma))/sigma;\n" +
|
"return 0.39894*exp(-0.5*x*x/(sigma*sigma))/sigma;\n" +
|
||||||
"}\n" +
|
"}\n" +
|
||||||
|
|
||||||
"void main()\n" +
|
"void main()\n" +
|
||||||
"{\n" +
|
"{\n" +
|
||||||
"vec3 c = texture2D(uSampler, gl_FragCoord.xy / vec2(screenWidth, screenHeight).xy).rgb;\n" +
|
"vec3 c = texture2D(uSampler, gl_FragCoord.xy / vec2(screenWidth, screenHeight).xy).rgb;\n" +
|
||||||
|
|
||||||
"const int mSize = 11;\n" +
|
"const int mSize = 11;\n" +
|
||||||
"const int kSize = (mSize - 1)/2;\n" +
|
"const int kSize = (mSize - 1)/2;\n" +
|
||||||
"float kernel[mSize];\n" +
|
"float kernel[mSize];\n" +
|
||||||
"vec3 final_colour = vec3(0.0);\n" +
|
"vec3 final_colour = vec3(0.0);\n" +
|
||||||
|
|
||||||
"float sigma = 7.0;\n" +
|
"float sigma = 7.0;\n" +
|
||||||
"float z = 0.0;\n" +
|
"float z = 0.0;\n" +
|
||||||
"for (int j = 0; j <= kSize; ++j)\n" +
|
"for (int j = 0; j <= kSize; ++j)\n" +
|
||||||
"{\n" +
|
"{\n" +
|
||||||
"kernel[kSize+j] = kernel[kSize-j] = normpdf(float(j),sigma);\n" +
|
"kernel[kSize+j] = kernel[kSize-j] = normpdf(float(j),sigma);\n" +
|
||||||
"}\n" +
|
"}\n" +
|
||||||
|
|
||||||
"for (int j = 0; j < mSize; ++j)\n" +
|
"for (int j = 0; j < mSize; ++j)\n" +
|
||||||
"{\n" +
|
"{\n" +
|
||||||
"z += kernel[j];\n" +
|
"z += kernel[j];\n" +
|
||||||
"}\n" +
|
"}\n" +
|
||||||
|
|
||||||
"for (int i = -kSize; i <= kSize; ++i)\n" +
|
"for (int i = -kSize; i <= kSize; ++i)\n" +
|
||||||
"{\n" +
|
"{\n" +
|
||||||
"for (int j = -kSize; j <= kSize; ++j)\n" +
|
"for (int j = -kSize; j <= kSize; ++j)\n" +
|
||||||
"{\n" +
|
"{\n" +
|
||||||
"final_colour += kernel[kSize+j]*kernel[kSize+i]*texture2D(uSampler, (gl_FragCoord.xy+vec2(float(i),float(j))) / vec2(screenWidth, screenHeight).xy).rgb;\n" +
|
"final_colour += kernel[kSize+j]*kernel[kSize+i]*texture2D(uSampler, (gl_FragCoord.xy+vec2(float(i),float(j))) / vec2(screenWidth, screenHeight).xy).rgb;\n" +
|
||||||
"}\n}\n" +
|
"}\n}\n" +
|
||||||
"gl_FragColor = vec4(final_colour/(z*z), 1.0);\n" +
|
"gl_FragColor = vec4(final_colour/(z*z), 1.0);\n" +
|
||||||
"}";
|
"}";
|
||||||
|
|
||||||
constructor(){
|
constructor(){
|
||||||
super(PostProcessor.default_vert, GaussianBlurEffect.blur_frag,{
|
super(PostProcessor.default_vert, GaussianBlurEffect.blur_frag,{
|
||||||
screenWidth: SceneManager.stage.stageWidth,
|
screenWidth: Core.graphicsDevice.viewport.width,
|
||||||
screenHeight: SceneManager.stage.stageHeight
|
screenHeight: Core.graphicsDevice.viewport.height
|
||||||
});
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,34 +1,36 @@
|
|||||||
class PolygonLightEffect extends egret.CustomFilter {
|
module es {
|
||||||
private static vertSrc = "attribute vec2 aVertexPosition;\n" +
|
export class PolygonLightEffect extends egret.CustomFilter {
|
||||||
"attribute vec2 aTextureCoord;\n" +
|
private static vertSrc = "attribute vec2 aVertexPosition;\n" +
|
||||||
|
"attribute vec2 aTextureCoord;\n" +
|
||||||
|
|
||||||
"uniform vec2 projectionVector;\n" +
|
"uniform vec2 projectionVector;\n" +
|
||||||
|
|
||||||
"varying vec2 vTextureCoord;\n" +
|
"varying vec2 vTextureCoord;\n" +
|
||||||
|
|
||||||
"const vec2 center = vec2(-1.0, 1.0);\n" +
|
"const vec2 center = vec2(-1.0, 1.0);\n" +
|
||||||
|
|
||||||
"void main(void) {\n" +
|
"void main(void) {\n" +
|
||||||
" gl_Position = vec4( (aVertexPosition / projectionVector) + center , 0.0, 1.0);\n" +
|
" gl_Position = vec4( (aVertexPosition / projectionVector) + center , 0.0, 1.0);\n" +
|
||||||
" vTextureCoord = aTextureCoord;\n" +
|
" vTextureCoord = aTextureCoord;\n" +
|
||||||
"}";
|
"}";
|
||||||
private static fragmentSrc = "precision lowp float;\n" +
|
private static fragmentSrc = "precision lowp float;\n" +
|
||||||
"varying vec2 vTextureCoord;\n" +
|
"varying vec2 vTextureCoord;\n" +
|
||||||
"uniform sampler2D uSampler;\n" +
|
"uniform sampler2D uSampler;\n" +
|
||||||
|
|
||||||
"#define SAMPLE_COUNT 15\n" +
|
"#define SAMPLE_COUNT 15\n" +
|
||||||
|
|
||||||
"uniform vec2 _sampleOffsets[SAMPLE_COUNT];\n" +
|
"uniform vec2 _sampleOffsets[SAMPLE_COUNT];\n" +
|
||||||
"uniform float _sampleWeights[SAMPLE_COUNT];\n" +
|
"uniform float _sampleWeights[SAMPLE_COUNT];\n" +
|
||||||
|
|
||||||
"void main(void) {\n" +
|
"void main(void) {\n" +
|
||||||
"vec4 c = vec4(0, 0, 0, 0);\n" +
|
"vec4 c = vec4(0, 0, 0, 0);\n" +
|
||||||
"for( int i = 0; i < SAMPLE_COUNT; i++ )\n" +
|
"for( int i = 0; i < SAMPLE_COUNT; i++ )\n" +
|
||||||
" c += texture2D( uSampler, vTextureCoord + _sampleOffsets[i] ) * _sampleWeights[i];\n" +
|
" c += texture2D( uSampler, vTextureCoord + _sampleOffsets[i] ) * _sampleWeights[i];\n" +
|
||||||
"gl_FragColor = c;\n" +
|
"gl_FragColor = c;\n" +
|
||||||
"}";
|
"}";
|
||||||
|
|
||||||
constructor(){
|
constructor(){
|
||||||
super(PolygonLightEffect.vertSrc, PolygonLightEffect.fragmentSrc);
|
super(PolygonLightEffect.vertSrc, PolygonLightEffect.fragmentSrc);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,27 +1,31 @@
|
|||||||
class GraphicsCapabilities extends egret.Capabilities {
|
module es {
|
||||||
|
export class GraphicsCapabilities extends egret.Capabilities {
|
||||||
|
|
||||||
public initialize(device: GraphicsDevice){
|
public initialize(device: GraphicsDevice){
|
||||||
this.platformInitialize(device);
|
this.platformInitialize(device);
|
||||||
}
|
|
||||||
|
|
||||||
private platformInitialize(device: GraphicsDevice){
|
|
||||||
let capabilities = this;
|
|
||||||
capabilities["isMobile"] = true;
|
|
||||||
|
|
||||||
let systemInfo = wx.getSystemInfoSync();
|
|
||||||
let systemStr = systemInfo.system.toLowerCase();
|
|
||||||
if (systemStr.indexOf("ios") > -1){
|
|
||||||
capabilities["os"] = "iOS";
|
|
||||||
} else if(systemStr.indexOf("android") > -1){
|
|
||||||
capabilities["os"] = "Android";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let language = systemInfo.language;
|
private platformInitialize(device: GraphicsDevice){
|
||||||
if (language.indexOf('zh') > -1){
|
if (GraphicsCapabilities.runtimeType != egret.RuntimeType.WXGAME)
|
||||||
language = "zh-CN";
|
return;
|
||||||
} else {
|
let capabilities = this;
|
||||||
language = "en-US";
|
capabilities["isMobile"] = true;
|
||||||
|
|
||||||
|
let systemInfo = wx.getSystemInfoSync();
|
||||||
|
let systemStr = systemInfo.system.toLowerCase();
|
||||||
|
if (systemStr.indexOf("ios") > -1){
|
||||||
|
capabilities["os"] = "iOS";
|
||||||
|
} else if(systemStr.indexOf("android") > -1){
|
||||||
|
capabilities["os"] = "Android";
|
||||||
|
}
|
||||||
|
|
||||||
|
let language = systemInfo.language;
|
||||||
|
if (language.indexOf('zh') > -1){
|
||||||
|
language = "zh-CN";
|
||||||
|
} else {
|
||||||
|
language = "en-US";
|
||||||
|
}
|
||||||
|
capabilities["language"] = language;
|
||||||
}
|
}
|
||||||
capabilities["language"] = language;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,10 +1,20 @@
|
|||||||
class GraphicsDevice {
|
module es {
|
||||||
private viewport: Viewport;
|
export class GraphicsDevice {
|
||||||
|
private _viewport: Viewport;
|
||||||
|
public get viewport(): Viewport{
|
||||||
|
return this._viewport;
|
||||||
|
}
|
||||||
|
|
||||||
public graphicsCapabilities: GraphicsCapabilities;
|
public graphicsCapabilities: GraphicsCapabilities;
|
||||||
|
|
||||||
constructor(){
|
constructor(){
|
||||||
this.graphicsCapabilities = new GraphicsCapabilities();
|
this.setup();
|
||||||
this.graphicsCapabilities.initialize(this);
|
this.graphicsCapabilities = new GraphicsCapabilities();
|
||||||
|
this.graphicsCapabilities.initialize(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
private setup(){
|
||||||
|
this._viewport = new Viewport(0, 0, Core._instance.stage.stageWidth, Core._instance.stage.stageHeight);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,58 +1,60 @@
|
|||||||
class PostProcessor {
|
module es {
|
||||||
public enable: boolean;
|
export class PostProcessor {
|
||||||
public effect: egret.Filter;
|
public enabled: boolean;
|
||||||
public scene: Scene;
|
public effect: egret.Filter;
|
||||||
public shape: egret.Shape;
|
public scene: Scene;
|
||||||
|
public shape: egret.Shape;
|
||||||
|
|
||||||
public static default_vert = "attribute vec2 aVertexPosition;\n" +
|
public static default_vert = "attribute vec2 aVertexPosition;\n" +
|
||||||
"attribute vec2 aTextureCoord;\n" +
|
"attribute vec2 aTextureCoord;\n" +
|
||||||
"attribute vec2 aColor;\n" +
|
"attribute vec2 aColor;\n" +
|
||||||
|
|
||||||
"uniform vec2 projectionVector;\n" +
|
"uniform vec2 projectionVector;\n" +
|
||||||
//"uniform vec2 offsetVector;\n" +
|
//"uniform vec2 offsetVector;\n" +
|
||||||
|
|
||||||
"varying vec2 vTextureCoord;\n" +
|
"varying vec2 vTextureCoord;\n" +
|
||||||
"varying vec4 vColor;\n" +
|
"varying vec4 vColor;\n" +
|
||||||
|
|
||||||
"const vec2 center = vec2(-1.0, 1.0);\n" +
|
"const vec2 center = vec2(-1.0, 1.0);\n" +
|
||||||
|
|
||||||
"void main(void) {\n" +
|
"void main(void) {\n" +
|
||||||
"gl_Position = vec4( (aVertexPosition / projectionVector) + center , 0.0, 1.0);\n" +
|
"gl_Position = vec4( (aVertexPosition / projectionVector) + center , 0.0, 1.0);\n" +
|
||||||
"vTextureCoord = aTextureCoord;\n" +
|
"vTextureCoord = aTextureCoord;\n" +
|
||||||
"vColor = vec4(aColor.x, aColor.x, aColor.x, aColor.x);\n" +
|
"vColor = vec4(aColor.x, aColor.x, aColor.x, aColor.x);\n" +
|
||||||
"}";
|
"}";
|
||||||
|
|
||||||
constructor(effect: egret.Filter = null){
|
constructor(effect: egret.Filter = null){
|
||||||
this.enable = true;
|
this.enabled = true;
|
||||||
this.effect = effect;
|
this.effect = effect;
|
||||||
}
|
|
||||||
|
|
||||||
public onAddedToScene(scene: Scene){
|
|
||||||
this.scene = scene;
|
|
||||||
this.shape = new egret.Shape();
|
|
||||||
this.shape.graphics.beginFill(0xFFFFFF, 1);
|
|
||||||
this.shape.graphics.drawRect(0, 0, SceneManager.stage.stageWidth, SceneManager.stage.stageHeight);
|
|
||||||
this.shape.graphics.endFill();
|
|
||||||
scene.addChild(this.shape);
|
|
||||||
}
|
|
||||||
|
|
||||||
public process(){
|
|
||||||
this.drawFullscreenQuad();
|
|
||||||
}
|
|
||||||
|
|
||||||
public onSceneBackBufferSizeChanged(newWidth: number, newHeight: number){}
|
|
||||||
|
|
||||||
protected drawFullscreenQuad(){
|
|
||||||
this.scene.filters = [this.effect];
|
|
||||||
// this.shape.filters = [this.effect];
|
|
||||||
}
|
|
||||||
|
|
||||||
public unload(){
|
|
||||||
if (this.effect){
|
|
||||||
this.effect = null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.scene.removeChild(this.shape);
|
public onAddedToScene(scene: Scene){
|
||||||
this.scene = null;
|
this.scene = scene;
|
||||||
|
this.shape = new egret.Shape();
|
||||||
|
this.shape.graphics.beginFill(0xFFFFFF, 1);
|
||||||
|
this.shape.graphics.drawRect(0, 0, Core.graphicsDevice.viewport.width, Core.graphicsDevice.viewport.height);
|
||||||
|
this.shape.graphics.endFill();
|
||||||
|
scene.addChild(this.shape);
|
||||||
|
}
|
||||||
|
|
||||||
|
public process(){
|
||||||
|
this.drawFullscreenQuad();
|
||||||
|
}
|
||||||
|
|
||||||
|
public onSceneBackBufferSizeChanged(newWidth: number, newHeight: number){}
|
||||||
|
|
||||||
|
protected drawFullscreenQuad(){
|
||||||
|
this.scene.filters = [this.effect];
|
||||||
|
// this.shape.filters = [this.effect];
|
||||||
|
}
|
||||||
|
|
||||||
|
public unload(){
|
||||||
|
if (this.effect){
|
||||||
|
this.effect = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.scene.removeChild(this.shape);
|
||||||
|
this.scene = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,8 @@
|
|||||||
class GaussianBlurPostProcessor extends PostProcessor {
|
module es {
|
||||||
public onAddedToScene(scene: Scene){
|
export class GaussianBlurPostProcessor extends PostProcessor {
|
||||||
super.onAddedToScene(scene);
|
public onAddedToScene(scene: Scene){
|
||||||
this.effect = new GaussianBlurEffect();
|
super.onAddedToScene(scene);
|
||||||
|
this.effect = new GaussianBlurEffect();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,13 +1,19 @@
|
|||||||
///<reference path="./Renderer.ts" />
|
///<reference path="./Renderer.ts" />
|
||||||
class DefaultRenderer extends Renderer {
|
module es {
|
||||||
public render(scene: Scene) {
|
export class DefaultRenderer extends Renderer {
|
||||||
let cam = this.camera ? this.camera : scene.camera;
|
constructor(){
|
||||||
this.beginRender(cam);
|
super(0, null);
|
||||||
|
}
|
||||||
|
|
||||||
for (let i = 0; i < scene.renderableComponents.count; i++){
|
public render(scene: Scene) {
|
||||||
let renderable = scene.renderableComponents.buffer[i];
|
let cam = this.camera ? this.camera : scene.camera;
|
||||||
if (renderable.enabled && renderable.isVisibleFromCamera(cam))
|
this.beginRender(cam);
|
||||||
this.renderAfterStateCheck(renderable, cam);
|
|
||||||
|
for (let i = 0; i < scene.renderableComponents.count; i++){
|
||||||
|
let renderable = scene.renderableComponents.buffer[i];
|
||||||
|
if (renderable.enabled && renderable.isVisibleFromCamera(cam))
|
||||||
|
this.renderAfterStateCheck(renderable, cam);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,7 +1,47 @@
|
|||||||
interface IRenderable {
|
module es {
|
||||||
bounds: Rectangle;
|
/**
|
||||||
enabled: boolean;
|
* 当该接口应用到组件时,它将注册组件以场景渲染器显示
|
||||||
isVisible: boolean;
|
* 该接口请谨慎实现
|
||||||
isVisibleFromCamera(camera: Camera);
|
*/
|
||||||
render(camera: Camera);
|
export interface IRenderable {
|
||||||
|
/**
|
||||||
|
* 对象的AABB用于相机剔除
|
||||||
|
*/
|
||||||
|
bounds: Rectangle;
|
||||||
|
/**
|
||||||
|
* 这个组件是否应该被渲染
|
||||||
|
*/
|
||||||
|
enabled: boolean;
|
||||||
|
/**
|
||||||
|
* 较低的渲染层在前面,较高的在后面
|
||||||
|
*/
|
||||||
|
renderLayer: number;
|
||||||
|
/**
|
||||||
|
* 可渲染的可见性。状态的改变会调用onBecameVisible/onBecameInvisible方法
|
||||||
|
*/
|
||||||
|
isVisible: boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 如果renderableComponent的边界与camera.bounds相交 返回true
|
||||||
|
* 用于处理isVisible标志的状态开关
|
||||||
|
* 在渲染方法中使用这个方法来决定是否渲染
|
||||||
|
* @param camera
|
||||||
|
*/
|
||||||
|
isVisibleFromCamera(camera: Camera);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 由渲染器调用。可以使用摄像机进行剔除
|
||||||
|
* @param camera
|
||||||
|
*/
|
||||||
|
render(camera: Camera);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用于排序IRenderables的比较器
|
||||||
|
*/
|
||||||
|
export class RenderableComparer {
|
||||||
|
public compare(self: IRenderable, other: IRenderable){
|
||||||
|
return other.renderLayer - self.renderLayer;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,46 +1,48 @@
|
|||||||
class PolyLight extends RenderableComponent {
|
module es {
|
||||||
public power: number;
|
export class PolyLight extends RenderableComponent {
|
||||||
protected _radius: number;
|
public power: number;
|
||||||
private _lightEffect;
|
protected _radius: number;
|
||||||
private _indices: number[] = [];
|
private _lightEffect;
|
||||||
|
private _indices: number[] = [];
|
||||||
|
|
||||||
public get radius(){
|
public get radius(){
|
||||||
return this._radius;
|
return this._radius;
|
||||||
}
|
|
||||||
public set radius(value: number){
|
|
||||||
this.setRadius(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
constructor(radius: number, color: number, power: number){
|
|
||||||
super();
|
|
||||||
|
|
||||||
this.radius = radius;
|
|
||||||
this.power = power;
|
|
||||||
this.color = color;
|
|
||||||
this.computeTriangleIndices();
|
|
||||||
}
|
|
||||||
|
|
||||||
private computeTriangleIndices(totalTris: number = 20){
|
|
||||||
this._indices.length = 0;
|
|
||||||
|
|
||||||
for (let i = 0; i < totalTris; i += 2){
|
|
||||||
this._indices.push(0);
|
|
||||||
this._indices.push(i + 2);
|
|
||||||
this._indices.push(i + 1);
|
|
||||||
}
|
}
|
||||||
}
|
public set radius(value: number){
|
||||||
|
this.setRadius(value);
|
||||||
public setRadius(radius: number){
|
|
||||||
if (radius != this._radius){
|
|
||||||
this._radius = radius;
|
|
||||||
this._areBoundsDirty = true;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public render(camera: Camera) {
|
constructor(radius: number, color: number, power: number){
|
||||||
}
|
super();
|
||||||
|
|
||||||
public reset(){
|
this.radius = radius;
|
||||||
|
this.power = power;
|
||||||
|
this.color = color;
|
||||||
|
this.computeTriangleIndices();
|
||||||
|
}
|
||||||
|
|
||||||
|
private computeTriangleIndices(totalTris: number = 20){
|
||||||
|
this._indices.length = 0;
|
||||||
|
|
||||||
|
for (let i = 0; i < totalTris; i += 2){
|
||||||
|
this._indices.push(0);
|
||||||
|
this._indices.push(i + 2);
|
||||||
|
this._indices.push(i + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public setRadius(radius: number){
|
||||||
|
if (radius != this._radius){
|
||||||
|
this._radius = radius;
|
||||||
|
this._areBoundsDirty = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public render(camera: Camera) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public reset(){
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,38 +1,63 @@
|
|||||||
/**
|
module es {
|
||||||
* 渲染器被添加到场景中并处理所有对RenderableComponent的实际调用
|
|
||||||
*/
|
|
||||||
abstract class Renderer {
|
|
||||||
/**
|
/**
|
||||||
* 渲染器用于渲染的摄像机(实际上是用于剔除的变换矩阵和边界)
|
* 渲染器被添加到场景中并处理所有对RenderableComponent的实际调用
|
||||||
* 不是必须的
|
|
||||||
* Renderer子类可以选择调用beginRender时使用的摄像头
|
|
||||||
*/
|
*/
|
||||||
public camera: Camera;
|
export abstract class Renderer {
|
||||||
|
/**
|
||||||
|
* 渲染器用于渲染的摄像机(实际上是用于剔除的变换矩阵和边界)
|
||||||
|
* 不是必须的
|
||||||
|
* Renderer子类可以选择调用beginRender时使用的摄像头
|
||||||
|
*/
|
||||||
|
public camera: Camera;
|
||||||
|
/**
|
||||||
|
* 指定场景调用渲染器的顺序
|
||||||
|
*/
|
||||||
|
public readonly renderOrder: number = 0;
|
||||||
|
|
||||||
/**
|
protected constructor(renderOrder: number, camera: Camera = null){
|
||||||
* 当渲染器被添加到场景时调用
|
this.camera = camera;
|
||||||
* @param scene
|
this.renderOrder = renderOrder;
|
||||||
*/
|
}
|
||||||
public onAddedToScene(scene: Scene){}
|
|
||||||
|
|
||||||
protected beginRender(cam: Camera){
|
/**
|
||||||
|
* 当渲染器被添加到场景时调用
|
||||||
|
* @param scene
|
||||||
|
*/
|
||||||
|
public onAddedToScene(scene: Scene){}
|
||||||
|
|
||||||
}
|
/**
|
||||||
|
* 当场景结束或渲染器从场景中移除时调用。使用这个进行清理。
|
||||||
|
*/
|
||||||
|
public unload(){ }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param scene
|
* @param cam
|
||||||
*/
|
*/
|
||||||
public abstract render(scene: Scene);
|
protected beginRender(cam: Camera){ }
|
||||||
|
|
||||||
public unload(){ }
|
public abstract render(scene: Scene);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param renderable
|
* @param renderable
|
||||||
* @param cam
|
* @param cam
|
||||||
*/
|
*/
|
||||||
protected renderAfterStateCheck(renderable: IRenderable, cam: Camera){
|
protected renderAfterStateCheck(renderable: IRenderable, cam: Camera){
|
||||||
renderable.render(cam);
|
renderable.render(cam);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 当默认场景渲染目标被调整大小和当场景已经开始添加渲染器时调用
|
||||||
|
* @param newWidth
|
||||||
|
* @param newHeight
|
||||||
|
*/
|
||||||
|
public onSceneBackBufferSizeChanged(newWidth: number, newHeight: number){
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public compareTo(other: Renderer): number{
|
||||||
|
return this.renderOrder - other.renderOrder;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,7 +1,9 @@
|
|||||||
/**
|
module es {
|
||||||
* 渲染器使用自己的不移动的摄像机进行渲染。
|
/**
|
||||||
*/
|
* 渲染器使用自己的不移动的摄像机进行渲染。
|
||||||
class ScreenSpaceRenderer extends Renderer {
|
*/
|
||||||
public render(scene: Scene) {
|
export class ScreenSpaceRenderer extends Renderer {
|
||||||
|
public render(scene: Scene) {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,38 +1,38 @@
|
|||||||
///<reference path="./SceneTransition.ts"/>
|
///<reference path="./SceneTransition.ts"/>
|
||||||
class FadeTransition extends SceneTransition {
|
module es {
|
||||||
public fadeToColor: number = 0x000000;
|
export class FadeTransition extends SceneTransition {
|
||||||
public fadeOutDuration = 0.4;
|
public fadeToColor: number = 0x000000;
|
||||||
public fadeEaseType: Function = egret.Ease.quadInOut;
|
public fadeOutDuration = 0.4;
|
||||||
public delayBeforeFadeInDuration = 0.1;
|
public fadeEaseType: Function = egret.Ease.quadInOut;
|
||||||
private _mask: egret.Shape;
|
public delayBeforeFadeInDuration = 0.1;
|
||||||
private _alpha: number = 0;
|
private _mask: egret.Shape;
|
||||||
|
private _alpha: number = 0;
|
||||||
|
|
||||||
constructor(sceneLoadAction: Function) {
|
constructor(sceneLoadAction: Function) {
|
||||||
super(sceneLoadAction);
|
super(sceneLoadAction);
|
||||||
this._mask = new egret.Shape();
|
this._mask = new egret.Shape();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async onBeginTransition() {
|
public async onBeginTransition() {
|
||||||
this._mask.graphics.beginFill(this.fadeToColor, 1);
|
this._mask.graphics.beginFill(this.fadeToColor, 1);
|
||||||
this._mask.graphics.drawRect(0, 0, SceneManager.stage.stageWidth, SceneManager.stage.stageHeight);
|
this._mask.graphics.drawRect(0, 0, Core.graphicsDevice.viewport.width, Core.graphicsDevice.viewport.height);
|
||||||
this._mask.graphics.endFill();
|
this._mask.graphics.endFill();
|
||||||
SceneManager.stage.addChild(this._mask);
|
|
||||||
|
|
||||||
egret.Tween.get(this).to({ _alpha: 1}, this.fadeOutDuration * 1000, this.fadeEaseType)
|
egret.Tween.get(this).to({ _alpha: 1}, this.fadeOutDuration * 1000, this.fadeEaseType)
|
||||||
.call(async () => {
|
.call(async () => {
|
||||||
await this.loadNextScene();
|
await this.loadNextScene();
|
||||||
}).wait(this.delayBeforeFadeInDuration).call(() => {
|
}).wait(this.delayBeforeFadeInDuration).call(() => {
|
||||||
egret.Tween.get(this).to({ _alpha: 0 }, this.fadeOutDuration * 1000, this.fadeEaseType).call(() => {
|
egret.Tween.get(this).to({ _alpha: 0 }, this.fadeOutDuration * 1000, this.fadeEaseType).call(() => {
|
||||||
this.transitionComplete();
|
this.transitionComplete();
|
||||||
SceneManager.stage.removeChild(this._mask);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public render(){
|
public render(){
|
||||||
this._mask.graphics.clear();
|
this._mask.graphics.clear();
|
||||||
this._mask.graphics.beginFill(this.fadeToColor, this._alpha);
|
this._mask.graphics.beginFill(this.fadeToColor, this._alpha);
|
||||||
this._mask.graphics.drawRect(0, 0, SceneManager.stage.stageWidth, SceneManager.stage.stageHeight);
|
this._mask.graphics.drawRect(0, 0, Core.graphicsDevice.viewport.width, Core.graphicsDevice.viewport.height);
|
||||||
this._mask.graphics.endFill();
|
this._mask.graphics.endFill();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,75 +1,77 @@
|
|||||||
/**
|
module es {
|
||||||
* SceneTransition用于从一个场景过渡到另一个场景或在一个有效果的场景中过渡
|
|
||||||
*/
|
|
||||||
abstract class SceneTransition {
|
|
||||||
private _hasPreviousSceneRender: boolean;
|
|
||||||
/** 是否加载新场景的标志 */
|
|
||||||
public loadsNewScene: boolean;
|
|
||||||
/**
|
/**
|
||||||
* 将此用于两个部分的转换。例如,淡出会先淡出到黑色,然后当isNewSceneLoaded为true,它会淡出。
|
* SceneTransition用于从一个场景过渡到另一个场景或在一个有效果的场景中过渡
|
||||||
* 对于场景过渡,isNewSceneLoaded应该在中点设置为true,这就标识一个新的场景被加载了。
|
|
||||||
*/
|
*/
|
||||||
public isNewSceneLoaded: boolean;
|
export abstract class SceneTransition {
|
||||||
/** 返回新加载场景的函数 */
|
private _hasPreviousSceneRender: boolean;
|
||||||
protected sceneLoadAction: Function;
|
/** 是否加载新场景的标志 */
|
||||||
/** 在loadNextScene执行时调用。这在进行场景间过渡时很有用,这样你就知道什么时候可以更多地使用相机或者重置任何实体 */
|
public loadsNewScene: boolean;
|
||||||
public onScreenObscured: Function;
|
/**
|
||||||
/** 当转换完成执行时调用,以便可以调用其他工作,比如启动另一个转换。 */
|
* 将此用于两个部分的转换。例如,淡出会先淡出到黑色,然后当isNewSceneLoaded为true,它会淡出。
|
||||||
public onTransitionCompleted: Function;
|
* 对于场景过渡,isNewSceneLoaded应该在中点设置为true,这就标识一个新的场景被加载了。
|
||||||
|
*/
|
||||||
|
public isNewSceneLoaded: boolean;
|
||||||
|
/** 返回新加载场景的函数 */
|
||||||
|
protected sceneLoadAction: Function;
|
||||||
|
/** 在loadNextScene执行时调用。这在进行场景间过渡时很有用,这样你就知道什么时候可以更多地使用相机或者重置任何实体 */
|
||||||
|
public onScreenObscured: Function;
|
||||||
|
/** 当转换完成执行时调用,以便可以调用其他工作,比如启动另一个转换。 */
|
||||||
|
public onTransitionCompleted: Function;
|
||||||
|
|
||||||
public get hasPreviousSceneRender(){
|
public get hasPreviousSceneRender(){
|
||||||
if (!this._hasPreviousSceneRender){
|
if (!this._hasPreviousSceneRender){
|
||||||
this._hasPreviousSceneRender = true;
|
this._hasPreviousSceneRender = true;
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
constructor(sceneLoadAction: Function) {
|
||||||
}
|
this.sceneLoadAction = sceneLoadAction;
|
||||||
|
this.loadsNewScene = sceneLoadAction != null;
|
||||||
constructor(sceneLoadAction: Function) {
|
|
||||||
this.sceneLoadAction = sceneLoadAction;
|
|
||||||
this.loadsNewScene = sceneLoadAction != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public preRender() { }
|
|
||||||
|
|
||||||
public render() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public async onBeginTransition() {
|
|
||||||
await this.loadNextScene();
|
|
||||||
this.transitionComplete();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected transitionComplete() {
|
|
||||||
SceneManager.sceneTransition = null;
|
|
||||||
|
|
||||||
if (this.onTransitionCompleted) {
|
|
||||||
this.onTransitionCompleted();
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
protected async loadNextScene() {
|
public preRender() { }
|
||||||
if (this.onScreenObscured)
|
|
||||||
this.onScreenObscured();
|
|
||||||
|
|
||||||
if (!this.loadsNewScene) {
|
public render() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public async onBeginTransition() {
|
||||||
|
await this.loadNextScene();
|
||||||
|
this.transitionComplete();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected transitionComplete() {
|
||||||
|
Core._instance._sceneTransition = null;
|
||||||
|
|
||||||
|
if (this.onTransitionCompleted) {
|
||||||
|
this.onTransitionCompleted();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected async loadNextScene() {
|
||||||
|
if (this.onScreenObscured)
|
||||||
|
this.onScreenObscured();
|
||||||
|
|
||||||
|
if (!this.loadsNewScene) {
|
||||||
|
this.isNewSceneLoaded = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Core.scene = await this.sceneLoadAction();
|
||||||
this.isNewSceneLoaded = true;
|
this.isNewSceneLoaded = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
SceneManager.scene = await this.sceneLoadAction();
|
public tickEffectProgressProperty(filter: egret.CustomFilter, duration: number, easeType: Function, reverseDirection = false): Promise<boolean>{
|
||||||
this.isNewSceneLoaded = true;
|
return new Promise((resolve)=>{
|
||||||
}
|
let start = reverseDirection ? 1 : 0;
|
||||||
|
let end = reverseDirection ? 0 : 1;
|
||||||
|
|
||||||
public tickEffectProgressProperty(filter: egret.CustomFilter, duration: number, easeType: Function, reverseDirection = false): Promise<boolean>{
|
egret.Tween.get(filter.uniforms).set({_progress: start}).to({_progress: end}, duration * 1000, easeType).call(()=>{
|
||||||
return new Promise((resolve)=>{
|
resolve();
|
||||||
let start = reverseDirection ? 1 : 0;
|
});
|
||||||
let end = reverseDirection ? 0 : 1;
|
|
||||||
|
|
||||||
egret.Tween.get(filter.uniforms).set({_progress: start}).to({_progress: end}, duration * 1000, easeType).call(()=>{
|
|
||||||
resolve();
|
|
||||||
});
|
});
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,65 +1,65 @@
|
|||||||
class WindTransition extends SceneTransition {
|
module es {
|
||||||
private _mask: egret.Shape;
|
export class WindTransition extends SceneTransition {
|
||||||
private _windEffect: egret.CustomFilter;
|
private _mask: egret.Shape;
|
||||||
|
private _windEffect: egret.CustomFilter;
|
||||||
|
|
||||||
public duration = 1;
|
public duration = 1;
|
||||||
public set windSegments(value: number) {
|
public set windSegments(value: number) {
|
||||||
this._windEffect.uniforms._windSegments = value;
|
this._windEffect.uniforms._windSegments = value;
|
||||||
}
|
}
|
||||||
public set size(value: number) {
|
public set size(value: number) {
|
||||||
this._windEffect.uniforms._size = value;
|
this._windEffect.uniforms._size = value;
|
||||||
}
|
}
|
||||||
public easeType = egret.Ease.quadOut;
|
public easeType = egret.Ease.quadOut;
|
||||||
constructor(sceneLoadAction: Function) {
|
constructor(sceneLoadAction: Function) {
|
||||||
super(sceneLoadAction);
|
super(sceneLoadAction);
|
||||||
|
|
||||||
let vertexSrc = "attribute vec2 aVertexPosition;\n" +
|
let vertexSrc = "attribute vec2 aVertexPosition;\n" +
|
||||||
"attribute vec2 aTextureCoord;\n" +
|
"attribute vec2 aTextureCoord;\n" +
|
||||||
|
|
||||||
"uniform vec2 projectionVector;\n" +
|
"uniform vec2 projectionVector;\n" +
|
||||||
|
|
||||||
"varying vec2 vTextureCoord;\n" +
|
"varying vec2 vTextureCoord;\n" +
|
||||||
|
|
||||||
"const vec2 center = vec2(-1.0, 1.0);\n" +
|
"const vec2 center = vec2(-1.0, 1.0);\n" +
|
||||||
|
|
||||||
"void main(void) {\n" +
|
"void main(void) {\n" +
|
||||||
" gl_Position = vec4( (aVertexPosition / projectionVector) + center , 0.0, 1.0);\n" +
|
" gl_Position = vec4( (aVertexPosition / projectionVector) + center , 0.0, 1.0);\n" +
|
||||||
" vTextureCoord = aTextureCoord;\n" +
|
" vTextureCoord = aTextureCoord;\n" +
|
||||||
"}";
|
"}";
|
||||||
let fragmentSrc = "precision lowp float;\n" +
|
let fragmentSrc = "precision lowp float;\n" +
|
||||||
"varying vec2 vTextureCoord;\n" +
|
"varying vec2 vTextureCoord;\n" +
|
||||||
"uniform sampler2D uSampler;\n" +
|
"uniform sampler2D uSampler;\n" +
|
||||||
"uniform float _progress;\n" +
|
"uniform float _progress;\n" +
|
||||||
"uniform float _size;\n" +
|
"uniform float _size;\n" +
|
||||||
"uniform float _windSegments;\n" +
|
"uniform float _windSegments;\n" +
|
||||||
|
|
||||||
"void main(void) {\n" +
|
"void main(void) {\n" +
|
||||||
"vec2 co = floor(vec2(0.0, vTextureCoord.y * _windSegments));\n" +
|
"vec2 co = floor(vec2(0.0, vTextureCoord.y * _windSegments));\n" +
|
||||||
"float x = sin(dot(co.xy, vec2(12.9898, 78.233))) * 43758.5453;\n" +
|
"float x = sin(dot(co.xy, vec2(12.9898, 78.233))) * 43758.5453;\n" +
|
||||||
"float r = x - floor(x);\n" +
|
"float r = x - floor(x);\n" +
|
||||||
"float m = smoothstep(0.0, -_size, vTextureCoord.x * (1.0 - _size) + _size * r - (_progress * (1.0 + _size)));\n" +
|
"float m = smoothstep(0.0, -_size, vTextureCoord.x * (1.0 - _size) + _size * r - (_progress * (1.0 + _size)));\n" +
|
||||||
"vec4 fg = texture2D(uSampler, vTextureCoord);\n" +
|
"vec4 fg = texture2D(uSampler, vTextureCoord);\n" +
|
||||||
"gl_FragColor = mix(fg, vec4(0, 0, 0, 0), m);\n" +
|
"gl_FragColor = mix(fg, vec4(0, 0, 0, 0), m);\n" +
|
||||||
"}";
|
"}";
|
||||||
|
|
||||||
this._windEffect = new egret.CustomFilter(vertexSrc, fragmentSrc, {
|
this._windEffect = new egret.CustomFilter(vertexSrc, fragmentSrc, {
|
||||||
_progress: 0,
|
_progress: 0,
|
||||||
_size: 0.3,
|
_size: 0.3,
|
||||||
_windSegments: 100
|
_windSegments: 100
|
||||||
});
|
});
|
||||||
|
|
||||||
this._mask = new egret.Shape();
|
this._mask = new egret.Shape();
|
||||||
this._mask.graphics.beginFill(0xFFFFFF, 1);
|
this._mask.graphics.beginFill(0xFFFFFF, 1);
|
||||||
this._mask.graphics.drawRect(0, 0, SceneManager.stage.stageWidth, SceneManager.stage.stageHeight);
|
this._mask.graphics.drawRect(0, 0, Core.graphicsDevice.viewport.width, Core.graphicsDevice.viewport.height);
|
||||||
this._mask.graphics.endFill();
|
this._mask.graphics.endFill();
|
||||||
this._mask.filters = [this._windEffect];
|
this._mask.filters = [this._windEffect];
|
||||||
SceneManager.stage.addChild(this._mask);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public async onBeginTransition() {
|
public async onBeginTransition() {
|
||||||
this.loadNextScene();
|
this.loadNextScene();
|
||||||
await this.tickEffectProgressProperty(this._windEffect, this.duration, this.easeType);
|
await this.tickEffectProgressProperty(this._windEffect, this.duration, this.easeType);
|
||||||
this.transitionComplete();
|
this.transitionComplete();
|
||||||
SceneManager.stage.removeChild(this._mask);
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,34 +1,50 @@
|
|||||||
class Viewport {
|
module es {
|
||||||
private _x: number;
|
export class Viewport {
|
||||||
private _y: number;
|
private _x: number;
|
||||||
private _width: number;
|
private _y: number;
|
||||||
private _height: number;
|
private _width: number;
|
||||||
private _minDepth: number;
|
private _height: number;
|
||||||
private _maxDepth: number;
|
private _minDepth: number;
|
||||||
|
private _maxDepth: number;
|
||||||
|
|
||||||
public get aspectRatio(){
|
public get height(){
|
||||||
if ((this._height != 0) && (this._width != 0))
|
return this._height;
|
||||||
return (this._width / this._height);
|
}
|
||||||
return 0;
|
public set height(value: number){
|
||||||
}
|
this._height = value;
|
||||||
|
}
|
||||||
|
|
||||||
public get bounds(){
|
public get width(){
|
||||||
return new Rectangle(this._x, this._y, this._width, this._height);
|
return this._width;
|
||||||
}
|
}
|
||||||
public set bounds(value: Rectangle){
|
public set width(value: number){
|
||||||
this._x = value.x;
|
this._width = value;
|
||||||
this._y = value.y;
|
}
|
||||||
this._width = value.width;
|
|
||||||
this._height = value.height;
|
|
||||||
}
|
|
||||||
|
|
||||||
constructor(x: number, y: number, width: number, height: number){
|
public get aspectRatio(){
|
||||||
this._x = x;
|
if ((this._height != 0) && (this._width != 0))
|
||||||
this._y = y;
|
return (this._width / this._height);
|
||||||
this._width = width;
|
return 0;
|
||||||
this._height = height;
|
}
|
||||||
this._minDepth = 0;
|
|
||||||
this._maxDepth = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
public get bounds(){
|
||||||
|
return new Rectangle(this._x, this._y, this._width, this._height);
|
||||||
|
}
|
||||||
|
public set bounds(value: Rectangle){
|
||||||
|
this._x = value.x;
|
||||||
|
this._y = value.y;
|
||||||
|
this._width = value.width;
|
||||||
|
this._height = value.height;
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(x: number, y: number, width: number, height: number){
|
||||||
|
this._x = x;
|
||||||
|
this._y = y;
|
||||||
|
this._width = width;
|
||||||
|
this._height = height;
|
||||||
|
this._minDepth = 0;
|
||||||
|
this._maxDepth = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
+119
-117
@@ -1,121 +1,123 @@
|
|||||||
/** 贝塞尔帮助类 */
|
module es {
|
||||||
class Bezier {
|
/** 贝塞尔帮助类 */
|
||||||
/**
|
export class Bezier {
|
||||||
* 二次贝塞尔曲线
|
/**
|
||||||
* @param p0
|
* 二次贝塞尔曲线
|
||||||
* @param p1
|
* @param p0
|
||||||
* @param p2
|
* @param p1
|
||||||
* @param t
|
* @param p2
|
||||||
*/
|
* @param t
|
||||||
public static getPoint(p0: Vector2, p1: Vector2, p2: Vector2, t: number): Vector2 {
|
*/
|
||||||
t = MathHelper.clamp01(t);
|
public static getPoint(p0: Vector2, p1: Vector2, p2: Vector2, t: number): Vector2 {
|
||||||
let oneMinusT = 1 - t;
|
t = MathHelper.clamp01(t);
|
||||||
return Vector2.add(Vector2.add(Vector2.multiply(new Vector2(oneMinusT * oneMinusT), p0),
|
let oneMinusT = 1 - t;
|
||||||
Vector2.multiply(new Vector2(2 * oneMinusT * t), p1)), Vector2.multiply(new Vector2(t * t), p2));
|
return Vector2.add(Vector2.add(Vector2.multiply(new Vector2(oneMinusT * oneMinusT), p0),
|
||||||
}
|
Vector2.multiply(new Vector2(2 * oneMinusT * t), p1)), Vector2.multiply(new Vector2(t * t), p2));
|
||||||
|
|
||||||
/**
|
|
||||||
* 得到二次贝塞尔函数的一阶导数
|
|
||||||
* @param p0
|
|
||||||
* @param p1
|
|
||||||
* @param p2
|
|
||||||
* @param t
|
|
||||||
*/
|
|
||||||
public static getFirstDerivative(p0: Vector2, p1: Vector2, p2: Vector2, t: number) {
|
|
||||||
return Vector2.add(Vector2.multiply(new Vector2(2 * (1 - t)), Vector2.subtract(p1, p0)),
|
|
||||||
Vector2.multiply(new Vector2(2 * t), Vector2.subtract(p2, p1)));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 得到一个三次贝塞尔函数的一阶导数
|
|
||||||
* @param start
|
|
||||||
* @param firstControlPoint
|
|
||||||
* @param secondControlPoint
|
|
||||||
* @param end
|
|
||||||
* @param t
|
|
||||||
*/
|
|
||||||
public static getFirstDerivativeThree(start: Vector2, firstControlPoint: Vector2, secondControlPoint: Vector2,
|
|
||||||
end: Vector2, t: number) {
|
|
||||||
t = MathHelper.clamp01(t);
|
|
||||||
let oneMunusT = 1 - t;
|
|
||||||
return Vector2.add(Vector2.add(Vector2.multiply(new Vector2(3 * oneMunusT * oneMunusT), Vector2.subtract(firstControlPoint, start)),
|
|
||||||
Vector2.multiply(new Vector2(6 * oneMunusT * t), Vector2.subtract(secondControlPoint, firstControlPoint))),
|
|
||||||
Vector2.multiply(new Vector2(3 * t * t), Vector2.subtract(end, secondControlPoint)));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 计算一个三次贝塞尔
|
|
||||||
* @param start
|
|
||||||
* @param firstControlPoint
|
|
||||||
* @param secondControlPoint
|
|
||||||
* @param end
|
|
||||||
* @param t
|
|
||||||
*/
|
|
||||||
public static getPointThree(start: Vector2, firstControlPoint: Vector2, secondControlPoint: Vector2,
|
|
||||||
end: Vector2, t: number) {
|
|
||||||
t = MathHelper.clamp01(t);
|
|
||||||
let oneMunusT = 1 - t;
|
|
||||||
return Vector2.add(Vector2.add(Vector2.add(Vector2.multiply(new Vector2(oneMunusT * oneMunusT * oneMunusT), start),
|
|
||||||
Vector2.multiply(new Vector2(3 * oneMunusT * oneMunusT * t), firstControlPoint)),
|
|
||||||
Vector2.multiply(new Vector2(3 * oneMunusT * t * t), secondControlPoint)),
|
|
||||||
Vector2.multiply(new Vector2(t * t * t), end));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 递归地细分bezier曲线,直到满足距离校正
|
|
||||||
* 在这种算法中,平面切片的点要比曲面切片少。返回完成后应返回到ListPool的合并列表。
|
|
||||||
* @param start
|
|
||||||
* @param firstCtrlPoint
|
|
||||||
* @param secondCtrlPoint
|
|
||||||
* @param end
|
|
||||||
* @param distanceTolerance
|
|
||||||
*/
|
|
||||||
public static getOptimizedDrawingPoints(start: Vector2, firstCtrlPoint: Vector2, secondCtrlPoint: Vector2,
|
|
||||||
end: Vector2, distanceTolerance: number = 1) {
|
|
||||||
let points = ListPool.obtain<Vector2>();
|
|
||||||
points.push(start);
|
|
||||||
this.recursiveGetOptimizedDrawingPoints(start, firstCtrlPoint, secondCtrlPoint, end, points, distanceTolerance);
|
|
||||||
points.push(end);
|
|
||||||
|
|
||||||
return points;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 递归地细分bezier曲线,直到满足距离校正。在这种算法中,平面切片的点要比曲面切片少。
|
|
||||||
* @param start
|
|
||||||
* @param firstCtrlPoint
|
|
||||||
* @param secondCtrlPoint
|
|
||||||
* @param end
|
|
||||||
* @param points
|
|
||||||
* @param distanceTolerance
|
|
||||||
*/
|
|
||||||
private static recursiveGetOptimizedDrawingPoints(start: Vector2, firstCtrlPoint: Vector2, secondCtrlPoint: Vector2,
|
|
||||||
end: Vector2, points: Vector2[], distanceTolerance: number) {
|
|
||||||
// 计算线段的所有中点
|
|
||||||
let pt12 = Vector2.divide(Vector2.add(start, firstCtrlPoint), new Vector2(2));
|
|
||||||
let pt23 = Vector2.divide(Vector2.add(firstCtrlPoint, secondCtrlPoint), new Vector2(2));
|
|
||||||
let pt34 = Vector2.divide(Vector2.add(secondCtrlPoint, end), new Vector2(2));
|
|
||||||
|
|
||||||
// 计算新半直线的中点
|
|
||||||
let pt123 = Vector2.divide(Vector2.add(pt12, pt23), new Vector2(2));
|
|
||||||
let pt234 = Vector2.divide(Vector2.add(pt23, pt34), new Vector2(2));
|
|
||||||
|
|
||||||
// 最后再细分最后两个中点。如果我们满足我们的距离公差,这将是我们使用的最后一点。
|
|
||||||
let pt1234 = Vector2.divide(Vector2.add(pt123, pt234), new Vector2(2));
|
|
||||||
|
|
||||||
// 试着用一条直线来近似整个三次曲线
|
|
||||||
let deltaLine = Vector2.subtract(end, start);
|
|
||||||
|
|
||||||
let d2 = Math.abs(((firstCtrlPoint.x, end.x) * deltaLine.y - (firstCtrlPoint.y - end.y) * deltaLine.x));
|
|
||||||
let d3 = Math.abs(((secondCtrlPoint.x - end.x) * deltaLine.y - (secondCtrlPoint.y - end.y) * deltaLine.x));
|
|
||||||
|
|
||||||
if ((d2 + d3) * (d2 + d3) < distanceTolerance * (deltaLine.x * deltaLine.x + deltaLine.y * deltaLine.y)) {
|
|
||||||
points.push(pt1234);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 继续细分
|
/**
|
||||||
this.recursiveGetOptimizedDrawingPoints(start, pt12, pt123, pt1234, points, distanceTolerance);
|
* 得到二次贝塞尔函数的一阶导数
|
||||||
this.recursiveGetOptimizedDrawingPoints(pt1234, pt234, pt34, end, points, distanceTolerance);
|
* @param p0
|
||||||
|
* @param p1
|
||||||
|
* @param p2
|
||||||
|
* @param t
|
||||||
|
*/
|
||||||
|
public static getFirstDerivative(p0: Vector2, p1: Vector2, p2: Vector2, t: number) {
|
||||||
|
return Vector2.add(Vector2.multiply(new Vector2(2 * (1 - t)), Vector2.subtract(p1, p0)),
|
||||||
|
Vector2.multiply(new Vector2(2 * t), Vector2.subtract(p2, p1)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 得到一个三次贝塞尔函数的一阶导数
|
||||||
|
* @param start
|
||||||
|
* @param firstControlPoint
|
||||||
|
* @param secondControlPoint
|
||||||
|
* @param end
|
||||||
|
* @param t
|
||||||
|
*/
|
||||||
|
public static getFirstDerivativeThree(start: Vector2, firstControlPoint: Vector2, secondControlPoint: Vector2,
|
||||||
|
end: Vector2, t: number) {
|
||||||
|
t = MathHelper.clamp01(t);
|
||||||
|
let oneMunusT = 1 - t;
|
||||||
|
return Vector2.add(Vector2.add(Vector2.multiply(new Vector2(3 * oneMunusT * oneMunusT), Vector2.subtract(firstControlPoint, start)),
|
||||||
|
Vector2.multiply(new Vector2(6 * oneMunusT * t), Vector2.subtract(secondControlPoint, firstControlPoint))),
|
||||||
|
Vector2.multiply(new Vector2(3 * t * t), Vector2.subtract(end, secondControlPoint)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 计算一个三次贝塞尔
|
||||||
|
* @param start
|
||||||
|
* @param firstControlPoint
|
||||||
|
* @param secondControlPoint
|
||||||
|
* @param end
|
||||||
|
* @param t
|
||||||
|
*/
|
||||||
|
public static getPointThree(start: Vector2, firstControlPoint: Vector2, secondControlPoint: Vector2,
|
||||||
|
end: Vector2, t: number) {
|
||||||
|
t = MathHelper.clamp01(t);
|
||||||
|
let oneMunusT = 1 - t;
|
||||||
|
return Vector2.add(Vector2.add(Vector2.add(Vector2.multiply(new Vector2(oneMunusT * oneMunusT * oneMunusT), start),
|
||||||
|
Vector2.multiply(new Vector2(3 * oneMunusT * oneMunusT * t), firstControlPoint)),
|
||||||
|
Vector2.multiply(new Vector2(3 * oneMunusT * t * t), secondControlPoint)),
|
||||||
|
Vector2.multiply(new Vector2(t * t * t), end));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 递归地细分bezier曲线,直到满足距离校正
|
||||||
|
* 在这种算法中,平面切片的点要比曲面切片少。返回完成后应返回到ListPool的合并列表。
|
||||||
|
* @param start
|
||||||
|
* @param firstCtrlPoint
|
||||||
|
* @param secondCtrlPoint
|
||||||
|
* @param end
|
||||||
|
* @param distanceTolerance
|
||||||
|
*/
|
||||||
|
public static getOptimizedDrawingPoints(start: Vector2, firstCtrlPoint: Vector2, secondCtrlPoint: Vector2,
|
||||||
|
end: Vector2, distanceTolerance: number = 1) {
|
||||||
|
let points = ListPool.obtain<Vector2>();
|
||||||
|
points.push(start);
|
||||||
|
this.recursiveGetOptimizedDrawingPoints(start, firstCtrlPoint, secondCtrlPoint, end, points, distanceTolerance);
|
||||||
|
points.push(end);
|
||||||
|
|
||||||
|
return points;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 递归地细分bezier曲线,直到满足距离校正。在这种算法中,平面切片的点要比曲面切片少。
|
||||||
|
* @param start
|
||||||
|
* @param firstCtrlPoint
|
||||||
|
* @param secondCtrlPoint
|
||||||
|
* @param end
|
||||||
|
* @param points
|
||||||
|
* @param distanceTolerance
|
||||||
|
*/
|
||||||
|
private static recursiveGetOptimizedDrawingPoints(start: Vector2, firstCtrlPoint: Vector2, secondCtrlPoint: Vector2,
|
||||||
|
end: Vector2, points: Vector2[], distanceTolerance: number) {
|
||||||
|
// 计算线段的所有中点
|
||||||
|
let pt12 = Vector2.divide(Vector2.add(start, firstCtrlPoint), new Vector2(2));
|
||||||
|
let pt23 = Vector2.divide(Vector2.add(firstCtrlPoint, secondCtrlPoint), new Vector2(2));
|
||||||
|
let pt34 = Vector2.divide(Vector2.add(secondCtrlPoint, end), new Vector2(2));
|
||||||
|
|
||||||
|
// 计算新半直线的中点
|
||||||
|
let pt123 = Vector2.divide(Vector2.add(pt12, pt23), new Vector2(2));
|
||||||
|
let pt234 = Vector2.divide(Vector2.add(pt23, pt34), new Vector2(2));
|
||||||
|
|
||||||
|
// 最后再细分最后两个中点。如果我们满足我们的距离公差,这将是我们使用的最后一点。
|
||||||
|
let pt1234 = Vector2.divide(Vector2.add(pt123, pt234), new Vector2(2));
|
||||||
|
|
||||||
|
// 试着用一条直线来近似整个三次曲线
|
||||||
|
let deltaLine = Vector2.subtract(end, start);
|
||||||
|
|
||||||
|
let d2 = Math.abs(((firstCtrlPoint.x, end.x) * deltaLine.y - (firstCtrlPoint.y - end.y) * deltaLine.x));
|
||||||
|
let d3 = Math.abs(((secondCtrlPoint.x - end.x) * deltaLine.y - (secondCtrlPoint.y - end.y) * deltaLine.x));
|
||||||
|
|
||||||
|
if ((d2 + d3) * (d2 + d3) < distanceTolerance * (deltaLine.x * deltaLine.x + deltaLine.y * deltaLine.y)) {
|
||||||
|
points.push(pt1234);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 继续细分
|
||||||
|
this.recursiveGetOptimizedDrawingPoints(start, pt12, pt123, pt1234, points, distanceTolerance);
|
||||||
|
this.recursiveGetOptimizedDrawingPoints(pt1234, pt234, pt34, end, points, distanceTolerance);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+55
-53
@@ -1,62 +1,64 @@
|
|||||||
/**
|
module es {
|
||||||
* 帮助处理位掩码的实用程序类
|
|
||||||
* 除了isFlagSet之外,所有方法都期望flag参数是一个非移位的标志
|
|
||||||
* 允许您使用普通的(0、1、2、3等)来设置/取消您的标记
|
|
||||||
*/
|
|
||||||
class Flags {
|
|
||||||
/**
|
/**
|
||||||
* 检查位标志是否已在数值中设置
|
* 帮助处理位掩码的实用程序类
|
||||||
* 检查期望标志是否已经移位
|
* 除了isFlagSet之外,所有方法都期望flag参数是一个非移位的标志
|
||||||
* @param self
|
* 允许您使用普通的(0、1、2、3等)来设置/取消您的标记
|
||||||
* @param flag
|
|
||||||
*/
|
*/
|
||||||
public static isFlagSet(self: number, flag: number): boolean{
|
export class Flags {
|
||||||
return (self & flag) != 0;
|
/**
|
||||||
}
|
* 检查位标志是否已在数值中设置
|
||||||
|
* 检查期望标志是否已经移位
|
||||||
|
* @param self
|
||||||
|
* @param flag
|
||||||
|
*/
|
||||||
|
public static isFlagSet(self: number, flag: number): boolean{
|
||||||
|
return (self & flag) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 检查位标志是否在数值中设置
|
* 检查位标志是否在数值中设置
|
||||||
* @param self
|
* @param self
|
||||||
* @param flag
|
* @param flag
|
||||||
*/
|
*/
|
||||||
public static isUnshiftedFlagSet(self: number, flag: number): boolean{
|
public static isUnshiftedFlagSet(self: number, flag: number): boolean{
|
||||||
flag = 1 << flag;
|
flag = 1 << flag;
|
||||||
return (self & flag) != 0;
|
return (self & flag) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 设置数值标志位,移除所有已经设置的标志
|
* 设置数值标志位,移除所有已经设置的标志
|
||||||
* @param self
|
* @param self
|
||||||
* @param flag
|
* @param flag
|
||||||
*/
|
*/
|
||||||
public static setFlagExclusive(self: number, flag: number){
|
public static setFlagExclusive(self: number, flag: number){
|
||||||
return 1 << flag;
|
return 1 << flag;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 设置标志位
|
* 设置标志位
|
||||||
* @param self
|
* @param self
|
||||||
* @param flag
|
* @param flag
|
||||||
*/
|
*/
|
||||||
public static setFlag(self: number, flag: number){
|
public static setFlag(self: number, flag: number){
|
||||||
return (self | 1 << flag);
|
return (self | 1 << flag);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 取消标志位
|
* 取消标志位
|
||||||
* @param self
|
* @param self
|
||||||
* @param flag
|
* @param flag
|
||||||
*/
|
*/
|
||||||
public static unsetFlag(self: number, flag: number){
|
public static unsetFlag(self: number, flag: number){
|
||||||
flag = 1 << flag;
|
flag = 1 << flag;
|
||||||
return (self & (~flag));
|
return (self & (~flag));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 反转数值集合位
|
* 反转数值集合位
|
||||||
* @param self
|
* @param self
|
||||||
*/
|
*/
|
||||||
public static invertFlags(self: number){
|
public static invertFlags(self: number){
|
||||||
return ~self;
|
return ~self;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,78 +1,80 @@
|
|||||||
class MathHelper {
|
module es {
|
||||||
public static readonly Epsilon: number = 0.00001;
|
export class MathHelper {
|
||||||
public static readonly Rad2Deg = 57.29578;
|
public static readonly Epsilon: number = 0.00001;
|
||||||
public static readonly Deg2Rad = 0.0174532924;
|
public static readonly Rad2Deg = 57.29578;
|
||||||
|
public static readonly Deg2Rad = 0.0174532924;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 将弧度转换成角度。
|
* 将弧度转换成角度。
|
||||||
* @param radians 用弧度表示的角
|
* @param radians 用弧度表示的角
|
||||||
*/
|
*/
|
||||||
public static toDegrees(radians: number){
|
public static toDegrees(radians: number){
|
||||||
return radians * 57.295779513082320876798154814105;
|
return radians * 57.295779513082320876798154814105;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 将角度转换为弧度
|
* 将角度转换为弧度
|
||||||
* @param degrees
|
* @param degrees
|
||||||
*/
|
*/
|
||||||
public static toRadians(degrees: number){
|
public static toRadians(degrees: number){
|
||||||
return degrees * 0.017453292519943295769236907684886;
|
return degrees * 0.017453292519943295769236907684886;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* mapps值(在leftMin - leftMax范围内)到rightMin - rightMax范围内的值
|
* mapps值(在leftMin - leftMax范围内)到rightMin - rightMax范围内的值
|
||||||
* @param value
|
* @param value
|
||||||
* @param leftMin
|
* @param leftMin
|
||||||
* @param leftMax
|
* @param leftMax
|
||||||
* @param rightMin
|
* @param rightMin
|
||||||
* @param rightMax
|
* @param rightMax
|
||||||
*/
|
*/
|
||||||
public static map(value: number, leftMin: number, leftMax: number, rightMin: number, rightMax: number){
|
public static map(value: number, leftMin: number, leftMax: number, rightMin: number, rightMax: number){
|
||||||
return rightMin + (value - leftMin) * (rightMax - rightMin) / (leftMax - leftMin);
|
return rightMin + (value - leftMin) * (rightMax - rightMin) / (leftMax - leftMin);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static lerp(value1: number, value2: number, amount: number){
|
public static lerp(value1: number, value2: number, amount: number){
|
||||||
return value1 + (value2 - value1) * amount;
|
return value1 + (value2 - value1) * amount;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static clamp(value: number, min: number, max: number){
|
public static clamp(value: number, min: number, max: number){
|
||||||
if (value < min)
|
if (value < min)
|
||||||
return min;
|
return min;
|
||||||
|
|
||||||
if (value > max)
|
if (value > max)
|
||||||
return max;
|
return max;
|
||||||
|
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static pointOnCirlce(circleCenter: Vector2, radius: number, angleInDegrees: number){
|
public static pointOnCirlce(circleCenter: Vector2, radius: number, angleInDegrees: number){
|
||||||
let radians = MathHelper.toRadians(angleInDegrees);
|
let radians = MathHelper.toRadians(angleInDegrees);
|
||||||
return new Vector2(Math.cos(radians) * radians + circleCenter.x, Math.sin(radians) * radians + circleCenter.y);
|
return new Vector2(Math.cos(radians) * radians + circleCenter.x, Math.sin(radians) * radians + circleCenter.y);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 如果值为偶数,返回true
|
* 如果值为偶数,返回true
|
||||||
* @param value
|
* @param value
|
||||||
*/
|
*/
|
||||||
public static isEven(value: number){
|
public static isEven(value: number){
|
||||||
return value % 2 == 0;
|
return value % 2 == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 数值限定在0-1之间
|
* 数值限定在0-1之间
|
||||||
* @param value
|
* @param value
|
||||||
*/
|
*/
|
||||||
public static clamp01(value: number){
|
public static clamp01(value: number){
|
||||||
if (value < 0)
|
if (value < 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (value > 1)
|
if (value > 1)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static angleBetweenVectors(from: Vector2, to: Vector2){
|
public static angleBetweenVectors(from: Vector2, to: Vector2){
|
||||||
return Math.atan2(to.y - from.y, to.x - from.x);
|
return Math.atan2(to.y - from.y, to.x - from.x);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+151
-186
@@ -1,217 +1,182 @@
|
|||||||
/**
|
module es {
|
||||||
* 表示右手3 * 3的浮点矩阵,可以存储平移、缩放和旋转信息。
|
export var matrixPool = [];
|
||||||
*/
|
|
||||||
class Matrix2D {
|
|
||||||
public m11: number = 0;
|
|
||||||
public m12: number = 0;
|
|
||||||
|
|
||||||
public m21: number = 0;
|
|
||||||
public m22: number = 0;
|
|
||||||
|
|
||||||
public m31: number = 0;
|
|
||||||
public m32: number = 0;
|
|
||||||
|
|
||||||
private static _identity: Matrix2D = new Matrix2D(1, 0, 0, 1, 0, 0);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 单位矩阵
|
* 表示右手3 * 3的浮点矩阵,可以存储平移、缩放和旋转信息。
|
||||||
*/
|
*/
|
||||||
public static get identity(){
|
export class Matrix2D extends egret.Matrix{
|
||||||
return Matrix2D._identity;
|
public get m11(): number{
|
||||||
}
|
return this.a;
|
||||||
|
}
|
||||||
|
public set m11(value: number){
|
||||||
|
this.a = value;
|
||||||
|
}
|
||||||
|
public get m12(): number{
|
||||||
|
return this.b;
|
||||||
|
}
|
||||||
|
public set m12(value: number){
|
||||||
|
this.b = value;
|
||||||
|
}
|
||||||
|
public get m21(): number{
|
||||||
|
return this.c;
|
||||||
|
}
|
||||||
|
public set m21(value: number){
|
||||||
|
this.c = value;
|
||||||
|
}
|
||||||
|
public get m22(): number{
|
||||||
|
return this.d;
|
||||||
|
}
|
||||||
|
public set m22(value: number){
|
||||||
|
this.d = value;
|
||||||
|
}
|
||||||
|
public get m31(): number {
|
||||||
|
return this.tx;
|
||||||
|
}
|
||||||
|
public set m31(value: number){
|
||||||
|
this.tx = value;
|
||||||
|
}
|
||||||
|
public get m32(): number{
|
||||||
|
return this.ty;
|
||||||
|
}
|
||||||
|
public set m32(value: number){
|
||||||
|
this.ty = value;
|
||||||
|
}
|
||||||
|
|
||||||
constructor(m11?: number, m12?: number, m21?: number, m22?: number, m31?: number, m32?: number){
|
/**
|
||||||
this.m11 = m11 ? m11 : 1;
|
* 从对象池中取出或创建一个新的Matrix对象。
|
||||||
this.m12 = m12 ? m12 : 0;
|
*/
|
||||||
|
public static create(): Matrix2D{
|
||||||
|
let matrix = matrixPool.pop();
|
||||||
|
if (!matrix)
|
||||||
|
matrix = new Matrix2D();
|
||||||
|
return matrix;
|
||||||
|
}
|
||||||
|
|
||||||
this.m21 = m21 ? m21 : 0;
|
public identity(): Matrix2D{
|
||||||
this.m22 = m22 ? m22 : 1;
|
this.a = this.d = 1;
|
||||||
|
this.b = this.c = this.tx = this.ty = 0;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
this.m31 = m31 ? m31 : 0;
|
public translate(dx: number, dy: number): Matrix2D {
|
||||||
this.m32 = m32 ? m32 : 0;
|
this.tx += dx;
|
||||||
}
|
this.ty += dy;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
/** 存储在这个矩阵中的位置 */
|
public scale(sx: number, sy: number): Matrix2D {
|
||||||
public get translation(){
|
if (sx !== 1){
|
||||||
return new Vector2(this.m31, this.m32);
|
this.a *= sx;
|
||||||
}
|
this.c *= sx;
|
||||||
|
this.tx *= sx;
|
||||||
|
}
|
||||||
|
if (sy !== 1){
|
||||||
|
this.b *= sy;
|
||||||
|
this.d *= sy;
|
||||||
|
this.ty *= sy;
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
public set translation(value: Vector2){
|
public rotate(angle: number): Matrix2D {
|
||||||
this.m31 = value.x;
|
angle = +angle;
|
||||||
this.m32 = value.y;
|
if (angle !== 0) {
|
||||||
}
|
angle = angle / DEG_TO_RAD;
|
||||||
|
let u = Math.cos(angle);
|
||||||
|
let v = Math.sin(angle);
|
||||||
|
let ta = this.a;
|
||||||
|
let tb = this.b;
|
||||||
|
let tc = this.c;
|
||||||
|
let td = this.d;
|
||||||
|
let ttx = this.tx;
|
||||||
|
let tty = this.ty;
|
||||||
|
this.a = ta * u - tb * v;
|
||||||
|
this.b = ta * v + tb * u;
|
||||||
|
this.c = tc * u - td * v;
|
||||||
|
this.d = tc * v + td * u;
|
||||||
|
this.tx = ttx * u - tty * v;
|
||||||
|
this.ty = ttx * v + tty * u;
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
/** 以弧度表示的旋转存储在这个矩阵中 */
|
public invert(): Matrix2D {
|
||||||
public get rotation(){
|
this.$invertInto(this);
|
||||||
return Math.atan2(this.m21, this.m11);
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public set rotation(value: number){
|
/**
|
||||||
let val1 = Math.cos(value);
|
* 创建一个新的matrix, 它包含两个矩阵的和。
|
||||||
let val2 = Math.sin(value);
|
* @param matrix
|
||||||
|
*/
|
||||||
|
public add(matrix: Matrix2D): Matrix2D{
|
||||||
|
this.m11 += matrix.m11;
|
||||||
|
this.m12 += matrix.m12;
|
||||||
|
|
||||||
this.m11 = val1;
|
this.m21 += matrix.m21;
|
||||||
this.m12 = val2;
|
this.m22 += matrix.m22;
|
||||||
this.m21 = -val2;
|
|
||||||
this.m22 = val1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
this.m31 += matrix.m31;
|
||||||
* 以度为单位的旋转存储在这个矩阵中
|
this.m32 += matrix.m32;
|
||||||
*/
|
|
||||||
public get rotationDegrees(){
|
|
||||||
return MathHelper.toDegrees(this.rotation);
|
|
||||||
}
|
|
||||||
|
|
||||||
public set rotationDegrees(value: number){
|
return this;
|
||||||
this.rotation = MathHelper.toRadians(value);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public get scale(){
|
public substract(matrix: Matrix2D): Matrix2D {
|
||||||
return new Vector2(this.m11, this.m22);
|
this.m11 -= matrix.m11;
|
||||||
}
|
this.m12 -= matrix.m12;
|
||||||
|
|
||||||
public set scale(value: Vector2){
|
this.m21 -= matrix.m21;
|
||||||
this.m11 = value.x;
|
this.m22 -= matrix.m22;
|
||||||
this.m12 = value.y;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
this.m31 -= matrix.m31;
|
||||||
* 创建一个新的matrix, 它包含两个矩阵的和。
|
this.m32 -= matrix.m32;
|
||||||
* @param matrix1
|
|
||||||
* @param matrix2
|
|
||||||
*/
|
|
||||||
public static add(matrix1: Matrix2D, matrix2: Matrix2D){
|
|
||||||
matrix1.m11 += matrix2.m11;
|
|
||||||
matrix1.m12 += matrix2.m12;
|
|
||||||
|
|
||||||
matrix1.m21 += matrix2.m21;
|
return this;
|
||||||
matrix1.m22 += matrix2.m22;
|
}
|
||||||
|
|
||||||
matrix1.m31 += matrix2.m31;
|
public divide(matrix: Matrix2D): Matrix2D{
|
||||||
matrix1.m32 += matrix2.m32;
|
this.m11 /= matrix.m11;
|
||||||
|
this.m12 /= matrix.m12;
|
||||||
|
|
||||||
return matrix1;
|
this.m21 /= matrix.m21;
|
||||||
}
|
this.m22 /= matrix.m22;
|
||||||
|
|
||||||
public static divide(matrix1: Matrix2D, matrix2: Matrix2D){
|
this.m31 /= matrix.m31;
|
||||||
matrix1.m11 /= matrix2.m11;
|
this.m32 /= matrix.m32;
|
||||||
matrix1.m12 /= matrix2.m12;
|
|
||||||
|
|
||||||
matrix1.m21 /= matrix2.m21;
|
return this;
|
||||||
matrix1.m22 /= matrix2.m22;
|
}
|
||||||
|
|
||||||
matrix1.m31 /= matrix2.m31;
|
public multiply(matrix: Matrix2D): Matrix2D{
|
||||||
matrix1.m32 /= matrix2.m32;
|
let m11 = ( this.m11 * matrix.m11 ) + ( this.m12 * matrix.m21 );
|
||||||
|
let m12 = ( this.m11 * matrix.m12 ) + ( this.m12 * matrix.m22 );
|
||||||
|
|
||||||
return matrix1;
|
let m21 = ( this.m21 * matrix.m11 ) + ( this.m22 * matrix.m21 );
|
||||||
}
|
let m22 = ( this.m21 * matrix.m12 ) + ( this.m22 * matrix.m22 );
|
||||||
|
|
||||||
public static multiply(matrix1: Matrix2D, matrix2: Matrix2D){
|
let m31 = ( this.m31 * matrix.m11 ) + ( this.m32 * matrix.m21 ) + matrix.m31;
|
||||||
let result = new Matrix2D();
|
let m32 = ( this.m31 * matrix.m12 ) + ( this.m32 * matrix.m22 ) + matrix.m32;
|
||||||
|
|
||||||
let m11 = ( matrix1.m11 * matrix2.m11 ) + ( matrix1.m12 * matrix2.m21 );
|
this.m11 = m11;
|
||||||
let m12 = ( matrix1.m11 * matrix2.m12 ) + ( matrix1.m12 * matrix2.m22 );
|
this.m12 = m12;
|
||||||
|
|
||||||
let m21 = ( matrix1.m21 * matrix2.m11 ) + ( matrix1.m22 * matrix2.m21 );
|
this.m21 = m21;
|
||||||
let m22 = ( matrix1.m21 * matrix2.m12 ) + ( matrix1.m22 * matrix2.m22 );
|
this.m22 = m22;
|
||||||
|
|
||||||
let m31 = ( matrix1.m31 * matrix2.m11 ) + ( matrix1.m32 * matrix2.m21 ) + matrix2.m31;
|
this.m31 = m31;
|
||||||
let m32 = ( matrix1.m31 * matrix2.m12 ) + ( matrix1.m32 * matrix2.m22 ) + matrix2.m32;
|
this.m32 = m32;
|
||||||
|
|
||||||
result.m11 = m11;
|
return this;
|
||||||
result.m12 = m12;
|
}
|
||||||
|
|
||||||
result.m21 = m21;
|
public determinant(){
|
||||||
result.m22 = m22;
|
return this.m11 * this.m22 - this.m12 * this.m21;
|
||||||
|
}
|
||||||
|
|
||||||
result.m31 = m31;
|
public release(matrix: Matrix2D) {
|
||||||
result.m32 = m32;
|
if (!matrix)
|
||||||
|
return;
|
||||||
return result;
|
matrixPool.push(matrix);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static multiplyTranslation(matrix: Matrix2D, x: number, y: number){
|
|
||||||
let trans = Matrix2D.createTranslation(x, y);
|
|
||||||
return Matrix2D.multiply(matrix, trans);
|
|
||||||
}
|
|
||||||
|
|
||||||
public determinant(){
|
|
||||||
return this.m11 * this.m22 - this.m12 * this.m21;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static invert(matrix: Matrix2D, result: Matrix2D = new Matrix2D()){
|
|
||||||
let det = 1 / matrix.determinant();
|
|
||||||
|
|
||||||
result.m11 = matrix.m22 * det;
|
|
||||||
result.m12 = -matrix.m12 * det;
|
|
||||||
|
|
||||||
result.m21 = -matrix.m21 * det;
|
|
||||||
result.m22 = matrix.m11 * det;
|
|
||||||
|
|
||||||
result.m31 = (matrix.m32 * matrix.m21 - matrix.m31 * matrix.m22) * det;
|
|
||||||
result.m32 = -(matrix.m32 * matrix.m11 - matrix.m31 * matrix.m12) * det;
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 创建一个新的tranlation
|
|
||||||
* @param xPosition
|
|
||||||
* @param yPosition
|
|
||||||
*/
|
|
||||||
public static createTranslation(xPosition: number, yPosition: number){
|
|
||||||
let result = new Matrix2D();
|
|
||||||
|
|
||||||
result.m11 = 1;
|
|
||||||
result.m12 = 0;
|
|
||||||
|
|
||||||
result.m21 = 0;
|
|
||||||
result.m22 = 1;
|
|
||||||
|
|
||||||
result.m31 = xPosition;
|
|
||||||
result.m32 = yPosition;
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 根据position 创建一个translation
|
|
||||||
* @param position
|
|
||||||
*/
|
|
||||||
public static createTranslationVector(position: Vector2){
|
|
||||||
return this.createTranslation(position.x, position.y);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static createRotation(radians: number, result?: Matrix2D){
|
|
||||||
result = new Matrix2D();
|
|
||||||
|
|
||||||
let val1 = Math.cos(radians);
|
|
||||||
let val2 = Math.sin(radians);
|
|
||||||
|
|
||||||
result.m11 = val1;
|
|
||||||
result.m12 = val2;
|
|
||||||
result.m21 = -val2;
|
|
||||||
result.m22 = val1;
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static createScale(xScale: number, yScale: number, result: Matrix2D = new Matrix2D()){
|
|
||||||
result.m11 = xScale;
|
|
||||||
result.m12 = 0;
|
|
||||||
|
|
||||||
result.m21 = 0;
|
|
||||||
result.m22 = yScale;
|
|
||||||
|
|
||||||
result.m31 = 0;
|
|
||||||
result.m32 = 0;
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public toEgretMatrix(): egret.Matrix{
|
|
||||||
let matrix = new egret.Matrix(this.m11, this.m12, this.m21, this.m22, this.m31, this.m32);
|
|
||||||
return matrix;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+155
-133
@@ -1,164 +1,186 @@
|
|||||||
class Rectangle extends egret.Rectangle {
|
module es {
|
||||||
/**
|
export class Rectangle extends egret.Rectangle {
|
||||||
* 获取矩形的最大点,即右下角
|
/**
|
||||||
*/
|
* 获取矩形的最大点,即右下角
|
||||||
public get max() {
|
*/
|
||||||
return new Vector2(this.right, this.bottom);
|
public get max() {
|
||||||
}
|
return new Vector2(this.right, this.bottom);
|
||||||
|
}
|
||||||
|
|
||||||
/** 中心点坐标 */
|
/** 中心点坐标 */
|
||||||
public get center() {
|
public get center() {
|
||||||
return new Vector2(this.x + (this.width / 2), this.y + (this.height / 2));
|
return new Vector2(this.x + (this.width / 2), this.y + (this.height / 2));
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 左上角的坐标 */
|
/** 左上角的坐标 */
|
||||||
public get location() {
|
public get location() {
|
||||||
return new Vector2(this.x, this.y);
|
return new Vector2(this.x, this.y);
|
||||||
}
|
}
|
||||||
/** 左上角的坐标 */
|
/** 左上角的坐标 */
|
||||||
public set location(value: Vector2) {
|
public set location(value: Vector2) {
|
||||||
this.x = value.x;
|
this.x = value.x;
|
||||||
this.y = value.y;
|
this.y = value.y;
|
||||||
}
|
}
|
||||||
|
|
||||||
public get size() {
|
public get size() {
|
||||||
return new Vector2(this.width, this.height);
|
return new Vector2(this.width, this.height);
|
||||||
}
|
}
|
||||||
|
|
||||||
public set size(value: Vector2) {
|
public set size(value: Vector2) {
|
||||||
this.width = value.x;
|
this.width = value.x;
|
||||||
this.height = value.y;
|
this.height = value.y;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 是否与另一个矩形相交
|
* 是否与另一个矩形相交
|
||||||
* @param value
|
* @param value
|
||||||
*/
|
*/
|
||||||
public intersects(value: egret.Rectangle) {
|
public intersects(value: egret.Rectangle) {
|
||||||
return value.left < this.right &&
|
return value.left < this.right &&
|
||||||
this.left < value.right &&
|
this.left < value.right &&
|
||||||
value.top < this.bottom &&
|
value.top < this.bottom &&
|
||||||
this.top < value.bottom;
|
this.top < value.bottom;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取所提供的矩形是否在此矩形的边界内
|
* 获取所提供的矩形是否在此矩形的边界内
|
||||||
* @param value
|
* @param value
|
||||||
*/
|
*/
|
||||||
public containsRect(value: Rectangle) {
|
public containsRect(value: Rectangle) {
|
||||||
return ((((this.x <= value.x) && (value.x < (this.x + this.width))) &&
|
return ((((this.x <= value.x) && (value.x < (this.x + this.width))) &&
|
||||||
(this.y <= value.y)) &&
|
(this.y <= value.y)) &&
|
||||||
(value.y < (this.y + this.height)));
|
(value.y < (this.y + this.height)));
|
||||||
}
|
}
|
||||||
|
|
||||||
public getHalfSize() {
|
public getHalfSize() {
|
||||||
return new Vector2(this.width * 0.5, this.height * 0.5);
|
return new Vector2(this.width * 0.5, this.height * 0.5);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 创建一个矩形的最小/最大点(左上角,右下角的点)
|
* 创建一个矩形的最小/最大点(左上角,右下角的点)
|
||||||
* @param minX
|
* @param minX
|
||||||
* @param minY
|
* @param minY
|
||||||
* @param maxX
|
* @param maxX
|
||||||
* @param maxY
|
* @param maxY
|
||||||
*/
|
*/
|
||||||
public static fromMinMax(minX: number, minY: number, maxX: number, maxY: number) {
|
public static fromMinMax(minX: number, minY: number, maxX: number, maxY: number) {
|
||||||
return new Rectangle(minX, minY, maxX - minX, maxY - minY);
|
return new Rectangle(minX, minY, maxX - minX, maxY - minY);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取矩形边界上与给定点最近的点
|
* 获取矩形边界上与给定点最近的点
|
||||||
* @param point
|
* @param point
|
||||||
*/
|
* @param edgeNormal
|
||||||
public getClosestPointOnRectangleBorderToPoint(point: Vector2): { res: Vector2, edgeNormal: Vector2 } {
|
*/
|
||||||
let edgeNormal = Vector2.zero;
|
public getClosestPointOnRectangleBorderToPoint(point: Vector2, edgeNormal: Vector2): Vector2 {
|
||||||
|
edgeNormal = Vector2.zero;
|
||||||
|
|
||||||
// 对于每个轴,如果点在盒子外面
|
// 对于每个轴,如果点在盒子外面
|
||||||
let res = new Vector2();
|
let res = new Vector2();
|
||||||
res.x = MathHelper.clamp(point.x, this.left, this.right);
|
res.x = MathHelper.clamp(point.x, this.left, this.right);
|
||||||
res.y = MathHelper.clamp(point.y, this.top, this.bottom);
|
res.y = MathHelper.clamp(point.y, this.top, this.bottom);
|
||||||
|
|
||||||
// 如果点在矩形内,我们需要推res到边界,因为它将在矩形内
|
// 如果点在矩形内,我们需要推res到边界,因为它将在矩形内
|
||||||
if (this.contains(res.x, res.y)) {
|
if (this.contains(res.x, res.y)) {
|
||||||
let dl = res.x - this.left;
|
let dl = res.x - this.left;
|
||||||
let dr = this.right - res.x;
|
let dr = this.right - res.x;
|
||||||
let dt = res.y - this.top;
|
let dt = res.y - this.top;
|
||||||
let db = this.bottom - res.y;
|
let db = this.bottom - res.y;
|
||||||
|
|
||||||
let min = Math.min(dl, dr, dt, db);
|
let min = Math.min(dl, dr, dt, db);
|
||||||
if (min == dt) {
|
if (min == dt) {
|
||||||
res.y = this.top;
|
res.y = this.top;
|
||||||
edgeNormal.y = -1;
|
edgeNormal.y = -1;
|
||||||
} else if (min == db) {
|
} else if (min == db) {
|
||||||
res.y = this.bottom;
|
res.y = this.bottom;
|
||||||
edgeNormal.y = 1;
|
edgeNormal.y = 1;
|
||||||
} else if (min == dl) {
|
} else if (min == dl) {
|
||||||
res.x = this.left;
|
res.x = this.left;
|
||||||
edgeNormal.x = -1;
|
edgeNormal.x = -1;
|
||||||
|
} else {
|
||||||
|
res.x = this.right;
|
||||||
|
edgeNormal.x = 1;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
res.x = this.right;
|
if (res.x == this.left) edgeNormal.x = -1;
|
||||||
edgeNormal.x = 1;
|
if (res.x == this.right) edgeNormal.x = 1;
|
||||||
|
if (res.y == this.top) edgeNormal.y = -1;
|
||||||
|
if (res.y == this.bottom) edgeNormal.y = 1;
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
if (res.x == this.left) edgeNormal.x = -1;
|
return res;
|
||||||
if (res.x == this.right) edgeNormal.x = 1;
|
|
||||||
if (res.y == this.top) edgeNormal.y = -1;
|
|
||||||
if (res.y == this.bottom) edgeNormal.y = 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return { res: res, edgeNormal: edgeNormal };
|
/**
|
||||||
}
|
*
|
||||||
|
*/
|
||||||
|
public getClosestPointOnBoundsToOrigin() {
|
||||||
|
let max = this.max;
|
||||||
|
let minDist = Math.abs(this.location.x);
|
||||||
|
let boundsPoint = new Vector2(this.location.x, 0);
|
||||||
|
|
||||||
/**
|
if (Math.abs(max.x) < minDist) {
|
||||||
*
|
minDist = Math.abs(max.x);
|
||||||
*/
|
boundsPoint.x = max.x;
|
||||||
public getClosestPointOnBoundsToOrigin() {
|
boundsPoint.y = 0;
|
||||||
let max = this.max;
|
}
|
||||||
let minDist = Math.abs(this.location.x);
|
|
||||||
let boundsPoint = new Vector2(this.location.x, 0);
|
|
||||||
|
|
||||||
if (Math.abs(max.x) < minDist) {
|
if (Math.abs(max.y) < minDist) {
|
||||||
minDist = Math.abs(max.x);
|
minDist = Math.abs(max.y);
|
||||||
boundsPoint.x = max.x;
|
boundsPoint.x = 0;
|
||||||
boundsPoint.y = 0;
|
boundsPoint.y = max.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Math.abs(this.location.y) < minDist) {
|
||||||
|
minDist = Math.abs(this.location.y);
|
||||||
|
boundsPoint.x = 0;
|
||||||
|
boundsPoint.y = this.location.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
return boundsPoint;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Math.abs(max.y) < minDist) {
|
public calculateBounds(parentPosition: Vector2, position: Vector2, origin: Vector2, scale: Vector2, rotation: number, width: number, height: number){
|
||||||
minDist = Math.abs(max.y);
|
this.x = parentPosition.x + position.x - origin.x * scale.x;
|
||||||
boundsPoint.x = 0;
|
this.y = parentPosition.y + position.y - origin.y * scale.y;
|
||||||
boundsPoint.y = max.y;
|
this.width = width * scale.x;
|
||||||
|
this.height = height * scale.y;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Math.abs(this.location.y) < minDist) {
|
/**
|
||||||
minDist = Math.abs(this.location.y);
|
* 将egret矩形转化为Rectangle
|
||||||
boundsPoint.x = 0;
|
* @param rect
|
||||||
boundsPoint.y = this.location.y;
|
*/
|
||||||
|
public setEgretRect(rect: egret.Rectangle): Rectangle{
|
||||||
|
this.x = rect.x;
|
||||||
|
this.y = rect.y;
|
||||||
|
this.width = rect.width;
|
||||||
|
this.height = rect.height;
|
||||||
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
return boundsPoint;
|
/**
|
||||||
}
|
* 给定多边形的点,计算边界
|
||||||
|
* @param points
|
||||||
|
*/
|
||||||
|
public static rectEncompassingPoints(points: Vector2[]) {
|
||||||
|
// 我们需要求出x/y的最小值/最大值
|
||||||
|
let minX = Number.POSITIVE_INFINITY;
|
||||||
|
let minY = Number.POSITIVE_INFINITY;
|
||||||
|
let maxX = Number.NEGATIVE_INFINITY;
|
||||||
|
let maxY = Number.NEGATIVE_INFINITY;
|
||||||
|
|
||||||
/**
|
for (let i = 0; i < points.length; i++) {
|
||||||
* 给定多边形的点,计算边界
|
let pt = points[i];
|
||||||
* @param points
|
|
||||||
*/
|
|
||||||
public static rectEncompassingPoints(points: Vector2[]) {
|
|
||||||
// 我们需要求出x/y的最小值/最大值
|
|
||||||
let minX = Number.POSITIVE_INFINITY;
|
|
||||||
let minY = Number.POSITIVE_INFINITY;
|
|
||||||
let maxX = Number.NEGATIVE_INFINITY;
|
|
||||||
let maxY = Number.NEGATIVE_INFINITY;
|
|
||||||
|
|
||||||
for (let i = 0; i < points.length; i++) {
|
if (pt.x < minX) minX = pt.x;
|
||||||
let pt = points[i];
|
if (pt.x > maxX) maxX = pt.x;
|
||||||
|
|
||||||
if (pt.x < minX) minX = pt.x;
|
if (pt.y < minY) minY = pt.y;
|
||||||
if (pt.x > maxX) maxX = pt.x;
|
if (pt.y > maxY) maxY = pt.y;
|
||||||
|
}
|
||||||
|
|
||||||
if (pt.y < minY) minY = pt.y;
|
return this.fromMinMax(minX, minY, maxX, maxY);
|
||||||
if (pt.y > maxY) maxY = pt.y;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.fromMinMax(minX, minY, maxX, maxY);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+207
-160
@@ -1,183 +1,230 @@
|
|||||||
/** 2d 向量 */
|
module es {
|
||||||
class Vector2 {
|
/** 2d 向量 */
|
||||||
public x: number = 0;
|
export class Vector2 {
|
||||||
public y: number = 0;
|
public x: number = 0;
|
||||||
|
public y: number = 0;
|
||||||
|
|
||||||
private static readonly unitYVector = new Vector2(0, 1);
|
private static readonly unitYVector = new Vector2(0, 1);
|
||||||
private static readonly unitXVector = new Vector2(1, 0);
|
private static readonly unitXVector = new Vector2(1, 0);
|
||||||
private static readonly unitVector2 = new Vector2(1, 1);
|
private static readonly unitVector2 = new Vector2(1, 1);
|
||||||
private static readonly zeroVector2 = new Vector2(0, 0);
|
private static readonly zeroVector2 = new Vector2(0, 0);
|
||||||
public static get zero(){
|
public static get zero(){
|
||||||
return Vector2.zeroVector2;
|
return Vector2.zeroVector2;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static get one(){
|
public static get one(){
|
||||||
return Vector2.unitVector2;
|
return Vector2.unitVector2;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static get unitX(){
|
public static get unitX(){
|
||||||
return Vector2.unitXVector;
|
return Vector2.unitXVector;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static get unitY(){
|
public static get unitY(){
|
||||||
return Vector2.unitYVector;
|
return Vector2.unitYVector;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 从两个值构造一个带有X和Y的二维向量。
|
* 从两个值构造一个带有X和Y的二维向量。
|
||||||
* @param x 二维空间中的x坐标
|
* @param x 二维空间中的x坐标
|
||||||
* @param y 二维空间的y坐标
|
* @param y 二维空间的y坐标
|
||||||
*/
|
*/
|
||||||
constructor(x? : number, y?: number){
|
constructor(x? : number, y?: number){
|
||||||
this.x = x ? x : 0;
|
this.x = x ? x : 0;
|
||||||
this.y = y ? y : this.x;
|
this.y = y ? y : this.x;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param value1
|
* @param value
|
||||||
* @param value2
|
*/
|
||||||
*/
|
public add(value: Vector2): Vector2{
|
||||||
public static add(value1: Vector2, value2: Vector2){
|
this.x += value.x;
|
||||||
let result: Vector2 = new Vector2(0, 0);
|
this.y += value.y;
|
||||||
result.x = value1.x + value2.x;
|
return this;
|
||||||
result.y = value1.y + value2.y;
|
}
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param value1
|
* @param value
|
||||||
* @param value2
|
*/
|
||||||
*/
|
public divide(value: Vector2): Vector2{
|
||||||
public static divide(value1: Vector2, value2: Vector2){
|
this.x /= value.x;
|
||||||
let result: Vector2 = new Vector2(0, 0);
|
this.y /= value.y;
|
||||||
result.x = value1.x / value2.x;
|
return this;
|
||||||
result.y = value1.y / value2.y;
|
}
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param value1
|
* @param value
|
||||||
* @param value2
|
*/
|
||||||
*/
|
public multiply(value: Vector2): Vector2{
|
||||||
public static multiply(value1: Vector2, value2: Vector2){
|
this.x *= value.x;
|
||||||
let result: Vector2 = new Vector2(0, 0);
|
this.y *= value.y;
|
||||||
result.x = value1.x * value2.x;
|
return this;
|
||||||
result.y = value1.y * value2.y;
|
}
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param value1
|
* @param value
|
||||||
* @param value2
|
*/
|
||||||
*/
|
public subtract(value: Vector2){
|
||||||
public static subtract(value1: Vector2, value2: Vector2){
|
this.x -= value.x;
|
||||||
let result: Vector2 = new Vector2(0, 0);
|
this.y -= value.y;
|
||||||
result.x = value1.x - value2.x;
|
return this;
|
||||||
result.y = value1.y - value2.y;
|
}
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 变成一个方向相同的单位向量 */
|
/**
|
||||||
public normalize(){
|
*
|
||||||
let val = 1 / Math.sqrt((this.x * this.x) + (this.y * this.y));
|
* @param value1
|
||||||
this.x *= val;
|
* @param value2
|
||||||
this.y *= val;
|
*/
|
||||||
}
|
public static add(value1: Vector2, value2: Vector2){
|
||||||
|
let result: Vector2 = new Vector2(0, 0);
|
||||||
|
result.x = value1.x + value2.x;
|
||||||
|
result.y = value1.y + value2.y;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
/** 返回它的长度 */
|
/**
|
||||||
public length(){
|
*
|
||||||
return Math.sqrt((this.x * this.x) + (this.y * this.y));
|
* @param value1
|
||||||
}
|
* @param value2
|
||||||
|
*/
|
||||||
|
public static divide(value1: Vector2, value2: Vector2){
|
||||||
|
let result: Vector2 = new Vector2(0, 0);
|
||||||
|
result.x = value1.x / value2.x;
|
||||||
|
result.y = value1.y / value2.y;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
/** 对x和y值四舍五入 */
|
/**
|
||||||
public round(): Vector2{
|
*
|
||||||
return new Vector2(Math.round(this.x), Math.round(this.y));
|
* @param value1
|
||||||
}
|
* @param value2
|
||||||
|
*/
|
||||||
|
public static multiply(value1: Vector2, value2: Vector2){
|
||||||
|
let result: Vector2 = new Vector2(0, 0);
|
||||||
|
result.x = value1.x * value2.x;
|
||||||
|
result.y = value1.y * value2.y;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 创建一个新的Vector2
|
*
|
||||||
* 它包含来自另一个向量的标准化值。
|
* @param value1
|
||||||
* @param value
|
* @param value2
|
||||||
*/
|
*/
|
||||||
public static normalize(value: Vector2){
|
public static subtract(value1: Vector2, value2: Vector2){
|
||||||
let val = 1 / Math.sqrt((value.x * value.x) + (value.y * value.y));
|
let result: Vector2 = new Vector2(0, 0);
|
||||||
value.x *= val;
|
result.x = value1.x - value2.x;
|
||||||
value.y *= val;
|
result.y = value1.y - value2.y;
|
||||||
return value;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** 变成一个方向相同的单位向量 */
|
||||||
* 返回两个向量的点积
|
public normalize(){
|
||||||
* @param value1
|
let val = 1 / Math.sqrt((this.x * this.x) + (this.y * this.y));
|
||||||
* @param value2
|
this.x *= val;
|
||||||
*/
|
this.y *= val;
|
||||||
public static dot(value1: Vector2, value2: Vector2): number{
|
}
|
||||||
return (value1.x * value2.x) + (value1.y * value2.y);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/** 返回它的长度 */
|
||||||
* 返回两个向量之间距离的平方
|
public length(){
|
||||||
* @param value1
|
return Math.sqrt((this.x * this.x) + (this.y * this.y));
|
||||||
* @param value2
|
}
|
||||||
*/
|
|
||||||
public static distanceSquared(value1: Vector2, value2: Vector2){
|
|
||||||
let v1 = value1.x - value2.x, v2 = value1.y - value2.y;
|
|
||||||
return (v1 * v1) + (v2 * v2);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/** 对x和y值四舍五入 */
|
||||||
*
|
public round(): Vector2{
|
||||||
* @param value1
|
return new Vector2(Math.round(this.x), Math.round(this.y));
|
||||||
* @param min
|
}
|
||||||
* @param max
|
|
||||||
*/
|
|
||||||
public static clamp(value1: Vector2, min: Vector2, max: Vector2){
|
|
||||||
return new Vector2(MathHelper.clamp(value1.x, min.x, max.x),
|
|
||||||
MathHelper.clamp(value1.y, min.y, max.y));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 包含指定向量的线性插值
|
* 创建一个新的Vector2
|
||||||
* @param value1 第一个向量
|
* 它包含来自另一个向量的标准化值。
|
||||||
* @param value2 第二个向量
|
* @param value
|
||||||
* @param amount 权重值(0.0到1.0之间)
|
*/
|
||||||
*/
|
public static normalize(value: Vector2){
|
||||||
public static lerp(value1: Vector2, value2: Vector2, amount: number){
|
let val = 1 / Math.sqrt((value.x * value.x) + (value.y * value.y));
|
||||||
return new Vector2(MathHelper.lerp(value1.x, value2.x, amount), MathHelper.lerp(value1.y, value2.y, amount));
|
value.x *= val;
|
||||||
}
|
value.y *= val;
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
* 返回两个向量的点积
|
||||||
* @param position
|
* @param value1
|
||||||
* @param matrix
|
* @param value2
|
||||||
*/
|
*/
|
||||||
public static transform(position: Vector2, matrix: Matrix2D){
|
public static dot(value1: Vector2, value2: Vector2): number{
|
||||||
return new Vector2((position.x * matrix.m11) + (position.y * matrix.m21), (position.x * matrix.m12) + (position.y * matrix.m22));
|
return (value1.x * value2.x) + (value1.y * value2.y);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 返回两个向量之间的距离
|
* 返回两个向量之间距离的平方
|
||||||
* @param value1
|
* @param value1
|
||||||
* @param value2
|
* @param value2
|
||||||
*/
|
*/
|
||||||
public static distance(value1: Vector2, value2: Vector2){
|
public static distanceSquared(value1: Vector2, value2: Vector2){
|
||||||
let v1 = value1.x - value2.x, v2 = value1.y - value2.y;
|
let v1 = value1.x - value2.x, v2 = value1.y - value2.y;
|
||||||
return Math.sqrt((v1 * v1) + (v2 * v2));
|
return (v1 * v1) + (v2 * v2);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 矢量反演的结果
|
*
|
||||||
* @param value
|
* @param value1
|
||||||
*/
|
* @param min
|
||||||
public static negate(value: Vector2){
|
* @param max
|
||||||
let result: Vector2 = new Vector2();
|
*/
|
||||||
result.x = -value.x;
|
public static clamp(value1: Vector2, min: Vector2, max: Vector2){
|
||||||
result.y = -value.y;
|
return new Vector2(MathHelper.clamp(value1.x, min.x, max.x),
|
||||||
|
MathHelper.clamp(value1.y, min.y, max.y));
|
||||||
|
}
|
||||||
|
|
||||||
return result;
|
/**
|
||||||
|
* 包含指定向量的线性插值
|
||||||
|
* @param value1 第一个向量
|
||||||
|
* @param value2 第二个向量
|
||||||
|
* @param amount 权重值(0.0到1.0之间)
|
||||||
|
*/
|
||||||
|
public static lerp(value1: Vector2, value2: Vector2, amount: number){
|
||||||
|
return new Vector2(MathHelper.lerp(value1.x, value2.x, amount), MathHelper.lerp(value1.y, value2.y, amount));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param position
|
||||||
|
* @param matrix
|
||||||
|
*/
|
||||||
|
public static transform(position: Vector2, matrix: Matrix2D){
|
||||||
|
return new Vector2((position.x * matrix.m11) + (position.y * matrix.m21) + matrix.m31,
|
||||||
|
(position.x * matrix.m12) + (position.y * matrix.m22) + matrix.m32);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 返回两个向量之间的距离
|
||||||
|
* @param value1
|
||||||
|
* @param value2
|
||||||
|
*/
|
||||||
|
public static distance(value1: Vector2, value2: Vector2){
|
||||||
|
let v1 = value1.x - value2.x, v2 = value1.y - value2.y;
|
||||||
|
return Math.sqrt((v1 * v1) + (v2 * v2));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 矢量反演的结果
|
||||||
|
* @param value
|
||||||
|
*/
|
||||||
|
public static negate(value: Vector2){
|
||||||
|
let result: Vector2 = new Vector2();
|
||||||
|
result.x = -value.x;
|
||||||
|
result.y = -value.y;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public equals(other: Vector2){
|
||||||
|
return other.x == this.x && other.y == this.y;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,11 +1,13 @@
|
|||||||
class Vector3 {
|
module es {
|
||||||
public x: number;
|
export class Vector3 {
|
||||||
public y: number;
|
public x: number;
|
||||||
public z: number;
|
public y: number;
|
||||||
|
public z: number;
|
||||||
|
|
||||||
constructor(x: number, y: number, z: number){
|
constructor(x: number, y: number, z: number){
|
||||||
this.x = x;
|
this.x = x;
|
||||||
this.y = y;
|
this.y = y;
|
||||||
this.z = z;
|
this.z = z;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user