I’m working on this code where if you put in certain characters for the map
array, the canvas will display the image corresponding to that character.
I have an array for all the ground blocks, at the top.
Here’s my code so far:
const blockSize = 160; let ground = []; function setup() { createCanvas(400, 400); ground = new Ground(x*blockSize,y*blockSize) } function preload() { groundImg = loadImage('https://mars.stcollier.repl.co/images/ground.png'); } let map = [ [ "################", "################", "################", "################", "################", "################", "################", "################", "################", "################" ] ]; for (var i = 0; i < map.length; i++) { ground.push([]); for (var y = 0; y < map[i].length; y++) { for (var x = 0; x < map[i][y].length; x++) { switch (map[i][y][x]) { case "#": ground[i].push(ground); break; } } } } function draw() { for (var i = 0; i < ground.length; i++) { ground[i].draw(); } } class Ground { constructor(x, y) { this.pos = createVector(x, y) } draw() { drawImage(groundImg, this.pos.x, this.pos.y, blockSize, blockSize) } }
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width"> <title>repl.it</title> <link href="style.css" rel="stylesheet" type="text/css" /> <script src="https://cdn.jsdelivr.net/npm/p5@1.3.1/lib/p5.js"></script> </head> <body> <script src="script.js"></script> </body> </html>
However, nothing seems to be drawing to the screen. I believe this might be a problem with my loops. Does anyone have a fix for this?
Thanks for any help.
Advertisement
Answer
There are a bunch of defects in your code:
- You are replacing the
ground
array with a single instance ofGround
in yoursetup()
function - You are pushing a reference to
ground
into itself ion your for loop that initializes it drawImage()
is not a function, perhaps you meanimage()
inGround.draw
- In your main
draw()
function you are treatingground
like an array of objects with a.draw()
function, butground
is either a single instance ofGround
and not an array, or it is an array of arrays ofGround
objects.
Here’s a working example:
const blockSize = 16; let ground = []; function setup() { createCanvas(400, 400); } function preload() { groundImg = loadImage('https://mars.stcollier.repl.co/images/ground.png'); } let map = [ [ "################", "#####000000#####", "####0######0####", "###0##0##0##0###", "###0########0###", "###0##0##0##0###", "###0###00###0###", "####0######0####", "#####000000#####", "################" ] ]; // This code could be moved to the setup() function, but in any case it cannot be run until the Ground class is actually declared function init() { for (var i = 0; i < map.length; i++) { ground.push([]); for (var y = 0; y < map[i].length; y++) { for (var x = 0; x < map[i][y].length; x++) { switch (map[i][y][x]) { case "#": // I'm assuming that this is what you actually intended to do // Instead of pushing a reference to the ground array into itself ground[i].push(new Ground(x*blockSize,y*blockSize)); break; } } } } } function draw() { for (var i = 0; i < ground.length; i++) { // ground contains arrays of Ground objects, not sure why for (var j = 0; j < ground[i].length; j++) { ground[i][j].draw(); } } } class Ground { constructor(x, y) { this.pos = new p5.Vector(x, y) } draw() { image(groundImg, this.pos.x, this.pos.y, blockSize, blockSize) } } // Don't call init() until the Ground class is actually declared init();
<script src="https://cdn.jsdelivr.net/npm/p5@1.3.1/lib/p5.js"></script>
Some honest feedback: you need to work on your basic debugging. When you run your code and it doesn’t work check the JavaScript console. Look at the error message in detail. Look for the line in your code where the error is being thrown and make an effort to deduce why it might be happening. When your code doesn’t do what you expect but doesn’t show errors, add console.log()
statements to see if your expectations are valid. Think about what each line of code is doing (i.e. do things like ground[i].push(ground)
make any kind of sense whatsoever).
How I Debugged Your Code
- Run the code, nothing happened, no errors ๐
- Add
console.log('drawing: ' + ground.length)
to thedraw()
function (and addnoLoop()
to prevent the log getting spammed).
- Result:
drawing: undefined
- That is odd, I thought
ground
was an array ๐คจ
- Scan the code for assignments to
ground
, discover that ground is initialized twice, once as an array, and once asnew Ground()
. - Since the latter (
new Ground()
) makes no sense, comment it out. - Hit the run button,
TypeError: ground[i].draw is not a function
coming from line 48 (inside the maindraw()
function) - Look at the code that initializes
ground
in more detail, realize that it is an array of arrays, correct the code indraw()
to have a nested loop. - Run the code:
TypeError: ground[i][j].draw is not a function
- Look at the
ground
initialization code more more depth, noticeground[i].push(ground)
๐คฏ - At a guess this should be
ground[i].push(new Ground(...))
, give that a try - Run the code:
ReferenceError: Cannot access 'Ground' before initialization
- This is a facet of JavaScript, you cannot use Classes in running code before they are declared (although you can reference them in the body of a function so long as that function is not called until the Class is declared).
- At this point we can either move the ground initialization code into
setup()
or a specialinit
function that we invoke ourselves after declaring theGround
class. - I opted for the custom
init
function
- Run the code:
ReferenceError: createVector is not defined
- Oops, I forgot that p5.js functions like
createVector
are not available globally untilsetup()
is called ๐คฆโโ๏ธ. I would have avoided this if I had moved the ground initialization code tosetup()
, but fortunately we can usenew p5.Vector()
any time.
- Run the code:
ReferenceError: drawImage is not defined
- easy fix, should be
image()
Success ๐