<canvas class="game-area__ctx" width="500px" height="600px" style="border: 1px solid black;"></canvas>
const canvas = document.querySelector(".game-area__ctx");
const ctx = canvas.getContext("2d");
const gridCheckbox = document.querySelector("input[id=toggleGrid]");
let activeElement;
let gameObj;
let walls;
localStorage.setItem(
"level-1",
`{"walls":[{"x":82,"y":70,"w":1,"h":20,"id":1,"hide":0,"active":0,"bern":[0,0,1,0],"thru":[0,0,0,0]},{"x":10,"y":31,"w":31,"h":1,"id":2,"hide":0,"active":0,"bern":[0,1,0,1],"thru":[0,0,0,0]},{"x":61,"y":103,"w":1,"h":10,"id":3,"hide":0,"active":0,"bern":[0,0,0,0],"thru":[1,1,1,0]},{"x":9,"y":8,"w":1,"h":24,"id":4,"hide":0,"active":0,"bern":[0,0,0,0],"thru":[0,0,0,0]},{"x":35,"y":47,"w":1,"h":21,"id":5,"hide":0,"active":0,"bern":[0,1,1,0],"thru":[0,1,1,0]},{"x":9,"y":39,"w":1,"h":28,"id":6,"hide":0,"active":0,"bern":[1,0,0,1],"thru":[0,1,1,0]},{"x":10,"y":39,"w":15,"h":1,"id":7,"hide":0,"active":1,"bern":[0,0,1,1],"thru":[1,0,1,0]},{"x":40,"y":32,"w":1,"h":15,"id":8,"hide":0,"active":0,"bern":[0,0,0,0],"thru":[0,0,0,0]},{"x":9,"y":67,"w":20,"h":1,"id":9,"hide":0,"active":0,"bern":[0,0,0,0],"thru":[0,0,0,0]},{"x":24,"y":40,"w":1,"h":7,"id":10,"hide":0,"active":0,"bern":[0,0,0,0],"thru":[0,0,0,0]},{"x":95,"y":112,"w":5,"h":1,"id":11,"hide":0,"active":0,"bern":[0,0,0,0],"thru":[0,0,0,0]},{"x":36,"y":47,"w":5,"h":1,"id":12,"hide":0,"active":0,"bern":[0,0,0,0],"thru":[0,0,0,0]},{"x":48,"y":67,"w":1,"h":15,"id":13,"hide":0,"active":0,"bern":[0,0,0,0],"thru":[0,0,0,0]},{"x":61,"y":95,"w":12,"h":1,"id":14,"hide":0,"active":0,"bern":[0,0,0,0],"thru":[0,0,0,0]},{"x":41,"y":90,"w":1,"h":14,"id":15,"hide":0,"active":0,"bern":[0,0,0,0],"thru":[0,0,0,0]},{"x":60,"y":82,"w":1,"h":14,"id":16,"hide":0,"active":0,"bern":[0,0,0,0],"thru":[0,0,0,0]},{"x":9,"y":112,"w":77,"h":1,"id":17,"hide":0,"active":0,"bern":[0,0,0,0],"thru":[0,0,0,0]},{"x":36,"y":67,"w":12,"h":1,"id":18,"hide":0,"active":0,"bern":[0,0,0,0],"thru":[0,0,0,0]},{"x":0,"y":104,"w":52,"h":1,"id":19,"hide":0,"active":0,"bern":[0,0,0,0],"thru":[0,0,0,0]},{"x":85,"y":103,"w":1,"h":9,"id":20,"hide":0,"active":0,"bern":[0,0,0,0],"thru":[0,0,0,0]},{"x":49,"y":81,"w":12,"h":1,"id":21,"hide":0,"active":0,"bern":[0,0,0,0],"thru":[0,0,0,0]},{"x":29,"y":80,"w":1,"h":10,"id":22,"hide":0,"active":0,"bern":[0,0,0,0],"thru":[0,0,0,0]},{"x":29,"y":90,"w":12,"h":1,"id":23,"hide":0,"active":0,"bern":[0,0,0,0],"thru":[0,0,0,0]},{"x":0,"y":79,"w":30,"h":1,"id":24,"hide":0,"active":0,"bern":[0,0,0,0],"thru":[0,0,0,0]},{"x":29,"y":47,"w":1,"h":21,"id":25,"hide":0,"active":0,"bern":[0,0,0,0],"thru":[0,0,0,0]},{"x":74,"y":90,"w":9,"h":1,"id":26,"hide":0,"active":0,"bern":[0,0,0,0],"thru":[0,0,0,0]},{"x":24,"y":47,"w":5,"h":1,"id":27,"hide":0,"active":0,"bern":[0,0,0,0],"thru":[0,0,0,0]},{"x":90,"y":33,"w":1,"h":70,"id":28,"hide":0,"active":0,"bern":[0,0,0,0],"thru":[0,0,0,0]},{"x":73,"y":90,"w":1,"h":15,"id":29,"hide":0,"active":0,"bern":[0,0,0,0],"thru":[0,0,0,0]},{"x":85,"y":102,"w":5,"h":1,"id":30,"hide":0,"active":0,"bern":[0,0,0,0],"thru":[0,0,0,0]}]}`
);
const selectedLevel = JSON.parse(localStorage.getItem("level-1"));
const gridSettings = {
squareWidth: 100,
squareHeight: 120
};
const ball = {
w: 25,
h: 25
};
const w = canvas.width;
const h = canvas.height;
const getXPixelRatio = canvas.width / gridSettings.squareWidth;
const getYPixelRatio = canvas.height / gridSettings.squareHeight;
const xCoordsToPixels = (coords) => coords * getXPixelRatio;
const yCoordsToPixels = (coords) => coords * getYPixelRatio;
const renderGrid = () => {
ctx.beginPath();
ctx.strokeStyle = "#bdbdbd";
ctx.lineWidth = 0.3;
for (let x = getXPixelRatio; x < w; x += getXPixelRatio)
ctx.strokeRect(x, 0, 0.1, h);
for (let y = getYPixelRatio; y < h; y += getYPixelRatio)
ctx.strokeRect(0, y, w, 0.1);
ctx.fill();
ctx.closePath();
};
const loadLevels = () => {
gameObj = JSON.parse(localStorage.getItem(`level-1`));
if (!gameObj) return;
walls = gameObj.walls;
};
const drawElement = (element) => {
let fillColor = "#2c8fdb";
ctx.beginPath();
ctx.rect(
xCoordsToPixels(element.x),
yCoordsToPixels(element.y),
xCoordsToPixels(element.w),
yCoordsToPixels(element.h)
);
ctx.fillStyle = element.color || "black";
ctx.fill();
ctx.closePath();
};
const drawRect = (x = 0, y = 0) => {
ctx.fillStyle = "black";
ctx.fillRect(x, y, ball.w, ball.h);
};
function edge(c, min, max) {
return Math.max(min, Math.min(max, c));
}
// https://stackoverflow.com/questions/4977491/determining-if-two-line-segments-intersect/4977569#4977569
// returns true iff the line from (a,b)->(c,d) intersects with (p,q)->(r,s)
function lineLineIntersects(a, b, c, d, p, q, r, s) {
var det, gamma, lambda;
det = (c - a) * (s - q) - (r - p) * (d - b);
if (det === 0) {
return false;
} else {
lambda = ((s - q) * (r - a) + (p - r) * (s - b)) / det;
gamma = ((b - d) * (r - a) + (c - a) * (s - b)) / det;
return 0 < lambda && lambda < 1 && 0 < gamma && gamma < 1;
}
}
function intersectBallWall(targetPos, currPos, ball, wall) {
const isBallCantMove = lineLineIntersects(
targetPos.x, targetPos.y,
currPos.x, currPos.y,
getXPixelRatio * wall.x, getXPixelRatio * wall.y,
getYPixelRatio * (wall.x + wall.w), getYPixelRatio * (wall.y + wall.h)
);
const isTouchWall = !(
getXPixelRatio * wall.x >= targetPos.x + ball.w ||
getXPixelRatio * (wall.x + wall.w) <= targetPos.x ||
getYPixelRatio * wall.y >= targetPos.y + ball.h ||
getYPixelRatio * (wall.y + wall.h) <= targetPos.y
);
return isTouchWall || isBallCantMove;
}
const rectPos = { x: 0, y: 0 };
const currPos = { x: 0, y: 0 };
const mouseEvent = () => {
canvas.onmousedown = (e) => {
const start = { x: e.offsetX, y: e.offsetY };
canvas.onmousemove = (e) => {
const targetPos = {
x: getXPixelRatio * Math.round((rectPos.x + e.offsetX - start.x) / getXPixelRatio),
y: getYPixelRatio * Math.round((rectPos.y + e.offsetY - start.y) / getYPixelRatio)
}
if (walls.some((wall) => intersectBallWall(targetPos, currPos, ball, wall))) {
return;
}
currPos.x = edge(targetPos.x, 0, w - 25);
currPos.y = edge(targetPos.y, 0, h - 25);
renderAll();
drawRect(currPos.x, currPos.y);
};
document.onmouseup = (e) => {
rectPos.x = currPos.x;
rectPos.y = currPos.y;
canvas.onmousemove = null;
};
};
};
const renderWalls = () => {
walls.forEach((e) => drawElement(e));
};
const renderAll = () => {
ctx.clearRect(0, 0, w, h);
mouseEvent();
renderGrid();
renderWalls();
};
window.addEventListener("DOMContentLoaded", () => {
loadLevels();
renderAll();
drawRect();
});
This Pen doesn't use any external CSS resources.
This Pen doesn't use any external JavaScript resources.