pxt-common-packages
Version:
Microsoft MakeCode (PXT) common packages
119 lines (108 loc) • 4.05 kB
text/typescript
namespace scene {
export class Camera {
// coordinate used for all physics computation
protected _offsetX: number;
protected _offsetY: number;
// coordinate used for draw sprites, may including shaking
drawOffsetX: number;
drawOffsetY: number;
sprite: Sprite;
protected _lastUpdatedSpriteX: number;
protected _lastUpdatedSpriteY: number;
protected shakeStartTime: number;
protected shakeDuration: number;
protected shakeAmplitude: number;
constructor() {
this._offsetX = 0;
this._offsetY = 0;
this.drawOffsetX = 0;
this.drawOffsetY = 0;
}
get offsetX() {
return this._offsetX;
}
set offsetX(v: number) {
const scene = game.currentScene();
if (scene.tileMap && scene.tileMap.enabled) {
this._offsetX = Math.floor(scene.tileMap.offsetX(v));
} else {
this._offsetX = Math.floor(v);
}
}
get offsetY() {
return this._offsetY;
}
set offsetY(v: number) {
const scene = game.currentScene();
if (scene.tileMap && scene.tileMap.enabled) {
this._offsetY = Math.floor(scene.tileMap.offsetY(v));
} else {
this._offsetY = Math.floor(v);
}
}
get x() {
return this.offsetX + (screen.width >> 1);
}
get y() {
return this.offsetY + (screen.height >> 1);
}
get left() {
return this.offsetX;
}
get right() {
return this.offsetX + screen.width;
}
get top() {
return this.offsetY;
}
get bottom() {
return this.offsetY + screen.height;
}
shake(amplitude: number = 4, duration: number = 1000) {
if (amplitude <= 0 || duration <= 0) {
this.shakeStartTime = undefined;
} else {
// this overrides any existing shake operation
this.shakeStartTime = control.millis();
this.shakeAmplitude = amplitude;
this.shakeDuration = duration;
// don't reset offset, will be recomputed in update
}
}
isUpdated() {
return !this.sprite || (this.sprite.x === this._lastUpdatedSpriteX && this.sprite.y === this._lastUpdatedSpriteY);
}
update() {
// if sprite, follow sprite
if (this.sprite) {
this._lastUpdatedSpriteX = this.sprite.x;
this._lastUpdatedSpriteY = this.sprite.y;
this.offsetX = this.sprite.left + (this.sprite.width >> 1) - (screen.width >> 1);
this.offsetY = this.sprite.top + (this.sprite.width >> 1) - (screen.height >> 1);
}
this.drawOffsetX = this.offsetX;
this.drawOffsetY = this.offsetY;
// apply shake if needed
if (this.shakeStartTime !== undefined) {
const elapsed = control.millis() - this.shakeStartTime;
if (elapsed >= this.shakeDuration) {
// we are done!
this.shakeStartTime = undefined;
} else {
// compute new shake
const percentComplete = elapsed / this.shakeDuration;
const dampStart = 0.75;
let damp = 1;
if (percentComplete >= dampStart)
damp = Math.max(0, 1 - percentComplete);
const f = this.shakeAmplitude * damp;
const x = (Math.random() * f) >> 0;
const y = (Math.random() * f) >> 0;
// apply to offset
this.drawOffsetX += x;
this.drawOffsetY += y;
}
}
}
}
}