@moderrkowo/jsgl
Version:
Client-side JavaScript library for creating web 2D games. Focusing at objective game.
417 lines (416 loc) • 16.7 kB
JavaScript
"use strict";
var __assign = (this && this.__assign) || function () {
__assign = Object.assign || function(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
t[p] = s[p];
}
return t;
};
return __assign.apply(this, arguments);
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.Renderer = void 0;
var Vector2_1 = require("../structs/Vector2");
var DrawSettings_1 = require("../structs/DrawSettings");
var MathUtils_1 = require("../utils/math/MathUtils");
var RotationStyle_1 = require("../enums/RotationStyle");
var Rotation_1 = require("../structs/Rotation");
/**
* Class represents Game Renderer.
* @group Important Classes
*/
var Renderer = /** @class */ (function () {
/**
* Constructs new Renderer.
* @param handler The {@link Game} reference
*/
function Renderer(handler) {
/**
* How many pixels have one grid unit.
*/
this.gridSize = 0;
/**
* The decimal midpoint of parent element size.
*/
this.canvasParentSize = 1;
this.handler = handler;
}
/**
* Resizes canvas to parent element size by canvasParentSize (decimal midpoint).
* @method
* @example
* renderer.resizeCanvas();
*/
Renderer.prototype.resizeCanvas = function () {
if (!(this.handler.canvas instanceof HTMLCanvasElement))
throw new Error('Cannot resize undefined canvas!');
var canvas = this.handler.canvas;
var parent = canvas.parentElement;
if (parent == null)
throw new Error('Parent cannot be null!');
var maxWidth = parent.clientWidth;
var maxHeight = parent.clientHeight;
var width = (maxWidth * this.canvasParentSize) / this.handler.grid.x;
var height = (maxHeight * this.canvasParentSize) / this.handler.grid.y;
this.gridSize = Math.floor(Math.min(width, height));
this.canvasWidth = this.handler.grid.x * this.gridSize;
this.canvasHeight = this.handler.grid.y * this.gridSize;
};
Object.defineProperty(Renderer.prototype, "canvasWidth", {
/**
* Gets canvas width in pixels.
*/
get: function () {
return this.handler.canvas.width;
},
/**
* Sets canvas width in pixels.
* @param width The new width
*/
set: function (width) {
this.handler.canvas.width = width;
},
enumerable: false,
configurable: true
});
Object.defineProperty(Renderer.prototype, "canvasHeight", {
/**
* Gets canvas height in pixels.
*/
get: function () {
return this.handler.canvas.height;
},
/**
* Sets canvas height in pixels.
* @param height The new height
*/
set: function (height) {
this.handler.canvas.height = height;
},
enumerable: false,
configurable: true
});
Object.defineProperty(Renderer.prototype, "ctx", {
/**
* Gets the {@link CanvasRenderingContext2D}.
*/
get: function () {
var context = this.handler.canvas.getContext('2d');
if (context == null)
throw new Error('There was a problem during getting the context');
return context;
},
enumerable: false,
configurable: true
});
Object.defineProperty(Renderer.prototype, "canvasSize", {
/**
* Gets the Vector2 of width and height in pixels.
*/
get: function () {
return new Vector2_1.Vector2(this.canvasWidth, this.canvasHeight);
},
enumerable: false,
configurable: true
});
/**
* Scales number from client coordinate to grid coordinate.
* @method
* @param a - The client coordinate
* @returns The scaled number
* @example
* const scaledToGrid = renderer.scale(5);
*/
Renderer.prototype.scale = function (a) {
return a * this.gridSize;
};
/**
* Combines given draw settings with default draw settings.
* @method
* @param drawSettings - The given draw settings
* @returns The combined draw settings
* @example
* const drawSettings = renderer.combineDrawSettings({ color: 'red' });
*/
Renderer.prototype.combineDrawSettings = function (drawSettings) {
return __assign(__assign({}, DrawSettings_1.defaultDrawSettings), drawSettings);
};
/**
* Sets canvas context properties to given settings.
* @param drawSettings - The draw settings
*/
Renderer.prototype.setContextSettings = function (drawSettings) {
var _a, _b, _c, _d;
if (drawSettings.color !== undefined)
this.ctx.fillStyle = drawSettings.color;
if (drawSettings.borderColor !== undefined)
this.ctx.strokeStyle = drawSettings.borderColor;
if (drawSettings.borderSize !== undefined)
this.ctx.lineWidth = this.scale(drawSettings.borderSize / 64);
if (drawSettings.alpha !== undefined)
this.ctx.globalAlpha = (0, MathUtils_1.Clamp01)(drawSettings.alpha);
if (((_a = drawSettings.shadow) === null || _a === void 0 ? void 0 : _a.color) !== undefined)
this.ctx.shadowColor = drawSettings.shadow.color;
if (((_b = drawSettings.shadow) === null || _b === void 0 ? void 0 : _b.offsetX) !== undefined)
this.ctx.shadowOffsetX = this.scale(drawSettings.shadow.offsetX);
if (((_c = drawSettings.shadow) === null || _c === void 0 ? void 0 : _c.offsetY) !== undefined)
this.ctx.shadowOffsetY = this.scale(drawSettings.shadow.offsetY);
if (((_d = drawSettings.shadow) === null || _d === void 0 ? void 0 : _d.blur) !== undefined)
this.ctx.shadowBlur = this.scale(drawSettings.shadow.blur);
};
/**
* Draws a rect.
* @method
* @param worldX - The X-coordinate
* @param worldY - The Y-coordinate
* @param worldWidth - The width
* @param worldHeight - The height
* @param drawSettings - The draw settings
* @example
* renderer.drawRectangle(5, 2, 1, 1, { color: 'green', border: true });
*/
Renderer.prototype.drawRectangle = function (worldX, worldY, worldWidth, worldHeight, drawSettings) {
drawSettings = this.combineDrawSettings(drawSettings);
var dx = this.scale(worldX - this.handler.canvasViewOffset.x);
var dy = this.scale(worldY - this.handler.canvasViewOffset.y);
var dw = this.scale(worldWidth);
var dh = this.scale(worldHeight);
this.ctx.save();
this.ctx.translate(dx + dw / 2, dy + dh / 2);
if (drawSettings.angle !== undefined) {
if (drawSettings.rotationStyle === RotationStyle_1.RotationStyle.allAround) {
this.ctx.rotate(Rotation_1.Rotation.ToRadians(drawSettings.angle));
}
}
this.ctx.translate(-dx - dw / 2, -dy - dh / 2);
this.setContextSettings(drawSettings);
//
if (drawSettings.fill)
this.ctx.fillRect(dx, dy, dw, dh);
if (drawSettings.border)
this.ctx.strokeRect(dx, dy, dw, dh);
//
this.ctx.restore();
};
/**
* Draws a circle.
* @method
* @param worldX - The X-coordinate
* @param worldY - The Y-coordinate
* @param diameter - The diameter
* @param drawSettings - The draw settings
* @example
* renderer.drawCircle(0, 0, 1, { color: 'yellow' });
*/
Renderer.prototype.drawCircle = function (worldX, worldY, diameter, drawSettings) {
drawSettings = this.combineDrawSettings(drawSettings);
var dx = this.scale(worldX - this.handler.canvasViewOffset.x);
var dy = this.scale(worldY - this.handler.canvasViewOffset.y);
var dr = this.scale(diameter / 2);
this.setContextSettings(drawSettings);
//
this.ctx.beginPath();
this.ctx.arc(dx + dr, dy + dr, dr, 0, 2 * Math.PI);
this.ctx.closePath();
if (drawSettings.fill)
this.ctx.fill();
if (drawSettings.border)
this.ctx.stroke();
};
/**
* Draws line from position to another position.
* @method
* @param fromWorldX - From X-coordinate
* @param fromWorldY - From Y-coordinate
* @param toWorldX - To X-coordinate
* @param toWorldY - To Y-coordinate
* @param drawSettings - The draw settings
* @example
* renderer.drawLine(2, 3, 3, 4);
*/
Renderer.prototype.drawLine = function (fromWorldX, fromWorldY, toWorldX, toWorldY, drawSettings) {
drawSettings = this.combineDrawSettings(drawSettings);
this.setContextSettings(drawSettings);
this.ctx.beginPath();
this.ctx.moveTo(this.scale(fromWorldX - this.handler.canvasViewOffset.x), this.scale(fromWorldY - this.handler.canvasViewOffset.y));
this.ctx.lineTo(this.scale(toWorldX - this.handler.canvasViewOffset.x), this.scale(toWorldY - this.handler.canvasViewOffset.y));
this.ctx.closePath();
this.ctx.stroke();
};
/**
* Draws arrow from position to another position.
* @method
* @param fromWorldX - From X-coordinate
* @param fromWorldY - From Y-coordinate
* @param toWorldX - To X-coordinate
* @param toWorldY - To Y-coordinate
* @param drawSettings - The draw settings
* @example
* renderer.drawArrow(2, 3, 3, 4);
*/
Renderer.prototype.drawArrow = function (fromWorldX, fromWorldY, toWorldX, toWorldY, drawSettings) {
drawSettings = this.combineDrawSettings(drawSettings);
// Scaling
var size = this.gridSize / 16;
this.ctx.lineWidth = this.gridSize / 64;
this.setContextSettings(drawSettings);
var p1 = new Vector2_1.Vector2((fromWorldX - this.handler.canvasViewOffset.x) * this.gridSize, (fromWorldY - this.handler.canvasViewOffset.y) * this.gridSize);
var p2 = new Vector2_1.Vector2((toWorldX - this.handler.canvasViewOffset.x) * this.gridSize, (toWorldY - this.handler.canvasViewOffset.y) * this.gridSize);
// Angle
var angle = Math.atan2(p2.y - p1.y, p2.x - p1.x);
var hyp = Math.sqrt((p2.x - p1.x) * (p2.x - p1.x) + (p2.y - p1.y) * (p2.y - p1.y));
// Rotate
this.ctx.save();
this.ctx.translate(p1.x, p1.y);
this.ctx.rotate(angle);
// Line
this.ctx.beginPath();
this.ctx.moveTo(0, 0);
this.ctx.lineTo(hyp - size, 0);
this.ctx.closePath();
this.ctx.stroke();
// Triangle
this.ctx.beginPath();
this.ctx.lineTo(hyp - size, size);
this.ctx.lineTo(hyp, 0);
this.ctx.lineTo(hyp - size, -size);
this.ctx.closePath();
this.ctx.fill();
this.ctx.restore();
};
/**
* Clears the canvas.
* @method
* @example
* renderer.clearFrame();
*/
Renderer.prototype.clearFrame = function () {
this.ctx.clearRect(0, 0, this.canvasWidth, this.canvasHeight);
};
/**
* Fills the canvas with color property from settings.
* @param drawSettings - The settings
* @deprecated
*/
Renderer.prototype.fillFrame = function (drawSettings) {
drawSettings = this.combineDrawSettings(drawSettings);
this.setContextSettings(drawSettings);
this.ctx.fillRect(0, 0, this.canvasWidth, this.canvasHeight);
};
/**
* Fills canvas with image.
* @param image - The image
* @deprecated
*/
Renderer.prototype.fillImageFrame = function (image) {
this.ctx.drawImage(image, 0, 0, this.canvasWidth, this.canvasHeight);
};
/**
* Fills canvas with content.
* @method
* @param content - The color, image or {@link DrawSettings}
* @example
* renderer.fill('white');
* renderer.fill({ color: 'white' })
* renderer.fill(game.GetImage('background'));
*/
Renderer.prototype.fill = function (content) {
if (content instanceof HTMLCanvasElement) {
this.setContextSettings(DrawSettings_1.defaultDrawSettings);
this.ctx.drawImage(content, 0, 0, this.canvasWidth, this.canvasHeight);
return;
}
else if (typeof content === 'string') {
this.setContextSettings(this.combineDrawSettings({ color: content }));
}
else {
this.setContextSettings(this.combineDrawSettings(content));
}
this.ctx.fillRect(0, 0, this.canvasWidth, this.canvasHeight);
};
/**
* Draws image.
* @method
* @param image - The image
* @param worldX - The X-coordinate
* @param worldY - The Y-coordinate
* @param worldWidth - The width
* @param worldHeight - The height
* @param drawSettings - The draw settings
* @example
* renderer.drawImage(game.GetImage('player'), 0, 0, 1, 1, { angle: 45 });
*/
Renderer.prototype.drawImage = function (image, worldX, worldY, worldWidth, worldHeight, drawSettings) {
drawSettings = this.combineDrawSettings(drawSettings);
var dx = this.scale(worldX - this.handler.canvasViewOffset.x);
var dy = this.scale(worldY - this.handler.canvasViewOffset.y);
var dw = this.scale(worldWidth);
var dh = this.scale(worldHeight);
this.ctx.save();
this.ctx.translate(dx + dw / 2, dy + dh / 2);
if (drawSettings.angle !== undefined) {
if (drawSettings.rotationStyle === RotationStyle_1.RotationStyle.allAround) {
this.ctx.rotate(Rotation_1.Rotation.ToRadians(drawSettings.angle));
}
}
this.ctx.translate(-dx - dw / 2, -dy - dh / 2);
this.ctx.drawImage(image, dx, dy, dw, dh);
this.ctx.restore();
};
/**
* Draws sprite texture.
* @method
* @param sprite - The sprite
* @returns is success?
* @example
* const exampleSprite = ...;
* renderer.drawSprite(exampleSprite);
*/
Renderer.prototype.drawSprite = function (sprite) {
if (sprite.texture === undefined || sprite.texture === null) {
console.warn('The Sprite ', sprite, ' has not assigned texture!');
return false;
}
if (!(sprite.texture instanceof HTMLImageElement)) {
console.warn("Texture ".concat(sprite.name, "[").concat(sprite.id, "] cannot be ").concat(typeof sprite.texture, "!"));
return false;
}
this.drawImage(sprite.texture, sprite.transform.position.x, sprite.transform.position.y, sprite.transform.scale.x, sprite.transform.scale.y, {
angle: sprite.transform.eulerAngles,
rotationStyle: sprite.rotationStyle,
});
return true;
};
/**
* Draws hitbox with direction arrow.
* @method
* @param clickableObject - The clickable game object
* @example
* const exampleClickableObject = ...;
* renderer.drawHitbox(exampleClickableObject);
*/
Renderer.prototype.drawHitbox = function (clickableObject) {
if (!clickableObject.showHitbox)
return;
var pos = clickableObject.transform.position;
var center = clickableObject.transform.positionCenter;
var scale = clickableObject.transform.scale;
this.drawRectangle(pos.x, pos.y, scale.x, scale.y, {
borderColor: 'red',
fill: false,
border: true,
});
this.drawLine(pos.x, pos.y, pos.x + scale.x, pos.y + scale.y, {
borderColor: 'red',
});
this.drawLine(pos.x + scale.x, pos.y, pos.x, pos.y + scale.y, {
borderColor: 'red',
});
var angle = Rotation_1.Rotation.ToRadians(clickableObject.transform.eulerAngles);
this.drawArrow(center.x, center.y, center.x + (scale.x / 2) * Math.cos(angle), center.y + (scale.y / 2) * Math.sin(angle), { color: 'red', borderColor: 'red' });
};
return Renderer;
}());
exports.Renderer = Renderer;