Skip to content

Commit

Permalink
scaling from the bottom right corner
Browse files Browse the repository at this point in the history
  • Loading branch information
kleber-swf committed Aug 28, 2021
1 parent c4d5e75 commit dee36f4
Show file tree
Hide file tree
Showing 2 changed files with 133 additions and 37 deletions.
9 changes: 9 additions & 0 deletions example/game.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ function create() {
for (let i = 0; i < game.width; i += 100) grid.moveTo(i, 0).lineTo(i, game.height);
for (let i = 0; i < game.height; i += 100) grid.moveTo(0, i).lineTo(game.width, i);

grid.__skip = true;
game.world.add(grid);

const SIZE = 200;
Expand Down Expand Up @@ -119,6 +120,14 @@ function create() {
child.pivot.set(SIZE, SIZE);


child = el(DIST * 3, 100, SIZE*2, SIZE*2, parent, 'child');
child.pivot.set(SIZE * 1.5, SIZE * 1.5);

child = el(DIST * 3+200, 500+DIST, SIZE*2, SIZE*2, parent, 'child');
child.pivot.set(SIZE * 2.5, SIZE * 2.5);
child.scale.set(0.5, 0.5);


// game.add.text(0, 0, 'this text scrolls\nwith the background', { font: '32px Arial', fill: '#f26c4f', align: 'center' });

// logo1 = game.add.sprite(0, 0, 'phaser');
Expand Down
161 changes: 124 additions & 37 deletions src/editor/selection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ const ANCHOR_COLOR = 0xFFFFFF;
const ANCHOR_STROKE = 0xD9B448;

export class Selection extends Phaser.Graphics {
private readonly scaleKnobs: Phaser.Graphics[];
private readonly scaleKnobs: ScaleKnob[];

private _obj: PIXI.DisplayObject = null;
public get hasObject() { return !!this._obj; }
Expand All @@ -17,38 +17,32 @@ export class Selection extends Phaser.Graphics {
super(game);
this.name = '__selection';
this.__skip = true;
this.scaler = new Scaler();
this.scaleKnobs = this.createScaleKnobs();
this.setSelection(null);
}

private createScaleKnobs() {
const knobs: Phaser.Graphics[] = [];
for (let i = 0; i < 4; i++) {
const knob = new Phaser.Graphics(this.game)
.lineStyle(2, BORDER_STROKE, 1)
.beginFill(BORDER_COLOR, 1)
.drawCircle(0, 0, 16);
knob.inputEnabled = true;
knob.events.onInputDown.add(this.startScaling, this);
knob.events.onInputUp.add(this.stopScaling, this);
this.addChild(knob);
knobs.push(knob);
}
const knobs: ScaleKnob[] = [
new ScaleKnob(this.game, 1, 1, 0, 0), // top left
new ScaleKnob(this.game, 0, 1, 1, 0), // top right
new ScaleKnob(this.game, 0, 0, 1, 1), // bottom right
new ScaleKnob(this.game, 1, 0, 0, 1), // bottom left
];

knobs.forEach(k => {
k.events.onInputDown.add(() => this.startScaling(k), this);
k.events.onInputUp.add(this.stopScaling, this);
this.addChild(k);
});

return knobs;
}

public setSelection(obj: PIXI.DisplayObject) {
this._obj = obj;
this.clear();
if (!obj) return;

const bounds = obj.getBounds();
this._objUnscaledBounds.setTo(
bounds.x, bounds.y,
bounds.width / obj.scale.x,
bounds.height / obj.scale.y,
);

this.redraw();
if (this.visible = !!obj) this.redraw();
}

private redraw() {
Expand All @@ -57,7 +51,7 @@ export class Selection extends Phaser.Graphics {
const bounds = this._obj.getBounds();
this.drawBorder(bounds);
this.drawPivot(this._obj.pivot);
// this.drawAnchor(obj.anchor, bounds);
this.drawAnchor(this._obj.anchor, bounds);
this.drawScaleKnobs(bounds);
this.position.set(bounds.x, bounds.y);
}
Expand All @@ -73,6 +67,7 @@ export class Selection extends Phaser.Graphics {
}

private drawPivot(pivot: PIXI.Point) {
// TODO should't I use the scale too?
this
.lineStyle(3, PIVOT_STROKE, 1)
.moveTo(pivot.x - 10, pivot.y)
Expand Down Expand Up @@ -112,26 +107,118 @@ export class Selection extends Phaser.Graphics {


private _scaling = false;
private _objUnscaledBounds = new Phaser.Rectangle();
private scaler: Scaler;

private startScaling(knob: ScaleKnob) {
this.scaler.startScaling(this._obj, knob);
this._scaling = true;
}

public stopScaling() {
this._scaling = false;
this.scaler.stopScaling();
this.redraw();
}

public update() {
super.update();
if (this._scaling) {
this.scaler.scale(this.game.input.mousePointer);
this.redraw();
}
}

postUpdate() {
if (this._obj) this._obj.updateTransform();
}
}

export class ScaleKnob extends Phaser.Graphics {
constructor(game: Phaser.Game,
public readonly xwf: number,
public readonly yhf: number,
public readonly pxf: number,
public readonly pyf: number,
) {
super(game);
this.lineStyle(2, BORDER_STROKE, 1)
.beginFill(BORDER_COLOR, 1)
.drawCircle(0, 0, 16);
this.inputEnabled = true;
}
}


export class Scaler {
private objUnscaledBounds = new Phaser.Rectangle();
private obj: PIXI.DisplayObject;
private objOriginalPivot = new PIXI.Point();
private knob: ScaleKnob;

private startScaling() { this._scaling = true; }
private stopScaling() { this._scaling = false; }
private _left: boolean;
private _top: boolean;

private doScale(pointer: Phaser.Pointer) {
const distX = pointer.x - this._objUnscaledBounds.x;
const distY = pointer.y - this._objUnscaledBounds.y;
public startScaling(obj: PIXI.DisplayObject, knob: ScaleKnob) {
this.obj = obj;
this.knob = knob;
this._left = knob.xwf === 0;
this._top = knob.yhf === 0;

this._obj.scale.set(
distX / this._objUnscaledBounds.width,
distY / this._objUnscaledBounds.height,
const bounds = obj.getBounds();

this.objUnscaledBounds.setTo(
bounds.x + bounds.width * knob.xwf,
bounds.y + bounds.height * knob.yhf,
bounds.width / obj.scale.x,
bounds.height / obj.scale.y,
);

this.redraw();
const originalPivot = this.obj.pivot.clone();
const transformPivot = new Phaser.Point(
knob.xwf * (bounds.width / obj.scale.x),
knob.yhf * (bounds.height / obj.scale.y),
);

const pos = obj.position.clone();

obj.pivot.set(transformPivot.x, transformPivot.y);

obj.position.set(
pos.x + (transformPivot.x - originalPivot.x * obj.scale.x),
pos.y + (transformPivot.y - originalPivot.y * obj.scale.y),
);

this.objOriginalPivot = originalPivot;
}

public stopScaling() {
const obj = this.obj;
const bounds = obj.getBounds();
const pos = obj.position;
const knob = this.knob;
const originalPivot = this.objOriginalPivot;
const transformPivot = obj.pivot.clone();

obj.pivot.set(originalPivot.x, originalPivot.y);
obj.position.set(
pos.x - (transformPivot.x - originalPivot.x * obj.scale.x),
pos.y - (transformPivot.y - originalPivot.y * obj.scale.y),
);
}

public update() {
super.update();
if (this._scaling) this.doScale(this.game.input.mousePointer);
public scale(pointer: Phaser.Pointer) {
const ub = this.objUnscaledBounds;
const distX = this._left
? pointer.x - ub.x
: ub.x - pointer.x;

const distY = this._top
? pointer.y - ub.y
: ub.y - pointer.y;

this.obj.scale.set(
distX / ub.width,
distY / ub.height,
);
}
}

0 comments on commit dee36f4

Please sign in to comment.