I'm building a program that runs through an matrix (nxn) avoiding collisions with certain obstacles. I'm having trouble implementing a generic algorithm that works for all possible collision situations, the ultimate goal is to go through all the points of the matrix.
The algorithm I built is looping and can not complete the matrix.
Note: The red square can move in any direction (horizontal, vertical and diagonal movements), but only one cell(square) at a time.
var WALL = 0;
var started = false;
var gridSize = 20;
class Agent {
constructor(x, y, charge, cap, distance) {
this.x = x;
this.y = y;
this.charge = charge;
this.cap = cap;
this.distance = distance;
}
}
$(function() {
var $grid = $("#search_grid");
var opts = {
gridSize: 20
};
var grid = new GraphSearch($grid, opts);
//Initializes the agent
$("#btnInit").click(function() {
if (!started) {
var agent = new Agent(0, 0, 100, 50, 0);
agent.initialize();
started = true;
}
});
});
//Initializes the matrix
function GraphSearch($graph, options) {
this.$graph = $graph;
this.opts = options;
this.initialize();
}
//Initializes the matrix
GraphSearch.prototype.initialize = function() {
this.grid = [];
$graph = this.$graph;
$graph.empty();
var cellWidth = ($graph.width() / this.opts.gridSize) - 2,
cellHeight = ($graph.height() / this.opts.gridSize) - 2,
lineHeight = (this.opts.gridSize >= 30 ? "9.px" : ($graph.height() / this.opts.gridSize) - 10 + "px"),
fontSize = (this.opts.gridSize >= 30 ? "10px" : "20px");
$cellTemplate = $("<span />").addClass("grid_item").width(cellWidth).height(cellHeight).css("line-height", lineHeight).css("font-size", fontSize);
for (var x = 0; x < this.opts.gridSize; x++) {
var $row = $("<div class='row' />");
for (var y = 0; y < this.opts.gridSize; y++) {
var id = "cell_" + x + "_" + y,
$cell = $cellTemplate.clone();
$cell.attr("id", id).attr("x", x).attr("y", y);
$row.append($cell);
var isWall = addWall(x, y, this.opts.gridSize);
if (isWall === 1) {
$cell.addClass("wall");
} else {
$cell.addClass('weight1');
}
}
$graph.append($row);
//Fix for stackoverflow snippet
if ($(window).width() < 700) {
$("#search_grid").css("width", "320px");
$("#main").css("width", "38%");
} else {
$("#search_grid").css("width", "300px");
$("#main").css("width", "20%");
}
}
};
//Where will be wall in the matrix
addWall = function(x, y, size) {
var limitPointLeftUp = [2, 3];
var limitPointRightUp = [2, size - 4];
var limitPointLeftDown = [size - 4, 2];
var limitPointRightDown = [size - 4, size - 4];
if ((x == 2 && y == 2) || (x == 2 && y == size - 3)) {
return 1;
}
if ((x == size - 3 && y == 2) || (x == size - 3 && y == size - 3)) {
return 1;
}
if (x >= 2 && (y == 3 && x >= limitPointLeftUp[0] && x <= limitPointLeftDown[0] + 1)) {
return 1;
}
if (x >= 2 && (y == size - 4 && x >= limitPointRightUp[0] && x <= limitPointRightDown[0] + 1)) {
return 1;
}
if ((x == 1 && y == 5) || (x == 9 && y == 17) || (x == 6 && y == 0) || (x == 9 && y == 7) || (x == 15 && y == 0) || (x == 15 && y == 2) || (x == 18 && y == 15)) {
return 1;
}
}
//Initializes the agent
Agent.prototype.initialize = function() {
var agent = this;
var lastDir = "right";
var tryTo = "";
var trying = false;
var right = true;
var up = false;
var down = false;
var left = false;
var timerId = 0;
//Simulates agent movement [Here is my problem]
timerId = setInterval(function() {
RemoveAgent();
var cell = $("#search_grid .row .grid_item[x=" + agent.x + "][y=" + agent.y + "]");
cell.css("background-color", "#e2e2e2");
cell.addClass("agent");
//start direction: right
if (right) {
lastDir = "right";
if (tryTo == "down" && trying) {
if (EmptySqm(agent.x + 1, agent.y)) {
trying = false;
right = false;
down = true;
agent.x++;
}
} else if (tryTo == "up" && trying) {
if (EmptySqm(agent.x - 1, agent.y)) {
trying = false;
right = false;
up = true;
agent.x--;
}
}
if (right) {
//check if is valid sqm
if (ValidSqm(agent.x, agent.y + 1)) {
//go right if empty
if (EmptySqm(agent.x, agent.y + 1)) {
agent.y++;
} else {
right = false;
//check up sqm
if (EmptySqm(agent.x - 1, agent.y)) {
up = true;
trying = true;
}
//check down
else if (EmptySqm(agent.x + 1, agent.y)) {
down = true;
trying = true;
}
}
} else {
agent.x++;
right = false;
left = true;
}
}
//left direction
} else if (left) {
lastDir = "left";
if (tryTo == "down" && trying) {
if (EmptySqm(agent.x + 1, agent.y)) {
trying = false;
left = false;
down = true;
agent.x++;
}
} else if (tryTo == "up" && trying) {
if (EmptySqm(agent.x - 1, agent.y)) {
trying = false;
left = false;
up = true;
agent.x--;
}
}
if (left) {
if (ValidSqm(agent.x, agent.y - 1)) {
if (EmptySqm(agent.x, agent.y - 1)) {
agent.y--;
} else {
left = false;
if (EmptySqm(agent.x + 1, agent.y)) {
down = true;
trying = true;
} else if (EmptySqm(agent.x - 1, agent.y)) {
up = true;
trying = true;
}
}
} else {
agent.x++;
right = true;
left = false;
}
}
//up direction
} else if (up) {
tryTo = "down";
if (lastDir == "left") {
if (EmptySqm(agent.x, agent.y - 1)) {
up = false;
left = true;
agent.y--;
}
} else if (lastDir == "right") {
if (EmptySqm(agent.x, agent.y + 1)) {
up = false;
right = true;
agent.y++;
}
}
if (up) {
if (ValidSqm(agent.x - 1, agent.y)) {
if (EmptySqm(agent.x - 1, agent.y)) {
agent.x--;
} else {
up = false;
//check left sqm
if (EmptySqm(agent.x, agent.y - 1)) {
left = true;
agent.y--;
}
//check right sqm
else if (EmptySqm(agent.x, agent.y + 1)) {
right = true;
agent.y++;
}
//check down sqm
else if (EmptySqm(agent.x + 1, agent.y)) {
down = true;
agent.x++;
}
}
} else {
agent.x++;
up = false;
down = true;
}
}
//down direction
} else if (down) {
tryTo = "up";
if (lastDir == "left") {
if (EmptySqm(agent.x, agent.y - 1)) {
down = false;
left = true;
agent.y--;
}
} else if (lastDir == "right") {
if (EmptySqm(agent.x, agent.y + 1)) {
down = false;
right = true;
agent.y++;
}
}
if (down) {
if (ValidSqm(agent.x + 1, agent.y)) {
if (EmptySqm(agent.x + 1, agent.y)) {
agent.x++;
} else {
down = false;
//check left sqm
if (EmptySqm(agent.x, agent.y - 1)) {
left = true;
agent.y--;
}
//check right sqm
else if (EmptySqm(agent.x, agent.y + 1)) {
right = true;
agent.y++;
}
//check up sqm
else if (EmptySqm(agent.x - 1, agent.y)) {
up = true;
agent.x--;
}
}
} else {
agent.x--;
up = true;
down = false;
}
}
}
}, 100);
var stopInterval = function() {
clearInterval(timerId);
};
};
EmptySqm = function(x, y) {
var bNotWall = !$("#search_grid .row .grid_item[x=" + x + "][y=" + y + "]").hasClass("wall");
return bNotWall;
}
RemoveAgent = function() {
$("#search_grid .row .grid_item").removeClass("agent");
}
ValidSqm = function(x, y) {
return ((x >= 0 && x < gridSize) && (y >= 0 && y < gridSize));
}
html,
body {
height: 100%;
margin: 0;
}
.buttons {
float: right;
position: relative;
right: 10px;
top: 10px;
}
.buttons a {
text-decoration: none;
}
#content {
margin: 0 auto;
width: 98%;
text-align: center;
}
#controls {
text-align: center;
margin-bottom: 25px;
padding: 5px;
}
#search_grid {
width: 320px;
height: 300px;
position: relative;
}
#main {
margin: auto;
width: 20%;
}
.grid_item {
display: block;
border: 1px solid #bbb;
float: left;
line-height: 12px;
font-size: 10px;
}
.grid_item.wall {
background-color: #000000;
}
.grid_item.weight1 {
background-color: #ffffff;
}
.agent {
text-align: center;
color: grey;
font-size: 20px;
background-color: red !important;
color: blue;
font-weight: bold;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<body>
<div id="content">
<input type="button" id="btnInit" value="Start" /><br><br>
<div id="main">
<div id="search_grid">Loading...</div>
</div>
</div>
<div id="footer"></div>
</body>
I solved my problem with the help of the a* algorithm, more specifically this implementation, the deviation of the obstacles is done with the move method, which returns the path to a certain cell
path = grid.move(currentCell, endCell);
var agentSpeed = 10;
var WALL = 0;
var started = false;
var gridSize = 20;
var x = 0;
var y = 0;
var runsSameLine = false;
class Agent {
constructor(x, y, charge, cap, distance) {
this.x = x;
this.y = y;
this.charge = charge;
this.cap = cap;
this.distance = distance;
}
}
$(function() {
var $grid = $("#search_grid");
var opts = {
gridSize: gridSize
};
var grid = new GraphSearch($grid, opts, astar.search);
//Initializes the agent
$("#btnInit").click(function() {
if (!started) {
var agent = new Agent(0, 0, 100, 50, 0);
agent.initialize();
started = true;
}
});
});
//Initializes the matrix
function GraphSearch($graph, options, implementation) {
this.$graph = $graph;
this.search = implementation;
this.opts = options;
this.initialize();
}
var grid;
GraphSearch.prototype.move = function($start, $end) {
var end = this.nodeFromElement($end);
if ($end.hasClass("wall")) {
return;
}
var start = this.nodeFromElement($start);
var path = this.search(this.graph.nodes, start, end, true);
if (!path || path.length == 0) {
//this.animateNoPath();
} else {
return path;
}
};
GraphSearch.prototype.nodeFromElement = function($cell) {
return this.graph.nodes[parseInt($cell.attr("x"))][parseInt($cell.attr("y"))];
};
//Initializes the matrix
GraphSearch.prototype.initialize = function() {
this.grid = [];
var self = this,
nodes = [],
$graph = this.$graph;
$graph.empty();
var cellWidth = ($graph.width() / this.opts.gridSize) - 2,
cellHeight = ($graph.height() / this.opts.gridSize) - 2,
lineHeight = (this.opts.gridSize >= 30 ? "9.px" : ($graph.height() / this.opts.gridSize) - 10 + "px"),
fontSize = (this.opts.gridSize >= 30 ? "10px" : "20px");
$cellTemplate = $("<span />").addClass("grid_item").width(cellWidth).height(cellHeight).css("line-height", lineHeight).css("font-size", fontSize);
for (var x = 0; x < this.opts.gridSize; x++) {
var $row = $("<div class='row' />");
nodeRow = [],
gridRow = [];
for (var y = 0; y < this.opts.gridSize; y++) {
var id = "cell_" + x + "_" + y,
$cell = $cellTemplate.clone();
$cell.attr("id", id).attr("x", x).attr("y", y);
$row.append($cell);
gridRow.push($cell);
var isWall = addWall(x, y, this.opts.gridSize);
if (isWall === 1) {
$cell.addClass("wall");
nodeRow.push(1);
} else {
$cell.addClass('weight1');
nodeRow.push(0);
}
}
$graph.append($row);
this.grid.push(gridRow);
nodes.push(nodeRow);
//Fix for stackoverflow snippet
if ($(window).width() < 700) {
$("#search_grid").css("width", "320px");
$("#main").css("width", "38%");
} else {
$("#search_grid").css("width", "300px");
$("#main").css("width", "20%");
}
}
this.graph = new Graph(nodes);
this.$cells = $graph.find(".grid_item");
grid = this;
};
//Where will be wall in the matrix
addWall = function(x, y, size) {
var limitPointLeftUp = [2, 3];
var limitPointRightUp = [2, size - 4];
var limitPointLeftDown = [size - 4, 2];
var limitPointRightDown = [size - 4, size - 4];
if ((x == 2 && y == 2) || (x == 2 && y == size - 3)) {
return 1;
}
if ((x == size - 3 && y == 2) || (x == size - 3 && y == size - 3)) {
return 1;
}
if (x >= 2 && (y == 3 && x >= limitPointLeftUp[0] && x <= limitPointLeftDown[0] + 1)) {
return 1;
}
if (x >= 2 && (y == size - 4 && x >= limitPointRightUp[0] && x <= limitPointRightDown[0] + 1)) {
return 1;
}
if ((x == 1 && y == 5) || (x == 9 && y == 17) || (x == 6 && y == 0) || (x == 9 && y == 7) || (x == 15 && y == 0) || (x == 15 && y == 2) || (x == 18 && y == 15)) {
return 1;
}
}
//Initializes the agent
Agent.prototype.initialize = function() {
var agent = this;
var goToLeft = false;
var goToRight = true;
var rightLimit = gridSize - 1;
var leftLimit = 0;
var lastPos = 0;
var path = [];
var completedPath = true;
timerId = setInterval(function() {
agent.x = x;
agent.y = y;
currentCell = $("#search_grid .row .grid_item[x=" + x + "][y=" + y + "]");
currentCell.css("background-color", "#e2e2e2");
if (agent.x == gridSize - 1 && agent.y == 0) {
stopInterval(timerId);
return false;
}
if (goToRight && y == rightLimit) {
if (runsSameLine) {
goToLeft = true;
goToRight = false;
runsSameLine = false;
} else {
if (FreeCell((x + 1), y)) {
endCell = $("#search_grid .row .grid_item[x=" + (x + 1) + "][y=" + y + "]");
x++;
goToLeft = true;
goToRight = false;
} else {
endCell = FindNextFreeCell(x, y, "limDir");
goToLeft = true;
goToRight = false;
}
}
} else if (goToLeft && y == leftLimit) {
if (runsSameLine) {
goToLeft = false;
goToRight = true;
runsSameLine = false;
} else {
if (FreeCell((x + 1), y)) {
endCell = $("#search_grid .row .grid_item[x=" + (x + 1) + "][y=" + y + "]");
x++;
goToLeft = false;
goToRight = true;
} else {
endCell = FindNextFreeCell(x, y, "limEsq");
goToLeft = false;
goToRight = true;
}
}
} else if (goToRight) {
if (FreeCell(x, (y + 1))) {
endCell = $("#search_grid .row .grid_item[x=" + x + "][y=" + (y + 1) + "]");
y++;
} else {
endCell = FindNextFreeCell(x, y, "dir");
}
} else if (goToLeft) {
if (FreeCell(x, (y - 1))) {
endCell = $("#search_grid .row .grid_item[x=" + x + "][y=" + (y - 1) + "]");
y--;
} else {
endCell = FindNextFreeCell(x, y, "esq");
}
}
if (completedPath) {
path = grid.move(currentCell, endCell);
}
if (path) {
if (lastPos == path.length - 1) {
completedPath = true;
}
if (path.length > 1 && lastPos < path.length && lastPos != path.length - 1) {
x = path[lastPos].x;
y = path[lastPos].y;
lastPos++;
completedPath = false;
} else if (completedPath) {
x = path[lastPos].x;
y = path[lastPos].y;
lastPos = 0;
}
}
grid.$cells.removeClass("agent");
$("#search_grid .row .grid_item[x=" + x + "][y=" + y + "]").addClass("agent");
}, agentSpeed);
var stopInterval = function() {
clearInterval(timerId);
};
};
FindNextFreeCell = function(x, y, dir) {
if (dir == "limDir") {
if (x != gridSize) {
for (var y = y; y >= 0; y--) {
if (FreeCell((x + 1), y)) {
return getCell((x + 1), y);
}
}
}
} else if (dir == "limEsq") {
if (x != gridSize) {
for (var y = y; y <= gridSize; y++) {
if (FreeCell((x + 1), y)) {
return getCell((x + 1), y);
}
}
}
} else if (dir == "dir") {
for (var y = y; y < gridSize - 1; y++) {
if (FreeCell(x, (y + 1))) {
return getCell(x, (y + 1));
}
}
for (var x = x; x <= gridSize - 1; x++) {
if (FreeCell((x + 1), y)) {
runsSameLine = true;
return getCell((x + 1), y);
}
}
} else if (dir == "esq") {
for (var y = y; y > 0; y--) {
if (FreeCell(x, (y - 1))) {
return getCell(x, (y - 1));
}
}
for (var x = x; x <= gridSize - 1; x++) {
if (FreeCell((x + 1), y)) {
runsSameLine = true;
return getCell((x + 1), y);
}
}
}
}
EmptySqm = function(x, y) {
var bNotWall = !$("#search_grid .row .grid_item[x=" + x + "][y=" + y + "]").hasClass("wall");
return bNotWall;
}
getCell = function(x, y) {
return $("#search_grid .row .grid_item[x=" + x + "][y=" + y + "]");
}
FreeCell = function(x, y) {
var bNaoTemParede = !$("#search_grid .row .grid_item[x=" + x + "][y=" + y + "]").hasClass("wall");
var bNaoTemLixeira = !$("#search_grid .row .grid_item[x=" + x + "][y=" + y + "]").hasClass("lixeira");
var bNaoTemRecarga = !$("#search_grid .row .grid_item[x=" + x + "][y=" + y + "]").hasClass("pontoRecarga");
return bNaoTemParede && bNaoTemLixeira && bNaoTemRecarga;
}
ValidSqm = function(x, y) {
return ((x >= 0 && x < gridSize) && (y >= 0 && y < gridSize));
}
// javascript-astar
// http://github.com/bgrins/javascript-astar
// Freely distributable under the MIT License.
// Implements the astar search algorithm in javascript using a binary heap.
var astar = {
init: function(grid) {
for (var x = 0, xl = grid.length; x < xl; x++) {
for (var y = 0, yl = grid[x].length; y < yl; y++) {
var node = grid[x][y];
node.f = 0;
node.g = 0;
node.h = 0;
node.cost = node.type;
node.visited = false;
node.closed = false;
node.parent = null;
}
}
},
heap: function() {
return new BinaryHeap(function(node) {
return node.f;
});
},
search: function(grid, start, end, diagonal, heuristic) {
astar.init(grid);
heuristic = heuristic || astar.manhattan;
diagonal = !!diagonal;
var openHeap = astar.heap();
openHeap.push(start);
while (openHeap.size() > 0) {
// Grab the lowest f(x) to process next. Heap keeps this sorted for us.
var currentNode = openHeap.pop();
// End case -- result has been found, return the traced path.
if (currentNode === end) {
var curr = currentNode;
var ret = [];
while (curr.parent) {
ret.push(curr);
curr = curr.parent;
}
return ret.reverse();
}
// Normal case -- move currentNode from open to closed, process each of its neighbors.
currentNode.closed = true;
// Find all neighbors for the current node. Optionally find diagonal neighbors as well (false by default).
var neighbors = astar.neighbors(grid, currentNode, diagonal);
for (var i = 0, il = neighbors.length; i < il; i++) {
var neighbor = neighbors[i];
if (neighbor.closed || neighbor.isWall() || $("#search_grid .row .grid_item[x=" + neighbor.x + "][y=" + neighbor.y + "]").hasClass("pontoRecarga") || $("#search_grid .row .grid_item[x=" + neighbor.x + "][y=" + neighbor.y + "]").hasClass("lixeira")) {
// Not a valid node to process, skip to next neighbor.
continue;
}
// The g score is the shortest distance from start to current node.
// We need to check if the path we have arrived at this neighbor is the shortest one we have seen yet.
var gScore = currentNode.g + neighbor.cost;
var beenVisited = neighbor.visited;
if (!beenVisited || gScore < neighbor.g) {
// Found an optimal (so far) path to this node. Take score for node to see how good it is.
neighbor.visited = true;
neighbor.parent = currentNode;
neighbor.h = neighbor.h || heuristic(neighbor.pos, end.pos);
neighbor.g = gScore;
neighbor.f = neighbor.g + neighbor.h;
if (!beenVisited) {
// Pushing to heap will put it in proper place based on the 'f' value.
openHeap.push(neighbor);
} else {
// Already seen the node, but since it has been rescored we need to reorder it in the heap
openHeap.rescoreElement(neighbor);
}
}
}
}
// No result was found - empty array signifies failure to find path.
return [];
},
manhattan: function(pos0, pos1) {
// See list of heuristics: http://theory.stanford.edu/~amitp/GameProgramming/Heuristics.html
var d1 = Math.abs(pos1.x - pos0.x);
var d2 = Math.abs(pos1.y - pos0.y);
return d1 + d2;
},
neighbors: function(grid, node, diagonals) {
var ret = [];
var x = node.x;
var y = node.y;
// West
if (grid[x - 1] && grid[x - 1][y]) {
ret.push(grid[x - 1][y]);
}
// East
if (grid[x + 1] && grid[x + 1][y]) {
ret.push(grid[x + 1][y]);
}
// South
if (grid[x] && grid[x][y - 1]) {
ret.push(grid[x][y - 1]);
}
// North
if (grid[x] && grid[x][y + 1]) {
ret.push(grid[x][y + 1]);
}
if (diagonals) {
// Southwest
if (grid[x - 1] && grid[x - 1][y - 1]) {
ret.push(grid[x - 1][y - 1]);
}
// Southeast
if (grid[x + 1] && grid[x + 1][y - 1]) {
ret.push(grid[x + 1][y - 1]);
}
// Northwest
if (grid[x - 1] && grid[x - 1][y + 1]) {
ret.push(grid[x - 1][y + 1]);
}
// Northeast
if (grid[x + 1] && grid[x + 1][y + 1]) {
ret.push(grid[x + 1][y + 1]);
}
}
return ret;
}
};
// javascript-astar
// http://github.com/bgrins/javascript-astar
// Freely distributable under the MIT License.
// Includes Binary Heap (with modifications) from Marijn Haverbeke.
// http://eloquentjavascript.net/appendix2.html
var GraphNodeType = {
OPEN: 0,
WALL: 1
};
// Creates a Graph class used in the astar search algorithm.
function Graph(grid) {
var nodes = [];
for (var x = 0; x < grid.length; x++) {
nodes[x] = [];
for (var y = 0, row = grid[x]; y < row.length; y++) {
nodes[x][y] = new GraphNode(x, y, row[y]);
}
}
this.input = grid;
this.nodes = nodes;
}
Graph.prototype.toString = function() {
var graphString = "\n";
var nodes = this.nodes;
var rowDebug, row, y, l;
for (var x = 0, len = nodes.length; x < len; x++) {
rowDebug = "";
row = nodes[x];
for (y = 0, l = row.length; y < l; y++) {
rowDebug += row[y].type + " ";
}
graphString = graphString + rowDebug + "\n";
}
return graphString;
};
function GraphNode(x, y, type) {
this.data = {};
this.x = x;
this.y = y;
this.pos = {
x: x,
y: y
};
this.type = type;
}
GraphNode.prototype.toString = function() {
return "[" + this.x + " " + this.y + "]";
};
GraphNode.prototype.isWall = function() {
return this.type === GraphNodeType.WALL;
};
function BinaryHeap(scoreFunction) {
this.content = [];
this.scoreFunction = scoreFunction;
}
BinaryHeap.prototype = {
push: function(element) {
// Add the new element to the end of the array.
this.content.push(element);
// Allow it to sink down.
this.sinkDown(this.content.length - 1);
},
pop: function() {
// Store the first element so we can return it later.
var result = this.content[0];
// Get the element at the end of the array.
var end = this.content.pop();
// If there are any elements left, put the end element at the
// start, and let it bubble up.
if (this.content.length > 0) {
this.content[0] = end;
this.bubbleUp(0);
}
return result;
},
remove: function(node) {
var i = this.content.indexOf(node);
// When it is found, the process seen in 'pop' is repeated
// to fill up the hole.
var end = this.content.pop();
if (i !== this.content.length - 1) {
this.content[i] = end;
if (this.scoreFunction(end) < this.scoreFunction(node)) {
this.sinkDown(i);
} else {
this.bubbleUp(i);
}
}
},
size: function() {
return this.content.length;
},
rescoreElement: function(node) {
this.sinkDown(this.content.indexOf(node));
},
sinkDown: function(n) {
// Fetch the element that has to be sunk.
var element = this.content[n];
// When at 0, an element can not sink any further.
while (n > 0) {
// Compute the parent element's index, and fetch it.
var parentN = ((n + 1) >> 1) - 1,
parent = this.content[parentN];
// Swap the elements if the parent is greater.
if (this.scoreFunction(element) < this.scoreFunction(parent)) {
this.content[parentN] = element;
this.content[n] = parent;
// Update 'n' to continue at the new position.
n = parentN;
}
// Found a parent that is less, no need to sink any further.
else {
break;
}
}
},
bubbleUp: function(n) {
// Look up the target element and its score.
var length = this.content.length,
element = this.content[n],
elemScore = this.scoreFunction(element);
while (true) {
// Compute the indices of the child elements.
var child2N = (n + 1) << 1,
child1N = child2N - 1;
// This is used to store the new position of the element,
// if any.
var swap = null;
var child1Score;
// If the first child exists (is inside the array)...
if (child1N < length) {
// Look it up and compute its score.
var child1 = this.content[child1N];
child1Score = this.scoreFunction(child1);
// If the score is less than our element's, we need to swap.
if (child1Score < elemScore) {
swap = child1N;
}
}
// Do the same checks for the other child.
if (child2N < length) {
var child2 = this.content[child2N],
child2Score = this.scoreFunction(child2);
if (child2Score < (swap === null ? elemScore : child1Score)) {
swap = child2N;
}
}
// If the element needs to be moved, swap it, and continue.
if (swap !== null) {
this.content[n] = this.content[swap];
this.content[swap] = element;
n = swap;
}
// Otherwise, we are done.
else {
break;
}
}
}
};
html,
body {
height: 100%;
margin: 0;
}
.buttons {
float: right;
position: relative;
right: 10px;
top: 10px;
}
.buttons a {
text-decoration: none;
}
#content {
margin: 0 auto;
width: 98%;
text-align: center;
}
#controls {
text-align: center;
margin-bottom: 25px;
padding: 5px;
}
#search_grid {
width: 300px;
height: 300px;
position: relative;
}
#main {
margin: auto;
width: 20%;
}
.grid_item {
display: block;
border: 1px solid #bbb;
float: left;
line-height: 12px;
font-size: 10px;
}
.grid_item.wall {
background-color: #000000;
}
.grid_item.weight1 {
background-color: #ffffff;
}
.agent {
text-align: center;
color: grey;
font-size: 20px;
background-color: red !important;
color: blue;
font-weight: bold;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<body>
<div id="content">
<input type="button" id="btnInit" value="Start" /><br><br>
<div id="main">
<div id="search_grid">Loading...</div>
</div>
</div>
<div id="footer"></div>
</body>
Related
EDIT: Big edit from ealier
I have achieved: the ultimate for-loop HELL.
What it does: scans an image and finds a 40 by 40 pixel square that has every pixel within it approximately the same color.
The problem: The code doesn't work as intended. Unsure why, but all my attempts to debug are in vain.
jimp.read('jeffrey.png')
.then(image => {
console.log(jimp.intToRGBA(image.getPixelColor(0,0)))
console.log(image.bitmap.width)
console.log(image.bitmap.height)
var breakAll = false;
var FINALX;
var FINALY;
var doneCounter = 0;
//40 by 40 pixels needed for qr code. Thisis barcode, so make it 40 by 80 or smthn, figure out that x thing.
for(var x = 0; x < image.bitmap.width; x++) {
var breakThis = false;
console.log(x + " is x")
if(breakAll == true) {
break;
}
var verticalStart = 0;
for(var y1 = verticalStart; y1 < image.bitmap.height; y1++) {
if(breakAll == true) {
break;
}
var tempStandardR = jimp.intToRGBA(image.getPixelColor(x,y1)).r;
var tempStandardG = jimp.intToRGBA(image.getPixelColor(x,y1)).g;
var tempStandardB = jimp.intToRGBA(image.getPixelColor(x,y1)).b;
var verticalCounter = 0;
for(var y2 = y1; y2 < image.bitmap.height; y2++) {
if(breakAll == true) {
break;
}
if(verticalCounter >= 40) {
//Then do X stuff
//horizcountertim
for(var y3 = y1; y3 < y1 + 40; y3++) {
if(breakAll == true) {
break;
}
breakThis = false;
var horizontalCounter = 0;
var tempStandardR3 = jimp.intToRGBA(image.getPixelColor(x,y3)).r;
var tempStandardG3 = jimp.intToRGBA(image.getPixelColor(x,y3)).g;
var tempStandardB3 = jimp.intToRGBA(image.getPixelColor(x,y3)).b;
for(var x2 = x; x2 < x + 41; x2++) {
if(breakAll == true) {
break;
}
console.log(doneCounter)
if(doneCounter >= 40) {
//SUCESS!!!!!!
//THE SPOT HAS BEEN FOUND AT (x minus 40, y minus 40).
//insert other image in this image at above coordinates. Wow I highly doubt this works.
console.log('SUCESS!!!!!!!!!')
FINALX = x2-40;
FINALY = y3-40;
breakAll = true;
break;
}
if(breakAll == true) {
break;
}
var tempStandardR4 = jimp.intToRGBA(image.getPixelColor(x2,y3)).r;
var tempStandardG4 = jimp.intToRGBA(image.getPixelColor(x2,y3)).g;
var tempStandardB4 = jimp.intToRGBA(image.getPixelColor(x2,y3)).b;
if((((tempStandardR3 - tempStandardR4) <= 20) && ((tempStandardR3 - tempStandardR4) >= -20)) && (((tempStandardG3 - tempStandardG4) <= 20) && ((tempStandardG3 - tempStandardG4) >= -20)) && (((tempStandardB3 - tempStandardB4) <= 20) && ((tempStandardB3 - tempStandardB4) >= -20))) {
horizontalCounter++;
if(horizontalCounter == 40) {
horizontalCounter = 0;
doneCounter++;
break;
}
// if((x2 - x >= 39) && (y3 - y1) >= 39) {
if(breakAll == true) {
break;
}
}
else {
horizontalCounter = 0;
verticalCounter = 0;
doneCounter = 0;
console.log('donecounter reset')
verticalStart = y3;
//y2 = y3;
breakThis = true;
break;
}
}
if(breakAll == true) {
break;
}
if(breakThis = true) {
break;
}
}
if(breakThis = true) {
breakThis = false;
break;
}
}
if(breakAll == true) {
break;
}
var tempStandardR2 = jimp.intToRGBA(image.getPixelColor(x,y2)).r;
var tempStandardG2 = jimp.intToRGBA(image.getPixelColor(x,y2)).g;
var tempStandardB2 = jimp.intToRGBA(image.getPixelColor(x,y2)).b;
if((((tempStandardR - tempStandardR2) <= 20) && ((tempStandardR - tempStandardR2) >= -20)) && (((tempStandardG - tempStandardG2) <= 20) && ((tempStandardG - tempStandardG2) >= -20)) && (((tempStandardB - tempStandardB2) <= 20) && ((tempStandardB - tempStandardB2) >= -20))) {
verticalCounter++;
}
else {
verticalCounter = 0;
verticalStart = y2;
console.log('lvl1 reset')
doneCounter = 0;
break;
}
}
}
}
console.log(' done');
console.log(FINALX + " = x")
console.log(FINALY + " = y")
})
.catch(err => {
console.log(err);
})
Each of the tempStandards are the RGB value for that individual pixel.
All of the for loops are to get a 40 by 40 open grid.
The issue I do see is a problem, but am baffled as to why, is doneCounter, that is supposed to ++ every time a horizontal counter has reached 40 and thus finished its horizontal check of one row of the 40 by 40 grid.
The issue when console logging doneCounter is, it console logs the same value twice, which makes no sense since its within the same for loop that has an if else statement that either adds to donecounter or resets it to 0.
EDIT: I scrapped the above code to try and remake it entirely to see if that would let it work, still failed though and not a clue as to why: Below is the updated attempt:
jimp.read('jeffrey.png')
.then(image => {
console.log(jimp.intToRGBA(image.getPixelColor(0,0)))
console.log(image.bitmap.width)
console.log(image.bitmap.height)
var breakAll = false;
var FINALX;
var FINALY;
var doneCounter = 0;
var veritcalCounter = 0;
var verticalStart = 0;
var horizontalCounter = 0;
var breakAll = false;
var breakThis = false;
//40 by 40 pixels needed for qr code. Thisis barcode, so make it 40 by 80 or smthn, figure out that x thing.
for(var x = 0; x < image.bitmap.width; x++) {
console.log(x)
verticalCounter = 0;
for(var y = 0; y < image.bitmap.height; y++) {
var tempStandardR = jimp.intToRGBA(image.getPixelColor(x,verticalStart)).r;
var tempStandardG = jimp.intToRGBA(image.getPixelColor(x,verticalStart)).g;
var tempStandardB = jimp.intToRGBA(image.getPixelColor(x,verticalStart)).b;
var tempStandardR2 = jimp.intToRGBA(image.getPixelColor(x,y)).r;
var tempStandardG2 = jimp.intToRGBA(image.getPixelColor(x,y)).g;
var tempStandardB2 = jimp.intToRGBA(image.getPixelColor(x,y)).b;
if((((tempStandardR - tempStandardR2) <= 20) && ((tempStandardR - tempStandardR2) >= -20)) && (((tempStandardG - tempStandardG2) <= 20) && ((tempStandardG - tempStandardG2) >= -20)) && (((tempStandardB - tempStandardB2) <= 20) && ((tempStandardB - tempStandardB2) >= -20))) {
verticalCounter++;
if(verticalCounter == 40) {
verticalCounter = 0;
for(var y1 = y-40; y1 < y; y1++) {
horizontalCounter = 0;
for(var x1 = x; x1 < x+41; x1++) {
var tempStandardR3 = jimp.intToRGBA(image.getPixelColor(x,y1)).r;
var tempStandardG3 = jimp.intToRGBA(image.getPixelColor(x,y1)).g;
var tempStandardB3 = jimp.intToRGBA(image.getPixelColor(x1,y1)).b;
var tempStandardR4 = jimp.intToRGBA(image.getPixelColor(x1,y1)).r;
var tempStandardG4 = jimp.intToRGBA(image.getPixelColor(x1,y1)).g;
var tempStandardB4 = jimp.intToRGBA(image.getPixelColor(x1,y1)).b;
if((((tempStandardR3 - tempStandardR4) <= 20) && ((tempStandardR3 - tempStandardR4) >= -20)) && (((tempStandardG3 - tempStandardG4) <= 20) && ((tempStandardG3 - tempStandardG4) >= -20)) && (((tempStandardB3 - tempStandardB4) <= 20) && ((tempStandardB3 - tempStandardB4) >= -20))) {
if(x1 == x+40) {
doneCounter++;
if(doneCounter == 39) {
//SUCESS!!!!!!
//THE SPOT HAS BEEN FOUND AT (x minus 40, y minus 40).
//insert other image in this image at above coordinates. Wow I highly doubt this works.
console.log('SUCESS!!!!!!!!!')
FINALX = x;
FINALY = y1-40;
breakAll = true;
break;
}
break;
}
}
else {
verticalCounter = 0;
horizontalCounter = 0;
doneCounter = 0;
y = y1;
breakThis = true;
break;
}
if(breakAll == true) {
break;
}
}
if(breakThis == true) {
breakThis = false;
break;
}
if(breakAll == true) {
break;
}
}
if(breakAll == true) {
break;
}
}
if(breakAll == true) {
break;
}
}
else {
verticalCounter = 0;
verticalStart = 0;
}
if(breakAll == true) {
break;
}
}
if(breakAll == true) {
break;
}
}
console.log(' done');
console.log(FINALX + " = x")
console.log(FINALY + " = y")
})
.catch(err => {
console.log(err);
})
I am building a JavaScript game, based on Mario.
I have already implemented "physics" for lava, so when the character would fall into it, they would lose 1 life. What I am trying to achieve is that lava drops would act the same, so on contact they would hurt the character and make it respawn at the start of the area / level.
The code can be found here and seen below:
//////////////////////////////
// This is only a demo code //
//////////////////////////////
var LEVELS = [
[" ",
" ",
" ",
" ",
" xxx ",
" xx!xx ",
" x!!!x ",
" xx!xx ",
" x xvx ",
" x x",
" x x",
" x x",
" x x",
" x x",
" x # xxxxx o x",
" xxxxxx xxxxxxxxx xxxxxxxxxx",
" x x ",
" x!!!!!x ",
" x!!!!!x ",
" xxxxxxx ",
" "]
];
var life = 3;
document.getElementById("life").innerHTML = ("Lives left: " + life);
function Vector(x, y) {
this.x = x; this.y = y;
}
Vector.prototype.plus = function(other) {
return new Vector(this.x + other.x, this.y + other.y);
};
Vector.prototype.times = function(scale) {
return new Vector(this.x * scale, this.y * scale);
};
// Note: uppercase words are used that means constructor are values
var actorchars = {
"#": Player,
"o": Coin,
"|": Lava,
"v": Lava
};
function Player(pos) {
this.pos = pos.plus(new Vector(0, -.5));
this.size = new Vector(.5, 1);
this.speed = new Vector(0, 0);
}
Player.prototype.type = "player";
function Lava(pos, ch) {
this.pos = pos;
this.size = new Vector(1, 1);
if (ch === "|")
this.speed = new Vector(0, 2);
else if (ch === 'v'){
this.speed = new Vector(0, 3);
this.repeatPos = pos;
}
}
Lava.prototype.type = "Lava";
function Coin(pos) {
this.basePos = this.pos = pos;
this.size = new Vector(.6, .6);
// take a look back
this.wobble = Math.random() * Math.PI * 2;
}
Coin.prototype.type = "coin";
Level.prototype.isFinished = function() {
return this.status !== null && this.finishDelay < 0;
};
function Level(plan) {
this.width = plan[0].length;
this.height = plan.length;
this.grid = [];
this.actors = [];
for (var y = 0; y < this.height; y++) {
var line = plan[y], gridLine = [];
for (var x = 0; x < this.width; x++) {
var ch = line[x], fieldType = null;
var Actor = actorchars[ch];
if (Actor)
this.actors.push(new Actor(new Vector(x, y), ch));
else if (ch === "x")
fieldType = "wall";
else if (ch === "!")
fieldType = "lava";
else if (ch === "|")
fieldType = "lava";
else if (ch === "v"){
fieldType = "lava";
console.log(fieldType);
}
gridLine.push(fieldType);
}
this.grid.push(gridLine);
}
this.player = this.actors.filter(function(actor) {
return actor.type === "player";
})[0];
this.status = this.finishDelay = null;
}
function element(name, className) {
var elem = document.createElement(name);
if(className) elem.className = className;
return elem;
}
function DOMDisplay(parent, level) {
this.wrap = parent.appendChild(element("div", "game"));
this.level = level;
this.wrap.appendChild(this.drawBackground());
this.actorLayer = null;
this.drawFrame();
}
var scale = 15;
DOMDisplay.prototype.drawBackground = function() {
var table = element("table", "background");
table.style.width = this.level.width * scale + "px";
table.style.height = this.level.height * scale + "px";
this.level.grid.forEach(function(row) {
var rowElement = table.appendChild(element("tr"));
rowElement.style.height = scale + "px";
row.forEach(function(type) {
rowElement.appendChild(element("td", type));
});
});
return table;
};
DOMDisplay.prototype.drawActors = function() {
var wrap = element("div");
this.level.actors.forEach(function(actor) {
var rect = wrap.appendChild(element("div", "actor " + actor.type));
rect.style.width = actor.size.x * scale + "px";
rect.style.height = actor.size.y * scale + "px";
rect.style.left = actor.pos.x * scale + "px";
rect.style.top = actor.pos.y * scale + "px";
});
return wrap;
};
DOMDisplay.prototype.drawFrame = function() {
if (this.actorLayer)
this.wrap.removeChild(this.actorLayer);
this.actorLayer = this.wrap.appendChild(this.drawActors());
this.wrap.className = "game " + (this.level.status || "");
this.scrollPlayerIntoView();
};
// clear it later
DOMDisplay.prototype.scrollPlayerIntoView = function() {
var width = this.wrap.clientWidth;
var height = this.wrap.clientHeight;
var margin = width / 3;
// The viewport
var left = this.wrap.scrollLeft, right = left + width;
var top = this.wrap.scrollTop, bottom = top + height;
var player = this.level.player;
var center = player.pos.plus(player.size.times(0.5))
.times(scale);
if (center.x < left + margin)
this.wrap.scrollLeft = center.x - margin;
else if (center.x > right - margin)
this.wrap.scrollLeft = center.x + margin - width;
if (center.y < top + margin)
this.wrap.scrollTop = center.y - margin;
else if (center.y > bottom - margin)
this.wrap.scrollTop = center.y + margin - height;
};
DOMDisplay.prototype.clear = function() {
this.wrap.parentNode.removeChild(this.wrap);
};
Level.prototype.obstacleAt = function(pos, size) {
var xStart = Math.floor(pos.x);
var xEnd = Math.ceil(pos.x + size.x);
var yStart = Math.floor(pos.y);
var yEnd = Math.ceil(pos.y + size.y);
if (xStart < 0 || xEnd > this.width || yStart < 0)
return "wall";
if (yEnd > this.height)
return "lava";
for (var y = yStart; y < yEnd; y++) {
for (var x = xStart; x < xEnd; x++) {
var fieldType = this.grid[y][x];
if (fieldType) return fieldType;
}
}
};
Level.prototype.actorAt = function(actor) {
for (var i = 0; i < this.actors.length; i++) {
var other = this.actors[i];
if (other != actor &&
actor.pos.x + actor.size.x > other.pos.x &&
actor.pos.x < other.pos.x + other.size.x &&
actor.pos.y + actor.size.y > other.pos.y &&
actor.pos.y < other.pos.y + other.size.y)
return other;
}
};
var maxStep = 0.05;
Level.prototype.animate = function(step, keys) {
if (this.status !== null)
this.finishDelay -= step;
while (step > 0) {
var thisStep = Math.min(step, maxStep);
this.actors.forEach(function(actor) {
actor.act(thisStep, this, keys);
}, this);
step -= thisStep;
}
};
Lava.prototype.act = function(step, level) {
var newPos = this.pos.plus(this.speed.times(step));
if (!level.obstacleAt(newPos, this.size))
this.pos = newPos;
else if (this.repeatPos)
this.pos = this.repeatPos;
else
this.speed = this.speed.times(-1);
};
var wobbleSpeed = 8, wobbleDist = 0.07;
Coin.prototype.act = function(step) {
this.wobble += step * wobbleSpeed;
var wobblePos = Math.sin(this.wobble) * wobbleDist;
this.pos = this.basePos.plus(new Vector(0, wobblePos));
};
var playerXSpeed = 10;
Player.prototype.moveX = function(step, level, keys) {
this.speed.x = 0;
if (keys.left) this.speed.x -= playerXSpeed;
if (keys.right) this.speed.x += playerXSpeed;
var motion = new Vector(this.speed.x * step, 0);
var newPos = this.pos.plus(motion);
var obstacle = level.obstacleAt(newPos, this.size);
if (obstacle)
level.playerTouched(obstacle);
else
this.pos = newPos;
};
var gravity = 30;
var jumpSpeed = 17;
Player.prototype.moveY = function(step, level, keys) {
this.speed.y += step * gravity;
var motion = new Vector(0, this.speed.y * step);
var newPos = this.pos.plus(motion);
var obstacle = level.obstacleAt(newPos, this.size);
if (obstacle) {
level.playerTouched(obstacle);
if (keys.up && this.speed.y > 0)
this.speed.y = -jumpSpeed;
else
this.speed.y = 0;
} else {
this.pos = newPos;
}
};
Player.prototype.act = function(step, level, keys) {
this.moveX(step, level, keys);
this.moveY(step, level, keys);
var otherActor = level.actorAt(this);
if (otherActor)
level.playerTouched(otherActor.type, otherActor);
// Losing animation
if (level.status == "lost") {
this.pos.y += step;
this.size.y -= step;
}
};
Level.prototype.playerTouched = function(type, actor) {
if (type == "lava" && this.status === null) {
this.status = "lost";
life -= 1;
console.log(life);
document.getElementById("life").innerHTML = ("Lives left: " + life);
if(life < 0) {
sessionStorage.setItem("reloading", "true");
document.location.reload();
}
this.finishDelay = 1;
} else if (type == "coin") {
this.actors = this.actors.filter(function(other) {
return other != actor;
});
if (!this.actors.some(function(actor) {
return actor.type == "coin";
})) {
life += 1;
document.getElementById("life").innerHTML = ("Lives left: " + life);
this.status = "won";
this.finishDelay = 1;
}
}
};
var arrowCodes = {37: "left", 38: "up", 39: "right"};
function trackKeys(codes) {
var pressed = Object.create(null);
function handler(event) {
if (codes.hasOwnProperty(event.keyCode)) {
var down = event.type == "keydown";
pressed[codes[event.keyCode]] = down;
event.preventDefault();
}
}
addEventListener("keydown", handler);
addEventListener("keyup", handler);
return pressed;
}
function runAnimation(frameFunc) {
var lastTime = null;
function frame(time) {
var stop = false;
if (lastTime !== null) {
var timeStep = Math.min(time - lastTime, 100) / 1000;
stop = frameFunc(timeStep) === false;
}
lastTime = time;
if (!stop)
requestAnimationFrame(frame);
}
requestAnimationFrame(frame);
}
var arrows = trackKeys(arrowCodes);
function runLevel(level, Display, andThen) {
var display = new Display(document.body, level);
runAnimation(function(step) {
level.animate(step, arrows);
display.drawFrame(step);
if (level.isFinished()) {
display.clear();
if (andThen)
andThen(level.status);
return false;
}
});
}
var lives = function() {
ctx.font = "20px Courier";
ctx.fontFamily = "monospace";
ctx.fillStyle = "#666";
ctx.textAlign = "left";
ctx.textBaseline = "top";
ctx.fillText("Lives left: " + life, 10, 10);
};
function runGame(plans, Display) {
function startLevel(n) {
runLevel(new Level(plans[n]), Display, function(status) {
if (status == "lost") {
startLevel(n);
} else if (n < plans.length - 1)
startLevel(n + 1);
else
alert("You win!");
});
}
startLevel(0);
}
runGame(LEVELS, DOMDisplay);
body {
background: #222;
}
h2 {
color: #666;
font-family: monospace;
text-align: center;
}
.background {
table-layout: fixed;
border-spacing: 0;
}
.background td {
padding: 0;
}
.lava, .actor {
background: #e55;
}
.wall {
background: #444;
border: solid 3px #333;
box-sizing: content-box;
}
.actor {
position: absolute;
}
.coin {
background: #e2e838;
border-radius: 50%;
}
.player {
background: #335699;
box-shadow: none;
}
.lost .player {
background: #a04040;
}
.won .player {
background: green;
}
.game {
position: relative;
overflow: hidden;
}
#life {
font = 20px;
font-family: monospace;
color: #666;
text-align: left;
baseline: top;
margin-left: 30px;
font-weight: bold;
}
<h2>Simple JavaScript Game</h2>
<div id="life"></div>
So just a quick explanation, the following elements act as:
"x" represents a wall
"#" acts as a character
"!", "v" act as lava
"o" is a coin, which finishes the level by being collected
Current code:
Level.prototype.playerTouched = function(type, actor) {
if (type == "lava" && this.status === null) {
The problem is that you use different types for the "lava pool" and "lava drops".
The last one type is 'Lava' and not 'lava' as the first. So if you want to keep it that way is as simple as that:
Level.prototype.playerTouched = function(type, actor) {
if ((type == "lava" || type == "Lava") && this.status === null) {
With regards,
Chris Karanikas.
I have another question about game creation, that I already reached out for.
As I continued developing the game and tried to implement point counter I have encountered another issue.
It seems that sometimes the points are being counter instead of +1 to +2 or even +3.
I am suspecting incorrect placement of the code-part expo += 1 as it would (probably) get looped 2 (or multiple) times instead of once, but frankly, I am not sure.
The code can be found here or below:
var LEVELS = [
[" x x",
" xx x",
" xxx x x",
" xx!xx x ox",
" x!!!x x xx",
" xx!xx x x",
" x xvx x x",
" x xx x",
" x x x",
" x x x",
" x x xx",
" x x",
" x # xxxxx o x",
" xxxxxx xxxxxxxxx xxxxxxxxxxxxx",
" x x ",
" x!!!!!x ",
" x!!!!!x ",
" xxxxxxx ",
" "],
];
var life = 3;
var expo = 0;
document.getElementById("life").innerHTML = ("Lives left: " + life);
document.getElementById("expo").innerHTML = ("Points: " + expo);
function Vector(x, y) {
this.x = x; this.y = y;
}
Vector.prototype.plus = function(other) {
return new Vector(this.x + other.x, this.y + other.y);
};
Vector.prototype.times = function(scale) {
return new Vector(this.x * scale, this.y * scale);
};
// Note: uppercase words are used that means constructor are values
var actorchars = {
"#": Player,
"o": Coin,
"=": Lava,
"|": Lava,
"v": Lava,
"#": Lava
};
function Player(pos) {
this.pos = pos.plus(new Vector(0, -.5));
this.size = new Vector(.5, 1);
this.speed = new Vector(0, 0);
}
Player.prototype.type = "player";
function Lava(pos, ch) {
this.pos = pos;
this.size = new Vector(1, 1);
if (ch === "=")
this.speed = new Vector(2, 0);
else if (ch === '|')
this.speed = new Vector(0, 2);
else if (ch === 'v'){
this.speed = new Vector(0, 5); // new Vector(0, 3);
this.repeatPos = pos;
} else if (ch === '#'){
this.speed = new Vector(0, 10);
}
}
Lava.prototype.type = "lava"
//Lava.prototype.type = "Lava";
function Coin(pos) {
this.basePos = this.pos = pos;
this.size = new Vector(.6, .6);
// take a look back
this.wobble = Math.random() * Math.PI * 2;
}
Coin.prototype.type = "coin";
Level.prototype.isFinished = function() {
return this.status !== null && this.finishDelay < 0;
};
function Level(plan) {
this.width = plan[0].length;
this.height = plan.length;
this.grid = [];
this.actors = [];
for (var y = 0; y < this.height; y++) {
var line = plan[y], gridLine = [];
for (var x = 0; x < this.width; x++) {
var ch = line[x], fieldType = null;
var Actor = actorchars[ch];
if (Actor)
this.actors.push(new Actor(new Vector(x, y), ch));
else if (ch === "x")
fieldType = "wall";
else if (ch === "!")
fieldType = "lava";
else if (ch === "|")
fieldType = "lava";
else if (ch === "=")
fieldType = "lava";
else if (ch === "#")
fieldType = "lava";
else if (ch === "v"){
fieldType = "lava";
console.log(fieldType);
}
gridLine.push(fieldType);
}
this.grid.push(gridLine);
}
this.player = this.actors.filter(function(actor) {
return actor.type === "player";
})[0];
this.status = this.finishDelay = null;
}
function element(name, className) {
var elem = document.createElement(name);
if(className) elem.className = className;
return elem;
}
function DOMDisplay(parent, level) {
this.wrap = parent.appendChild(element("div", "game"));
this.level = level;
this.wrap.appendChild(this.drawBackground());
this.actorLayer = null;
this.drawFrame();
}
var scale = 15;
DOMDisplay.prototype.drawBackground = function() {
var table = element("table", "background");
table.style.width = this.level.width * scale + "px";
table.style.height = this.level.height * scale + "px";
this.level.grid.forEach(function(row) {
var rowElement = table.appendChild(element("tr"));
rowElement.style.height = scale + "px";
row.forEach(function(type) {
rowElement.appendChild(element("td", type));
});
});
return table;
};
DOMDisplay.prototype.drawActors = function() {
var wrap = element("div");
this.level.actors.forEach(function(actor) {
var rect = wrap.appendChild(element("div", "actor " + actor.type));
rect.style.width = actor.size.x * scale + "px";
rect.style.height = actor.size.y * scale + "px";
rect.style.left = actor.pos.x * scale + "px";
rect.style.top = actor.pos.y * scale + "px";
});
return wrap;
};
DOMDisplay.prototype.drawFrame = function() {
if (this.actorLayer)
this.wrap.removeChild(this.actorLayer);
this.actorLayer = this.wrap.appendChild(this.drawActors());
this.wrap.className = "game " + (this.level.status || "");
this.scrollPlayerIntoView();
};
// clear it later
DOMDisplay.prototype.scrollPlayerIntoView = function() {
var width = this.wrap.clientWidth;
var height = this.wrap.clientHeight;
var margin = width / 3;
// The viewport
var left = this.wrap.scrollLeft, right = left + width;
var top = this.wrap.scrollTop, bottom = top + height;
var player = this.level.player;
var center = player.pos.plus(player.size.times(0.5))
.times(scale);
if (center.x < left + margin)
this.wrap.scrollLeft = center.x - margin;
else if (center.x > right - margin)
this.wrap.scrollLeft = center.x + margin - width;
if (center.y < top + margin)
this.wrap.scrollTop = center.y - margin;
else if (center.y > bottom - margin)
this.wrap.scrollTop = center.y + margin - height;
};
DOMDisplay.prototype.clear = function() {
this.wrap.parentNode.removeChild(this.wrap);
};
Level.prototype.obstacleAt = function(pos, size) {
var xStart = Math.floor(pos.x);
var xEnd = Math.ceil(pos.x + size.x);
var yStart = Math.floor(pos.y);
var yEnd = Math.ceil(pos.y + size.y);
if (xStart < 0 || xEnd > this.width || yStart < 0)
return "wall";
if (yEnd > this.height)
return "lava";
for (var y = yStart; y < yEnd; y++) {
for (var x = xStart; x < xEnd; x++) {
var fieldType = this.grid[y][x];
if (fieldType) return fieldType;
}
}
};
Level.prototype.actorAt = function(actor) {
for (var i = 0; i < this.actors.length; i++) {
var other = this.actors[i];
if (other != actor &&
actor.pos.x + actor.size.x > other.pos.x &&
actor.pos.x < other.pos.x + other.size.x &&
actor.pos.y + actor.size.y > other.pos.y &&
actor.pos.y < other.pos.y + other.size.y)
return other;
}
};
var maxStep = 0.05;
Level.prototype.animate = function(step, keys) {
if (this.status !== null)
this.finishDelay -= step;
while (step > 0) {
var thisStep = Math.min(step, maxStep);
this.actors.forEach(function(actor) {
actor.act(thisStep, this, keys);
}, this);
step -= thisStep;
}
};
Lava.prototype.act = function(step, level) {
var newPos = this.pos.plus(this.speed.times(step));
if (!level.obstacleAt(newPos, this.size))
this.pos = newPos;
else if (this.repeatPos)
this.pos = this.repeatPos;
else
this.speed = this.speed.times(-1);
};
var wobbleSpeed = 8, wobbleDist = 0.07;
Coin.prototype.act = function(step) {
this.wobble += step * wobbleSpeed;
var wobblePos = Math.sin(this.wobble) * wobbleDist;
this.pos = this.basePos.plus(new Vector(0, wobblePos));
};
var playerXSpeed = 10;
Player.prototype.moveX = function(step, level, keys) {
this.speed.x = 0;
if (keys.left) this.speed.x -= playerXSpeed;
if (keys.right) this.speed.x += playerXSpeed;
var motion = new Vector(this.speed.x * step, 0);
var newPos = this.pos.plus(motion);
var obstacle = level.obstacleAt(newPos, this.size);
if (obstacle)
level.playerTouched(obstacle);
else
this.pos = newPos;
};
var gravity = 30;
var jumpSpeed = 17;
Player.prototype.moveY = function(step, level, keys) {
this.speed.y += step * gravity;
var motion = new Vector(0, this.speed.y * step);
var newPos = this.pos.plus(motion);
var obstacle = level.obstacleAt(newPos, this.size);
if (obstacle) {
level.playerTouched(obstacle);
if (keys.up && this.speed.y > 0)
this.speed.y = -jumpSpeed;
else
this.speed.y = 0;
} else {
this.pos = newPos;
}
};
Player.prototype.act = function(step, level, keys) {
this.moveX(step, level, keys);
this.moveY(step, level, keys);
var otherActor = level.actorAt(this);
if (otherActor)
level.playerTouched(otherActor.type, otherActor);
// Losing animation
if (level.status == "lost") {
this.pos.y += step;
this.size.y -= step;
}
};
Level.prototype.playerTouched = function(type, actor) {
//if (type == "lava" || type == "Lava" && this.status === null) { //DOESN'T SEEM TO WORK, FIND OUT WHY MASS DAMAGE
if (type == "lava" && this.status === null) {
this.status = "lost";
life -= 1;
console.log(life);
expo = 0;
document.getElementById("expo").innerHTML = ("Points: " + expo);
document.getElementById("life").innerHTML = ("Lives left: " + life);
if(life < 0) {
sessionStorage.setItem("reloading", "true");
document.location.reload();
}
this.finishDelay = 1;
} else if (type == "coin") {
this.actors = this.actors.filter(function(other) {
return other != actor;
});
if (!this.actors.some(function(actor) {
console.log("coin picked up")
expo += 1;
document.getElementById("expo").innerHTML = ("Points: " + expo);
return actor.type == "coin";
})) {
life += 1;
document.getElementById("life").innerHTML = ("Lives left: " + life);
this.status = "won";
this.finishDelay = 1;
}
}
};
var arrowCodes = {37: "left", 38: "up", 39: "right"};
function trackKeys(codes) {
var pressed = Object.create(null);
function handler(event) {
if (codes.hasOwnProperty(event.keyCode)) {
var down = event.type == "keydown";
pressed[codes[event.keyCode]] = down;
event.preventDefault();
}
}
addEventListener("keydown", handler);
addEventListener("keyup", handler);
return pressed;
}
function runAnimation(frameFunc) {
var lastTime = null;
function frame(time) {
var stop = false;
if (lastTime !== null) {
var timeStep = Math.min(time - lastTime, 100) / 1000;
stop = frameFunc(timeStep) === false;
}
lastTime = time;
if (!stop)
requestAnimationFrame(frame);
}
requestAnimationFrame(frame);
}
var arrows = trackKeys(arrowCodes);
function runLevel(level, Display, andThen) {
var display = new Display(document.body, level);
runAnimation(function(step) {
level.animate(step, arrows);
display.drawFrame(step);
if (level.isFinished()) {
display.clear();
if (andThen)
andThen(level.status);
return false;
}
});
}
var lives = function() {
ctx.font = "20px Courier";
ctx.fontFamily = "monospace";
ctx.fillStyle = "#666";
ctx.textAlign = "left";
ctx.textBaseline = "top";
ctx.fillText("Lives left: " + life, 10, 10);
};
function runGame(plans, Display) {
function startLevel(n) {
runLevel(new Level(plans[n]), Display, function(status) {
if (status == "lost") {
startLevel(n);
} else if (n < plans.length - 1)
startLevel(n + 1);
else
alert("You win!");
});
}
startLevel(0);
}
function restart() {
sessionStorage.setItem("reloading", "true");
document.location.reload();
}
runGame(LEVELS, DOMDisplay);
body {
background: #222;
}
h2 {
color: #666;
font-family: monospace;
text-align: center;
}
.background {
table-layout: fixed;
border-spacing: 0;
}
.background td {
padding: 0;
}
.lava, .actor {
background: #e55;
}
.wall {
background: #444;
border: solid 3px #333;
box-sizing: content-box;
}
.actor {
position: absolute;
}
.coin {
background: #e2e838;
border-radius: 50%;
}
.player {
background: #335699;
box-shadow: none;
}
.lost .player {
background: #a04040;
}
.won .player {
background: green;
}
.game {
position: relative;
overflow: hidden;
}
#life, #expo {
font = 20px;
font-family: monospace;
color: #666;
text-align: left;
baseline: top;
margin-left: 30px;
font-weight: bold;
}
input {
margin-left: 30px;
float: right;
position: relative;
top: -30px;
}
<!DOCTYPE html>
<html lang="en" >
<head>
<meta charset="UTF-8">
<title>game</title>
</head>
<body>
<h2>Simple JavaScript Game</h2>
<div id="life"></div>
<div id="expo"></div>
<div>
<input type="button" onclick="restart()" value="Restart"/>
</div>
</body>
</html>
I have already tried some options and quite interesting, was that if I removed all "lava sources" as variants or/and all collisions of those, the counter would work as it should.
Another level, that might get some ideas about my findings, found here.
I will really appreciate any help, Thanks
EDIT::
I would like to mess with the existing code as minimal as possible, if not, I will have to scrap the code and redo most of it (at least that's the only option I saw).
OK, so it seems that what fixed my issue was incorrect placement of the following sentences:
expo += 1;
document.getElementById("expo").innerHTML = ("Points: " + expo);
The placement of code before:
else if (type == "coin") {
this.actors = this.actors.filter(function(other) {
return other != actor;
});
if (!this.actors.some(function(actor) {
console.log("coin picked up")
expo += 1;
document.getElementById("expo").innerHTML = ("Points: " + expo);
return actor.type == "coin";
})) {
life += 1;
document.getElementById("life").innerHTML = ("Lives left: " + life);
this.status = "won";
this.finishDelay = 1;
}
The correct placement of the code:
else if (type == "coin") {
expo += 1;
document.getElementById("expo").innerHTML = ("Points: " + expo);
this.actors = this.actors.filter(function(other) {
return other != actor;
});
if (!this.actors.some(function(actor) {
console.log("coin picked up")
return actor.type == "coin";
})) {
life += 1;
document.getElementById("life").innerHTML = ("Lives left: " + life);
this.status = "won";
this.finishDelay = 1;
}
I've been trying to work out this simple javascript tic tac toe game. I'm trying to make the board size a variable and number needed in a row a variable. I've created a global variable for board size and number in a row. However it doesn't seem to be working. It makes the board the size I want but only a few of the squares will actually result in a 'Win'. Could someone please help me out ;).
Here is an image of one of the issues: http://imgur.com/oNK9ErK
I imagine the error occurs here:
function checkWinner(mArr) {
var winner = [false, ""];
for (var i = 0; i < mArr.length; i++) {
var hor = [],
ver = [],
diag = [];
if (mArr[i][3] !== "") {
//horizontal
if (i % 3 === 0) {
for (var j = 0; j < 3; j++) {
hor.push([mArr[i + j][3], i + j]);
}
if (hor.length === numinrow) {
winner = isWinner(hor);
if (winner[0]) {
return winner;
}
}
}
//vertical && diag/anti diag
if (i < 3) {
for (var j = 0; j + i < mArr.length; j += 3) {
ver.push([mArr[i + j][3], i + j]);
}
if (ver.length === numinrow) {
winner = isWinner(ver);
if (winner[0]) {
return winner;
}
}
if (i !== 1) {
for (var z = 0; z + i < mArr.length - i; z += (4 - i)) {
diag.push([mArr[i + z][3], i + z]);
}
if (diag.length === numinrow) {
winner = isWinner(diag);
if (winner[0]) {
return winner;
}
}
}
}
}
}
return winner;
}
Here is the entire .js
(function () {
var bsize = 5;
var numinrow = 3;
function Board(id, c, r) {
if (this instanceof Board) {
this.CANVAS = document.getElementById(id);
this.CTX = this.CANVAS.getContext("2d");
this.WIDTH = this.CANVAS.width || 0;
this.HEIGHT = this.CANVAS.height || 0;
this.COLS = c || bsize;
this.ROWS = r || bsize;
this.TILEWIDTH = (this.WIDTH / this.COLS);
this.moveCount = 0;
this.board = this.gameBoard(this.TILEWIDTH, this.COLS, this.ROWS);
this.CANVAS.addEventListener('selectstart', function (e) {
e.preventDefault();
return false;
}, false);
this.winner = [false, ""];
this.boardDisabled = false;
} else {
return new Board(id, c, r);
}
}
Board.prototype.draw = function () {
var ctx = this.CTX;
ctx.beginPath();
ctx.lineWidth = 5;
ctx.strokeStyle = "#168dd9";
// Draw column dividers
for (var i = 1; i <= this.COLS - 1; i++) {
ctx.moveTo(this.TILEWIDTH * i, 0);
ctx.lineTo(this.TILEWIDTH * i, this.HEIGHT);
}
//Draw horizontal dividers
for (var i = 1; i <= this.ROWS - 1; i++) {
ctx.moveTo(0, this.TILEWIDTH * i);
ctx.lineTo(this.WIDTH, this.TILEWIDTH * i);
}
ctx.stroke();
};
Board.prototype.gameBoard = function (t, c, r) {
var b = [],
count = 0;
// Create gameboard array with the following data:
// [x pos, y pos, tile count, empty string for move symbol (x or o)]
for (var y = 0; y < r; y++) {
for (var x = 0; x < c; x++) {
b.push([x * t, y * t, count++, ""]);
}
}
return b;
};
Board.prototype.updateScore = function () {
if (supports_html5_storage()) {
var p = sessionStorage.score || {
"score_x": 0,
"score_o": 0,
"score_tie": 0
},
w = "score_" + (this.winner[1][0] || "tie");
if (sessionStorage.score) {
p = JSON.parse(p);
}
p[w] ++;
sessionStorage.score = JSON.stringify(p);
this.updateScoreBoard();
}
};
Board.prototype.updateScoreBoard = function () {
if (supports_html5_storage()) {
var p = sessionStorage.score ? JSON.parse(sessionStorage.score) : {
"score_x": 0,
"score_o": 0,
"score_tie": 0
};
for (var s in p) {
if (p.hasOwnProperty(s)) {
document.getElementById(s).innerHTML = p[s];
}
}
}
};
Board.prototype.reset = function (x) {
var timer = x || 4000;
window.setTimeout(function () {
window.location.reload(false);
}, timer);
};
Board.prototype.resetScore = function () {
if (supports_html5_storage()) {
sessionStorage.removeItem("score");
this.updateScoreBoard();
}
};
Board.prototype.move = function (coor) {
var width = this.TILEWIDTH,
ctx = this.CTX,
board = this.board,
blen = board.length;
//Loop through and find tile that click was detected on
for (var i = 0; i < blen; i++) {
if (coor.x > board[i][0] && coor.y > board[i][1] && coor.x < board[i][0] + width && coor.y < board[i][1] + width) {
var x = board[i][0],
y = board[i][1],
validTile = board[i][3] === "";
if (validTile) {
if (this.moveCount++ % 2 === 1) {
moveO(x, y, width, ctx);
board[i][3] = "o";
} else {
moveX(x, y, width, ctx);
board[i][3] = "x";
}
}
//Check board for winner if move count is 5 or more
if (this.moveCount > 4) {
this.winner = checkWinner(board);
var w = this.winner,
winner = w[0],
shape = w[1][0],
boardDisabled = this.boardDisabled;
//If there is a winner, redraw winning tiles in red
if (winner && !boardDisabled) {
if (shape === "o") {
for (var j = 1; j < 4; j++) {
moveO(board[w[j][1]][0], board[w[j][1]]
[1], width, ctx, "red", 5);
}
} else {
for (var j = 1; j < 4; j++) {
moveX(board[w[j][1]][0], board[w[j][1]]
[1], width, ctx, "red", 5);
}
}
}
if ((winner || this.moveCount === board.length) && !boardDisabled) {
if (!winner) {
//If tie, redraw all moves in red
for (var j = 0; j < board.length; j++) {
if (board[j][3] === "o") {
moveO(board[j][0], board[j][1], width, ctx, "red", 5);
} else {
moveX(board[j][0], board[j][1], width, ctx, "red", 5);
}
}
}
this.boardDisabled = true;
this.updateScore();
this.reset();
}
}
break;
}
}
};
function checkWinner(mArr) {
var winner = [false, ""];
for (var i = 0; i < mArr.length; i++) {
var hor = [],
ver = [],
diag = [];
if (mArr[i][3] !== "") {
//horizontal
if (i % 3 === 0) {
for (var j = 0; j < 3; j++) {
hor.push([mArr[i + j][3], i + j]);
}
if (hor.length === numinrow) {
winner = isWinner(hor);
if (winner[0]) {
return winner;
}
}
}
//vertical && diag/anti diag
if (i < 3) {
for (var j = 0; j + i < mArr.length; j += 3) {
ver.push([mArr[i + j][3], i + j]);
}
if (ver.length === numinrow) {
winner = isWinner(ver);
if (winner[0]) {
return winner;
}
}
if (i !== 1) {
for (var z = 0; z + i < mArr.length - i; z += (4 - i)) {
diag.push([mArr[i + z][3], i + z]);
}
if (diag.length === numinrow) {
winner = isWinner(diag);
if (winner[0]) {
return winner;
}
}
}
}
}
}
return winner;
}
function isWinner(arr) {
arr.sort();
var w = arr[0][0] && arr[0][0] === arr[arr.length - 1][0] ? [true].concat(arr) : [false, ""];
return w;
}
function moveO(x, y, r, ctx, fill, lineW) {
var x = x + r / 2,
y = y + r / 2,
r = r / 2 - (r * 0.15);
ctx.beginPath();
ctx.lineWidth = lineW || 3;
ctx.strokeStyle = fill || "#333";
ctx.arc(x, y, r, 0, 2 * Math.PI);
ctx.stroke();
}
function moveX(x, y, w, ctx, fill, lineW) {
var pad = w * 0.15,
lineCoor = [
[
[x + pad, y + pad], //line 1 start
[x + w - pad, y + w - pad] //line 1 end
],
[
[x + pad, y + w - pad], //line 2 start
[x + w - pad, y + pad] //line 2 end
]
];
ctx.beginPath();
ctx.lineWidth = lineW || 3;
ctx.strokeStyle = fill || "#333";
for (var i = 0; i < 2; i++) {
ctx.moveTo(lineCoor[i][0][0], lineCoor[i][0][1]);
ctx.lineTo(lineCoor[i][1][0], lineCoor[i][1][1]);
}
ctx.stroke();
}
function clickTouch(e) {
var coor = b.CANVAS.relMouseCoords(e);
if (!b.winner[0]) {
b.move(coor);
}
}
function clickTouchReset(e) {
var target = e.target.id;
if (target === "resetScore" && confirm("Are you sure you want to reset the score?")) {
b.resetScore();
} else if (target === "resetGame") {
b.reset(1);
}
}
// Initialize Game
//BOARD SIZE
var b = new Board("game", bsize, bsize),
resetcon = document.getElementById("reset");
b.draw();
b.updateScoreBoard();
//Add event listeners for click or touch
window.addEventListener("click", clickTouch, false);
window.addEventListener("touchstart", clickTouch, false);
resetcon.addEventListener("click", clickTouchReset, false);
resetcon.addEventListener("touchstart", clickTouchReset, false);
})();
/*****
Get Mouse click coordinates within canvas
Modified to include touch events
Source: http://stackoverflow.com/a/9961416
******/
HTMLCanvasElement.prototype.relMouseCoords = function (event) {
var totalOffsetX = 0,
totalOffsetY = 0,
canvasX = 0,
canvasY = 0,
touch = event.touches,
currentElement = this;
do {
totalOffsetX += currentElement.offsetLeft;
totalOffsetY += currentElement.offsetTop;
}
while (currentElement = currentElement.offsetParent)
canvasX = (touch ? touch[0].pageX : event.pageX) - totalOffsetX;
canvasY = (touch ? touch[0].pageY : event.pageY) - totalOffsetY;
canvasX = Math.round(canvasX * (this.width / this.offsetWidth));
canvasY = Math.round(canvasY * (this.height / this.offsetHeight));
return {
x: canvasX,
y: canvasY
}
}
function supports_html5_storage() {
try {
return 'sessionStorage' in window && window.sessionStorage !== null;
} catch (e) {
return false;
}
}
I have made a snake game with processign.js and im trying to make the collision with itself. The problem is that it isnt working as it should.
var screen = 0;
var bg = color(60,150,60);
var snake;
var apple;
var bonus;
var nBonus = 0;
var gameOver = false;
var appleSize = 10;
var applePosX = round(random(10,width-appleSize)/10)*10;
var applePosY = round(random(10,height-appleSize)/10)*10;
var keys = [];
void keyPressed() {
keys[keyCode] = true;
};
void keyReleased() {
keys[keyCode] = false;
};
frameRate(10);
// collision with itself
// -----------------------------------------------------------------------
// ------------------------------- THE SNAKE -----------------------------
var Snake = function(x, y) {
this.x = x;
this.y = y;
this.len = 1;
this.size = 10;
this.snakePosX = 0;
this.snakePosY = 0;
this.points = 0;
this.positions = [];
this.moving = false;
this.apples = 0;
for(var i=0; i<this.len; i++) {
var posX = this.x-i*10;
var posY = this.y;
this.positions[i] = {x:posX, y:posY};
}
};
Snake.prototype.draw = function() {
fill(0);
stroke(255,255,255);
for(var i=0; i<this.positions.length; i++) {
rect(this.positions[i].x, this.positions[i].y, this.size, this.size);
}
};
Snake.prototype.move = function() {
if(gameOver === false) {
if(keys[UP]) {
this.snakePosY = -this.size;
this.snakePosX = 0;
this.moving = true;
}
if(keys[DOWN]) {
this.snakePosY = this.size;
this.snakePosX = 0;
this.moving = true;
}
if(keys[LEFT]) {
this.snakePosX = -this.size;
this.snakePosY = 0;
this.moving = true;
}
if(keys[RIGHT]) {
this.snakePosX = this.size;
this.snakePosY = 0;
this.moving = true;
}
}
if(this.moving == true) {
if(snake.positions.length == 1) {
this.positions[0].x += this.snakePosX;
this.positions[0].y += this.snakePosY;
}
else {
for(var i=1; i<this.positions.length; i++) {
this.positions[i-1].x = this.positions[i].x;
this.positions[i-1].y = this.positions[i].y;
this.positions[i].x += this.snakePosX;
this.positions[i].y += this.snakePosY;
}
}
}
};
Snake.prototype.checkColl = function() {
// collision with itself
if(this.positions.length>1) {
for(var i=0; i<this.positions.length; i++) {
if(this.positions[0].x > 350) {
text('holly crap', 100, 100);
}
}
}
// collision with walls
if(this.positions[0].x > width-this.size || this.positions[0].x < 0 || this.positions[0].y > height-this.size || this.positions[0].y < 0) {
gameOver = true;
gameIsOver();
}
// collision with apples
for(var i=0; i<this.positions.length; i++) {
if(this.positions[i].x >= apple.x && this.positions[i].x+10 <= apple.x+10 && this.positions[i].y >= apple.y && this.positions[i].y+10 <= apple.y+10) {
apple.draw();
this.apples ++;
this.points += 10;
this.positions.unshift({x:apple.x, y:apple.y});
apple.x = round(random(10,width-appleSize)/10)*10;
apple.y = round(random(10,height-appleSize)/10)*10;
if(this.apples > 1 && this.apples % 5 == 0) {
nBonus = 1;
}
}
}
// collision with bonus
if(this.positions[0].x >= bonus.x && this.positions[0].x+10 <= bonus.x+10 && this.positions[0].y >= bonus.y && this.positions[0].y+10 <= bonus.y+10) {
if(this.moving) {
bonus.x = round(random(10,width-appleSize)/10)*10;
bonus.y = round(random(10,height-appleSize)/10)*10;
nBonus = 0;
this.points += 10;
}
}
};
// ------------------------ THE APPLES -----------------------------------
var Apple = function(x, y) {
this.x = x;
this.y = y;
};
Apple.prototype.draw = function() {
fill(255,0,0);
noStroke();
rect(this.x, this.y, appleSize, appleSize);
};
// ------------------------ THE BONUS -----------------------------------
var Bonus = function(x, y) {
this.x = x;
this.y = y;
}
Bonus.prototype.draw = function() {
fill(150,0,0);
stroke(255,255,255)
rect(this.x, this.y, appleSize, appleSize);
};
// -----------------------------------------------------------------------
snake = new Snake(width/2, height/2);
apple = new Apple(applePosX, applePosY);
bonus = new Bonus(width/2, height/2);
// -----------------------------------------------------------------------
void gameIsOver() {
fill(0);
textAlign(CENTER);
text("Game Over\nPress 'S' to play again", width/2, height/2);
textAlign(LEFT);
if(keys[83]) {
screen = 2;
gameOver = false;
}
}
void playGame() {
if(screen === 0) {
if(mouseX >= width/2-50 && mouseY <= width/2+50 && mouseY >= height/2-15 && mouseY <= height/2+15) {
if(mousePressed) {
screen = 1;
}
}
}
}
void makeScreen() {
if(screen === 0) {
textAlign(CENTER);
textSize(30);
text('SNAKE GAME', width/2, 100);
stroke(255,255,255);
noFill();
rectMode(CENTER);
rect(width/2, height/2, 100, 30);
textSize(15);
text('Play', width/2, height/2+5);
textSize(11);
text('By Eskimopest', width/2, height-20);
textAlign(LEFT);
rectMode(LEFT);
playGame();
}
if(screen === 1) {
snake.draw();
snake.move();
snake.checkColl();
apple.draw();
if(nBonus === 1) {
bonus.draw();
}
fill(0);
text('POINTS : '+ snake.points, 10, 20);
text('APPLES : '+ snake.apples, 10, 40);
}
if(screen === 2) {
snake.points = 0;
snake.apples = 0;
snake.x = width/2;
snake.y = height/2;
snake.len = 1;
snake.positions = [{x:snake.x, y:snake.y}];
snake.snakePosX = 0;
snake.snakePosY = 0;
applePosX = round(random(10,width-appleSize)/10)*10;
applePosY = round(random(10,height-appleSize)/10)*10;
screen = 1;
}
}
// -----------------------------------------------------------------------
void draw() {
background(bg);
makeScreen();
for(var i=0; i<snake.positions.length; i++) {
text(i + 'x:'+snake.positions[i].x + ' y:'+snake.positions[i].y, 600, 20+i*10);
}
}
The problem is in snake.prototype.checkColl and I'm trying to make this work but with no results. When I try to make
if(this.positions[0].x = this.positions[i].x)
nothing happens. If anyone could help me I would be very appreciated.
That should be:
if(this.positions[0].x == this.positions[i].x)
Using a single = is doing an assignment. You want to do a comparison, so you need double ==.