新增虚拟输入类 VirtualInput

This commit is contained in:
yhh
2020-08-27 18:48:20 +08:00
parent e81f98ff17
commit d07912d610
47 changed files with 3428 additions and 1615 deletions

View File

@@ -127,15 +127,5 @@ module es {
return this;
}
/**
* 创建此组件的克隆
*/
public clone(): Component {
let component = ObjectUtils.clone<Component>(this);
component.entity = null;
return component;
}
}
}

View File

@@ -8,12 +8,24 @@ module es {
/**
* 零参数构造函数要求RenderableComponent在实体上这样碰撞器可以在实体被添加到场景时调整自身的大小。
*/
constructor() {
constructor(x?: number, y?: number, width?: number, height?: number) {
super();
// 我们在这里插入一个1x1框作为占位符直到碰撞器在下一阵被添加到实体并可以获得更精确的自动调整大小数据
this.shape = new Box(1, 1);
this._colliderRequiresAutoSizing = true;
if (x == undefined && y == undefined){
if (width == undefined && height == undefined){
// 我们在这里插入一个1x1框作为占位符直到碰撞器在下一阵被添加到实体并可以获得更精确的自动调整大小数据
this.shape = new Box(1, 1);
this._colliderRequiresAutoSizing = true;
}else if (width != undefined && height != undefined){
x = -width / 2;
y = -height / 2;
this._localOffset = new Vector2(x + width / 2, y + height / 2);
this.shape = new Box(width, height);
}
}else if (x != undefined && y != undefined && width != undefined && height != undefined){
this._localOffset = new Vector2(x + width / 2, y + height / 2);
this.shape = new Box(width, height);
}
}
public get width() {
@@ -32,20 +44,6 @@ module es {
this.setHeight(value);
}
/**
* 创建一个BoxCollider并使用x/y组件作为localOffset
* @param x
* @param y
* @param width
* @param height
*/
public createBoxRect(x: number, y: number, width: number, height: number): BoxCollider{
this._localOffset = new Vector2(x + width / 2, y + width / 2);
this.shape = new Box(width, height);
this._colliderRequiresAutoSizing = false;
return this;
}
/**
* 设置BoxCollider的大小
* @param width
@@ -110,11 +108,11 @@ module es {
if (!this.pixelShape2.parent)
this.debugDisplayObject.addChild(this.pixelShape2);
// this.hollowShape.graphics.clear();
// this.hollowShape.graphics.beginFill(Colors.colliderBounds, 0);
// this.hollowShape.graphics.lineStyle(Size.lineSizeMultiplier, Colors.colliderBounds);
// this.hollowShape.graphics.drawRect(this.bounds.x, this.bounds.y, this.bounds.width, this.bounds.height);
// this.hollowShape.graphics.endFill();
this.hollowShape.graphics.clear();
this.hollowShape.graphics.beginFill(Colors.colliderBounds, 0);
this.hollowShape.graphics.lineStyle(Size.lineSizeMultiplier, Colors.colliderBounds);
this.hollowShape.graphics.drawRect(this.bounds.x, this.bounds.y, this.bounds.width, this.bounds.height);
this.hollowShape.graphics.endFill();
this.polygonShape.graphics.clear();
if (poly.points.length >= 2){

View File

@@ -13,11 +13,14 @@ module es {
constructor(radius?: number) {
super();
if (radius)
if (radius == undefined){
// 我们在这里插入一个1px的圆圈作为占位符
// 直到碰撞器被添加到实体并可以获得更精确的自动调整大小数据的下一帧
this.shape = new Circle(1);
this._colliderRequiresAutoSizing = true;
// 我们在这里插入一个1px的圆圈作为占位符
// 直到碰撞器被添加到实体并可以获得更精确的自动调整大小数据的下一帧
this.shape = new Circle(radius ? radius : 1);
}else{
this.shape = new Circle(radius);
}
}
public get radius(): number {

View File

@@ -1,6 +1,5 @@
module es {
export abstract class Collider extends Component {
public debug
/**
* 对撞机的基本形状
*/
@@ -12,12 +11,12 @@ module es {
/**
* 在处理冲突时physicsLayer可以用作过滤器。Flags类有帮助位掩码的方法
*/
public physicsLayer = 1 << 0;
public physicsLayer = new Ref(1 << 0);
/**
* 碰撞器在使用移动器移动时应该碰撞的层
* 默认为所有层
*/
public collidesWithLayers = Physics.allLayers;
public collidesWithLayers: Ref<number> = new Ref(Physics.allLayers);
/**
* 如果为true碰撞器将根据附加的变换缩放和旋转
*/
@@ -124,8 +123,8 @@ module es {
let renderableBounds = renderable.bounds;
// 这里我们需要大小*反尺度,因为当我们自动调整碰撞器的大小时,它需要没有缩放的渲染
let width = renderableBounds.width / this.entity.scale.x;
let height = renderableBounds.height / this.entity.scale.y;
let width = renderableBounds.width / this.entity.transform.scale.x;
let height = renderableBounds.height / this.entity.transform.scale.y;
// 圆碰撞器需要特别注意原点
if (this instanceof CircleCollider) {
this.radius = Math.max(width, height) * 0.5;
@@ -214,7 +213,7 @@ module es {
public collidesWith(collider: Collider, motion: Vector2, result: CollisionResult): boolean {
// 改变形状的位置,使它在移动后的位置,这样我们可以检查重叠
let oldPosition = this.entity.position;
this.entity.position = this.entity.position.add(motion);
this.entity.position.add(motion);
let didCollide = this.shape.collidesWithShape(collider.shape, result);
if (didCollide)
@@ -225,15 +224,5 @@ module es {
return didCollide;
}
public clone(): Component {
let collider = ObjectUtils.clone<Collider>(this);
collider.entity = null;
if (this.shape)
collider.shape = this.shape.clone();
return collider;
}
}
}

View File

@@ -36,7 +36,7 @@ module es {
let bounds = collider.bounds;
bounds.x += motion.x;
bounds.y += motion.y;
let neighbors = Physics.boxcastBroadphaseExcludingSelf(collider, bounds, collider.collidesWithLayers);
let neighbors = Physics.boxcastBroadphaseExcludingSelf(collider, bounds, collider.collidesWithLayers.value);
for (let j = 0; j < neighbors.length; j++) {
let neighbor = neighbors[j];

View File

@@ -24,13 +24,12 @@ module es {
let didCollide = false;
// 获取我们在新位置可能发生碰撞的任何东西
this.entity.position = Vector2.add(this.entity.position, motion);
this.entity.position.add(motion);
// 获取任何可能在新位置发生碰撞的东西
let neighbors = Physics.boxcastBroadphase(this._collider.bounds, this._collider.collidesWithLayers);
for (let i = 0; i < neighbors.length; i++) {
let neighbor = neighbors[i];
if (this._collider.overlaps(neighbor) && neighbor.enabled) {
let neighbors = Physics.boxcastBroadphase(this._collider.bounds, this._collider.collidesWithLayers.value);
for (let neighbor of neighbors){
if (this._collider.overlaps(neighbor) && neighbor.enabled){
didCollide = true;
this.notifyTriggerListeners(this._collider, neighbor);
}

View File

@@ -3,7 +3,7 @@ module es {
public readonly sprites: Sprite[];
public readonly frameRate: number;
constructor(sprites: Sprite[], frameRate: number) {
constructor(sprites: Sprite[], frameRate: number = 10) {
this.sprites = sprites;
this.frameRate = frameRate;
}

View File

@@ -1,7 +1,7 @@
module es {
export class TiledMapRenderer extends RenderableComponent {
public tiledMap: TmxMap;
public physicsLayer: number = 1 << 0;
public physicsLayer: Ref<number> = new Ref(1 << 0);
/**
* 如果空,所有层将被渲染
*/
@@ -27,7 +27,7 @@ module es {
this.displayObject = new egret.DisplayObjectContainer();
if (collisionLayerName) {
this.collisionLayer = tiledMap.tileLayers[collisionLayerName];
this.collisionLayer = tiledMap.tileLayers.find(layer => layer.name == collisionLayerName);
}
}
@@ -123,7 +123,7 @@ module es {
// 为我们收到的矩形创建碰撞器
this._colliders = [];
for (let i = 0; i < collisionRects.length; i++) {
let collider = new BoxCollider().createBoxRect(collisionRects[i].x + this._localOffset.x,
let collider = new BoxCollider(collisionRects[i].x + this._localOffset.x,
collisionRects[i].y + this._localOffset.y, collisionRects[i].width, collisionRects[i].height);
collider.physicsLayer = this.physicsLayer;
collider.entity = this.entity;

View File

@@ -200,6 +200,7 @@ module es {
// 更新我们所有的系统管理器
Time.update(egret.getTimer());
Input.update();
if (this._scene) {
for (let i = this._globalManagers.length - 1; i >= 0; i--) {

View File

@@ -280,20 +280,6 @@ module es {
}
}
/**
* 创建此实体的深层克隆。子类可以重写此方法来复制任何自定义字段。
* 当重写时应该调用CopyFrom方法它将为您克隆所有组件、碰撞器和转换子组件。
* 注意克隆的实体不会被添加到任何场景中!你必须自己添加它们!
* @param position
*/
public clone(position: Vector2 = new Vector2()): Entity {
let entity = new Entity(this.name + "(clone)");
entity.copyFrom(this);
entity.transform.position = position;
return entity;
}
/**
* 在提交了所有挂起的实体更改后,将此实体添加到场景时调用
*/
@@ -413,31 +399,5 @@ module es {
public toString(): string {
return `[Entity: name: ${this.name}, tag: ${this.tag}, enabled: ${this.enabled}, depth: ${this.updateOrder}]`;
}
/**
* 将实体的属性、组件和碰撞器复制到此实例
* @param entity
*/
protected copyFrom(entity: Entity) {
this.tag = entity.tag;
this.updateInterval = entity.updateInterval;
this.updateOrder = entity.updateOrder;
this.enabled = entity.enabled;
this.transform.scale = entity.transform.scale;
this.transform.rotation = entity.transform.rotation;
for (let i = 0; i < entity.components.count; i++)
this.addComponent(entity.components.buffer[i].clone());
for (let i = 0; i < entity.components._componentsToAdd.length; i++)
this.addComponent(entity.components._componentsToAdd[i].clone());
for (let i = 0; i < entity.transform.childCount; i++) {
let child = entity.transform.getChild(i).entity;
let childClone = child.clone();
childClone.transform.copyFrom(child.transform);
childClone.transform.parent = this.transform;
}
}
}
}

View File

@@ -30,8 +30,8 @@ module es {
* @param self
* @param flag
*/
public static setFlagExclusive(self: number, flag: number) {
return 1 << flag;
public static setFlagExclusive(self: Ref<number>, flag: number) {
self.value = 1 << flag;
}
/**
@@ -39,8 +39,8 @@ module es {
* @param self
* @param flag
*/
public static setFlag(self: number, flag: number) {
return (self | 1 << flag);
public static setFlag(self: Ref<number>, flag: number) {
self.value = (self.value | 1 << flag);
}
/**
@@ -48,17 +48,17 @@ module es {
* @param self
* @param flag
*/
public static unsetFlag(self: number, flag: number) {
public static unsetFlag(self: Ref<number>, flag: number) {
flag = 1 << flag;
return (self & (~flag));
self.value = (self.value & (~flag));
}
/**
* 反转数值集合位
* @param self
*/
public static invertFlags(self: number) {
return ~self;
public static invertFlags(self: Ref<number>) {
self.value = ~self.value;
}
}
}

View File

@@ -67,28 +67,51 @@ module es {
return Vector2.add(lineA, new Vector2(v.x * t, v.y * t));
}
public static isCircleToCircle(circleCenter1: Vector2, circleRadius1: number, circleCenter2: Vector2, circleRadius2: number): boolean {
public static circleToCircle(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 {
public static circleToLine(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 {
public static circleToPoint(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);
public static rectToCircle(rect: egret.Rectangle, cPosition: Vector2, cRadius: number): boolean {
if (this.rectToPoint(rect.x, rect.y, rect.width, rect.height, cPosition))
return true;
return vx * vx + vy * vy < cRadius * cRadius;
let edgeFrom: Vector2 = Vector2.zero;
let edgeTo: Vector2 = Vector2.zero;
let sector = this.getSector(rect.x, rect.y, rect.width, rect.height, cPosition);
if ((sector & PointSectors.top) != 0){
edgeFrom = new Vector2(rect.x, rect.y);
edgeTo = new Vector2(rect.x + rect.width, rect.y);
if (this.circleToLine(cPosition, cRadius, edgeFrom, edgeTo))
return true;
}
if ((sector & PointSectors.bottom) != 0){
edgeFrom = new Vector2(rect.x, rect.y + rect.width);
edgeTo = new Vector2(rect.x + rect.width, rect.y + rect.height);
if (this.circleToLine(cPosition, cRadius, edgeFrom, edgeTo))
return true;
}
if ((sector & PointSectors.left) != 0){
edgeFrom = new Vector2(rect.x + rect.width, rect.y);
edgeTo = new Vector2(rect.x + rect.width, rect.y + rect.height);
if (this.circleToLine(cPosition, cRadius, edgeFrom, edgeTo))
return true;
}
return false;
}
public static isRectToLine(rect: Rectangle, lineFrom: Vector2, lineTo: Vector2) {
public static rectToLine(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);
@@ -134,7 +157,7 @@ module es {
return false;
}
public static isRectToPoint(rX: number, rY: number, rW: number, rH: number, point: Vector2) {
public static rectToPoint(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;
}

View File

@@ -60,7 +60,7 @@ module es {
return this.bounds.intersects(other.bounds);
if (other instanceof Circle)
return Collisions.isRectToCircle(this.bounds, other.position, other.radius);
return Collisions.rectToCircle(this.bounds, other.position, other.radius);
}
return super.overlaps(other);

View File

@@ -25,21 +25,21 @@ module es {
// 为了处理偏移原点的旋转,我们只需要将圆心围绕(0,0)在一个圆上移动我们的偏移量就是0角
let offsetAngle = Math.atan2(collider.localOffset.y, collider.localOffset.x) * MathHelper.Rad2Deg;
let offsetLength = hasUnitScale ? collider._localOffsetLength : Vector2.multiply(collider.localOffset, collider.entity.transform.scale).length();
this.center = MathHelper.pointOnCirlce(Vector2.zero, offsetLength, collider.entity.transform.rotation + offsetAngle);
this.center = MathHelper.pointOnCirlce(Vector2.zero, offsetLength, collider.entity.transform.rotationDegrees + offsetAngle);
}
}
this.position = Vector2.add(collider.transform.position, this.center);
this.position = Vector2.add(collider.entity.transform.position, this.center);
this.bounds = new Rectangle(this.position.x - this.radius, this.position.y - this.radius, this.radius * 2, this.radius * 2);
}
public overlaps(other: Shape) {
let result: CollisionResult = new CollisionResult();
if (other instanceof Box && (other as Box).isUnrotated)
return Collisions.isRectToCircle(other.bounds, this.position, this.radius);
return Collisions.rectToCircle(other.bounds, this.position, this.radius);
if (other instanceof Circle)
return Collisions.isCircleToCircle(this.position, this.radius, other.position, (other as Circle).radius);
return Collisions.circleToCircle(this.position, this.radius, other.position, (other as Circle).radius);
if (other instanceof Polygon)
return ShapeCollisions.circleToPolygon(this, other, result);

View File

@@ -76,7 +76,7 @@ module es {
public buildEdgeNormals() {
// 对于box 我们只需要两条边,因为另外两条边是平行的
let totalEdges = this.isBox ? 2 : this.points.length;
if (this._edgeNormals == null || this._edgeNormals.length != totalEdges)
if (this._edgeNormals == undefined || this._edgeNormals.length != totalEdges)
this._edgeNormals = new Array(totalEdges);
let p2: Vector2;
@@ -169,7 +169,7 @@ module es {
edgeNormal.y = 0;
let closestPoint = new Vector2(0, 0);
let tempDistanceSquared;
let tempDistanceSquared = 0;
for (let i = 0; i < points.length; i++) {
let j = i + 1;
if (j == points.length)
@@ -200,9 +200,9 @@ module es {
* @param originalPoints
* @param rotatedPoints
*/
public static rotatePolygonVerts(radians: number, originalPoints: Vector2[], rotatedPoints){
public static rotatePolygonVerts(radians: number, originalPoints: Vector2[], rotatedPoints: Vector2[]){
let cos = Math.cos(radians);
let sin = Math.sign(radians);
let sin = Math.sin(radians);
for (let i = 0; i < originalPoints.length; i ++){
let position = originalPoints[i];

View File

@@ -26,9 +26,5 @@ module es {
public abstract containsPoint(point: Vector2);
public abstract pointCollidesWithShape(point: Vector2, result: CollisionResult): boolean;
public clone(): Shape {
return ObjectUtils.clone<Shape>(this);
}
}
}

View File

@@ -130,7 +130,7 @@ module es {
let collider = cell[i];
// 如果它是自身或者如果它不匹配我们的层掩码 跳过这个碰撞器
if (collider == excludeCollider || !Flags.isFlagSet(layerMask, collider.physicsLayer))
if (collider == excludeCollider || !Flags.isFlagSet(layerMask, collider.physicsLayer.value))
continue;
if (bounds.intersects(collider.bounds)) {
@@ -364,7 +364,7 @@ module es {
continue;
// 确保碰撞器在图层蒙版上
if (!Flags.isFlagSet(this._layerMask, potential.physicsLayer))
if (!Flags.isFlagSet(this._layerMask, potential.physicsLayer.value))
continue;
// TODO: rayIntersects的性能够吗?需要测试它。Collisions.rectToLine可能更快

View File

@@ -47,7 +47,7 @@ module es {
* 返回平铺空间中的矩形列表,其中任何非空平铺组合为边界区域
*/
public getCollisionRectangles(): Rectangle[] {
let checkedIndexes = [];
let checkedIndexes: boolean[] = new Array(this.tiles.length);
let rectangles = [];
let startCol = -1;
let index = -1;
@@ -55,12 +55,12 @@ module es {
for (let y = 0; y < this.map.height; y ++){
for (let x = 0; x< this.map.width; x ++){
index = y * this.map.width + x;
let tile = this.getTile(x, y);
let tile = this.getTile(x, y);
if (tile && !checkedIndexes[index]){
if (startCol < 0)
startCol = x;
checkedIndexes[index] = true;
}else if(tile || checkedIndexes[index]){
}else if(!tile || checkedIndexes[index] == true){
if (startCol >= 0){
rectangles.push(this.findBoundsRect(startCol, x, y, checkedIndexes));
startCol = -1;
@@ -90,7 +90,7 @@ module es {
for (let x = startX; x < endX; x ++){
index = y * this.map.width + x;
let tile = this.getTile(x, y);
if (tile || checkedIndexes[index]){
if (!tile || checkedIndexes[index]){
// 再次将我们到目前为止在这一行中访问过的所有内容设置为false因为它不会包含在矩形中应该再次进行检查
for (let _x = startX; _x < x; _x++){
index = y * this.map.width + _x;
@@ -132,7 +132,7 @@ module es {
* TmxTilesetTile只存在于动态的tiles和带有附加属性的tiles中。
*/
public get tilesetTile(): TmxTilesetTile {
if (this._tilesetTileIndex == undefined){
if (!this._tilesetTileIndex){
this._tilesetTileIndex = -1;
if (this.tileset.firstGid <= this.gid){
let tilesetTile = this.tileset.tiles.get(this.gid - this.tileset.firstGid);

View File

@@ -55,6 +55,8 @@ module es {
return this._gameTouchs[0].position;
}
public static _virtualInputs: VirtualInput[] = [];
/** 获取最大触摸数 */
public static get maxSupportedTouch() {
return Core._instance.stage.maxTouches;
@@ -91,11 +93,45 @@ module es {
this.initTouchCache();
}
public static update(){
KeyboardUtils.update();
for (let i = 0; i < this._virtualInputs.length; i ++)
this._virtualInputs[i].update();
}
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);
}
/**
* press
* @param key
*/
public static isKeyPressed(key: Keys): boolean{
return KeyboardUtils.currentKeys.contains(key) && !KeyboardUtils.previousKeys.contains(key);
}
public static isKeyPressedBoth(keyA: Keys, keyB: Keys){
return this.isKeyPressed(keyA) || this.isKeyPressed(keyB);
}
public static isKeyDown(key: Keys): boolean {
return KeyboardUtils.currentKeys.contains(key);
}
public static isKeyDownBoth(keyA: Keys, keyB: Keys){
return this.isKeyDown(keyA) || this.isKeyDown(keyB);
}
public static isKeyReleased(key: Keys){
return !KeyboardUtils.currentKeys.contains(key) && KeyboardUtils.previousKeys.contains(key);
}
public static isKeyReleasedBoth(keyA: Keys, keyB: Keys){
return this.isKeyReleased(keyA) || this.isKeyReleased(keyB);
}
private static initTouchCache() {
this._totalTouchCount = 0;
this._touchIndex = 0;

View File

@@ -0,0 +1,47 @@
import Keys = es.Keys;
class KeyboardUtils {
/**
* 当前帧按键状态
*/
public static currentKeys: Keys[] = [];
/**
* 上一帧按键状态
*/
public static previousKeys: Keys[] = [];
private static keyStatusKeys: Keys[] = [];
public static init(): void {
document.addEventListener("keydown", KeyboardUtils.onKeyDownHandler);
document.addEventListener("keyup", KeyboardUtils.onKeyUpHandler);
}
public static update(){
KeyboardUtils.previousKeys.length = 0;
for (let key of KeyboardUtils.currentKeys){
KeyboardUtils.previousKeys.push(key);
KeyboardUtils.currentKeys.remove(key);
}
KeyboardUtils.currentKeys.length = 0;
for (let key of KeyboardUtils.keyStatusKeys){
KeyboardUtils.currentKeys.push(key);
}
}
public static destroy(): void {
KeyboardUtils.currentKeys.length = 0;
document.removeEventListener("keyup", KeyboardUtils.onKeyUpHandler);
document.removeEventListener("keypress", KeyboardUtils.onKeyDownHandler);
}
private static onKeyDownHandler(event: KeyboardEvent): void {
if (!KeyboardUtils.keyStatusKeys.contains(event.keyCode))
KeyboardUtils.keyStatusKeys.push(event.keyCode);
}
private static onKeyUpHandler(event: KeyboardEvent): void {
if (KeyboardUtils.keyStatusKeys.contains(event.keyCode))
KeyboardUtils.keyStatusKeys.remove(event.keyCode);
}
}

View File

@@ -0,0 +1,116 @@
module es {
export enum Keys {
none,
back = 8,
tab = 9,
enter = 13,
capsLock = 20,
escape = 27,
space = 32,
pageUp = 33,
pageDown = 34,
end = 35,
home = 36,
left = 37,
up = 38,
right = 39,
down = 40,
select = 41,
print = 42,
execute = 43,
printScreen = 44,
insert = 45,
delete = 46,
help = 47,
d0 = 48,
d1 = 49,
d2 = 50,
d3 = 51,
d4 = 52,
d5 = 53,
d6 = 54,
d7 = 55,
d8 = 56,
d9 = 57,
a = 65,
b = 66,
c = 67,
d = 68,
e = 69,
f = 70,
g = 71,
h = 72,
i = 73,
j = 74,
k = 75,
l = 76,
m = 77,
n = 78,
o = 79,
p = 80,
q = 81,
r = 82,
s = 83,
t = 84,
u = 85,
v = 86,
w = 87,
x = 88,
y = 89,
z = 90,
leftWindows = 91,
rightWindows = 92,
apps = 93,
sleep = 95,
numPad0 = 96,
numPad1 = 97,
numPad2 = 98,
numPad3 = 99,
numPad4 = 100,
numPad5 = 101,
numPad6 = 102,
numPad7 = 103,
numPad8 = 104,
numPad9 = 105,
multiply = 106,
add = 107,
seperator = 108,
subtract = 109,
decimal = 110,
divide = 111,
f1 = 112,
f2 = 113,
f3 = 114,
f4 = 115,
f5 = 116,
f6 = 117,
f7 = 118,
f8 = 119,
f9 = 120,
f10 = 121,
f11 = 122,
f12 = 123,
f13 = 124,
f14 = 125,
f15 = 126,
f16 = 127,
f17 = 128,
f18 = 129,
f19 = 130,
f20 = 131,
f21 = 132,
f22 = 133,
f23 = 134,
f24 = 135,
numLock = 144,
scroll = 145,
leftShift = 160,
rightShift = 161,
leftControl = 162,
rightControl = 163,
leftAlt = 164,
rightAlt = 165,
browserBack = 166,
browserForward = 167
}
}

View File

@@ -0,0 +1,79 @@
///<reference path="VirtualInput.ts"/>
///<reference path="VirtualIntegerAxis.ts"/>
module es {
/**
* 用-1和1之间的浮点数表示的虚拟输入
*/
export class VirtualAxis extends VirtualInput {
public nodes: VirtualAxisNode[] = [];
public get value() {
for (let i = 0; i < this.nodes.length; i++) {
let val = this.nodes[i].value;
if (val != 0)
return val;
}
return 0;
}
constructor(...nodes: VirtualAxisNode[]) {
super();
this.nodes.concat(nodes);
}
public update() {
for (let i = 0; i < this.nodes.length; i++)
this.nodes[i].update();
}
}
export class KeyboardKeys extends VirtualAxisNode {
public overlapBehavior: OverlapBehavior;
public positive: Keys;
public negative: Keys;
public _value: number = 0;
public _turned: boolean;
constructor(overlapBehavior: OverlapBehavior, negative: Keys, positive: Keys) {
super();
this.overlapBehavior = overlapBehavior;
this.negative = negative;
this.positive = positive;
}
public update() {
if (Input.isKeyDown(this.positive)) {
if (Input.isKeyDown(this.negative)) {
switch (this.overlapBehavior) {
default:
case es.OverlapBehavior.cancelOut:
this._value = 0;
break;
case es.OverlapBehavior.takeNewer:
if (!this._turned) {
this._value *= -1;
this._turned = true;
}
break;
case es.OverlapBehavior.takeOlder:
break;
}
} else {
this._turned = false;
this._value = 1;
}
} else if (Input.isKeyDown(this.negative)) {
this._turned = false;
this._value = -1;
} else {
this._turned = false;
this._value = 0;
}
}
public get value(){
return this._value;
}
}
}

View File

@@ -0,0 +1,134 @@
///<reference path="./VirtualInput.ts" />
module es {
/**
* 用布尔值表示的虚拟输入。除了简单地检查当前按钮状态,
* 您还可以询问它是否刚刚被按下或释放了这个框架。
* 您还可以将按下的按钮存储在缓冲区中一段有限的时间或者直到调用consumeBuffer()将其使用为止。
*/
export class VirtualButton extends VirtualInput{
public nodes: Node[] = [];
public bufferTime: number = 0;
public firstRepeatTime: number = 0;
public mutiRepeatTime: number = 0;
public isRepeating: boolean;
public _bufferCounter: number = 0;
public _repeatCounter: number = 0;
public _willRepeat: boolean;
constructor(bufferTime: number = 0, ...nodes: Node[]){
super();
this.nodes = nodes;
this.bufferTime = bufferTime;
}
public setRepeat(firstRepeatTime: number, mutiRepeatTime: number = firstRepeatTime){
this.firstRepeatTime = firstRepeatTime;
this.mutiRepeatTime = mutiRepeatTime;
this._willRepeat = this.firstRepeatTime > 0;
if (!this._willRepeat)
this.isRepeating = false;
}
public update() {
this._bufferCounter -= Time.unscaledDeltaTime;
this.isRepeating = false;
let check = false;
for (let i = 0; i < this.nodes.length; i ++){
this.nodes[i].update();
if (this.nodes[i].isPressed){
this._bufferCounter = this.bufferTime;
check = true;
}else if(this.nodes[i].isDown){
check = true;
}
}
if (!check){
this._repeatCounter = 0;
this._bufferCounter = 0;
}else if(this._willRepeat){
if (this._repeatCounter == 0){
this._repeatCounter = this.firstRepeatTime;
}else{
this._repeatCounter -= Time.unscaledDeltaTime;
if (this._repeatCounter <= 0){
this.isRepeating = true;
this._repeatCounter = this.mutiRepeatTime;
}
}
}
}
public get isDown(){
for (let node of this.nodes){
if (node.isDown)
return true;
}
return false;
}
public get isPressed(){
if (this._bufferCounter > 0 || this.isRepeating)
return true;
for (let node of this.nodes){
if (node.isPressed)
return true;
}
return false;
}
public get isReleased(){
for (let node of this.nodes){
if (node.isReleased)
return true;
}
return false;
}
public consumeBuffer(){
this._bufferCounter = 0;
}
/**
* 添加一个键盘键到这个虚拟按钮
* @param key
*/
public addKeyboardKey(key: Keys): VirtualButton{
this.nodes.push(new KeyboardKey(key));
return this;
}
}
export abstract class Node extends VirtualInputNode {
public abstract isDown: boolean;
public abstract isPressed: boolean;
public abstract isReleased: boolean;
}
export class KeyboardKey extends Node {
public key: Keys;
constructor(key: Keys){
super();
this.key = key;
}
public get isDown(){
return Input.isKeyDown(this.key);
}
public get isPressed(){
return Input.isKeyPressed(this.key);
}
public get isReleased(){
return Input.isKeyReleased(this.key);
}
}
}

View File

@@ -0,0 +1,43 @@
module es {
export enum OverlapBehavior {
/**
* 重复的输入将导致相互抵消,并且不会记录任何输入。
* 例如:按左箭头键,按住时按右箭头键。这将导致相互抵消。
*/
cancelOut,
/**
* 将使用找到的第一个输入
*/
takeOlder,
/**
* 将使用找到的最后一个输入
*/
takeNewer,
}
/**
* 虚拟按钮其状态由其VirtualInputNodes的状态决定
*/
export abstract class VirtualInput {
protected constructor() {
Input._virtualInputs.push(this);
}
/**
* 从输入系统取消虚拟输入的注册。在轮询VirtualInput之后调用这个函数
*/
public deregister(){
Input._virtualInputs.remove(this);
}
public abstract update();
}
/**
* 将它们添加到您的VirtualInput中以定义它如何确定当前输入状态。
* 例如如果你想检查一个键盘键是否被按下创建一个VirtualButton并添加一个VirtualButton.keyboardkey
*/
export abstract class VirtualInputNode {
public update() {}
}
}

View File

@@ -0,0 +1,44 @@
module es {
/**
* 用int(-1、0或1)表示的虚拟输入。它对应的输入可以从上到下到下,
* 如使用两个键盘键作为正/负检查。
*/
export class VirtualIntegerAxis extends VirtualInput {
public nodes: VirtualAxisNode[] = [];
public get value(){
for (let i = 0; i < this.nodes.length; i ++){
let val = this.nodes[i].value;
if (val != 0)
return Math.sign(val);
}
return 0;
}
constructor(...nodes: VirtualAxisNode[]){
super();
this.nodes.concat(nodes);
}
public update() {
for (let i = 0; i < this.nodes.length; i ++)
this.nodes[i].update();
}
/**
* 添加键盘键来模拟这个虚拟输入的左/右或上/下
* @param overlapBehavior
* @param negative
* @param positive
*/
public addKeyboardKeys(overlapBehavior: OverlapBehavior, negative: Keys, positive: Keys){
this.nodes.push(new KeyboardKeys(overlapBehavior, negative, positive));
return this;
}
}
export abstract class VirtualAxisNode extends VirtualInputNode {
public abstract value: number;
}
}

View File

@@ -1,225 +0,0 @@
class KeyboardUtils {
/**
* 键盘事件类型
*/
public static TYPE_KEY_DOWN: number = 0;
public static TYPE_KEY_UP: number = 1;
/**
* 键值字符串枚举
*/
public static A: string = "A";
public static B: string = "B";
public static C: string = "C";
public static D: string = "D";
public static E: string = "E";
public static F: string = "F";
public static G: string = "G";
public static H: string = "H";
public static I: string = "I";
public static J: string = "J";
public static K: string = "K";
public static L: string = "L";
public static M: string = "M";
public static N: string = "N";
public static O: string = "O";
public static P: string = "P";
public static Q: string = "Q";
public static R: string = "R";
public static S: string = "S";
public static T: string = "T";
public static U: string = "U";
public static V: string = "V";
public static W: string = "W";
public static X: string = "X";
public static Y: string = "Y";
public static Z: string = "Z";
public static ESC: string = "Esc";
public static F1: string = "F1";
public static F2: string = "F2";
public static F3: string = "F3";
public static F4: string = "F4";
public static F5: string = "F5";
public static F6: string = "F6";
public static F7: string = "F7";
public static F8: string = "F8";
public static F9: string = "F9";
public static F10: string = "F10";
public static F11: string = "F11";
public static F12: string = "F12";
public static NUM_1: string = "1";
public static NUM_2: string = "2";
public static NUM_3: string = "3";
public static NUM_4: string = "4";
public static NUM_5: string = "5";
public static NUM_6: string = "6";
public static NUM_7: string = "7";
public static NUM_8: string = "8";
public static NUM_9: string = "9";
public static NUM_0: string = "0";
public static TAB: string = "Tab";
public static CTRL: string = "Ctrl";
public static ALT: string = "Alt";
public static SHIFT: string = "Shift";
public static CAPS_LOCK: string = "Caps Lock";
public static ENTER: string = "Enter";
public static SPACE: string = "Space";
public static BACK_SPACE: string = "Back Space";
public static INSERT: string = "Insert";
public static DELETE: string = "Page Down";
public static HOME: string = "Home";
public static END: string = "Page Down";
public static PAGE_UP: string = "Page Up";
public static PAGE_DOWN: string = "Page Down";
public static LEFT: string = "Left";
public static RIGHT: string = "Right";
public static UP: string = "Up";
public static DOWN: string = "Down";
public static PAUSE_BREAK: string = "Pause Break";
public static NUM_LOCK: string = "Num Lock";
public static SCROLL_LOCK: string = "Scroll Lock";
public static WINDOWS: string = "Windows";
//存放按下注册数据的字典
private static keyDownDict: Object;
//存放按起注册数据的字典
private static keyUpDict: Object;
public static init(): void {
KeyboardUtils.keyDownDict = {};
KeyboardUtils.keyUpDict = {};
document.addEventListener("keydown", KeyboardUtils.onKeyDonwHander);
document.addEventListener("keyup", KeyboardUtils.onKeyUpHander);
}
/**
* 注册按键
* @param key 键值
* @param fun 回调方法
* @param type 按键类型 TYPE_KEY_DOWN、TYPE_KEY_UP
*/
public static registerKey(key: string, fun: Function, thisObj: any, type: number = 0, ...args): void {
var keyDict: Object = type ? this.keyUpDict : this.keyDownDict;
keyDict[key] = {"fun": fun, args: args, "thisObj": thisObj};
}
/**
* 注销按键
* @param key 键值
* @param type 注销的类型
*/
public static unregisterKey(key: string, type: number = 0): void {
var keyDict: Object = type ? this.keyUpDict : this.keyDownDict;
delete keyDict[key];
}
/**
* 销毁方法
*/
public static destroy(): void {
KeyboardUtils.keyDownDict = null;
KeyboardUtils.keyUpDict = null;
document.removeEventListener("keydown", this.onKeyDonwHander);
document.removeEventListener("keyup", this.onKeyUpHander);
}
private static onKeyDonwHander(event: KeyboardEvent): void {
if (!KeyboardUtils.keyDownDict) return;
var key: string = KeyboardUtils.keyCodeToString(event.keyCode);
var o: Object = KeyboardUtils.keyDownDict[key];
if (o) {
var fun: Function = o["fun"];
var thisObj: any = o["thisObj"];
var args: any = o["args"];
fun.apply(thisObj, args);
}
}
private static onKeyUpHander(event: KeyboardEvent): void {
if (!KeyboardUtils.keyUpDict) return;
var key: string = KeyboardUtils.keyCodeToString(event.keyCode);
var o: Object = KeyboardUtils.keyUpDict[key];
if (o) {
var fun: Function = o["fun"];
var thisObj: any = o["thisObj"];
var args: any = o["args"];
fun.apply(thisObj, args);
}
}
/**
* 根据keyCode或charCode获取相应的字符串代号
* @param keyCode
* @return 键盘所指字符串代号
*/
private static keyCodeToString(keyCode: number): string {
switch (keyCode) {
case 8:
return this.BACK_SPACE;
case 9:
return this.TAB;
case 13:
return this.ENTER;
case 16:
return this.SHIFT;
case 17:
return this.CTRL;
case 19:
return this.PAUSE_BREAK;
case 20:
return this.CAPS_LOCK;
case 27:
return this.ESC;
case 32:
return this.SPACE;
case 33:
return this.PAGE_UP;
case 34:
return this.PAGE_DOWN;
case 35:
return this.END;
case 36:
return this.HOME;
case 37:
return this.LEFT;
case 38:
return this.UP;
case 39:
return this.RIGHT;
case 40:
return this.DOWN;
case 45:
return this.INSERT;
case 46:
return this.DELETE;
case 91:
return this.WINDOWS;
case 112:
return this.F1;
case 113:
return this.F2;
case 114:
return this.F3;
case 115:
return this.F4;
case 116:
return this.F5;
case 117:
return this.F6;
case 118:
return this.F7;
case 119:
return this.F8;
case 120:
return this.F9;
case 122:
return this.F11;
case 123:
return this.F12;
case 144:
return this.NUM_LOCK;
case 145:
return this.SCROLL_LOCK;
default:
return String.fromCharCode(keyCode);
}
}
}