# How to get character position in 2D map array by its position on canvas

My arrayMap consists of 0, 1 and 2. 0 is water and character is allowed to be on. 1 and 2 are ground and the collision should happen.

To get and check what array number the character is standing on, I take the character position and divide it by my tileset size which is 36px and use Math.floor to round the number. I place it like this: console.log(mapArray[Math.floor(boatPosX / 36)][Math.floor(boatPosX / 36)]); and I know if its 0, 1 or 2 he is standing on. Which is great so far. But my collision still doesn't work the way it should. Actually it acts so weird I don't even know how to fix it properly. If I put some 1 in my player start position, I get collision, but if I place it at 0 in array and move onto 1 myself, it doesn't work.

So it's giving me different results every time. I feel like I'm almost here but some stupid bug is ruining it all.

var mapArray = [
[2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2],
[2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2],
[2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2],
[2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0],
[0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
];
function isPositionWall(ptX, ptY) {
var gridX = Math.floor(ptX / 36);
var gridY = Math.floor(ptY / 36);
if(mapArray[gridX][gridY] == 1)
return true;
}

var boatPosX = canvas.height/2 - 50;
var boatPosY = canvas.height/2 - 50;

function render(viewport) {
context.save();
context.translate(view.x, view.y);
requestAnimationFrame(render);
var oldPosX = boatPosX;
var oldPosY = boatPosY;

for (let i = 0; i < mapArray.length; i++) {
for (let j = 0; j < mapArray[i].length; j++) {
if (mapArray[j][i] == 0) {
this.sprite.draw(
background,
190,
230,
26,
26,
i * this.sprite.width,
j * this.sprite.height,
this.sprite.width,
this.sprite.height
);
}
if (mapArray[j][i] == 1) {
this.sprite.draw(
background,
30,
30,
26,
26,
i * this.sprite.width,
j * this.sprite.height,
this.sprite.width,
this.sprite.height
);

}
if (mapArray[j][i] == 2) {
this.sprite.draw(
background,
200,
20,
26,
26,
i * this.sprite.width,
j * this.sprite.height,
this.sprite.width,
this.sprite.height
);
}
}
}
this.ship.drawimage(boat, boatPosX, boatPosY, 50, 50);

if(isPositionWall(boatPosX, boatPosY)) {
//boatPosX = oldPosY;
console.log("collision");
}
console.log(mapArray[Math.floor(boatPosX / 36)][Math.floor(boatPosX / 36)]);
context.restore();

};

function move(e) {
if (e.keyCode == 39) {
boatPosX += 5;
view.x -= 5
moveCount++;
console.log(moveCount);
console.log("right");
}


That's parts of the code that are related to the question. If you need need more code, let me know. I'm looking for some directions what I'm doing wrong. Thanks.

• Have found the issue and updated my answer below. – KevLoughrey May 24 '18 at 1:32

EDIT: Oh dear, how didn't I spot this earlier. All the stuff in my original answer still applies, but the issue you're having is being caused by a simple array indexing mixup. Rows (which function as Y values in this case) are accessed before columns (X values)!

If you change

if(mapArray[gridX][gridY] == 1)
return true;


to

if(mapArray[gridY][gridX] == 1)
return true;


it will work. Working codepen example: https://codepen.io/anon/pen/XqwNMp?editors=0010

Welcome to the joys of programming!

From a quick glance, your code looks ok. Your collision detection may be the issue - it only checks if a single point on the boat (the top left corner, I'd guess?) is intersecting with tiles, rather than the entire boat itself. That is to say, collisions will currently only be registered when the top left corner of the boat sprite hits another tile, rather than the whole boat.

If you'll forgive the crude MS Paint:

1 shows the boat beside a tile. The point you're using to check for collisions is marked in red (top left).

2 shows the boat intersecting the tile. A collision should be reported here, but isn't, because the red point isn't inside the other square.

3 is a case where a collision is reported.

Like I said, this might be the problem, but it's hard to tell from the code given.

If it is the issue, then the fix is relatively simple. If the user is moving the boat right, then check if both right-hand corners (top and bottom) are intersecting tiles to the right, and check what sort of tiles they are. If one of them is a collider, then you know what to do - set the boat pos to the old pos, just like you have commented out!

Same for moving left, up, and down.

• Wow, thanks for the clear explanation and the effort, I was actually wondering if the position of my character starts the left top corner or the center, etc. It makes sense. I tested it more and unfortunately it just behaves nonsense. Even when I'm at the top of water in some places console shows me that I'm standing on the ground. I'm wondering if it has anything to do with my canvas transform function? There is definitely something odd. I made a codepen, I would appreciate it if you would check it. codepen.io/Limpuls/pen/deEGXX Move little bit to the right and you see its 0 collision – Limpuls May 23 '18 at 20:23
• @Limpuls You may use the Codepen source you liked to write a more specific question, more users could help you – liggiorgio May 23 '18 at 23:46
• Hey thanks for the extended answer, works like a charm, well almost. like you said, I'm still checking against top left corner for collision. So let's say if my character moves to the right, I want to check the right side for collision. In that case I would need to check for mapArray[gridY][gridX]  where gridX would be gridX + the width of the character which in this case is 36px. And by this I would check for collision on the right side, right? Also would I want to test this on every keyboard arrow key, so that if I press right key, iI check right collision, not left?thanks – Limpuls May 24 '18 at 14:53
• Yes, that's the general idea. But you need to do two checks for each collision, as it's possible that either the top or bottom corner of the boat sprite will be colliding and the other won't. So, for right-side collisions, you'll not only check the top right point [boatPosX + boatWidth, boatPosY] but also the bottom right [boatPosX + boatWidth, boatPosY + boatHeight]. Yes, you only need to check for collisions in the direction you're moving, so if you're moving right, you only need to check for collisions with objects to the right of the boat. If the game gets more complex this may change. – KevLoughrey May 24 '18 at 15:34