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 RenderingManager from "../Rendering/RenderingManager";
|
||||
import CanvasRenderer from "../Rendering/CanvasRenderer";
|
||||
import Color from "../Utils/Color";
|
||||
|
||||
export default class GameLoop {
|
||||
gameOptions: GameOptions;
|
||||
|
@ -63,6 +64,7 @@ export default class GameLoop {
|
|||
readonly HEIGHT: number;
|
||||
private viewport: Viewport;
|
||||
private ctx: CanvasRenderingContext2D;
|
||||
private clearColor: Color;
|
||||
|
||||
// All of the necessary subsystems that need to run here
|
||||
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
|
||||
this.renderingManager = new CanvasRenderer();
|
||||
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
|
||||
this.viewport = new Viewport();
|
||||
|
@ -272,6 +275,8 @@ export default class GameLoop {
|
|||
*/
|
||||
render(): void {
|
||||
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();
|
||||
Debug.render(this.ctx);
|
||||
Stats.render();
|
||||
|
@ -279,12 +284,14 @@ export default class GameLoop {
|
|||
}
|
||||
|
||||
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 {
|
||||
let gOpt = new GameOptions();
|
||||
|
||||
gOpt.viewportSize = options.viewportSize ? options.viewportSize : {x: 800, y: 600};
|
||||
gOpt.clearColor = options.clearColor ? options.clearColor : {r: 255, g: 255, b: 255};
|
||||
|
||||
return gOpt;
|
||||
}
|
||||
|
|
|
@ -45,6 +45,14 @@ export default abstract class CanvasNode extends GameNode implements Region {
|
|||
this.scaleChanged();
|
||||
}
|
||||
|
||||
set scaleX(value: number) {
|
||||
this.scale.x = value;
|
||||
}
|
||||
|
||||
set scaleY(value: number) {
|
||||
this.scale.y = value;
|
||||
}
|
||||
|
||||
protected positionChanged(): void {
|
||||
super.positionChanged();
|
||||
this.updateBoundary();
|
||||
|
|
|
@ -9,11 +9,12 @@ import Shape from "../DataTypes/Shapes/Shape";
|
|||
import Map from "../DataTypes/Map";
|
||||
import AABB from "../DataTypes/Shapes/AABB";
|
||||
import NavigationPath from "../Pathfinding/NavigationPath";
|
||||
import TweenManager from "../Rendering/Animations/TweenManager";
|
||||
|
||||
/**
|
||||
* 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 ----------*/
|
||||
private _position: Vec2;
|
||||
|
||||
|
@ -46,12 +47,14 @@ export default abstract class GameNode implements Positioned, Unique, Updateable
|
|||
path: NavigationPath;
|
||||
pathfinding: boolean = false;
|
||||
|
||||
/*---------- GENERAL ----------*/
|
||||
protected input: InputReceiver;
|
||||
protected receiver: Receiver;
|
||||
protected emitter: Emitter;
|
||||
protected scene: Scene;
|
||||
protected layer: Layer;
|
||||
|
||||
tweens: TweenManager;
|
||||
rotation: number;
|
||||
|
||||
constructor(){
|
||||
this.input = InputReceiver.getInstance();
|
||||
|
@ -59,6 +62,8 @@ export default abstract class GameNode implements Positioned, Unique, Updateable
|
|||
this._position.setOnChange(() => this.positionChanged());
|
||||
this.receiver = new Receiver();
|
||||
this.emitter = new Emitter();
|
||||
this.tweens = new TweenManager(this);
|
||||
this.rotation = 0;
|
||||
}
|
||||
|
||||
/*---------- POSITIONED ----------*/
|
||||
|
@ -190,6 +195,19 @@ export default abstract class GameNode implements Positioned, Unique, Updateable
|
|||
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 ----------*/
|
||||
/**
|
||||
* Sets the scene for this object.
|
||||
|
@ -226,7 +244,15 @@ export default abstract class GameNode implements Positioned, Unique, Updateable
|
|||
}
|
||||
};
|
||||
|
||||
abstract update(deltaT: number): void;
|
||||
|
||||
debug_render = (ctx: CanvasRenderingContext2D): void => {};
|
||||
update(deltaT: number): void {
|
||||
this.tweens.update(deltaT);
|
||||
}
|
||||
}
|
||||
|
||||
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.size.set(5, 5);
|
||||
}
|
||||
|
||||
update(deltaT: number): void {}
|
||||
}
|
|
@ -38,6 +38,4 @@ export default class Rect extends Graphic {
|
|||
getBorderWidth(): number {
|
||||
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
|
||||
this.size.set(spritesheet.spriteWidth, spritesheet.spriteHeight);
|
||||
|
||||
this.animation = new AnimationManager();
|
||||
this.animation = new AnimationManager(this);
|
||||
|
||||
// Add the animations to the animated sprite
|
||||
for(let animation of spritesheet.animations){
|
||||
|
|
|
@ -8,6 +8,8 @@ import Vec2 from "../../DataTypes/Vec2";
|
|||
export default class Sprite extends CanvasNode {
|
||||
imageId: string;
|
||||
imageOffset: Vec2;
|
||||
invertX: boolean;
|
||||
invertY: boolean;
|
||||
|
||||
constructor(imageId: string){
|
||||
super();
|
||||
|
@ -15,6 +17,8 @@ export default class Sprite extends CanvasNode {
|
|||
let image = ResourceManager.getInstance().getImage(this.imageId);
|
||||
this.size = new Vec2(image.width, image.height);
|
||||
this.imageOffset = Vec2.ZERO;
|
||||
this.invertX = false;
|
||||
this.invertY = false;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -24,6 +28,4 @@ export default class Sprite extends CanvasNode {
|
|||
setImageOffset(offset: Vec2): void {
|
||||
this.imageOffset = offset;
|
||||
}
|
||||
|
||||
update(deltaT: number): void {}
|
||||
}
|
|
@ -59,6 +59,8 @@ export default abstract class UIElement extends CanvasNode {
|
|||
}
|
||||
|
||||
update(deltaT: number): void {
|
||||
super.update(deltaT);
|
||||
|
||||
// See of this object was just clicked
|
||||
if(this.input.isMouseJustPressed()){
|
||||
let clickPos = this.input.getMousePressPosition();
|
||||
|
|
|
@ -9,6 +9,7 @@ import Shape from "../DataTypes/Shapes/Shape";
|
|||
import MathUtils from "../Utils/MathUtils";
|
||||
import OrthogonalTilemap from "../Nodes/Tilemaps/OrthogonalTilemap";
|
||||
import AABB from "../DataTypes/Shapes/AABB";
|
||||
import Debug from "../Debug/Debug";
|
||||
|
||||
export default class BasicPhysicsManager extends PhysicsManager {
|
||||
|
||||
|
|
|
@ -40,7 +40,8 @@ export default class AnimationManager {
|
|||
/** The onEnd event of a pending animation */
|
||||
protected pendingOnEnd: string;
|
||||
|
||||
constructor(){
|
||||
constructor(owner: CanvasNode){
|
||||
this.owner = owner;
|
||||
this.animationState = AnimationState.STOPPED;
|
||||
this.currentAnimation = "";
|
||||
this.currentFrame = 0;
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
import { TweenableProperties } from "../../Nodes/GameNode";
|
||||
import { EaseFunctionType } from "../../Utils/EaseFunctions";
|
||||
|
||||
export enum AnimationState {
|
||||
STOPPED = 0,
|
||||
PAUSED = 1,
|
||||
|
@ -10,5 +13,33 @@ export class AnimationData {
|
|||
}
|
||||
|
||||
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 TextInput from "../Nodes/UIElements/TextInput";
|
||||
import AnimatedSprite from "../Nodes/Sprites/AnimatedSprite";
|
||||
import Vec2 from "../DataTypes/Vec2";
|
||||
|
||||
export default class CanvasRenderer extends RenderingManager {
|
||||
protected ctx: CanvasRenderingContext2D;
|
||||
|
@ -25,8 +26,11 @@ export default class CanvasRenderer extends RenderingManager {
|
|||
protected tilemapRenderer: TilemapRenderer;
|
||||
protected uiElementRenderer: UIElementRenderer;
|
||||
|
||||
protected origin: Vec2;
|
||||
protected zoom: number;
|
||||
|
||||
constructor(){
|
||||
super();;
|
||||
super();
|
||||
}
|
||||
|
||||
setScene(scene: Scene){
|
||||
|
@ -79,6 +83,24 @@ export default class CanvasRenderer extends RenderingManager {
|
|||
}
|
||||
|
||||
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){
|
||||
this.renderAnimatedSprite(<AnimatedSprite>node);
|
||||
} else if(node instanceof Sprite){
|
||||
|
@ -88,18 +110,14 @@ export default class CanvasRenderer extends RenderingManager {
|
|||
} else if(node instanceof UIElement){
|
||||
this.renderUIElement(<UIElement>node);
|
||||
}
|
||||
|
||||
this.ctx.setTransform(1, 0, 0, 1, 0, 0);
|
||||
}
|
||||
|
||||
protected renderSprite(sprite: Sprite): void {
|
||||
// Get the image from the resource manager
|
||||
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:
|
||||
image crop start -> x, y
|
||||
|
@ -111,15 +129,15 @@ export default class CanvasRenderer extends RenderingManager {
|
|||
this.ctx.drawImage(image,
|
||||
sprite.imageOffset.x, sprite.imageOffset.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*zoom, sprite.size.y * sprite.scale.y*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*this.zoom, sprite.size.y * sprite.scale.y*this.zoom);
|
||||
|
||||
// Debug mode
|
||||
if(this.debug){
|
||||
this.ctx.lineWidth = 4;
|
||||
this.ctx.strokeStyle = "#00FF00"
|
||||
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
|
||||
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 animationOffset = sprite.getAnimationOffset(animationIndex);
|
||||
|
@ -141,30 +153,30 @@ export default class CanvasRenderer extends RenderingManager {
|
|||
Coordinates in the space of the image:
|
||||
image crop start -> x, y
|
||||
image crop size -> w, h
|
||||
Coordinates in the space of the world
|
||||
image draw start -> x, y
|
||||
Coordinates in the space of the world (given we moved)
|
||||
image draw start -> -w/2, -h/2
|
||||
image draw size -> w, h
|
||||
*/
|
||||
this.ctx.drawImage(image,
|
||||
sprite.imageOffset.x + animationOffset.x, sprite.imageOffset.y + animationOffset.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*zoom, sprite.size.y * sprite.scale.y*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*this.zoom, sprite.size.y * sprite.scale.y*this.zoom);
|
||||
|
||||
// Debug mode
|
||||
if(this.debug){
|
||||
this.ctx.lineWidth = 4;
|
||||
this.ctx.strokeStyle = "#00FF00"
|
||||
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 {
|
||||
if(graphic instanceof Point){
|
||||
this.graphicRenderer.renderPoint(<Point>graphic);
|
||||
this.graphicRenderer.renderPoint(<Point>graphic, this.origin, this.zoom);
|
||||
} 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 {
|
||||
if(uiElement instanceof Label){
|
||||
this.uiElementRenderer.renderLabel(uiElement);
|
||||
this.uiElementRenderer.renderLabel(uiElement, this.origin, this.zoom);
|
||||
} else if(uiElement instanceof Button){
|
||||
this.uiElementRenderer.renderButton(uiElement);
|
||||
this.uiElementRenderer.renderButton(uiElement, this.origin, this.zoom);
|
||||
} else if(uiElement instanceof Slider){
|
||||
this.uiElementRenderer.renderSlider(uiElement);
|
||||
this.uiElementRenderer.renderSlider(uiElement, this.origin, this.zoom);
|
||||
} 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 Rect from "../../Nodes/Graphics/Rect";
|
||||
import ResourceManager from "../../ResourceManager/ResourceManager";
|
||||
|
@ -17,28 +18,22 @@ export default class GraphicRenderer {
|
|||
this.scene = scene;
|
||||
}
|
||||
|
||||
renderPoint(point: Point): void {
|
||||
let origin = this.scene.getViewTranslation(point);
|
||||
let zoom = this.scene.getViewScale();
|
||||
|
||||
renderPoint(point: Point, origin: Vec2, zoom: number): void {
|
||||
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);
|
||||
}
|
||||
|
||||
renderRect(rect: Rect): void {
|
||||
let origin = this.scene.getViewTranslation(rect);
|
||||
let zoom = this.scene.getViewScale();
|
||||
|
||||
renderRect(rect: Rect, origin: Vec2, zoom: number): void {
|
||||
// Draw the interior of the rect
|
||||
if(rect.color.a !== 0){
|
||||
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
|
||||
this.ctx.strokeStyle = rect.getBorderColor().toStringRGB();
|
||||
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;
|
||||
}
|
||||
|
||||
renderLabel(label: Label): void {
|
||||
renderLabel(label: Label, origin: Vec2, zoom: number): void {
|
||||
// If the size is unassigned (by the user or automatically) assign it
|
||||
label.handleInitialSizing(this.ctx);
|
||||
|
||||
// Grab the global alpha so we can adjust it for this render
|
||||
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
|
||||
this.ctx.font = label.getFontString();
|
||||
let offset = label.calculateTextOffset(this.ctx);
|
||||
|
@ -38,39 +35,37 @@ export default class UIElementRenderer {
|
|||
// Stroke and fill a rounded rect and give it text
|
||||
this.ctx.globalAlpha = label.backgroundColor.a;
|
||||
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);
|
||||
|
||||
this.ctx.strokeStyle = label.calculateBorderColor();
|
||||
this.ctx.globalAlpha = label.borderColor.a;
|
||||
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);
|
||||
|
||||
this.ctx.fillStyle = label.calculateTextColor();
|
||||
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;
|
||||
}
|
||||
|
||||
renderButton(button: Button): void {
|
||||
this.renderLabel(button);
|
||||
renderButton(button: Button, origin: Vec2, zoom: number): void {
|
||||
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
|
||||
let previousAlpha = this.ctx.globalAlpha;
|
||||
this.ctx.globalAlpha = slider.getLayer().getAlpha();
|
||||
|
||||
let origin = this.scene.getViewTranslation(slider);
|
||||
|
||||
// Calcualate the slider size
|
||||
let sliderSize = new Vec2(slider.size.x, 2);
|
||||
|
||||
// Draw the slider
|
||||
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);
|
||||
|
||||
// Calculate the nib size and position
|
||||
|
@ -80,20 +75,20 @@ export default class UIElementRenderer {
|
|||
|
||||
// Draw the nib
|
||||
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);
|
||||
|
||||
// Reset the alpha
|
||||
this.ctx.globalAlpha = previousAlpha;
|
||||
}
|
||||
|
||||
renderTextInput(textInput: TextInput): void {
|
||||
renderTextInput(textInput: TextInput, origin: Vec2, zoom: number): void {
|
||||
// Show a cursor sometimes
|
||||
if(textInput.focused && textInput.cursorCounter % 60 > 30){
|
||||
textInput.text += "|";
|
||||
}
|
||||
|
||||
this.renderLabel(textInput);
|
||||
this.renderLabel(textInput, origin, zoom);
|
||||
|
||||
if(textInput.focused){
|
||||
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 {
|
||||
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 GoombaController from "../Enemies/GoombaController";
|
||||
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 {
|
||||
PLAYER_HIT_COIN = "PlayerHitCoin",
|
||||
|
@ -15,32 +18,30 @@ export enum MarioEvents {
|
|||
}
|
||||
|
||||
export default class Level1 extends Scene {
|
||||
player: GameNode;
|
||||
player: AnimatedSprite;
|
||||
coinCount: number = 0;
|
||||
coinCountLabel: Label;
|
||||
livesCount: number = 3;
|
||||
livesCountLabel: Label;
|
||||
|
||||
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("koopa", "assets/sprites/Koopa.png");
|
||||
this.load.spritesheet("player", "assets/spritesheets/walking.json");
|
||||
}
|
||||
|
||||
startScene(): void {
|
||||
let tilemap = this.add.tilemap("level1", new Vec2(2, 2))[0].getItems()[0];
|
||||
console.log(tilemap);
|
||||
console.log((tilemap as OrthogonalTilemap).getTileAtRowCol(new Vec2(8, 17)));
|
||||
(tilemap as OrthogonalTilemap).setTileAtRowCol(new Vec2(8, 17), 1);
|
||||
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);
|
||||
let tilemap = <OrthogonalTilemap>this.add.tilemap("level1", new Vec2(2, 2))[0].getItems()[0];
|
||||
//tilemap.position.set(tilemap.size.x*tilemap.scale.x/2, tilemap.size.y*tilemap.scale.y/2);
|
||||
tilemap.position.set(0, 0);
|
||||
this.viewport.setBounds(0, 0, 128*32, 20*32);
|
||||
|
||||
// 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.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.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.viewport.follow(this.player);
|
||||
this.viewport.enableZoom();
|
||||
this.viewport.setZoomLevel(2);
|
||||
|
||||
// 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}]){
|
||||
let goomba = this.add.sprite("goomba", "Main");
|
||||
goomba.position.set(pos.x*64, pos.y*64);
|
||||
goomba.scale.set(2, 2);
|
||||
goomba.addPhysics();
|
||||
goomba.addAI(GoombaController, {jumpy: false});
|
||||
goomba.setPhysicsLayer("enemy");
|
||||
}
|
||||
// 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");
|
||||
// goomba.position.set(pos.x*64, pos.y*64);
|
||||
// goomba.scale.set(2, 2);
|
||||
// goomba.addPhysics();
|
||||
// goomba.addAI(GoombaController, {jumpy: false});
|
||||
// goomba.setPhysicsLayer("enemy");
|
||||
// }
|
||||
|
||||
for(let pos of [{x: 67, y: 18}, {x: 86, y: 21}, {x: 128, y: 18}]){
|
||||
let koopa = this.add.sprite("koopa", "Main");
|
||||
koopa.position.set(pos.x*64, pos.y*64);
|
||||
koopa.scale.set(2, 2);
|
||||
koopa.addPhysics();
|
||||
koopa.addAI(GoombaController, {jumpy: true});
|
||||
koopa.setPhysicsLayer("enemy");
|
||||
}
|
||||
// for(let pos of [{x: 67, y: 18}, {x: 86, y: 21}, {x: 128, y: 18}]){
|
||||
// let koopa = this.add.sprite("koopa", "Main");
|
||||
// koopa.position.set(pos.x*64, pos.y*64);
|
||||
// koopa.scale.set(2, 2);
|
||||
// koopa.addPhysics();
|
||||
// koopa.addAI(GoombaController, {jumpy: true});
|
||||
// koopa.setPhysicsLayer("enemy");
|
||||
// }
|
||||
|
||||
// Add 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(this.player.position.y > 21*64){
|
||||
this.player.position.set(192, 1152);
|
||||
if(this.player.position.y > 100*64){
|
||||
this.player.position.set(5*32, 18*32);
|
||||
this.livesCount -= 1
|
||||
this.livesCountLabel.setText("Lives: " + this.livesCount);
|
||||
}
|
||||
|
|
|
@ -1,16 +1,18 @@
|
|||
import Vec2 from "../../DataTypes/Vec2";
|
||||
import Debug from "../../Debug/Debug";
|
||||
import InputReceiver from "../../Input/InputReceiver";
|
||||
import AnimatedSprite from "../../Nodes/Sprites/AnimatedSprite";
|
||||
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 Scene from "../../Scene/Scene";
|
||||
import Color from "../../Utils/Color";
|
||||
import { EaseFunctionType } from "../../Utils/EaseFunctions";
|
||||
import Level1 from "./Level1";
|
||||
|
||||
export default class MainMenu extends Scene {
|
||||
|
||||
animatedSprite: AnimatedSprite;
|
||||
|
||||
loadScene(): void {
|
||||
this.load.spritesheet("walker", "assets/spritesheets/walking.json");
|
||||
}
|
||||
|
@ -47,6 +49,44 @@ export default class MainMenu extends Scene {
|
|||
animatedSprite.scale.set(4, 4);
|
||||
animatedSprite.animation.play("JUMP");
|
||||
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 {
|
||||
|
|
|
@ -27,9 +27,9 @@ export enum PlayerStates {
|
|||
export default class PlayerController extends StateMachineAI {
|
||||
protected owner: GameNode;
|
||||
velocity: Vec2 = Vec2.ZERO;
|
||||
speed: number = 400;
|
||||
MIN_SPEED: number = 400;
|
||||
MAX_SPEED: number = 1000;
|
||||
speed: number = 200;
|
||||
MIN_SPEED: number = 200;
|
||||
MAX_SPEED: number = 500;
|
||||
tilemap: OrthogonalTilemap;
|
||||
|
||||
initializeAI(owner: GameNode, options: Record<string, any>){
|
||||
|
|
|
@ -1,10 +1,14 @@
|
|||
import AnimatedSprite from "../../../../Nodes/Sprites/AnimatedSprite";
|
||||
import OnGround from "./OnGround";
|
||||
import { PlayerStates } from "./PlayerController";
|
||||
import PlayerState from "./PlayerState";
|
||||
|
||||
export default class Idle extends OnGround {
|
||||
owner: AnimatedSprite;
|
||||
|
||||
onEnter(): void {
|
||||
this.parent.speed = this.parent.MIN_SPEED;
|
||||
this.owner.animation.play("IDLE", true);
|
||||
}
|
||||
|
||||
update(deltaT: number): void {
|
||||
|
@ -24,4 +28,8 @@ export default class Idle extends OnGround {
|
|||
|
||||
this.owner.move(this.parent.velocity.scaled(deltaT));
|
||||
}
|
||||
|
||||
onExit(): void {
|
||||
this.owner.animation.stop();
|
||||
}
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
import Vec2 from "../../../../DataTypes/Vec2";
|
||||
import GameEvent from "../../../../Events/GameEvent";
|
||||
import AnimatedSprite from "../../../../Nodes/Sprites/AnimatedSprite";
|
||||
import MathUtils from "../../../../Utils/MathUtils";
|
||||
import { CustomGameEventType } from "../../../CustomGameEventType";
|
||||
import Level1, { MarioEvents } from "../../../Mario/Level1";
|
||||
|
@ -7,8 +8,11 @@ import { PlayerStates } from "./PlayerController";
|
|||
import PlayerState from "./PlayerState";
|
||||
|
||||
export default class Jump extends PlayerState {
|
||||
owner: AnimatedSprite;
|
||||
|
||||
onEnter(): void {}
|
||||
onEnter(): void {
|
||||
this.owner.animation.play("JUMP", true);
|
||||
}
|
||||
|
||||
handleInput(event: GameEvent): void {}
|
||||
|
||||
|
@ -27,8 +31,8 @@ export default class Jump extends PlayerState {
|
|||
console.log("Hit tile: " + tile);
|
||||
|
||||
// If coin block, change to empty coin block
|
||||
if(tile === 4){
|
||||
this.parent.tilemap.setTileAtRowCol(pos, 12);
|
||||
if(tile === 17){
|
||||
this.parent.tilemap.setTileAtRowCol(pos, 18);
|
||||
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));
|
||||
}
|
||||
|
||||
onExit(): void {}
|
||||
onExit(): void {
|
||||
this.owner.animation.stop();
|
||||
}
|
||||
}
|
|
@ -1,4 +1,6 @@
|
|||
import GameEvent from "../../../../Events/GameEvent";
|
||||
import Sprite from "../../../../Nodes/Sprites/Sprite";
|
||||
import MathUtils from "../../../../Utils/MathUtils";
|
||||
import { CustomGameEventType } from "../../../CustomGameEventType";
|
||||
import PlayerState from "./PlayerState";
|
||||
|
||||
|
@ -13,9 +15,18 @@ export default class OnGround extends PlayerState {
|
|||
}
|
||||
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")){
|
||||
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)
|
||||
} else if(!this.owner.onGround){
|
||||
this.finished("jump");
|
||||
|
|
|
@ -1,15 +1,19 @@
|
|||
import State from "../../../../DataTypes/State/State";
|
||||
import StateMachine from "../../../../DataTypes/State/StateMachine";
|
||||
import Vec2 from "../../../../DataTypes/Vec2";
|
||||
import Debug from "../../../../Debug/Debug";
|
||||
import InputReceiver from "../../../../Input/InputReceiver";
|
||||
import CanvasNode from "../../../../Nodes/CanvasNode";
|
||||
import GameNode from "../../../../Nodes/GameNode";
|
||||
import Sprite from "../../../../Nodes/Sprites/Sprite";
|
||||
import MathUtils from "../../../../Utils/MathUtils";
|
||||
import PlayerController from "../../PlayerController";
|
||||
|
||||
|
||||
export default abstract class PlayerState extends State {
|
||||
input: InputReceiver = InputReceiver.getInstance();
|
||||
owner: GameNode;
|
||||
gravity: number = 7000;
|
||||
gravity: number = 1000;
|
||||
parent: PlayerController;
|
||||
|
||||
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 OnGround from "./OnGround";
|
||||
import { PlayerStates } from "./PlayerController";
|
||||
|
||||
export default class Run extends OnGround {
|
||||
owner: AnimatedSprite;
|
||||
|
||||
onEnter(): void {
|
||||
this.parent.speed = this.parent.MAX_SPEED;
|
||||
this.owner.animation.play("WALK", true);
|
||||
}
|
||||
|
||||
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.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 OnGround from "./OnGround";
|
||||
import { PlayerStates } from "./PlayerController";
|
||||
|
||||
export default class Walk extends OnGround {
|
||||
owner: AnimatedSprite;
|
||||
|
||||
onEnter(): void {
|
||||
this.parent.speed = this.parent.MAX_SPEED/2;
|
||||
this.owner.animation.play("WALK", true);
|
||||
}
|
||||
|
||||
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.owner.move(this.parent.velocity.scaled(deltaT));
|
||||
}
|
||||
|
||||
onExit(): void {
|
||||
this.owner.animation.stop();
|
||||
}
|
||||
}
|
|
@ -7,6 +7,7 @@ function main(){
|
|||
// Create the game object
|
||||
let options = {
|
||||
viewportSize: {x: 800, y: 600},
|
||||
clearColor: {r: 34, g: 32, b: 52}
|
||||
}
|
||||
|
||||
let game = new GameLoop(options);
|
||||
|
|
|
@ -59,6 +59,6 @@
|
|||
],
|
||||
"compilerOptions": {
|
||||
"noImplicitAny": true,
|
||||
"target": "es5"
|
||||
"target": "es2016"
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user