added tween animations
This commit is contained in:
parent
32d63ea2bf
commit
5bf6e96778
|
@ -11,6 +11,7 @@ import Stats from "../Debug/Stats";
|
||||||
import ArrayUtils from "../Utils/ArrayUtils";
|
import ArrayUtils from "../Utils/ArrayUtils";
|
||||||
import RenderingManager from "../Rendering/RenderingManager";
|
import RenderingManager from "../Rendering/RenderingManager";
|
||||||
import CanvasRenderer from "../Rendering/CanvasRenderer";
|
import CanvasRenderer from "../Rendering/CanvasRenderer";
|
||||||
|
import Color from "../Utils/Color";
|
||||||
|
|
||||||
export default class GameLoop {
|
export default class GameLoop {
|
||||||
gameOptions: GameOptions;
|
gameOptions: GameOptions;
|
||||||
|
@ -63,6 +64,7 @@ export default class GameLoop {
|
||||||
readonly HEIGHT: number;
|
readonly HEIGHT: number;
|
||||||
private viewport: Viewport;
|
private viewport: Viewport;
|
||||||
private ctx: CanvasRenderingContext2D;
|
private ctx: CanvasRenderingContext2D;
|
||||||
|
private clearColor: Color;
|
||||||
|
|
||||||
// All of the necessary subsystems that need to run here
|
// All of the necessary subsystems that need to run here
|
||||||
private eventQueue: EventQueue;
|
private eventQueue: EventQueue;
|
||||||
|
@ -107,6 +109,7 @@ export default class GameLoop {
|
||||||
// For now, just hard code a canvas renderer. We can do this with options later
|
// For now, just hard code a canvas renderer. We can do this with options later
|
||||||
this.renderingManager = new CanvasRenderer();
|
this.renderingManager = new CanvasRenderer();
|
||||||
this.ctx = this.renderingManager.initializeCanvas(this.GAME_CANVAS, this.WIDTH, this.HEIGHT);
|
this.ctx = this.renderingManager.initializeCanvas(this.GAME_CANVAS, this.WIDTH, this.HEIGHT);
|
||||||
|
this.clearColor = new Color(this.gameOptions.clearColor.r, this.gameOptions.clearColor.g, this.gameOptions.clearColor.b);
|
||||||
|
|
||||||
// Size the viewport to the game canvas
|
// Size the viewport to the game canvas
|
||||||
this.viewport = new Viewport();
|
this.viewport = new Viewport();
|
||||||
|
@ -272,6 +275,8 @@ export default class GameLoop {
|
||||||
*/
|
*/
|
||||||
render(): void {
|
render(): void {
|
||||||
this.ctx.clearRect(0, 0, this.WIDTH, this.HEIGHT);
|
this.ctx.clearRect(0, 0, this.WIDTH, this.HEIGHT);
|
||||||
|
this.ctx.fillStyle = this.clearColor.toString();
|
||||||
|
this.ctx.fillRect(0, 0, this.WIDTH, this.HEIGHT);
|
||||||
this.sceneManager.render();
|
this.sceneManager.render();
|
||||||
Debug.render(this.ctx);
|
Debug.render(this.ctx);
|
||||||
Stats.render();
|
Stats.render();
|
||||||
|
@ -279,12 +284,14 @@ export default class GameLoop {
|
||||||
}
|
}
|
||||||
|
|
||||||
class GameOptions {
|
class GameOptions {
|
||||||
viewportSize: {x: number, y: number}
|
viewportSize: {x: number, y: number};
|
||||||
|
clearColor: {r: number, g: number, b: number}
|
||||||
|
|
||||||
static parse(options: Record<string, any>): GameOptions {
|
static parse(options: Record<string, any>): GameOptions {
|
||||||
let gOpt = new GameOptions();
|
let gOpt = new GameOptions();
|
||||||
|
|
||||||
gOpt.viewportSize = options.viewportSize ? options.viewportSize : {x: 800, y: 600};
|
gOpt.viewportSize = options.viewportSize ? options.viewportSize : {x: 800, y: 600};
|
||||||
|
gOpt.clearColor = options.clearColor ? options.clearColor : {r: 255, g: 255, b: 255};
|
||||||
|
|
||||||
return gOpt;
|
return gOpt;
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,6 +45,14 @@ export default abstract class CanvasNode extends GameNode implements Region {
|
||||||
this.scaleChanged();
|
this.scaleChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
set scaleX(value: number) {
|
||||||
|
this.scale.x = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
set scaleY(value: number) {
|
||||||
|
this.scale.y = value;
|
||||||
|
}
|
||||||
|
|
||||||
protected positionChanged(): void {
|
protected positionChanged(): void {
|
||||||
super.positionChanged();
|
super.positionChanged();
|
||||||
this.updateBoundary();
|
this.updateBoundary();
|
||||||
|
|
|
@ -9,11 +9,12 @@ import Shape from "../DataTypes/Shapes/Shape";
|
||||||
import Map from "../DataTypes/Map";
|
import Map from "../DataTypes/Map";
|
||||||
import AABB from "../DataTypes/Shapes/AABB";
|
import AABB from "../DataTypes/Shapes/AABB";
|
||||||
import NavigationPath from "../Pathfinding/NavigationPath";
|
import NavigationPath from "../Pathfinding/NavigationPath";
|
||||||
|
import TweenManager from "../Rendering/Animations/TweenManager";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The representation of an object in the game world
|
* The representation of an object in the game world
|
||||||
*/
|
*/
|
||||||
export default abstract class GameNode implements Positioned, Unique, Updateable, Physical, Actor, Debug_Renderable {
|
export default abstract class GameNode implements Positioned, Unique, Updateable, Physical, Actor {
|
||||||
/*---------- POSITIONED ----------*/
|
/*---------- POSITIONED ----------*/
|
||||||
private _position: Vec2;
|
private _position: Vec2;
|
||||||
|
|
||||||
|
@ -46,12 +47,14 @@ export default abstract class GameNode implements Positioned, Unique, Updateable
|
||||||
path: NavigationPath;
|
path: NavigationPath;
|
||||||
pathfinding: boolean = false;
|
pathfinding: boolean = false;
|
||||||
|
|
||||||
|
/*---------- GENERAL ----------*/
|
||||||
protected input: InputReceiver;
|
protected input: InputReceiver;
|
||||||
protected receiver: Receiver;
|
protected receiver: Receiver;
|
||||||
protected emitter: Emitter;
|
protected emitter: Emitter;
|
||||||
protected scene: Scene;
|
protected scene: Scene;
|
||||||
protected layer: Layer;
|
protected layer: Layer;
|
||||||
|
tweens: TweenManager;
|
||||||
|
rotation: number;
|
||||||
|
|
||||||
constructor(){
|
constructor(){
|
||||||
this.input = InputReceiver.getInstance();
|
this.input = InputReceiver.getInstance();
|
||||||
|
@ -59,6 +62,8 @@ export default abstract class GameNode implements Positioned, Unique, Updateable
|
||||||
this._position.setOnChange(() => this.positionChanged());
|
this._position.setOnChange(() => this.positionChanged());
|
||||||
this.receiver = new Receiver();
|
this.receiver = new Receiver();
|
||||||
this.emitter = new Emitter();
|
this.emitter = new Emitter();
|
||||||
|
this.tweens = new TweenManager(this);
|
||||||
|
this.rotation = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*---------- POSITIONED ----------*/
|
/*---------- POSITIONED ----------*/
|
||||||
|
@ -190,6 +195,19 @@ export default abstract class GameNode implements Positioned, Unique, Updateable
|
||||||
this.aiActive = active;
|
this.aiActive = active;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*---------- TWEENABLE PROPERTIES ----------*/
|
||||||
|
set positionX(value: number) {
|
||||||
|
this.position.x = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
set positionY(value: number) {
|
||||||
|
this.position.y = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract set scaleX(value: number);
|
||||||
|
|
||||||
|
abstract set scaleY(value: number);
|
||||||
|
|
||||||
/*---------- GAME NODE ----------*/
|
/*---------- GAME NODE ----------*/
|
||||||
/**
|
/**
|
||||||
* Sets the scene for this object.
|
* Sets the scene for this object.
|
||||||
|
@ -226,7 +244,15 @@ export default abstract class GameNode implements Positioned, Unique, Updateable
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
abstract update(deltaT: number): void;
|
update(deltaT: number): void {
|
||||||
|
this.tweens.update(deltaT);
|
||||||
debug_render = (ctx: CanvasRenderingContext2D): void => {};
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum TweenableProperties{
|
||||||
|
posX = "positionX",
|
||||||
|
posY = "positionY",
|
||||||
|
scaleX = "scaleX",
|
||||||
|
scaleY = "scaleY",
|
||||||
|
rotation = "rotation"
|
||||||
}
|
}
|
|
@ -8,6 +8,4 @@ export default class Point extends Graphic {
|
||||||
this.position = position;
|
this.position = position;
|
||||||
this.size.set(5, 5);
|
this.size.set(5, 5);
|
||||||
}
|
}
|
||||||
|
|
||||||
update(deltaT: number): void {}
|
|
||||||
}
|
}
|
|
@ -38,6 +38,4 @@ export default class Rect extends Graphic {
|
||||||
getBorderWidth(): number {
|
getBorderWidth(): number {
|
||||||
return this.borderWidth;
|
return this.borderWidth;
|
||||||
}
|
}
|
||||||
|
|
||||||
update(deltaT: number): void {}
|
|
||||||
}
|
}
|
|
@ -21,7 +21,7 @@ export default class AnimatedSprite extends Sprite {
|
||||||
// Set the size of the sprite to the sprite size specified by the spritesheet
|
// Set the size of the sprite to the sprite size specified by the spritesheet
|
||||||
this.size.set(spritesheet.spriteWidth, spritesheet.spriteHeight);
|
this.size.set(spritesheet.spriteWidth, spritesheet.spriteHeight);
|
||||||
|
|
||||||
this.animation = new AnimationManager();
|
this.animation = new AnimationManager(this);
|
||||||
|
|
||||||
// Add the animations to the animated sprite
|
// Add the animations to the animated sprite
|
||||||
for(let animation of spritesheet.animations){
|
for(let animation of spritesheet.animations){
|
||||||
|
|
|
@ -8,6 +8,8 @@ import Vec2 from "../../DataTypes/Vec2";
|
||||||
export default class Sprite extends CanvasNode {
|
export default class Sprite extends CanvasNode {
|
||||||
imageId: string;
|
imageId: string;
|
||||||
imageOffset: Vec2;
|
imageOffset: Vec2;
|
||||||
|
invertX: boolean;
|
||||||
|
invertY: boolean;
|
||||||
|
|
||||||
constructor(imageId: string){
|
constructor(imageId: string){
|
||||||
super();
|
super();
|
||||||
|
@ -15,6 +17,8 @@ export default class Sprite extends CanvasNode {
|
||||||
let image = ResourceManager.getInstance().getImage(this.imageId);
|
let image = ResourceManager.getInstance().getImage(this.imageId);
|
||||||
this.size = new Vec2(image.width, image.height);
|
this.size = new Vec2(image.width, image.height);
|
||||||
this.imageOffset = Vec2.ZERO;
|
this.imageOffset = Vec2.ZERO;
|
||||||
|
this.invertX = false;
|
||||||
|
this.invertY = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -24,6 +28,4 @@ export default class Sprite extends CanvasNode {
|
||||||
setImageOffset(offset: Vec2): void {
|
setImageOffset(offset: Vec2): void {
|
||||||
this.imageOffset = offset;
|
this.imageOffset = offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
update(deltaT: number): void {}
|
|
||||||
}
|
}
|
|
@ -59,6 +59,8 @@ export default abstract class UIElement extends CanvasNode {
|
||||||
}
|
}
|
||||||
|
|
||||||
update(deltaT: number): void {
|
update(deltaT: number): void {
|
||||||
|
super.update(deltaT);
|
||||||
|
|
||||||
// See of this object was just clicked
|
// See of this object was just clicked
|
||||||
if(this.input.isMouseJustPressed()){
|
if(this.input.isMouseJustPressed()){
|
||||||
let clickPos = this.input.getMousePressPosition();
|
let clickPos = this.input.getMousePressPosition();
|
||||||
|
|
|
@ -9,6 +9,7 @@ import Shape from "../DataTypes/Shapes/Shape";
|
||||||
import MathUtils from "../Utils/MathUtils";
|
import MathUtils from "../Utils/MathUtils";
|
||||||
import OrthogonalTilemap from "../Nodes/Tilemaps/OrthogonalTilemap";
|
import OrthogonalTilemap from "../Nodes/Tilemaps/OrthogonalTilemap";
|
||||||
import AABB from "../DataTypes/Shapes/AABB";
|
import AABB from "../DataTypes/Shapes/AABB";
|
||||||
|
import Debug from "../Debug/Debug";
|
||||||
|
|
||||||
export default class BasicPhysicsManager extends PhysicsManager {
|
export default class BasicPhysicsManager extends PhysicsManager {
|
||||||
|
|
||||||
|
|
|
@ -40,7 +40,8 @@ export default class AnimationManager {
|
||||||
/** The onEnd event of a pending animation */
|
/** The onEnd event of a pending animation */
|
||||||
protected pendingOnEnd: string;
|
protected pendingOnEnd: string;
|
||||||
|
|
||||||
constructor(){
|
constructor(owner: CanvasNode){
|
||||||
|
this.owner = owner;
|
||||||
this.animationState = AnimationState.STOPPED;
|
this.animationState = AnimationState.STOPPED;
|
||||||
this.currentAnimation = "";
|
this.currentAnimation = "";
|
||||||
this.currentFrame = 0;
|
this.currentFrame = 0;
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
import { TweenableProperties } from "../../Nodes/GameNode";
|
||||||
|
import { EaseFunctionType } from "../../Utils/EaseFunctions";
|
||||||
|
|
||||||
export enum AnimationState {
|
export enum AnimationState {
|
||||||
STOPPED = 0,
|
STOPPED = 0,
|
||||||
PAUSED = 1,
|
PAUSED = 1,
|
||||||
|
@ -10,5 +13,33 @@ export class AnimationData {
|
||||||
}
|
}
|
||||||
|
|
||||||
export class TweenData {
|
export class TweenData {
|
||||||
|
// Members for initialization by the user
|
||||||
|
/** The amount of time in ms to wait before executing the tween */
|
||||||
|
startDelay: number;
|
||||||
|
/** The duration of time over which the value with change from start to end */
|
||||||
|
duration: number;
|
||||||
|
/** An array of the effects on the properties of the object */
|
||||||
|
effects: [{
|
||||||
|
property: TweenableProperties;
|
||||||
|
start: any;
|
||||||
|
end: any;
|
||||||
|
ease: EaseFunctionType;
|
||||||
|
}];
|
||||||
|
/** Whether or not this tween should reverse from end to start for each property when it finishes */
|
||||||
|
reverseOnComplete: boolean;
|
||||||
|
/** Whether or not this tween should loop when it completes */
|
||||||
|
loop: boolean;
|
||||||
|
|
||||||
|
// Members for management by the tween manager
|
||||||
|
/** The progress of this tween through its effects */
|
||||||
|
progress: number;
|
||||||
|
|
||||||
|
/** The amount of time in ms that has passed from when this tween started running */
|
||||||
|
elapsedTime: number;
|
||||||
|
|
||||||
|
/** The state of this tween */
|
||||||
|
animationState: AnimationState;
|
||||||
|
|
||||||
|
/** Whether or not this tween is currently reversing */
|
||||||
|
reversing: boolean;
|
||||||
}
|
}
|
141
src/Rendering/Animations/TweenManager.ts
Normal file
141
src/Rendering/Animations/TweenManager.ts
Normal file
|
@ -0,0 +1,141 @@
|
||||||
|
import Map from "../../DataTypes/Map";
|
||||||
|
import GameNode from "../../Nodes/GameNode";
|
||||||
|
import { AnimationState, TweenData } from "./AnimationTypes";
|
||||||
|
import EaseFunctions from "../../Utils/EaseFunctions";
|
||||||
|
import MathUtils from "../../Utils/MathUtils";
|
||||||
|
|
||||||
|
export default class TweenManager {
|
||||||
|
protected owner: GameNode;
|
||||||
|
|
||||||
|
protected tweens: Map<TweenData>;
|
||||||
|
|
||||||
|
constructor(owner: GameNode){
|
||||||
|
this.owner = owner;
|
||||||
|
this.tweens = new Map();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a tween to this game node
|
||||||
|
* @param key The name of the tween
|
||||||
|
* @param tween The data of the tween
|
||||||
|
*/
|
||||||
|
add(key: string, tween: Record<string, any> | TweenData): void {
|
||||||
|
let typedTween = <TweenData>tween;
|
||||||
|
|
||||||
|
// Initialize members that we need (and the user didn't provide)
|
||||||
|
typedTween.progress = 0;
|
||||||
|
typedTween.elapsedTime = 0;
|
||||||
|
typedTween.animationState = AnimationState.STOPPED;
|
||||||
|
|
||||||
|
this.tweens.add(key, typedTween);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Play a tween with a certain name
|
||||||
|
* @param key The name of the tween to play
|
||||||
|
* @param loop Whether or not the tween should loop
|
||||||
|
*/
|
||||||
|
play(key: string, loop?: boolean): void {
|
||||||
|
if(this.tweens.has(key)){
|
||||||
|
let tween = this.tweens.get(key);
|
||||||
|
|
||||||
|
// Set loop if needed
|
||||||
|
if(loop !== undefined){
|
||||||
|
tween.loop = loop;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start the tween running
|
||||||
|
tween.animationState = AnimationState.PLAYING;
|
||||||
|
tween.elapsedTime = 0;
|
||||||
|
tween.progress = 0;
|
||||||
|
tween.reversing = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pauses a playing tween. Does not affect tweens that are stopped.
|
||||||
|
* @param key The name of the tween to pause.
|
||||||
|
*/
|
||||||
|
pause(key: string): void {
|
||||||
|
if(this.tweens.has(key)){
|
||||||
|
this.tweens.get(key).animationState = AnimationState.PAUSED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resumes a paused tween.
|
||||||
|
* @param key The name of the tween to resume
|
||||||
|
*/
|
||||||
|
resume(key: string): void {
|
||||||
|
if(this.tweens.has(key)){
|
||||||
|
let tween = this.tweens.get(key);
|
||||||
|
if(tween.animationState === AnimationState.PAUSED)
|
||||||
|
tween.animationState = AnimationState.PLAYING;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stops a currently playing tween
|
||||||
|
* @param key
|
||||||
|
*/
|
||||||
|
stop(key: string): void {
|
||||||
|
if(this.tweens.has(key)){
|
||||||
|
this.tweens.get(key).animationState = AnimationState.STOPPED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
update(deltaT: number): void {
|
||||||
|
this.tweens.forEach(key => {
|
||||||
|
let tween = this.tweens.get(key);
|
||||||
|
if(tween.animationState === AnimationState.PLAYING){
|
||||||
|
// Update the progress of the tween
|
||||||
|
tween.elapsedTime += deltaT*1000;
|
||||||
|
|
||||||
|
// If we're past the startDelay, do the tween
|
||||||
|
if(tween.elapsedTime >= tween.startDelay){
|
||||||
|
if(!tween.reversing && tween.elapsedTime >= tween.startDelay + tween.duration){
|
||||||
|
// If we're over time, stop the tween, loop, or reverse
|
||||||
|
if(tween.reverseOnComplete){
|
||||||
|
// If we're over time and can reverse, do so
|
||||||
|
tween.reversing = true;
|
||||||
|
} else if(tween.loop){
|
||||||
|
// If we can't reverse and can loop, do so
|
||||||
|
tween.elapsedTime -= tween.duration;
|
||||||
|
} else {
|
||||||
|
// We aren't looping and can't reverse, so stop
|
||||||
|
tween.animationState = AnimationState.STOPPED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for the end of reversing
|
||||||
|
if(tween.reversing && tween.elapsedTime >= tween.startDelay + 2*tween.duration){
|
||||||
|
if(tween.loop){
|
||||||
|
tween.reversing = false;
|
||||||
|
tween.elapsedTime -= 2*tween.duration;
|
||||||
|
} else {
|
||||||
|
tween.animationState = AnimationState.STOPPED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the progress, make sure it is between 0 and 1. Errors from this should never be large
|
||||||
|
if(tween.reversing){
|
||||||
|
tween.progress = MathUtils.clamp01((2*tween.duration - (tween.elapsedTime- tween.startDelay))/tween.duration);
|
||||||
|
} else {
|
||||||
|
tween.progress = MathUtils.clamp01((tween.elapsedTime - tween.startDelay)/tween.duration);
|
||||||
|
}
|
||||||
|
|
||||||
|
for(let effect of tween.effects){
|
||||||
|
// Get the value from the ease function that corresponds to our progress
|
||||||
|
let ease = EaseFunctions[effect.ease](tween.progress);
|
||||||
|
|
||||||
|
// Use the value to lerp the property
|
||||||
|
let value = MathUtils.lerp(effect.start, effect.end, ease);
|
||||||
|
|
||||||
|
// Assign the value of the property
|
||||||
|
this.owner[effect.property] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -18,6 +18,7 @@ import Button from "../Nodes/UIElements/Button";
|
||||||
import Slider from "../Nodes/UIElements/Slider";
|
import Slider from "../Nodes/UIElements/Slider";
|
||||||
import TextInput from "../Nodes/UIElements/TextInput";
|
import TextInput from "../Nodes/UIElements/TextInput";
|
||||||
import AnimatedSprite from "../Nodes/Sprites/AnimatedSprite";
|
import AnimatedSprite from "../Nodes/Sprites/AnimatedSprite";
|
||||||
|
import Vec2 from "../DataTypes/Vec2";
|
||||||
|
|
||||||
export default class CanvasRenderer extends RenderingManager {
|
export default class CanvasRenderer extends RenderingManager {
|
||||||
protected ctx: CanvasRenderingContext2D;
|
protected ctx: CanvasRenderingContext2D;
|
||||||
|
@ -25,8 +26,11 @@ export default class CanvasRenderer extends RenderingManager {
|
||||||
protected tilemapRenderer: TilemapRenderer;
|
protected tilemapRenderer: TilemapRenderer;
|
||||||
protected uiElementRenderer: UIElementRenderer;
|
protected uiElementRenderer: UIElementRenderer;
|
||||||
|
|
||||||
|
protected origin: Vec2;
|
||||||
|
protected zoom: number;
|
||||||
|
|
||||||
constructor(){
|
constructor(){
|
||||||
super();;
|
super();
|
||||||
}
|
}
|
||||||
|
|
||||||
setScene(scene: Scene){
|
setScene(scene: Scene){
|
||||||
|
@ -79,6 +83,24 @@ export default class CanvasRenderer extends RenderingManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected renderNode(node: CanvasNode): void {
|
protected renderNode(node: CanvasNode): void {
|
||||||
|
// Calculate the origin of the viewport according to this sprite
|
||||||
|
this.origin = this.scene.getViewTranslation(node);
|
||||||
|
|
||||||
|
// Get the zoom level of the scene
|
||||||
|
this.zoom = this.scene.getViewScale();
|
||||||
|
|
||||||
|
// Move the canvas to the position of the node and rotate
|
||||||
|
let xScale = 1;
|
||||||
|
let yScale = 1;
|
||||||
|
|
||||||
|
if(node instanceof Sprite){
|
||||||
|
xScale = node.invertX ? -1 : 1;
|
||||||
|
yScale = node.invertY ? -1 : 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.ctx.setTransform(xScale, 0, 0, yScale, (node.position.x - this.origin.x)*this.zoom, (node.position.y - this.origin.y)*this.zoom);
|
||||||
|
this.ctx.rotate(node.rotation);
|
||||||
|
|
||||||
if(node instanceof AnimatedSprite){
|
if(node instanceof AnimatedSprite){
|
||||||
this.renderAnimatedSprite(<AnimatedSprite>node);
|
this.renderAnimatedSprite(<AnimatedSprite>node);
|
||||||
} else if(node instanceof Sprite){
|
} else if(node instanceof Sprite){
|
||||||
|
@ -88,18 +110,14 @@ export default class CanvasRenderer extends RenderingManager {
|
||||||
} else if(node instanceof UIElement){
|
} else if(node instanceof UIElement){
|
||||||
this.renderUIElement(<UIElement>node);
|
this.renderUIElement(<UIElement>node);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.ctx.setTransform(1, 0, 0, 1, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected renderSprite(sprite: Sprite): void {
|
protected renderSprite(sprite: Sprite): void {
|
||||||
// Get the image from the resource manager
|
// Get the image from the resource manager
|
||||||
let image = this.resourceManager.getImage(sprite.imageId);
|
let image = this.resourceManager.getImage(sprite.imageId);
|
||||||
|
|
||||||
// Calculate the origin of the viewport according to this sprite
|
|
||||||
let origin = this.scene.getViewTranslation(sprite);
|
|
||||||
|
|
||||||
// Get the zoom level of the scene
|
|
||||||
let zoom = this.scene.getViewScale();
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Coordinates in the space of the image:
|
Coordinates in the space of the image:
|
||||||
image crop start -> x, y
|
image crop start -> x, y
|
||||||
|
@ -111,15 +129,15 @@ export default class CanvasRenderer extends RenderingManager {
|
||||||
this.ctx.drawImage(image,
|
this.ctx.drawImage(image,
|
||||||
sprite.imageOffset.x, sprite.imageOffset.y,
|
sprite.imageOffset.x, sprite.imageOffset.y,
|
||||||
sprite.size.x, sprite.size.y,
|
sprite.size.x, sprite.size.y,
|
||||||
(sprite.position.x - origin.x - sprite.size.x*sprite.scale.x/2)*zoom, (sprite.position.y - origin.y - sprite.size.y*sprite.scale.y/2)*zoom,
|
(-sprite.size.x*sprite.scale.x/2)*this.zoom, (-sprite.size.y*sprite.scale.y/2)*this.zoom,
|
||||||
sprite.size.x * sprite.scale.x*zoom, sprite.size.y * sprite.scale.y*zoom);
|
sprite.size.x * sprite.scale.x*this.zoom, sprite.size.y * sprite.scale.y*this.zoom);
|
||||||
|
|
||||||
// Debug mode
|
// Debug mode
|
||||||
if(this.debug){
|
if(this.debug){
|
||||||
this.ctx.lineWidth = 4;
|
this.ctx.lineWidth = 4;
|
||||||
this.ctx.strokeStyle = "#00FF00"
|
this.ctx.strokeStyle = "#00FF00"
|
||||||
let b = sprite.boundary;
|
let b = sprite.boundary;
|
||||||
this.ctx.strokeRect(b.x - b.hw - origin.x, b.y - b.hh - origin.y, b.hw*2*zoom, b.hh*2*zoom);
|
this.ctx.strokeRect(-b.hw*this.zoom, -b.hh*this.zoom, b.hw*2*this.zoom, b.hh*2*this.zoom);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -127,12 +145,6 @@ export default class CanvasRenderer extends RenderingManager {
|
||||||
// Get the image from the resource manager
|
// Get the image from the resource manager
|
||||||
let image = this.resourceManager.getImage(sprite.imageId);
|
let image = this.resourceManager.getImage(sprite.imageId);
|
||||||
|
|
||||||
// Calculate the origin of the viewport according to this sprite
|
|
||||||
let origin = this.scene.getViewTranslation(sprite);
|
|
||||||
|
|
||||||
// Get the zoom level of the scene
|
|
||||||
let zoom = this.scene.getViewScale();
|
|
||||||
|
|
||||||
let animationIndex = sprite.animation.getIndexAndAdvanceAnimation();
|
let animationIndex = sprite.animation.getIndexAndAdvanceAnimation();
|
||||||
|
|
||||||
let animationOffset = sprite.getAnimationOffset(animationIndex);
|
let animationOffset = sprite.getAnimationOffset(animationIndex);
|
||||||
|
@ -141,30 +153,30 @@ export default class CanvasRenderer extends RenderingManager {
|
||||||
Coordinates in the space of the image:
|
Coordinates in the space of the image:
|
||||||
image crop start -> x, y
|
image crop start -> x, y
|
||||||
image crop size -> w, h
|
image crop size -> w, h
|
||||||
Coordinates in the space of the world
|
Coordinates in the space of the world (given we moved)
|
||||||
image draw start -> x, y
|
image draw start -> -w/2, -h/2
|
||||||
image draw size -> w, h
|
image draw size -> w, h
|
||||||
*/
|
*/
|
||||||
this.ctx.drawImage(image,
|
this.ctx.drawImage(image,
|
||||||
sprite.imageOffset.x + animationOffset.x, sprite.imageOffset.y + animationOffset.y,
|
sprite.imageOffset.x + animationOffset.x, sprite.imageOffset.y + animationOffset.y,
|
||||||
sprite.size.x, sprite.size.y,
|
sprite.size.x, sprite.size.y,
|
||||||
(sprite.position.x - origin.x - sprite.size.x*sprite.scale.x/2)*zoom, (sprite.position.y - origin.y - sprite.size.y*sprite.scale.y/2)*zoom,
|
(-sprite.size.x*sprite.scale.x/2)*this.zoom, (-sprite.size.y*sprite.scale.y/2)*this.zoom,
|
||||||
sprite.size.x * sprite.scale.x*zoom, sprite.size.y * sprite.scale.y*zoom);
|
sprite.size.x * sprite.scale.x*this.zoom, sprite.size.y * sprite.scale.y*this.zoom);
|
||||||
|
|
||||||
// Debug mode
|
// Debug mode
|
||||||
if(this.debug){
|
if(this.debug){
|
||||||
this.ctx.lineWidth = 4;
|
this.ctx.lineWidth = 4;
|
||||||
this.ctx.strokeStyle = "#00FF00"
|
this.ctx.strokeStyle = "#00FF00"
|
||||||
let b = sprite.boundary;
|
let b = sprite.boundary;
|
||||||
this.ctx.strokeRect(b.x - b.hw - origin.x, b.y - b.hh - origin.y, b.hw*2*zoom, b.hh*2*zoom);
|
this.ctx.strokeRect(-b.hw*this.zoom, -b.hh*this.zoom, b.hw*2*this.zoom, b.hh*2*this.zoom);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected renderGraphic(graphic: Graphic): void {
|
protected renderGraphic(graphic: Graphic): void {
|
||||||
if(graphic instanceof Point){
|
if(graphic instanceof Point){
|
||||||
this.graphicRenderer.renderPoint(<Point>graphic);
|
this.graphicRenderer.renderPoint(<Point>graphic, this.origin, this.zoom);
|
||||||
} else if(graphic instanceof Rect){
|
} else if(graphic instanceof Rect){
|
||||||
this.graphicRenderer.renderRect(<Rect>graphic);
|
this.graphicRenderer.renderRect(<Rect>graphic, this.origin, this.zoom);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -176,13 +188,13 @@ export default class CanvasRenderer extends RenderingManager {
|
||||||
|
|
||||||
protected renderUIElement(uiElement: UIElement): void {
|
protected renderUIElement(uiElement: UIElement): void {
|
||||||
if(uiElement instanceof Label){
|
if(uiElement instanceof Label){
|
||||||
this.uiElementRenderer.renderLabel(uiElement);
|
this.uiElementRenderer.renderLabel(uiElement, this.origin, this.zoom);
|
||||||
} else if(uiElement instanceof Button){
|
} else if(uiElement instanceof Button){
|
||||||
this.uiElementRenderer.renderButton(uiElement);
|
this.uiElementRenderer.renderButton(uiElement, this.origin, this.zoom);
|
||||||
} else if(uiElement instanceof Slider){
|
} else if(uiElement instanceof Slider){
|
||||||
this.uiElementRenderer.renderSlider(uiElement);
|
this.uiElementRenderer.renderSlider(uiElement, this.origin, this.zoom);
|
||||||
} else if(uiElement instanceof TextInput){
|
} else if(uiElement instanceof TextInput){
|
||||||
this.uiElementRenderer.renderTextInput(uiElement);
|
this.uiElementRenderer.renderTextInput(uiElement, this.origin, this.zoom);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,3 +1,4 @@
|
||||||
|
import Vec2 from "../../DataTypes/Vec2";
|
||||||
import Point from "../../Nodes/Graphics/Point";
|
import Point from "../../Nodes/Graphics/Point";
|
||||||
import Rect from "../../Nodes/Graphics/Rect";
|
import Rect from "../../Nodes/Graphics/Rect";
|
||||||
import ResourceManager from "../../ResourceManager/ResourceManager";
|
import ResourceManager from "../../ResourceManager/ResourceManager";
|
||||||
|
@ -17,28 +18,22 @@ export default class GraphicRenderer {
|
||||||
this.scene = scene;
|
this.scene = scene;
|
||||||
}
|
}
|
||||||
|
|
||||||
renderPoint(point: Point): void {
|
renderPoint(point: Point, origin: Vec2, zoom: number): void {
|
||||||
let origin = this.scene.getViewTranslation(point);
|
|
||||||
let zoom = this.scene.getViewScale();
|
|
||||||
|
|
||||||
this.ctx.fillStyle = point.color.toStringRGBA();
|
this.ctx.fillStyle = point.color.toStringRGBA();
|
||||||
this.ctx.fillRect((point.position.x - origin.x - point.size.x/2)*zoom, (point.position.y - origin.y - point.size.y/2)*zoom,
|
this.ctx.fillRect((-point.size.x/2)*zoom, (-point.size.y/2)*zoom,
|
||||||
point.size.x*zoom, point.size.y*zoom);
|
point.size.x*zoom, point.size.y*zoom);
|
||||||
}
|
}
|
||||||
|
|
||||||
renderRect(rect: Rect): void {
|
renderRect(rect: Rect, origin: Vec2, zoom: number): void {
|
||||||
let origin = this.scene.getViewTranslation(rect);
|
|
||||||
let zoom = this.scene.getViewScale();
|
|
||||||
|
|
||||||
// Draw the interior of the rect
|
// Draw the interior of the rect
|
||||||
if(rect.color.a !== 0){
|
if(rect.color.a !== 0){
|
||||||
this.ctx.fillStyle = rect.color.toStringRGB();
|
this.ctx.fillStyle = rect.color.toStringRGB();
|
||||||
this.ctx.fillRect((rect.position.x - rect.size.x/2 - origin.x)*zoom, (rect.position.y - rect.size.y/2 - origin.y)*zoom, rect.size.x*zoom, rect.size.y*zoom);
|
this.ctx.fillRect((-rect.size.x/2)*zoom, (-rect.size.y/2)*zoom, rect.size.x*zoom, rect.size.y*zoom);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Draw the border of the rect
|
// Draw the border of the rect
|
||||||
this.ctx.strokeStyle = rect.getBorderColor().toStringRGB();
|
this.ctx.strokeStyle = rect.getBorderColor().toStringRGB();
|
||||||
this.ctx.lineWidth = rect.getBorderWidth();
|
this.ctx.lineWidth = rect.getBorderWidth();
|
||||||
this.ctx.strokeRect((rect.position.x - rect.size.x/2 - origin.x)*zoom, (rect.position.y - rect.size.y/2 - origin.y)*zoom, rect.size.x*zoom, rect.size.y*zoom);
|
this.ctx.strokeRect((-rect.size.x/2)*zoom, (-rect.size.y/2)*zoom, rect.size.x*zoom, rect.size.y*zoom);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -21,16 +21,13 @@ export default class UIElementRenderer {
|
||||||
this.scene = scene;
|
this.scene = scene;
|
||||||
}
|
}
|
||||||
|
|
||||||
renderLabel(label: Label): void {
|
renderLabel(label: Label, origin: Vec2, zoom: number): void {
|
||||||
// If the size is unassigned (by the user or automatically) assign it
|
// If the size is unassigned (by the user or automatically) assign it
|
||||||
label.handleInitialSizing(this.ctx);
|
label.handleInitialSizing(this.ctx);
|
||||||
|
|
||||||
// Grab the global alpha so we can adjust it for this render
|
// Grab the global alpha so we can adjust it for this render
|
||||||
let previousAlpha = this.ctx.globalAlpha;
|
let previousAlpha = this.ctx.globalAlpha;
|
||||||
|
|
||||||
// Get the origin of the viewport according to this label
|
|
||||||
let origin = this.scene.getViewTranslation(label);
|
|
||||||
|
|
||||||
// Get the font and text position in label
|
// Get the font and text position in label
|
||||||
this.ctx.font = label.getFontString();
|
this.ctx.font = label.getFontString();
|
||||||
let offset = label.calculateTextOffset(this.ctx);
|
let offset = label.calculateTextOffset(this.ctx);
|
||||||
|
@ -38,39 +35,37 @@ export default class UIElementRenderer {
|
||||||
// Stroke and fill a rounded rect and give it text
|
// Stroke and fill a rounded rect and give it text
|
||||||
this.ctx.globalAlpha = label.backgroundColor.a;
|
this.ctx.globalAlpha = label.backgroundColor.a;
|
||||||
this.ctx.fillStyle = label.calculateBackgroundColor();
|
this.ctx.fillStyle = label.calculateBackgroundColor();
|
||||||
this.ctx.fillRoundedRect(label.position.x - origin.x - label.size.x/2, label.position.y - origin.y - label.size.y/2,
|
this.ctx.fillRoundedRect(-label.size.x/2, -label.size.y/2,
|
||||||
label.size.x, label.size.y, label.borderRadius);
|
label.size.x, label.size.y, label.borderRadius);
|
||||||
|
|
||||||
this.ctx.strokeStyle = label.calculateBorderColor();
|
this.ctx.strokeStyle = label.calculateBorderColor();
|
||||||
this.ctx.globalAlpha = label.borderColor.a;
|
this.ctx.globalAlpha = label.borderColor.a;
|
||||||
this.ctx.lineWidth = label.borderWidth;
|
this.ctx.lineWidth = label.borderWidth;
|
||||||
this.ctx.strokeRoundedRect(label.position.x - origin.x - label.size.x/2, label.position.y - origin.y - label.size.y/2,
|
this.ctx.strokeRoundedRect(-label.size.x/2, -label.size.y/2,
|
||||||
label.size.x, label.size.y, label.borderRadius);
|
label.size.x, label.size.y, label.borderRadius);
|
||||||
|
|
||||||
this.ctx.fillStyle = label.calculateTextColor();
|
this.ctx.fillStyle = label.calculateTextColor();
|
||||||
this.ctx.globalAlpha = label.textColor.a;
|
this.ctx.globalAlpha = label.textColor.a;
|
||||||
this.ctx.fillText(label.text, label.position.x + offset.x - origin.x - label.size.x/2, label.position.y + offset.y - origin.y - label.size.y/2);
|
this.ctx.fillText(label.text, offset.x - label.size.x/2, offset.y - label.size.y/2);
|
||||||
|
|
||||||
this.ctx.globalAlpha = previousAlpha;
|
this.ctx.globalAlpha = previousAlpha;
|
||||||
}
|
}
|
||||||
|
|
||||||
renderButton(button: Button): void {
|
renderButton(button: Button, origin: Vec2, zoom: number): void {
|
||||||
this.renderLabel(button);
|
this.renderLabel(button, origin, zoom);
|
||||||
}
|
}
|
||||||
|
|
||||||
renderSlider(slider: Slider): void {
|
renderSlider(slider: Slider, origin: Vec2, zoom: number): void {
|
||||||
// Grab the global alpha so we can adjust it for this render
|
// Grab the global alpha so we can adjust it for this render
|
||||||
let previousAlpha = this.ctx.globalAlpha;
|
let previousAlpha = this.ctx.globalAlpha;
|
||||||
this.ctx.globalAlpha = slider.getLayer().getAlpha();
|
this.ctx.globalAlpha = slider.getLayer().getAlpha();
|
||||||
|
|
||||||
let origin = this.scene.getViewTranslation(slider);
|
|
||||||
|
|
||||||
// Calcualate the slider size
|
// Calcualate the slider size
|
||||||
let sliderSize = new Vec2(slider.size.x, 2);
|
let sliderSize = new Vec2(slider.size.x, 2);
|
||||||
|
|
||||||
// Draw the slider
|
// Draw the slider
|
||||||
this.ctx.fillStyle = slider.sliderColor.toString();
|
this.ctx.fillStyle = slider.sliderColor.toString();
|
||||||
this.ctx.fillRoundedRect(slider.position.x - origin.x - sliderSize.x/2, slider.position.y - origin.y - sliderSize.y/2,
|
this.ctx.fillRoundedRect(-sliderSize.x/2, -sliderSize.y/2,
|
||||||
sliderSize.x, sliderSize.y, slider.borderRadius);
|
sliderSize.x, sliderSize.y, slider.borderRadius);
|
||||||
|
|
||||||
// Calculate the nib size and position
|
// Calculate the nib size and position
|
||||||
|
@ -80,20 +75,20 @@ export default class UIElementRenderer {
|
||||||
|
|
||||||
// Draw the nib
|
// Draw the nib
|
||||||
this.ctx.fillStyle = slider.nibColor.toString();
|
this.ctx.fillStyle = slider.nibColor.toString();
|
||||||
this.ctx.fillRoundedRect(nibPosition.x - origin.x - nibSize.x/2, nibPosition.y - origin.y - nibSize.y/2,
|
this.ctx.fillRoundedRect(-nibSize.x/2, -nibSize.y/2,
|
||||||
nibSize.x, nibSize.y, slider.borderRadius);
|
nibSize.x, nibSize.y, slider.borderRadius);
|
||||||
|
|
||||||
// Reset the alpha
|
// Reset the alpha
|
||||||
this.ctx.globalAlpha = previousAlpha;
|
this.ctx.globalAlpha = previousAlpha;
|
||||||
}
|
}
|
||||||
|
|
||||||
renderTextInput(textInput: TextInput): void {
|
renderTextInput(textInput: TextInput, origin: Vec2, zoom: number): void {
|
||||||
// Show a cursor sometimes
|
// Show a cursor sometimes
|
||||||
if(textInput.focused && textInput.cursorCounter % 60 > 30){
|
if(textInput.focused && textInput.cursorCounter % 60 > 30){
|
||||||
textInput.text += "|";
|
textInput.text += "|";
|
||||||
}
|
}
|
||||||
|
|
||||||
this.renderLabel(textInput);
|
this.renderLabel(textInput, origin, zoom);
|
||||||
|
|
||||||
if(textInput.focused){
|
if(textInput.focused){
|
||||||
if(textInput.cursorCounter % 60 > 30){
|
if(textInput.cursorCounter % 60 > 30){
|
||||||
|
|
|
@ -120,6 +120,10 @@ export default class Viewport {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setZoomLevel(zoom: number): void {
|
||||||
|
this.view.halfSize.scale(1/zoom);
|
||||||
|
}
|
||||||
|
|
||||||
getZoomLevel(): number {
|
getZoomLevel(): number {
|
||||||
return this.canvasSize.x/this.view.hw/2
|
return this.canvasSize.x/this.view.hw/2
|
||||||
}
|
}
|
||||||
|
|
53
src/Utils/EaseFunctions.ts
Normal file
53
src/Utils/EaseFunctions.ts
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
export default class EaseFunctions {
|
||||||
|
|
||||||
|
static easeInOutSine(x: number): number {
|
||||||
|
return -(Math.cos(Math.PI * x) - 1) / 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
static easeOutInSine(x: number): number {
|
||||||
|
return x < 0.5 ? -Math.cos(Math.PI*(x + 0.5))/2 : -Math.cos(Math.PI*(x - 0.5))/2 + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static easeOutSine(x: number): number {
|
||||||
|
return Math.sin((x * Math.PI) / 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
static easeInSine(x: number): number {
|
||||||
|
return 1 - Math.cos((x * Math.PI) / 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
static easeInOutQuint(x: number): number {
|
||||||
|
return x < 0.5 ? 16 * x * x * x * x * x : 1 - Math.pow(-2 * x + 2, 5) / 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
static easeInOutQuad(x: number): number {
|
||||||
|
return x < 0.5 ? 2 * x * x : 1 - Math.pow(-2 * x + 2, 2) / 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
static easeOutInQuad(x: number): number {
|
||||||
|
return x < 0.5 ? this.easeOutIn_OutPow(x, 2) : this.easeOutIn_InPow(x, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static easeOutIn_OutPow(x: number, pow: number): number {
|
||||||
|
return 0.5 - Math.pow(-2 * x + 1, pow) / 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static easeOutIn_InPow(x: number, pow: number): number {
|
||||||
|
return 0.5 + Math.pow(2 * x - 1, pow) / 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum EaseFunctionType {
|
||||||
|
// SINE
|
||||||
|
IN_OUT_SINE = "easeInOutSine",
|
||||||
|
OUT_IN_SINE = "easeOutInSine",
|
||||||
|
IN_SINE = "easeInSine",
|
||||||
|
OUT_SINE = "easeOutSine",
|
||||||
|
|
||||||
|
// QUAD
|
||||||
|
IN_OUT_QUAD = "easeInOutQuad",
|
||||||
|
OUT_IN_QUAD = "easeOutInQuad",
|
||||||
|
|
||||||
|
// QUINT
|
||||||
|
IN_OUT_QUINT = "easeInOutQuint"
|
||||||
|
}
|
|
@ -8,6 +8,9 @@ import Scene from "../../Scene/Scene";
|
||||||
import PlayerController from "../Player/PlayerController";
|
import PlayerController from "../Player/PlayerController";
|
||||||
import GoombaController from "../Enemies/GoombaController";
|
import GoombaController from "../Enemies/GoombaController";
|
||||||
import OrthogonalTilemap from "../../Nodes/Tilemaps/OrthogonalTilemap";
|
import OrthogonalTilemap from "../../Nodes/Tilemaps/OrthogonalTilemap";
|
||||||
|
import AnimatedSprite from "../../Nodes/Sprites/AnimatedSprite";
|
||||||
|
import Debug from "../../Debug/Debug";
|
||||||
|
import { EaseFunctionType } from "../../Utils/EaseFunctions";
|
||||||
|
|
||||||
export enum MarioEvents {
|
export enum MarioEvents {
|
||||||
PLAYER_HIT_COIN = "PlayerHitCoin",
|
PLAYER_HIT_COIN = "PlayerHitCoin",
|
||||||
|
@ -15,32 +18,30 @@ export enum MarioEvents {
|
||||||
}
|
}
|
||||||
|
|
||||||
export default class Level1 extends Scene {
|
export default class Level1 extends Scene {
|
||||||
player: GameNode;
|
player: AnimatedSprite;
|
||||||
coinCount: number = 0;
|
coinCount: number = 0;
|
||||||
coinCountLabel: Label;
|
coinCountLabel: Label;
|
||||||
livesCount: number = 3;
|
livesCount: number = 3;
|
||||||
livesCountLabel: Label;
|
livesCountLabel: Label;
|
||||||
|
|
||||||
loadScene(): void {
|
loadScene(): void {
|
||||||
this.load.tilemap("level1", "/assets/tilemaps/level1.json");
|
this.load.tilemap("level1", "/assets/tilemaps/2bitlevel1.json");
|
||||||
this.load.image("goomba", "assets/sprites/Goomba.png");
|
this.load.image("goomba", "assets/sprites/Goomba.png");
|
||||||
this.load.image("koopa", "assets/sprites/Koopa.png");
|
this.load.image("koopa", "assets/sprites/Koopa.png");
|
||||||
|
this.load.spritesheet("player", "assets/spritesheets/walking.json");
|
||||||
}
|
}
|
||||||
|
|
||||||
startScene(): void {
|
startScene(): void {
|
||||||
let tilemap = this.add.tilemap("level1", new Vec2(2, 2))[0].getItems()[0];
|
let tilemap = <OrthogonalTilemap>this.add.tilemap("level1", new Vec2(2, 2))[0].getItems()[0];
|
||||||
console.log(tilemap);
|
//tilemap.position.set(tilemap.size.x*tilemap.scale.x/2, tilemap.size.y*tilemap.scale.y/2);
|
||||||
console.log((tilemap as OrthogonalTilemap).getTileAtRowCol(new Vec2(8, 17)));
|
tilemap.position.set(0, 0);
|
||||||
(tilemap as OrthogonalTilemap).setTileAtRowCol(new Vec2(8, 17), 1);
|
this.viewport.setBounds(0, 0, 128*32, 20*32);
|
||||||
console.log((tilemap as OrthogonalTilemap).getTileAtRowCol(new Vec2(8, 17)));
|
|
||||||
this.viewport.setBounds(0, 0, 150*64, 20*64);
|
|
||||||
|
|
||||||
// Give parallax to the parallax layers
|
|
||||||
(this.getLayer("Clouds") as ParallaxLayer).parallax.set(0.5, 1);
|
|
||||||
(this.getLayer("Hills") as ParallaxLayer).parallax.set(0.8, 1);
|
|
||||||
|
|
||||||
// Add the player (a rect for now)
|
// Add the player (a rect for now)
|
||||||
this.player = this.add.graphic(GraphicType.RECT, "Main", {position: new Vec2(192, 1152), size: new Vec2(64, 64)});
|
// this.player = this.add.graphic(GraphicType.RECT, "Main", {position: new Vec2(192, 1152), size: new Vec2(64, 64)});
|
||||||
|
this.player = this.add.animatedSprite("player", "Main");
|
||||||
|
this.player.scale.set(2, 2);
|
||||||
|
this.player.position.set(5*32, 18*32);
|
||||||
this.player.addPhysics();
|
this.player.addPhysics();
|
||||||
this.player.addAI(PlayerController, {playerType: "platformer", tilemap: "Main"});
|
this.player.addAI(PlayerController, {playerType: "platformer", tilemap: "Main"});
|
||||||
|
|
||||||
|
@ -49,28 +50,43 @@ export default class Level1 extends Scene {
|
||||||
this.player.addTrigger("coinBlock", MarioEvents.PLAYER_HIT_COIN_BLOCK);
|
this.player.addTrigger("coinBlock", MarioEvents.PLAYER_HIT_COIN_BLOCK);
|
||||||
this.player.setPhysicsLayer("player");
|
this.player.setPhysicsLayer("player");
|
||||||
|
|
||||||
|
this.player.tweens.add("flip", {
|
||||||
|
startDelay: 0,
|
||||||
|
duration: 500,
|
||||||
|
effects: [
|
||||||
|
{
|
||||||
|
property: "rotation",
|
||||||
|
start: 0,
|
||||||
|
end: 2*Math.PI,
|
||||||
|
ease: EaseFunctionType.IN_OUT_QUAD
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
this.receiver.subscribe([MarioEvents.PLAYER_HIT_COIN, MarioEvents.PLAYER_HIT_COIN_BLOCK]);
|
this.receiver.subscribe([MarioEvents.PLAYER_HIT_COIN, MarioEvents.PLAYER_HIT_COIN_BLOCK]);
|
||||||
|
|
||||||
this.viewport.follow(this.player);
|
this.viewport.follow(this.player);
|
||||||
|
this.viewport.enableZoom();
|
||||||
|
this.viewport.setZoomLevel(2);
|
||||||
|
|
||||||
// Add enemies
|
// Add enemies
|
||||||
for(let pos of [{x: 21, y: 18}, {x: 30, y: 18}, {x: 37, y: 18}, {x: 41, y: 18}, {x: 105, y: 8}, {x: 107, y: 8}, {x: 125, y: 18}]){
|
// for(let pos of [{x: 21, y: 18}, {x: 30, y: 18}, {x: 37, y: 18}, {x: 41, y: 18}, {x: 105, y: 8}, {x: 107, y: 8}, {x: 125, y: 18}]){
|
||||||
let goomba = this.add.sprite("goomba", "Main");
|
// let goomba = this.add.sprite("goomba", "Main");
|
||||||
goomba.position.set(pos.x*64, pos.y*64);
|
// goomba.position.set(pos.x*64, pos.y*64);
|
||||||
goomba.scale.set(2, 2);
|
// goomba.scale.set(2, 2);
|
||||||
goomba.addPhysics();
|
// goomba.addPhysics();
|
||||||
goomba.addAI(GoombaController, {jumpy: false});
|
// goomba.addAI(GoombaController, {jumpy: false});
|
||||||
goomba.setPhysicsLayer("enemy");
|
// goomba.setPhysicsLayer("enemy");
|
||||||
}
|
// }
|
||||||
|
|
||||||
for(let pos of [{x: 67, y: 18}, {x: 86, y: 21}, {x: 128, y: 18}]){
|
// for(let pos of [{x: 67, y: 18}, {x: 86, y: 21}, {x: 128, y: 18}]){
|
||||||
let koopa = this.add.sprite("koopa", "Main");
|
// let koopa = this.add.sprite("koopa", "Main");
|
||||||
koopa.position.set(pos.x*64, pos.y*64);
|
// koopa.position.set(pos.x*64, pos.y*64);
|
||||||
koopa.scale.set(2, 2);
|
// koopa.scale.set(2, 2);
|
||||||
koopa.addPhysics();
|
// koopa.addPhysics();
|
||||||
koopa.addAI(GoombaController, {jumpy: true});
|
// koopa.addAI(GoombaController, {jumpy: true});
|
||||||
koopa.setPhysicsLayer("enemy");
|
// koopa.setPhysicsLayer("enemy");
|
||||||
}
|
// }
|
||||||
|
|
||||||
// Add UI
|
// Add UI
|
||||||
this.addUILayer("UI");
|
this.addUILayer("UI");
|
||||||
|
@ -106,9 +122,10 @@ export default class Level1 extends Scene {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Debug.log("playerpos", this.player.position.toString());
|
||||||
// If player falls into a pit, kill them off and reset their position
|
// If player falls into a pit, kill them off and reset their position
|
||||||
if(this.player.position.y > 21*64){
|
if(this.player.position.y > 100*64){
|
||||||
this.player.position.set(192, 1152);
|
this.player.position.set(5*32, 18*32);
|
||||||
this.livesCount -= 1
|
this.livesCount -= 1
|
||||||
this.livesCountLabel.setText("Lives: " + this.livesCount);
|
this.livesCountLabel.setText("Lives: " + this.livesCount);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,16 +1,18 @@
|
||||||
import Vec2 from "../../DataTypes/Vec2";
|
import Vec2 from "../../DataTypes/Vec2";
|
||||||
import Debug from "../../Debug/Debug";
|
import Debug from "../../Debug/Debug";
|
||||||
import InputReceiver from "../../Input/InputReceiver";
|
import InputReceiver from "../../Input/InputReceiver";
|
||||||
|
import AnimatedSprite from "../../Nodes/Sprites/AnimatedSprite";
|
||||||
import Button from "../../Nodes/UIElements/Button";
|
import Button from "../../Nodes/UIElements/Button";
|
||||||
import Label from "../../Nodes/UIElements/Label";
|
|
||||||
import Slider from "../../Nodes/UIElements/Slider";
|
|
||||||
import { UIElementType } from "../../Nodes/UIElements/UIElementTypes";
|
import { UIElementType } from "../../Nodes/UIElements/UIElementTypes";
|
||||||
import Scene from "../../Scene/Scene";
|
import Scene from "../../Scene/Scene";
|
||||||
import Color from "../../Utils/Color";
|
import Color from "../../Utils/Color";
|
||||||
|
import { EaseFunctionType } from "../../Utils/EaseFunctions";
|
||||||
import Level1 from "./Level1";
|
import Level1 from "./Level1";
|
||||||
|
|
||||||
export default class MainMenu extends Scene {
|
export default class MainMenu extends Scene {
|
||||||
|
|
||||||
|
animatedSprite: AnimatedSprite;
|
||||||
|
|
||||||
loadScene(): void {
|
loadScene(): void {
|
||||||
this.load.spritesheet("walker", "assets/spritesheets/walking.json");
|
this.load.spritesheet("walker", "assets/spritesheets/walking.json");
|
||||||
}
|
}
|
||||||
|
@ -47,6 +49,44 @@ export default class MainMenu extends Scene {
|
||||||
animatedSprite.scale.set(4, 4);
|
animatedSprite.scale.set(4, 4);
|
||||||
animatedSprite.animation.play("JUMP");
|
animatedSprite.animation.play("JUMP");
|
||||||
animatedSprite.animation.queue("WALK", true);
|
animatedSprite.animation.queue("WALK", true);
|
||||||
|
|
||||||
|
animatedSprite.tweens.add("wiggle", {
|
||||||
|
startDelay: 0,
|
||||||
|
duration: 300,
|
||||||
|
effects: [{
|
||||||
|
property: "rotation",
|
||||||
|
start: -0.1,
|
||||||
|
end: 0.1,
|
||||||
|
ease: EaseFunctionType.IN_OUT_SINE
|
||||||
|
}],
|
||||||
|
reverseOnComplete: true,
|
||||||
|
loop: true
|
||||||
|
});
|
||||||
|
|
||||||
|
animatedSprite.tweens.play("wiggle");
|
||||||
|
|
||||||
|
animatedSprite.tweens.add("scale", {
|
||||||
|
startDelay: 0,
|
||||||
|
duration: 1000,
|
||||||
|
effects: [{
|
||||||
|
property: "scaleX",
|
||||||
|
start: 4,
|
||||||
|
end: 6,
|
||||||
|
ease: EaseFunctionType.IN_OUT_SINE
|
||||||
|
},
|
||||||
|
{
|
||||||
|
property: "scaleY",
|
||||||
|
start: 4,
|
||||||
|
end: 6,
|
||||||
|
ease: EaseFunctionType.IN_OUT_SINE
|
||||||
|
}],
|
||||||
|
reverseOnComplete: true,
|
||||||
|
loop: true
|
||||||
|
});
|
||||||
|
|
||||||
|
animatedSprite.tweens.play("scale");
|
||||||
|
|
||||||
|
this.animatedSprite = animatedSprite;
|
||||||
}
|
}
|
||||||
|
|
||||||
updateScene(): void {
|
updateScene(): void {
|
||||||
|
|
|
@ -27,9 +27,9 @@ export enum PlayerStates {
|
||||||
export default class PlayerController extends StateMachineAI {
|
export default class PlayerController extends StateMachineAI {
|
||||||
protected owner: GameNode;
|
protected owner: GameNode;
|
||||||
velocity: Vec2 = Vec2.ZERO;
|
velocity: Vec2 = Vec2.ZERO;
|
||||||
speed: number = 400;
|
speed: number = 200;
|
||||||
MIN_SPEED: number = 400;
|
MIN_SPEED: number = 200;
|
||||||
MAX_SPEED: number = 1000;
|
MAX_SPEED: number = 500;
|
||||||
tilemap: OrthogonalTilemap;
|
tilemap: OrthogonalTilemap;
|
||||||
|
|
||||||
initializeAI(owner: GameNode, options: Record<string, any>){
|
initializeAI(owner: GameNode, options: Record<string, any>){
|
||||||
|
|
|
@ -1,10 +1,14 @@
|
||||||
|
import AnimatedSprite from "../../../../Nodes/Sprites/AnimatedSprite";
|
||||||
import OnGround from "./OnGround";
|
import OnGround from "./OnGround";
|
||||||
import { PlayerStates } from "./PlayerController";
|
import { PlayerStates } from "./PlayerController";
|
||||||
import PlayerState from "./PlayerState";
|
import PlayerState from "./PlayerState";
|
||||||
|
|
||||||
export default class Idle extends OnGround {
|
export default class Idle extends OnGround {
|
||||||
|
owner: AnimatedSprite;
|
||||||
|
|
||||||
onEnter(): void {
|
onEnter(): void {
|
||||||
this.parent.speed = this.parent.MIN_SPEED;
|
this.parent.speed = this.parent.MIN_SPEED;
|
||||||
|
this.owner.animation.play("IDLE", true);
|
||||||
}
|
}
|
||||||
|
|
||||||
update(deltaT: number): void {
|
update(deltaT: number): void {
|
||||||
|
@ -24,4 +28,8 @@ export default class Idle extends OnGround {
|
||||||
|
|
||||||
this.owner.move(this.parent.velocity.scaled(deltaT));
|
this.owner.move(this.parent.velocity.scaled(deltaT));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onExit(): void {
|
||||||
|
this.owner.animation.stop();
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -1,5 +1,6 @@
|
||||||
import Vec2 from "../../../../DataTypes/Vec2";
|
import Vec2 from "../../../../DataTypes/Vec2";
|
||||||
import GameEvent from "../../../../Events/GameEvent";
|
import GameEvent from "../../../../Events/GameEvent";
|
||||||
|
import AnimatedSprite from "../../../../Nodes/Sprites/AnimatedSprite";
|
||||||
import MathUtils from "../../../../Utils/MathUtils";
|
import MathUtils from "../../../../Utils/MathUtils";
|
||||||
import { CustomGameEventType } from "../../../CustomGameEventType";
|
import { CustomGameEventType } from "../../../CustomGameEventType";
|
||||||
import Level1, { MarioEvents } from "../../../Mario/Level1";
|
import Level1, { MarioEvents } from "../../../Mario/Level1";
|
||||||
|
@ -7,8 +8,11 @@ import { PlayerStates } from "./PlayerController";
|
||||||
import PlayerState from "./PlayerState";
|
import PlayerState from "./PlayerState";
|
||||||
|
|
||||||
export default class Jump extends PlayerState {
|
export default class Jump extends PlayerState {
|
||||||
|
owner: AnimatedSprite;
|
||||||
|
|
||||||
onEnter(): void {}
|
onEnter(): void {
|
||||||
|
this.owner.animation.play("JUMP", true);
|
||||||
|
}
|
||||||
|
|
||||||
handleInput(event: GameEvent): void {}
|
handleInput(event: GameEvent): void {}
|
||||||
|
|
||||||
|
@ -27,8 +31,8 @@ export default class Jump extends PlayerState {
|
||||||
console.log("Hit tile: " + tile);
|
console.log("Hit tile: " + tile);
|
||||||
|
|
||||||
// If coin block, change to empty coin block
|
// If coin block, change to empty coin block
|
||||||
if(tile === 4){
|
if(tile === 17){
|
||||||
this.parent.tilemap.setTileAtRowCol(pos, 12);
|
this.parent.tilemap.setTileAtRowCol(pos, 18);
|
||||||
this.emitter.fireEvent(MarioEvents.PLAYER_HIT_COIN_BLOCK);
|
this.emitter.fireEvent(MarioEvents.PLAYER_HIT_COIN_BLOCK);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -49,5 +53,7 @@ export default class Jump extends PlayerState {
|
||||||
this.owner.move(this.parent.velocity.scaled(deltaT));
|
this.owner.move(this.parent.velocity.scaled(deltaT));
|
||||||
}
|
}
|
||||||
|
|
||||||
onExit(): void {}
|
onExit(): void {
|
||||||
|
this.owner.animation.stop();
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -1,4 +1,6 @@
|
||||||
import GameEvent from "../../../../Events/GameEvent";
|
import GameEvent from "../../../../Events/GameEvent";
|
||||||
|
import Sprite from "../../../../Nodes/Sprites/Sprite";
|
||||||
|
import MathUtils from "../../../../Utils/MathUtils";
|
||||||
import { CustomGameEventType } from "../../../CustomGameEventType";
|
import { CustomGameEventType } from "../../../CustomGameEventType";
|
||||||
import PlayerState from "./PlayerState";
|
import PlayerState from "./PlayerState";
|
||||||
|
|
||||||
|
@ -13,9 +15,18 @@ export default class OnGround extends PlayerState {
|
||||||
}
|
}
|
||||||
super.update(deltaT);
|
super.update(deltaT);
|
||||||
|
|
||||||
|
let direction = this.getInputDirection();
|
||||||
|
|
||||||
|
if(direction.x !== 0){
|
||||||
|
(<Sprite>this.owner).invertX = MathUtils.sign(direction.x) < 0;
|
||||||
|
}
|
||||||
|
|
||||||
if(this.input.isJustPressed("w") || this.input.isJustPressed("space")){
|
if(this.input.isJustPressed("w") || this.input.isJustPressed("space")){
|
||||||
this.finished("jump");
|
this.finished("jump");
|
||||||
this.parent.velocity.y = -2000;
|
this.parent.velocity.y = -500;
|
||||||
|
if(this.parent.velocity.x !== 0){
|
||||||
|
this.owner.tweens.play("flip");
|
||||||
|
}
|
||||||
this.emitter.fireEvent(CustomGameEventType.PLAYER_JUMP)
|
this.emitter.fireEvent(CustomGameEventType.PLAYER_JUMP)
|
||||||
} else if(!this.owner.onGround){
|
} else if(!this.owner.onGround){
|
||||||
this.finished("jump");
|
this.finished("jump");
|
||||||
|
|
|
@ -1,15 +1,19 @@
|
||||||
import State from "../../../../DataTypes/State/State";
|
import State from "../../../../DataTypes/State/State";
|
||||||
import StateMachine from "../../../../DataTypes/State/StateMachine";
|
import StateMachine from "../../../../DataTypes/State/StateMachine";
|
||||||
import Vec2 from "../../../../DataTypes/Vec2";
|
import Vec2 from "../../../../DataTypes/Vec2";
|
||||||
|
import Debug from "../../../../Debug/Debug";
|
||||||
import InputReceiver from "../../../../Input/InputReceiver";
|
import InputReceiver from "../../../../Input/InputReceiver";
|
||||||
|
import CanvasNode from "../../../../Nodes/CanvasNode";
|
||||||
import GameNode from "../../../../Nodes/GameNode";
|
import GameNode from "../../../../Nodes/GameNode";
|
||||||
|
import Sprite from "../../../../Nodes/Sprites/Sprite";
|
||||||
|
import MathUtils from "../../../../Utils/MathUtils";
|
||||||
import PlayerController from "../../PlayerController";
|
import PlayerController from "../../PlayerController";
|
||||||
|
|
||||||
|
|
||||||
export default abstract class PlayerState extends State {
|
export default abstract class PlayerState extends State {
|
||||||
input: InputReceiver = InputReceiver.getInstance();
|
input: InputReceiver = InputReceiver.getInstance();
|
||||||
owner: GameNode;
|
owner: GameNode;
|
||||||
gravity: number = 7000;
|
gravity: number = 1000;
|
||||||
parent: PlayerController;
|
parent: PlayerController;
|
||||||
|
|
||||||
constructor(parent: StateMachine, owner: GameNode){
|
constructor(parent: StateMachine, owner: GameNode){
|
||||||
|
|
|
@ -1,10 +1,15 @@
|
||||||
|
import AnimatedSprite from "../../../../Nodes/Sprites/AnimatedSprite";
|
||||||
|
import MathUtils from "../../../../Utils/MathUtils";
|
||||||
import { CustomGameEventType } from "../../../CustomGameEventType";
|
import { CustomGameEventType } from "../../../CustomGameEventType";
|
||||||
import OnGround from "./OnGround";
|
import OnGround from "./OnGround";
|
||||||
import { PlayerStates } from "./PlayerController";
|
import { PlayerStates } from "./PlayerController";
|
||||||
|
|
||||||
export default class Run extends OnGround {
|
export default class Run extends OnGround {
|
||||||
|
owner: AnimatedSprite;
|
||||||
|
|
||||||
onEnter(): void {
|
onEnter(): void {
|
||||||
this.parent.speed = this.parent.MAX_SPEED;
|
this.parent.speed = this.parent.MAX_SPEED;
|
||||||
|
this.owner.animation.play("WALK", true);
|
||||||
}
|
}
|
||||||
|
|
||||||
update(deltaT: number): void {
|
update(deltaT: number): void {
|
||||||
|
@ -25,4 +30,8 @@ export default class Run extends OnGround {
|
||||||
this.emitter.fireEvent(CustomGameEventType.PLAYER_MOVE, {position: this.owner.position.clone()});
|
this.emitter.fireEvent(CustomGameEventType.PLAYER_MOVE, {position: this.owner.position.clone()});
|
||||||
this.owner.move(this.parent.velocity.scaled(deltaT));
|
this.owner.move(this.parent.velocity.scaled(deltaT));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onExit(): void {
|
||||||
|
this.owner.animation.stop();
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -1,10 +1,14 @@
|
||||||
|
import AnimatedSprite from "../../../../Nodes/Sprites/AnimatedSprite";
|
||||||
import { CustomGameEventType } from "../../../CustomGameEventType";
|
import { CustomGameEventType } from "../../../CustomGameEventType";
|
||||||
import OnGround from "./OnGround";
|
import OnGround from "./OnGround";
|
||||||
import { PlayerStates } from "./PlayerController";
|
import { PlayerStates } from "./PlayerController";
|
||||||
|
|
||||||
export default class Walk extends OnGround {
|
export default class Walk extends OnGround {
|
||||||
|
owner: AnimatedSprite;
|
||||||
|
|
||||||
onEnter(): void {
|
onEnter(): void {
|
||||||
this.parent.speed = this.parent.MAX_SPEED/2;
|
this.parent.speed = this.parent.MAX_SPEED/2;
|
||||||
|
this.owner.animation.play("WALK", true);
|
||||||
}
|
}
|
||||||
|
|
||||||
update(deltaT: number): void {
|
update(deltaT: number): void {
|
||||||
|
@ -25,4 +29,8 @@ export default class Walk extends OnGround {
|
||||||
this.emitter.fireEvent(CustomGameEventType.PLAYER_MOVE, {position: this.owner.position.clone()});
|
this.emitter.fireEvent(CustomGameEventType.PLAYER_MOVE, {position: this.owner.position.clone()});
|
||||||
this.owner.move(this.parent.velocity.scaled(deltaT));
|
this.owner.move(this.parent.velocity.scaled(deltaT));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onExit(): void {
|
||||||
|
this.owner.animation.stop();
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -7,6 +7,7 @@ function main(){
|
||||||
// Create the game object
|
// Create the game object
|
||||||
let options = {
|
let options = {
|
||||||
viewportSize: {x: 800, y: 600},
|
viewportSize: {x: 800, y: 600},
|
||||||
|
clearColor: {r: 34, g: 32, b: 52}
|
||||||
}
|
}
|
||||||
|
|
||||||
let game = new GameLoop(options);
|
let game = new GameLoop(options);
|
||||||
|
|
|
@ -59,6 +59,6 @@
|
||||||
],
|
],
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"noImplicitAny": true,
|
"noImplicitAny": true,
|
||||||
"target": "es5"
|
"target": "es2016"
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user