Fabric.js: cannot get bounding box to match it's (dynamic) object - javascript

I am trying to give the user of a page the possibility to draw his/her own polygon onto an image. I use fabric.js (1.5.0) for that, and I borrowed quite some code from the examples there, however, in my case, the bounding boxes of the created polygons just don't match the polygons.
FireBug shows the points of the polygons being rather local than global, what is in my believe the cause of the problem. I'm kind of lost though in finding the crucial lines...
See the jsfiddle below for my example
https://jsfiddle.net/y9kqjLhk/
Any ideas?
Thanks

i hade the same issue a few months ago, as i wanted to draw a dynamic polygon with mouse click.
i give you an example on jsfiddle that you can do exactly what you need, the only difference is that i use the previous version of fabricjs .
i hope it helps, good luck.
this is the code and below i give the live jsfiddle example:
var roof = null;
var roofPoints = [];
var lines = [];
var lineCounter = 0;
var drawingObject = {};
drawingObject.type = "";
drawingObject.background = "";
drawingObject.border = "";
function Point(x, y) {
this.x = x;
this.y = y;
}
$("#btnRoof").click(function () {
if (drawingObject.type == "roof") {
drawingObject.type = "";
lines.forEach(function(value, index, ar){
canvas.remove(value);
});
//canvas.remove(lines[lineCounter - 1]);
roof = makeRoof(roofPoints);
canvas.add(roof);
canvas.renderAll();
} else {
drawingObject.type = "roof"; // roof type
}
});
// canvas Drawing
var canvas = new fabric.Canvas('canvas',{backgroundColor : 'yellow'});
var x = 0;
var y = 0;
fabric.util.addListener(window,'dblclick', function(){
drawingObject.type = "";
lines.forEach(function(value, index, ar){
canvas.remove(value);
});
//canvas.remove(lines[lineCounter - 1]);
roof = makeRoof(roofPoints);
canvas.add(roof);
canvas.renderAll();
console.log("double click");
//clear arrays
roofPoints = [];
lines = [];
lineCounter = 0;
});
canvas.on('mouse:down', function (options) {
if (drawingObject.type == "roof") {
canvas.selection = false;
setStartingPoint(options); // set x,y
roofPoints.push(new Point(x, y));
var points = [x, y, x, y];
lines.push(new fabric.Line(points, {
strokeWidth: 1,
selectable: false,
stroke: 'red'
}).setOriginX(x).setOriginY(y));
canvas.add(lines[lineCounter]);
lineCounter++;
canvas.on('mouse:up', function (options) {
canvas.selection = true;
});
}
});
canvas.on('mouse:move', function (options) {
if (lines[0] !== null && lines[0] !== undefined && drawingObject.type == "roof") {
setStartingPoint(options);
lines[lineCounter - 1].set({
x2: x,
y2: y
});
canvas.renderAll();
}
});
function setStartingPoint(options) {
var offset = $('#canvas').offset();
x = options.e.pageX - offset.left;
y = options.e.pageY - offset.top;
}
function makeRoof(roofPoints) {
var left = findLeftPaddingForRoof(roofPoints);
var top = findTopPaddingForRoof(roofPoints);
roofPoints.push(new Point(roofPoints[0].x,roofPoints[0].y))
var roof = new fabric.Polyline(roofPoints, {
fill: 'rgba(0,0,0,0)',
stroke:'#7F7F7F'
});
roof.set({
left: left,
top: top,
});
return roof;
}
function findTopPaddingForRoof(roofPoints) {
var result = 999999;
for (var f = 0; f < lineCounter; f++) {
if (roofPoints[f].y < result) {
result = roofPoints[f].y;
}
}
return Math.abs(result);
}
function findLeftPaddingForRoof(roofPoints) {
var result = 999999;
for (var i = 0; i < lineCounter; i++) {
if (roofPoints[i].x < result) {
result = roofPoints[i].x;
}
}
return Math.abs(result);
}
jsfiddle: http://jsfiddle.net/tornado1979/svb3q6xL/1/
click on the label to start drawind and stop drawing on mouse double click, enywhere on canvas.

Related

How would I add a level system for the score increasing?

I am making a slight Tetris remake and I wanted to add a leveling system for when my score reaches, for example, 100, the speed that the blocks go down will also increase. How would I go about doing this? I have the entirety of the javascript code right here so please let me know what I can do to fix it:
//-------------------------------------------------------------------------
// base helper methods
//-------------------------------------------------------------------------
function get(id) { return document.getElementById(id); }
function hide(id) { get(id).style.visibility = 'hidden'; }
function show(id) { get(id).style.visibility = null; }
function html(id, html) { get(id).innerHTML = html; }
function timestamp() { return new Date().getTime(); }
function random(min, max) { return (min + (Math.random() * (max - min))); }
function randomChoice(choices) { return choices[Math.round(random(0, choices.length-1))]; }
if (!window.requestAnimationFrame) { // http://paulirish.com/2011/requestanimationframe-for-smart-animating/
window.requestAnimationFrame = window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.oRequestAnimationFrame ||
window.msRequestAnimationFrame ||
function(callback, element) {
window.setTimeout(callback, 1000 / 60);
}
}
//-------------------------------------------------------------------------
// game constants
//-------------------------------------------------------------------------
var KEY = { ESC: 27, SPACE: 32, LEFT: 37, UP: 38, RIGHT: 39, DOWN: 40 },
DIR = { UP: 0, RIGHT: 1, DOWN: 2, LEFT: 3, MIN: 0, MAX: 3 },
stats = new Stats(),
canvas = get('canvas'),
ctx = canvas.getContext('2d'),
ucanvas = get('upcoming'),
uctx = ucanvas.getContext('2d'),
speed = { start: 0.6, decrement: 0.005, min: 0.1 }, // how long before piece drops by 1 row (seconds)
nx = 10, // width of tetris court (in blocks)
ny = 20, // height of tetris court (in blocks)
nu = 5; // width/height of upcoming preview (in blocks)
//-------------------------------------------------------------------------
// game variables (initialized during reset)
//-------------------------------------------------------------------------
var dx, dy, // pixel size of a single tetris block
blocks, // 2 dimensional array (nx*ny) representing tetris court - either empty block or occupied by a 'piece'
actions, // queue of user actions (inputs)
playing, // true|false - game is in progress
dt, // time since starting this game
current, // the current piece
next, // the next piece
score, // the current score
vscore, // the currently displayed score (it catches up to score in small chunks - like a spinning slot machine)
rows, // number of completed rows in the current game
step; // how long before current piece drops by 1 row
//-------------------------------------------------------------------------
// tetris pieces
//
// blocks: each element represents a rotation of the piece (0, 90, 180, 270)
// each element is a 16 bit integer where the 16 bits represent
// a 4x4 set of blocks, e.g. j.blocks[0] = 0x44C0
//
// 0100 = 0x4 << 3 = 0x4000
// 0100 = 0x4 << 2 = 0x0400
// 1100 = 0xC << 1 = 0x00C0
// 0000 = 0x0 << 0 = 0x0000
// ------
// 0x44C0
//
//-------------------------------------------------------------------------
var i = { size: 4, blocks: [0x0F00, 0x2222, 0x00F0, 0x4444], color: 'cyan' };
var j = { size: 3, blocks: [0x44C0, 0x8E00, 0x6440, 0x0E20], color: 'blue' };
var l = { size: 3, blocks: [0x4460, 0x0E80, 0xC440, 0x2E00], color: 'orange' };
var o = { size: 2, blocks: [0xCC00, 0xCC00, 0xCC00, 0xCC00], color: 'yellow' };
var s = { size: 3, blocks: [0x06C0, 0x8C40, 0x6C00, 0x4620], color: 'lime' };
var t = { size: 3, blocks: [0x0E40, 0x4C40, 0x4E00, 0x4640], color: 'purple' };
var z = { size: 3, blocks: [0x0C60, 0x4C80, 0xC600, 0x2640], color: 'red' };
var p = { size: 3, blocks: [0x0F00, 0x2222, 0x00F0,], color: 'maroon' };
//------------------------------------------------
// do the bit manipulation and iterate through each
// occupied block (x,y) for a given piece
//------------------------------------------------
function eachblock(type, x, y, dir, fn) {
var bit, result, row = 0, col = 0, blocks = type.blocks[dir];
for(bit = 0x8000 ; bit > 0 ; bit = bit >> 1) {
if (blocks & bit) {
fn(x + col, y + row);
}
if (++col === 4) {
col = 0;
++row;
}
}
}
//-----------------------------------------------------
// check if a piece can fit into a position in the grid
//-----------------------------------------------------
function occupied(type, x, y, dir) {
var result = false
eachblock(type, x, y, dir, function(x, y) {
if ((x < 0) || (x >= nx) || (y < 0) || (y >= ny) || getBlock(x,y))
result = true;
});
return result;
}
function unoccupied(type, x, y, dir) {
return !occupied(type, x, y, dir);
}
//-----------------------------------------
// start with 4 instances of each piece and
// pick randomly until the 'bag is empty'
//-----------------------------------------
var pieces = [];
function randomPiece() {
if (pieces.length == 0)
pieces = [i,i,i,i,j,j,j,j,l,l,l,l,o,o,o,o,s,s,s,s,t,t,t,t,z,z,z,z,p,p,p,p];
var type = pieces.splice(random(0, pieces.length-1), 1)[0];
return { type: type, dir: DIR.UP, x: Math.round(random(0, nx - type.size)), y: 0 };
}
//-------------------------------------------------------------------------
// GAME LOOP
//-------------------------------------------------------------------------
function run() {
showStats(); // initialize FPS counter
addEvents(); // attach keydown and resize events
var last = now = timestamp();
function frame() {
now = timestamp();
update(Math.min(1, (now - last) / 1000.0)); // using requestAnimationFrame have to be able to handle large delta's caused when it 'hibernates' in a background or non-visible tab
draw();
stats.update();
last = now;
requestAnimationFrame(frame, canvas);
}
resize(); // setup all our sizing information
reset(); // reset the per-game variables
frame(); // start the first frame
}
function showStats() {
stats.domElement.id = 'stats';
get('menu').appendChild(stats.domElement);
}
function addEvents() {
document.addEventListener('keydown', keydown, false);
window.addEventListener('resize', resize, false);
}
function resize(event) {
canvas.width = canvas.clientWidth; // set canvas logical size equal to its physical size
canvas.height = canvas.clientHeight; // (ditto)
ucanvas.width = ucanvas.clientWidth;
ucanvas.height = ucanvas.clientHeight;
dx = canvas.width / nx; // pixel size of a single tetris block
dy = canvas.height / ny; // (ditto)
invalidate();
invalidateNext();
}
function keydown(ev) {
var handled = false;
if (playing) {
switch(ev.keyCode) {
case KEY.LEFT: actions.push(DIR.LEFT); handled = true; break;
case KEY.RIGHT: actions.push(DIR.RIGHT); handled = true; break;
case KEY.UP: actions.push(DIR.UP); handled = true; break;
case KEY.DOWN: actions.push(DIR.DOWN); handled = true; break;
case KEY.ESC: lose(); handled = true; break;
}
}
else if (ev.keyCode == KEY.SPACE) {
play();
handled = true;
}
if (handled)
ev.preventDefault(); // prevent arrow keys from scrolling the page (supported in IE9+ and all other browsers)
}
//-------------------------------------------------------------------------
// GAME LOGIC
//-------------------------------------------------------------------------
function play() { hide('start'); reset(); playing = true; }
function lose() { show('start'); setVisualScore(); playing = false; }
function setVisualScore(n) { vscore = n || score; invalidateScore(); }
function setScore(n) { score = n; setVisualScore(n); }
function addScore(n) { score = score + n; }
function clearScore() { setScore(0); }
function clearRows() { setRows(0); }
function setRows(n) { rows = n; step = Math.max(speed.min, speed.start - (speed.decrement*rows)); invalidateRows(); }
function addRows(n) { setRows(rows + n); }
function getBlock(x,y) { return (blocks && blocks[x] ? blocks[x][y] : null); }
function setBlock(x,y,type) { blocks[x] = blocks[x] || []; blocks[x][y] = type; invalidate(); }
function clearBlocks() { blocks = []; invalidate(); }
function clearActions() { actions = []; }
function setCurrentPiece(piece) { current = piece || randomPiece(); invalidate(); }
function setNextPiece(piece) { next = piece || randomPiece(); invalidateNext(); }
function reset() {
dt = 0;
clearActions();
clearBlocks();
clearRows();
clearScore();
setCurrentPiece(next);
setNextPiece();
}
function update(idt) {
if (playing) {
if (vscore < score)
setVisualScore(vscore + 1);
handle(actions.shift());
dt = dt + idt;
if (dt > step) {
dt = dt - step;
drop();
}
}
}
function handle(action) {
switch(action) {
case DIR.LEFT: move(DIR.LEFT); break;
case DIR.RIGHT: move(DIR.RIGHT); break;
case DIR.UP: rotate(); break;
case DIR.DOWN: drop(); break;
}
}
function move(dir) {
var x = current.x, y = current.y;
switch(dir) {
case DIR.RIGHT: x = x + 1; break;
case DIR.LEFT: x = x - 1; break;
case DIR.DOWN: y = y + 1; break;
}
if (unoccupied(current.type, x, y, current.dir)) {
current.x = x;
current.y = y;
invalidate();
return true;
}
else {
return false;
}
}
function rotate() {
var newdir = (current.dir == DIR.MAX ? DIR.MIN : current.dir + 1);
if (unoccupied(current.type, current.x, current.y, newdir)) {
current.dir = newdir;
invalidate();
}
}
//This is how we make the piece drop down and place:
function drop() {
if (!move(DIR.DOWN)) {
addScore(10);
dropPiece();
removeLines();
setCurrentPiece(next);
setNextPiece(randomPiece());
clearActions();
if (occupied(current.type, current.x, current.y, current.dir)) {
lose();
}
}
}
function dropPiece() {
eachblock(current.type, current.x, current.y, current.dir, function(x, y) {
setBlock(x, y, current.type);
});
}
function removeLines() {
var x, y, complete, n = 0;
for(y = ny ; y > 0 ; --y) {
complete = true;
for(x = 0 ; x < nx ; ++x) {
if (!getBlock(x, y))
complete = false;
}
if (complete) {
removeLine(y);
y = y + 1; // recheck same line
n++;
}
}
if (n > 0) {
addRows(n);
addScore(100*Math.pow(2,n-1)); // 1: 100, 2: 200, 3: 400, 4: 800
}
}
function removeLine(n) {
var x, y;
for(y = n ; y >= 0 ; --y) {
for(x = 0 ; x < nx ; ++x)
setBlock(x, y, (y == 0) ? null : getBlock(x, y-1));
}
}
//-------------------------------------------------------------------------
// RENDERING
//-------------------------------------------------------------------------
var invalid = {};
function invalidate() { invalid.court = true; }
function invalidateNext() { invalid.next = true; }
function invalidateScore() { invalid.score = true; }
function invalidateRows() { invalid.rows = true; }
function draw() {
ctx.save();
ctx.lineWidth = 1;
ctx.translate(0.5, 0.5); // for crisp 1px black lines
drawCourt();
drawNext();
drawScore();
drawRows();
ctx.restore();
}
function drawCourt() {
if (invalid.court) {
ctx.clearRect(0, 0, canvas.width, canvas.height);
if (playing)
drawPiece(ctx, current.type, current.x, current.y, current.dir);
var x, y, block;
for(y = 0 ; y < ny ; y++) {
for (x = 0 ; x < nx ; x++) {
if (block = getBlock(x,y))
drawBlock(ctx, x, y, block.color);
}
}
ctx.strokeRect(0, 0, nx*dx - 1, ny*dy - 1); // court boundary
invalid.court = false;
}
}
function drawNext() {
if (invalid.next) {
var padding = (nu - next.type.size) / 2; // half-complete attempt at centering next piece display
uctx.save();
uctx.translate(0.5, 0.5);
uctx.clearRect(0, 0, nu*dx, nu*dy);
drawPiece(uctx, next.type, padding, padding, next.dir);
uctx.strokeStyle = 'black';
uctx.strokeRect(0, 0, nu*dx - 1, nu*dy - 1);
uctx.restore();
invalid.next = false;
}
}
function drawScore() {
if (invalid.score) {
html('score', ("00000" + Math.floor(vscore)).slice(-5));
invalid.score = false;
}
}
function drawRows() {
if (invalid.rows) {
html('rows', rows);
invalid.rows = false;
}
}
function drawPiece(ctx, type, x, y, dir) {
eachblock(type, x, y, dir, function(x, y) {
drawBlock(ctx, x, y, type.color);
});
}
function drawBlock(ctx, x, y, color) {
ctx.fillStyle = color;
ctx.fillRect(x*dx, y*dy, dx, dy);
ctx.strokeRect(x*dx, y*dy, dx, dy)
}
//-------------------------------------------------------------------------
// FINALLY, lets run the game
//-------------------------------------------------------------------------
run();
You have a function called addScore that seems to be used to update the user's score. You could add a conditional block inside this function that will update the game speed when the new score is above the threshold you choose. Alternatively, if you would prefer to keep addScore purely focused on updating the value of the score, you could add this conditional block wherever you're calling addScore.

Canvas overlay after creating object

After drawing a shape, i would like to automaticly create overlay(or just add color to rest of the screen) outside the object (It will be locked so user can create only one shape - as for now i dont know how to code that also)
My code:
<body>
<label class="btn btn--primary" id="btnRoof"><b>Click to draw</b> </label>
<canvas id="canvas" class="canvas" width="800" height="800"></canvas>
<script>
var roof = null;
var roofPoints = [];
var lines = [];
var lineCounter = 0;
var drawingObject = {};
drawingObject.type = "";
drawingObject.background = "";
drawingObject.border = "";
function Point(x, y) {
this.x = x;
this.y = y;
}
$("#btnRoof").click(function () {
if (drawingObject.type == "roof") {
drawingObject.type = "";
lines.forEach(function (value, index, ar) {
canvas.remove(value);
});
//canvas.remove(lines[lineCounter - 1]);
roof = makeRoof(roofPoints);
canvas.add(roof);
canvas.renderAll();
} else {
drawingObject.type = "roof"; // roof type
}
});
// canvas Drawing
var canvas = new fabric.Canvas('canvas');
var x = 0;
var y = 0;
fabric.util.addListener(window, 'dblclick', function () {
drawingObject.type = "";
lines.forEach(function (value, index, ar) {
canvas.remove(value);
});
//canvas.remove(lines[lineCounter - 1]);
roof = makeRoof(roofPoints);
canvas.add(roof);
canvas.renderAll();
console.log("double click");
//clear arrays
roofPoints = [];
lines = [];
lineCounter = 0;
});
canvas.on('mouse:down', function (options) {
if (drawingObject.type == "roof") {
canvas.selection = false;
setStartingPoint(options); // set x,y
roofPoints.push(new Point(x, y));
var points = [x, y, x, y];
lines.push(new fabric.Line(points, {
strokeWidth: 2,
selectable: false,
stroke: 'blue'
}).setOriginX(x).setOriginY(y));
canvas.add(lines[lineCounter]);
lineCounter++;
canvas.on('mouse:up', function (options) {
canvas.selection = true;
});
}
});
canvas.on('mouse:move', function (options) {
if (lines[0] !== null && lines[0] !== undefined && drawingObject.type == "roof") {
setStartingPoint(options);
lines[lineCounter - 1].set({
x2: x,
y2: y
});
canvas.renderAll();
}
});
function setStartingPoint(options) {
var offset = $('#canvas').offset();
x = options.e.pageX - offset.left;
y = options.e.pageY - offset.top;
}
function makeRoof(roofPoints) {
var left = findLeftPaddingForRoof(roofPoints);
var top = findTopPaddingForRoof(roofPoints);
roofPoints.push(new Point(roofPoints[0].x, roofPoints[0].y))
var roof = new fabric.Polyline(roofPoints, {
fill: 'rgba(0,230,64,0.5)',
stroke: 'green',
strokeWidth: 2,
});
roof.set({
left: left,
top: top,
});
return roof;
}
function findTopPaddingForRoof(roofPoints) {
var result = 999999;
for (var f = 0; f < lineCounter; f++) {
if (roofPoints[f].y < result) {
result = roofPoints[f].y;
}
}
return Math.abs(result);
}
function findLeftPaddingForRoof(roofPoints) {
var result = 999999;
for (var i = 0; i < lineCounter; i++) {
if (roofPoints[i].x < result) {
result = roofPoints[i].x;
}
}
return Math.abs(result);
}
</script>
</body>
</html>
For now i can lock shape with doubleclick, but have no idea how to add overlay outside of it.

Game Collision-detection FIX

I am making a game where it's about clicking on the nearest yellow dot from the green dot.
I got a list named dots.
You can check out my codepen to see the code I'm using.
My problem is that when you're playing the game, sometimes some of the yellow dots are too close to each other. So I am thinking if it's possible to make a collision-detection or something else, to check if the yellow dots collides?
Here is a picture of my game...
I made a red circle around the problem:
The link to my codepen project: /lolkie02/pen/PJVOdy?editors=0010
If you wanna try the game, it only works through iPhone or Android browser since I made the buttons etc. 'touchstart' in the javascript.
function getDistance(obj1, obj2) {
return Math.floor(
Math.sqrt(Math.pow(obj1.cx - obj2.cx, 2) + Math.pow(obj1.cy - obj2.cy, 2))
);
}
function getRandomArbitrary(min, max) {
return Math.floor(Math.random() * (max - min) + min);
}
function comparator(a, b) {
if (a[1] < b[1]) return -1;
if (a[1] > b[1]) return 1;
return 0;
}
function difference(source, toRemove) {
return source.filter(function(value) {
return toRemove.indexOf(value) == -1;
});
}
////////////////
// global vars
////////////////
var svg = document.getElementById("svg");
var dotMatrix = document.createElementNS(
"http://www.w3.org/2000/svg",
"circle"
);
var lineMatrix = document.createElementNS("http://www.w3.org/2000/svg", "line");
var screenW = window.innerWidth;
var screenH = window.innerHeight;
var totalDist = document.getElementById("distance");
////////////////
// line constructor
////////////////
function Line(x1, y1, x2, y2) {
this.x1 = x1;
this.y1 = y1;
this.x2 = x2;
this.y2 = y2;
this.el = document.createElementNS("http://www.w3.org/2000/svg", "line");
this.class = "line";
this.update = function(x1, y1, x2, y2) {
this.el.setAttribute("x1", x1 || this.x1);
this.el.setAttribute("y1", y1 || this.y1);
this.el.setAttribute("x2", x2 || this.x2);
this.el.setAttribute("y2", y2 || this.y2);
this.setAttr("class", this.class);
};
this.setAttr = function(attr, value) {
this.el.setAttribute(attr, value);
};
this.append = function() {
svg.insertBefore(this.el, svg.firstChild);
};
}
////////////////
// dot constructor
////////////////
function Dot(r, cx, cy) {
this.r = r;
this.cx = cx;
this.cy = cy;
this.el = document.createElementNS("http://www.w3.org/2000/svg", "circle");
this.class = "dot";
this.update = function() {
this.el.setAttribute("r", this.r);
this.el.setAttribute("cx", this.cx);
this.el.setAttribute("cy", this.cy);
this.setAttr("class", this.class);
};
// activates a dot
this.activate = function() {
for (i = 0; i < dots.num; i++) {
dots.list[i].setAttr("data-selected", "false");
}
this.setAttr("data-selected", "true");
};
this.visited = function() {
this.setAttr("data-visited", "true");
};
// sets attribute to element
this.setAttr = function(attr, value) {
this.el.setAttribute(attr, value);
};
// gets attribute to element
this.getAttr = function(attr) {
return this.el.getAttribute(attr);
};
// appends element to svg and attaches event listeners
this.append = function() {
svg.appendChild(this.el);
this.el.addEventListener("touchstart", this.onClick);
};
// on click on element
this.onClick = function(event) {
//gets the id and the coords of the dot
var thisId = Number(event.target.getAttribute("data-id").substr(3, 2));
var thisCx = dots.list[thisId].cx;
var thisCy = dots.list[thisId].cy;
// calculates the distance between dots
var distances = [];
for (i = 0; i < dots.num; i++) {
distances[i] = [i, getDistance(dots.selected, dots.list[i])];
}
distances.sort(comparator);
distances.splice(0, 1);
var distancesLeft = [];
for (i = 0; i < distances.length; i++) {
if (dots.left.includes(distances[i][0])) {
distancesLeft.push(distances[i][0]);
}
}
//if the element is the nearest
if (thisId == distancesLeft[0] && dots.left.includes(thisId)) {
// calculates distances
var newDistance = getDistance(dots.list[thisId], dots.selected);
app.score.update(1); // punteggio x numero di poi
// app.score.update(newDistance); punteggio x distanza
//sets the active class to the selected dot
dots.list[thisId].activate();
dots.list[thisId].visited();
// creates the line
lines.list.push(
new Line(
dots.selected.cx,
dots.selected.cy,
dots.list[thisId].cx,
dots.list[thisId].cy
)
);
lines.list[lines.list.length - 1].update();
lines.list[lines.list.length - 1].append();
// creates the preview line
//TODO: eliminare le vecchie preline che rimangono vive
svg.addEventListener("mousemove", function prelineMove(e) {
mouseX = e.pageX;
mouseY = e.pageY;
app.preline.update(thisCx, thisCy, mouseX, mouseY);
});
//saves the selected dots coordinates
dots.selected.id = thisId;
dots.selected.cx = thisCx;
dots.selected.cy = thisCy;
//removes the dot from the list of remaining dots
for (i = 0; i < dots.left.length; i++) {
if (dots.left[i] === thisId) {
dots.left.splice(i, 1);
}
}
if (dots.left.length == 0) {
app.end(true);
}
} else {
app.end(false);
}
};
}
////////////////
// lines group
////////////////
var lines = {
list: []
};
////////////////
// dots group
////////////////
var dots = {};
dots.num = 20;
dots.list = [];
dots.start = 0;
dots.selected = {};
dots.selected.id = dots.start;
dots.left = [];
dots.preline;
////////////////
// app
////////////////
var app = {};
app.level = 2;
app.score = {};
app.score.number = 0;
app.score.el = document.getElementById("score");
app.score.update = function(score) {
app.score.number += score;
app.score.el.textContent = app.score.number;
};
app.score.reset = function() {
app.score.number = 0;
app.score.update(0);
};
app.results = function(points) {
if (points == "reset") {
sessionStorage.setItem("results", 0);
} else {
if (!sessionStorage.getItem("results")) {
sessionStorage.setItem("results", points);
} else {
var newscore = points;
sessionStorage.setItem("results", newscore);
}
}
};
app.launchScreen = function(lastScore, title, description, btnText) {
app.launchScreen.el = document.getElementById("launch-screen");
app.launchScreen.el.setAttribute("class", "is-visible");
var launchScreenTitle = document.getElementById("launch-screen__title");
launchScreenTitle.textContent = title;
var launchScreenDescription = document.getElementById(
"launch-screen__description"
);
launchScreenDescription.textContent = description;
app.launchScreen.btn = document.getElementById("start-btn");
app.launchScreen.btn.textContent = btnText;
app.launchScreen.btn.addEventListener("touchstart", function lauch() {
app.launchScreen.el.setAttribute("class", "");
app.start(app.level);
document.getElementById("score2").style.display = "block";
app.launchScreen.btn.removeEventListener("touchstart", lauch);
});
};
app.preline = new Line(0, 0, 200, 200);
app.preline.setAttr("id", "preline");
app.start = function(dotsNum) {
dots.num = dotsNum;
for (i = 0; i < dots.num; i++) {
var cx = getRandomArbitrary(45, screenW - 45);
var cy = getRandomArbitrary(45, screenH - 45);
dots.list[i] = new Dot(14, cx, cy);
dots.list[i].setAttr("data-id", "id-" + i);
dots.list[i].setAttr(
"style",
"animation-delay:" + i / 10 + "s; transform-origin: " + cx + 'px ' + cy + 'px;');
dots.list[i].update();
dots.list[i].append();
dots.left.push(i);
if (i == dots.start) {
dots.selected.cx = dots.list[dots.start].cx;
dots.selected.cy = dots.list[dots.start].cy;
dots.list[dots.start].setAttr("class", "dot dot--starting");
dots.left.splice(i, 1);
}
// adds the preline
app.preline.update(
dots.selected.cx,
dots.selected.cy,
dots.selected.cx,
dots.selected.cy
);
app.preline.append();
svg.addEventListener("mousemove", function prelineMove(e) {
mouseX = e.pageX;
mouseY = e.pageY;
app.preline.update(dots.selected.cx, dots.selected.cy, mouseX, mouseY);
});
}
// sets starting point
dots.list[dots.start].setAttr("data-selected", "true");
};
app.end = function(win) {
if (win) {
app.level += 2;
app.results(app.score.number);
} else {
app.level = 2;
}
dots.list = [];
dots.selected = {};
dots.left.length = 0;
svg.innerHTML = "";
if (win) {
app.launchScreen(
app.score.number,
"", //"Sådan!",
"", //"Din score er nu: " + sessionStorage.getItem("results") + ' Det næste level vil blive endnu hårdere.',
"NÆSTE LEVEL"
);
} else {
app.launchScreen(
0,
"", //"ARGH!",
"", //"Din endelige score blev: " + sessionStorage.getItem("results"),
"PRØV IGEN"
);
app.results("reset");
app.score.reset();
var score2 = document.getElementById('score2');
var number = score2.innerHTML;
number = 0;
score2.innerHTML = number;
document.getElementById("score2").style.display = "none";
}
};
app.launchScreen(
0,
"STIFINDER",
"Find den tætteste gule prik",
"SPIL"
);
$('.btn').on('touchstart',function(e,data) {
var score2 = document.getElementById('score2');
var number = score2.innerHTML;
number++;
score2.innerHTML = number;
});
Use Pythagorean theorem to determine whether the distance of the centers of two dots are closer (or equal) to the sum of their radii - in that case you have collision.
My answer to the similar question :https://stackoverflow.com/a/46973584/4154250

Trying to select lines or rectangles on a canvas

I want to be able to click any line(muscle) and new line then highlight it in my program like I can do with the nodes right now. I want to use context.isPointInPath(), but I feel like that will be too limiting in the fact that the lines are only 1 pixel wide. And now I want to look at changing the lines to rectangles. Because then I would be able to just see if the mouseclick is within the rectangle height and width. But, I'm having trouble finding out a way to connect the rectangle to two nodes like I have it with the strokes right now.
My program so far:
/*jshint esversion: 6 */
//draw everything on canvas
//TODO: Change use of canvas to a container and moving elements around to avoid the buffer of frame drawing
//Node class
class Node {
constructor(x, y, r, color, highlight, highlightColor) {
this.x = x;
this.y = y;
this.r = r || 20;
this.color = color || "#ff0";
this.highlight = highlight || false;
this.highlightColor = highlightColor || "#0000FF";
}
}
//Muscle class
class Muscle {
constructor(node1, node2, width, color) {
this.node1 = node1;
this.node2 = node2;
this.width = width || 5;
this.color = color || "#f00";
//Properties of the nodes this muscle attaches to
Object.defineProperties(this, {
node1x: {
"get": () => this.node1.x,
"set": x => {
this.node1.x = x;
}
},
node1y: {
"get": () => this.node1.y,
"set": y => {
this.node1.y = y;
}
},
node2x: {
"get": () => this.node2.x,
"set": x => {
this.node2.x = x;
}
},
node2y: {
"get": () => this.node2.y,
"set": y => {
this.node2.x = y;
}
}
});
}
}
function setParentForNodes() {
this.nodes.forEach(node => {
node.parentCreature = this;
});
}
class Creature {
constructor(nodes, muscles, nodeColors) {
this.nodes = nodes;
this.muscles = muscles;
this.nodeColors = nodeColors || "#ff0";
setParentForNodes.call(this);
Object.defineProperties(this, {
creatureNumber: {
"get": () => creatures.indexOf(this),
}
});
}
addNewNode(newNode) {
newNode.parentCreature = this;
this.nodes.push(newNode);
}
addNewNodes(newNodes) {
newNodes.forEach(function(node) {
node.parentCreature = this;
}, this);
this.nodes = this.nodes.concat(newNodes);
}
}
var nodes = [
new Node(100, 100),
new Node(200, 200)
];
var muscles = [
new Muscle(nodes[0], nodes[1])
];
var creatures = [
new Creature(nodes, muscles)
];
var addNodePressed = false;
var attachMusclePressed = false;
var addLimbPressed = false;
function draw(container, ctx, nodes, creatureMuscles) {
//draw in the container
ctx.fillStyle = "#000000";
ctx.fillRect(container.y, container.x, container.width, container.height);
// for loop to draw all objects of nodes
for (let i = 0; i < creatures.length; i++) {
var creatureNodes = creatures[i].nodes;
for (let i = 0; i < creatureNodes.length; i++) {
ctx.beginPath();
ctx.arc(creatureNodes[i].x, creatureNodes[i].y, creatureNodes[i].r, 0, 2 * Math.PI);
ctx.fillStyle = creatureNodes[i].color;
ctx.closePath();
ctx.fill();
//check if node needs to be highlighted
if (creatureNodes[i].highlight == true) {
ctx.beginPath();
ctx.arc(creatureNodes[i].x, creatureNodes[i].y, creatureNodes[i].r, 0, 2 * Math.PI);
ctx.strokeStyle = creatureNodes[i].highlightColor;
ctx.lineWidth = 5; // for now
ctx.closePath();
ctx.stroke();
}
}
creatureMuscles = creatures[i].muscles;
//loop and draw every muscle
for (let i = 0; i < creatureMuscles.length; i++) {
ctx.beginPath();
ctx.moveTo(creatureMuscles[i].node1x, creatureMuscles[i].node1y);
ctx.lineTo(creatureMuscles[i].node2x, creatureMuscles[i].node2y);
ctx.strokeStyle = creatureMuscles[i].color;
ctx.lineWidth = creatureMuscles[i].width;
ctx.closePath();
ctx.stroke();
}
}
}
//Handle moving a node with mousedrag
function handleMouseDrag(canvas, creatureNodes) {
var isDrag = false;
var dragNode;
var offset = {
x: 0,
y: 0,
x0: 0,
y0: 0
};
canvas.addEventListener("mousedown", function(e) {
//mousedown then save the position in var x and y
var x = e.offsetX,
y = e.offsetY;
//loop through all the nodes to find the first node that is within radius of the mouse click
for (let i = 0; i < creatures.length; i++) {
var creatureNodes = creatures[i].nodes;
for (let i = 0; i < creatureNodes.length; i++) {
if (Math.pow(x - creatureNodes[i].x, 2) + Math.pow(y - creatureNodes[i].y, 2) < Math.pow(creatureNodes[i].r, 2)) {
isDrag = true;
dragNode = creatureNodes[i];
//offset.x&y = where the node is currently
//offset x0&y0 = where the user clicked
offset = {
x: dragNode.x,
y: dragNode.y,
x0: x,
y0: y
};
return;
}
}
}
});
// when mouse moves and isDrag is true, move the node's position
canvas.addEventListener("mousemove", function(e) {
/*when the user moves the mouse, take the difference of where his mouse is right now and where the user clicked.
Then, add that to where the node is right now to find the correct placement of the node without centering on your mouse
*/
if (isDrag) {
dragNode.x = e.offsetX - offset.x0 + offset.x; // where the mouse is right now - where the user mousedown + where the node is right now
dragNode.y = e.offsetY - offset.y0 + offset.y;
}
});
canvas.addEventListener("mouseup", function(e) {
isDrag = false;
});
canvas.addEventListener("mouseleave", function(e) {
isDrag = false;
});
}
//Handle highlighting and button functionality
function handleMouseClick(canvas, nodes, muscles) {
var highlighted;
var highlightedNode;
canvas.addEventListener("mousedown", function(e) {
var x = e.offsetX,
y = e.offsetY;
var loopbreak = false;
for (let i = 0; i < creatures.length; i++) {
var creatureNodes = creatures[i].nodes;
for (let i = 0; i < creatureNodes.length; i++) {
// check if click is within radius of a node, if it is, highlight and set highlight boolean to true.
if (Math.pow(x - creatureNodes[i].x, 2) + Math.pow(y - creatureNodes[i].y, 2) < Math.pow(creatureNodes[i].r, 2)) {
var clickedNode = creatureNodes[i];
if (addNodePressed) {
console.log("Not valid. Cannot add a node on top of another node.");
loopbreak = true;
break;
} else if (addLimbPressed) {
console.log("Not valid. Cannot add a limb on top of another node.");
loopbreak = true;
break;
} else if (attachMusclePressed) {
if (highlightedNode == clickedNode) {
console.log("Not valid. Cannot attach muscle to the same node.");
loopbreak = true;
break;
} else {
var newMuscle;
if (highlightedNode.parentCreature.creatureNumber == clickedNode.parentCreature.creatureNumber) {
newMuscle = new Muscle(highlightedNode, clickedNode);
highlightedNode.parentCreature.muscles.push(newMuscle);
attachMuscle();
highlightedNode.highlight = false;
highlighted = false;
devTools(true, false, false, false);
} else {
var newNodes = [];
var newMuscles = [];
if (highlightedNode.parentCreature.creatureNumber > clickedNode.parentCreature.creatureNumber) {
highlightedNode.parentCreature.nodes.forEach(function(node) {
newNodes.push(node);
});
highlightedNode.parentCreature.muscles.forEach(function(muscle) {
newMuscles.push(muscle);
});
newMuscle = new Muscle(highlightedNode, clickedNode);
clickedNode.parentCreature.muscles.push(newMuscle);
clickedNode.parentCreature.muscles = clickedNode.parentCreature.muscles.concat(newMuscles);
creatures.splice(creatures.indexOf(highlightedNode.parentCreature), 1);
clickedNode.parentCreature.addNewNodes(newNodes);
} else {
clickedNode.parentCreature.nodes.forEach(function(node) {
newNodes.push(node);
console.log("Clicked node is bigger.");
});
clickedNode.parentCreature.muscles.forEach(function(muscle) {
newMuscles.push(muscle);
});
newMuscle = new Muscle(highlightedNode, clickedNode);
highlightedNode.parentCreature.muscles.push(newMuscle);
highlightedNode.parentCreature.muscles = highlightedNode.parentCreature.muscles.concat(newMuscles);
creatures.splice(creatures.indexOf(clickedNode.parentCreature), 1);
highlightedNode.parentCreature.addNewNodes(newNodes);
}
highlightedNode.highlight = false;
attachMuscle();
devTools(true, false, false, false);
}
}
}
//no button pressed - highlight/unhighlight node
else {
if (highlighted || creatureNodes[i].highlight) {
if (highlightedNode != creatureNodes[i]) {
highlightedNode.highlight = false;
highlightedNode = creatureNodes[i];
highlightedNode.highlight = true;
devTools(false, true, true, true);
} else {
highlightedNode = creatureNodes[i];
highlightedNode.highlight = false;
highlighted = false;
highlightedNode = undefined;
devTools(true, false, false, false);
}
} else {
highlightedNode = creatureNodes[i];
highlightedNode.highlight = true;
highlighted = true;
devTools(false, true, true, true);
}
loopbreak = true;
break;
}
}
}
}
// if click was not in radius of any nodes then check for add limb or create node button press.
if (!loopbreak) {
loopbreak = false;
var newNode;
if (addNodePressed) {
newNode = new Node(x, y);
let newNodes = [];
let newMuscles = [];
newNodes.push(newNode);
var newCreature = new Creature(newNodes, newMuscles);
creatures.push(newCreature);
addNode();
addNodePressed = false;
devTools(true, false, false, false);
} else if (addLimbPressed) {
newNode = new Node(x, y);
let newMuscle = new Muscle(newNode, highlightedNode);
highlightedNode.parentCreature.addNewNode(newNode);
highlightedNode.parentCreature.muscles.push(newMuscle);
addLimb();
addLimbPressed = false;
highlightedNode.highlight = false;
highlighted = false;
highlightedNode = undefined;
devTools(true, false, false, false);
}
}
});
}
//Handle Devtools
function devTools(addNode, removeNode, attachMuscle, addLimb) {
var creatureNumberHTML = document.getElementById("creatureNumber");
var selectedHTML = document.getElementById("selected");
var addNodeB = document.getElementById("addNode");
var removeNodeB = document.getElementById("removeNode");
var attachMuscleB = document.getElementById("attachMuscle");
var addLimbB = document.getElementById("addLimb");
addNodeB.disabled = (addNode) ? false : true;
removeNodeB.disabled = (removeNode) ? false : true;
attachMuscleB.disabled = (attachMuscle) ? false : true;
addLimbB.disabled = (addLimb) ? false : true;
for (let i = 0; i < creatures.length; i++) {
var creatureNumber = i;
var creatureNodes = creatures[i].nodes;
for (let i = 0; i < creatureNodes.length; i++) {
if (creatureNodes[i].highlight == true) {
selectedHTML.innerHTML = `Selected: ${i} node`;
creatureNumberHTML.innerHTML = `Creature number: ${creatureNumber}`;
return;
} else {
creatureNumberHTML.innerHTML = "Creature number: -";
selectedHTML.innerHTML = "Selected: None";
}
}
}
}
//Handle add node button
function addNode() {
var addNodeB = document.getElementById("addNode");
if (addNodePressed) {
addNodePressed = false;
addNodeB.style.background = "";
} else {
addNodePressed = true;
addNodeB.style.backgroundColor = "#808080";
//and unhighlight
}
}
//Handle remove node button
function removeNode() {
for (let i = 0; i < creatures.length; i++) {
var creatureNodes = creatures[i].nodes;
var creatureMuscles = creatures[i].muscles;
for (let i = 0; i < creatureNodes.length; i++) {
if (creatureNodes[i].highlight == true) {
let highlightedNode = creatureNodes[i];
for (let i = 0; i < creatureMuscles.length; i++) {
if (creatureMuscles[i].node1 == highlightedNode || creatureMuscles[i].node2 == highlightedNode) {
creatureMuscles.splice(i, 1);
i--;
}
}
creatureNodes.splice(i, 1);
}
}
}
devTools(true, false, false, false);
}
//Handle attach muscle button
function attachMuscle() {
var attachMuscleB = document.getElementById("attachMuscle");
if (attachMusclePressed) {
attachMusclePressed = false;
attachMuscleB.style.background = "";
} else {
attachMusclePressed = true;
attachMuscleB.style.backgroundColor = "#808080";
}
}
//Handle add limb button
function addLimb() {
var addLimbB = document.getElementById("addLimb");
if (addLimbPressed) {
addLimbPressed = false;
addLimbB.style.background = "";
} else {
addLimbPressed = true;
addLimbB.style.backgroundColor = "#808080";
}
}
//Main - Grabs document elements to draw a canvas on, init node and muscle arrays and then continuously updates frame to redraw
function main() {
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var container = {
x: 0,
y: 0,
get width() {
return canvas.width;
},
get height() {
return canvas.height;
}
};
handleMouseDrag(canvas, nodes);
handleMouseClick(canvas, nodes, muscles);
// refresh and redraw with new properties in an updateframe infinite loop
function updateFrame() {
ctx.save();
draw(container, ctx, nodes, muscles);
ctx.restore();
requestAnimationFrame(updateFrame);
}
updateFrame();
}
main();
#canvas {
display: block;
}
#info {
display: inline-block;
text-overflow: clip;
overflow: hidden;
margin-right: 200px;
}
#commands {
display: inline-block;
text-align: center;
margin-left: 200px;
}
#devTools {
background-color: aqua;
width: 1500px;
}
section {
width: 200px;
height: 200px;
background-color: grey;
vertical-align: top;
}
<!DOCTYPE HTML>
<html>
<head>
<meta charset="UTF-8">
<link rel="stylesheet" type="text/css" href="styles.css" />
</head>
<body>
<!--TODO: Adjust the size of the canvas to fit the window-->
<canvas id="canvas" width="1500" , height="600"></canvas>
<!--TODO: Create buttons for all devtools under the canvas-->
<!--TODO: Make a container for all devtools under the canvas, then add all the functionality to it after-->
<div id="devTools">
<section id="info">
<p>Info</p>
<p id="creatureNumber">Creature Number: -</p>
<p id="selected">Selected: </p>
</section>
<section id="commands">
<p>Commands</p>
<button type="button" id="addNode" onclick="addNode()">Add node</button>
<button type="button" id="removeNode" disabled=true onclick="removeNode()">Remove node</button>
<button type="button" id="attachMuscle" disabled=true onclick="attachMuscle()">Attach muscle</button>
<button type="button" id="addLimb" disabled=true onclick="addLimb()">Add Limb</button>
<div id="muscleLength">
<button type="button" id="increaseLengthB">↑</button>
<p>Muscle Length</p>
<button type="button" id="decreaseLengthB">↓</button>
</div>
</section>
</div>
<script src="scripts/script.js"></script>
</body>
</html>
Another way to solve this is to use a thicker line-width and use isPointInStroke() instead.
var ctx = c.getContext("2d");
var path = new Path2D(); // to store and reuse path
var onLine = false; // state (for demo)
path.moveTo(10, 10); // store a line on path
path.lineTo(200, 100);
ctx.lineWidth = 16; // line width
render(); // initial render
function render() {
ctx.clearRect(0,0,300,150);
ctx.strokeStyle = onLine ? "#09f" : "#000"; // color based on state
ctx.stroke(path); // stroke path
}
c.onmousemove = function(e) { // demo: is mouse on stroke?
onLine = ctx.isPointInStroke(path, e.clientX, e.clientY);
render();
};
body, html {margin:0}
<canvas id=c></canvas>
Note: IE11 does not support the path argument - for it you will need to use ordinary path on the context itself (ctx.moveTo etc.)

JavaScript with PHP SESSION

I have a problem because I can not add php session to post in javascript, or do not know how to do it, here is my code which is a problem.
if (!this.movesAvailable()) {
var xmlhttp = null;
this.over = true; // Game over!
xmlhttp = new XMLHttpRequest();
xmlhttp.open("GET", "http://obiektywnywaper.pl/2048/post.php?user=&wynik="+self.score, true);
xmlhttp.send();
alert(self.score);
}
I tried something like this, but it does not work
if (!this.movesAvailable()) {
var xmlhttp = null;
var user=<?echo $_SESSION['user'];?>;
this.over = true; // Game over!
xmlhttp = new XMLHttpRequest();
xmlhttp.open("GET", "http://obiektywnywaper.pl/2048/post.php?user="+user+"&wynik="+self.score, true);
xmlhttp.send();
alert(self.score);
}
I add also the js file
function GameManager(size, InputManager, Actuator, ScoreManager) {
this.size = size; // Size of the grid
this.inputManager = new InputManager;
this.scoreManager = new ScoreManager;
this.actuator = new Actuator;
this.startTiles = 2;
this.inputManager.on("move", this.move.bind(this));
this.inputManager.on("restart", this.restart.bind(this));
this.inputManager.on("keepPlaying", this.keepPlaying.bind(this));
this.inputManager.on("showInfo", this.showInfo.bind(this));
this.inputManager.on("hideInfo", this.hideInfo.bind(this));
this.setup();
}
// Restart the game
GameManager.prototype.restart = function () {
this.actuator.continue();
this.setup();
};
// Keep playing after winning
GameManager.prototype.keepPlaying = function () {
this.keepPlaying = true;
this.actuator.continue();
};
GameManager.prototype.showInfo = function () {
this.actuator.showInfo();
};
GameManager.prototype.hideInfo = function () {
this.actuator.hideInfo();
};
GameManager.prototype.isGameTerminated = function () {
if (this.over || (this.won && !this.keepPlaying)) {
return true;
} else {
return false;
}
};
// Set up the game
GameManager.prototype.setup = function () {
this.grid = new Grid(this.size);
this.score = 0;
this.over = false;
this.won = false;
this.keepPlaying = false;
// Add the initial tiles
this.addStartTiles();
// Update the actuator
this.actuate();
};
// Set up the initial tiles to start the game with
GameManager.prototype.addStartTiles = function () {
for (var i = 0; i < this.startTiles; i++) {
this.addRandomTile();
}
};
// Adds a tile in a random position
GameManager.prototype.addRandomTile = function () {
if (this.grid.cellsAvailable()) {
var value = Math.random() < 0.9 ? 2 : 4;
var tile = new Tile(this.grid.randomAvailableCell(), value);
this.grid.insertTile(tile);
}
};
// Sends the updated grid to the actuator
GameManager.prototype.actuate = function () {
if (this.scoreManager.get() < this.score) {
this.scoreManager.set(this.score);
}
this.actuator.actuate(this.grid, {
score: this.score,
over: this.over,
won: this.won,
bestScore: this.scoreManager.get(),
terminated: this.isGameTerminated()
});
};
// Save all tile positions and remove merger info
GameManager.prototype.prepareTiles = function () {
this.grid.eachCell(function (x, y, tile) {
if (tile) {
tile.mergedFrom = null;
tile.savePosition();
}
});
};
// Move a tile and its representation
GameManager.prototype.moveTile = function (tile, cell) {
this.grid.cells[tile.x][tile.y] = null;
this.grid.cells[cell.x][cell.y] = tile;
tile.updatePosition(cell);
};
// Move tiles on the grid in the specified direction
GameManager.prototype.move = function (direction) {
// 0: up, 1: right, 2:down, 3: left
var self = this;
if (this.isGameTerminated()) return; // Don't do anything if the game's over
var cell, tile;
var vector = this.getVector(direction);
var traversals = this.buildTraversals(vector);
var moved = false;
// Save the current tile positions and remove merger information
this.prepareTiles();
// Traverse the grid in the right direction and move tiles
traversals.x.forEach(function (x) {
traversals.y.forEach(function (y) {
cell = { x: x, y: y };
tile = self.grid.cellContent(cell);
if (tile) {
var positions = self.findFarthestPosition(cell, vector);
var next = self.grid.cellContent(positions.next);
// Only one merger per row traversal?
if (next && next.value === tile.value && !next.mergedFrom) {
var merged = new Tile(positions.next, tile.value * 2);
merged.mergedFrom = [tile, next];
self.grid.insertTile(merged);
self.grid.removeTile(tile);
// Converge the two tiles' positions
tile.updatePosition(positions.next);
// Update the score
self.score += merged.value;
// The mighty 2048 tile
if (merged.value === 2048) self.won = true;
} else {
self.moveTile(tile, positions.farthest);
}
if (!self.positionsEqual(cell, tile)) {
moved = true; // The tile moved from its original cell!
}
}
});
});
if (moved) {
this.addRandomTile();
if (!this.movesAvailable()) {
var xmlhttp = null;
this.over = true; // Game over!
xmlhttp = new XMLHttpRequest();
xmlhttp.open("GET", "http://obiektywnywaper.pl/2048/post.php?user=&wynik="+self.score, true);
xmlhttp.send();
alert(self.score);
}
this.actuate();
}
};
// Get the vector representing the chosen direction
GameManager.prototype.getVector = function (direction) {
// Vectors representing tile movement
var map = {
0: { x: 0, y: -1 }, // up
1: { x: 1, y: 0 }, // right
2: { x: 0, y: 1 }, // down
3: { x: -1, y: 0 } // left
};
return map[direction];
};
// Build a list of positions to traverse in the right order
GameManager.prototype.buildTraversals = function (vector) {
var traversals = { x: [], y: [] };
for (var pos = 0; pos < this.size; pos++) {
traversals.x.push(pos);
traversals.y.push(pos);
}
// Always traverse from the farthest cell in the chosen direction
if (vector.x === 1) traversals.x = traversals.x.reverse();
if (vector.y === 1) traversals.y = traversals.y.reverse();
return traversals;
};
GameManager.prototype.findFarthestPosition = function (cell, vector) {
var previous;
// Progress towards the vector direction until an obstacle is found
do {
previous = cell;
cell = { x: previous.x + vector.x, y: previous.y + vector.y };
} while (this.grid.withinBounds(cell) &&
this.grid.cellAvailable(cell));
return {
farthest: previous,
next: cell // Used to check if a merge is required
};
};
GameManager.prototype.movesAvailable = function () {
return this.grid.cellsAvailable() || this.tileMatchesAvailable();
};
// Check for available matches between tiles (more expensive check)
GameManager.prototype.tileMatchesAvailable = function () {
var self = this;
var tile;
for (var x = 0; x < this.size; x++) {
for (var y = 0; y < this.size; y++) {
tile = this.grid.cellContent({ x: x, y: y });
if (tile) {
for (var direction = 0; direction < 4; direction++) {
var vector = self.getVector(direction);
var cell = { x: x + vector.x, y: y + vector.y };
var other = self.grid.cellContent(cell);
if (other && other.value === tile.value) {
return true; // These two tiles can be merged
}
}
}
}
}
return false;
};
GameManager.prototype.positionsEqual = function (first, second) {
return first.x === second.x && first.y === second.y;
};
I don't know php, but classic asp works in similar fashion as far as I know. If you set the variable outside the scope of the function, and also include apostrophes, it should work.
var user="<?php echo $_SESSION['user'];?>"; //possibly declared outside of scope
Edited as per #developerwjk's comment about the php-syntax

Categories

Resources