1

I'm in deep water at the moment. Not sure I know what I'm doing! Anyway, I'm trying to make a map for my snake game. At the moment I'm trying to add a wall but it wont work! This is the code: https://editor.p5js.org/JensHaglof/sketches/YwtUO8992

Or written out:

wallCount = 0
var walls = []
walls.push([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
walls.push([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
walls.push([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
walls.push([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
walls.push([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
walls.push([1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0])
walls.push([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
walls.push([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
walls.push([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
walls.push([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
walls.push([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
walls.push([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
walls.push([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
walls.push([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
walls.push([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
walls.push([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
walls.push([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
walls.push([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
walls.push([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
walls.push([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])
function setup() {
  createCanvas(400, 400);

  for (let i = 0; i < 20; i++){
    for (let j = 0 ; j < 20 ; j++){
      if (walls[i][j] == 1){
        walls[i][j] = new Wall(walls[i]*20, walls[j]*20);
        wallCount = wallCount + 1
      }
      }
}
}

function Wall(x, y){
  this.x = x;
  this.y = y;
  rect(this.x, this.y, 20, 20);

  this.display = function(){
  fill(255, 255, 0);
  rect(this.x, this.y, 20, 20);
  }
}

function draw() {

  background(0);
  for (let i = 0 ; i < wallCount ; i++){
    for (let j = 0 ; j < wallCount ; j++){
    walls[i][j].display();
  }
  }

}

I get an error "TypeError: walls[i][j].display is not a function (sketch: line 52)"

I have no clue where to begin. I'm trying so many things but it's like I'm shooting in the dark. Anyone knows what's wrong? /Jens

Jens
  • 183
  • 1
  • 10
  • `walls[i][j].display is not a function` which means the one of the index does not exist. Check `wall[i]` exist or check `walls[i][j]` exist. – James Sep 23 '19 at 11:46
  • Yes, that is true. I have mentioned above one case where it can throw that error. I see, you are trying to access `Array` function `display` which is not exist. – James Sep 23 '19 at 11:52
  • @James Nope, the OP is not trying to access a function of `Array` – Ruan Mendes Sep 23 '19 at 11:54
  • This is so new to me. Aren't I declaring the display function in the Wall function? – Jens Sep 23 '19 at 11:54
  • @Jens See my answer, there's a clear explanation – Ruan Mendes Sep 23 '19 at 11:56

3 Answers3

4

You are only initializing the spots where 1s are in your array, but your code expects the entire 2D array to contain instances of Wall.

Without understanding what you are doing, you need to check whether each object is an instance of wall

if (walls[i][j] instanceof Wall) {
  walls[i][j].display();
}
Ruan Mendes
  • 90,375
  • 31
  • 153
  • 217
  • Thank you so much! I've just started to learn about constructor functions and it's very new and confusing. instanceof was a new thing to me! Just what I was looking for! – Jens Sep 23 '19 at 12:02
0

The problem is that you are trying to get the walls from the walls array which also contains zeros (bad naming). Based on your design, the first wall is not guaranteed to be at [0][0]

You should either create a separate array just for the walls:

var wallList = [];
var walls = [];

function setup() {
  createCanvas(400, 400);

  for (let i = 0; i < walls.length; i++) {
    for (let j = 0; j < walls.length; j++) {
      if (walls[i][j] == 1) {
        walls[i][j] = new Wall(walls[i] * 20, walls[j] * 20);
        wallList.push(walls[i][j]);
      }
    }
  }
}

function Wall(x, y) {
  this.x = x;
  this.y = y;
  rect(this.x, this.y, 20, 20);

  this.display = function() {
    fill(255, 255, 0);
    rect(this.x, this.y, 20, 20);
  }
}

function draw() {
  background(0);
  for (let i = 0; i < wallList.length; i++) {
    wallList[i][j].display();
  }
}

Or you should check loop through all the items and check if each one is a wall before continuing:

var walls = [];

function setup() {
  createCanvas(400, 400);

  for (let i = 0; i < walls.length; i++) {
    for (let j = 0; j < walls.length; j++) {
      if (walls[i][j] == 1) {
        walls[i][j] = new Wall(walls[i] * 20, walls[j] * 20);
      }
    }
  }
}

function Wall(x, y) {
  this.x = x;
  this.y = y;
  rect(this.x, this.y, 20, 20);

  this.display = function() {
    fill(255, 255, 0);
    rect(this.x, this.y, 20, 20);
  }
}

function draw() {
  background(0);
  for (let i = 0; i < walls.length; i++) {
    for (let j = 0; j < walls.length; j++) {
      if(walls[i][j] instanceof Wall) walls[i][j].display();
    }
  }
}
nick zoum
  • 7,216
  • 7
  • 36
  • 80
  • The real problem is hidden in your answer and you never explained it. You should strive for explaining the problem first, then you can mention any suggestion improvements. Here's a suggestion improvement for you, when the rest of the code avoids brace-less ifs, you should also. – Ruan Mendes Sep 23 '19 at 11:55
  • But then you chose to post it because you saw that I already answered it with basically the same thing? – Ruan Mendes Sep 23 '19 at 12:01
  • Hi Nick! Thanks for the answer! To have a separate array for the ones that equalled 1 was a nice solution! But I think I'll go with the "instanceof" solution instead. Still a nice solution! – Jens Sep 23 '19 at 12:04
  • @JuanMendes No, I always post a basic answer, and then work on it more – nick zoum Sep 23 '19 at 12:07
  • Your basic answer had a lot of code ;) @Jens This answer also mentions `instanceof`, it's just buried in all the code – Ruan Mendes Sep 23 '19 at 12:17
  • @JuanMendes 95% was copied from the original question – nick zoum Sep 23 '19 at 12:18
  • And the OP didn't find what the real problem was ;) – Ruan Mendes Sep 23 '19 at 12:19
0

Not a solution to your problem, but something you should do nevertheless. Refactor this function

function Wall(x, y){
  this.x = x;
  this.y = y;
  rect(this.x, this.y, 20, 20);

  this.display = function(){
  fill(255, 255, 0);
  rect(this.x, this.y, 20, 20);
  }
}

into

function Wall(x, y){
  this.x = x;
  this.y = y;
  rect(this.x, this.y, 20, 20);
}

Wall.prototype.display = function() {
  fill(255, 255, 0);
  rect(this.x, this.y, 20, 20);
}

In your original code, avery call of the Wall constructor will create a new independent (even though identical to every other one) display function, which performance-wise is just bad. Use the function prototype instead.

mbojko
  • 13,503
  • 1
  • 16
  • 26
  • A function directly on the prototype doesn't require looking up the prototype chain, so it's up the the OP to decide if they prefer quick access instead of slightly more memory. You should post a [link to an explanation](https://stackoverflow.com/questions/310870/use-of-prototype-vs-this-in-javascript/310914#310914) instead of an answer. – Ruan Mendes Sep 23 '19 at 12:16