全部移动至es模块

This commit is contained in:
yhh
2020-07-23 11:00:46 +08:00
parent 814234ca61
commit 1b52bc5fd1
71 changed files with 19273 additions and 16907 deletions
+1410 -1132
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
+1410 -1132
View File
File diff suppressed because it is too large Load Diff
+6137 -5356
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 (SceneManager.scene){
SceneManager.scene.addChild(debugShape); SceneManager.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;
}
} }
} }
+5 -3
View File
@@ -1,4 +1,6 @@
enum CoreEvents{ module es {
/** 当场景发生变化时触发 */ export enum CoreEvents{
SceneChanged, /** 当场景发生变化时触发 */
SceneChanged,
}
} }
+1 -1
View File
@@ -36,7 +36,7 @@ module es {
*/ */
public static createWithDefaultRenderer(){ public static createWithDefaultRenderer(){
let scene = new Scene(); let scene = new Scene();
scene.addRenderer(new DefaultRenderer()) scene.addRenderer(new DefaultRenderer());
return scene; return scene;
} }
+126 -124
View File
@@ -1,144 +1,146 @@
/** 运行时的场景管理。 */ module es {
class SceneManager { /** 运行时的场景管理。 */
private static _scene: Scene; export class SceneManager {
private static _nextScene: Scene; private static _scene: Scene;
public static sceneTransition: SceneTransition; private static _nextScene: Scene;
public static stage: egret.Stage; public static sceneTransition: SceneTransition;
/** 订阅此事件以在活动场景发生更改时得到通知。 */ public static stage: egret.Stage;
public static activeSceneChanged: Function; /** 订阅此事件以在活动场景发生更改时得到通知。 */
/** 核心发射器。只发出核心级别的事件 */ public static activeSceneChanged: Function;
public static emitter: Emitter<CoreEvents>; /** 核心发射器。只发出核心级别的事件 */
/** 全局内容管理器加载任何应该停留在场景之间的资产 */ public static emitter: Emitter<CoreEvents>;
public static content: ContentManager; /** 全局内容管理器加载任何应该停留在场景之间的资产 */
/** 简化对内部类的全局内容实例的访问 */ public static content: ContentManager;
private static _instnace: SceneManager; /** 简化对内部类的全局内容实例的访问 */
private static timerRuler: TimeRuler; private static _instnace: SceneManager;
public static get Instance(){ private static timerRuler: TimeRuler;
return this._instnace; 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);
SceneManager.timerRuler = new TimeRuler();
}
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); constructor(stage: egret.Stage) {
} stage.addEventListener(egret.Event.ENTER_FRAME, SceneManager.update, this);
public static initialize(stage: egret.Stage) { SceneManager._instnace = this;
Input.initialize(stage); SceneManager.emitter = new Emitter<CoreEvents>();
} SceneManager.content = new ContentManager();
public static update() { SceneManager.stage = stage;
SceneManager.startDebugUpdate(); SceneManager.initialize(stage);
Time.update(egret.getTimer()); SceneManager.timerRuler = new TimeRuler();
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.endDebugUpdate(); public static get scene() {
SceneManager.render(); return this._scene;
} }
public static set scene(value: Scene) {
if (!value)
throw new Error("场景不能为空");
public static render() { if (this._scene == null) {
if (this.sceneTransition){ this._scene = value;
this.sceneTransition.preRender(); this._scene.begin();
SceneManager.Instance.onSceneChanged();
} else {
this._nextScene = value;
}
if (this._scene && !this.sceneTransition.hasPreviousSceneRender){ this.registerActiveSceneChanged(this._scene, this._nextScene);
this._scene.render(); }
this._scene.postRender();
this.sceneTransition.onBeginTransition(); public static initialize(stage: egret.Stage) {
} else if (this.sceneTransition) { Input.initialize(stage);
if (this._scene && this.sceneTransition.isNewSceneLoaded) { }
this._scene.render();
this._scene.postRender(); public static update() {
SceneManager.startDebugUpdate();
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();
} }
this.sceneTransition.render(); 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();
}
} }
} else if (this._scene) {
this._scene.render();
Debug.render(); SceneManager.endDebugUpdate();
SceneManager.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; public static render() {
return sceneTransition; if (this.sceneTransition){
} this.sceneTransition.preRender();
public static registerActiveSceneChanged(current: Scene, next: Scene){ if (this._scene && !this.sceneTransition.hasPreviousSceneRender){
if (this.activeSceneChanged) this._scene.render();
this.activeSceneChanged(current, next); 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) {
public onSceneChanged(){ this._scene.render();
SceneManager.emitter.emit(CoreEvents.SceneChanged);
Time.sceneChanged();
}
private static startDebugUpdate(){ Debug.render();
TimeRuler.Instance.startFrame();
TimeRuler.Instance.beginMark("update", 0x00FF00);
}
private static endDebugUpdate(){ this._scene.postRender();
TimeRuler.Instance.endMark("update"); }
}
/**
* 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();
}
private static startDebugUpdate(){
TimeRuler.Instance.startFrame();
TimeRuler.Instance.beginMark("update", 0x00FF00);
}
private static endDebugUpdate(){
TimeRuler.Instance.endMark("update");
}
} }
} }
@@ -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();
} }
+1 -1
View File
@@ -160,7 +160,7 @@ module es {
this.updateLists(); this.updateLists();
for (let i = 0; i < this._entities.length; i ++){ for (let i = 0; i < this._entities.length; i ++){
this._entities[i]._isDestoryed = true; this._entities[i]._isDestroyed = true;
this._entities[i].onRemovedFromScene(); this._entities[i].onRemovedFromScene();
this._entities[i].scene = null; this._entities[i].scene = 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;
}
} }
} }
+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 = 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;
} }
//从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);
}
} }
} }
@@ -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: SceneManager.stage.stageWidth,
screenHeight: SceneManager.stage.stageHeight screenHeight: SceneManager.stage.stageHeight
}); });
}
} }
} }
@@ -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);
}
} }
} }
+23 -21
View File
@@ -1,27 +1,29 @@
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){ let capabilities = this;
language = "zh-CN"; capabilities["isMobile"] = true;
} else {
language = "en-US"; 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;
} }
} }
+8 -6
View File
@@ -1,10 +1,12 @@
class GraphicsDevice { module es {
private viewport: Viewport; export class GraphicsDevice {
private viewport: Viewport;
public graphicsCapabilities: GraphicsCapabilities; public graphicsCapabilities: GraphicsCapabilities;
constructor(){ constructor(){
this.graphicsCapabilities = new GraphicsCapabilities(); this.graphicsCapabilities = new GraphicsCapabilities();
this.graphicsCapabilities.initialize(this); this.graphicsCapabilities.initialize(this);
}
} }
} }
@@ -1,58 +1,60 @@
class PostProcessor { module es {
public enabled: 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.enabled = 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, 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);
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,15 @@
///<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; public render(scene: Scene) {
this.beginRender(cam); let cam = this.camera ? this.camera : scene.camera;
this.beginRender(cam);
for (let i = 0; i < scene.renderableComponents.count; i++){ for (let i = 0; i < scene.renderableComponents.count; i++){
let renderable = scene.renderableComponents.buffer[i]; let renderable = scene.renderableComponents.buffer[i];
if (renderable.enabled && renderable.isVisibleFromCamera(cam)) if (renderable.enabled && renderable.isVisibleFromCamera(cam))
this.renderAfterStateCheck(renderable, cam); this.renderAfterStateCheck(renderable, cam);
}
} }
} }
} }
@@ -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(){
}
} }
} }
+30 -28
View File
@@ -1,38 +1,40 @@
/** module es {
* RenderableComponent的实际调用
*/
abstract class Renderer {
/** /**
* () * RenderableComponent的实际调用
*
* Renderer子类可以选择调用beginRender时使用的摄像头
*/ */
public camera: Camera; export abstract class Renderer {
/**
* ()
*
* Renderer子类可以选择调用beginRender时使用的摄像头
*/
public camera: Camera;
/** /**
* *
* @param scene * @param scene
*/ */
public onAddedToScene(scene: Scene){} public onAddedToScene(scene: Scene){}
protected beginRender(cam: Camera){ protected beginRender(cam: Camera){
} }
/** /**
* *
* @param scene * @param scene
*/ */
public abstract render(scene: Scene); public abstract render(scene: Scene);
public unload(){ } public unload(){ }
/** /**
* *
* @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);
}
} }
} }
@@ -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,40 @@
///<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, SceneManager.stage.stageWidth, SceneManager.stage.stageHeight);
this._mask.graphics.endFill(); this._mask.graphics.endFill();
SceneManager.stage.addChild(this._mask); 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); 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, SceneManager.stage.stageWidth, SceneManager.stage.stageHeight);
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() {
SceneManager.sceneTransition = null;
if (this.onTransitionCompleted) {
this.onTransitionCompleted();
}
}
protected async loadNextScene() {
if (this.onScreenObscured)
this.onScreenObscured();
if (!this.loadsNewScene) {
this.isNewSceneLoaded = true;
}
SceneManager.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,67 @@
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, SceneManager.stage.stageWidth, SceneManager.stage.stageHeight);
this._mask.graphics.endFill(); this._mask.graphics.endFill();
this._mask.filters = [this._windEffect]; this._mask.filters = [this._windEffect];
SceneManager.stage.addChild(this._mask); 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); SceneManager.stage.removeChild(this._mask);
}
} }
} }
+31 -29
View File
@@ -1,34 +1,36 @@
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 aspectRatio(){
if ((this._height != 0) && (this._width != 0)) if ((this._height != 0) && (this._width != 0))
return (this._width / this._height); return (this._width / this._height);
return 0; return 0;
} }
public get bounds(){ public get bounds(){
return new Rectangle(this._x, this._y, this._width, this._height); return new Rectangle(this._x, this._y, this._width, this._height);
} }
public set bounds(value: Rectangle){ public set bounds(value: Rectangle){
this._x = value.x; this._x = value.x;
this._y = value.y; this._y = value.y;
this._width = value.width; this._width = value.width;
this._height = value.height; this._height = value.height;
} }
constructor(x: number, y: number, width: number, height: number){ constructor(x: number, y: number, width: number, height: number){
this._x = x; this._x = x;
this._y = y; this._y = y;
this._width = width; this._width = width;
this._height = height; this._height = height;
this._minDepth = 0; this._minDepth = 0;
this._maxDepth = 1; 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);
}
} }
} }
+165 -163
View File
@@ -1,217 +1,219 @@
/** module es {
* 3 * 3
*/
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 {
return Matrix2D._identity; public m11: number = 0;
} public m12: number = 0;
constructor(m11?: number, m12?: number, m21?: number, m22?: number, m31?: number, m32?: number){ public m21: number = 0;
this.m11 = m11 ? m11 : 1; public m22: number = 0;
this.m12 = m12 ? m12 : 0;
this.m21 = m21 ? m21 : 0; public m31: number = 0;
this.m22 = m22 ? m22 : 1; public m32: number = 0;
this.m31 = m31 ? m31 : 0; private static _identity: Matrix2D = new Matrix2D(1, 0, 0, 1, 0, 0);
this.m32 = m32 ? m32 : 0;
}
/** 存储在这个矩阵中的位置 */ /**
public get translation(){ *
return new Vector2(this.m31, this.m32); */
} public static get identity(){
return Matrix2D._identity;
}
public set translation(value: Vector2){ constructor(m11?: number, m12?: number, m21?: number, m22?: number, m31?: number, m32?: number){
this.m31 = value.x; this.m11 = m11 ? m11 : 1;
this.m32 = value.y; this.m12 = m12 ? m12 : 0;
}
/** 以弧度表示的旋转存储在这个矩阵中 */ this.m21 = m21 ? m21 : 0;
public get rotation(){ this.m22 = m22 ? m22 : 1;
return Math.atan2(this.m21, this.m11);
}
public set rotation(value: number){ this.m31 = m31 ? m31 : 0;
let val1 = Math.cos(value); this.m32 = m32 ? m32 : 0;
let val2 = Math.sin(value); }
this.m11 = val1; /** 存储在这个矩阵中的位置 */
this.m12 = val2; public get translation(){
this.m21 = -val2; return new Vector2(this.m31, this.m32);
this.m22 = val1; }
}
/** public set translation(value: Vector2){
* this.m31 = value.x;
*/ this.m32 = value.y;
public get rotationDegrees(){ }
return MathHelper.toDegrees(this.rotation);
}
public set rotationDegrees(value: number){ /** 以弧度表示的旋转存储在这个矩阵中 */
this.rotation = MathHelper.toRadians(value); public get rotation(){
} return Math.atan2(this.m21, this.m11);
}
public get scale(){ public set rotation(value: number){
return new Vector2(this.m11, this.m22); let val1 = Math.cos(value);
} let val2 = Math.sin(value);
public set scale(value: Vector2){ this.m11 = val1;
this.m11 = value.x; this.m12 = val2;
this.m12 = value.y; this.m21 = -val2;
} this.m22 = val1;
}
/** /**
* matrix, *
* @param matrix1 */
* @param matrix2 public get rotationDegrees(){
*/ return MathHelper.toDegrees(this.rotation);
public static add(matrix1: Matrix2D, matrix2: Matrix2D){ }
matrix1.m11 += matrix2.m11;
matrix1.m12 += matrix2.m12;
matrix1.m21 += matrix2.m21; public set rotationDegrees(value: number){
matrix1.m22 += matrix2.m22; this.rotation = MathHelper.toRadians(value);
}
matrix1.m31 += matrix2.m31; public get scale(){
matrix1.m32 += matrix2.m32; return new Vector2(this.m11, this.m22);
}
return matrix1; public set scale(value: Vector2){
} this.m11 = value.x;
this.m12 = value.y;
}
public static divide(matrix1: Matrix2D, matrix2: Matrix2D){ /**
matrix1.m11 /= matrix2.m11; * matrix,
matrix1.m12 /= matrix2.m12; * @param matrix1
* @param matrix2
*/
public static add(matrix1: Matrix2D, matrix2: Matrix2D){
matrix1.m11 += matrix2.m11;
matrix1.m12 += matrix2.m12;
matrix1.m21 /= matrix2.m21; matrix1.m21 += matrix2.m21;
matrix1.m22 /= matrix2.m22; matrix1.m22 += matrix2.m22;
matrix1.m31 /= matrix2.m31; matrix1.m31 += matrix2.m31;
matrix1.m32 /= matrix2.m32; matrix1.m32 += matrix2.m32;
return matrix1; return matrix1;
} }
public static multiply(matrix1: Matrix2D, matrix2: Matrix2D){ public static divide(matrix1: Matrix2D, matrix2: Matrix2D){
let result = new Matrix2D(); matrix1.m11 /= matrix2.m11;
matrix1.m12 /= matrix2.m12;
let m11 = ( matrix1.m11 * matrix2.m11 ) + ( matrix1.m12 * matrix2.m21 ); matrix1.m21 /= matrix2.m21;
let m12 = ( matrix1.m11 * matrix2.m12 ) + ( matrix1.m12 * matrix2.m22 ); matrix1.m22 /= matrix2.m22;
let m21 = ( matrix1.m21 * matrix2.m11 ) + ( matrix1.m22 * matrix2.m21 ); matrix1.m31 /= matrix2.m31;
let m22 = ( matrix1.m21 * matrix2.m12 ) + ( matrix1.m22 * matrix2.m22 ); matrix1.m32 /= matrix2.m32;
let m31 = ( matrix1.m31 * matrix2.m11 ) + ( matrix1.m32 * matrix2.m21 ) + matrix2.m31; return matrix1;
let m32 = ( matrix1.m31 * matrix2.m12 ) + ( matrix1.m32 * matrix2.m22 ) + matrix2.m32; }
result.m11 = m11; public static multiply(matrix1: Matrix2D, matrix2: Matrix2D){
result.m12 = m12; let result = new Matrix2D();
result.m21 = m21; let m11 = ( matrix1.m11 * matrix2.m11 ) + ( matrix1.m12 * matrix2.m21 );
result.m22 = m22; let m12 = ( matrix1.m11 * matrix2.m12 ) + ( matrix1.m12 * matrix2.m22 );
result.m31 = m31; let m21 = ( matrix1.m21 * matrix2.m11 ) + ( matrix1.m22 * matrix2.m21 );
result.m32 = m32; let m22 = ( matrix1.m21 * matrix2.m12 ) + ( matrix1.m22 * matrix2.m22 );
return result; let m31 = ( matrix1.m31 * matrix2.m11 ) + ( matrix1.m32 * matrix2.m21 ) + matrix2.m31;
} let m32 = ( matrix1.m31 * matrix2.m12 ) + ( matrix1.m32 * matrix2.m22 ) + matrix2.m32;
public static multiplyTranslation(matrix: Matrix2D, x: number, y: number){ result.m11 = m11;
let trans = Matrix2D.createTranslation(x, y); result.m12 = m12;
return Matrix2D.multiply(matrix, trans);
}
public determinant(){ result.m21 = m21;
return this.m11 * this.m22 - this.m12 * this.m21; result.m22 = m22;
}
public static invert(matrix: Matrix2D, result: Matrix2D = new Matrix2D()){ result.m31 = m31;
let det = 1 / matrix.determinant(); result.m32 = m32;
result.m11 = matrix.m22 * det; return result;
result.m12 = -matrix.m12 * det; }
result.m21 = -matrix.m21 * det; public static multiplyTranslation(matrix: Matrix2D, x: number, y: number){
result.m22 = matrix.m11 * det; let trans = Matrix2D.createTranslation(x, y);
return Matrix2D.multiply(matrix, trans);
}
result.m31 = (matrix.m32 * matrix.m21 - matrix.m31 * matrix.m22) * det; public determinant(){
result.m32 = -(matrix.m32 * matrix.m11 - matrix.m31 * matrix.m12) * det; return this.m11 * this.m22 - this.m12 * this.m21;
}
return result; public static invert(matrix: Matrix2D, result: Matrix2D = new Matrix2D()){
} let det = 1 / matrix.determinant();
/** result.m11 = matrix.m22 * det;
* tranlation result.m12 = -matrix.m12 * det;
* @param xPosition
* @param yPosition
*/
public static createTranslation(xPosition: number, yPosition: number){
let result = new Matrix2D();
result.m11 = 1; result.m21 = -matrix.m21 * det;
result.m12 = 0; result.m22 = matrix.m11 * det;
result.m21 = 0; result.m31 = (matrix.m32 * matrix.m21 - matrix.m31 * matrix.m22) * det;
result.m22 = 1; result.m32 = -(matrix.m32 * matrix.m11 - matrix.m31 * matrix.m12) * det;
result.m31 = xPosition; return result;
result.m32 = yPosition; }
return result; /**
} * tranlation
* @param xPosition
* @param yPosition
*/
public static createTranslation(xPosition: number, yPosition: number){
let result = new Matrix2D();
/** result.m11 = 1;
* position translation result.m12 = 0;
* @param position
*/
public static createTranslationVector(position: Vector2){
return this.createTranslation(position.x, position.y);
}
public static createRotation(radians: number, result?: Matrix2D){ result.m21 = 0;
result = new Matrix2D(); result.m22 = 1;
let val1 = Math.cos(radians); result.m31 = xPosition;
let val2 = Math.sin(radians); result.m32 = yPosition;
result.m11 = val1; return result;
result.m12 = val2; }
result.m21 = -val2;
result.m22 = val1;
return result; /**
} * position translation
* @param position
*/
public static createTranslationVector(position: Vector2){
return this.createTranslation(position.x, position.y);
}
public static createScale(xScale: number, yScale: number, result: Matrix2D = new Matrix2D()){ public static createRotation(radians: number, result?: Matrix2D){
result.m11 = xScale; result = new Matrix2D();
result.m12 = 0;
result.m21 = 0; let val1 = Math.cos(radians);
result.m22 = yScale; let val2 = Math.sin(radians);
result.m31 = 0; result.m11 = val1;
result.m32 = 0; result.m12 = val2;
result.m21 = -val2;
result.m22 = val1;
return result; return result;
} }
public toEgretMatrix(): egret.Matrix{ public static createScale(xScale: number, yScale: number, result: Matrix2D = new Matrix2D()){
let matrix = new egret.Matrix(this.m11, this.m12, this.m21, this.m22, this.m31, this.m32); result.m11 = xScale;
return matrix; 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;
}
} }
} }
+154 -152
View File
@@ -1,183 +1,185 @@
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
*/ */
public getClosestPointOnRectangleBorderToPoint(point: Vector2): { res: Vector2, edgeNormal: Vector2 } { public getClosestPointOnRectangleBorderToPoint(point: Vector2): { res: Vector2, edgeNormal: Vector2 } {
let edgeNormal = Vector2.zero; let 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: res, edgeNormal: edgeNormal };
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;
public calculateBounds(parentPosition: Vector2, position: Vector2, origin: Vector2, scale: Vector2, rotation: number, width: number, height: number){ for (let i = 0; i < points.length; i++) {
this.x = parentPosition.x + position.x - origin.x * scale.x; let pt = points[i];
this.y = parentPosition.y + position.y - origin.y * scale.y;
this.width = width * scale.x;
this.height = height * scale.y;
}
/** if (pt.x < minX) minX = pt.x;
* egret矩形转化为Rectangle if (pt.x > maxX) maxX = pt.x;
* @param rect
*/
public setEgretRect(rect: egret.Rectangle): Rectangle{
this.x = rect.x;
this.y = rect.y;
this.width = rect.width;
this.height = rect.height;
return this;
}
/** if (pt.y < minY) minY = pt.y;
* if (pt.y > maxY) maxY = pt.y;
* @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++) { return this.fromMinMax(minX, minY, maxX, maxY);
let pt = points[i];
if (pt.x < minX) minX = pt.x;
if (pt.x > maxX) maxX = pt.x;
if (pt.y < minY) minY = pt.y;
if (pt.y > maxY) maxY = pt.y;
} }
return this.fromMinMax(minX, minY, maxX, maxY);
} }
} }
+162 -160
View File
@@ -1,183 +1,185 @@
/** 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 value1
* @param value2 * @param value2
*/ */
public static add(value1: Vector2, value2: Vector2){ public static add(value1: Vector2, value2: Vector2){
let result: Vector2 = new Vector2(0, 0); let result: Vector2 = new Vector2(0, 0);
result.x = value1.x + value2.x; result.x = value1.x + value2.x;
result.y = value1.y + value2.y; result.y = value1.y + value2.y;
return result; return result;
} }
/** /**
* *
* @param value1 * @param value1
* @param value2 * @param value2
*/ */
public static divide(value1: Vector2, value2: Vector2){ public static divide(value1: Vector2, value2: Vector2){
let result: Vector2 = new Vector2(0, 0); let result: Vector2 = new Vector2(0, 0);
result.x = value1.x / value2.x; result.x = value1.x / value2.x;
result.y = value1.y / value2.y; result.y = value1.y / value2.y;
return result; return result;
} }
/** /**
* *
* @param value1 * @param value1
* @param value2 * @param value2
*/ */
public static multiply(value1: Vector2, value2: Vector2){ public static multiply(value1: Vector2, value2: Vector2){
let result: Vector2 = new Vector2(0, 0); let result: Vector2 = new Vector2(0, 0);
result.x = value1.x * value2.x; result.x = value1.x * value2.x;
result.y = value1.y * value2.y; result.y = value1.y * value2.y;
return result; return result;
} }
/** /**
* *
* @param value1 * @param value1
* @param value2 * @param value2
*/ */
public static subtract(value1: Vector2, value2: Vector2){ public static subtract(value1: Vector2, value2: Vector2){
let result: Vector2 = new Vector2(0, 0); let result: Vector2 = new Vector2(0, 0);
result.x = value1.x - value2.x; result.x = value1.x - value2.x;
result.y = value1.y - value2.y; result.y = value1.y - value2.y;
return result; return result;
} }
/** 变成一个方向相同的单位向量 */ /** 变成一个方向相同的单位向量 */
public normalize(){ public normalize(){
let val = 1 / Math.sqrt((this.x * this.x) + (this.y * this.y)); let val = 1 / Math.sqrt((this.x * this.x) + (this.y * this.y));
this.x *= val; this.x *= val;
this.y *= val; this.y *= val;
} }
/** 返回它的长度 */ /** 返回它的长度 */
public length(){ public length(){
return Math.sqrt((this.x * this.x) + (this.y * this.y)); return Math.sqrt((this.x * this.x) + (this.y * this.y));
} }
/** 对x和y值四舍五入 */ /** 对x和y值四舍五入 */
public round(): Vector2{ public round(): Vector2{
return new Vector2(Math.round(this.x), Math.round(this.y)); return new Vector2(Math.round(this.x), Math.round(this.y));
} }
/** /**
* Vector2 * Vector2
* *
* @param value * @param value
*/ */
public static normalize(value: Vector2){ public static normalize(value: Vector2){
let val = 1 / Math.sqrt((value.x * value.x) + (value.y * value.y)); let val = 1 / Math.sqrt((value.x * value.x) + (value.y * value.y));
value.x *= val; value.x *= val;
value.y *= val; value.y *= val;
return value; return value;
} }
/** /**
* *
* @param value1 * @param value1
* @param value2 * @param value2
*/ */
public static dot(value1: Vector2, value2: Vector2): number{ public static dot(value1: Vector2, value2: Vector2): number{
return (value1.x * value2.x) + (value1.y * value2.y); return (value1.x * value2.x) + (value1.y * value2.y);
} }
/** /**
* *
* @param value1 * @param value1
* @param value2 * @param value2
*/ */
public static distanceSquared(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 (v1 * v1) + (v2 * v2); return (v1 * v1) + (v2 * v2);
} }
/** /**
* *
* @param value1 * @param value1
* @param min * @param min
* @param max * @param max
*/ */
public static clamp(value1: Vector2, min: Vector2, max: Vector2){ public static clamp(value1: Vector2, min: Vector2, max: Vector2){
return new Vector2(MathHelper.clamp(value1.x, min.x, max.x), return new Vector2(MathHelper.clamp(value1.x, min.x, max.x),
MathHelper.clamp(value1.y, min.y, max.y)); MathHelper.clamp(value1.y, min.y, max.y));
} }
/** /**
* 线 * 线
* @param value1 * @param value1
* @param value2 * @param value2
* @param amount (0.01.0) * @param amount (0.01.0)
*/ */
public static lerp(value1: Vector2, value2: Vector2, amount: number){ 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)); return new Vector2(MathHelper.lerp(value1.x, value2.x, amount), MathHelper.lerp(value1.y, value2.y, amount));
} }
/** /**
* *
* @param position * @param position
* @param matrix * @param matrix
*/ */
public static transform(position: Vector2, matrix: Matrix2D){ public static transform(position: Vector2, matrix: Matrix2D){
return new Vector2((position.x * matrix.m11) + (position.y * matrix.m21), (position.x * matrix.m12) + (position.y * matrix.m22)); return new Vector2((position.x * matrix.m11) + (position.y * matrix.m21), (position.x * matrix.m12) + (position.y * matrix.m22));
} }
/** /**
* *
* @param value1 * @param value1
* @param value2 * @param value2
*/ */
public static distance(value1: Vector2, value2: Vector2){ public static distance(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 Math.sqrt((v1 * v1) + (v2 * v2));
} }
/** /**
* *
* @param value * @param value
*/ */
public static negate(value: Vector2){ public static negate(value: Vector2){
let result: Vector2 = new Vector2(); let result: Vector2 = new Vector2();
result.x = -value.x; result.x = -value.x;
result.y = -value.y; result.y = -value.y;
return result; return result;
}
} }
} }
+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;
}
} }
} }
+84 -80
View File
@@ -1,100 +1,104 @@
/** 移动器使用的帮助器类,用于管理触发器碰撞器交互并调用itriggerlistener。 */ module es {
class ColliderTriggerHelper {
private _entity: Entity;
/** 存储当前帧中发生的所有活动交集对 */
private _activeTriggerIntersections: Pair<Collider>[] = [];
/** 存储前一帧的交叉对,以便我们可以在移动该帧后检测出口 */
private _previousTriggerIntersections: Pair<Collider>[] = [];
private _tempTriggerList: ITriggerListener[] = [];
constructor(entity: Entity) {
this._entity = entity;
}
/** /**
* itriggerlistener * 使itriggerlistener
*/ */
public update() { export class ColliderTriggerHelper {
let colliders = this._entity.getComponents(Collider); private _entity: Entity;
for (let i = 0; i < colliders.length; i++) { /** 存储当前帧中发生的所有活动交集对 */
let collider = colliders[i]; private _activeTriggerIntersections: Pair<Collider>[] = [];
/** 存储前一帧的交叉对,以便我们可以在移动该帧后检测出口 */
private _previousTriggerIntersections: Pair<Collider>[] = [];
private _tempTriggerList: ITriggerListener[] = [];
let boxcastResult = Physics.boxcastBroadphase(collider.bounds, collider.collidesWithLayers); constructor(entity: Entity) {
collider.bounds = boxcastResult.rect; this._entity = entity;
let neighbors = boxcastResult.colliders; }
for (let j = 0; j < neighbors.length; j++) {
let neighbor = neighbors[j];
if (!collider.isTrigger && !neighbor.isTrigger)
continue;
if (collider.overlaps(neighbor)) { /**
let pair = new Pair<Collider>(collider, neighbor); * itriggerlistener
let shouldReportTriggerEvent = this._activeTriggerIntersections.findIndex(value => { */
return value.first == pair.first && value.second == pair.second; public update() {
}) == -1 && this._previousTriggerIntersections.findIndex(value => { let colliders = this._entity.getComponents(Collider);
return value.first == pair.first && value.second == pair.second; for (let i = 0; i < colliders.length; i++) {
}) == -1; let collider = colliders[i];
if (shouldReportTriggerEvent) let boxcastResult = Physics.boxcastBroadphase(collider.bounds, collider.collidesWithLayers);
this.notifyTriggerListeners(pair, true); collider.bounds = boxcastResult.rect;
let neighbors = boxcastResult.colliders;
for (let j = 0; j < neighbors.length; j++) {
let neighbor = neighbors[j];
if (!collider.isTrigger && !neighbor.isTrigger)
continue;
if (!this._activeTriggerIntersections.contains(pair)) if (collider.overlaps(neighbor)) {
this._activeTriggerIntersections.push(pair); let pair = new Pair<Collider>(collider, neighbor);
let shouldReportTriggerEvent = this._activeTriggerIntersections.findIndex(value => {
return value.first == pair.first && value.second == pair.second;
}) == -1 && this._previousTriggerIntersections.findIndex(value => {
return value.first == pair.first && value.second == pair.second;
}) == -1;
if (shouldReportTriggerEvent)
this.notifyTriggerListeners(pair, true);
if (!this._activeTriggerIntersections.contains(pair))
this._activeTriggerIntersections.push(pair);
}
} }
} }
ListPool.free(colliders);
this.checkForExitedColliders();
} }
ListPool.free(colliders); private checkForExitedColliders(){
for (let i = 0; i < this._activeTriggerIntersections.length; i ++){
let index = this._previousTriggerIntersections.findIndex(value => {
if (value.first == this._activeTriggerIntersections[i].first && value.second == this._activeTriggerIntersections[i].second)
return true;
this.checkForExitedColliders(); return false;
} });
if (index != -1)
private checkForExitedColliders(){ this._previousTriggerIntersections.removeAt(index);
for (let i = 0; i < this._activeTriggerIntersections.length; i ++){
let index = this._previousTriggerIntersections.findIndex(value => {
if (value.first == this._activeTriggerIntersections[i].first && value.second == this._activeTriggerIntersections[i].second)
return true;
return false;
});
if (index != -1)
this._previousTriggerIntersections.removeAt(index);
}
for (let i = 0; i < this._previousTriggerIntersections.length; i ++){
this.notifyTriggerListeners(this._previousTriggerIntersections[i], false)
}
this._previousTriggerIntersections.length = 0;
for (let i = 0; i < this._activeTriggerIntersections.length; i ++){
if (!this._previousTriggerIntersections.contains(this._activeTriggerIntersections[i])){
this._previousTriggerIntersections.push(this._activeTriggerIntersections[i]);
}
}
this._activeTriggerIntersections.length = 0;
}
private notifyTriggerListeners(collisionPair: Pair<Collider>, isEntering: boolean) {
collisionPair.first.entity.getComponents("ITriggerListener", this._tempTriggerList);
for (let i = 0; i < this._tempTriggerList.length; i ++){
if (isEntering){
this._tempTriggerList[i].onTriggerEnter(collisionPair.second, collisionPair.first);
} else {
this._tempTriggerList[i].onTriggerExit(collisionPair.second, collisionPair.first);
} }
this._tempTriggerList.length = 0; for (let i = 0; i < this._previousTriggerIntersections.length; i ++){
this.notifyTriggerListeners(this._previousTriggerIntersections[i], false)
}
this._previousTriggerIntersections.length = 0;
for (let i = 0; i < this._activeTriggerIntersections.length; i ++){
if (!this._previousTriggerIntersections.contains(this._activeTriggerIntersections[i])){
this._previousTriggerIntersections.push(this._activeTriggerIntersections[i]);
}
}
this._activeTriggerIntersections.length = 0;
}
if (collisionPair.second.entity){ private notifyTriggerListeners(collisionPair: Pair<Collider>, isEntering: boolean) {
collisionPair.second.entity.getComponents("ITriggerListener", this._tempTriggerList); collisionPair.first.entity.getComponents("ITriggerListener", this._tempTriggerList);
for (let i = 0; i < this._tempTriggerList.length; i ++){ for (let i = 0; i < this._tempTriggerList.length; i ++){
if (isEntering){ if (isEntering){
this._tempTriggerList[i].onTriggerEnter(collisionPair.first, collisionPair.second); this._tempTriggerList[i].onTriggerEnter(collisionPair.second, collisionPair.first);
} else { } else {
this._tempTriggerList[i].onTriggerExit(collisionPair.first, collisionPair.second); this._tempTriggerList[i].onTriggerExit(collisionPair.second, collisionPair.first);
}
} }
this._tempTriggerList.length = 0; this._tempTriggerList.length = 0;
if (collisionPair.second.entity){
collisionPair.second.entity.getComponents("ITriggerListener", this._tempTriggerList);
for (let i = 0; i < this._tempTriggerList.length; i ++){
if (isEntering){
this._tempTriggerList[i].onTriggerEnter(collisionPair.first, collisionPair.second);
} else {
this._tempTriggerList[i].onTriggerExit(collisionPair.first, collisionPair.second);
}
}
this._tempTriggerList.length = 0;
}
} }
} }
} }
+154 -152
View File
@@ -1,168 +1,170 @@
enum PointSectors { module es {
center = 0, export enum PointSectors {
top = 1, center = 0,
bottom = 2, top = 1,
topLeft = 9, bottom = 2,
topRight = 5, topLeft = 9,
left = 8, topRight = 5,
right = 4, left = 8,
bottomLeft = 10, right = 4,
bottomRight = 6 bottomLeft = 10,
} bottomRight = 6
class Collisions {
public static isLineToLine(a1: Vector2, a2: Vector2, b1: Vector2, b2: Vector2): boolean {
let b = Vector2.subtract(a2, a1);
let d = Vector2.subtract(b2, b1);
let bDotDPerp = b.x * d.y - b.y * d.x;
// 如果b*d = 0,表示这两条直线平行,因此有无穷个交点
if (bDotDPerp == 0)
return false;
let c = Vector2.subtract(b1, a1);
let t = (c.x * d.y - c.y * d.x) / bDotDPerp;
if (t < 0 || t > 1)
return false;
let u = (c.x * b.y - c.y * b.x) / bDotDPerp;
if (u < 0 || u > 1)
return false;
return true;
} }
public static lineToLineIntersection(a1: Vector2, a2: Vector2, b1: Vector2, b2: Vector2): Vector2 { export class Collisions {
let intersection = new Vector2(0, 0); public static isLineToLine(a1: Vector2, a2: Vector2, b1: Vector2, b2: Vector2): boolean {
let b = Vector2.subtract(a2, a1);
let d = Vector2.subtract(b2, b1);
let bDotDPerp = b.x * d.y - b.y * d.x;
let b = Vector2.subtract(a2, a1); // 如果b*d = 0,表示这两条直线平行,因此有无穷个交点
let d = Vector2.subtract(b2, b1); if (bDotDPerp == 0)
let bDotDPerp = b.x * d.y - b.y * d.x; return false;
// 如果b*d = 0,表示这两条直线平行,因此有无穷个交点 let c = Vector2.subtract(b1, a1);
if (bDotDPerp == 0) let t = (c.x * d.y - c.y * d.x) / bDotDPerp;
return intersection; if (t < 0 || t > 1)
return false;
let c = Vector2.subtract(b1, a1); let u = (c.x * b.y - c.y * b.x) / bDotDPerp;
let t = (c.x * d.y - c.y * d.x) / bDotDPerp; if (u < 0 || u > 1)
if (t < 0 || t > 1) return false;
return intersection;
let u = (c.x * b.y - c.y * b.x) / bDotDPerp;
if (u < 0 || u > 1)
return intersection;
intersection = Vector2.add(a1, new Vector2(t * b.x, t * b.y));
return intersection;
}
public static closestPointOnLine(lineA: Vector2, lineB: Vector2, closestTo: Vector2) {
let v = Vector2.subtract(lineB, lineA);
let w = Vector2.subtract(closestTo, lineA);
let t = Vector2.dot(w, v) / Vector2.dot(v, v);
t = MathHelper.clamp(t, 0, 1);
return Vector2.add(lineA, new Vector2(v.x * t, v.y * t));
}
public static isCircleToCircle(circleCenter1: Vector2, circleRadius1: number, circleCenter2: Vector2, circleRadius2: number): boolean {
return Vector2.distanceSquared(circleCenter1, circleCenter2) < (circleRadius1 + circleRadius2) * (circleRadius1 + circleRadius2);
}
public static isCircleToLine(circleCenter: Vector2, radius: number, lineFrom: Vector2, lineTo: Vector2): boolean {
return Vector2.distanceSquared(circleCenter, this.closestPointOnLine(lineFrom, lineTo, circleCenter)) < radius * radius;
}
public static isCircleToPoint(circleCenter: Vector2, radius: number, point: Vector2): boolean {
return Vector2.distanceSquared(circleCenter, point) < radius * radius;
}
public static isRectToCircle(rect: egret.Rectangle, cPosition: Vector2, cRadius: number): boolean {
let ew = rect.width * 0.5;
let eh = rect.height * 0.5;
let vx = Math.max(0, Math.max(cPosition.x - rect.x) - ew);
let vy = Math.max(0, Math.max(cPosition.y - rect.y) - eh);
return vx * vx + vy * vy < cRadius * cRadius;
}
public static isRectToLine(rect: Rectangle, lineFrom: Vector2, lineTo: Vector2){
let fromSector = this.getSector(rect.x, rect.y, rect.width, rect.height, lineFrom);
let toSector = this.getSector(rect.x, rect.y, rect.width, rect.height, lineTo);
if (fromSector == PointSectors.center || toSector == PointSectors.center){
return true; return true;
} else if((fromSector & toSector) != 0){
return false;
} else{
let both = fromSector | toSector;
// 线对边进行检查
let edgeFrom: Vector2;
let edgeTo: Vector2;
if ((both & PointSectors.top) != 0){
edgeFrom = new Vector2(rect.x, rect.y);
edgeTo = new Vector2(rect.x + rect.width, rect.y);
if (this.isLineToLine(edgeFrom, edgeTo, lineFrom, lineTo))
return true;
}
if ((both & PointSectors.bottom) != 0){
edgeFrom = new Vector2(rect.x, rect.y + rect.height);
edgeTo = new Vector2(rect.x + rect.width, rect.y + rect.height);
if (this.isLineToLine(edgeFrom, edgeTo, lineFrom, lineTo))
return true;
}
if ((both & PointSectors.left) != 0){
edgeFrom = new Vector2(rect.x, rect.y);
edgeTo = new Vector2(rect.x, rect.y + rect.height);
if (this.isLineToLine(edgeFrom, edgeTo, lineFrom, lineTo))
return true;
}
if ((both & PointSectors.right) != 0){
edgeFrom = new Vector2(rect.x + rect.width, rect.y);
edgeTo = new Vector2(rect.x + rect.width, rect.y + rect.height);
if (this.isLineToLine(edgeFrom, edgeTo, lineFrom, lineTo))
return true;
}
} }
return false; public static lineToLineIntersection(a1: Vector2, a2: Vector2, b1: Vector2, b2: Vector2): Vector2 {
} let intersection = new Vector2(0, 0);
public static isRectToPoint(rX: number, rY: number, rW: number, rH: number, point: Vector2) { let b = Vector2.subtract(a2, a1);
return point.x >= rX && point.y >= rY && point.x < rX + rW && point.y < rY + rH; let d = Vector2.subtract(b2, b1);
} let bDotDPerp = b.x * d.y - b.y * d.x;
/** // 如果b*d = 0,表示这两条直线平行,因此有无穷个交点
* 使CohenSutherland算法 if (bDotDPerp == 0)
* return intersection;
* :
* 1001 1000 1010
* 0001 0000 0010
* 0101 0100 0110
* @param rX
* @param rY
* @param rW
* @param rH
* @param point
*/
public static getSector(rX: number, rY: number, rW: number, rH: number, point: Vector2): PointSectors {
let sector = PointSectors.center;
if (point.x < rX) let c = Vector2.subtract(b1, a1);
sector |= PointSectors.left; let t = (c.x * d.y - c.y * d.x) / bDotDPerp;
else if (point.x >= rX + rW) if (t < 0 || t > 1)
sector |= PointSectors.right; return intersection;
if (point.y < rY) let u = (c.x * b.y - c.y * b.x) / bDotDPerp;
sector |= PointSectors.top; if (u < 0 || u > 1)
else if (point.y >= rY + rH) return intersection;
sector |= PointSectors.bottom;
return sector; intersection = Vector2.add(a1, new Vector2(t * b.x, t * b.y));
return intersection;
}
public static closestPointOnLine(lineA: Vector2, lineB: Vector2, closestTo: Vector2) {
let v = Vector2.subtract(lineB, lineA);
let w = Vector2.subtract(closestTo, lineA);
let t = Vector2.dot(w, v) / Vector2.dot(v, v);
t = MathHelper.clamp(t, 0, 1);
return Vector2.add(lineA, new Vector2(v.x * t, v.y * t));
}
public static isCircleToCircle(circleCenter1: Vector2, circleRadius1: number, circleCenter2: Vector2, circleRadius2: number): boolean {
return Vector2.distanceSquared(circleCenter1, circleCenter2) < (circleRadius1 + circleRadius2) * (circleRadius1 + circleRadius2);
}
public static isCircleToLine(circleCenter: Vector2, radius: number, lineFrom: Vector2, lineTo: Vector2): boolean {
return Vector2.distanceSquared(circleCenter, this.closestPointOnLine(lineFrom, lineTo, circleCenter)) < radius * radius;
}
public static isCircleToPoint(circleCenter: Vector2, radius: number, point: Vector2): boolean {
return Vector2.distanceSquared(circleCenter, point) < radius * radius;
}
public static isRectToCircle(rect: egret.Rectangle, cPosition: Vector2, cRadius: number): boolean {
let ew = rect.width * 0.5;
let eh = rect.height * 0.5;
let vx = Math.max(0, Math.max(cPosition.x - rect.x) - ew);
let vy = Math.max(0, Math.max(cPosition.y - rect.y) - eh);
return vx * vx + vy * vy < cRadius * cRadius;
}
public static isRectToLine(rect: Rectangle, lineFrom: Vector2, lineTo: Vector2){
let fromSector = this.getSector(rect.x, rect.y, rect.width, rect.height, lineFrom);
let toSector = this.getSector(rect.x, rect.y, rect.width, rect.height, lineTo);
if (fromSector == PointSectors.center || toSector == PointSectors.center){
return true;
} else if((fromSector & toSector) != 0){
return false;
} else{
let both = fromSector | toSector;
// 线对边进行检查
let edgeFrom: Vector2;
let edgeTo: Vector2;
if ((both & PointSectors.top) != 0){
edgeFrom = new Vector2(rect.x, rect.y);
edgeTo = new Vector2(rect.x + rect.width, rect.y);
if (this.isLineToLine(edgeFrom, edgeTo, lineFrom, lineTo))
return true;
}
if ((both & PointSectors.bottom) != 0){
edgeFrom = new Vector2(rect.x, rect.y + rect.height);
edgeTo = new Vector2(rect.x + rect.width, rect.y + rect.height);
if (this.isLineToLine(edgeFrom, edgeTo, lineFrom, lineTo))
return true;
}
if ((both & PointSectors.left) != 0){
edgeFrom = new Vector2(rect.x, rect.y);
edgeTo = new Vector2(rect.x, rect.y + rect.height);
if (this.isLineToLine(edgeFrom, edgeTo, lineFrom, lineTo))
return true;
}
if ((both & PointSectors.right) != 0){
edgeFrom = new Vector2(rect.x + rect.width, rect.y);
edgeTo = new Vector2(rect.x + rect.width, rect.y + rect.height);
if (this.isLineToLine(edgeFrom, edgeTo, lineFrom, lineTo))
return true;
}
}
return false;
}
public static isRectToPoint(rX: number, rY: number, rW: number, rH: number, point: Vector2) {
return point.x >= rX && point.y >= rY && point.x < rX + rW && point.y < rY + rH;
}
/**
* 使CohenSutherland算法
*
* :
* 1001 1000 1010
* 0001 0000 0010
* 0101 0100 0110
* @param rX
* @param rY
* @param rW
* @param rH
* @param point
*/
public static getSector(rX: number, rY: number, rW: number, rH: number, point: Vector2): PointSectors {
let sector = PointSectors.center;
if (point.x < rX)
sector |= PointSectors.left;
else if (point.x >= rX + rW)
sector |= PointSectors.right;
if (point.y < rY)
sector |= PointSectors.top;
else if (point.y >= rY + rH)
sector |= PointSectors.bottom;
return sector;
}
} }
} }
+55 -53
View File
@@ -1,64 +1,66 @@
class Physics { module es {
private static _spatialHash: SpatialHash; export class Physics {
/** 调用reset并创建一个新的SpatialHash时使用的单元格大小 */ private static _spatialHash: SpatialHash;
public static spatialHashCellSize = 100; /** 调用reset并创建一个新的SpatialHash时使用的单元格大小 */
/** 接受layerMask的所有方法的默认值 */ public static spatialHashCellSize = 100;
public static readonly allLayers: number = -1; /** 接受layerMask的所有方法的默认值 */
public static readonly allLayers: number = -1;
public static reset(){ public static reset(){
this._spatialHash = new SpatialHash(this.spatialHashCellSize); this._spatialHash = new SpatialHash(this.spatialHashCellSize);
} }
/** /**
* SpatialHash中移除所有碰撞器 * SpatialHash中移除所有碰撞器
*/ */
public static clear(){ public static clear(){
this._spatialHash.clear(); this._spatialHash.clear();
} }
public static overlapCircleAll(center: Vector2, randius: number, results: any[], layerMask = -1){ public static overlapCircleAll(center: Vector2, randius: number, results: any[], layerMask = -1){
return this._spatialHash.overlapCircle(center, randius, results, layerMask); return this._spatialHash.overlapCircle(center, randius, results, layerMask);
} }
public static boxcastBroadphase(rect: Rectangle, layerMask: number = this.allLayers){ public static boxcastBroadphase(rect: Rectangle, layerMask: number = this.allLayers){
let boxcastResult = this._spatialHash.aabbBroadphase(rect, null, layerMask); let boxcastResult = this._spatialHash.aabbBroadphase(rect, null, layerMask);
return {colliders: boxcastResult.tempHashSet, rect: boxcastResult.bounds}; return {colliders: boxcastResult.tempHashSet, rect: boxcastResult.bounds};
} }
public static boxcastBroadphaseExcludingSelf(collider: Collider, rect: Rectangle, layerMask = this.allLayers){ public static boxcastBroadphaseExcludingSelf(collider: Collider, rect: Rectangle, layerMask = this.allLayers){
return this._spatialHash.aabbBroadphase(rect, collider, layerMask); return this._spatialHash.aabbBroadphase(rect, collider, layerMask);
} }
/** /**
* *
* @param collider * @param collider
*/ */
public static addCollider(collider: Collider){ public static addCollider(collider: Collider){
Physics._spatialHash.register(collider); Physics._spatialHash.register(collider);
} }
/** /**
* *
* @param collider * @param collider
*/ */
public static removeCollider(collider: Collider){ public static removeCollider(collider: Collider){
Physics._spatialHash.remove(collider); Physics._spatialHash.remove(collider);
} }
/** /**
* *
* @param collider * @param collider
*/ */
public static updateCollider(collider: Collider){ public static updateCollider(collider: Collider){
this._spatialHash.remove(collider); this._spatialHash.remove(collider);
this._spatialHash.register(collider); this._spatialHash.register(collider);
} }
/** /**
* debug绘制空间散列的内容 * debug绘制空间散列的内容
* @param secondsToDisplay * @param secondsToDisplay
*/ */
public static debugDraw(secondsToDisplay){ public static debugDraw(secondsToDisplay){
this._spatialHash.debugDraw(secondsToDisplay, 2); this._spatialHash.debugDraw(secondsToDisplay, 2);
}
} }
} }
+10 -8
View File
@@ -1,11 +1,13 @@
class CollisionResult { module es {
public collider: Collider; export class CollisionResult {
public minimumTranslationVector: Vector2 = Vector2.zero; public collider: Collider;
public normal: Vector2 = Vector2.zero; public minimumTranslationVector: Vector2 = Vector2.zero;
public point: Vector2 = Vector2.zero; public normal: Vector2 = Vector2.zero;
public point: Vector2 = Vector2.zero;
public invertResult(){ public invertResult(){
this.minimumTranslationVector = Vector2.negate(this.minimumTranslationVector); this.minimumTranslationVector = Vector2.negate(this.minimumTranslationVector);
this.normal = Vector2.negate(this.normal); this.normal = Vector2.negate(this.normal);
}
} }
} }
@@ -1,302 +1,304 @@
class ShapeCollisions { module es {
/** export class ShapeCollisions {
* /**
* @param first *
* @param second * @param first
*/ * @param second
public static polygonToPolygon(first: Polygon, second: Polygon) { */
let result = new CollisionResult(); public static polygonToPolygon(first: Polygon, second: Polygon) {
let isIntersecting = true; let result = new CollisionResult();
let isIntersecting = true;
let firstEdges = first.edgeNormals; let firstEdges = first.edgeNormals;
let secondEdges = second.edgeNormals; let secondEdges = second.edgeNormals;
let minIntervalDistance = Number.POSITIVE_INFINITY; let minIntervalDistance = Number.POSITIVE_INFINITY;
let translationAxis = new Vector2(); let translationAxis = new Vector2();
let polygonOffset = Vector2.subtract(first.position, second.position); let polygonOffset = Vector2.subtract(first.position, second.position);
let axis: Vector2; let axis: Vector2;
// 循环穿过两个多边形的所有边 // 循环穿过两个多边形的所有边
for (let edgeIndex = 0; edgeIndex < firstEdges.length + secondEdges.length; edgeIndex++) { for (let edgeIndex = 0; edgeIndex < firstEdges.length + secondEdges.length; edgeIndex++) {
// 1. 找出当前多边形是否相交 // 1. 找出当前多边形是否相交
// 多边形的归一化轴垂直于缓存给我们的当前边 // 多边形的归一化轴垂直于缓存给我们的当前边
if (edgeIndex < firstEdges.length) { if (edgeIndex < firstEdges.length) {
axis = firstEdges[edgeIndex]; axis = firstEdges[edgeIndex];
} else { } else {
axis = secondEdges[edgeIndex - firstEdges.length]; axis = secondEdges[edgeIndex - firstEdges.length];
}
// 求多边形在当前轴上的投影
let minA = 0;
let minB = 0;
let maxA = 0;
let maxB = 0;
let intervalDist = 0;
let ta = this.getInterval(axis, first, minA, maxA);
minA = ta.min;
minB = ta.max;
let tb = this.getInterval(axis, second, minB, maxB);
minB = tb.min;
maxB = tb.max;
// 将区间设为第二个多边形的空间。由轴上投影的位置差偏移。
let relativeIntervalOffset = Vector2.dot(polygonOffset, axis);
minA += relativeIntervalOffset;
maxA += relativeIntervalOffset;
// 检查多边形投影是否正在相交
intervalDist = this.intervalDistance(minA, maxA, minB, maxB);
if (intervalDist > 0)
isIntersecting = false;
// 对于多对多数据类型转换,添加一个Vector2?参数称为deltaMovement。为了提高速度,我们这里不使用它
// TODO: 现在找出多边形是否会相交。只要检查速度就行了
// 如果多边形不相交,也不会相交,退出循环
if (!isIntersecting)
return null;
// 检查当前间隔距离是否为最小值。如果是,则存储间隔距离和当前距离。这将用于计算最小平移向量
intervalDist = Math.abs(intervalDist);
if (intervalDist < minIntervalDistance) {
minIntervalDistance = intervalDist;
translationAxis = axis;
if (Vector2.dot(translationAxis, polygonOffset) < 0)
translationAxis = new Vector2(-translationAxis);
}
} }
// 求多边形在当前轴上的投影 // 利用最小平移向量对多边形进行推入。
let minA = 0; result.normal = translationAxis;
let minB = 0; result.minimumTranslationVector = Vector2.multiply(new Vector2(-translationAxis.x, -translationAxis.y), new Vector2(minIntervalDistance));
let maxA = 0;
let maxB = 0;
let intervalDist = 0;
let ta = this.getInterval(axis, first, minA, maxA);
minA = ta.min;
minB = ta.max;
let tb = this.getInterval(axis, second, minB, maxB);
minB = tb.min;
maxB = tb.max;
// 将区间设为第二个多边形的空间。由轴上投影的位置差偏移。
let relativeIntervalOffset = Vector2.dot(polygonOffset, axis);
minA += relativeIntervalOffset;
maxA += relativeIntervalOffset;
// 检查多边形投影是否正在相交
intervalDist = this.intervalDistance(minA, maxA, minB, maxB);
if (intervalDist > 0)
isIntersecting = false;
// 对于多对多数据类型转换,添加一个Vector2?参数称为deltaMovement。为了提高速度,我们这里不使用它
// TODO: 现在找出多边形是否会相交。只要检查速度就行了
// 如果多边形不相交,也不会相交,退出循环
if (!isIntersecting)
return null;
// 检查当前间隔距离是否为最小值。如果是,则存储间隔距离和当前距离。这将用于计算最小平移向量
intervalDist = Math.abs(intervalDist);
if (intervalDist < minIntervalDistance) {
minIntervalDistance = intervalDist;
translationAxis = axis;
if (Vector2.dot(translationAxis, polygonOffset) < 0)
translationAxis = new Vector2(-translationAxis);
}
}
// 利用最小平移向量对多边形进行推入。
result.normal = translationAxis;
result.minimumTranslationVector = Vector2.multiply(new Vector2(-translationAxis.x, -translationAxis.y), new Vector2(minIntervalDistance));
return result;
}
/**
* [minA, maxA][minB, maxB]
* @param minA
* @param maxA
* @param minB
* @param maxB
*/
public static intervalDistance(minA: number, maxA: number, minB: number, maxB) {
if (minA < minB)
return minB - maxA;
return minA - minB;
}
/**
* [minmax]
* @param axis
* @param polygon
* @param min
* @param max
*/
public static getInterval(axis: Vector2, polygon: Polygon, min: number, max: number) {
let dot = Vector2.dot(polygon.points[0], axis);
min = max = dot;
for (let i = 1; i < polygon.points.length; i++) {
dot = Vector2.dot(polygon.points[i], axis);
if (dot < min) {
min = dot;
} else if (dot > max) {
max = dot;
}
}
return { min: min, max: max };
}
/**
*
* @param circle
* @param polygon
*/
public static circleToPolygon(circle: Circle, polygon: Polygon) {
let result = new CollisionResult();
let poly2Circle = Vector2.subtract(circle.position, polygon.position);
let gpp = Polygon.getClosestPointOnPolygonToPoint(polygon.points, poly2Circle);
let closestPoint: Vector2 = gpp.closestPoint;
let distanceSquared: number = gpp.distanceSquared;
result.normal = gpp.edgeNormal;
let circleCenterInsidePoly = polygon.containsPoint(circle.position);
if (distanceSquared > circle.radius * circle.radius && !circleCenterInsidePoly)
return null;
let mtv: Vector2;
if (circleCenterInsidePoly) {
mtv = Vector2.multiply(result.normal, new Vector2(Math.sqrt(distanceSquared) - circle.radius));
} else {
if (distanceSquared == 0) {
mtv = Vector2.multiply(result.normal, new Vector2(circle.radius));
} else {
let distance = Math.sqrt(distanceSquared);
mtv = Vector2.multiply(new Vector2(-Vector2.subtract(poly2Circle, closestPoint)), new Vector2((circle.radius - distanceSquared) / distance));
}
}
result.minimumTranslationVector = mtv;
result.point = Vector2.add(closestPoint, polygon.position);
return result;
}
/**
*
* @param circle
* @param box
*/
public static circleToBox(circle: Circle, box: Box): CollisionResult {
let result = new CollisionResult();
let closestPointOnBounds = box.bounds.getClosestPointOnRectangleBorderToPoint(circle.position).res;
if (box.containsPoint(circle.position)) {
result.point = closestPointOnBounds;
let safePlace = Vector2.add(closestPointOnBounds, Vector2.subtract(result.normal, new Vector2(circle.radius)));
result.minimumTranslationVector = Vector2.subtract(circle.position, safePlace);
return result; return result;
} }
let sqrDistance = Vector2.distanceSquared(closestPointOnBounds, circle.position); /**
if (sqrDistance == 0) { * [minA, maxA][minB, maxB]
result.minimumTranslationVector = Vector2.multiply(result.normal, new Vector2(circle.radius)); * @param minA
} else if (sqrDistance <= circle.radius * circle.radius) { * @param maxA
result.normal = Vector2.subtract(circle.position, closestPointOnBounds); * @param minB
let depth = result.normal.length() - circle.radius; * @param maxB
result.normal = Vector2Ext.normalize(result.normal); */
result.minimumTranslationVector = Vector2.multiply(new Vector2(depth), result.normal); public static intervalDistance(minA: number, maxA: number, minB: number, maxB) {
if (minA < minB)
return minB - maxA;
return result; return minA - minB;
} }
return null; /**
} * [minmax]
* @param axis
* @param polygon
* @param min
* @param max
*/
public static getInterval(axis: Vector2, polygon: Polygon, min: number, max: number) {
let dot = Vector2.dot(polygon.points[0], axis);
min = max = dot;
/** for (let i = 1; i < polygon.points.length; i++) {
* dot = Vector2.dot(polygon.points[i], axis);
* @param point if (dot < min) {
* @param circle min = dot;
*/ } else if (dot > max) {
public static pointToCircle(point: Vector2, circle: Circle) { max = dot;
let result = new CollisionResult(); }
}
let distanceSquared = Vector2.distanceSquared(point, circle.position); return { min: min, max: max };
let sumOfRadii = 1 + circle.radius;
let collided = distanceSquared < sumOfRadii * sumOfRadii;
if (collided) {
result.normal = Vector2.normalize(Vector2.subtract(point, circle.position));
let depth = sumOfRadii - Math.sqrt(distanceSquared);
result.minimumTranslationVector = Vector2.multiply(new Vector2(-depth, -depth), result.normal);
result.point = Vector2.add(circle.position, Vector2.multiply(result.normal, new Vector2(circle.radius, circle.radius)));
return result;
} }
return null; /**
} *
* @param circle
* @param polygon
*/
public static circleToPolygon(circle: Circle, polygon: Polygon) {
let result = new CollisionResult();
/** let poly2Circle = Vector2.subtract(circle.position, polygon.position);
*
* @param lineA
* @param lineB
* @param closestTo
*/
public static closestPointOnLine(lineA: Vector2, lineB: Vector2, closestTo: Vector2) {
let v = Vector2.subtract(lineB, lineA);
let w = Vector2.subtract(closestTo, lineA);
let t = Vector2.dot(w, v) / Vector2.dot(v, v);
t = MathHelper.clamp(t, 0, 1);
return Vector2.add(lineA, Vector2.multiply(v, new Vector2(t, t))); let gpp = Polygon.getClosestPointOnPolygonToPoint(polygon.points, poly2Circle);
} let closestPoint: Vector2 = gpp.closestPoint;
let distanceSquared: number = gpp.distanceSquared;
/**
*
* @param point
* @param poly
*/
public static pointToPoly(point: Vector2, poly: Polygon) {
let result = new CollisionResult();
if (poly.containsPoint(point)) {
let distanceSquared: number;
let gpp = Polygon.getClosestPointOnPolygonToPoint(poly.points, Vector2.subtract(point, poly.position));
let closestPoint = gpp.closestPoint;
distanceSquared = gpp.distanceSquared;
result.normal = gpp.edgeNormal; result.normal = gpp.edgeNormal;
result.minimumTranslationVector = Vector2.multiply(result.normal, new Vector2(Math.sqrt(distanceSquared), Math.sqrt(distanceSquared))); let circleCenterInsidePoly = polygon.containsPoint(circle.position);
result.point = Vector2.add(closestPoint, poly.position); if (distanceSquared > circle.radius * circle.radius && !circleCenterInsidePoly)
return result;
}
return null;
}
/**
*
* @param first
* @param second
*/
public static circleToCircle(first: Circle, second: Circle){
let result = new CollisionResult();
let distanceSquared = Vector2.distanceSquared(first.position, second.position);
let sumOfRadii = first.radius + second.radius;
let collided = distanceSquared < sumOfRadii * sumOfRadii;
if (collided){
result.normal = Vector2.normalize(Vector2.subtract(first.position, second.position));
let depth = sumOfRadii - Math.sqrt(distanceSquared);
result.minimumTranslationVector = Vector2.multiply(new Vector2(-depth), result.normal);
result.point = Vector2.add(second.position, Vector2.multiply(result.normal, new Vector2(second.radius)));
return result;
}
return null;
}
/**
*
* @param first
* @param second
*/
public static boxToBox(first: Box, second: Box){
let result = new CollisionResult();
let minkowskiDiff = this.minkowskiDifference(first, second);
if (minkowskiDiff.contains(0, 0)){
// 计算MTV。如果它是零,我们就可以称它为非碰撞
result.minimumTranslationVector = minkowskiDiff.getClosestPointOnBoundsToOrigin();
if (result.minimumTranslationVector.x == 0 && result.minimumTranslationVector.y == 0)
return null; return null;
result.normal = new Vector2(-result.minimumTranslationVector.x, -result.minimumTranslationVector.y); let mtv: Vector2;
result.normal.normalize(); if (circleCenterInsidePoly) {
mtv = Vector2.multiply(result.normal, new Vector2(Math.sqrt(distanceSquared) - circle.radius));
} else {
if (distanceSquared == 0) {
mtv = Vector2.multiply(result.normal, new Vector2(circle.radius));
} else {
let distance = Math.sqrt(distanceSquared);
mtv = Vector2.multiply(new Vector2(-Vector2.subtract(poly2Circle, closestPoint)), new Vector2((circle.radius - distanceSquared) / distance));
}
}
result.minimumTranslationVector = mtv;
result.point = Vector2.add(closestPoint, polygon.position);
return result; return result;
} }
return null; /**
} *
* @param circle
* @param box
*/
public static circleToBox(circle: Circle, box: Box): CollisionResult {
let result = new CollisionResult();
let closestPointOnBounds = box.bounds.getClosestPointOnRectangleBorderToPoint(circle.position).res;
private static minkowskiDifference(first: Box, second: Box){ if (box.containsPoint(circle.position)) {
// 我们需要第一个框的左上角 result.point = closestPointOnBounds;
// 碰撞器只会修改运动的位置所以我们需要用位置来计算出运动是什么。
let positionOffset = Vector2.subtract(first.position, Vector2.add(first.bounds.location, Vector2.divide(first.bounds.size, new Vector2(2))));
let topLeft = Vector2.subtract(Vector2.add(first.bounds.location, positionOffset), second.bounds.max);
let fullSize = Vector2.add(first.bounds.size, second.bounds.size);
return new Rectangle(topLeft.x, topLeft.y, fullSize.x, fullSize.y) let safePlace = Vector2.add(closestPointOnBounds, Vector2.subtract(result.normal, new Vector2(circle.radius)));
result.minimumTranslationVector = Vector2.subtract(circle.position, safePlace);
return result;
}
let sqrDistance = Vector2.distanceSquared(closestPointOnBounds, circle.position);
if (sqrDistance == 0) {
result.minimumTranslationVector = Vector2.multiply(result.normal, new Vector2(circle.radius));
} else if (sqrDistance <= circle.radius * circle.radius) {
result.normal = Vector2.subtract(circle.position, closestPointOnBounds);
let depth = result.normal.length() - circle.radius;
result.normal = Vector2Ext.normalize(result.normal);
result.minimumTranslationVector = Vector2.multiply(new Vector2(depth), result.normal);
return result;
}
return null;
}
/**
*
* @param point
* @param circle
*/
public static pointToCircle(point: Vector2, circle: Circle) {
let result = new CollisionResult();
let distanceSquared = Vector2.distanceSquared(point, circle.position);
let sumOfRadii = 1 + circle.radius;
let collided = distanceSquared < sumOfRadii * sumOfRadii;
if (collided) {
result.normal = Vector2.normalize(Vector2.subtract(point, circle.position));
let depth = sumOfRadii - Math.sqrt(distanceSquared);
result.minimumTranslationVector = Vector2.multiply(new Vector2(-depth, -depth), result.normal);
result.point = Vector2.add(circle.position, Vector2.multiply(result.normal, new Vector2(circle.radius, circle.radius)));
return result;
}
return null;
}
/**
*
* @param lineA
* @param lineB
* @param closestTo
*/
public static closestPointOnLine(lineA: Vector2, lineB: Vector2, closestTo: Vector2) {
let v = Vector2.subtract(lineB, lineA);
let w = Vector2.subtract(closestTo, lineA);
let t = Vector2.dot(w, v) / Vector2.dot(v, v);
t = MathHelper.clamp(t, 0, 1);
return Vector2.add(lineA, Vector2.multiply(v, new Vector2(t, t)));
}
/**
*
* @param point
* @param poly
*/
public static pointToPoly(point: Vector2, poly: Polygon) {
let result = new CollisionResult();
if (poly.containsPoint(point)) {
let distanceSquared: number;
let gpp = Polygon.getClosestPointOnPolygonToPoint(poly.points, Vector2.subtract(point, poly.position));
let closestPoint = gpp.closestPoint;
distanceSquared = gpp.distanceSquared;
result.normal = gpp.edgeNormal;
result.minimumTranslationVector = Vector2.multiply(result.normal, new Vector2(Math.sqrt(distanceSquared), Math.sqrt(distanceSquared)));
result.point = Vector2.add(closestPoint, poly.position);
return result;
}
return null;
}
/**
*
* @param first
* @param second
*/
public static circleToCircle(first: Circle, second: Circle){
let result = new CollisionResult();
let distanceSquared = Vector2.distanceSquared(first.position, second.position);
let sumOfRadii = first.radius + second.radius;
let collided = distanceSquared < sumOfRadii * sumOfRadii;
if (collided){
result.normal = Vector2.normalize(Vector2.subtract(first.position, second.position));
let depth = sumOfRadii - Math.sqrt(distanceSquared);
result.minimumTranslationVector = Vector2.multiply(new Vector2(-depth), result.normal);
result.point = Vector2.add(second.position, Vector2.multiply(result.normal, new Vector2(second.radius)));
return result;
}
return null;
}
/**
*
* @param first
* @param second
*/
public static boxToBox(first: Box, second: Box){
let result = new CollisionResult();
let minkowskiDiff = this.minkowskiDifference(first, second);
if (minkowskiDiff.contains(0, 0)){
// 计算MTV。如果它是零,我们就可以称它为非碰撞
result.minimumTranslationVector = minkowskiDiff.getClosestPointOnBoundsToOrigin();
if (result.minimumTranslationVector.x == 0 && result.minimumTranslationVector.y == 0)
return null;
result.normal = new Vector2(-result.minimumTranslationVector.x, -result.minimumTranslationVector.y);
result.normal.normalize();
return result;
}
return null;
}
private static minkowskiDifference(first: Box, second: Box){
// 我们需要第一个框的左上角
// 碰撞器只会修改运动的位置所以我们需要用位置来计算出运动是什么。
let positionOffset = Vector2.subtract(first.position, Vector2.add(first.bounds.location, Vector2.divide(first.bounds.size, new Vector2(2))));
let topLeft = Vector2.subtract(Vector2.add(first.bounds.location, positionOffset), second.bounds.max);
let fullSize = Vector2.add(first.bounds.size, second.bounds.size);
return new Rectangle(topLeft.x, topLeft.y, fullSize.x, fullSize.y)
}
} }
} }
+63 -61
View File
@@ -1,69 +1,71 @@
/** module es {
* /**
*/ *
class Layout { */
public clientArea: Rectangle; export class Layout {
public safeArea: Rectangle; public clientArea: Rectangle;
public safeArea: Rectangle;
constructor(){
this.clientArea = new Rectangle(0, 0, SceneManager.stage.stageWidth, SceneManager.stage.stageHeight);
this.safeArea = this.clientArea;
}
public place(size: Vector2, horizontalMargin: number, verticalMargine: number, alignment: Alignment){
let rc = new Rectangle(0, 0, size.x, size.y);
if ((alignment & Alignment.left) != 0){
rc.x = this.clientArea.x + (this.clientArea.width * horizontalMargin);
}else if((alignment & Alignment.right) != 0){
rc.x = this.clientArea.x + (this.clientArea.width * (1 - horizontalMargin)) - rc.width;
} else if((alignment & Alignment.horizontalCenter) != 0){
rc.x = this.clientArea.x + (this.clientArea.width - rc.width) / 2 + (horizontalMargin * this.clientArea.width);
}else{
constructor(){
this.clientArea = new Rectangle(0, 0, SceneManager.stage.stageWidth, SceneManager.stage.stageHeight);
this.safeArea = this.clientArea;
} }
if ((alignment & Alignment.top) != 0){ public place(size: Vector2, horizontalMargin: number, verticalMargine: number, alignment: Alignment){
rc.y = this.clientArea.y + (this.clientArea.height * verticalMargine); let rc = new Rectangle(0, 0, size.x, size.y);
}else if((alignment & Alignment.bottom) != 0){ if ((alignment & Alignment.left) != 0){
rc.y = this.clientArea.y + (this.clientArea.height * (1 - verticalMargine)) - rc.height; rc.x = this.clientArea.x + (this.clientArea.width * horizontalMargin);
} else if((alignment & Alignment.verticalCenter) != 0){ }else if((alignment & Alignment.right) != 0){
rc.y = this.clientArea.y + (this.clientArea.height - rc.height) / 2 + (verticalMargine * this.clientArea.height); rc.x = this.clientArea.x + (this.clientArea.width * (1 - horizontalMargin)) - rc.width;
}else{ } else if((alignment & Alignment.horizontalCenter) != 0){
rc.x = this.clientArea.x + (this.clientArea.width - rc.width) / 2 + (horizontalMargin * this.clientArea.width);
}else{
}
if ((alignment & Alignment.top) != 0){
rc.y = this.clientArea.y + (this.clientArea.height * verticalMargine);
}else if((alignment & Alignment.bottom) != 0){
rc.y = this.clientArea.y + (this.clientArea.height * (1 - verticalMargine)) - rc.height;
} else if((alignment & Alignment.verticalCenter) != 0){
rc.y = this.clientArea.y + (this.clientArea.height - rc.height) / 2 + (verticalMargine * this.clientArea.height);
}else{
}
// 确保布局区域在安全区域内。
if (rc.left < this.safeArea.left)
rc.x = this.safeArea.left;
if (rc.right > this.safeArea.right)
rc.x = this.safeArea.right - rc.width;
if (rc.top < this.safeArea.top)
rc.y = this.safeArea.top;
if (rc.bottom > this.safeArea.bottom)
rc.y = this.safeArea.bottom - rc.height;
return rc;
} }
}
// 确保布局区域在安全区域内。 export enum Alignment {
if (rc.left < this.safeArea.left) none = 0,
rc.x = this.safeArea.left; left = 1,
right = 2,
if (rc.right > this.safeArea.right) horizontalCenter = 4,
rc.x = this.safeArea.right - rc.width; top = 8,
bottom = 16,
if (rc.top < this.safeArea.top) verticalCenter = 32,
rc.y = this.safeArea.top; topLeft = top | left,
topRight = top | right,
if (rc.bottom > this.safeArea.bottom) topCenter = top | horizontalCenter,
rc.y = this.safeArea.bottom - rc.height; bottomLeft = bottom | left,
bottomRight = bottom | right,
return rc; bottomCenter = bottom | horizontalCenter,
centerLeft = verticalCenter | left,
centerRight = verticalCenter | right,
center = verticalCenter | horizontalCenter
} }
} }
enum Alignment {
none = 0,
left = 1,
right = 2,
horizontalCenter = 4,
top = 8,
bottom = 16,
verticalCenter = 32,
topLeft = top | left,
topRight = top | right,
topCenter = top | horizontalCenter,
bottomLeft = bottom | left,
bottomRight = bottom | right,
bottomCenter = bottom | horizontalCenter,
centerLeft = verticalCenter | left,
centerRight = verticalCenter | right,
center = verticalCenter | horizontalCenter
}
+321 -319
View File
@@ -1,349 +1,351 @@
/** module es {
* 使CPU使用情况
*/
class TimeRuler {
/** 最大条数 8 */
public static readonly maxBars = 8;
/** */
public static readonly maxSamples = 256;
/** 每条的最大嵌套调用 */
public static readonly maxNestCall = 32;
/** 条的高度(以像素为单位) */
public static readonly barHeight = 8;
/** 最大显示帧 */
public static readonly maxSampleFrames = 4;
/** 持续时间(帧数)为采取抓拍日志。 */
public static readonly logSnapDuration = 120;
public static readonly barPadding = 2;
public static readonly autoAdjustDelay = 30;
public static Instance: TimeRuler;
private _frameKey = 'frame';
private _logKey = 'log';
/** 每帧的日志 */
private _logs: FrameLog[];
/** 当前显示帧计数 */
private sampleFrames: number;
/** 获取/设置目标样本帧。 */
public targetSampleFrames: number;
/** 获取/设置计时器标尺宽度。 */
public width: number;
public enabled: true;
/** TimerRuler画的位置。 */
private _position: Vector2;
/** 上一帧日志 */
private _prevLog: FrameLog;
/** 当前帧日志 */
private _curLog: FrameLog;
/** 当前帧数量 */
private frameCount: number;
/** */
private markers: MarkerInfo[] = [];
/** 秒表用来测量时间。 */
private stopwacth: stopwatch.Stopwatch = new stopwatch.Stopwatch();
/** 从标记名映射到标记id的字典。 */
private _markerNameToIdMap: Map<string, number> = new Map<string, number>();
/** /**
* StartFrame更新方法 * 使CPU使用情况
*
* StartFrame调用
* StartFrame调用的次数Draw被调用
*/ */
private _updateCount: number; export class TimeRuler {
/** */ /** 最大条数 8 */
public showLog = false; public static readonly maxBars = 8;
private _frameAdjust: number; /** */
public static readonly maxSamples = 256;
/** 每条的最大嵌套调用 */
public static readonly maxNestCall = 32;
/** 条的高度(以像素为单位) */
public static readonly barHeight = 8;
/** 最大显示帧 */
public static readonly maxSampleFrames = 4;
/** 持续时间(帧数)为采取抓拍日志。 */
public static readonly logSnapDuration = 120;
public static readonly barPadding = 2;
public static readonly autoAdjustDelay = 30;
public static Instance: TimeRuler;
private _frameKey = 'frame';
private _logKey = 'log';
constructor() { /** 每帧的日志 */
TimeRuler.Instance = this; private _logs: FrameLog[];
this._logs = new Array<FrameLog>(2); /** 当前显示帧计数 */
for (let i = 0; i < this._logs.length; ++i) private sampleFrames: number;
this._logs[i] = new FrameLog(); /** 获取/设置目标样本帧。 */
public targetSampleFrames: number;
/** 获取/设置计时器标尺宽度。 */
public width: number;
public enabled: true;
/** TimerRuler画的位置。 */
private _position: Vector2;
/** 上一帧日志 */
private _prevLog: FrameLog;
/** 当前帧日志 */
private _curLog: FrameLog;
/** 当前帧数量 */
private frameCount: number;
/** */
private markers: MarkerInfo[] = [];
/** 秒表用来测量时间。 */
private stopwacth: stopwatch.Stopwatch = new stopwatch.Stopwatch();
/** 从标记名映射到标记id的字典。 */
private _markerNameToIdMap: Map<string, number> = new Map<string, number>();
/**
* StartFrame更新方法
*
* StartFrame调用
* StartFrame调用的次数Draw被调用
*/
private _updateCount: number;
/** */
public showLog = false;
private _frameAdjust: number;
this.sampleFrames = this.targetSampleFrames = 1; constructor() {
this.width = SceneManager.stage.stageWidth * 0.8; TimeRuler.Instance = this;
this.onGraphicsDeviceReset(); this._logs = new Array<FrameLog>(2);
} for (let i = 0; i < this._logs.length; ++i)
this._logs[i] = new FrameLog();
private onGraphicsDeviceReset() { this.sampleFrames = this.targetSampleFrames = 1;
let layout = new Layout(); this.width = SceneManager.stage.stageWidth * 0.8;
this._position = layout.place(new Vector2(this.width, TimeRuler.barHeight), 0, 0.01, Alignment.bottomCenter).location; this.onGraphicsDeviceReset();
} }
/** private onGraphicsDeviceReset() {
* let layout = new Layout();
*/ this._position = layout.place(new Vector2(this.width, TimeRuler.barHeight), 0, 0.01, Alignment.bottomCenter).location;
public startFrame() { }
// 当这个方法被多次调用时,我们跳过重置帧。
let lock = new LockUtils(this._frameKey);
lock.lock().then(() => {
this._updateCount = parseInt(egret.localStorage.getItem(this._frameKey), 10);
if (isNaN(this._updateCount))
this._updateCount = 0;
let count = this._updateCount;
count += 1;
egret.localStorage.setItem(this._frameKey, count.toString());
if (this.enabled && (1 < count && count < TimeRuler.maxSampleFrames))
return;
// 更新当前帧日志。 /**
this._prevLog = this._logs[this.frameCount++ & 0x1]; *
this._curLog = this._logs[this.frameCount & 0x1]; */
public startFrame() {
// 当这个方法被多次调用时,我们跳过重置帧。
let lock = new LockUtils(this._frameKey);
lock.lock().then(() => {
this._updateCount = parseInt(egret.localStorage.getItem(this._frameKey), 10);
if (isNaN(this._updateCount))
this._updateCount = 0;
let count = this._updateCount;
count += 1;
egret.localStorage.setItem(this._frameKey, count.toString());
if (this.enabled && (1 < count && count < TimeRuler.maxSampleFrames))
return;
let endFrameTime = this.stopwacth.getTime(); // 更新当前帧日志。
// 更新标记并创建日志。 this._prevLog = this._logs[this.frameCount++ & 0x1];
for (let barIndex = 0; barIndex < this._prevLog.bars.length; ++barIndex) { this._curLog = this._logs[this.frameCount & 0x1];
let prevBar = this._prevLog.bars[barIndex];
let nextBar = this._curLog.bars[barIndex];
// 重新打开在前一帧中没有调用结束标记的标记。 let endFrameTime = this.stopwacth.getTime();
for (let nest = 0; nest < prevBar.nestCount; ++nest) { // 更新标记并创建日志。
let markerIdx = prevBar.markerNests[nest]; for (let barIndex = 0; barIndex < this._prevLog.bars.length; ++barIndex) {
prevBar.markers[markerIdx].endTime = endFrameTime; let prevBar = this._prevLog.bars[barIndex];
nextBar.markerNests[nest] = nest; let nextBar = this._curLog.bars[barIndex];
nextBar.markers[nest].markerId = prevBar.markers[markerIdx].markerId;
nextBar.markers[nest].beginTime = 0;
nextBar.markers[nest].endTime = -1;
nextBar.markers[nest].color = prevBar.markers[markerIdx].color;
}
// 更新日志标记 // 重新打开在前一帧中没有调用结束标记的标记。
for (let markerIdx = 0; markerIdx < prevBar.markCount; ++markerIdx) { for (let nest = 0; nest < prevBar.nestCount; ++nest) {
let duration = prevBar.markers[markerIdx].endTime - prevBar.markers[markerIdx].beginTime; let markerIdx = prevBar.markerNests[nest];
let markerId = prevBar.markers[markerIdx].markerId; prevBar.markers[markerIdx].endTime = endFrameTime;
let m = this.markers[markerId]; nextBar.markerNests[nest] = nest;
nextBar.markers[nest].markerId = prevBar.markers[markerIdx].markerId;
nextBar.markers[nest].beginTime = 0;
nextBar.markers[nest].endTime = -1;
nextBar.markers[nest].color = prevBar.markers[markerIdx].color;
}
m.logs[barIndex].color = prevBar.markers[markerIdx].color; // 更新日志标记
if (!m.logs[barIndex].initialized) { for (let markerIdx = 0; markerIdx < prevBar.markCount; ++markerIdx) {
m.logs[barIndex].min = duration; let duration = prevBar.markers[markerIdx].endTime - prevBar.markers[markerIdx].beginTime;
m.logs[barIndex].max = duration; let markerId = prevBar.markers[markerIdx].markerId;
m.logs[barIndex].avg = duration; let m = this.markers[markerId];
m.logs[barIndex].initialized = true;
} else {
m.logs[barIndex].min = Math.min(m.logs[barIndex].min, duration);
m.logs[barIndex].max = Math.min(m.logs[barIndex].max, duration);
m.logs[barIndex].avg += duration;
m.logs[barIndex].avg *= 0.5;
if (m.logs[barIndex].samples++ >= TimeRuler.logSnapDuration) { m.logs[barIndex].color = prevBar.markers[markerIdx].color;
m.logs[barIndex].snapMin = m.logs[barIndex].min; if (!m.logs[barIndex].initialized) {
m.logs[barIndex].snapMax = m.logs[barIndex].max; m.logs[barIndex].min = duration;
m.logs[barIndex].snapAvg = m.logs[barIndex].avg; m.logs[barIndex].max = duration;
m.logs[barIndex].samples = 0; m.logs[barIndex].avg = duration;
m.logs[barIndex].initialized = true;
} else {
m.logs[barIndex].min = Math.min(m.logs[barIndex].min, duration);
m.logs[barIndex].max = Math.min(m.logs[barIndex].max, duration);
m.logs[barIndex].avg += duration;
m.logs[barIndex].avg *= 0.5;
if (m.logs[barIndex].samples++ >= TimeRuler.logSnapDuration) {
m.logs[barIndex].snapMin = m.logs[barIndex].min;
m.logs[barIndex].snapMax = m.logs[barIndex].max;
m.logs[barIndex].snapAvg = m.logs[barIndex].avg;
m.logs[barIndex].samples = 0;
}
} }
} }
nextBar.markCount = prevBar.nestCount;
nextBar.nestCount = prevBar.nestCount;
} }
nextBar.markCount = prevBar.nestCount; this.stopwacth.reset();
nextBar.nestCount = prevBar.nestCount; this.stopwacth.start();
}
this.stopwacth.reset();
this.stopwacth.start();
});
}
/**
*
* @param markerName
* @param color
*/
public beginMark(markerName: string, color: number, barIndex: number = 0) {
let lock = new LockUtils(this._frameKey);
lock.lock().then(() => {
if (barIndex < 0 || barIndex >= TimeRuler.maxBars)
throw new Error("barIndex argument out of range");
let bar = this._curLog.bars[barIndex];
if (bar.markCount >= TimeRuler.maxSamples) {
throw new Error("exceeded sample count. either set larger number to timeruler.maxsaple or lower sample count");
}
if (bar.nestCount >= TimeRuler.maxNestCall) {
throw new Error("exceeded nest count. either set larger number to timeruler.maxnestcall or lower nest calls");
}
// 获取注册的标记
let markerId = this._markerNameToIdMap.get(markerName);
if (isNaN(markerId)) {
// 如果此标记未注册,则注册此标记。
markerId = this.markers.length;
this._markerNameToIdMap.set(markerName, markerId);
}
bar.markerNests[bar.nestCount++] = bar.markCount;
bar.markers[bar.markCount].markerId = markerId;
bar.markers[bar.markCount].color = color;
bar.markers[bar.markCount].beginTime = this.stopwacth.getTime();
bar.markers[bar.markCount].endTime = -1;
});
}
/**
*
* @param markerName
* @param barIndex
*/
public endMark(markerName: string, barIndex: number = 0) {
let lock = new LockUtils(this._frameKey);
lock.lock().then(() => {
if (barIndex < 0 || barIndex >= TimeRuler.maxBars)
throw new Error("barIndex argument out of range");
let bar = this._curLog.bars[barIndex];
if (bar.nestCount <= 0) {
throw new Error("call beginMark method before calling endMark method");
}
let markerId = this._markerNameToIdMap.get(markerName);
if (isNaN(markerId)) {
throw new Error(`Marker ${markerName} is not registered. Make sure you specifed same name as you used for beginMark method`);
}
let markerIdx = bar.markerNests[--bar.nestCount];
if (bar.markers[markerIdx].markerId != markerId) {
throw new Error("Incorrect call order of beginMark/endMark method. beginMark(A), beginMark(B), endMark(B), endMark(A) But you can't called it like beginMark(A), beginMark(B), endMark(A), endMark(B).");
}
bar.markers[markerIdx].endTime = this.stopwacth.getTime();
});
}
/**
* bar索引和标记名称的平均时间
* @param barIndex
* @param markerName
*/
public getAverageTime(barIndex: number, markerName: string) {
if (barIndex < 0 || barIndex >= TimeRuler.maxBars) {
throw new Error("barIndex argument out of range");
}
let result = 0;
let markerId = this._markerNameToIdMap.get(markerName);
if (markerId) {
result = this.markers[markerId].logs[barIndex].avg;
}
return result;
}
/**
*
*/
public resetLog() {
let lock = new LockUtils(this._logKey);
lock.lock().then(() => {
let count = parseInt(egret.localStorage.getItem(this._logKey), 10);
count += 1;
egret.localStorage.setItem(this._logKey, count.toString());
this.markers.forEach(markerInfo => {
for (let i = 0; i < markerInfo.logs.length; ++i){
markerInfo.logs[i].initialized = false;
markerInfo.logs[i].snapMin = 0;
markerInfo.logs[i].snapMax = 0;
markerInfo.logs[i].snapAvg = 0;
markerInfo.logs[i].min = 0;
markerInfo.logs[i].max = 0;
markerInfo.logs[i].avg = 0;
markerInfo.logs[i].samples = 0;
}
}); });
}); }
}
public render(position: Vector2 = this._position, width: number = this.width){ /**
egret.localStorage.setItem(this._frameKey, "0"); *
* @param markerName
* @param color
*/
public beginMark(markerName: string, color: number, barIndex: number = 0) {
let lock = new LockUtils(this._frameKey);
lock.lock().then(() => {
if (barIndex < 0 || barIndex >= TimeRuler.maxBars)
throw new Error("barIndex argument out of range");
if (!this.showLog) let bar = this._curLog.bars[barIndex];
return; if (bar.markCount >= TimeRuler.maxSamples) {
throw new Error("exceeded sample count. either set larger number to timeruler.maxsaple or lower sample count");
}
let height = 0; if (bar.nestCount >= TimeRuler.maxNestCall) {
let maxTime = 0; throw new Error("exceeded nest count. either set larger number to timeruler.maxnestcall or lower nest calls");
this._prevLog.bars.forEach(bar => { }
if (bar.markCount > 0){
height += TimeRuler.barHeight + TimeRuler.barPadding * 2; // 获取注册的标记
maxTime = Math.max(maxTime, bar.markers[bar.markCount - 1].endTime); let markerId = this._markerNameToIdMap.get(markerName);
if (isNaN(markerId)) {
// 如果此标记未注册,则注册此标记。
markerId = this.markers.length;
this._markerNameToIdMap.set(markerName, markerId);
}
bar.markerNests[bar.nestCount++] = bar.markCount;
bar.markers[bar.markCount].markerId = markerId;
bar.markers[bar.markCount].color = color;
bar.markers[bar.markCount].beginTime = this.stopwacth.getTime();
bar.markers[bar.markCount].endTime = -1;
});
}
/**
*
* @param markerName
* @param barIndex
*/
public endMark(markerName: string, barIndex: number = 0) {
let lock = new LockUtils(this._frameKey);
lock.lock().then(() => {
if (barIndex < 0 || barIndex >= TimeRuler.maxBars)
throw new Error("barIndex argument out of range");
let bar = this._curLog.bars[barIndex];
if (bar.nestCount <= 0) {
throw new Error("call beginMark method before calling endMark method");
}
let markerId = this._markerNameToIdMap.get(markerName);
if (isNaN(markerId)) {
throw new Error(`Marker ${markerName} is not registered. Make sure you specifed same name as you used for beginMark method`);
}
let markerIdx = bar.markerNests[--bar.nestCount];
if (bar.markers[markerIdx].markerId != markerId) {
throw new Error("Incorrect call order of beginMark/endMark method. beginMark(A), beginMark(B), endMark(B), endMark(A) But you can't called it like beginMark(A), beginMark(B), endMark(A), endMark(B).");
}
bar.markers[markerIdx].endTime = this.stopwacth.getTime();
});
}
/**
* bar索引和标记名称的平均时间
* @param barIndex
* @param markerName
*/
public getAverageTime(barIndex: number, markerName: string) {
if (barIndex < 0 || barIndex >= TimeRuler.maxBars) {
throw new Error("barIndex argument out of range");
}
let result = 0;
let markerId = this._markerNameToIdMap.get(markerName);
if (markerId) {
result = this.markers[markerId].logs[barIndex].avg;
} }
})
const frameSpan = 1 / 60 * 1000; return result;
let sampleSpan = this.sampleFrames * frameSpan;
if (maxTime > sampleSpan){
this._frameAdjust = Math.max(0, this._frameAdjust) + 1;
}else{
this._frameAdjust = Math.min(0, this._frameAdjust) - 1;
} }
if (Math.max(this._frameAdjust) > TimeRuler.autoAdjustDelay){ /**
this.sampleFrames = Math.min(TimeRuler.maxSampleFrames, this.sampleFrames); *
this.sampleFrames = Math.max(this.targetSampleFrames, (maxTime / frameSpan) + 1); */
public resetLog() {
let lock = new LockUtils(this._logKey);
lock.lock().then(() => {
let count = parseInt(egret.localStorage.getItem(this._logKey), 10);
count += 1;
egret.localStorage.setItem(this._logKey, count.toString());
this.markers.forEach(markerInfo => {
for (let i = 0; i < markerInfo.logs.length; ++i){
markerInfo.logs[i].initialized = false;
markerInfo.logs[i].snapMin = 0;
markerInfo.logs[i].snapMax = 0;
markerInfo.logs[i].snapAvg = 0;
this._frameAdjust = 0; markerInfo.logs[i].min = 0;
markerInfo.logs[i].max = 0;
markerInfo.logs[i].avg = 0;
markerInfo.logs[i].samples = 0;
}
});
});
} }
let msToPs = width / sampleSpan; public render(position: Vector2 = this._position, width: number = this.width){
let startY = position.y - (height - TimeRuler.barHeight); egret.localStorage.setItem(this._frameKey, "0");
let y = startY;
// TODO: draw if (!this.showLog)
return;
let height = 0;
let maxTime = 0;
this._prevLog.bars.forEach(bar => {
if (bar.markCount > 0){
height += TimeRuler.barHeight + TimeRuler.barPadding * 2;
maxTime = Math.max(maxTime, bar.markers[bar.markCount - 1].endTime);
}
})
const frameSpan = 1 / 60 * 1000;
let sampleSpan = this.sampleFrames * frameSpan;
if (maxTime > sampleSpan){
this._frameAdjust = Math.max(0, this._frameAdjust) + 1;
}else{
this._frameAdjust = Math.min(0, this._frameAdjust) - 1;
}
if (Math.max(this._frameAdjust) > TimeRuler.autoAdjustDelay){
this.sampleFrames = Math.min(TimeRuler.maxSampleFrames, this.sampleFrames);
this.sampleFrames = Math.max(this.targetSampleFrames, (maxTime / frameSpan) + 1);
this._frameAdjust = 0;
}
let msToPs = width / sampleSpan;
let startY = position.y - (height - TimeRuler.barHeight);
let y = startY;
// TODO: draw
}
}
/**
*
*/
export class FrameLog {
public bars: MarkerCollection[];
constructor() {
this.bars = new Array<MarkerCollection>(TimeRuler.maxBars);
this.bars.fill(new MarkerCollection(), 0, TimeRuler.maxBars);
}
}
/**
*
*/
export class MarkerCollection {
public markers: Marker[] = new Array<Marker>(TimeRuler.maxSamples);
public markCount: number = 0;
public markerNests: number[] = new Array<number>(TimeRuler.maxNestCall);
public nestCount: number = 0;
constructor(){
this.markers.fill(new Marker(), 0, TimeRuler.maxSamples);
this.markerNests.fill(0, 0, TimeRuler.maxNestCall);
}
}
export class Marker {
public markerId: number = 0;
public beginTime: number = 0;
public endTime: number = 0;
public color: number = 0x000000;
}
export class MarkerInfo {
public name: string;
public logs: MarkerLog[] = new Array<MarkerLog>(TimeRuler.maxBars);
constructor(name) {
this.name = name;
this.logs.fill(new MarkerLog(), 0, TimeRuler.maxBars);
}
}
export class MarkerLog {
public snapMin: number = 0;
public snapMax: number = 0;
public snapAvg: number = 0;
public min: number = 0;
public max: number = 0;
public avg: number = 0;
public samples: number = 0;
public color: number = 0x000000;
public initialized: boolean = false;
} }
} }
/**
*
*/
class FrameLog {
public bars: MarkerCollection[];
constructor() {
this.bars = new Array<MarkerCollection>(TimeRuler.maxBars);
this.bars.fill(new MarkerCollection(), 0, TimeRuler.maxBars);
}
}
/**
*
*/
class MarkerCollection {
public markers: Marker[] = new Array<Marker>(TimeRuler.maxSamples);
public markCount: number = 0;
public markerNests: number[] = new Array<number>(TimeRuler.maxNestCall);
public nestCount: number = 0;
constructor(){
this.markers.fill(new Marker(), 0, TimeRuler.maxSamples);
this.markerNests.fill(0, 0, TimeRuler.maxNestCall);
}
}
class Marker {
public markerId: number = 0;
public beginTime: number = 0;
public endTime: number = 0;
public color: number = 0x000000;
}
class MarkerInfo {
public name: string;
public logs: MarkerLog[] = new Array<MarkerLog>(TimeRuler.maxBars);
constructor(name) {
this.name = name;
this.logs.fill(new MarkerLog(), 0, TimeRuler.maxBars);
}
}
class MarkerLog {
public snapMin: number = 0;
public snapMax: number = 0;
public snapAvg: number = 0;
public min: number = 0;
public max: number = 0;
public avg: number = 0;
public samples: number = 0;
public color: number = 0x000000;
public initialized: boolean = false;
}
+37 -35
View File
@@ -1,41 +1,43 @@
class ContentManager { module es {
protected loadedAssets: Map<string, any> = new Map<string, any>(); export class ContentManager {
protected loadedAssets: Map<string, any> = new Map<string, any>();
/** 异步加载资源 */ /** 异步加载资源 */
public loadRes(name: string, local: boolean = true): Promise<any> { public loadRes(name: string, local: boolean = true): Promise<any> {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
let res = this.loadedAssets.get(name); let res = this.loadedAssets.get(name);
if (res) { if (res) {
resolve(res); resolve(res);
return; return;
} }
if (local) { if (local) {
RES.getResAsync(name).then((data) => { RES.getResAsync(name).then((data) => {
this.loadedAssets.set(name, data); this.loadedAssets.set(name, data);
resolve(data); resolve(data);
}).catch((err) => { }).catch((err) => {
console.error("资源加载错误:", name, err); console.error("资源加载错误:", name, err);
reject(err); reject(err);
}); });
} else { } else {
RES.getResByUrl(name).then((data) => { RES.getResByUrl(name).then((data) => {
this.loadedAssets.set(name, data); this.loadedAssets.set(name, data);
resolve(data); resolve(data);
}).catch((err) => { }).catch((err) => {
console.error("资源加载错误:", name, err); console.error("资源加载错误:", name, err);
reject(err); reject(err);
}); });
} }
}); });
} }
public dispose() { public dispose() {
this.loadedAssets.forEach(value => { this.loadedAssets.forEach(value => {
let assetsToRemove = value; let assetsToRemove = value;
assetsToRemove.dispose(); assetsToRemove.dispose();
}); });
this.loadedAssets.clear(); this.loadedAssets.clear();
}
} }
} }
+56 -54
View File
@@ -1,59 +1,61 @@
/** 各种辅助方法来辅助绘图 */ module es {
class DrawUtils { /** 各种辅助方法来辅助绘图 */
public static drawLine(shape: egret.Shape, start: Vector2, end: Vector2, color: number, thickness: number = 1){ export class DrawUtils {
this.drawLineAngle(shape, start, MathHelper.angleBetweenVectors(start, end), Vector2.distance(start, end), color, thickness); public static drawLine(shape: egret.Shape, start: Vector2, end: Vector2, color: number, thickness: number = 1){
} this.drawLineAngle(shape, start, MathHelper.angleBetweenVectors(start, end), Vector2.distance(start, end), color, thickness);
public static drawLineAngle(shape: egret.Shape, start: Vector2, radians: number, length: number, color: number, thickness = 1){
shape.graphics.beginFill(color);
shape.graphics.drawRect(start.x, start.y, 1, 1);
shape.graphics.endFill();
shape.scaleX = length;
shape.scaleY = thickness;
shape.$anchorOffsetX = 0;
shape.$anchorOffsetY = 0;
shape.rotation = radians;
}
public static drawHollowRect(shape: egret.Shape, rect: Rectangle, color: number, thickness = 1){
this.drawHollowRectR(shape, rect.x, rect.y, rect.width, rect.height, color, thickness);
}
public static drawHollowRectR(shape: egret.Shape, x: number, y: number, width: number, height: number, color: number, thickness = 1){
let tl = new Vector2(x, y).round();
let tr = new Vector2(x + width, y).round();
let br = new Vector2(x + width, y + height).round();
let bl = new Vector2(x, y + height).round();
this.drawLine(shape, tl, tr, color, thickness);
this.drawLine(shape, tr, br, color, thickness);
this.drawLine(shape, br, bl, color, thickness);
this.drawLine(shape, bl, tl, color, thickness);
}
public static drawPixel(shape: egret.Shape, position: Vector2, color: number, size: number = 1){
let destRect = new Rectangle(position.x, position.y, size, size);
if (size != 1){
destRect.x -= size * 0.5;
destRect.y -= size * 0.5;
} }
shape.graphics.beginFill(color); public static drawLineAngle(shape: egret.Shape, start: Vector2, radians: number, length: number, color: number, thickness = 1){
shape.graphics.drawRect(destRect.x, destRect.y, destRect.width, destRect.height); shape.graphics.beginFill(color);
shape.graphics.endFill(); shape.graphics.drawRect(start.x, start.y, 1, 1);
} shape.graphics.endFill();
public static getColorMatrix(color: number): egret.ColorMatrixFilter{ shape.scaleX = length;
let colorMatrix = [ shape.scaleY = thickness;
1, 0, 0, 0, 0, shape.$anchorOffsetX = 0;
0, 1, 0, 0, 0, shape.$anchorOffsetY = 0;
0, 0, 1, 0, 0, shape.rotation = radians;
0, 0, 0, 1, 0 }
];
colorMatrix[0] = Math.floor(color / 256 / 256) / 255; public static drawHollowRect(shape: egret.Shape, rect: Rectangle, color: number, thickness = 1){
colorMatrix[6] = Math.floor(color / 256 % 256) / 255; this.drawHollowRectR(shape, rect.x, rect.y, rect.width, rect.height, color, thickness);
colorMatrix[12] = color % 256 / 255; }
return new egret.ColorMatrixFilter(colorMatrix);
public static drawHollowRectR(shape: egret.Shape, x: number, y: number, width: number, height: number, color: number, thickness = 1){
let tl = new Vector2(x, y).round();
let tr = new Vector2(x + width, y).round();
let br = new Vector2(x + width, y + height).round();
let bl = new Vector2(x, y + height).round();
this.drawLine(shape, tl, tr, color, thickness);
this.drawLine(shape, tr, br, color, thickness);
this.drawLine(shape, br, bl, color, thickness);
this.drawLine(shape, bl, tl, color, thickness);
}
public static drawPixel(shape: egret.Shape, position: Vector2, color: number, size: number = 1){
let destRect = new Rectangle(position.x, position.y, size, size);
if (size != 1){
destRect.x -= size * 0.5;
destRect.y -= size * 0.5;
}
shape.graphics.beginFill(color);
shape.graphics.drawRect(destRect.x, destRect.y, destRect.width, destRect.height);
shape.graphics.endFill();
}
public static getColorMatrix(color: number): egret.ColorMatrixFilter{
let colorMatrix = [
1, 0, 0, 0, 0,
0, 1, 0, 0, 0,
0, 0, 1, 0, 0,
0, 0, 0, 1, 0
];
colorMatrix[0] = Math.floor(color / 256 / 256) / 255;
colorMatrix[6] = Math.floor(color / 256 % 256) / 255;
colorMatrix[12] = color % 256 / 255;
return new egret.ColorMatrixFilter(colorMatrix);
}
} }
} }
+60 -59
View File
@@ -1,68 +1,69 @@
/** module es {
*
*/
class Emitter<T> {
private _messageTable: Map<T, FuncPack[]>;
constructor(){
this._messageTable = new Map<T, FuncPack[]>();
}
/** /**
* *
* @param eventType
* @param handler
* @param context
*/ */
public addObserver(eventType: T, handler: Function, context: any){ export class FuncPack {
let list: FuncPack[] = this._messageTable.get(eventType); /** 函数 */
if (!list){ public func: Function;
list = []; /** 上下文 */
this._messageTable.set(eventType, list); public context: any;
constructor(func: Function, context: any){
this.func = func;
this.context = context;
}
}
/**
*
*/
export class Emitter<T> {
private _messageTable: Map<T, FuncPack[]>;
constructor(){
this._messageTable = new Map<T, FuncPack[]>();
} }
if (list.contains(handler)) /**
console.warn("您试图添加相同的观察者两次"); *
list.push(new FuncPack(handler, context)); * @param eventType
} * @param handler
* @param context
*/
public addObserver(eventType: T, handler: Function, context: any){
let list: FuncPack[] = this._messageTable.get(eventType);
if (!list){
list = [];
this._messageTable.set(eventType, list);
}
/** if (list.contains(handler))
* console.warn("您试图添加相同的观察者两次");
* @param eventType list.push(new FuncPack(handler, context));
* @param handler }
*/
public removeObserver(eventType: T, handler: Function){
let messageData = this._messageTable.get(eventType);
let index = messageData.findIndex(data => data.func == handler);
if (index != -1)
messageData.removeAt(index);
}
/** /**
* *
* @param eventType * @param eventType
* @param data * @param handler
*/ */
public emit(eventType: T, data?: any){ public removeObserver(eventType: T, handler: Function){
let list: FuncPack[] = this._messageTable.get(eventType); let messageData = this._messageTable.get(eventType);
if (list){ let index = messageData.findIndex(data => data.func == handler);
for (let i = list.length - 1; i >= 0; i --) if (index != -1)
list[i].func.call(list[i].context, data); messageData.removeAt(index);
}
/**
*
* @param eventType
* @param data
*/
public emit(eventType: T, data?: any){
let list: FuncPack[] = this._messageTable.get(eventType);
if (list){
for (let i = list.length - 1; i >= 0; i --)
list[i].func.call(list[i].context, data);
}
} }
} }
} }
/**
*
*/
class FuncPack {
/** 函数 */
public func: Function;
/** 上下文 */
public context: any;
constructor(func: Function, context: any){
this.func = func;
this.context = context;
}
}
+37 -35
View File
@@ -1,46 +1,48 @@
class GlobalManager { module es {
public static globalManagers: GlobalManager[] = []; export class GlobalManager {
private _enabled: boolean; public static globalManagers: GlobalManager[] = [];
private _enabled: boolean;
public get enabled(){ public get enabled(){
return this._enabled; return this._enabled;
} }
public set enabled(value: boolean){ public set enabled(value: boolean){
this.setEnabled(value); this.setEnabled(value);
} }
public setEnabled(isEnabled: boolean){ public setEnabled(isEnabled: boolean){
if (this._enabled != isEnabled){ if (this._enabled != isEnabled){
this._enabled = isEnabled; this._enabled = isEnabled;
if (this._enabled){ if (this._enabled){
this.onEnabled(); this.onEnabled();
} else { } else {
this.onDisabled(); this.onDisabled();
}
} }
} }
}
public onEnabled(){} public onEnabled(){}
public onDisabled(){} public onDisabled(){}
public update(){} public update(){}
public static registerGlobalManager(manager: GlobalManager){ public static registerGlobalManager(manager: GlobalManager){
this.globalManagers.push(manager); this.globalManagers.push(manager);
manager.enabled = true; manager.enabled = true;
}
public static unregisterGlobalManager(manager: GlobalManager){
this.globalManagers.remove(manager);
manager.enabled = false;
}
public static getGlobalManager<T extends GlobalManager>(type){
for (let i = 0; i < this.globalManagers.length; i ++){
if (this.globalManagers[i] instanceof type)
return this.globalManagers[i] as T;
} }
return null; public static unregisterGlobalManager(manager: GlobalManager){
this.globalManagers.remove(manager);
manager.enabled = false;
}
public static getGlobalManager<T extends GlobalManager>(type){
for (let i = 0; i < this.globalManagers.length; i ++){
if (this.globalManagers[i] instanceof type)
return this.globalManagers[i] as T;
}
return null;
}
} }
} }
+133 -131
View File
@@ -1,147 +1,149 @@
class TouchState { module es {
public x = 0; export class TouchState {
public y = 0; public x = 0;
public touchPoint: number = -1; public y = 0;
public touchDown: boolean = false; public touchPoint: number = -1;
public get position(){ public touchDown: boolean = false;
return new Vector2(this.x, this.y); public get position(){
} return new Vector2(this.x, this.y);
public reset(){
this.x = 0;
this.y = 0;
this.touchDown = false;
this.touchPoint = -1;
}
}
class Input {
private static _init: boolean = false;
private static _stage: egret.Stage;
private static _previousTouchState: TouchState = new TouchState();
private static _gameTouchs: TouchState[] = [];
private static _resolutionOffset: Vector2 = new Vector2();
private static _resolutionScale: Vector2 = Vector2.one;
private static _touchIndex: number = 0;
private static _totalTouchCount: number = 0;
/** 返回第一个触摸点的坐标 */
public static get touchPosition(){
if (!this._gameTouchs[0])
return Vector2.zero;
return this._gameTouchs[0].position;
}
/** 获取最大触摸数 */
public static get maxSupportedTouch(){
return this._stage.maxTouches;
}
/**
*
*/
public static set maxSupportedTouch(value: number){
this._stage.maxTouches = value;
this.initTouchCache();
}
/** 获取缩放值 默认为1 */
public static get resolutionScale(){
return this._resolutionScale;
}
/** 当前触摸点数量 */
public static get totalTouchCount(){
return this._totalTouchCount;
}
/**
*
* touchPoint是否为-1
* touchDown
*/
public static get gameTouchs(){
return this._gameTouchs;
}
/** 获取第一个触摸点距离上次距离的增量 */
public static get touchPositionDelta(){
let delta = Vector2.subtract(this.touchPosition, this._previousTouchState.position);
if (delta.length() > 0){
this.setpreviousTouchState(this._gameTouchs[0]);
} }
return delta;
}
public static initialize(stage: egret.Stage){ public reset(){
if (this._init) this.x = 0;
return; this.y = 0;
this.touchDown = false;
this._init = true; this.touchPoint = -1;
this._stage = stage;
this._stage.addEventListener(egret.TouchEvent.TOUCH_BEGIN, this.touchBegin, this);
this._stage.addEventListener(egret.TouchEvent.TOUCH_MOVE, this.touchMove, this);
this._stage.addEventListener(egret.TouchEvent.TOUCH_END, this.touchEnd, this);
this._stage.addEventListener(egret.TouchEvent.TOUCH_CANCEL, this.touchEnd, this);
this._stage.addEventListener(egret.TouchEvent.TOUCH_RELEASE_OUTSIDE, this.touchEnd, this);
this.initTouchCache();
}
private static initTouchCache(){
this._totalTouchCount = 0;
this._touchIndex = 0;
this._gameTouchs.length = 0;
for (let i = 0; i < this.maxSupportedTouch; i ++){
this._gameTouchs.push(new TouchState());
} }
} }
private static touchBegin(evt: egret.TouchEvent){ export class Input {
if (this._touchIndex < this.maxSupportedTouch){ private static _init: boolean = false;
this._gameTouchs[this._touchIndex].touchPoint = evt.touchPointID; private static _stage: egret.Stage;
this._gameTouchs[this._touchIndex].touchDown = evt.touchDown; private static _previousTouchState: TouchState = new TouchState();
this._gameTouchs[this._touchIndex].x = evt.stageX; private static _gameTouchs: TouchState[] = [];
this._gameTouchs[this._touchIndex].y = evt.stageY; private static _resolutionOffset: Vector2 = new Vector2();
if (this._touchIndex == 0){ private static _resolutionScale: Vector2 = Vector2.one;
private static _touchIndex: number = 0;
private static _totalTouchCount: number = 0;
/** 返回第一个触摸点的坐标 */
public static get touchPosition(){
if (!this._gameTouchs[0])
return Vector2.zero;
return this._gameTouchs[0].position;
}
/** 获取最大触摸数 */
public static get maxSupportedTouch(){
return this._stage.maxTouches;
}
/**
*
*/
public static set maxSupportedTouch(value: number){
this._stage.maxTouches = value;
this.initTouchCache();
}
/** 获取缩放值 默认为1 */
public static get resolutionScale(){
return this._resolutionScale;
}
/** 当前触摸点数量 */
public static get totalTouchCount(){
return this._totalTouchCount;
}
/**
*
* touchPoint是否为-1
* touchDown
*/
public static get gameTouchs(){
return this._gameTouchs;
}
/** 获取第一个触摸点距离上次距离的增量 */
public static get touchPositionDelta(){
let delta = Vector2.subtract(this.touchPosition, this._previousTouchState.position);
if (delta.length() > 0){
this.setpreviousTouchState(this._gameTouchs[0]); this.setpreviousTouchState(this._gameTouchs[0]);
} }
this._touchIndex ++; return delta;
this._totalTouchCount ++;
}
}
private static touchMove(evt: egret.TouchEvent){
if (evt.touchPointID == this._gameTouchs[0].touchPoint){
this.setpreviousTouchState(this._gameTouchs[0]);
} }
let touchIndex = this._gameTouchs.findIndex(touch => touch.touchPoint == evt.touchPointID); public static initialize(stage: egret.Stage){
if (touchIndex != -1){ if (this._init)
let touchData = this._gameTouchs[touchIndex]; return;
touchData.x = evt.stageX;
touchData.y = evt.stageY;
}
}
private static touchEnd(evt: egret.TouchEvent){ this._init = true;
let touchIndex = this._gameTouchs.findIndex(touch => touch.touchPoint == evt.touchPointID); this._stage = stage;
if (touchIndex != -1){ this._stage.addEventListener(egret.TouchEvent.TOUCH_BEGIN, this.touchBegin, this);
let touchData = this._gameTouchs[touchIndex]; this._stage.addEventListener(egret.TouchEvent.TOUCH_MOVE, this.touchMove, this);
touchData.reset(); this._stage.addEventListener(egret.TouchEvent.TOUCH_END, this.touchEnd, this);
if (touchIndex == 0) this._stage.addEventListener(egret.TouchEvent.TOUCH_CANCEL, this.touchEnd, this);
this._previousTouchState.reset(); this._stage.addEventListener(egret.TouchEvent.TOUCH_RELEASE_OUTSIDE, this.touchEnd, this);
this._totalTouchCount --;
if (this.totalTouchCount == 0){ this.initTouchCache();
this._touchIndex = 0; }
private static initTouchCache(){
this._totalTouchCount = 0;
this._touchIndex = 0;
this._gameTouchs.length = 0;
for (let i = 0; i < this.maxSupportedTouch; i ++){
this._gameTouchs.push(new TouchState());
} }
} }
}
private static setpreviousTouchState(touchState: TouchState){ private static touchBegin(evt: egret.TouchEvent){
this._previousTouchState = new TouchState(); if (this._touchIndex < this.maxSupportedTouch){
this._previousTouchState.x = touchState.position.x; this._gameTouchs[this._touchIndex].touchPoint = evt.touchPointID;
this._previousTouchState.y = touchState.position.y; this._gameTouchs[this._touchIndex].touchDown = evt.touchDown;
this._previousTouchState.touchPoint = touchState.touchPoint; this._gameTouchs[this._touchIndex].x = evt.stageX;
this._previousTouchState.touchDown = touchState.touchDown; this._gameTouchs[this._touchIndex].y = evt.stageY;
} if (this._touchIndex == 0){
this.setpreviousTouchState(this._gameTouchs[0]);
}
this._touchIndex ++;
this._totalTouchCount ++;
}
}
public static scaledPosition(position: Vector2){ private static touchMove(evt: egret.TouchEvent){
let scaledPos = new Vector2(position.x - this._resolutionOffset.x, position.y - this._resolutionOffset.y); if (evt.touchPointID == this._gameTouchs[0].touchPoint){
return Vector2.multiply(scaledPos, this.resolutionScale); this.setpreviousTouchState(this._gameTouchs[0]);
}
let touchIndex = this._gameTouchs.findIndex(touch => touch.touchPoint == evt.touchPointID);
if (touchIndex != -1){
let touchData = this._gameTouchs[touchIndex];
touchData.x = evt.stageX;
touchData.y = evt.stageY;
}
}
private static touchEnd(evt: egret.TouchEvent){
let touchIndex = this._gameTouchs.findIndex(touch => touch.touchPoint == evt.touchPointID);
if (touchIndex != -1){
let touchData = this._gameTouchs[touchIndex];
touchData.reset();
if (touchIndex == 0)
this._previousTouchState.reset();
this._totalTouchCount --;
if (this.totalTouchCount == 0){
this._touchIndex = 0;
}
}
}
private static setpreviousTouchState(touchState: TouchState){
this._previousTouchState = new TouchState();
this._previousTouchState.x = touchState.position.x;
this._previousTouchState.y = touchState.position.y;
this._previousTouchState.touchPoint = touchState.touchPoint;
this._previousTouchState.touchDown = touchState.touchDown;
}
public static scaledPosition(position: Vector2){
let scaledPos = new Vector2(position.x - this._resolutionOffset.x, position.y - this._resolutionOffset.y);
return Vector2.multiply(scaledPos, this.resolutionScale);
}
} }
} }
+45 -43
View File
@@ -1,54 +1,56 @@
/** module es {
*
*/
class ListPool {
private static readonly _objectQueue = [];
/** /**
* 使cacheCount对象填充缓存 *
* @param cacheCount
*/ */
public static warmCache(cacheCount: number){ export class ListPool {
cacheCount -= this._objectQueue.length; private static readonly _objectQueue = [];
if (cacheCount > 0){
for (let i = 0; i < cacheCount; i ++){ /**
this._objectQueue.unshift([]); * 使cacheCount对象填充缓存
* @param cacheCount
*/
public static warmCache(cacheCount: number){
cacheCount -= this._objectQueue.length;
if (cacheCount > 0){
for (let i = 0; i < cacheCount; i ++){
this._objectQueue.unshift([]);
}
} }
} }
}
/** /**
* cacheCount项目 * cacheCount项目
* @param cacheCount * @param cacheCount
*/ */
public static trimCache(cacheCount){ public static trimCache(cacheCount){
while (cacheCount > this._objectQueue.length) while (cacheCount > this._objectQueue.length)
this._objectQueue.shift(); this._objectQueue.shift();
} }
/** /**
* *
*/ */
public static clearCache(){ public static clearCache(){
this._objectQueue.length = 0; this._objectQueue.length = 0;
} }
/** /**
* *
*/ */
public static obtain<T>(): T[] { public static obtain<T>(): T[] {
if (this._objectQueue.length > 0) if (this._objectQueue.length > 0)
return this._objectQueue.shift(); return this._objectQueue.shift();
return []; return [];
} }
/** /**
* *
* @param obj * @param obj
*/ */
public static free<T>(obj: Array<T>){ public static free<T>(obj: Array<T>){
this._objectQueue.unshift(obj); this._objectQueue.unshift(obj);
obj.length = 0; obj.length = 0;
}
} }
} }
+17 -15
View File
@@ -1,20 +1,22 @@
/** module es {
* DTO /**
*/ * DTO
class Pair<T> { */
public first: T; export class Pair<T> {
public second: T; public first: T;
public second: T;
constructor(first: T, second: T){ constructor(first: T, second: T){
this.first = first; this.first = first;
this.second = second; this.second = second;
} }
public clear(){ public clear(){
this.first = this.second = null; this.first = this.second = null;
} }
public equals(other: Pair<T>){ public equals(other: Pair<T>){
return this.first == other.first && this.second == other.second; return this.first == other.first && this.second == other.second;
}
} }
} }
+17 -15
View File
@@ -1,17 +1,19 @@
class RectangleExt { module es {
/** export class RectangleExt {
* /**
* @param first *
* @param point * @param first
*/ * @param point
public static union(first: Rectangle, point: Vector2){ */
let rect = new Rectangle(point.x, point.y, 0, 0); public static union(first: Rectangle, point: Vector2){
// let rectResult = first.union(rect); let rect = new Rectangle(point.x, point.y, 0, 0);
let result = new Rectangle(); // let rectResult = first.union(rect);
result.x = Math.min(first.x, rect.x); let result = new Rectangle();
result.y = Math.min(first.y, rect.y); result.x = Math.min(first.x, rect.x);
result.width = Math.max(first.right, rect.right) - result.x; result.y = Math.min(first.y, rect.y);
result.height = Math.max(first.bottom, result.bottom) - result.y; result.width = Math.max(first.right, rect.right) - result.x;
return result; result.height = Math.max(first.bottom, result.bottom) - result.y;
return result;
}
} }
} }
+89 -87
View File
@@ -1,111 +1,113 @@
/** module es {
*
*/
class Triangulator {
/** /**
* 使 *
*/ */
public triangleIndices: number[] = []; export class Triangulator {
/**
* 使
*/
public triangleIndices: number[] = [];
private _triPrev: number[] = new Array<number>(12); private _triPrev: number[] = new Array<number>(12);
private _triNext: number[] = new Array<number>(12); private _triNext: number[] = new Array<number>(12);
/** /**
* CCWarePointsCCW参数传递为false * CCWarePointsCCW参数传递为false
* @param points * @param points
* @param arePointsCCW * @param arePointsCCW
*/ */
public triangulate(points: Vector2[], arePointsCCW: boolean = true){ public triangulate(points: Vector2[], arePointsCCW: boolean = true){
let count = points.length; let count = points.length;
// 设置前一个链接和下一个链接 // 设置前一个链接和下一个链接
this.initialize(count); this.initialize(count);
// 非三角的多边形断路器 // 非三角的多边形断路器
let iterations = 0; let iterations = 0;
// 从0开始 // 从0开始
let index = 0; let index = 0;
// 继续移除所有的三角形,直到只剩下一个三角形 // 继续移除所有的三角形,直到只剩下一个三角形
while (count > 3 && iterations < 500){ while (count > 3 && iterations < 500){
iterations ++; iterations ++;
let isEar = true; let isEar = true;
let a = points[this._triPrev[index]]; let a = points[this._triPrev[index]];
let b = points[index]; let b = points[index];
let c = points[this._triNext[index]]; let c = points[this._triNext[index]];
if (Vector2Ext.isTriangleCCW(a, b, c)){ if (Vector2Ext.isTriangleCCW(a, b, c)){
let k = this._triNext[this._triNext[index]]; let k = this._triNext[this._triNext[index]];
do { do {
if (Triangulator.testPointTriangle(points[k], a, b, c)){ if (Triangulator.testPointTriangle(points[k], a, b, c)){
isEar = false; isEar = false;
break; break;
} }
k = this._triNext[k]; k = this._triNext[k];
} while (k != this._triPrev[index]); } while (k != this._triPrev[index]);
}else{ }else{
isEar = false; isEar = false;
}
if (isEar){
this.triangleIndices.push(this._triPrev[index]);
this.triangleIndices.push(index);
this.triangleIndices.push(this._triNext[index]);
// 删除vert通过重定向相邻vert的上一个和下一个链接,从而减少vertext计数
this._triNext[this._triPrev[index]] = this._triNext[index];
this._triPrev[this._triNext[index]] = this._triPrev[index];
count --;
// 接下来访问前一个vert
index = this._triPrev[index];
}else{
index = this._triNext[index];
}
} }
if (isEar){ this.triangleIndices.push(this._triPrev[index]);
this.triangleIndices.push(this._triPrev[index]); this.triangleIndices.push(index);
this.triangleIndices.push(index); this.triangleIndices.push(this._triNext[index]);
this.triangleIndices.push(this._triNext[index]);
// 删除vert通过重定向相邻vert的上一个和下一个链接,从而减少vertext计数 if (!arePointsCCW)
this._triNext[this._triPrev[index]] = this._triNext[index]; this.triangleIndices.reverse();
this._triPrev[this._triNext[index]] = this._triPrev[index]; }
count --;
// 接下来访问前一个vert private initialize(count: number){
index = this._triPrev[index]; this.triangleIndices.length = 0;
}else{
index = this._triNext[index]; if (this._triNext.length < count){
this._triNext.reverse();
this._triNext = new Array<number>(Math.max(this._triNext.length * 2, count));
} }
if (this._triPrev.length < count){
this._triPrev.reverse();
this._triPrev = new Array<number>(Math.max(this._triPrev.length * 2, count));
}
for (let i = 0; i < count;i ++){
this._triPrev[i] = i - 1;
this._triNext[i] = i + 1;
}
this._triPrev[0] = count - 1;
this._triNext[count - 1] = 0;
} }
this.triangleIndices.push(this._triPrev[index]); public static testPointTriangle(point: Vector2, a: Vector2, b: Vector2, c: Vector2): boolean{
this.triangleIndices.push(index); if (Vector2Ext.cross(Vector2.subtract(point, a), Vector2.subtract(b, a)) < 0)
this.triangleIndices.push(this._triNext[index]); return false;
if (!arePointsCCW) if (Vector2Ext.cross(Vector2.subtract(point, b), Vector2.subtract(c, b)) < 0)
this.triangleIndices.reverse(); return false;
}
private initialize(count: number){ if (Vector2Ext.cross(Vector2.subtract(point, c), Vector2.subtract(a, c)) < 0)
this.triangleIndices.length = 0; return false;
if (this._triNext.length < count){ return true;
this._triNext.reverse();
this._triNext = new Array<number>(Math.max(this._triNext.length * 2, count));
} }
if (this._triPrev.length < count){
this._triPrev.reverse();
this._triPrev = new Array<number>(Math.max(this._triPrev.length * 2, count));
}
for (let i = 0; i < count;i ++){
this._triPrev[i] = i - 1;
this._triNext[i] = i + 1;
}
this._triPrev[0] = count - 1;
this._triNext[count - 1] = 0;
}
public static testPointTriangle(point: Vector2, a: Vector2, b: Vector2, c: Vector2): boolean{
if (Vector2Ext.cross(Vector2.subtract(point, a), Vector2.subtract(b, a)) < 0)
return false;
if (Vector2Ext.cross(Vector2.subtract(point, b), Vector2.subtract(c, b)) < 0)
return false;
if (Vector2Ext.cross(Vector2.subtract(point, c), Vector2.subtract(a, c)) < 0)
return false;
return true;
} }
} }
+72 -70
View File
@@ -1,59 +1,60 @@
class Vector2Ext { module es {
/** export class Vector2Ext {
* CCW还是CW /**
* @param a * CCW还是CW
* @param center * @param a
* @param c * @param center
*/ * @param c
public static isTriangleCCW(a: Vector2, center: Vector2, c: Vector2) { */
return this.cross(Vector2.subtract(center, a), Vector2.subtract(c, center)) < 0; public static isTriangleCCW(a: Vector2, center: Vector2, c: Vector2) {
} return this.cross(Vector2.subtract(center, a), Vector2.subtract(c, center)) < 0;
/**
* (Perp(u) v)
* @param u
* @param v
*/
public static cross(u: Vector2, v: Vector2) {
return u.y * v.x - u.x * v.y;
}
/**
*
* @param first
* @param second
*/
public static perpendicular(first: Vector2, second: Vector2) {
return new Vector2(-1 * (second.y - first.y), second.x - first.x);
}
/**
* Vector2的临时解决方案
*
* @param vec
*/
public static normalize(vec: Vector2) {
let magnitude = Math.sqrt((vec.x * vec.x) + (vec.y * vec.y));
if (magnitude > MathHelper.Epsilon) {
vec = Vector2.divide(vec, new Vector2(magnitude));
} else {
vec.x = vec.y = 0;
} }
return vec; /**
} * (Perp(u) v)
* @param u
* @param v
*/
public static cross(u: Vector2, v: Vector2) {
return u.y * v.x - u.x * v.y;
}
/** /**
* Vector2的数组中的向量应用变换 *
* @param sourceArray * @param first
* @param sourceIndex * @param second
* @param matrix */
* @param destinationArray public static perpendicular(first: Vector2, second: Vector2) {
* @param destinationIndex return new Vector2(-1 * (second.y - first.y), second.x - first.x);
* @param length }
*/
public static transformA(sourceArray: Vector2[], sourceIndex: number, matrix: Matrix2D, /**
destinationArray: Vector2[], destinationIndex: number, length: number) { * Vector2的临时解决方案
*
* @param vec
*/
public static normalize(vec: Vector2) {
let magnitude = Math.sqrt((vec.x * vec.x) + (vec.y * vec.y));
if (magnitude > MathHelper.Epsilon) {
vec = Vector2.divide(vec, new Vector2(magnitude));
} else {
vec.x = vec.y = 0;
}
return vec;
}
/**
* Vector2的数组中的向量应用变换
* @param sourceArray
* @param sourceIndex
* @param matrix
* @param destinationArray
* @param destinationIndex
* @param length
*/
public static transformA(sourceArray: Vector2[], sourceIndex: number, matrix: Matrix2D,
destinationArray: Vector2[], destinationIndex: number, length: number) {
for (let i = 0; i < length; i ++){ for (let i = 0; i < length; i ++){
let position = sourceArray[sourceIndex + i]; let position = sourceArray[sourceIndex + i];
let destination = destinationArray[destinationIndex + i]; let destination = destinationArray[destinationIndex + i];
@@ -61,25 +62,26 @@ class Vector2Ext {
destination.y = (position.x * matrix.m12) + (position.y * matrix.m22) + matrix.m32; destination.y = (position.x * matrix.m12) + (position.y * matrix.m22) + matrix.m32;
destinationArray[destinationIndex + i] = destination; destinationArray[destinationIndex + i] = destination;
} }
} }
public static transformR(position: Vector2, matrix: Matrix2D){ public static transformR(position: Vector2, matrix: Matrix2D){
let x = (position.x * matrix.m11) + (position.y * matrix.m21) + matrix.m31; let x = (position.x * matrix.m11) + (position.y * matrix.m21) + matrix.m31;
let y = (position.x * matrix.m12) + (position.y * matrix.m22) + matrix.m32; let y = (position.x * matrix.m12) + (position.y * matrix.m22) + matrix.m32;
return new Vector2(x, y); return new Vector2(x, y);
} }
/** /**
* Vector2的数组中的所有向量应用变换 * Vector2的数组中的所有向量应用变换
* @param sourceArray * @param sourceArray
* @param matrix * @param matrix
* @param destinationArray * @param destinationArray
*/ */
public static transform(sourceArray: Vector2[], matrix: Matrix2D, destinationArray: Vector2[]) { public static transform(sourceArray: Vector2[], matrix: Matrix2D, destinationArray: Vector2[]) {
this.transformA(sourceArray, 0, matrix, destinationArray, 0, sourceArray.length); this.transformA(sourceArray, 0, matrix, destinationArray, 0, sourceArray.length);
} }
public static round(vec: Vector2){ public static round(vec: Vector2){
return new Vector2(Math.round(vec.x), Math.round(vec.y)); return new Vector2(Math.round(vec.x), Math.round(vec.y));
}
} }
} }