Skip to content

Commit

Permalink
Added the resize and setPosition methods on Layer (#2)
Browse files Browse the repository at this point in the history
  • Loading branch information
Zack Therrien authored Apr 19, 2020
1 parent 5836b46 commit f2e723a
Show file tree
Hide file tree
Showing 7 changed files with 149 additions and 36 deletions.
6 changes: 3 additions & 3 deletions examples/bouncing-square/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,9 @@ class Square implements IEntity {
this.dy = 1;
}

isXOutOfBounds = () => this.x < 0 || (this.x + SQUARE_WIDTH) > this.layer.width;
isXOutOfBounds = () => this.x < 0 || (this.x + SQUARE_WIDTH) > this.layer.getWidth();

isYOutOfBounds = () => this.y < 0 || (this.y + SQUARE_HEIGHT) > this.layer.height;
isYOutOfBounds = () => this.y < 0 || (this.y + SQUARE_HEIGHT) > this.layer.getHeight();

update(deltaTime: number) {
const dist = SQUARE_SPEED * deltaTime;
Expand All @@ -79,7 +79,7 @@ const engine = new Engine();

// Create the background layer
const backgroundLayer = new RenderingLayer(LayerIndex.BACKGROUND, LayerType.STATIC);
const backgroundEntity = new Background(backgroundLayer.width, backgroundLayer.height);
const backgroundEntity = new Background(backgroundLayer.getWidth(), backgroundLayer.getHeight());
backgroundLayer.addEntity(backgroundEntity);

// Register the layer background.
Expand Down
1 change: 1 addition & 0 deletions examples/pacman/entities/animal.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { IEntity, IRenderingLayer } from '../../../src';

// Dog and Cat image from: https://www.petbacker.com/blog/how-to/tips-on-how-to-make-a-dog-and-cat-become-friends
import * as DogCatCoveryJpg from '../dog-and-cat-cover.jpg';

import IManager from './manager';
Expand Down
4 changes: 2 additions & 2 deletions examples/pacman/entities/pacman.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ export default class PacMan implements IEntity {
this.animalManager = animalManager;

this.radius = BODY_RADIUS;
this.x = layer.width/2;
this.x = layer.getWidth()/2 + layer.getX(); // center in the layer.
this.y = pCy;
this.orientation = 'left';

Expand All @@ -62,7 +62,7 @@ export default class PacMan implements IEntity {
this.eyeCYdelta = 50 * Math.sin(0.3*Math.PI);
}

isOutOfBounds = (x: number) => (x + this.radius) > this.layer.width || (x - this.radius) < 0;
isOutOfBounds = (x: number) => (x + this.radius) > this.layer.getWidth() || (x - this.radius) < this.layer.getX();

changeDirection(directionKey: 'left' | 'right') {
if(directionKey === 'left') {
Expand Down
4 changes: 2 additions & 2 deletions examples/pacman/entities/score.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ export default class Score implements IEntity {

constructor(layer: IRenderingLayer) {
this.layer = layer;
this.width = layer.width;
this.height = layer.height;
this.width = layer.getWidth();
this.height = layer.getHeight();

this.score = 0;
}
Expand Down
2 changes: 1 addition & 1 deletion examples/pacman/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ const animalManager = new Manager<Animal>();

// Create the background layer
const backgroundLayer = new RenderingLayer(LayerIndex.BACKGROUND, LayerType.STATIC);
const backgroundEntity = new Background(backgroundLayer.width, backgroundLayer.height);
const backgroundEntity = new Background(backgroundLayer.getWidth(), backgroundLayer.getHeight());
backgroundLayer.addEntity(backgroundEntity);

// Register the layer background.
Expand Down
158 changes: 130 additions & 28 deletions src/RenderingLayer/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { LayerType, IEntity, LayerIndex, RenderLayerFunction, UpdateLayerFunction } from '../types';
import { LayerType, IEntity, LayerIndex, RenderLayerFunction, UpdateLayerFunction, ResizeMethod } from '../types';

/**
* An interface of all necessary functions and properties a rendering layer must have.
Expand All @@ -14,16 +14,6 @@ export interface IRenderingLayer {
*/
readonly layerType: LayerType;

/**
* Width of the document.
*/
readonly width: number;

/**
* Height of the document
*/
readonly height: number;

/**
* Render all entities in this layer to the context.
*/
Expand All @@ -39,6 +29,31 @@ export interface IRenderingLayer {
*/
getContext: () => CanvasRenderingContext2D;

/**
* Get the width of the layer
*/
getWidth: () => number;

/**
* Get the height of the layer
*/
getHeight: () => number;

/**
* Get the x position of the layer
*/
getX: () => number;

/**
* Get the y position of the layer
*/
getY: () => number;

/**
* Resize the layer
*/
resize: (width: number, height: number, resizeMethod: ResizeMethod) => void;

/**
* Add a new entity to this rendering layer
* @param entity New entity to be added
Expand Down Expand Up @@ -69,14 +84,24 @@ export class RenderingLayer implements IRenderingLayer {
readonly context: CanvasRenderingContext2D;

/**
* Width of the document.
* Width of the layer in the document
*/
private width: number;

/**
* Height of the layer in the document
*/
readonly width: number;
private height: number;

/**
* Height of the document
* X Position of the layer
*/
readonly height: number;
private x: number;

/**
* X Position of the layer
*/
private y: number;

/**
* List of entities that are part of this rendering layer.
Expand All @@ -89,34 +114,71 @@ export class RenderingLayer implements IRenderingLayer {
* @param layerType Whether the layer elements will be updated on every frame
* @param entity An optional, default first entity.
*/
constructor(layerIndex: LayerIndex, layerType: LayerType, entity?: IEntity) {
constructor(layerIndex: LayerIndex, layerType: LayerType, initialWidth?: number, initialHeight?: number, initialX: number = 0, initialY: number = 0) {
this.layerIndex = layerIndex;
this.layerType = layerType;

this.entities = [];
if (entity) {
this.addEntity(entity);
}

this.width = document.body.clientWidth + 1;
this.height = document.body.clientHeight + 1;
this.width = initialWidth === undefined ? (document.body.clientWidth + 1) : initialWidth;
this.height = initialHeight === undefined ? (document.body.clientHeight + 1) : initialHeight;
this.x = initialX;
this.y = initialY;

const canvas = document.createElement('canvas');
canvas.width = this.width;
canvas.height = this.height;
canvas.style.top = '0';
canvas.style.left = '0';
canvas.style.position = 'absolute';
canvas.style.zIndex = `${this.layerIndex}`;
canvas.style.display = 'inline';
document.body.appendChild(canvas);

const context = canvas.getContext('2d');
if (!context) {
throw new Error('Could not initialize canvas 2D context.');
}
this.context = context;
this.context.translate(-0.5, -0.5); // disables anti-aliasing
this.resize(this.width, this.height);
this.setPosition(this.x, this.y);
}

/**
* Change the size of the layer.
* @param newWidth The new width of the layer
* @param newHeight The new height of the layer
* @param resizeMethod How should we resize the layer: from the center, or from the top-left?
*/
resize(newWidth: number, newHeight: number, resizeMethod: ResizeMethod = ResizeMethod.FROM_ORIGIN) {
let xOffset = 0;
let yOffset = 0;
if(resizeMethod === ResizeMethod.FROM_CENTER) {
xOffset = (this.width - newWidth) / 2;
yOffset = (this.height - newHeight) / 2;
}

this.width = newWidth;
this.height = newHeight;

this.context.canvas.width = this.width;
this.context.canvas.height = this.height;

this.setPosition(this.x + xOffset, this.y + yOffset);
}

/**
* Change the position of this layer
* @param newX the x position where 0 is the left of the document body.
* @param newY the y position where 0 is the top of the document
*/
setPosition(newX: number, newY: number) {
this.x = newX;
this.y = newY;

if(!this._isLayerWithinBounds()) {
throw new Error('Cannot position and resize a layer outside of document body.');
}

this.context.canvas.style.left = `${this.x}px`;
this.context.canvas.style.top = `${this.y}px`;
}

/**
Expand Down Expand Up @@ -144,6 +206,34 @@ export class RenderingLayer implements IRenderingLayer {
}
}

/**
* Get the width of the layer
*/
getWidth() {
return this.width;
}

/**
* Get the height of the layer
*/
getHeight() {
return this.height;
}

/**
* Get the x position of the layer
*/
getX() {
return this.x;
}

/**
* Get the y position of the layer
*/
getY() {
return this.y;
}

/**
* Get the canvas context for this layer
*/
Expand Down Expand Up @@ -188,15 +278,27 @@ export class RenderingLayer implements IRenderingLayer {
* Returns true if the entity has a render function.
* @param entity
*/
_entityIsRenderable(entity: IEntity) {
private _entityIsRenderable(entity: IEntity) {
return Boolean(entity.render);
}

/**
* Returns true if the entity has an update function.
* @param entity
*/
_entityIsUpdatable(entity: IEntity) {
private _entityIsUpdatable(entity: IEntity) {
return Boolean(entity.update);
}

/**
* Is the layer within the document bounds.
*/
private _isLayerWithinBounds() {
return (
((this.width + this.x) > document.body.clientWidth) ||
((this.height + this.y) > document.body.clientHeight) ||
(this.x < 0) ||
(this.y < 0)
);
}
}
10 changes: 10 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,13 @@ export enum LayerType {
STATIC,
DYNAMIC,
}

/**
* Resize strategy types for the layer resize method.
* FROM_ORIGIN: will resize the layer but will also make sure the center stays at the same position
* FROM_CENTER: will resize the layer but will also make sure the top-left stays at the same position
*/
export enum ResizeMethod {
FROM_ORIGIN, // from the top left
FROM_CENTER, // from the center
}

0 comments on commit f2e723a

Please sign in to comment.