From 893c226fe4d64b47c0fdbaf8ed8cbdb8a18fdce5 Mon Sep 17 00:00:00 2001 From: Mal Date: Sun, 19 Jan 2020 00:45:17 +0100 Subject: [PATCH] Init --- .gitignore | 2 + index.html | 18 ++ js/geometry/GeometryCircle.js | 20 +++ js/geometry/GeometryLine.js | 55 ++++++ js/geometry/GeometryPoint.js | 30 ++++ js/geometry/GeometryPointCollection.js | 68 ++++++++ js/geometry/GeometryRect.js | 230 +++++++++++++++++++++++++ js/geometry/GeometryStroke.js | 50 ++++++ js/module.js | 17 ++ js/retro/RetroSprite.js | 51 ++++++ 10 files changed, 541 insertions(+) create mode 100644 .gitignore create mode 100644 index.html create mode 100644 js/geometry/GeometryCircle.js create mode 100644 js/geometry/GeometryLine.js create mode 100644 js/geometry/GeometryPoint.js create mode 100644 js/geometry/GeometryPointCollection.js create mode 100644 js/geometry/GeometryRect.js create mode 100644 js/geometry/GeometryStroke.js create mode 100644 js/module.js create mode 100644 js/retro/RetroSprite.js diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8e76864 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +.idea +test* diff --git a/index.html b/index.html new file mode 100644 index 0000000..f22181e --- /dev/null +++ b/index.html @@ -0,0 +1,18 @@ + + + + + Mr. Crocs Adventures + + + + + + + \ No newline at end of file diff --git a/js/geometry/GeometryCircle.js b/js/geometry/GeometryCircle.js new file mode 100644 index 0000000..ced408e --- /dev/null +++ b/js/geometry/GeometryCircle.js @@ -0,0 +1,20 @@ +import GeometryPoint from "./GeometryPoint.js"; + +export default class GeometryCircle +{ + constructor(x, y, radius) + { + this.position = new GeometryPoint(x, y); + this.radius = radius; + } + + getDistanceToCircle(circle) + { + return this.position.getDistanceToPoint(circle.position); + } + + hasIntersectionWithCircle(circle) + { + return this.getDistanceToCircle(circle) <= this.radius + circle.radius; + } +} \ No newline at end of file diff --git a/js/geometry/GeometryLine.js b/js/geometry/GeometryLine.js new file mode 100644 index 0000000..cdedf46 --- /dev/null +++ b/js/geometry/GeometryLine.js @@ -0,0 +1,55 @@ +import GeometryPoint from "./GeometryPoint.js"; +import GeometryStroke from "./GeometryStroke.js"; + +export default class GeometryLine +{ + constructor(pointA, pointB) + { + this.pointA = pointA; + this.pointB = pointB; + } + + getIntersectionWithLine(line) + { + try { + let xa = (line.pointB.x - line.pointA.x) * (this.pointB.x * this.pointA.y - this.pointA.x * this.pointB.y); + let xb = (this.pointB.x - this.pointA.x) * (line.pointB.x * line.pointA.y - line.pointA.x * line.pointB.y); + let xc = (line.pointB.y - line.pointA.y) * (this.pointB.x - this.pointA.x); + let xd = (this.pointB.y - this.pointA.y) * (line.pointB.x - line.pointA.x); + + let x = (xa - xb) / (xc - xd); + + if (isNaN(x)) { + return null; + } + + let ya = (this.pointA.y - this.pointB.y) *(line.pointB.x * line.pointA.y - line.pointA.x * line.pointB.y); + let yb = (line.pointA.y - line.pointB.y) *(this.pointB.x * this.pointA.y - this.pointA.x * this.pointB.y); + let yc = (line.pointB.y - line.pointA.y) * (this.pointB.x - this.pointA.x); + let yd = (this.pointB.y - this.pointA.y) * (line.pointB.x - line.pointA.x); + + let y = (ya - yb) / (yc - yd); + + if (isNaN(y)) { + return null; + } + + return new GeometryPoint(x, y); + } catch (error) { + return null; + } + } + + getStroke() + { + return new GeometryStroke(this.pointA, this.pointB); + } + + draw(context) + { + context.beginPath(); + context.moveTo(this.pointA.x, this.pointA.y); + context.lineTo(this.pointB.x, this.pointB.y); + context.stroke(); + } +} \ No newline at end of file diff --git a/js/geometry/GeometryPoint.js b/js/geometry/GeometryPoint.js new file mode 100644 index 0000000..bcbb722 --- /dev/null +++ b/js/geometry/GeometryPoint.js @@ -0,0 +1,30 @@ +export default class GeometryPoint +{ + constructor(x, y) + { + this.x = x; + this.y = y; + } + + isEqual(geometryPoint) + { + return this.x === geometryPoint.x && this.y === geometryPoint.y; + } + + getDistanceToPoint(geometryPoint) + { + return Math.sqrt(Math.pow(geometryPoint.x - this.x,2) + Math.pow(geometryPoint.y - this.y,2)); + } + + getAngleToPoint(geometryPoint) + { + return Math.atan2(this.y - geometryPoint.y, this.x - geometryPoint.x); + } + + draw(context) + { + context.beginPath(); + context.arc(this.x, this.y, 3, 0, 2 * Math.PI); + context.stroke(); + } +} \ No newline at end of file diff --git a/js/geometry/GeometryPointCollection.js b/js/geometry/GeometryPointCollection.js new file mode 100644 index 0000000..025a3ce --- /dev/null +++ b/js/geometry/GeometryPointCollection.js @@ -0,0 +1,68 @@ +import GeometryRect from "./GeometryRect.js"; + +export default class GeometryPointCollection +{ + constructor() + { + this.points = []; + } + + addGeometryPoint(geometryPoint) + { + if (!this.isContainingPoint(geometryPoint)) { + this.points.push(geometryPoint); + } + } + + isContainingPoint(geometryPoint) + { + for (let p = 0; p < this.points.length; p++) { + if (geometryPoint.isEqual(this.points[p])) { + return true; + } + } + + return false; + } + + getLength() + { + return this.points.length; + } + + getPoint(index) + { + return this.points[index]; + } + + forEach(callback) + { + this.points.forEach(callback); + } + + sort() + { + this.points.sort( + function (a, b) { + return a.x > b.x || a.y > b.y; + } + ) + } + + getRect() + { + if (this.getLength() < 2) { + console.log('GeometryPointCollection.getRect(): Collection must contain at least 2 points!'); + return null; + } + + this.sort(); + + let positionTopLeft = this.getPoint(0); + let positionBottomRight = this.getPoint(this.getLength() - 1); + let width = positionBottomRight.x - positionTopLeft.x; + let height = positionBottomRight.y - positionTopLeft.y; + + return new GeometryRect(positionTopLeft.x, positionTopLeft.y, width, height); + } +} \ No newline at end of file diff --git a/js/geometry/GeometryRect.js b/js/geometry/GeometryRect.js new file mode 100644 index 0000000..7f73865 --- /dev/null +++ b/js/geometry/GeometryRect.js @@ -0,0 +1,230 @@ +import GeometryPoint from "./GeometryPoint.js"; +import GeometryStroke from "./GeometryStroke.js"; +import GeometryPointCollection from "./GeometryPointCollection.js"; + +export default class GeometryRect +{ + /** + * @param x: float + * @param y: float + * @param width: float + * @param height: float + */ + constructor(x, y, width, height) + { + this.position = new GeometryPoint(x, y); + this.width = width; + this.height = height; + } + + /** + * Returns if the given point is inside this rect. + * + * @param geometryPoint + * @returns {boolean|boolean} + */ + isContainingPoint(geometryPoint) + { + let containsHorizontally = geometryPoint.x >= this.position.x && geometryPoint.x <= this.position.x + this.width; + let containsVertically = geometryPoint.y >= this.position.y && geometryPoint.y <= this.position.y + this.height; + + return containsHorizontally && containsVertically; + } + + getBorderTop() + { + return new GeometryStroke( + new GeometryPoint(this.position.x, this.position.y), + new GeometryPoint(this.position.x + this.width, this.position.y) + ); + } + + getBorderLeft() + { + return new GeometryStroke( + new GeometryPoint(this.position.x, this.position.y), + new GeometryPoint(this.position.x, this.position.y + this.height) + ); + } + + getBorderRight() + { + return new GeometryStroke( + new GeometryPoint(this.position.x + this.width, this.position.y), + new GeometryPoint(this.position.x + this.width, this.position.y + this.height) + ); + } + + getBorderBottom() { + return new GeometryStroke( + new GeometryPoint(this.position.x, this.position.y + this.height), + new GeometryPoint(this.position.x + this.width, this.position.y + this.height) + ); + } + + /** + * Returns all intersection points between this rect and a line. + * + * @param geometryLine + * @returns {GeometryPointCollection} + */ + getBorderIntersectionsWithLine(geometryLine) + { + let borders = [ + this.getBorderTop(), + this.getBorderLeft(), + this.getBorderRight(), + this.getBorderBottom() + ]; + + let intersections = new GeometryPointCollection(); + + borders.forEach( + (border) => { + let intersection = border.getIntersectionWithLine(geometryLine); + + if (intersection !== null && this.isContainingPoint(intersection)) { + intersections.addGeometryPoint(intersection); + } + } + ); + + return intersections; + } + + getBorderIntersectionsWithStroke(stroke) + { + let borders = [ + this.getBorderTop(), + this.getBorderLeft(), + this.getBorderRight(), + this.getBorderBottom() + ]; + + let intersections = new GeometryPointCollection(); + + borders.forEach( + (border) => { + let intersection = border.getIntersectionWithStroke(stroke); + + if (intersection !== null && this.isContainingPoint(intersection)) { + intersections.addGeometryPoint(intersection); + } + } + ); + + return intersections; + } + + /** + * Get all intersections between this and another rect as point collection. + * + * @param rect GeometryRect + * @returns {GeometryPointCollection} + */ + getBorderIntersectonsWithRect(rect) + { + let intersections = new GeometryPointCollection(); + + let strokes = [ + rect.getBorderTop(), + rect.getBorderLeft(), + rect.getBorderRight(), + rect.getBorderBottom(), + + ]; + + strokes.forEach( + (stroke) => { + this.getBorderIntersectionsWithStroke(stroke).forEach( + (point) => { + intersections.addGeometryPoint(point); + } + ) + } + ); + + return intersections; + } + + /** + * Returns the four points that define the edges of this rect. + * + * @returns {GeometryPointCollection} + */ + getRectanglePoints() + { + let collection = new GeometryPointCollection(); + + collection.addGeometryPoint(this.position); + collection.addGeometryPoint(new GeometryPoint(this.position.x + this.width, this.position.y)); + collection.addGeometryPoint(new GeometryPoint(this.position.x, this.position.y + this.height)); + collection.addGeometryPoint(new GeometryPoint(this.position.x + this.width, this.position.y + this.height)); + + return collection; + } + + /** + * Returns the intersection area between this and another rect as new rect or null. + * + * @param rect GeometryRect + * @returns {null|GeometryRect} + */ + getRectIntersection(rect) + { + let intersectionPoints = new GeometryPointCollection(); + + this.getRectanglePoints().forEach( + (point) => { + if (rect.isContainingPoint(point)) { + intersectionPoints.addGeometryPoint(point); + } + } + ); + + if (intersectionPoints.getLength() >= 4) { + return intersectionPoints.getRect(); + } + + rect.getRectanglePoints().forEach( + (point) => { + if (this.isContainingPoint(point)) { + intersectionPoints.addGeometryPoint(point); + } + } + ); + + if (intersectionPoints.getLength() >= 4) { + return intersectionPoints.getRect(); + } + + this.getBorderIntersectonsWithRect(rect).forEach( + (point) => { + intersectionPoints.addGeometryPoint(point); + } + ); + + if (intersectionPoints.getLength() >= 2) { + return intersectionPoints.getRect(); + } + + return null; + } + + /** + * Visualizes the rect. + * + * @param context Context + * @param color string + */ + draw(context, color = 'red') + { + context.fillStyle = color; + context.fillRect(this.position.x, this.position.y, this.width, this.height); + this.getBorderTop().draw(context); + this.getBorderLeft().draw(context); + this.getBorderRight().draw(context); + this.getBorderBottom().draw(context); + } + +} \ No newline at end of file diff --git a/js/geometry/GeometryStroke.js b/js/geometry/GeometryStroke.js new file mode 100644 index 0000000..3316715 --- /dev/null +++ b/js/geometry/GeometryStroke.js @@ -0,0 +1,50 @@ +import GeometryLine from "./GeometryLine.js"; +import GeometryRect from "./GeometryRect.js"; + +export default class GeometryStroke extends GeometryLine +{ + getIntersectionWithLine(line) { + let intersection = super.getIntersectionWithLine(line); + + if ( + intersection === null || + !this.getRect().isContainingPoint(intersection) + ) { + return null; + } + + return intersection; + } + + getLine() + { + return new GeometryLine(this.pointA, this.pointB); + } + + getIntersectionWithStroke(stroke) + { + let intersection = super.getIntersectionWithLine(stroke); + + if ( + intersection === null || + !this.getRect().isContainingPoint(intersection) || + !stroke.getRect().isContainingPoint(intersection) + + ) { + return null; + } + + return intersection; + } + + getRect() + { + let x = Math.min(this.pointA.x, this.pointB.x); + let y = Math.min(this.pointA.y, this.pointB.y); + + let width = Math.max(this.pointA.x, this.pointB.x) - x; + let height = Math.max(this.pointA.y, this.pointB.y) - y; + + return new GeometryRect(x, y, width, height); + } +} \ No newline at end of file diff --git a/js/module.js b/js/module.js new file mode 100644 index 0000000..be35390 --- /dev/null +++ b/js/module.js @@ -0,0 +1,17 @@ +import RetroSprite from "./retro/RetroSprite.js"; + +let image = new Image(); +image.src = 'graphics/mario.png'; + +image.onload = function () { + let sprite = new RetroSprite(image, 10); + let canvas = document.getElementById('canvas'); + canvas.width = window.innerWidth; + canvas.height = window.innerHeight; + + let context = canvas.getContext('2d'); + + console.log(context); + + sprite.draw(context); +}; \ No newline at end of file diff --git a/js/retro/RetroSprite.js b/js/retro/RetroSprite.js new file mode 100644 index 0000000..f953ec3 --- /dev/null +++ b/js/retro/RetroSprite.js @@ -0,0 +1,51 @@ +import GeometryPoint from "../geometry/GeometryPoint.js"; + +export default class RetroSprite +{ + constructor(image, scale = 1) + { + this.image = image; + this.canvas = document.createElement('canvas'); + this.context = this.canvas.getContext('2d'); + this.position = new GeometryPoint(); + this.scale = scale; + + this.render(); + } + + draw(context) + { + context.drawImage(this.canvas, this.position.x, this.position.y); + } + + hasRectCollisionWith(sprite) + { + + } + + hasCollisionWith(sprite) + { + + } + + render() + { + let canvasTemp = document.createElement('canvas'); + let contextTemp = canvasTemp.getContext('2d'); + contextTemp.drawImage(this.image, 0, 0); + + this.canvas.width = this.image.width * this.scale; + this.canvas.height = this.image.height * this.scale; + + this.context.clearRect(0, 0, this.image.width * this.scale, this.image.height * this.scale); + + for (let y = 0; y < this.image.height; y++) { + for (let x = 0; x < this.image.width; x++) { + let pixel = contextTemp.getImageData(x, y, 1, 1).data; + this.context.globalAlpha = pixel[3] / 255; + this.context.fillStyle = 'rgb(' + pixel[0] + ',' + pixel[1] + ',' + pixel[2] + ')'; + this.context.fillRect(x * this.scale, y * this.scale, this.scale, this.scale); + } + } + } +} \ No newline at end of file