新增跟随相机

This commit is contained in:
YHH
2020-06-19 09:16:49 +08:00
parent b83b1a5b21
commit 981e149ca5
14 changed files with 509 additions and 31 deletions

View File

@@ -303,6 +303,7 @@ declare class Transform {
setLocalPosition(localPosition: Vector2): this; setLocalPosition(localPosition: Vector2): this;
setPosition(position: Vector2): this; setPosition(position: Vector2): this;
setDirty(dirtyFlagType: DirtyType): void; setDirty(dirtyFlagType: DirtyType): void;
roundPosition(): void;
updateTransform(): void; updateTransform(): void;
} }
declare class Camera extends Component { declare class Camera extends Component {
@@ -323,6 +324,7 @@ declare class Camera extends Component {
minimumZoom: number; minimumZoom: number;
maximumZoom: number; maximumZoom: number;
origin: Vector2; origin: Vector2;
position: Vector2;
readonly transformMatrix: Matrix2D; readonly transformMatrix: Matrix2D;
readonly inverseTransformMatrix: Matrix2D; readonly inverseTransformMatrix: Matrix2D;
constructor(); constructor();
@@ -344,6 +346,29 @@ declare class CameraInset {
top: any; top: any;
bottom: any; bottom: any;
} }
declare class FollowCamera extends Component {
camera: Camera;
followLerp: number;
deadzone: Rectangle;
focusOffset: Vector2;
mapLockEnabled: boolean;
mapSize: Vector2;
private _targetEntity;
private _cameraStyle;
private _worldSpaceDeadZone;
private _desiredPositionDelta;
private _targetCollider;
constructor(targetEntity: Entity, cameraStyle?: CameraStyle);
onAddedToEntity(): void;
follow(targetEntity: Entity, cameraStyle?: CameraStyle): void;
update(): void;
private clampToMapSize;
private updateFollow;
}
declare enum CameraStyle {
lockOn = 0,
cameraWindow = 1
}
declare class Mesh extends Component { declare class Mesh extends Component {
private _verts; private _verts;
private _primitiveCount; private _primitiveCount;
@@ -647,9 +672,11 @@ declare class Rectangle {
readonly bottom: number; readonly bottom: number;
readonly center: Vector2; readonly center: Vector2;
location: Vector2; location: Vector2;
size: Vector2;
constructor(x?: number, y?: number, width?: number, height?: number); constructor(x?: number, y?: number, width?: number, height?: number);
intersects(value: Rectangle): boolean; intersects(value: Rectangle): boolean;
contains(value: Vector2): boolean; contains(value: Vector2): boolean;
containsRect(value: Rectangle): boolean;
static fromMinMax(minX: number, minY: number, maxX: number, maxY: number): Rectangle; static fromMinMax(minX: number, minY: number, maxX: number, maxY: number): Rectangle;
getClosestPointOnRectangleBorderToPoint(point: Point): { getClosestPointOnRectangleBorderToPoint(point: Point): {
res: Vector2; res: Vector2;
@@ -676,9 +703,11 @@ declare class Vector2 {
static subtract(value1: Vector2, value2: Vector2): Vector2; static subtract(value1: Vector2, value2: Vector2): Vector2;
normalize(): void; normalize(): void;
length(): number; length(): number;
round(): Vector2;
static normalize(value: Vector2): Vector2; static normalize(value: Vector2): Vector2;
static dot(value1: Vector2, value2: Vector2): number; static dot(value1: Vector2, value2: Vector2): number;
static distanceSquared(value1: Vector2, value2: Vector2): number; static distanceSquared(value1: Vector2, value2: Vector2): number;
static clamp(value1: Vector2, min: Vector2, max: Vector2): Vector2;
static lerp(value1: Vector2, value2: Vector2, amount: number): Vector2; static lerp(value1: Vector2, value2: Vector2, amount: number): Vector2;
static transform(position: Vector2, matrix: Matrix2D): Vector2; static transform(position: Vector2, matrix: Matrix2D): Vector2;
static distance(value1: Vector2, value2: Vector2): number; static distance(value1: Vector2, value2: Vector2): number;

View File

@@ -1162,8 +1162,8 @@ var Scene = (function (_super) {
} }
}; };
Scene.prototype.prepRenderState = function () { Scene.prototype.prepRenderState = function () {
this._projectionMatrix.m11 = 2 / this.stage.width; this._projectionMatrix.m11 = 2 / this.stage.stageWidth;
this._projectionMatrix.m22 = -2 / this.stage.height; this._projectionMatrix.m22 = -2 / this.stage.stageHeight;
this._transformMatrix = this.camera.transformMatrix; this._transformMatrix = this.camera.transformMatrix;
this._matrixTransformMatrix = Matrix2D.multiply(this._transformMatrix, this._projectionMatrix); this._matrixTransformMatrix = Matrix2D.multiply(this._transformMatrix, this._projectionMatrix);
}; };
@@ -1464,6 +1464,9 @@ var Transform = (function () {
} }
} }
}; };
Transform.prototype.roundPosition = function () {
this.position = this._position.round();
};
Transform.prototype.updateTransform = function () { Transform.prototype.updateTransform = function () {
if (this._hierachyDirty != DirtyType.clean) { if (this._hierachyDirty != DirtyType.clean) {
if (this.parent) if (this.parent)
@@ -1600,6 +1603,16 @@ var Camera = (function (_super) {
enumerable: true, enumerable: true,
configurable: true configurable: true
}); });
Object.defineProperty(Camera.prototype, "position", {
get: function () {
return this.entity.transform.position;
},
set: function (value) {
this.entity.transform.position = value;
},
enumerable: true,
configurable: true
});
Object.defineProperty(Camera.prototype, "transformMatrix", { Object.defineProperty(Camera.prototype, "transformMatrix", {
get: function () { get: function () {
if (this._areBoundsDirty) if (this._areBoundsDirty)
@@ -1696,6 +1709,103 @@ var CameraInset = (function () {
} }
return CameraInset; return CameraInset;
}()); }());
var FollowCamera = (function (_super) {
__extends(FollowCamera, _super);
function FollowCamera(targetEntity, cameraStyle) {
if (cameraStyle === void 0) { cameraStyle = CameraStyle.lockOn; }
var _this = _super.call(this) || this;
_this.followLerp = 0.1;
_this.deadzone = new Rectangle();
_this.focusOffset = new Vector2();
_this.mapSize = new Vector2();
_this._worldSpaceDeadZone = new Rectangle();
_this._desiredPositionDelta = new Vector2();
_this._targetEntity = targetEntity;
_this._cameraStyle = cameraStyle;
_this.camera = null;
return _this;
}
FollowCamera.prototype.onAddedToEntity = function () {
if (!this.camera)
this.camera = this.entity.scene.camera;
this.follow(this._targetEntity, this._cameraStyle);
};
FollowCamera.prototype.follow = function (targetEntity, cameraStyle) {
if (cameraStyle === void 0) { cameraStyle = CameraStyle.cameraWindow; }
this._targetEntity = targetEntity;
this._cameraStyle = cameraStyle;
var cameraBounds = this.camera.bounds;
switch (this._cameraStyle) {
case CameraStyle.cameraWindow:
var w = cameraBounds.width / 6;
var h = cameraBounds.height / 3;
this.deadzone = new Rectangle((cameraBounds.width - w) / 2, (cameraBounds.height - h) / 2, w, h);
break;
case CameraStyle.lockOn:
this.deadzone = new Rectangle(cameraBounds.width / 2, cameraBounds.height / 2, 10, 10);
break;
}
};
FollowCamera.prototype.update = function () {
var halfScreen = Vector2.multiply(this.camera.bounds.size, new Vector2(0.5));
this._worldSpaceDeadZone.x = this.camera.position.x - halfScreen.x + this.deadzone.x + this.focusOffset.x;
this._worldSpaceDeadZone.y = this.camera.position.y - halfScreen.y + this.deadzone.y + this.focusOffset.y;
this._worldSpaceDeadZone.width = this.deadzone.width;
this._worldSpaceDeadZone.height = this.deadzone.height;
if (this._targetEntity)
this.updateFollow();
this.camera.position = Vector2.lerp(this.camera.position, Vector2.add(this.camera.position, this._desiredPositionDelta), this.followLerp);
this.camera.entity.transform.roundPosition();
if (this.mapLockEnabled) {
this.camera.position = this.clampToMapSize(this.camera.position);
this.camera.entity.transform.roundPosition();
}
};
FollowCamera.prototype.clampToMapSize = function (position) {
var halfScreen = Vector2.multiply(new Vector2(this.camera.bounds.width, this.camera.bounds.height), new Vector2(0.5));
var cameraMax = new Vector2(this.mapSize.x - halfScreen.x, this.mapSize.y - halfScreen.y);
return Vector2.clamp(position, halfScreen, cameraMax);
};
FollowCamera.prototype.updateFollow = function () {
this._desiredPositionDelta.x = this._desiredPositionDelta.y = 0;
if (this._cameraStyle == CameraStyle.lockOn) {
var targetX = this._targetEntity.transform.position.x;
var targetY = this._targetEntity.transform.position.y;
if (this._worldSpaceDeadZone.x > targetX)
this._desiredPositionDelta.x = targetX - this._worldSpaceDeadZone.x;
else if (this._worldSpaceDeadZone.x < targetX)
this._desiredPositionDelta.x = targetX - this._worldSpaceDeadZone.x;
if (this._worldSpaceDeadZone.y < targetY)
this._desiredPositionDelta.y = targetY - this._worldSpaceDeadZone.y;
else if (this._worldSpaceDeadZone.y > targetY)
this._desiredPositionDelta.y = targetY - this._worldSpaceDeadZone.y;
}
else {
if (!this._targetCollider) {
this._targetCollider = this._targetEntity.getComponent(Collider);
if (!this._targetCollider)
return;
}
var targetBounds = this._targetEntity.getComponent(Collider).bounds;
if (!this._worldSpaceDeadZone.containsRect(targetBounds)) {
if (this._worldSpaceDeadZone.left > targetBounds.left)
this._desiredPositionDelta.x = targetBounds.left - this._worldSpaceDeadZone.left;
else if (this._worldSpaceDeadZone.right < targetBounds.right)
this._desiredPositionDelta.x = targetBounds.right - this._worldSpaceDeadZone.right;
if (this._worldSpaceDeadZone.bottom < targetBounds.bottom)
this._desiredPositionDelta.y = targetBounds.bottom - this._worldSpaceDeadZone.bottom;
else if (this._worldSpaceDeadZone.top > targetBounds.top)
this._desiredPositionDelta.y = targetBounds.top - this._worldSpaceDeadZone.top;
}
}
};
return FollowCamera;
}(Component));
var CameraStyle;
(function (CameraStyle) {
CameraStyle[CameraStyle["lockOn"] = 0] = "lockOn";
CameraStyle[CameraStyle["cameraWindow"] = 1] = "cameraWindow";
})(CameraStyle || (CameraStyle = {}));
var Mesh = (function (_super) { var Mesh = (function (_super) {
__extends(Mesh, _super); __extends(Mesh, _super);
function Mesh() { function Mesh() {
@@ -3025,6 +3135,17 @@ var Rectangle = (function () {
enumerable: true, enumerable: true,
configurable: true configurable: true
}); });
Object.defineProperty(Rectangle.prototype, "size", {
get: function () {
return new Vector2(this.width, this.height);
},
set: function (value) {
this.width = value.x;
this.height = value.y;
},
enumerable: true,
configurable: true
});
Rectangle.prototype.intersects = function (value) { Rectangle.prototype.intersects = function (value) {
return value.left < this.right && return value.left < this.right &&
this.left < value.right && this.left < value.right &&
@@ -3036,6 +3157,11 @@ var Rectangle = (function () {
(this.y <= value.y)) && (this.y <= value.y)) &&
(value.y < (this.y + this.height))); (value.y < (this.y + this.height)));
}; };
Rectangle.prototype.containsRect = function (value) {
return ((((this.x <= value.x) && (value.x < (this.x + this.width))) &&
(this.y <= value.y)) &&
(value.y < (this.y + this.height)));
};
Rectangle.fromMinMax = function (minX, minY, maxX, maxY) { Rectangle.fromMinMax = function (minX, minY, maxX, maxY) {
return new Rectangle(minX, minY, maxX - minX, maxY - minY); return new Rectangle(minX, minY, maxX - minX, maxY - minY);
}; };
@@ -3208,6 +3334,9 @@ var Vector2 = (function () {
Vector2.prototype.length = function () { Vector2.prototype.length = function () {
return Math.sqrt((this.x * this.x) + (this.y * this.y)); return Math.sqrt((this.x * this.x) + (this.y * this.y));
}; };
Vector2.prototype.round = function () {
return new Vector2(Math.round(this.x), Math.round(this.y));
};
Vector2.normalize = function (value) { Vector2.normalize = function (value) {
var val = 1 / Math.sqrt((value.x * value.x) + (value.y * value.y)); var val = 1 / Math.sqrt((value.x * value.x) + (value.y * value.y));
value.x *= val; value.x *= val;
@@ -3221,6 +3350,9 @@ var Vector2 = (function () {
var v1 = value1.x - value2.x, v2 = value1.y - value2.y; var v1 = value1.x - value2.x, v2 = value1.y - value2.y;
return (v1 * v1) + (v2 * v2); return (v1 * v1) + (v2 * v2);
}; };
Vector2.clamp = function (value1, min, max) {
return new Vector2(MathHelper.clamp(value1.x, min.x, max.x), MathHelper.clamp(value1.y, min.y, max.y));
};
Vector2.lerp = function (value1, value2, amount) { Vector2.lerp = function (value1, value2, amount) {
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));
}; };

File diff suppressed because one or more lines are too long

View File

@@ -104,6 +104,7 @@ class Main extends eui.UILayer {
player.addComponent(new SpriteRenderer()).setSprite(image); player.addComponent(new SpriteRenderer()).setSprite(image);
player.addComponent(new SpawnComponent(EnemyType.worm)); player.addComponent(new SpawnComponent(EnemyType.worm));
player.addComponent(new PlayerController()); player.addComponent(new PlayerController());
player.addComponent(new FollowCamera(player)).focusOffset = new Vector2(this.stage.stageWidth / 2, this.stage.stageHeight / 2);
for (let i = 0; i < 20; i ++){ for (let i = 0; i < 20; i ++){
let image = new eui.Image(RES.getRes("checkbox_select_disabled_png")); let image = new eui.Image(RES.getRes("checkbox_select_disabled_png"));
@@ -113,9 +114,6 @@ class Main extends eui.UILayer {
player2.transform.position = new Vector2(Math.random() * 100 * i, Math.random() * 100 * i); player2.transform.position = new Vector2(Math.random() * 100 * i, Math.random() * 100 * i);
} }
scene.camera.setPosition(new Vector2(-200, -200));
// Main.emitter.addObserver(CoreEmitterType.Update, ()=>{ // Main.emitter.addObserver(CoreEmitterType.Update, ()=>{
// console.log("update emitter"); // console.log("update emitter");
// }); // });

View File

@@ -22,8 +22,8 @@ class PlayerController extends Component {
if (this.down){ if (this.down){
let camera = SceneManager.getActiveScene().camera; let camera = SceneManager.getActiveScene().camera;
let worldVec = camera.screenToWorldPoint(this.touchPoint); let worldVec = camera.screenToWorldPoint(this.touchPoint);
console.log(worldVec, camera.transform.position); this.entity.position = Vector2.lerp(this.entity.position, Vector2.add(worldVec,
camera.transform.position = Vector2.lerp(camera.transform.position, worldVec, Time.deltaTime); new Vector2(this.entity.scene.stage.stageWidth / 2, this.entity.scene.stage.stageHeight / 2)), Time.deltaTime);
} }
} }
} }

View File

@@ -303,6 +303,7 @@ declare class Transform {
setLocalPosition(localPosition: Vector2): this; setLocalPosition(localPosition: Vector2): this;
setPosition(position: Vector2): this; setPosition(position: Vector2): this;
setDirty(dirtyFlagType: DirtyType): void; setDirty(dirtyFlagType: DirtyType): void;
roundPosition(): void;
updateTransform(): void; updateTransform(): void;
} }
declare class Camera extends Component { declare class Camera extends Component {
@@ -323,6 +324,7 @@ declare class Camera extends Component {
minimumZoom: number; minimumZoom: number;
maximumZoom: number; maximumZoom: number;
origin: Vector2; origin: Vector2;
position: Vector2;
readonly transformMatrix: Matrix2D; readonly transformMatrix: Matrix2D;
readonly inverseTransformMatrix: Matrix2D; readonly inverseTransformMatrix: Matrix2D;
constructor(); constructor();
@@ -344,6 +346,29 @@ declare class CameraInset {
top: any; top: any;
bottom: any; bottom: any;
} }
declare class FollowCamera extends Component {
camera: Camera;
followLerp: number;
deadzone: Rectangle;
focusOffset: Vector2;
mapLockEnabled: boolean;
mapSize: Vector2;
private _targetEntity;
private _cameraStyle;
private _worldSpaceDeadZone;
private _desiredPositionDelta;
private _targetCollider;
constructor(targetEntity: Entity, cameraStyle?: CameraStyle);
onAddedToEntity(): void;
follow(targetEntity: Entity, cameraStyle?: CameraStyle): void;
update(): void;
private clampToMapSize;
private updateFollow;
}
declare enum CameraStyle {
lockOn = 0,
cameraWindow = 1
}
declare class Mesh extends Component { declare class Mesh extends Component {
private _verts; private _verts;
private _primitiveCount; private _primitiveCount;
@@ -647,9 +672,11 @@ declare class Rectangle {
readonly bottom: number; readonly bottom: number;
readonly center: Vector2; readonly center: Vector2;
location: Vector2; location: Vector2;
size: Vector2;
constructor(x?: number, y?: number, width?: number, height?: number); constructor(x?: number, y?: number, width?: number, height?: number);
intersects(value: Rectangle): boolean; intersects(value: Rectangle): boolean;
contains(value: Vector2): boolean; contains(value: Vector2): boolean;
containsRect(value: Rectangle): boolean;
static fromMinMax(minX: number, minY: number, maxX: number, maxY: number): Rectangle; static fromMinMax(minX: number, minY: number, maxX: number, maxY: number): Rectangle;
getClosestPointOnRectangleBorderToPoint(point: Point): { getClosestPointOnRectangleBorderToPoint(point: Point): {
res: Vector2; res: Vector2;
@@ -676,9 +703,11 @@ declare class Vector2 {
static subtract(value1: Vector2, value2: Vector2): Vector2; static subtract(value1: Vector2, value2: Vector2): Vector2;
normalize(): void; normalize(): void;
length(): number; length(): number;
round(): Vector2;
static normalize(value: Vector2): Vector2; static normalize(value: Vector2): Vector2;
static dot(value1: Vector2, value2: Vector2): number; static dot(value1: Vector2, value2: Vector2): number;
static distanceSquared(value1: Vector2, value2: Vector2): number; static distanceSquared(value1: Vector2, value2: Vector2): number;
static clamp(value1: Vector2, min: Vector2, max: Vector2): Vector2;
static lerp(value1: Vector2, value2: Vector2, amount: number): Vector2; static lerp(value1: Vector2, value2: Vector2, amount: number): Vector2;
static transform(position: Vector2, matrix: Matrix2D): Vector2; static transform(position: Vector2, matrix: Matrix2D): Vector2;
static distance(value1: Vector2, value2: Vector2): number; static distance(value1: Vector2, value2: Vector2): number;

View File

@@ -1162,8 +1162,8 @@ var Scene = (function (_super) {
} }
}; };
Scene.prototype.prepRenderState = function () { Scene.prototype.prepRenderState = function () {
this._projectionMatrix.m11 = 2 / this.stage.width; this._projectionMatrix.m11 = 2 / this.stage.stageWidth;
this._projectionMatrix.m22 = -2 / this.stage.height; this._projectionMatrix.m22 = -2 / this.stage.stageHeight;
this._transformMatrix = this.camera.transformMatrix; this._transformMatrix = this.camera.transformMatrix;
this._matrixTransformMatrix = Matrix2D.multiply(this._transformMatrix, this._projectionMatrix); this._matrixTransformMatrix = Matrix2D.multiply(this._transformMatrix, this._projectionMatrix);
}; };
@@ -1464,6 +1464,9 @@ var Transform = (function () {
} }
} }
}; };
Transform.prototype.roundPosition = function () {
this.position = this._position.round();
};
Transform.prototype.updateTransform = function () { Transform.prototype.updateTransform = function () {
if (this._hierachyDirty != DirtyType.clean) { if (this._hierachyDirty != DirtyType.clean) {
if (this.parent) if (this.parent)
@@ -1600,6 +1603,16 @@ var Camera = (function (_super) {
enumerable: true, enumerable: true,
configurable: true configurable: true
}); });
Object.defineProperty(Camera.prototype, "position", {
get: function () {
return this.entity.transform.position;
},
set: function (value) {
this.entity.transform.position = value;
},
enumerable: true,
configurable: true
});
Object.defineProperty(Camera.prototype, "transformMatrix", { Object.defineProperty(Camera.prototype, "transformMatrix", {
get: function () { get: function () {
if (this._areBoundsDirty) if (this._areBoundsDirty)
@@ -1696,6 +1709,103 @@ var CameraInset = (function () {
} }
return CameraInset; return CameraInset;
}()); }());
var FollowCamera = (function (_super) {
__extends(FollowCamera, _super);
function FollowCamera(targetEntity, cameraStyle) {
if (cameraStyle === void 0) { cameraStyle = CameraStyle.lockOn; }
var _this = _super.call(this) || this;
_this.followLerp = 0.1;
_this.deadzone = new Rectangle();
_this.focusOffset = new Vector2();
_this.mapSize = new Vector2();
_this._worldSpaceDeadZone = new Rectangle();
_this._desiredPositionDelta = new Vector2();
_this._targetEntity = targetEntity;
_this._cameraStyle = cameraStyle;
_this.camera = null;
return _this;
}
FollowCamera.prototype.onAddedToEntity = function () {
if (!this.camera)
this.camera = this.entity.scene.camera;
this.follow(this._targetEntity, this._cameraStyle);
};
FollowCamera.prototype.follow = function (targetEntity, cameraStyle) {
if (cameraStyle === void 0) { cameraStyle = CameraStyle.cameraWindow; }
this._targetEntity = targetEntity;
this._cameraStyle = cameraStyle;
var cameraBounds = this.camera.bounds;
switch (this._cameraStyle) {
case CameraStyle.cameraWindow:
var w = cameraBounds.width / 6;
var h = cameraBounds.height / 3;
this.deadzone = new Rectangle((cameraBounds.width - w) / 2, (cameraBounds.height - h) / 2, w, h);
break;
case CameraStyle.lockOn:
this.deadzone = new Rectangle(cameraBounds.width / 2, cameraBounds.height / 2, 10, 10);
break;
}
};
FollowCamera.prototype.update = function () {
var halfScreen = Vector2.multiply(this.camera.bounds.size, new Vector2(0.5));
this._worldSpaceDeadZone.x = this.camera.position.x - halfScreen.x + this.deadzone.x + this.focusOffset.x;
this._worldSpaceDeadZone.y = this.camera.position.y - halfScreen.y + this.deadzone.y + this.focusOffset.y;
this._worldSpaceDeadZone.width = this.deadzone.width;
this._worldSpaceDeadZone.height = this.deadzone.height;
if (this._targetEntity)
this.updateFollow();
this.camera.position = Vector2.lerp(this.camera.position, Vector2.add(this.camera.position, this._desiredPositionDelta), this.followLerp);
this.camera.entity.transform.roundPosition();
if (this.mapLockEnabled) {
this.camera.position = this.clampToMapSize(this.camera.position);
this.camera.entity.transform.roundPosition();
}
};
FollowCamera.prototype.clampToMapSize = function (position) {
var halfScreen = Vector2.multiply(new Vector2(this.camera.bounds.width, this.camera.bounds.height), new Vector2(0.5));
var cameraMax = new Vector2(this.mapSize.x - halfScreen.x, this.mapSize.y - halfScreen.y);
return Vector2.clamp(position, halfScreen, cameraMax);
};
FollowCamera.prototype.updateFollow = function () {
this._desiredPositionDelta.x = this._desiredPositionDelta.y = 0;
if (this._cameraStyle == CameraStyle.lockOn) {
var targetX = this._targetEntity.transform.position.x;
var targetY = this._targetEntity.transform.position.y;
if (this._worldSpaceDeadZone.x > targetX)
this._desiredPositionDelta.x = targetX - this._worldSpaceDeadZone.x;
else if (this._worldSpaceDeadZone.x < targetX)
this._desiredPositionDelta.x = targetX - this._worldSpaceDeadZone.x;
if (this._worldSpaceDeadZone.y < targetY)
this._desiredPositionDelta.y = targetY - this._worldSpaceDeadZone.y;
else if (this._worldSpaceDeadZone.y > targetY)
this._desiredPositionDelta.y = targetY - this._worldSpaceDeadZone.y;
}
else {
if (!this._targetCollider) {
this._targetCollider = this._targetEntity.getComponent(Collider);
if (!this._targetCollider)
return;
}
var targetBounds = this._targetEntity.getComponent(Collider).bounds;
if (!this._worldSpaceDeadZone.containsRect(targetBounds)) {
if (this._worldSpaceDeadZone.left > targetBounds.left)
this._desiredPositionDelta.x = targetBounds.left - this._worldSpaceDeadZone.left;
else if (this._worldSpaceDeadZone.right < targetBounds.right)
this._desiredPositionDelta.x = targetBounds.right - this._worldSpaceDeadZone.right;
if (this._worldSpaceDeadZone.bottom < targetBounds.bottom)
this._desiredPositionDelta.y = targetBounds.bottom - this._worldSpaceDeadZone.bottom;
else if (this._worldSpaceDeadZone.top > targetBounds.top)
this._desiredPositionDelta.y = targetBounds.top - this._worldSpaceDeadZone.top;
}
}
};
return FollowCamera;
}(Component));
var CameraStyle;
(function (CameraStyle) {
CameraStyle[CameraStyle["lockOn"] = 0] = "lockOn";
CameraStyle[CameraStyle["cameraWindow"] = 1] = "cameraWindow";
})(CameraStyle || (CameraStyle = {}));
var Mesh = (function (_super) { var Mesh = (function (_super) {
__extends(Mesh, _super); __extends(Mesh, _super);
function Mesh() { function Mesh() {
@@ -3025,6 +3135,17 @@ var Rectangle = (function () {
enumerable: true, enumerable: true,
configurable: true configurable: true
}); });
Object.defineProperty(Rectangle.prototype, "size", {
get: function () {
return new Vector2(this.width, this.height);
},
set: function (value) {
this.width = value.x;
this.height = value.y;
},
enumerable: true,
configurable: true
});
Rectangle.prototype.intersects = function (value) { Rectangle.prototype.intersects = function (value) {
return value.left < this.right && return value.left < this.right &&
this.left < value.right && this.left < value.right &&
@@ -3036,6 +3157,11 @@ var Rectangle = (function () {
(this.y <= value.y)) && (this.y <= value.y)) &&
(value.y < (this.y + this.height))); (value.y < (this.y + this.height)));
}; };
Rectangle.prototype.containsRect = function (value) {
return ((((this.x <= value.x) && (value.x < (this.x + this.width))) &&
(this.y <= value.y)) &&
(value.y < (this.y + this.height)));
};
Rectangle.fromMinMax = function (minX, minY, maxX, maxY) { Rectangle.fromMinMax = function (minX, minY, maxX, maxY) {
return new Rectangle(minX, minY, maxX - minX, maxY - minY); return new Rectangle(minX, minY, maxX - minX, maxY - minY);
}; };
@@ -3208,6 +3334,9 @@ var Vector2 = (function () {
Vector2.prototype.length = function () { Vector2.prototype.length = function () {
return Math.sqrt((this.x * this.x) + (this.y * this.y)); return Math.sqrt((this.x * this.x) + (this.y * this.y));
}; };
Vector2.prototype.round = function () {
return new Vector2(Math.round(this.x), Math.round(this.y));
};
Vector2.normalize = function (value) { Vector2.normalize = function (value) {
var val = 1 / Math.sqrt((value.x * value.x) + (value.y * value.y)); var val = 1 / Math.sqrt((value.x * value.x) + (value.y * value.y));
value.x *= val; value.x *= val;
@@ -3221,6 +3350,9 @@ var Vector2 = (function () {
var v1 = value1.x - value2.x, v2 = value1.y - value2.y; var v1 = value1.x - value2.x, v2 = value1.y - value2.y;
return (v1 * v1) + (v2 * v2); return (v1 * v1) + (v2 * v2);
}; };
Vector2.clamp = function (value1, min, max) {
return new Vector2(MathHelper.clamp(value1.x, min.x, max.x), MathHelper.clamp(value1.y, min.y, max.y));
};
Vector2.lerp = function (value1, value2, amount) { Vector2.lerp = function (value1, value2, amount) {
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));
}; };

File diff suppressed because one or more lines are too long

View File

@@ -88,6 +88,14 @@ class Camera extends Component {
} }
} }
public get position(){
return this.entity.transform.position;
}
public set position(value: Vector2){
this.entity.transform.position = value;
}
public get transformMatrix(){ public get transformMatrix(){
if (this._areBoundsDirty) if (this._areBoundsDirty)
this.updateMatrixes(); this.updateMatrixes();

View File

@@ -0,0 +1,115 @@
class FollowCamera extends Component {
public camera: Camera;
public followLerp = 0.1;
public deadzone: Rectangle = new Rectangle();
public focusOffset: Vector2 = new Vector2();
public mapLockEnabled: boolean;
public mapSize: Vector2 = new Vector2();
private _targetEntity: Entity;
private _cameraStyle: CameraStyle;
private _worldSpaceDeadZone: Rectangle = new Rectangle();
private _desiredPositionDelta: Vector2 = new Vector2();
private _targetCollider: Collider;
constructor(targetEntity: Entity, cameraStyle: CameraStyle = CameraStyle.lockOn){
super();
this._targetEntity = targetEntity;
this._cameraStyle = cameraStyle;
this.camera = null;
}
public onAddedToEntity(){
if (!this.camera)
this.camera = this.entity.scene.camera;
this.follow(this._targetEntity, this._cameraStyle);
}
public follow(targetEntity: Entity, cameraStyle: CameraStyle = CameraStyle.cameraWindow){
this._targetEntity = targetEntity;
this._cameraStyle = cameraStyle;
let cameraBounds = this.camera.bounds;
switch (this._cameraStyle){
case CameraStyle.cameraWindow:
let w = cameraBounds.width / 6;
let h = cameraBounds.height / 3;
this.deadzone = new Rectangle((cameraBounds.width - w) / 2, (cameraBounds.height - h) / 2, w, h);
break;
case CameraStyle.lockOn:
this.deadzone = new Rectangle(cameraBounds.width / 2, cameraBounds.height / 2, 10, 10);
break;
}
}
public update(){
let halfScreen = Vector2.multiply(this.camera.bounds.size, new Vector2(0.5));
this._worldSpaceDeadZone.x = this.camera.position.x - halfScreen.x + this.deadzone.x + this.focusOffset.x;
this._worldSpaceDeadZone.y = this.camera.position.y - halfScreen.y + this.deadzone.y + this.focusOffset.y;
this._worldSpaceDeadZone.width = this.deadzone.width;
this._worldSpaceDeadZone.height = this.deadzone.height;
if (this._targetEntity)
this.updateFollow();
this.camera.position = Vector2.lerp(this.camera.position, Vector2.add(this.camera.position, this._desiredPositionDelta), this.followLerp);
this.camera.entity.transform.roundPosition();
if (this.mapLockEnabled){
this.camera.position = this.clampToMapSize(this.camera.position);
this.camera.entity.transform.roundPosition();
}
}
private clampToMapSize(position: Vector2){
let halfScreen = Vector2.multiply(new Vector2(this.camera.bounds.width, this.camera.bounds.height), new Vector2(0.5));
let cameraMax = new Vector2(this.mapSize.x - halfScreen.x, this.mapSize.y - halfScreen.y);
return Vector2.clamp(position, halfScreen, cameraMax);
}
private updateFollow(){
this._desiredPositionDelta.x = this._desiredPositionDelta.y = 0;
if (this._cameraStyle == CameraStyle.lockOn){
let targetX = this._targetEntity.transform.position.x;
let targetY = this._targetEntity.transform.position.y;
if (this._worldSpaceDeadZone.x > targetX)
this._desiredPositionDelta.x = targetX - this._worldSpaceDeadZone.x;
else if(this._worldSpaceDeadZone.x < targetX)
this._desiredPositionDelta.x = targetX - this._worldSpaceDeadZone.x;
if (this._worldSpaceDeadZone.y < targetY)
this._desiredPositionDelta.y = targetY - this._worldSpaceDeadZone.y;
else if(this._worldSpaceDeadZone.y > targetY)
this._desiredPositionDelta.y = targetY - this._worldSpaceDeadZone.y;
} else {
if (!this._targetCollider){
this._targetCollider = this._targetEntity.getComponent<Collider>(Collider);
if (!this._targetCollider)
return;
}
let targetBounds = this._targetEntity.getComponent<Collider>(Collider).bounds;
if (!this._worldSpaceDeadZone.containsRect(targetBounds)){
if (this._worldSpaceDeadZone.left > targetBounds.left)
this._desiredPositionDelta.x = targetBounds.left - this._worldSpaceDeadZone.left;
else if(this._worldSpaceDeadZone.right < targetBounds.right)
this._desiredPositionDelta.x = targetBounds.right - this._worldSpaceDeadZone.right;
if (this._worldSpaceDeadZone.bottom < targetBounds.bottom)
this._desiredPositionDelta.y = targetBounds.bottom - this._worldSpaceDeadZone.bottom;
else if(this._worldSpaceDeadZone.top > targetBounds.top)
this._desiredPositionDelta.y = targetBounds.top - this._worldSpaceDeadZone.top;
}
}
}
}
enum CameraStyle {
lockOn,
cameraWindow,
}

View File

@@ -155,8 +155,8 @@ class Scene extends egret.DisplayObjectContainer {
} }
public prepRenderState() { public prepRenderState() {
this._projectionMatrix.m11 = 2 / this.stage.width; this._projectionMatrix.m11 = 2 / this.stage.stageWidth;
this._projectionMatrix.m22 = -2 / this.stage.height; this._projectionMatrix.m22 = -2 / this.stage.stageHeight;
this._transformMatrix = this.camera.transformMatrix; this._transformMatrix = this.camera.transformMatrix;
this._matrixTransformMatrix = Matrix2D.multiply(this._transformMatrix, this._projectionMatrix); this._matrixTransformMatrix = Matrix2D.multiply(this._transformMatrix, this._projectionMatrix);

View File

@@ -283,6 +283,10 @@ class Transform {
} }
} }
public roundPosition(){
this.position = this._position.round();
}
public updateTransform(){ public updateTransform(){
if (this._hierachyDirty != DirtyType.clean){ if (this._hierachyDirty != DirtyType.clean){
if (this.parent) if (this.parent)

View File

@@ -23,7 +23,7 @@ class Rectangle {
return this.y + this.height; return this.y + this.height;
} }
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));
} }
@@ -36,6 +36,15 @@ class Rectangle {
this.y = value.y; this.y = value.y;
} }
public get size() {
return new Vector2(this.width, this.height);
}
public set size(value: Vector2) {
this.width = value.x;
this.height = value.y;
}
constructor(x?: number, y?: number, width?: number, height?: number) { constructor(x?: number, y?: number, width?: number, height?: number) {
this.x = x ? x : 0; this.x = x ? x : 0;
this.y = y ? y : 0; this.y = y ? y : 0;
@@ -56,53 +65,59 @@ class Rectangle {
(value.y < (this.y + this.height))); (value.y < (this.y + this.height)));
} }
public containsRect(value: Rectangle) {
return ((((this.x <= value.x) && (value.x < (this.x + this.width))) &&
(this.y <= value.y)) &&
(value.y < (this.y + this.height)));
}
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);
} }
public getClosestPointOnRectangleBorderToPoint(point: Point): {res: Vector2, edgeNormal: Vector2} { public getClosestPointOnRectangleBorderToPoint(point: Point): { res: Vector2, edgeNormal: Vector2 } {
let edgeNormal = new Vector2(0, 0); let edgeNormal = new Vector2(0, 0);
let res = new Vector2(0, 0); let res = new Vector2(0, 0);
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);
if (this.contains(res)){ if (this.contains(res)) {
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{ } else {
res.x = this.right; res.x = this.right;
edgeNormal.x = 1; edgeNormal.x = 1;
} }
} else { } else {
if (res.x == this.left){ if (res.x == this.left) {
edgeNormal.x = -1; edgeNormal.x = -1;
} }
if (res.x == this.right){ if (res.x == this.right) {
edgeNormal.x = 1; edgeNormal.x = 1;
} }
if (res.y == this.top){ if (res.y == this.top) {
edgeNormal.y = -1; edgeNormal.y = -1;
} }
if (res.y == this.bottom){ if (res.y == this.bottom) {
edgeNormal.y = 1; edgeNormal.y = 1;
} }
} }
return {res: res, edgeNormal: edgeNormal}; return { res: res, edgeNormal: edgeNormal };
} }
public calculateBounds(parentPosition: Vector2, position: Vector2, origin: Vector2, scale: Vector2, public calculateBounds(parentPosition: Vector2, position: Vector2, origin: Vector2, scale: Vector2,
@@ -149,26 +164,26 @@ class Rectangle {
* 给定多边形的点,计算边界 * 给定多边形的点,计算边界
* @param points * @param points
*/ */
public static rectEncompassingPoints(points: Vector2[]){ public static rectEncompassingPoints(points: Vector2[]) {
let minX = Number.POSITIVE_INFINITY; let minX = Number.POSITIVE_INFINITY;
let minY = Number.POSITIVE_INFINITY; let minY = Number.POSITIVE_INFINITY;
let maxX = Number.NEGATIVE_INFINITY; let maxX = Number.NEGATIVE_INFINITY;
let maxY = Number.NEGATIVE_INFINITY; let maxY = Number.NEGATIVE_INFINITY;
for (let i = 0; i < points.length; i ++){ for (let i = 0; i < points.length; i++) {
let pt = points[i]; let pt = points[i];
if (pt.x < minX){ if (pt.x < minX) {
minX = pt.x; minX = pt.x;
} }
if (pt.x > maxX){ if (pt.x > maxX) {
maxX = pt.x; maxX = pt.x;
} }
if (pt.y < minY){ if (pt.y < minY) {
minY = pt.y; minY = pt.y;
} }
if (pt.y > maxY){ if (pt.y > maxY) {
maxY = pt.y; maxY = pt.y;
} }
} }

View File

@@ -93,6 +93,11 @@ class Vector2 {
return Math.sqrt((this.x * this.x) + (this.y * this.y)); return Math.sqrt((this.x * this.x) + (this.y * this.y));
} }
/** 对x和y值四舍五入 */
public round(): Vector2{
return new Vector2(Math.round(this.x), Math.round(this.y));
}
/** /**
* 创建一个新的Vector2 * 创建一个新的Vector2
* 它包含来自另一个向量的标准化值。 * 它包含来自另一个向量的标准化值。
@@ -124,6 +129,17 @@ class Vector2 {
return (v1 * v1) + (v2 * v2); return (v1 * v1) + (v2 * v2);
} }
/**
*
* @param value1
* @param min
* @param max
*/
public static clamp(value1: Vector2, min: Vector2, max: Vector2){
return new Vector2(MathHelper.clamp(value1.x, min.x, max.x),
MathHelper.clamp(value1.y, min.y, max.y));
}
/** /**
* 包含指定向量的线性插值 * 包含指定向量的线性插值
* @param value1 第一个向量 * @param value1 第一个向量