This commit is contained in:
Mal 2020-01-19 00:45:17 +01:00
commit 893c226fe4
10 changed files with 541 additions and 0 deletions

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
.idea
test*

18
index.html Normal file
View File

@ -0,0 +1,18 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Mr. Crocs Adventures</title>
<style>
#canvas {
position: absolute;
top: 0;
left: 0;
}
</style>
<script type="module" src="js/module.js"></script>
</head>
<body>
<canvas id="canvas"></canvas>
</body>
</html>

View File

@ -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;
}
}

View File

@ -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();
}
}

View File

@ -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();
}
}

View File

@ -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);
}
}

230
js/geometry/GeometryRect.js Normal file
View File

@ -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);
}
}

View File

@ -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);
}
}

17
js/module.js Normal file
View File

@ -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);
};

51
js/retro/RetroSprite.js Normal file
View File

@ -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);
}
}
}
}