improved visual debugging
This commit is contained in:
parent
b8849b4c84
commit
4b8ebf360d
|
@ -1,8 +1,8 @@
|
|||
import Graph, { MAX_V } from "./Graph";
|
||||
import Vec2 from "../Vec2";
|
||||
import { Debug_Renderable } from "../Interfaces/Descriptors";
|
||||
import { DebugRenderable } from "../Interfaces/Descriptors";
|
||||
|
||||
export default class PositionGraph extends Graph implements Debug_Renderable{
|
||||
export default class PositionGraph extends Graph implements DebugRenderable{
|
||||
positions: Array<Vec2>;
|
||||
|
||||
constructor(directed: boolean = false){
|
||||
|
@ -38,9 +38,9 @@ export default class PositionGraph extends Graph implements Debug_Renderable{
|
|||
return "Node " + index + " - " + this.positions[index].toString();
|
||||
}
|
||||
|
||||
debug_render(ctx: CanvasRenderingContext2D, origin: Vec2, zoom: number): void {
|
||||
for(let point of this.positions){
|
||||
ctx.fillRect((point.x - origin.x - 4)*zoom, (point.y - origin.y - 4)*zoom, 8, 8);
|
||||
}
|
||||
debugRender = (): void => {
|
||||
// for(let point of this.positions){
|
||||
// ctx.fillRect((point.x - origin.x - 4)*zoom, (point.y - origin.y - 4)*zoom, 8, 8);
|
||||
// }
|
||||
}
|
||||
}
|
|
@ -156,12 +156,7 @@ export interface Updateable {
|
|||
update: (deltaT: number) => void;
|
||||
}
|
||||
|
||||
export interface Renderable {
|
||||
/** Renders this object. */
|
||||
render: (ctx: CanvasRenderingContext2D) => void;
|
||||
}
|
||||
|
||||
export interface Debug_Renderable {
|
||||
export interface DebugRenderable {
|
||||
/** Renders the debugging infor for this object. */
|
||||
debug_render: (ctx: CanvasRenderingContext2D, origin: Vec2, zoom: number) => void;
|
||||
debugRender(): void;
|
||||
}
|
||||
|
|
|
@ -307,17 +307,24 @@ export default class Vec2 {
|
|||
* @param other The vector to check against
|
||||
*/
|
||||
equals(other: Vec2): boolean {
|
||||
let xEq = Math.abs(this.x - other.x) < 0.00000001;
|
||||
let yEq = Math.abs(this.y - other.y) < 0.00000001;
|
||||
let xEq = Math.abs(this.x - other.x) < 0.0000001;
|
||||
let yEq = Math.abs(this.y - other.y) < 0.0000001;
|
||||
|
||||
return xEq && yEq;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this vector is the zero vector
|
||||
* Returns true if this vector is the zero vector exactly (not assured to be safe for floats).
|
||||
*/
|
||||
strictIsZero(): boolean {
|
||||
return this.x === 0 && this.y === 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this x and y for this vector are both zero.
|
||||
*/
|
||||
isZero(): boolean {
|
||||
return this.x === 0 && this.y === 0;
|
||||
return Math.abs(this.x) < 0.0000001 && Math.abs(this.y) < 0.0000001;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,27 +1,135 @@
|
|||
import Map from "../DataTypes/Map";
|
||||
import Vec2 from "../DataTypes/Vec2";
|
||||
import InputHandler from "../Input/InputHandler";
|
||||
import GameNode from "../Nodes/GameNode";
|
||||
import Color from "../Utils/Color";
|
||||
|
||||
type DebugRenderFunction = (ctx: CanvasRenderingContext2D) => void;
|
||||
|
||||
export default class Debug {
|
||||
|
||||
// A map of log messages to display on the screen
|
||||
/** A map of log messages to display on the screen */
|
||||
private static logMessages: Map<string> = new Map();
|
||||
|
||||
/** An array of game nodes to render debug info for */
|
||||
private static nodes: Array<GameNode>;
|
||||
|
||||
/** The rendering context for any debug messages */
|
||||
private static debugRenderingContext: CanvasRenderingContext2D;
|
||||
|
||||
/** The size of the debug canvas */
|
||||
private static debugCanvasSize: Vec2;
|
||||
|
||||
/** The rendering color for text */
|
||||
private static defaultTextColor: Color = Color.WHITE;
|
||||
|
||||
/**
|
||||
* Add a message to display on the debug screen
|
||||
* @param id A unique ID for this message
|
||||
* @param messages The messages to print to the debug screen
|
||||
*/
|
||||
static log(id: string, ...messages: any): void {
|
||||
let message = "";
|
||||
for(let i = 0; i < messages.length; i++){
|
||||
message += messages[i].toString();
|
||||
}
|
||||
// let message = "";
|
||||
// for(let i = 0; i < messages.length; i++){
|
||||
// message += messages[i].toString();
|
||||
// }
|
||||
// Join all messages with spaces
|
||||
let message = messages.map((m: any) => m.toString()).join(" ");
|
||||
this.logMessages.add(id, message);
|
||||
}
|
||||
|
||||
// TODO: Create a method that can delete messages from the log
|
||||
/**
|
||||
* Deletes a a key from the log and stops it from keeping up space on the screen
|
||||
* @param id
|
||||
*/
|
||||
static clearLogItem(id: string): void {
|
||||
this.logMessages.delete(id);
|
||||
}
|
||||
|
||||
static render(ctx: CanvasRenderingContext2D): void {
|
||||
/**
|
||||
* Sets the list of nodes to render with the debugger
|
||||
* @param nodes The new list of nodes
|
||||
*/
|
||||
static setNodes(nodes: Array<GameNode>): void {
|
||||
this.nodes = nodes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws a box at the specified position
|
||||
* @param center The center of the box
|
||||
* @param halfSize The dimensions of the box
|
||||
* @param filled A boolean for whether or not the box is filled
|
||||
*/
|
||||
static drawBox(center: Vec2, halfSize: Vec2, filled: boolean, color: Color): void {
|
||||
if(filled){
|
||||
this.debugRenderingContext.fillStyle = color.toString();
|
||||
this.debugRenderingContext.fillRect(center.x - halfSize.x, center.y - halfSize.y, halfSize.x*2, halfSize.y*2);
|
||||
} else {
|
||||
let lineWidth = 2;
|
||||
this.debugRenderingContext.lineWidth = lineWidth;
|
||||
this.debugRenderingContext.strokeStyle = color.toString();
|
||||
this.debugRenderingContext.strokeRect(center.x - halfSize.x, center.y - halfSize.y, halfSize.x*2, halfSize.y*2);
|
||||
}
|
||||
}
|
||||
|
||||
static drawRay(from: Vec2, to: Vec2, color: Color): void {
|
||||
this.debugRenderingContext.lineWidth = 2;
|
||||
this.debugRenderingContext.strokeStyle = color.toString();
|
||||
|
||||
this.debugRenderingContext.beginPath();
|
||||
this.debugRenderingContext.moveTo(from.x, from.y);
|
||||
this.debugRenderingContext.lineTo(to.x, to.y);
|
||||
this.debugRenderingContext.closePath();
|
||||
this.debugRenderingContext.stroke();
|
||||
}
|
||||
|
||||
static drawPoint(pos: Vec2, color: Color): void {
|
||||
let pointSize = 6;
|
||||
this.debugRenderingContext.fillStyle = color.toString();
|
||||
this.debugRenderingContext.fillRect(pos.x - pointSize/2, pos.y - pointSize/2, pointSize, pointSize);
|
||||
}
|
||||
|
||||
static setDefaultTextColor(color: Color): void {
|
||||
this.defaultTextColor = color;
|
||||
}
|
||||
|
||||
static initializeDebugCanvas(canvas: HTMLCanvasElement, width: number, height: number): CanvasRenderingContext2D {
|
||||
canvas.width = width;
|
||||
canvas.height = height;
|
||||
|
||||
this.debugCanvasSize = new Vec2(width, height);
|
||||
|
||||
this.debugRenderingContext = canvas.getContext("2d");
|
||||
|
||||
return this.debugRenderingContext;
|
||||
}
|
||||
|
||||
static clearCanvas(): void {
|
||||
this.debugRenderingContext.clearRect(0, 0, this.debugCanvasSize.x, this.debugCanvasSize.y);
|
||||
}
|
||||
|
||||
static render(): void {
|
||||
this.renderText();
|
||||
this.renderNodes();
|
||||
}
|
||||
|
||||
static renderText(): void {
|
||||
let y = 20;
|
||||
ctx.font = "20px Arial";
|
||||
ctx.fillStyle = "#000000";
|
||||
this.debugRenderingContext.font = "20px Arial";
|
||||
this.debugRenderingContext.fillStyle = this.defaultTextColor.toString();
|
||||
|
||||
// Draw all of the text
|
||||
this.logMessages.forEach((key: string) => {
|
||||
ctx.fillText(this.logMessages.get(key), 10, y)
|
||||
this.debugRenderingContext.fillText(this.logMessages.get(key), 10, y)
|
||||
y += 30;
|
||||
});
|
||||
}
|
||||
|
||||
static renderNodes(): void {
|
||||
if(this.nodes){
|
||||
this.nodes.forEach(node => {
|
||||
node.debugRender();
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
|
@ -59,7 +59,8 @@ export default class GameLoop {
|
|||
private numUpdateSteps: number;
|
||||
|
||||
// Game canvas and its width and height
|
||||
readonly GAME_CANVAS: HTMLCanvasElement;
|
||||
readonly GAME_CANVAS: HTMLCanvasElement;
|
||||
readonly DEBUG_CANVAS: HTMLCanvasElement;
|
||||
readonly WIDTH: number;
|
||||
readonly HEIGHT: number;
|
||||
private viewport: Viewport;
|
||||
|
@ -100,7 +101,7 @@ export default class GameLoop {
|
|||
|
||||
// Get the game canvas and give it a background color
|
||||
this.GAME_CANVAS = <HTMLCanvasElement>document.getElementById("game-canvas");
|
||||
this.GAME_CANVAS.style.setProperty("background-color", "whitesmoke");
|
||||
this.DEBUG_CANVAS = <HTMLCanvasElement>document.getElementById("debug-canvas");
|
||||
|
||||
// Give the canvas a size and get the rendering context
|
||||
this.WIDTH = this.gameOptions.viewportSize.x;
|
||||
|
@ -108,9 +109,14 @@ export default class GameLoop {
|
|||
|
||||
// For now, just hard code a canvas renderer. We can do this with options later
|
||||
this.renderingManager = new CanvasRenderer();
|
||||
this.initializeGameWindow();
|
||||
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);
|
||||
|
||||
// Initialize debug canvas
|
||||
|
||||
Debug.initializeDebugCanvas(this.DEBUG_CANVAS, this.WIDTH, this.HEIGHT);
|
||||
|
||||
// Size the viewport to the game canvas
|
||||
this.viewport = new Viewport();
|
||||
this.viewport.setCanvasSize(this.WIDTH, this.HEIGHT);
|
||||
|
@ -129,6 +135,17 @@ export default class GameLoop {
|
|||
Stats.initStats();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set up the game window that holds the canvases
|
||||
*/
|
||||
private initializeGameWindow(): void {
|
||||
const gameWindow = document.getElementById("game-window");
|
||||
|
||||
// Set the height of the game window
|
||||
gameWindow.style.width = this.WIDTH + "px";
|
||||
gameWindow.style.height = this.HEIGHT + "px";
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes the maximum allowed physics framerate of the game
|
||||
* @param initMax
|
||||
|
@ -274,11 +291,17 @@ export default class GameLoop {
|
|||
* Clears the canvas and defers scene rendering to the sceneManager. Renders the debug
|
||||
*/
|
||||
render(): void {
|
||||
// Clear the canvases
|
||||
this.ctx.clearRect(0, 0, this.WIDTH, this.HEIGHT);
|
||||
Debug.clearCanvas();
|
||||
|
||||
// Game Canvas
|
||||
this.ctx.fillStyle = this.clearColor.toString();
|
||||
this.ctx.fillRect(0, 0, this.WIDTH, this.HEIGHT);
|
||||
this.sceneManager.render();
|
||||
Debug.render(this.ctx);
|
||||
|
||||
// Debug render
|
||||
Debug.render();
|
||||
Stats.render();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
import GameNode from "./GameNode";
|
||||
import Vec2 from "../DataTypes/Vec2";
|
||||
import { Region, Renderable } from "../DataTypes/Interfaces/Descriptors";
|
||||
import { Region } from "../DataTypes/Interfaces/Descriptors";
|
||||
import AABB from "../DataTypes/Shapes/AABB";
|
||||
import Debug from "../Debug/Debug";
|
||||
import Color from "../Utils/Color";
|
||||
|
||||
/**
|
||||
* The representation of an object in the game world that can be drawn to the screen
|
||||
|
@ -75,6 +77,12 @@ export default abstract class CanvasNode extends GameNode implements Region {
|
|||
return this._boundary;
|
||||
}
|
||||
|
||||
get sizeWithZoom(): Vec2 {
|
||||
let zoom = this.scene.getViewScale();
|
||||
|
||||
return this.boundary.halfSize.clone().scaled(zoom, zoom);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the point (x, y) is inside of this canvas object
|
||||
* @param x
|
||||
|
@ -83,4 +91,9 @@ export default abstract class CanvasNode extends GameNode implements Region {
|
|||
contains(x: number, y: number): boolean {
|
||||
return this._boundary.containsPoint(new Vec2(x, y));
|
||||
}
|
||||
|
||||
debugRender(): void {
|
||||
super.debugRender();
|
||||
Debug.drawBox(this.relativePosition, this.sizeWithZoom, false, Color.GREEN);
|
||||
}
|
||||
}
|
|
@ -4,17 +4,19 @@ import Receiver from "../Events/Receiver";
|
|||
import Emitter from "../Events/Emitter";
|
||||
import Scene from "../Scene/Scene";
|
||||
import Layer from "../Scene/Layer";
|
||||
import { Physical, Positioned, isRegion, Unique, Updateable, Actor, AI, Debug_Renderable } from "../DataTypes/Interfaces/Descriptors"
|
||||
import { Physical, Positioned, isRegion, Unique, Updateable, Actor, AI, DebugRenderable } from "../DataTypes/Interfaces/Descriptors"
|
||||
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";
|
||||
import Debug from "../Debug/Debug";
|
||||
import Color from "../Utils/Color";
|
||||
|
||||
/**
|
||||
* The representation of an object in the game world
|
||||
*/
|
||||
export default abstract class GameNode implements Positioned, Unique, Updateable, Physical, Actor {
|
||||
export default abstract class GameNode implements Positioned, Unique, Updateable, Physical, Actor, DebugRenderable {
|
||||
/*---------- POSITIONED ----------*/
|
||||
private _position: Vec2;
|
||||
|
||||
|
@ -79,6 +81,13 @@ export default abstract class GameNode implements Positioned, Unique, Updateable
|
|||
this.positionChanged();
|
||||
}
|
||||
|
||||
get relativePosition(): Vec2 {
|
||||
let origin = this.scene.getViewTranslation(this);
|
||||
let zoom = this.scene.getViewScale();
|
||||
|
||||
return this.position.clone().sub(origin).scale(zoom);
|
||||
}
|
||||
|
||||
/*---------- UNIQUE ----------*/
|
||||
get id(): number {
|
||||
return this._id;
|
||||
|
@ -249,6 +258,15 @@ export default abstract class GameNode implements Positioned, Unique, Updateable
|
|||
update(deltaT: number): void {
|
||||
this.tweens.update(deltaT);
|
||||
}
|
||||
|
||||
debugRender(): void {
|
||||
Debug.drawPoint(this.relativePosition, Color.GREEN);
|
||||
|
||||
// If velocity is not zero, draw a vector for it
|
||||
if(this._velocity && !this._velocity.isZero()){
|
||||
Debug.drawRay(this.relativePosition, this._velocity.clone().scaleTo(20).add(this.relativePosition), Color.GREEN);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export enum TweenableProperties{
|
||||
|
|
|
@ -4,14 +4,14 @@ import Color from "../../Utils/Color";
|
|||
|
||||
export default class Rect extends Graphic {
|
||||
|
||||
protected borderColor: Color;
|
||||
borderColor: Color;
|
||||
protected borderWidth: number;
|
||||
|
||||
constructor(position: Vec2, size: Vec2){
|
||||
super();
|
||||
this.position = position;
|
||||
this.size = size;
|
||||
this.borderColor = this.color;
|
||||
this.borderColor = Color.TRANSPARENT;
|
||||
this.borderWidth = 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -49,6 +49,12 @@ export default abstract class Tilemap extends CanvasNode {
|
|||
return this.tileSize.scaled(this.scale.x, this.scale.y);
|
||||
}
|
||||
|
||||
getTileSizeWithZoom(): Vec2 {
|
||||
let zoom = this.scene.getViewScale();
|
||||
|
||||
return this.getTileSize().scale(zoom);
|
||||
}
|
||||
|
||||
/** Adds this tilemap to the physics system */
|
||||
addPhysics = (): void => {
|
||||
this.scene.getPhysicsManager().registerTilemap(this);
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
import Tilemap from "../Tilemap";
|
||||
import Vec2 from "../../DataTypes/Vec2";
|
||||
import { TiledTilemapData, TiledLayerData } from "../../DataTypes/Tilesets/TiledData";
|
||||
import Tileset from "../../DataTypes/Tilesets/Tileset";
|
||||
import Debug from "../../Debug/Debug";
|
||||
import Color from "../../Utils/Color";
|
||||
|
||||
/**
|
||||
* The representation of an orthogonal tilemap - i.e. a top down or platformer tilemap
|
||||
|
@ -46,6 +47,10 @@ export default class OrthogonalTilemap extends Tilemap {
|
|||
}
|
||||
}
|
||||
|
||||
getDimensions(): Vec2 {
|
||||
return new Vec2(this.numCols, this.numRows);
|
||||
}
|
||||
|
||||
getTileAtWorldPosition(worldCoords: Vec2): number {
|
||||
let localCoords = this.getColRowAt(worldCoords);
|
||||
return this.getTileAtRowCol(localCoords);
|
||||
|
@ -128,4 +133,20 @@ export default class OrthogonalTilemap extends Tilemap {
|
|||
}
|
||||
|
||||
update(deltaT: number): void {}
|
||||
|
||||
debugRender(){
|
||||
let tileSize = this.getTileSizeWithZoom();
|
||||
let origin = this.relativePosition.sub(this.sizeWithZoom);
|
||||
|
||||
for(let col = 0; col < this.numCols; col++){
|
||||
for(let row = 0; row < this.numRows; row++){
|
||||
if(this.isCollidable && this.isTileCollidable(col, row)){
|
||||
// Draw a box for this tile
|
||||
let center = new Vec2(origin.x + (col + 0.5)*tileSize.x, origin.y + (row + 0.5)*tileSize.y);
|
||||
|
||||
Debug.drawBox(center, tileSize.scaled(0.5), false, Color.BLUE);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -100,13 +100,4 @@ export default class Label extends UIElement{
|
|||
sizeToText(): void {
|
||||
this.sizeAssigned = false;
|
||||
}
|
||||
|
||||
debug_render = (ctx: CanvasRenderingContext2D): void => {
|
||||
let origin = this.scene.getViewTranslation(this);
|
||||
|
||||
ctx.lineWidth = 4;
|
||||
ctx.strokeStyle = "#00FF00"
|
||||
let b = this.boundary;
|
||||
ctx.strokeRect(b.x - b.hw - origin.x, b.y - b.hh - origin.y, b.hw*2, b.hh*2);
|
||||
};
|
||||
}
|
|
@ -326,10 +326,6 @@ export default class BasicPhysicsManager extends PhysicsManager {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
debug_render(ctx: CanvasRenderingContext2D): void {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// Collision data objects for tilemaps
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
import GameNode from "../Nodes/GameNode";
|
||||
import Vec2 from "../DataTypes/Vec2";
|
||||
import { Debug_Renderable, Updateable } from "../DataTypes/Interfaces/Descriptors";
|
||||
import { Updateable } from "../DataTypes/Interfaces/Descriptors";
|
||||
import Tilemap from "../Nodes/Tilemap";
|
||||
import Receiver from "../Events/Receiver";
|
||||
import Emitter from "../Events/Emitter";
|
||||
import Map from "../DataTypes/Map";
|
||||
|
||||
export default abstract class PhysicsManager implements Updateable, Debug_Renderable {
|
||||
export default abstract class PhysicsManager implements Updateable {
|
||||
protected receiver: Receiver;
|
||||
protected emitter: Emitter;
|
||||
|
||||
|
@ -43,12 +43,6 @@ export default abstract class PhysicsManager implements Updateable, Debug_Render
|
|||
*/
|
||||
abstract update(deltaT: number): void;
|
||||
|
||||
/**
|
||||
* Renders any debug shapes or graphics
|
||||
* @param ctx
|
||||
*/
|
||||
abstract debug_render(ctx: CanvasRenderingContext2D): void;
|
||||
|
||||
setLayer(node: GameNode, layer: string): void {
|
||||
node.physicsLayer = this.layerMap.get(layer);
|
||||
}
|
||||
|
|
|
@ -199,9 +199,9 @@ export default class CanvasRenderer extends RenderingManager {
|
|||
|
||||
protected renderGraphic(graphic: Graphic): void {
|
||||
if(graphic instanceof Point){
|
||||
this.graphicRenderer.renderPoint(<Point>graphic, this.origin, this.zoom);
|
||||
this.graphicRenderer.renderPoint(<Point>graphic, this.zoom);
|
||||
} else if(graphic instanceof Rect){
|
||||
this.graphicRenderer.renderRect(<Rect>graphic, this.origin, this.zoom);
|
||||
this.graphicRenderer.renderRect(<Rect>graphic, this.zoom);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -213,13 +213,13 @@ export default class CanvasRenderer extends RenderingManager {
|
|||
|
||||
protected renderUIElement(uiElement: UIElement): void {
|
||||
if(uiElement instanceof Label){
|
||||
this.uiElementRenderer.renderLabel(uiElement, this.origin, this.zoom);
|
||||
this.uiElementRenderer.renderLabel(uiElement);
|
||||
} else if(uiElement instanceof Button){
|
||||
this.uiElementRenderer.renderButton(uiElement, this.origin, this.zoom);
|
||||
this.uiElementRenderer.renderButton(uiElement);
|
||||
} else if(uiElement instanceof Slider){
|
||||
this.uiElementRenderer.renderSlider(uiElement, this.origin, this.zoom);
|
||||
this.uiElementRenderer.renderSlider(uiElement);
|
||||
} else if(uiElement instanceof TextInput){
|
||||
this.uiElementRenderer.renderTextInput(uiElement, this.origin, this.zoom);
|
||||
this.uiElementRenderer.renderTextInput(uiElement);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -18,22 +18,24 @@ export default class GraphicRenderer {
|
|||
this.scene = scene;
|
||||
}
|
||||
|
||||
renderPoint(point: Point, origin: Vec2, zoom: number): void {
|
||||
renderPoint(point: Point, zoom: number): void {
|
||||
this.ctx.fillStyle = point.color.toStringRGBA();
|
||||
this.ctx.fillRect((-point.size.x/2)*zoom, (-point.size.y/2)*zoom,
|
||||
point.size.x*zoom, point.size.y*zoom);
|
||||
}
|
||||
|
||||
renderRect(rect: Rect, origin: Vec2, zoom: number): void {
|
||||
renderRect(rect: Rect, zoom: number): void {
|
||||
// Draw the interior of the rect
|
||||
if(rect.color.a !== 0){
|
||||
this.ctx.fillStyle = rect.color.toStringRGB();
|
||||
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.size.x/2)*zoom, (-rect.size.y/2)*zoom, rect.size.x*zoom, rect.size.y*zoom);
|
||||
// Draw the border of the rect if it isn't transparent
|
||||
if(rect.borderColor.a !== 0){
|
||||
this.ctx.strokeStyle = rect.getBorderColor().toStringRGB();
|
||||
this.ctx.lineWidth = rect.getBorderWidth();
|
||||
this.ctx.strokeRect((-rect.size.x/2)*zoom, (-rect.size.y/2)*zoom, rect.size.x*zoom, rect.size.y*zoom);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -21,7 +21,7 @@ export default class UIElementRenderer {
|
|||
this.scene = scene;
|
||||
}
|
||||
|
||||
renderLabel(label: Label, origin: Vec2, zoom: number): void {
|
||||
renderLabel(label: Label): void {
|
||||
// If the size is unassigned (by the user or automatically) assign it
|
||||
label.handleInitialSizing(this.ctx);
|
||||
|
||||
|
@ -51,11 +51,11 @@ export default class UIElementRenderer {
|
|||
this.ctx.globalAlpha = previousAlpha;
|
||||
}
|
||||
|
||||
renderButton(button: Button, origin: Vec2, zoom: number): void {
|
||||
this.renderLabel(button, origin, zoom);
|
||||
renderButton(button: Button): void {
|
||||
this.renderLabel(button);
|
||||
}
|
||||
|
||||
renderSlider(slider: Slider, origin: Vec2, zoom: number): void {
|
||||
renderSlider(slider: Slider): void {
|
||||
// Grab the global alpha so we can adjust it for this render
|
||||
let previousAlpha = this.ctx.globalAlpha;
|
||||
this.ctx.globalAlpha = slider.getLayer().getAlpha();
|
||||
|
@ -82,13 +82,13 @@ export default class UIElementRenderer {
|
|||
this.ctx.globalAlpha = previousAlpha;
|
||||
}
|
||||
|
||||
renderTextInput(textInput: TextInput, origin: Vec2, zoom: number): void {
|
||||
renderTextInput(textInput: TextInput): void {
|
||||
// Show a cursor sometimes
|
||||
if(textInput.focused && textInput.cursorCounter % 60 > 30){
|
||||
textInput.text += "|";
|
||||
}
|
||||
|
||||
this.renderLabel(textInput, origin, zoom);
|
||||
this.renderLabel(textInput);
|
||||
|
||||
if(textInput.focused){
|
||||
if(textInput.cursorCounter % 60 > 30){
|
||||
|
|
|
@ -12,7 +12,7 @@ import GameLoop from "../Loop/GameLoop";
|
|||
import SceneManager from "./SceneManager";
|
||||
import Receiver from "../Events/Receiver";
|
||||
import Emitter from "../Events/Emitter";
|
||||
import { Renderable, Updateable } from "../DataTypes/Interfaces/Descriptors";
|
||||
import { Updateable } from "../DataTypes/Interfaces/Descriptors";
|
||||
import NavigationManager from "../Pathfinding/NavigationManager";
|
||||
import AIManager from "../AI/AIManager";
|
||||
import Map from "../DataTypes/Map";
|
||||
|
@ -22,8 +22,9 @@ import CanvasNode from "../Nodes/CanvasNode";
|
|||
import GameNode from "../Nodes/GameNode";
|
||||
import ArrayUtils from "../Utils/ArrayUtils";
|
||||
import RenderingManager from "../Rendering/RenderingManager";
|
||||
import Debug from "../Debug/Debug";
|
||||
|
||||
export default class Scene implements Updateable, Renderable {
|
||||
export default class Scene implements Updateable {
|
||||
/** The size of the game world. */
|
||||
protected worldSize: Vec2;
|
||||
|
||||
|
@ -164,6 +165,10 @@ export default class Scene implements Updateable, Renderable {
|
|||
|
||||
// Send the visible set, tilemaps, and uiLayers to the renderer
|
||||
this.renderingManager.render(visibleSet, this.tilemaps, this.uiLayers);
|
||||
|
||||
let nodes = this.sceneGraph.getAllNodes();
|
||||
this.tilemaps.forEach(tilemap => tilemap.visible && tilemap.debugRender());
|
||||
Debug.setNodes(nodes);
|
||||
}
|
||||
|
||||
setRunning(running: boolean): void {
|
||||
|
|
|
@ -83,6 +83,12 @@ export default abstract class SceneGraph {
|
|||
|
||||
abstract getNodesInRegion(boundary: AABB): Array<CanvasNode>;
|
||||
|
||||
getAllNodes(): Array<CanvasNode> {
|
||||
let arr = new Array<CanvasNode>();
|
||||
this.nodeMap.forEach(key => arr.push(this.nodeMap.get(key)));
|
||||
return arr;
|
||||
}
|
||||
|
||||
/**
|
||||
* The specific implementation of getting a node at certain coordinates
|
||||
* @param x
|
||||
|
|
|
@ -27,7 +27,6 @@ export default class Walk extends OnGround {
|
|||
}
|
||||
|
||||
if(this.parent.jumpy && (Date.now() - this.time > 500)){
|
||||
console.log("Jump");
|
||||
this.finished(GoombaStates.JUMP);
|
||||
this.parent.velocity.y = -300;
|
||||
}
|
||||
|
|
55
src/_DemoClasses/PhysicsTesting/TestScene.ts
Normal file
55
src/_DemoClasses/PhysicsTesting/TestScene.ts
Normal file
|
@ -0,0 +1,55 @@
|
|||
import Vec2 from "../../DataTypes/Vec2";
|
||||
import InputHandler from "../../Input/InputHandler";
|
||||
import InputReceiver from "../../Input/InputReceiver";
|
||||
import { GraphicType } from "../../Nodes/Graphics/GraphicTypes";
|
||||
import BasicPhysicsManager from "../../Physics/BasicPhysicsManager";
|
||||
import Scene from "../../Scene/Scene";
|
||||
import Color from "../../Utils/Color";
|
||||
|
||||
export default class TestScene extends Scene {
|
||||
|
||||
startScene(){
|
||||
// Opt into a custom physics manager
|
||||
this.physicsManager = new BasicPhysicsManager(this.sceneOptions.physics);
|
||||
|
||||
this.addLayer("main");
|
||||
|
||||
let player = this.add.graphic(GraphicType.RECT, "main", {position: new Vec2(100, 100), size: new Vec2(100, 100)});
|
||||
player.addPhysics();
|
||||
|
||||
player.update = (deltaT: number) => {
|
||||
const input = InputReceiver.getInstance()
|
||||
|
||||
let xDir = (input.isPressed("a") ? -1 : 0) + (input.isPressed("d") ? 1 : 0);
|
||||
let yDir = (input.isPressed("w") ? -1 : 0) + (input.isPressed("s") ? 1 : 0);
|
||||
|
||||
let dir = new Vec2(xDir, yDir);
|
||||
dir.normalize();
|
||||
|
||||
if(!dir.isZero()){
|
||||
player.move(dir.scale(deltaT * 300));
|
||||
}
|
||||
}
|
||||
|
||||
let block = this.add.graphic(GraphicType.RECT, "main", {position: new Vec2(300, 500), size: new Vec2(100, 100)});
|
||||
block.color = Color.CYAN;
|
||||
block.addPhysics(block.boundary, true, true);
|
||||
|
||||
let movingBlock = this.add.graphic(GraphicType.RECT, "main", {position: new Vec2(500, 200), size: new Vec2(100, 100)});
|
||||
movingBlock.color = Color.CYAN;
|
||||
movingBlock.addPhysics();
|
||||
|
||||
let timer = 0;
|
||||
let dir = new Vec2(1, 0);
|
||||
movingBlock.update = (deltaT: number) => {
|
||||
if(timer > 0.5){
|
||||
timer = 0;
|
||||
dir.scale(-1);
|
||||
}
|
||||
|
||||
movingBlock.move(dir.scaled(200*deltaT));
|
||||
|
||||
timer += deltaT;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -26,16 +26,45 @@ export default class Jump extends PlayerState {
|
|||
|
||||
// Go up plus some extra
|
||||
pos.y -= (this.owner.collisionShape.halfSize.y + 10);
|
||||
pos = this.parent.tilemap.getColRowAt(pos);
|
||||
let tile = this.parent.tilemap.getTileAtRowCol(pos);
|
||||
pos.x -= 16;
|
||||
let rowCol = this.parent.tilemap.getColRowAt(pos);
|
||||
let tile1 = this.parent.tilemap.getTileAtRowCol(rowCol);
|
||||
pos.x += 16;
|
||||
rowCol = this.parent.tilemap.getColRowAt(pos);
|
||||
let tile2 = this.parent.tilemap.getTileAtRowCol(rowCol);
|
||||
pos.x += 16;
|
||||
rowCol = this.parent.tilemap.getColRowAt(pos);
|
||||
let tile3 = this.parent.tilemap.getTileAtRowCol(rowCol);
|
||||
|
||||
let t1 = tile1 === 17;
|
||||
let t2 = tile2 === 17;
|
||||
let t3 = tile3 === 17;
|
||||
let air1 = tile1 === 0;
|
||||
let air2 = tile2 === 0;
|
||||
let air3 = tile3 === 0;
|
||||
let majority = (t1 && t2) || (t1 && t3) || (t2 && t3) || (t1 && t2 && t3);
|
||||
let minorityButAir = (t1 && air2 && air3) || (air1 && t2 && air3) || (air1 && air2 && t3);
|
||||
|
||||
// If coin block, change to empty coin block
|
||||
if(tile === 17){
|
||||
this.parent.tilemap.setTileAtRowCol(pos, 18);
|
||||
if(majority || minorityButAir){
|
||||
if(minorityButAir){
|
||||
// Get the correct position
|
||||
if(t1){
|
||||
pos.x -= 32;
|
||||
} else if(t2){
|
||||
pos.x -= 16;
|
||||
}
|
||||
rowCol = this.parent.tilemap.getColRowAt(pos);
|
||||
} else {
|
||||
pos.x -= 16;
|
||||
rowCol = this.parent.tilemap.getColRowAt(pos);
|
||||
}
|
||||
|
||||
this.parent.tilemap.setTileAtRowCol(rowCol, 18);
|
||||
this.emitter.fireEvent(MarioEvents.PLAYER_HIT_COIN_BLOCK);
|
||||
|
||||
let tileSize = this.parent.tilemap.getTileSize();
|
||||
this.parent.coin.position.copy(pos.scale(tileSize.x, tileSize.y).add(tileSize.scaled(0.5)));
|
||||
this.parent.coin.position.copy(rowCol.scale(tileSize.x, tileSize.y).add(tileSize.scaled(0.5)));
|
||||
|
||||
// Animate collision
|
||||
this.parent.coin.tweens.add("coin", {
|
||||
|
|
|
@ -3,10 +3,40 @@
|
|||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>Game</title>
|
||||
<style>
|
||||
#game-window {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
#game-canvas {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
left: 0px;
|
||||
}
|
||||
|
||||
#debug-canvas {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
left: 0px;
|
||||
pointer-events: none;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div style="display: flex; flex-direction: row;">
|
||||
<canvas id="game-canvas"></canvas>
|
||||
<!-- The main window of the game. This contains the rendered game and any debug text -->
|
||||
<div id="game-window">
|
||||
<!-- This is the canvas where the actual game is rendered -->
|
||||
<canvas id="game-canvas"></canvas>
|
||||
<!-- This is the canvas where the debug text and graphics are rendered -->
|
||||
<canvas id="debug-canvas"></canvas>
|
||||
</div>
|
||||
|
||||
<!-- This contains stats about the game for development purposes, such as the average update time -->
|
||||
<div>
|
||||
<canvas id="stats-canvas"></canvas>
|
||||
<select name="Display" id="chart-option">
|
||||
|
|
|
@ -2,6 +2,7 @@ import GameLoop from "./Loop/GameLoop";
|
|||
import {} from "./index";
|
||||
import MainMenu from "./_DemoClasses/Mario/MainMenu";
|
||||
import Level1 from "./_DemoClasses/Mario/Level1";
|
||||
import TestScene from "./_DemoClasses/PhysicsTesting/TestScene";
|
||||
|
||||
function main(){
|
||||
// Create the game object
|
||||
|
|
Loading…
Reference in New Issue
Block a user