移动部分类模块至es

优化框架
This commit is contained in:
YHH
2020-07-22 23:30:31 +08:00
parent 5b8f414a45
commit 15c0844e29
18 changed files with 1245 additions and 674 deletions

View File

@@ -1,33 +1,45 @@
module es {
export enum CameraStyle {
lockOn,
cameraWindow,
}
export class Camera extends Component {
private _zoom;
private _origin: Vector2 = Vector2.zero;
private _minimumZoom = 0.3;
private _maximumZoom = 3;
private _position: Vector2 = Vector2.zero;
/**
* 如果相机模式为cameraWindow 则会进行缓动移动
* 该值为移动速度
* 对entity.transform.position的快速访问
*/
public followLerp = 0.1;
public deadzone: Rectangle = new Rectangle();
/** 锁定偏移量 默认中心 */
public focusOffset: Vector2 = new Vector2();
/** 是否地图锁定 如果锁定则需要设置mapSize属性 */
public mapLockEnabled: boolean = false;
/** 设置地图大小 默认从0 0左上角开始 只需要输入地图宽高 */
public mapSize: Vector2 = new Vector2();
/** 跟随的实体 设置后镜头将锁定目标为中心 */
public targetEntity: Entity;
private _worldSpaceDeadZone: Rectangle = new Rectangle();
private _desiredPositionDelta: Vector2 = new Vector2();
private _targetCollider: Collider;
/** 相机模式 */
public cameraStyle: CameraStyle = CameraStyle.lockOn;
public get position() {
return this.entity.transform.position;
}
public get zoom(){
/**
* 对entity.transform.position的快速访问
* @param value
*/
public set position(value: Vector2) {
this.entity.transform.position = value;
}
/**
* 对entity.transform.rotation的快速访问
*/
public get rotation(): number {
return this.entity.transform.rotation;
}
/**
* 对entity.transform.rotation的快速访问
* @param value
*/
public set rotation(value: number) {
this.entity.transform.rotation = value;
}
/**
* 缩放值应该在-1和1之间、然后将该值从minimumZoom转换为maximumZoom。
* 允许你设置适当的最小/最大值,然后使用更直观的-1到1的映射来更改缩放
*/
public get zoom() {
if (this._zoom == 0)
return 1;
@@ -37,93 +49,143 @@ module es {
return MathHelper.map(this._zoom, 1, this._maximumZoom, 0, 1);
}
public set zoom(value: number){
/**
* 缩放值应该在-1和1之间、然后将该值从minimumZoom转换为maximumZoom。
* 允许你设置适当的最小/最大值,然后使用更直观的-1到1的映射来更改缩放
* @param value
*/
public set zoom(value: number) {
this.setZoom(value);
}
public get minimumZoom(){
/**
* 相机变焦可以达到的最小非缩放值0-number.max。默认为0.3
*/
public get minimumZoom() {
return this._minimumZoom;
}
public set minimumZoom(value: number){
/**
* 相机变焦可以达到的最小非缩放值0-number.max。默认为0.3
* @param value
*/
public set minimumZoom(value: number) {
this.setMinimumZoom(value);
}
public get maximumZoom(){
/**
* 相机变焦可以达到的最大非缩放值0-number.max。默认为3
*/
public get maximumZoom() {
return this._maximumZoom;
}
public set maximumZoom(value: number){
/**
* 相机变焦可以达到的最大非缩放值0-number.max。默认为3
* @param value
*/
public set maximumZoom(value: number) {
this.setMaximumZoom(value);
}
public get origin(){
/**
* 相机的边框
*/
public get bounds(){
return new Rectangle(0, 0, SceneManager.stage.stageWidth, SceneManager.stage.stageHeight);
}
public get origin() {
return this._origin;
}
public set origin(value: Vector2){
if (this._origin != value){
public set origin(value: Vector2) {
if (this._origin != value) {
this._origin = value;
}
}
public get position(){
return this._position;
}
private _zoom;
private _minimumZoom = 0.3;
private _maximumZoom = 3;
private _origin: Vector2 = Vector2.zero;
/**
* 如果相机模式为cameraWindow 则会进行缓动移动
* 该值为移动速度
*/
public followLerp = 0.1;
/**
* 在cameraWindow模式下宽度/高度被用做边界框,允许在不移动相机的情况下移动
* 在lockOn模式下只使用deadZone的x/y值 你可以通过直接setCenteredDeadzone重写它来自定义deadZone
*/
public deadzone: Rectangle = new Rectangle();
/**
* 相机聚焦于屏幕中心的偏移
*/
public focusOffset: Vector2 = new Vector2();
/**
* 如果为true 相机位置则不会超出地图矩形0, 0, mapwidth, mapheight
*/
public mapLockEnabled: boolean = false;
/**
* 當前地圖映射的寬度和高度
*/
public mapSize: Vector2 = new Vector2();
public set position(value: Vector2){
this._position = value;
}
public _targetEntity: Entity;
public _targetCollider: Collider;
public _desiredPositionDelta: Vector2 = new Vector2();
public _cameraStyle: CameraStyle;
public _worldSpaceDeadZone: Rectangle = new Rectangle();
public get x(){
return this._position.x;
}
public set x(value: number){
this._position.x = value;
}
public get y(){
return this._position.y;
}
public set y(value: number){
this._position.y = value;
}
constructor() {
constructor(targetEntity: Entity = null, cameraStyle: CameraStyle = CameraStyle.lockOn) {
super();
this.width = SceneManager.stage.stageWidth;
this.height = SceneManager.stage.stageHeight;
this._targetEntity = targetEntity;
this._cameraStyle = cameraStyle;
this.setZoom(0);
}
public onSceneSizeChanged(newWidth: number, newHeight: number){
/**
* 当场景渲染目标的大小发生变化时,我们会更新相机的原点并调整它的位置以保持它原来的位置
* @param newWidth
* @param newHeight
*/
public onSceneSizeChanged(newWidth: number, newHeight: number) {
let oldOrigin = this._origin;
this.origin = new Vector2(newWidth / 2, newHeight / 2);
this.entity.position = Vector2.add(this.entity.position, Vector2.subtract(this._origin, oldOrigin));
this.entity.transform.position = Vector2.add(this.entity.transform.position, Vector2.subtract(this._origin, oldOrigin));
}
public setMinimumZoom(minZoom: number): Camera{
if (this._zoom < minZoom)
this._zoom = this.minimumZoom;
this._minimumZoom = minZoom;
/**
* 对entity.transform.setPosition快速访问
* @param position
*/
public setPosition(position: Vector2) {
this.entity.transform.setPosition(position.x, position.y);
return this;
}
public setMaximumZoom(maxZoom: number): Camera {
if (this._zoom > maxZoom)
this._zoom = maxZoom;
this._maximumZoom = maxZoom;
/**
* 对entity.transform.setRotation的快速访问
* @param rotation
*/
public setRotation(rotation: number): Camera {
this.entity.transform.setRotation(rotation);
return this;
}
public setZoom(zoom: number): Camera{
/**
* 设置缩放值,缩放值应该在-1到1之间。然后将该值从minimumZoom转换为maximumZoom
* 允许您设置适当的最小/最大值。使用更直观的-1到1的映射来更改缩放
* @param zoom
*/
public setZoom(zoom: number): Camera {
let newZoom = MathHelper.clamp(zoom, -1, 1);
if (newZoom == 0){
if (newZoom == 0) {
this._zoom = 1;
} else if(newZoom < 0){
} else if (newZoom < 0) {
this._zoom = MathHelper.map(newZoom, -1, 0, this._minimumZoom, 1);
} else {
this._zoom = MathHelper.map(newZoom, 0, 1, 1, this._maximumZoom);
@@ -134,103 +196,138 @@ module es {
return this;
}
public setRotation(rotation: number): Camera {
SceneManager.scene.rotation = rotation;
/**
* 相机变焦可以达到的最小非缩放值0-number.max 默认为0.3
* @param minZoom
*/
public setMinimumZoom(minZoom: number): Camera {
if (this._zoom < minZoom)
this._zoom = this.minimumZoom;
this._minimumZoom = minZoom;
return this;
}
public setPosition(position: Vector2){
this.entity.position = position;
return this;
}
public follow(targetEntity: Entity, cameraStyle: CameraStyle = CameraStyle.cameraWindow){
this.targetEntity = targetEntity;
this.cameraStyle = cameraStyle;
let cameraBounds = new Rectangle(0, 0, SceneManager.stage.stageWidth, SceneManager.stage.stageHeight);
switch (this.cameraStyle){
case CameraStyle.cameraWindow:
let w = cameraBounds.width / 6;
let h = cameraBounds.height / 3;
this.deadzone = new Rectangle((cameraBounds.width - w) / 2, (cameraBounds.height - h) / 2, w, h);
break;
case CameraStyle.lockOn:
this.deadzone = new Rectangle(cameraBounds.width / 2, cameraBounds.height / 2, 10, 10);
break;
/**
* 相机变焦可以达到的最大非缩放值0-number.max 默认为3
* @param maxZoom
*/
public setMaximumZoom(maxZoom: number): Camera {
if (maxZoom <= 0) {
console.error("maximumZoom must be greater than zero");
return;
}
if (this._zoom > maxZoom)
this._zoom = maxZoom;
this._maximumZoom = maxZoom;
return this;
}
public update(){
let cameraBounds = new Rectangle(0, 0, SceneManager.stage.stageWidth, SceneManager.stage.stageHeight);
let halfScreen = Vector2.multiply(new Vector2(cameraBounds.width, cameraBounds.height), new Vector2(0.5));
this._worldSpaceDeadZone.x = this.position.x - halfScreen.x * SceneManager.scene.scaleX + this.deadzone.x + this.focusOffset.x;
public zoomIn(deltaZoom: number) {
this.zoom += deltaZoom;
}
public zoomOut(deltaZoom: number) {
this.zoom -= deltaZoom;
}
public onAddedToEntity() {
this.follow(this._targetEntity, this._cameraStyle);
}
public update() {
let halfScreen = Vector2.multiply(new Vector2(this.bounds.width, this.bounds.height), new Vector2(0.5));
this._worldSpaceDeadZone.x = this.position.x - halfScreen.x * SceneManager.scene.scaleX + this.deadzone.x + this.focusOffset.x;
this._worldSpaceDeadZone.y = this.position.y - halfScreen.y * SceneManager.scene.scaleY + this.deadzone.y + this.focusOffset.y;
this._worldSpaceDeadZone.width = this.deadzone.width;
this._worldSpaceDeadZone.height = this.deadzone.height;
if (this.targetEntity)
if (this._targetEntity)
this.updateFollow();
this.position = Vector2.lerp(this.position, Vector2.add(this.position, this._desiredPositionDelta), this.followLerp);
this.entity.roundPosition();
this.entity.transform.roundPosition();
if (this.mapLockEnabled){
if (this.mapLockEnabled) {
this.position = this.clampToMapSize(this.position);
this.entity.roundPosition();
this.entity.transform.roundPosition();
}
}
private clampToMapSize(position: Vector2){
let cameraBounds = new Rectangle(0, 0, SceneManager.stage.stageWidth, SceneManager.stage.stageHeight);
let halfScreen = Vector2.multiply(new Vector2(cameraBounds.width, cameraBounds.height), new Vector2(0.5));
/**
* 固定相机 永远不会离开地图的可见区域
* @param position
*/
public clampToMapSize(position: Vector2) {
let halfScreen = Vector2.multiply(new Vector2(this.bounds.width, this.bounds.height), new Vector2(0.5));
let cameraMax = new Vector2(this.mapSize.x - halfScreen.x, this.mapSize.y - halfScreen.y);
return Vector2.clamp(position, halfScreen, cameraMax);
}
private updateFollow(){
public updateFollow() {
this._desiredPositionDelta.x = this._desiredPositionDelta.y = 0;
if (this.cameraStyle == CameraStyle.lockOn){
let targetX = this.targetEntity.position.x;
let targetY = this.targetEntity.position.y;
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)
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)
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) {
this._targetCollider = this._targetEntity.getComponent<Collider>(Collider);
if (!this._targetCollider)
return;
}
let targetBounds = this.targetEntity.getComponent<Collider>(Collider).bounds;
if (!this._worldSpaceDeadZone.containsRect(targetBounds)){
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)
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)
else if (this._worldSpaceDeadZone.top > targetBounds.top)
this._desiredPositionDelta.y = targetBounds.top - this._worldSpaceDeadZone.top;
}
}
}
}
export enum CameraStyle {
lockOn,
cameraWindow,
public follow(targetEntity: Entity, cameraStyle: CameraStyle = CameraStyle.cameraWindow) {
this._targetEntity = targetEntity;
this._cameraStyle = cameraStyle;
switch (this._cameraStyle) {
case CameraStyle.cameraWindow:
let w = this.bounds.width / 6;
let h = this.bounds.height / 3;
this.deadzone = new Rectangle((this.bounds.width - w) / 2, (this.bounds.height - h) / 2, w, h);
break;
case CameraStyle.lockOn:
this.deadzone = new Rectangle(this.bounds.width / 2, this.bounds.height / 2, 10, 10);
break;
}
}
/**
* 以给定的尺寸设置当前相机边界中心的死区
* @param width
* @param height
*/
public setCenteredDeadzone(width: number, height: number) {
this.deadzone = new Rectangle((this.bounds.width - width) / 2, (this.bounds.height - height) / 2, width, height);
}
}
}

View File

@@ -0,0 +1,10 @@
module es {
/**
* 用于比较组件更新排序
*/
export class IUpdatableComparer {
public compare(a: Component, b: Component){
return a.updateOrder - b.updateOrder;
}
}
}

View File

@@ -1,161 +1,210 @@
abstract class Collider extends Component {
/** 对撞机的基本形状 */
public shape: Shape;
protected _localOffset: Vector2 = Vector2.zero;
public get localOffset(){
return this._localOffset;
}
public set localOffset(){
module es {
export abstract class Collider extends Component {
/**
* 对撞机的基本形状
*/
public shape: Shape;
/**
* 将localOffset添加到实体。获取碰撞器几何图形的最终位置。
* 允许向一个实体添加多个碰撞器并分别定位,还允许你设置缩放/旋转
*/
public get localOffset(): Vector2{
return this._localOffset;
}
}
public _localOffsetLength: number;
/** 在处理冲突时physicsLayer可以用作过滤器。Flags类有帮助位掩码的方法。 */
public physicsLayer = 1 << 0;
/** 如果这个碰撞器是一个触发器,它将不会引起碰撞,但它仍然会触发事件 */
public isTrigger: boolean;
/**
* 这个对撞机在物理系统注册时的边界。
* 存储这个允许我们始终能够安全地从物理系统中移除对撞机,即使它在试图移除它之前已经被移动了。
*/
public registeredPhysicsBounds: Rectangle = new Rectangle();
/** 如果为true碰撞器将根据附加的变换缩放和旋转 */
public shouldColliderScaleAndRotateWithTransform = true;
/** 默认为所有层。 */
public collidesWithLayers = Physics.allLayers;
/**
* 将localOffset添加到实体。获取碰撞器几何图形的最终位置。
* 允许向一个实体添加多个碰撞器并分别定位,还允许你设置缩放/旋转
* @param value
*/
public set localOffset(value: Vector2){
this.setLocalOffset(value);
}
/** 标记来跟踪我们的实体是否被添加到场景中 */
protected _isParentEntityAddedToScene;
protected _colliderRequiresAutoSizing;
/** 标记来记录我们是否注册了物理系统 */
protected _isColliderRegistered;
/**
* 镖师碰撞器的绝对位置
*/
public get absolutePosition(): Vector2{
return Vector2.add(this.entity.transform.position, this._localOffset);
}
public get bounds(): Rectangle {
let shapeBounds = this.shape.bounds;
let colliderBuonds = new Rectangle(this.entity.x, this.entity.y, shapeBounds.width, shapeBounds.height);
return colliderBuonds;
}
/**
* 封装变换。如果碰撞器没和实体一起旋转 则返回transform.rotation
*/
public get rotation(): number{
if (this.shouldColliderScaleAndRotateWithTransform && this.entity)
return this.entity.transform.rotation;
/**
* 将localOffset添加到实体。获取碰撞器的最终位置。
* 这允许您向一个实体添加多个碰撞器并分别定位它们。
* @param offset
*/
public setLocalOffset(offset: Vector2): Collider{
if (this._localOffset != offset){
this.unregisterColliderWithPhysicsSystem();
this._localOffset = offset;
this._localOffsetLength = this._localOffset.length();
return 0;
}
/**
* 如果这个碰撞器是一个触发器,它将不会引起碰撞,但它仍然会触发事件
*/
public isTrigger: boolean;
/**
* 在处理冲突时physicsLayer可以用作过滤器。Flags类有帮助位掩码的方法
*/
public physicsLayer = 1 << 0;
/**
* 碰撞器在使用移动器移动时应该碰撞的层
* 默认为所有层
*/
public collidesWithLayers = Physics.allLayers;
/**
* 如果为true碰撞器将根据附加的变换缩放和旋转
*/
public shouldColliderScaleAndRotateWithTransform = true;
public get bounds(): Rectangle {
this.shape.recalculateBounds(this);
return this.shape.bounds;
}
/**
* 这个对撞机在物理系统注册时的边界。
* 存储这个允许我们始终能够安全地从物理系统中移除对撞机,即使它在试图移除它之前已经被移动了。
*/
public registeredPhysicsBounds: Rectangle = new Rectangle();
protected _colliderRequiresAutoSizing;
protected _localOffset: Vector2 = Vector2.zero;
public _localOffsetLength: number;
/**
* 标记来跟踪我们的实体是否被添加到场景中
*/
protected _isParentEntityAddedToScene;
/**
* 标记来记录我们是否注册了物理系统
*/
protected _isColliderRegistered;
/**
* 将localOffset添加到实体。获取碰撞器的最终位置。
* 这允许您向一个实体添加多个碰撞器并分别定位它们。
* @param offset
*/
public setLocalOffset(offset: Vector2): Collider{
if (this._localOffset != offset){
this.unregisterColliderWithPhysicsSystem();
this._localOffset = offset;
this._localOffsetLength = this._localOffset.length();
this.registerColliderWithPhysicsSystem();
}
return this;
}
/**
* 如果为true碰撞器将根据附加的变换缩放和旋转
* @param shouldColliderScaleAndRotationWithTransform
*/
public setShouldColliderScaleAndRotateWithTransform(shouldColliderScaleAndRotationWithTransform: boolean): Collider {
this.shouldColliderScaleAndRotateWithTransform = shouldColliderScaleAndRotationWithTransform;
return this;
}
public onAddedToEntity() {
if (this._colliderRequiresAutoSizing) {
if (!(this instanceof BoxCollider || this instanceof CircleCollider)) {
console.error("Only box and circle colliders can be created automatically");
return;
}
let renderable = this.entity.getComponent<RenderableComponent>(RenderableComponent);
if (renderable) {
let bounds = renderable.bounds;
// 这里我们需要大小*反尺度,因为当我们自动调整碰撞器的大小时,它需要没有缩放的渲染
let width = bounds.width / this.entity.scale.x;
let height = bounds.height / this.entity.scale.y;
// 圆碰撞器需要特别注意原点
if (this instanceof CircleCollider){
let circleCollider = this as CircleCollider;
circleCollider.radius = Math.max(width, height) * 0.5;
} else {
this.width = width;
this.height = height;
}
// 获取渲染的中心将其转移到本地坐标并使用它作为碰撞器的localOffset
this.localOffset = Vector2.subtract(bounds.center, this.entity.transform.position);
} else {
console.warn("Collider has no shape and no RenderableComponent. Can't figure out how to size it.");
}
}
this._isParentEntityAddedToScene = true;
this.registerColliderWithPhysicsSystem();
}
return this;
}
/**
* 父实体会在不同的时间调用它(当添加到场景,启用,等等)
*/
public registerColliderWithPhysicsSystem() {
// 如果在将我们添加到实体之前更改了origin等属性则实体可以为null
if (this._isParentEntityAddedToScene && !this._isColliderRegistered) {
Physics.addCollider(this);
this._isColliderRegistered = true;
public onRemovedFromEntity() {
this.unregisterColliderWithPhysicsSystem();
this._isParentEntityAddedToScene = false;
}
}
/**
* 父实体会在不同的时候调用它(从场景中移除,禁用,等等)
*/
public unregisterColliderWithPhysicsSystem() {
if (this._isParentEntityAddedToScene && this._isColliderRegistered) {
Physics.removeCollider(this);
public onEntityTransformChanged(comp: transform.Component) {
if (this._isColliderRegistered)
Physics.updateCollider(this);
}
this._isColliderRegistered = false;
}
/**
* 检查这个形状是否与物理系统中的其他对撞机重叠
* @param other
*/
public overlaps(other: Collider) {
return this.shape.overlaps(other.shape);
}
public onEnabled() {
this.registerColliderWithPhysicsSystem();
}
/**
* 检查这个与运动应用的碰撞器(移动向量)是否与碰撞器碰撞。如果是这样将返回true并且结果将填充碰撞数据。
* @param collider
* @param motion
*/
public collidesWith(collider: Collider, motion: Vector2) {
// 改变形状的位置,使它在移动后的位置,这样我们可以检查重叠
let oldPosition = this.entity.position;
this.entity.position = Vector2.add(this.entity.position, motion);
public onDisabled() {
this.unregisterColliderWithPhysicsSystem();
}
let result = this.shape.collidesWithShape(collider.shape);
if (result)
result.collider = collider;
// 将图形位置返回到检查前的位置
this.entity.position = oldPosition;
return result;
}
public onAddedToEntity() {
if (this._colliderRequiresAutoSizing) {
if (!(this instanceof BoxCollider || this instanceof CircleCollider)) {
console.error("Only box and circle colliders can be created automatically");
}
let renderable = this.entity.getComponent<RenderableComponent>(RenderableComponent);
if (renderable) {
let bounds = renderable.bounds;
// 这里我们需要大小*反尺度,因为当我们自动调整碰撞器的大小时,它需要没有缩放的渲染
let width = bounds.width / this.entity.scale.x;
let height = bounds.height / this.entity.scale.y;
// 圆碰撞器需要特别注意原点
if (this instanceof CircleCollider){
let circleCollider = this as CircleCollider;
circleCollider.radius = Math.max(width, height) * 0.5;
} else {
this.width = width;
this.height = height;
}
// 获取渲染的中心将其转移到本地坐标并使用它作为碰撞器的localOffset
this.localOffset = Vector2.subtract(bounds.center, this.entity.position);
} else {
console.warn("Collider has no shape and no RenderableComponent. Can't figure out how to size it.");
/**
* 父实体会在不同的时间调用它(当添加到场景,启用,等等)
*/
public registerColliderWithPhysicsSystem() {
// 如果在将我们添加到实体之前更改了origin等属性则实体可以为null
if (this._isParentEntityAddedToScene && !this._isColliderRegistered) {
Physics.addCollider(this);
this._isColliderRegistered = true;
}
}
this._isParentEntityAddedToScene = true;
this.registerColliderWithPhysicsSystem();
}
/**
* 父实体会在不同的时候调用它(从场景中移除,禁用,等等)
*/
public unregisterColliderWithPhysicsSystem() {
if (this._isParentEntityAddedToScene && this._isColliderRegistered) {
Physics.removeCollider(this);
}
this._isColliderRegistered = false;
}
public onRemovedFromEntity() {
this.unregisterColliderWithPhysicsSystem();
this._isParentEntityAddedToScene = false;
}
/**
* 检查这个形状是否与物理系统中的其他对撞机重叠
* @param other
*/
public overlaps(other: Collider) {
return this.shape.overlaps(other.shape);
}
public onEnabled() {
this.registerColliderWithPhysicsSystem();
}
/**
* 检查这个与运动应用的碰撞器(移动向量)是否与碰撞器碰撞。如果是这样将返回true并且结果将填充碰撞数据。
* @param collider
* @param motion
*/
public collidesWith(collider: Collider, motion: Vector2) {
// 改变形状的位置,使它在移动后的位置,这样我们可以检查重叠
let oldPosition = this.entity.position;
this.entity.position = Vector2.add(this.entity.position, motion);
public onDisabled() {
this.unregisterColliderWithPhysicsSystem();
}
let result = this.shape.collidesWithShape(collider.shape);
if (result)
result.collider = collider;
public onEntityTransformChanged(comp: TransformComponent) {
if (this._isColliderRegistered)
Physics.updateCollider(this);
}
// 将图形位置返回到检查前的位置
this.entity.position = oldPosition;
public update(){
let renderable = this.entity.getComponent<RenderableComponent>(RenderableComponent);
if (renderable){
this.$setX(renderable.x);
this.$setY(renderable.y);
return result;
}
}
}
}

View File

@@ -1,4 +1,6 @@
/** 回收实例的组件类型。 */
abstract class PooledComponent extends Component {
public abstract reset();
}
module es {
/** 回收实例的组件类型。 */
export abstract class PooledComponent extends Component {
public abstract reset();
}
}

View File

@@ -1,56 +1,172 @@
///<reference path="./PooledComponent.ts" />
/**
* 所有可渲染组件的基类
*/
abstract class RenderableComponent extends PooledComponent implements IRenderable {
private _isVisible: boolean;
protected _areBoundsDirty = true;
protected _bounds: Rectangle = new Rectangle();
protected _localOffset: Vector2 = Vector2.zero;
module es {
/**
* 所有可渲染组件的基类
*/
export abstract class RenderableComponent extends Component implements IRenderable {
/**
* renderableComponent的宽度
* 如果你不重写bounds属性则需要实现这个
*/
public get width() {
return this.bounds.width;
}
public color: number = 0x000000;
/**
* renderableComponent的高度
* 如果你不重写bounds属性则需要实现这个
*/
public get height() {
return this.bounds.height;
}
public get width(){
return this.getWidth();
}
/**
* 这个物体的AABB, 用于相机剔除
*/
public get bounds(): Rectangle {
if (this._areBoundsDirty){
this._bounds.calculateBounds(this.entity.transform.position, this._localOffset, Vector2.zero,
this.entity.transform.scale, this.entity.transform.rotation, this.width, this.height);
this._areBoundsDirty = false;
}
public get height(){
return this.getHeight();
}
return this._bounds;
}
public get isVisible(){
return this._isVisible;
}
/**
* 较低的渲染层在前面,较高的在后面
*/
public get renderLayer(): number{
return this._renderLayer;
}
public set isVisible(value: boolean){
this._isVisible = value;
public set renderLayer(value: number){
if (this._isVisible)
this.onBecameVisible();
else
this.onBecameInvisible();
}
}
public get bounds(): Rectangle{
return new Rectangle(this.getBounds().x, this.getBounds().y, this.getBounds().width, this.getBounds().height);
}
/**
* 用于着色器处理精灵
*/
public color: number = 0x000000;
protected getWidth(){
return this.bounds.width;
}
/**
* 从父实体的偏移量。用于向需要特定定位的实体
*/
public get localOffset(): Vector2{
return this._localOffset;
}
protected getHeight(){
return this.bounds.height;
}
/**
* 从父实体的偏移量。用于向需要特定定位的实体
* @param value
*/
public set localOffset(value: Vector2){
this.setLocalOffset(value);
}
protected onBecameVisible(){}
/**
* 可渲染的可见性。状态的改变会调用onBecameVisible/onBecameInvisible方法
*/
public get isVisible() {
return this._isVisible;
}
protected onBecameInvisible(){}
/**
* 可渲染的可见性。状态的改变会调用onBecameVisible/onBecameInvisible方法
* @param value
*/
public set isVisible(value: boolean) {
if (this._isVisible != value){
this._isVisible = value;
public abstract render(camera: Camera);
if (this._isVisible)
this.onBecameVisible();
else
this.onBecameInvisible();
}
}
public isVisibleFromCamera(camera: Camera): boolean{
this.isVisible = camera.getBounds().intersects(this.getBounds());
return this.isVisible;
protected _localOffset: Vector2 = Vector2.zero;
protected _renderLayer: number = 0;
protected _bounds: Rectangle = new Rectangle();
private _isVisible: boolean;
protected _areBoundsDirty = true;
public onEntityTransformChanged(comp: transform.Component) {
this._areBoundsDirty = true;
}
/**
* 由渲染器调用。可以使用摄像机进行剔除
* @param camera
*/
public abstract render(camera: Camera);
/**
* 当renderableComponent进入相机框架时调用
* 如果渲染器不适用isVisibleFromCamera进行剔除检查 这些方法不会被调用
*/
protected onBecameVisible() {
}
/**
* 当renderableComponent离开相机框架时调用
* 如果渲染器不适用isVisibleFromCamera进行剔除检查 这些方法不会被调用
*/
protected onBecameInvisible() {
}
/**
* 如果renderableComponent的边界与camera.bounds相交 返回true
* 用于处理isVisible标志的状态开关
* 在渲染方法中使用这个方法来决定是否渲染
* @param camera
*/
public isVisibleFromCamera(camera: Camera): boolean {
this.isVisible = camera.bounds.intersects(this.bounds);
return this.isVisible;
}
/**
* 较低的渲染层在前面,较高的在后面
* @param renderLayer
*/
public setRenderLayer(renderLayer: number): RenderableComponent{
if (renderLayer != this._renderLayer){
let oldRenderLayer = this._renderLayer;
this._renderLayer = renderLayer;
// 如果该组件拥有一个实体那么是由ComponentList管理需要通知它改变了渲染层
if (this.entity && this.entity.scene)
this.entity.scene.renderableComponents.updateRenderableRenderLayer(this, oldRenderLayer, this._renderLayer);
}
return this;
}
/**
* 用于着色器处理精灵
* @param color
*/
public setColor(color: number): RenderableComponent{
this.color = color;
return this;
}
/**
* 从父实体的偏移量。用于向需要特定定位的实体
* @param offset
*/
public setLocalOffset(offset: Vector2): RenderableComponent{
if (this._localOffset != offset){
this._localOffset = offset;
}
return this;
}
public toString(){
return `[RenderableComponent] ${this}, renderLayer: ${this.renderLayer}`;
}
}
}

View File

@@ -14,7 +14,7 @@ class Sprite {
this.origin = origin;
let inverseTexW = 1 / texture.textureWidth;
let inverseTexH = 1 / texture.textureHeight
let inverseTexH = 1 / texture.textureHeight;
this.uvs.x = sourceRect.x * inverseTexW;
this.uvs.y = sourceRect.y * inverseTexH;

View File

@@ -1,66 +1,120 @@
class SpriteRenderer extends RenderableComponent {
private _sprite: Sprite;
protected bitmap: egret.Bitmap;
module es {
export class SpriteRenderer extends RenderableComponent {
public get bounds(){
if (this._areBoundsDirty){
if (this._sprite){
this._bounds.calculateBounds(this.entity.transform.position, this._localOffset, this._origin,
this.entity.transform.scale, this.entity.transform.rotation, this._sprite.sourceRect.width,
this._sprite.sourceRect.height);
this._areBoundsDirty = false;
}
/** 应该由这个精灵显示的精灵 */
public get sprite(): Sprite {
return this._sprite;
}
/** 应该由这个精灵显示的精灵 */
public set sprite(value: Sprite) {
this.setSprite(value);
}
public setSprite(sprite: Sprite): SpriteRenderer {
this.removeChildren();
this._sprite = sprite;
if (this._sprite) {
this.anchorOffsetX = this._sprite.origin.x / this._sprite.sourceRect.width;
this.anchorOffsetY = this._sprite.origin.y / this._sprite.sourceRect.height;
return this._bounds;
}
}
this.bitmap = new egret.Bitmap(sprite.texture2D);
this.addChild(this.bitmap);
return this;
}
public setColor(color: number): SpriteRenderer {
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;
let colorFilter = new egret.ColorMatrixFilter(colorMatrix);
this.filters = [colorFilter];
return this;
}
public isVisibleFromCamera(camera: Camera): boolean {
this.isVisible = new Rectangle(0, 0, this.stage.stageWidth, this.stage.stageHeight).intersects(this.bounds);
this.visible = this.isVisible;
return this.isVisible;
}
/** 渲染处理 在每个模块中处理各自的渲染逻辑 */
public render(camera: Camera) {
if (this.x != -camera.position.x + camera.origin.x ||
this.y != -camera.position.y + camera.origin.y) {
this.x = -camera.position.x + camera.origin.x;
this.y = -camera.position.y + camera.origin.y;
this.entity.onEntityTransformChanged(TransformComponent.position);
/**
* 精灵的原点。这是在设置精灵时自动设置的
*/
public get origin(): Vector2{
return this._origin;
}
}
public onRemovedFromEntity() {
if (this.parent)
this.parent.removeChild(this);
}
/**
* 精灵的原点。这是在设置精灵时自动设置的
* @param value
*/
public set origin(value: Vector2){
this.setOrigin(value);
}
public reset() {
/**
* 用归一化方法设置原点
* x/y 均为 0-1
*/
public get originNormalized(): Vector2{
return new Vector2(this._origin.x / this.width * this.entity.transform.scale.x,
this._origin.y / this.height * this.entity.transform.scale.y);
}
/**
* 用归一化方法设置原点
* x/y 均为 0-1
* @param value
*/
public set originNormalized(value: Vector2){
this.setOrigin(new Vector2(value.x * this.width / this.entity.transform.scale.x,
value.y * this.height / this.entity.transform.scale.y));
}
/**
* 应该由这个精灵显示的精灵
* 当设置时精灵的原点也被设置为精灵的origin
*/
public get sprite(): Sprite {
return this._sprite;
}
/**
* 应该由这个精灵显示的精灵
* 当设置时精灵的原点也被设置为精灵的origin
* @param value
*/
public set sprite(value: Sprite) {
this.setSprite(value);
}
protected _origin: Vector2;
protected _sprite: Sprite;
constructor(sprite: Sprite | egret.Texture) {
super();
if (sprite instanceof Sprite)
this.setSprite(sprite);
else if(sprite instanceof egret.Texture)
this.setSprite(new Sprite(sprite));
}
/**
* 设置精灵并更新精灵的原点以匹配sprite.origin
* @param sprite
*/
public setSprite(sprite: Sprite): SpriteRenderer {
this._sprite = sprite;
if (this._sprite) {
this._origin = this._sprite.origin;
}
return this;
}
/**
* 设置可渲染的原点
* @param origin
*/
public setOrigin(origin: Vector2): SpriteRenderer{
if (this._origin != origin){
this._origin = origin;
this._areBoundsDirty = true;
}
return this;
}
/**
* 用归一化方法设置原点
* x/y 均为 0-1
* @param value
*/
public setOriginNormalized(value: Vector2): SpriteRenderer{
this.setOrigin(new Vector2(value.x * this.width / this.entity.transform.scale.x,
value.y * this.height / this.entity.transform.scale.y));
return this;
}
public render(camera: Camera) {
// TODO: render
}
}
}