Implement smooth transitions
This commit is contained in:
parent
b7fec57c04
commit
584728a129
5 changed files with 101 additions and 18 deletions
|
@ -6,6 +6,7 @@ import Entity from '../model/Entity';
|
||||||
import EntityPosition from '../model/EntityPosition';
|
import EntityPosition from '../model/EntityPosition';
|
||||||
import MapData from '../model/MapData';
|
import MapData from '../model/MapData';
|
||||||
import Position from '../model/Position';
|
import Position from '../model/Position';
|
||||||
|
import Transition from '../model/Transition';
|
||||||
|
|
||||||
import InputHandler from '../view/InputHandler';
|
import InputHandler from '../view/InputHandler';
|
||||||
import MapView from '../view/MapView';
|
import MapView from '../view/MapView';
|
||||||
|
@ -38,24 +39,47 @@ export default class MapContext {
|
||||||
this.entities[entity.position.asString()] = entity;
|
this.entities[entity.position.asString()] = entity;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private addTransition(entity: EntityPosition, dest: Position, start: number, dur: number) {
|
||||||
|
entity.transition = new Transition(start, start+dur, entity.position, dest);
|
||||||
|
}
|
||||||
|
|
||||||
|
private finishTransition(entity: EntityPosition) {
|
||||||
|
entity.position = entity.transition.dest;
|
||||||
|
entity.transition = null;
|
||||||
|
}
|
||||||
|
|
||||||
private updateState(time: number): boolean {
|
private updateState(time: number): boolean {
|
||||||
var ret = false;
|
var ret = false;
|
||||||
var dir = this.playerEntity.direction;
|
|
||||||
|
|
||||||
if (this.inputHandler.keys[InputHandler.Up])
|
while (true) {
|
||||||
dir = Direction.North;
|
var origTime = time;
|
||||||
else if (this.inputHandler.keys[InputHandler.Right])
|
|
||||||
dir = Direction.East;
|
if (this.playerEntity.transition && this.playerEntity.transition.end <= time) {
|
||||||
else if (this.inputHandler.keys[InputHandler.Down])
|
origTime = this.playerEntity.transition.end;
|
||||||
dir = Direction.South;
|
this.finishTransition(this.playerEntity);
|
||||||
else if (this.inputHandler.keys[InputHandler.Left])
|
ret = true;
|
||||||
dir = Direction.West;
|
}
|
||||||
|
|
||||||
|
if (this.playerEntity.transition)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
var dir: Direction = null;
|
||||||
|
|
||||||
|
if (this.inputHandler.keys[InputHandler.Up])
|
||||||
|
dir = Direction.North;
|
||||||
|
else if (this.inputHandler.keys[InputHandler.Right])
|
||||||
|
dir = Direction.East;
|
||||||
|
else if (this.inputHandler.keys[InputHandler.Down])
|
||||||
|
dir = Direction.South;
|
||||||
|
else if (this.inputHandler.keys[InputHandler.Left])
|
||||||
|
dir = Direction.West;
|
||||||
|
|
||||||
|
if (dir === null)
|
||||||
|
return ret;
|
||||||
|
|
||||||
if (this.playerEntity.direction !== dir) {
|
|
||||||
this.playerEntity.direction = dir;
|
this.playerEntity.direction = dir;
|
||||||
ret = true;
|
this.addTransition(this.playerEntity, this.playerEntity.position.translate(dir, 1),
|
||||||
|
origTime, 250);
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,14 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
|
|
||||||
import Direction from '../model/Direction';
|
import Direction from './Direction';
|
||||||
import Entity from './Entity';
|
import Entity from './Entity';
|
||||||
import Position from './Position';
|
import Position from './Position';
|
||||||
|
import Transition from './Transition';
|
||||||
|
|
||||||
|
|
||||||
export default class EntityPosition {
|
export default class EntityPosition {
|
||||||
|
public transition: Transition = null;
|
||||||
|
|
||||||
constructor(public entity: Entity, public position: Position, public direction: Direction) {}
|
constructor(public entity: Entity, public position: Position, public direction: Direction) {}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,35 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
|
|
||||||
|
import Direction from './Direction';
|
||||||
|
|
||||||
|
|
||||||
export default class Position {
|
export default class Position {
|
||||||
constructor(public x: number, public y: number) {}
|
constructor(public x: number, public y: number) {}
|
||||||
|
|
||||||
|
translate(dir: Direction, amount: number): Position {
|
||||||
|
var p = new Position(this.x, this.y);
|
||||||
|
|
||||||
|
switch (dir) {
|
||||||
|
case Direction.North:
|
||||||
|
p.y -= amount;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Direction.East:
|
||||||
|
p.x += amount;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Direction.South:
|
||||||
|
p.y += amount;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Direction.West:
|
||||||
|
p.x -= amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
asString(): string {
|
asString(): string {
|
||||||
return `${this.x},${this.y}`;
|
return `${this.x},${this.y}`;
|
||||||
}
|
}
|
||||||
|
|
8
src/model/Transition.ts
Normal file
8
src/model/Transition.ts
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
|
||||||
|
import Position from './Position';
|
||||||
|
|
||||||
|
export default class Transition {
|
||||||
|
constructor(public start: number, public end: number, public orig: Position, public dest: Position) {}
|
||||||
|
};
|
|
@ -92,18 +92,34 @@ export default class MapView {
|
||||||
this.ctx.drawImage(tile, x, y);
|
this.ctx.drawImage(tile, x, y);
|
||||||
}
|
}
|
||||||
|
|
||||||
private drawEntity(e: EntityPosition) {
|
private drawEntity(e: EntityPosition, time: number): boolean {
|
||||||
var sprite = this.entitySprites[e.entity.name];
|
var sprite = this.entitySprites[e.entity.name];
|
||||||
if (!sprite)
|
if (!sprite)
|
||||||
return;
|
return false;
|
||||||
|
|
||||||
|
var x: number, y: number;
|
||||||
|
|
||||||
|
if (e.transition) {
|
||||||
|
var t = e.transition;
|
||||||
|
var d = (time - t.start) / (t.end-t.start);
|
||||||
|
|
||||||
|
x = (1-d) * t.orig.x + d * t.dest.x;
|
||||||
|
y = (1-d) * t.orig.y + d * t.dest.y;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
x = e.position.x;
|
||||||
|
y = e.position.y;
|
||||||
|
}
|
||||||
|
|
||||||
this.ctx.drawImage(
|
this.ctx.drawImage(
|
||||||
sprite,
|
sprite,
|
||||||
e.direction*tileSize, 0,
|
e.direction*tileSize, 0,
|
||||||
tileSize, tileSize,
|
tileSize, tileSize,
|
||||||
e.position.x*tileSize, e.position.y*tileSize,
|
x*tileSize, y*tileSize,
|
||||||
tileSize, tileSize
|
tileSize, tileSize
|
||||||
);
|
);
|
||||||
|
|
||||||
|
return !!e.transition;
|
||||||
}
|
}
|
||||||
|
|
||||||
private draw(time: number) {
|
private draw(time: number) {
|
||||||
|
@ -131,9 +147,15 @@ export default class MapView {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
var animate = false;
|
||||||
|
|
||||||
this.getEntities().forEach(e => {
|
this.getEntities().forEach(e => {
|
||||||
this.drawEntity(e);
|
if (this.drawEntity(e, time))
|
||||||
|
animate = true;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (animate)
|
||||||
|
this.redraw();
|
||||||
}
|
}
|
||||||
|
|
||||||
redraw() {
|
redraw() {
|
||||||
|
|
Reference in a new issue