Merge pull request #13 from esengine/develop_collider

整理ecs框架
This commit is contained in:
YHH
2020-07-28 11:08:46 +08:00
committed by GitHub
123 changed files with 25567 additions and 19739 deletions
+2
View File
@@ -1,3 +1,5 @@
/source/node_modules /source/node_modules
/demo/bin-debug /demo/bin-debug
/demo/bin-release /demo/bin-release
/.idea
/.vscode
-15
View File
@@ -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}"
}
]
}
+2
View File
@@ -0,0 +1,2 @@
# Default ignored files
/workspace.xml
+8
View File
@@ -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>
+6
View File
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="JavaScriptSettings">
<option name="languageLevel" value="ES6" />
</component>
</project>
+8
View File
@@ -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>
+6
View File
@@ -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>
+1479 -1134
View File
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
+1 -2
View File
@@ -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
View File
@@ -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");
// });
} }
} }
-3
View File
@@ -1,3 +0,0 @@
enum CoreEmitterType {
Update,
}
+71 -76
View File
@@ -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);
}
} }
} }
+54 -44
View File
@@ -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));
} }
} }
} }
+6 -2
View File
@@ -1,5 +1,9 @@
class SimplePooled extends PooledComponent { module component {
public reset(){ import PooledComponent = es.PooledComponent;
export class SimplePooled extends PooledComponent {
public reset(){
}
} }
} }
+32 -30
View File
@@ -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
}
+30 -28
View File
@@ -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;
}
} }
} }
} }
+1
View File
@@ -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": [
+1479 -1134
View File
File diff suppressed because it is too large Load Diff
+6762 -5364
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
File diff suppressed because one or more lines are too long
+122
View File
@@ -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 HashSetweightedNodes
*/
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 HashSetweightedNodes
*/ */
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);
}
} }
+21 -19
View File
@@ -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);
}
} }
+209 -207
View File
@@ -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的行为
* undefinedundefined * 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;
/**
*
* undefinedundefined
* 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的优先级高于lowertruefalse
* 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的优先级高于lowertruefalse
* 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
View File
@@ -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);
}
} }
} }
} }
+5 -3
View File
@@ -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;
}
} }
+42 -39
View File
@@ -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
View File
@@ -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
View File
@@ -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); /**
} * -11minimumZoom转换为maximumZoom
* /使-11
*/
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; * -11minimumZoom转换为maximumZoom
else if(this._worldSpaceDeadZone.x < targetX) * /使-11
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.max0.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.max0.3
* @param value
*/
public set minimumZoom(value: number) {
this.setMinimumZoom(value);
}
/**
* 0-number.max3
*/
public get maximumZoom() {
return this._maximumZoom;
}
/**
* 0-number.max3
* @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;
}
/**
* -11minimumZoom转换为maximumZoom
* /使-11
* @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,
}
+19 -17
View File
@@ -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;
}
}
}
+15 -23
View File
@@ -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);
}
} }
+70 -74
View File
@@ -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;
} }
} }
+5 -3
View File
@@ -1,4 +1,6 @@
/** 回收实例的组件类型。 */ module es {
abstract class PooledComponent extends Component { /** 回收实例的组件类型。 */
public abstract reset(); export abstract class PooledComponent extends Component {
public abstract reset();
}
} }
+173 -40
View File
@@ -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;
} }
} }
+21 -19
View File
@@ -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;
}
} }
} }
+8 -6
View File
@@ -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;
}
} }
} }
+132 -114
View File
@@ -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,
}
+118 -50
View File
@@ -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;
} }
} }
+230
View File
@@ -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;
}
}
}
+15 -3
View File
@@ -1,4 +1,16 @@
enum CoreEvents{ module es {
/** 当场景发生变化时触发 */ export enum CoreEvents{
SceneChanged, /**
* VRAM将被擦除
*/
GraphicsDeviceReset,
/**
*
*/
SceneChanged,
/**
*
*/
OrientationChanged,
}
} }
+391 -193
View File
@@ -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方法的频率12
} */
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); /**
} * destroytrue
*/
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
View File
@@ -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;
}
/**
* unloadPostProcessorunload来释放资源
* @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>();
}
} }
} }
-131
View File
@@ -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));
}
} }
} }
+56 -54
View File
@@ -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(){
}
} }
} }
+9 -7
View File
@@ -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();
}
} }
} }
+13 -11
View File
@@ -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();
} }
+504
View File
@@ -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
View File
@@ -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);
}
} }
} }
} }
+221 -174
View File
@@ -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();
} }
} }
} }
+15 -13
View File
@@ -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
View File
@@ -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;
} }
} }
} }
+66 -64
View File
@@ -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;
}
} }
} }
+51 -49
View File
@@ -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;
}
} }
} }
+94 -15
View File
@@ -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;
}
}
} }
} }
+134 -132
View File
@@ -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);
} }
} }
} }
+33 -31
View File
@@ -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
View File
@@ -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);
}
} }
} }
+25 -21
View File
@@ -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;
} }
} }
+16 -6
View File
@@ -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);
}
} }
} }
} }
+46 -6
View File
@@ -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(){
}
} }
} }
+53 -28
View File
@@ -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); }
} }
} }
+45 -29
View File
@@ -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
View File
@@ -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
View File
@@ -1,62 +1,64 @@
/** module es {
*
* isFlagSet之外flag参数是一个非移位的标志
* 使(0123)/
*/
class Flags {
/** /**
* *
* * isFlagSet之外flag参数是一个非移位的标志
* @param self * 使(0123)/
* @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;
}
} }
} }
+65 -63
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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.01.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.01.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;
}
} }
} }
+10 -8
View File
@@ -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