snake can't ride on edge of canvas in my JS game? - javascript

Hey guys I wrote a condition that would check the position of the snakes head to see if it hit the edge of the canvas. If this happens i wan't to stop the interval that the games running on. here's the code //check if snake hit wall
if(headX <= 0 || headY <= 0 || headX >= (cvsW-unit) || headY >= (cvsH-unit)) {
alert(headX);
clearInterval(runGame);
}
but sense the edge of the canvas has the x any y position of 0 this means if a food generates on the edge of the canvas the snake is unable to go there without the game stopping. And if you lower the values below 0 the snake head will now be able to go outside of the canvas. I don't know how to get around this plz help.
const canvas = document.querySelector('#canvas');
const ctx = canvas.getContext('2d');
//set canvas dimension equal to css dimension
canvas.width = 768;
canvas.height = 512;
//now put those dimensions into variables
const cvsW = canvas.width;
const cvsH = canvas.height;
//create snake unit
const unit = 16;
//create snake array
let snake = [{x: cvsW/2, y: cvsH/2}];
//delcare global variable to hold users direction
let direction;
//create food object
let food = {
x : Math.floor(Math.random()*((cvsW/unit)-1)+1)*unit,
y : Math.floor(Math.random()*((cvsH/unit)-1)+1)*unit
}
//read user's direction
document.addEventListener('keydown', changeDirection);
function changeDirection(e) {
//set direction
if (e.keyCode == 37 && direction != 'right') direction = 'left';
else if (e.keyCode == 38 && direction != 'down') direction = 'up';
else if (e.keyCode == 39 && direction != 'left') direction = 'right';
else if (e.keyCode == 40 && direction != 'up') direction = 'down';
}
function draw() {
//refresh canvas
ctx.clearRect(0, 0, cvsW, cvsH);
//draw snake
for(let i = 0; i < snake.length; i++) {
ctx.fillStyle = 'limegreen';
ctx.fillRect(snake[i].x, snake[i].y, unit, unit);
}
//grab head position
let headX = snake[0].x;
let headY = snake[0].y;
//check if snake hit wall
if(headX <= 0 || headY <= 0 || headX >= (cvsW-unit) || headY >= (cvsH-unit)) {
alert(headX);
clearInterval(runGame);
}
//posistion food on board
ctx.fillStyle = 'red';
ctx.fillRect(food.x, food.y, unit, unit);
//send the snake in chosen direction
if(direction == 'left') headX -= unit;
else if(direction == 'up') headY -= unit;
else if(direction == 'right') headX += unit;
else if(direction == 'down') headY += unit;
//create new head
let newHead = {x: headX, y: headY}
if(headX == food.x && headY == food.y) {
//create new food position
food = {
x : Math.floor(Math.random()*((cvsW/unit)-1)+1)*unit,
y : Math.floor(Math.random()*((cvsH/unit)-1)+1)*unit
}
//add 3 units to the snake
snake.unshift(newHead);
snake.unshift(newHead);
snake.unshift(newHead);
}
else {
//remove tail
snake.pop();
}
//add head to snake
snake.unshift(newHead);
}
//run game engine
let runGame = setInterval(draw, 70);
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Snake Game</title>
<style>
body {
background-color: #333;
}
canvas {
background-color: #4d4d4d;
margin: auto;
display: block;
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
width: 750px;
height: 500px;
}
</style>
</head>
<body>
<canvas id="canvas"></canvas>
<script src="script.js"></script>
</body>
</html>

From what I understand, you have a 48x32 grid whose spaces are 16px squares. The algorithm you use to generate your food's position on the grid:
let food = {
x : Math.floor(Math.random()*((cvsW/unit)-1)+1)*unit, // Chooses 1-47
y : Math.floor(Math.random()*((cvsH/unit)-1)+1)*unit // Chooses 1-31
}
chooses a value between 1 and 47 for x, and 1 and 31 for y. Well, the problem with that is that position 47 for x and position 31 for y are both on the edge of the grid (this is because the first x/y position is 0, not 1). To eliminate those spaces as choices, the algorithm simply needs to subtract 2 instead of 1 from the number of spaces on the grid (which is cvsW or cvsH divided by unit):
let food = {
x : Math.floor(Math.random()*((cvsW/unit)-2)+1)*unit, // Chooses 1-46
y : Math.floor(Math.random()*((cvsH/unit)-2)+1)*unit // Chooses 1-30
}
Basically, subtracting 1 only eliminated the last column/row as a choice for the x/y position, and then adding 1 shifted everything over to the right. Like this (for x):
The new algorithm does this, initially eliminating the last two choices then shifting over 1:

Related

Javascript snake game bugs

There are two issues, I can't control the snake, and now it just resets constantly without giving the snake a chance to move. I figured that if i kept coding the problem would go away but sadly its not a perfect world.
I tried different key codes for controlling the snake but it didn't work.
window.onload = function() {
var cvs = document.getElementById("canvas");
var ctx = cvs.getContext("2d");
var cvsW = cvs.width;
var cvsH = cvs.height;
var snekW = 10;
var snekH = 10;
//score
var score = 0;
//default direction
var direction = "right";
//read users directions
document.addEventListener("keydown",getDirection);
//To my knowledge this function should control the snake with the
keyboard
function getDirection(e)
{
if(e.keyCode == 37 && direction != "right"){
direction = "left";
}else if(e.keyCode == 38 && direction != "down"){
direction = "up";
}else if(e.keyCode == 39 && direction != "left"){
direction = "right";
}else if(e.keycode == 40 && direction != "up"){
direction = "down";
}
}
function drawSnek(x,y)
{
ctx.fillStyle = "Lime";
ctx.fillRect(x*snekW,y*snekH,snekW,snekH);
ctx.fillStyle = "#000";
ctx.strokeRect(x*snekW,y*snekH,snekW,snekH);
}
var len = 4; //default length of the snake
var snek = []; //the snake is an array
for(var i = len-1; i>=0; i--)
{
snek.push({x:i,y:0});
}
//exceptions for direction of snake
if(direction == "left") snekx--;
else if( direction == "up") sneky--;
else if( direction == "right") snekx++;
else if( direction == "down") sneky++;
//Functions for creating snake food have been removed.
var newHead = { x: snekx, y: sneky};
snek.unshift(newHead);
drawScore(score);
}
setInterval(draw, 10); //I do not fully understand this function
}
There were several issues with your code:
You needed a draw function that could be called in an interval. In this draw function you could draw the individual parts of the snake.
You were unable to control the snake correctly as you had a typo in the down part of the callback function.
You have to either introduce x / y variables for the head of the snake or use the first element of the array to retrieve it.
Unshifting the new position using snek.unshift will cause the snake to grow indefinitely. Removing array elements using
snek.splice(len,snek.length - len);
solves this problem.
If you only draw new elements to the screen the old parts you drew will still exist in new frames. A good idea would be to clear the canvas using
ctx.clearRect(0, 0, cvsW, cvsH);
window.onload = function () {
var cvs = document.getElementById("canvas");
var ctx = cvs.getContext("2d");
var cvsW = cvs.width;
var cvsH = cvs.height;
var snekW = 10;
var snekH = 10;
//score
var score = 0;
//default direction
var direction = "right";
//read users directions
document.addEventListener("keydown", getDirection);
//To my knowledge this function should control the snake with the keyboard
function getDirection(e) {
if (e.keyCode == 37 && direction != "right") {
direction = "left";
} else if (e.keyCode == 38 && direction != "down") {
direction = "up";
} else if (e.keyCode == 39 && direction != "left") {
direction = "right";
} else if (e.keyCode == 40 && direction != "up") {
direction = "down";
}
}
function drawSnek(x, y) {
ctx.fillStyle = "Lime";
ctx.fillRect(x * snekW, y * snekH, snekW, snekH);
ctx.fillStyle = "#000";
ctx.strokeRect(x * snekW, y * snekH, snekW, snekH);
}
let snekx = 0;
let sneky = 0;
var len = 4; //default length of the snake
var snek = []; //the snake is an array
for (var i = len - 1; i >= 0; i--) {
snek.push({ x: i, y: 0 });
}
function draw() {
ctx.clearRect(0, 0, cvsW, cvsH);
//exceptions for direction of snake
if (direction == "left") snekx--;
else if (direction == "up") sneky--;
else if (direction == "right") snekx++;
else if (direction == "down") sneky++;
//Functions for creating snake food have been removed.
var newHead = { x: snekx, y: sneky };
snek.unshift(newHead);
for(let i = 0; i < snek.length; i++) {
drawSnek(snek[i].x, snek[i].y)
}
snek.splice(len,snek.length - len);
//drawScore(score);
}
setInterval(draw, 50); //I do not fully understand this function
}
CodePen with fixed code:
https://codepen.io/lukasmoeller/pen/PvVzqq?editors=1111
(boundaries are not checked - the snake will leave the canvas)
Explanation of setInterval(fn, interval)
setInterval calls the function specified using fn every interval ms until it is cleared. The interval can be cleared by using clearInterval, passing it the return value of setInterval. If you want to delay function execution at the beginning you could add setTimeout, add a callback that sets the interval:
setTimeout(function(){
setInterval(draw, 50);
}, 1000)
This would only start drawing the game every 50 ms after 1000ms have passed.

pop function isn't taking tail off snake array?

I am making a snake game in JS. Right now I'm able to draw the snake to the canvas and accept a direction to move from the user. Given the direction I'm able to unshift() a new head to the snake, but for some reason I can't use the pop method to remove the tail. This just results in my snake growing bigger and bigger. Any ideas to why this is?
const canvas = document.querySelector('#canvas');
const ctx = canvas.getContext('2d');
//set canvas dimension equal to css dimension
canvas.width = 768;
canvas.height = 512;
//now put those dimensions into variables
const cvsW = canvas.width;
const cvsH = canvas.height;
//create snake unit
const unit = 16;
//create snake array
let snake = [{x: cvsW/2, y: cvsH/2}];
//read user's direction
document.addEventListener('keydown', changeDirection);
let direction;
function changeDirection(e) {
if (e.keyCode == 37 && direction != 'right') direction = 'left';
else if (e.keyCode == 38 && direction != 'down') direction = 'up';
else if (e.keyCode == 39 && direction != 'left') direction = 'right';
else if (e.keyCode == 40 && direction != 'up') direction = 'down';
console.log(direction);
}
function draw() {
for(let i = 0; i < snake.length; i++) {
ctx.fillStyle = 'limegreen';
ctx.fillRect(snake[i].x, snake[i].y, unit, unit);
}
//grab head position
let headX = snake[0].x;
let headY = snake[0].y;
snake.pop();
if(direction == 'left') headX -= unit;
else if(direction == 'up') headY -= unit;
else if(direction == 'right') headX += unit;
else if(direction == 'down') headY += unit;
//create new head
let newHead = {x: headX, y: headY}
//add head to snake
snake.unshift(newHead);
}
setInterval(draw, 100);
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Snake Game</title>
<style>
body {
background-color: #333;
}
canvas {
background-color: #4d4d4d;
margin: auto;
display: block;
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
width: 750px;
height: 500px;
}
</style>
</head>
<body>
<canvas id="canvas"></canvas>
<script src="script.js"></script>
</body>
</html>
You need to clear the current canvas every iteration, else pixels painted onto the canvas earlier will remain. Add
ctx.clearRect(0, 0, canvas.width, canvas.height);
right before you start iterating over the snake array to paint each square:
const canvas = document.querySelector('#canvas');
const ctx = canvas.getContext('2d');
//set canvas dimension equal to css dimension
canvas.width = 768;
canvas.height = 512;
//now put those dimensions into variables
const cvsW = canvas.width;
const cvsH = canvas.height;
//create snake unit
const unit = 16;
//create snake array
let snake = [{
x: cvsW / 2,
y: cvsH / 2
}];
//read user's direction
document.addEventListener('keydown', changeDirection);
let direction;
function changeDirection(e) {
if (e.keyCode == 37 && direction != 'right') direction = 'left';
else if (e.keyCode == 38 && direction != 'down') direction = 'up';
else if (e.keyCode == 39 && direction != 'left') direction = 'right';
else if (e.keyCode == 40 && direction != 'up') direction = 'down';
console.log(direction);
}
function draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = 'limegreen';
for (let i = 0; i < snake.length; i++) {
ctx.fillRect(snake[i].x, snake[i].y, unit, unit);
}
//grab head position
let headX = snake[0].x;
let headY = snake[0].y;
snake.pop();
if (direction == 'left') headX -= unit;
else if (direction == 'up') headY -= unit;
else if (direction == 'right') headX += unit;
else if (direction == 'down') headY += unit;
//create new head
let newHead = {
x: headX,
y: headY
}
//add head to snake
snake.unshift(newHead);
}
setInterval(draw, 100);
body {
background-color: #333;
}
canvas {
background-color: #4d4d4d;
margin: auto;
display: block;
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
width: 750px;
height: 500px;
}
<canvas id="canvas"></canvas>
Rearrange your draw function and add ctx.clearRect . Modify the draw function in the following way:
function draw() {
//grab head position
let headX = snake[0].x;
let headY = snake[0].y;
if(direction == 'left') headX -= unit;
else if(direction == 'up') headY -= unit;
else if(direction == 'right') headX += unit;
else if(direction == 'down') headY += unit;
//create new head
let newHead = {x: headX, y: headY}
//add head to snake
snake.unshift(newHead);
for(let i = 0; i < snake.length; i++) {
ctx.fillStyle = 'limegreen';
ctx.fillRect(snake[i].x, snake[i].y, unit, unit);
}
let popped = snake.pop();
ctx.clearRect(popped.x, popped.y, unit, unit);
}

snake can't move on the very edge of the canvas in my JS snake game

Hey guys I'm making a snake game in JS. The original problem i was working on was trying to get the game to stop running by using clearInterval(game); once the snake head makes contact with the edge of the canvas. Once I figured that out it created a new problem. You can't ride the snake on the edge of the canvas. This is a problem because the food will generate on the edge sometimes. Any ideas, I'm stumped. Thanks:)
const canvas = document.querySelector('#canvas');
const ctx = canvas.getContext('2d');
//set canvas dimension equal to css dimension
canvas.width = 768;
canvas.height = 512;
//now put those dimensions into variables
const cvsW = canvas.width;
const cvsH = canvas.height;
//create snake unit
const unit = 16;
//create snake array
let snake = [{x: cvsW/2, y: cvsH/2}];
//delcare global variable to hold users direction
let direction;
//create food object
let food = {
x : Math.floor(Math.random()*((cvsW/unit)-1)+1)*unit,
y : Math.floor(Math.random()*((cvsH/unit)-1)+1)*unit
}
//read user's direction
document.addEventListener('keydown', changeDirection);
function changeDirection(e) {
//set direction
if (e.keyCode == 37 && direction != 'right') direction = 'left';
else if (e.keyCode == 38 && direction != 'down') direction = 'up';
else if (e.keyCode == 39 && direction != 'left') direction = 'right';
else if (e.keyCode == 40 && direction != 'up') direction = 'down';
}
function draw() {
//refresh canvas
ctx.clearRect(0, 0, cvsW, cvsH);
//draw snake
for(let i = 0; i < snake.length; i++) {
ctx.fillStyle = 'limegreen';
ctx.fillRect(snake[i].x, snake[i].y, unit, unit);
}
//grab head position
let headX = snake[0].x;
let headY = snake[0].y;
//check if snake hit wall
if(headX <= 0 || headY <= 0 || headX >= (cvsW-unit) || headY >= (cvsH-unit)) {
clearInterval(runGame);
}
//posistion food on board
ctx.fillStyle = 'red';
ctx.fillRect(food.x, food.y, unit, unit);
//send the snake in chosen direction
if(direction == 'left') headX -= unit;
else if(direction == 'up') headY -= unit;
else if(direction == 'right') headX += unit;
else if(direction == 'down') headY += unit;
//create new head
let newHead = {x: headX, y: headY}
if(headX == food.x && headY == food.y) {
//create new food position
food = {
x : Math.floor(Math.random()*((cvsW/unit)-1)+1)*unit,
y : Math.floor(Math.random()*((cvsH/unit)-1)+1)*unit
}
//add 3 units to the snake
snake.unshift(newHead);
snake.unshift(newHead);
snake.unshift(newHead);
}
else {
//remove tail
snake.pop();
}
//add head to snake
snake.unshift(newHead);
}
//run game engine
let runGame = setInterval(draw, 70);
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Snake Game</title>
<style>
body {
background-color: #333;
}
canvas {
background-color: #4d4d4d;
margin: auto;
display: block;
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
width: 750px;
height: 500px;
}
</style>
</head>
<body>
<canvas id="canvas"></canvas>
<script src="script.js"></script>
</body>
</html>

snake game - snake movement using array.pop and array.unshift

In my code the snake and it's movement consists of an array. In other words the snake's head is the first array number and last number is snake's tail. I try to implement the movement using array.pop and array.unshift. The problem is that the snake gets bigger and bigger as it moves. I think it is some very small detail that I'm missing. Here is the code:
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var cWidth = canvas.width;
var cHeight = canvas.height;
var boxWidth = 10;
var boxHeight = 10;
var boxWH = 10; //One box width and height
var points = 0;
var score = document.getElementById("Score");
var foodImg = new Image();
var k;
foodImg.src = "Pictures/apple2.png";
var snake = [];
snake[0] = {
x: cWidth/2,
y: cHeight/2
};
var food = {
x: Math.floor(Math.random()*60)*boxWH,
y: Math.floor(Math.random()*60)*boxWH
}
document.addEventListener("keydown", direction);
function direction(event){
var key = event.keyCode;
if(key == 65 && k != "right"){
k = "left";
}
else if(key == 68 && k != "left"){
k = "right";
}
else if(key == 87 && k != "down"){
k = "up";
}
else if(key == 83 && k != "up"){
k = "down";
}
}
function SnakeGame(){
ctx.fillStyle = "green";
ctx.fillRect(0, 0, cWidth, cHeight);
var game = setInterval(Draw, 100);
}
function Draw(){
for(var i = 0; i<snake.length; i++){
ctx.fillStyle = (i == 0) ? "red" : "white";
ctx.fillRect(snake[i].x, snake[i].y, boxWH, boxWH);
ctx.strokeStyle = "yellow";
ctx.strokeRect(snake[i].x, snake[i].y, boxWH, boxWH);
}
ctx.drawImage(foodImg, food.x, food.y);
var snakeX = snake[0].x;
var snakeY = snake[0].y;
snake.pop();
if(k == "right") snakeX += boxWH;
if(k == "left") snakeX -= boxWH;
if(k == "up") snakeY -= boxWH;
if(k == "down") snakeY += boxWH;
var nHead = {
x: snakeX,
y: snakeY
}
snake.unshift(nHead);
}
the problem is that the sanke gets bigger and bigger as it moves
The snake has the correct size, what happens is that it is leaving a "trail". To avoid that, you need to clear the canvas each Draw call.
Just move the command to fill the canvas from the SnakeGame function to the beginning of Draw, like this:
function SnakeGame(){
var game = setInterval(Draw, 100);
}
function Draw(){
ctx.fillStyle = "green";
ctx.fillRect(0, 0, cWidth, cHeight);
for(var i = 0; i<snake.length; i++){
ctx.fillStyle = (i == 0) ? "red" : "white";
ctx.fillRect(snake[i].x, snake[i].y, boxWH, boxWH);
//(...)
The problem has to do with the fact that you draw the snake onto the canvas without resetting it every time. The new snake tiles are drawn, but the old ones are also still there.
You can fix it by moving these lines to the beginning of the Draw function, so they are executed every time you are about to redraw the snake:
ctx.fillStyle = "green";
ctx.fillRect(0, 0, cWidth, cHeight);

Tile map collide not working as expected in Javascript

I have been thinking of a way to set-up tile map collision with a player in the same way I have developed the game so far (or similar way if possible, so I do not have to redo everything :) ).
I got some ideas from tutorials and videos and decided to implement it to my code and the player definitely collides with something, though it doesn't look to be the correct tiles that it should be.
For example I want it to walk on over the tiles with Index 1, but to collide with tiles with Index 0 and 3, to stop the player movement.
Here is what I got so far:
<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<title>Canvas Tile Map</title>
<style>
#canvas{
border: 1px solid black;
}
</style>
</head>
<body>
<canvas id="canvas" height="650px" width="1000px"></canvas>
<script>
var canvas = document.getElementById("canvas");
var context = canvas.getContext("2d");
var go = 0;
var canvasBegX = -64;
var canvasEndX = 999;
var canvasBegY = -64;
var canvasEndY = 649;
var heroX = 0;
var heroY = 0;
var heroIndexX = 0;
var heroIndexY = 0;
var heroIndexXnew = 0;
var heroIndexYnew = 0;
//--------------------------------------------------------------
//ADD CHECKER IF KEY IS PRESSED OR RELEASED
window.addEventListener('keydown', function (e) {
canvas.key = e.keyCode;
})
window.addEventListener('keyup', function (e) {
canvas.key = false;
})
//--------------------------------------------------------------
//THE MAP
var mapArray=[
[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3],
[3,0,0,0,0,1,1,0,0,0,0,0,0,0,1,1,1,1,0,0,0,3],
[3,1,1,1,1,1,1,0,0,0,0,0,0,0,1,1,1,0,0,0,0,3],
[3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,1,3],
[3,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,3],
[3,1,1,1,0,1,1,0,0,0,0,0,1,1,1,1,1,0,0,0,0,3],
[3,1,1,1,0,1,1,0,0,0,0,0,1,1,1,1,1,0,0,0,0,3],
[3,0,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3],
[3,0,1,1,0,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,3],
[3,0,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3],
[3,0,1,1,1,1,1,0,0,0,0,0,0,1,1,1,1,0,0,0,0,3],
[3,0,1,1,1,1,1,0,0,0,0,1,1,1,1,1,1,1,1,0,1,3],
[3,0,0,0,0,1,1,0,0,0,0,1,1,0,0,1,1,1,1,0,0,3],
[3,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,3],
[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]
];
// x= 22
// y= 15
//-----------------------------------------------------------------------
//------------------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------
// DRAW PLAYER
player_image = new Image();
var player = new Object();
player.y = canvas.height/2-220; //player position y
player.x = canvas.width/2-340; //player position x
player.Width = 60;
player.Height = 60;
function drawPlayer() { // drawing the player
context.beginPath();
context.fillStyle = "red";
context.fillRect(player.x,player.y,player.Width,player.Height);
context.closePath();
}
//-----------------------------------------------------------------------
//------------------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------
// These I need for the map co-ordinates and when it moves the map upon key-press
var updateX=(player.x-210); // Starting point of canvas X
var updateY=(player.y-160); // Starting point of canvas Y
var posX=updateX;
var posY=updateY;
//------------------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------------
//DRAW THE MAP AND THE PLAYER
var grass = new Image();
var stone = new Image();
var black = new Image();
function drawMap() {
var posY = updateY; // new Y coordinates for the map after movement
grass.src= 'https://sarahkerrigan.biz/wpmtest/hosting/images/tile/grass.jpeg';
stone.src = 'https://sarahkerrigan.biz/wpmtest/hosting/images/tile/sand.jpeg';
black.src = 'https://sarahkerrigan.biz/wpmtest/hosting/images/tile/black.png';
//---------------------------------------------------------
// Draw the map loop
grass.onload = function (){
stone.onload = function (){
black.onload = function (){
for(var i=0; i < mapArray.length; i++){
for(var j=0; j < mapArray[i].length; j++){
if(mapArray[i][j]==0){
if (posY > canvasBegY && posY < canvasEndY && posX > canvasBegX && posX < canvasEndX){
context.drawImage(grass,posX, posY, 64, 64); // Load image for grass "0"
}
}
if(mapArray[i][j]==1){
if (posY > canvasBegY && posY < canvasEndY && posX > canvasBegX && posX < canvasEndX){
context.drawImage(stone,posX,posY,64,64); // Load image for stone "1"
}
}
if(mapArray[i][j]==3){
if (posY > canvasBegY && posY < canvasEndY && posX > canvasBegX && posX < canvasEndX){
context.drawImage(black,posX,posY,64,64); // Load image for black "3"
}
}
posX+=64;
}
posY+=64;
posX=updateX; // new X coordinates for the map after movement
//---------------------------------------------------------
drawPlayer(); // Draw the player
}
}
}
}
}
//-----------------------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------------------------
// PLAYER MOVEMENT BUTTONS
var rightPressed = false;
var leftPressed = false;
var upPressed = false;
var downPressed = false;
var endX=1408;
var endY=960;
document.addEventListener("keydown", keyDownHandler);
function keyDownHandler(e) {
if(e.keyCode == 39) {
rightPressed = true;
}
else if(e.keyCode == 37) {
leftPressed = true;
}
if(e.keyCode == 40) {
downPressed = true;
}
else if(e.keyCode == 38) {
upPressed = true;
}
}
document.addEventListener("keyup", keyUpHandler);
function keyUpHandler(e) {
if(e.keyCode == 39) {
rightPressed = false;
}
else if(e.keyCode == 37) {
leftPressed = false;
}
if(e.keyCode == 40) {
downPressed = false;
}
else if(e.keyCode == 38) {
upPressed = false;
}
}
//----------------------------------------------
//THE ACTUAL MOVEMENT + BOUNDARIES
function playerMovement(){
//------------------------------
//CHECK PLAYER X AND Y IN TILE INDEXES
heroX = Math.abs(updateX - player.x); //current hero X position starting from beginning of tilemap(outside of visible part)
heroY = Math.abs(updateY - player.y); //current hero Y position starting from beginning of tilemap(outside of visible part)
heroIndexX = heroX/64; // X index of hero to chech in which tile is currently located
heroIndexY = heroY/64; // Y index of hero to chech in which tile is currently located
heroIndexXnew = Math.ceil(heroIndexX); //index positioned on the right of the heroes index
heroIndexYnew = Math.ceil(heroIndexY) -2; //index positioned on the left of the heroes index
if(rightPressed) {
if (isPathTile(mapArray, heroIndexXnew, heroIndexYnew)){ // Nothing happens because you hit a tile
}else {
moveRight(); // if you are not at the wall, you go right
}
}
//------------------------------
else if(leftPressed) {
if (isPathTile(mapArray, heroIndexXnew - 2, heroIndexYnew)){ // Nothing happens because you hit a tile
}else {
moveLeft(); // if you are not at the wall, you go left
}
}
//------------------------------
if(downPressed) {
if(player.y>updateY+834){} // Nothing happens because you hit the bottom wall
else {
moveDown(); // if you are not at the wall, you go down
}
}
//------------------------------
else if(upPressed) {
if(player.y<updateY+64){} // Nothing happens because you hit the top wall
else {
moveUp(); // if you are not at the wall, you go up
}
}
}
//-----------------------------------------------------------------------
//------------------------------------------------------------------------------------------------------
//CAMERA BOUNDARIES
function moveRight(){
if(player.x<820){
player.x=player.x+4.1; //If you are at this position, move the player
}
else if(player.x>820){
updateX=updateX-4.1; //If you go over this position, move the background
}
}
function moveLeft(){
if(player.x>100){
player.x=player.x-4.1; //If you are at this position, move the player
}
else if(player.x<100){
updateX=updateX+4.1; //If you go over this position, move the background
}
}
function moveUp(){
if(player.y>80){
player.y=player.y-4.1; //If you are at this position, move the player
}
else if(player.y<80){
updateY=updateY+4.1; //If you go over this position, move the background
}
}
function moveDown(){
if(player.y<500){
player.y=player.y+4.1; //If you are at this position, move the player
}
else if(player.y>500){
updateY=updateY-4.1; //If you go over this position, move the background
}
}
//-----------------------------------------------------------------------
//------------------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------
//------------------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------
//------------------------------------------------------------------------------------------------------
// MOVEMENT BOUNDARIES WITH TILES
function isPathTile(mapArray, x, y) {
return (mapArray[x][y] === 0); // Because 0 is the path tile
}
//-----------------------------------------------------------------------
//------------------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------
//------------------------------------------------------------------------------------------------------
// THE GAME LOOP
function gameLoop(){
console.log("index X =" + heroIndexXnew);
console.log("index Y =" + heroIndexYnew);
playerMovement(); //Check for movements
drawMap(); //Draw the map and the player
requestAnimationFrame(gameLoop);
}
//-----------------------------------------------------------------------
//------------------------------------------------------------------------------------------------------
gameLoop(); // start the gameLoop
</script>
</body>
</html>
And here is a code to test it -
var canvas = document.getElementById("canvas");
var context = canvas.getContext("2d");
var go = 0;
var canvasBegX = -64;
var canvasEndX = 999;
var canvasBegY = -64;
var canvasEndY = 649;
var heroX = 0;
var heroY = 0;
var heroIndexX = 0;
var heroIndexY = 0;
var heroIndexXnew = 0;
var heroIndexYnew = 0;
//--------------------------------------------------------------
//ADD CHECKER IF KEY IS PRESSED OR RELEASED
window.addEventListener('keydown', function (e) {
canvas.key = e.keyCode;
})
window.addEventListener('keyup', function (e) {
canvas.key = false;
})
//--------------------------------------------------------------
//THE MAP
var mapArray=[
[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3],
[3,0,0,0,0,1,1,0,0,0,0,0,0,0,1,1,1,1,0,0,0,3],
[3,1,1,1,1,1,1,0,0,0,0,0,0,0,1,1,1,0,0,0,0,3],
[3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,1,3],
[3,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,3],
[3,1,1,1,0,1,1,0,0,0,0,0,1,1,1,1,1,0,0,0,0,3],
[3,1,1,1,0,1,1,0,0,0,0,0,1,1,1,1,1,0,0,0,0,3],
[3,0,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3],
[3,0,1,1,0,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,3],
[3,0,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,3],
[3,0,1,1,1,1,1,0,0,0,0,0,0,1,1,1,1,0,0,0,0,3],
[3,0,1,1,1,1,1,0,0,0,0,1,1,1,1,1,1,1,1,0,1,3],
[3,0,0,0,0,1,1,0,0,0,0,1,1,0,0,1,1,1,1,0,0,3],
[3,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,3],
[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]
];
// x= 22
// y= 15
//-----------------------------------------------------------------------
//------------------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------
// DRAW PLAYER
player_image = new Image();
var player = new Object();
player.y = canvas.height/2-220; //player position y
player.x = canvas.width/2-340; //player position x
player.Width = 60;
player.Height = 60;
function drawPlayer() { // drawing the player
context.beginPath();
context.fillStyle = "red";
context.fillRect(player.x,player.y,player.Width,player.Height);
context.closePath();
}
//-----------------------------------------------------------------------
//------------------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------
// These I need for the map co-ordinates and when it moves the map upon key-press
var updateX=(player.x-210); // Starting point of canvas X
var updateY=(player.y-160); // Starting point of canvas Y
var posX=updateX;
var posY=updateY;
//------------------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------------
//DRAW THE MAP AND THE PLAYER
var grass = new Image();
var stone = new Image();
var black = new Image();
function drawMap() {
var posY = updateY; // new Y coordinates for the map after movement
grass.src= 'https://sarahkerrigan.biz/wpmtest/hosting/images/tile/grass.jpeg';
stone.src = 'https://sarahkerrigan.biz/wpmtest/hosting/images/tile/sand.jpeg';
black.src = 'https://sarahkerrigan.biz/wpmtest/hosting/images/tile/black.png';
//---------------------------------------------------------
// Draw the map loop
grass.onload = function (){
stone.onload = function (){
black.onload = function (){
for(var i=0; i < mapArray.length; i++){
for(var j=0; j < mapArray[i].length; j++){
if(mapArray[i][j]==0){
if (posY > canvasBegY && posY < canvasEndY && posX > canvasBegX && posX < canvasEndX){
context.drawImage(grass,posX, posY, 64, 64); // Load image for grass "0"
}
}
if(mapArray[i][j]==1){
if (posY > canvasBegY && posY < canvasEndY && posX > canvasBegX && posX < canvasEndX){
context.drawImage(stone,posX,posY,64,64); // Load image for stone "1"
}
}
if(mapArray[i][j]==3){
if (posY > canvasBegY && posY < canvasEndY && posX > canvasBegX && posX < canvasEndX){
context.drawImage(black,posX,posY,64,64); // Load image for black "3"
}
}
posX+=64;
}
posY+=64;
posX=updateX; // new X coordinates for the map after movement
//---------------------------------------------------------
drawPlayer(); // Draw the player
}
}
}
}
}
//-----------------------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------------------------
// PLAYER MOVEMENT BUTTONS
var rightPressed = false;
var leftPressed = false;
var upPressed = false;
var downPressed = false;
var endX=1408;
var endY=960;
document.addEventListener("keydown", keyDownHandler);
function keyDownHandler(e) {
if(e.keyCode == 39) {
rightPressed = true;
}
else if(e.keyCode == 37) {
leftPressed = true;
}
if(e.keyCode == 40) {
downPressed = true;
}
else if(e.keyCode == 38) {
upPressed = true;
}
}
document.addEventListener("keyup", keyUpHandler);
function keyUpHandler(e) {
if(e.keyCode == 39) {
rightPressed = false;
}
else if(e.keyCode == 37) {
leftPressed = false;
}
if(e.keyCode == 40) {
downPressed = false;
}
else if(e.keyCode == 38) {
upPressed = false;
}
}
//----------------------------------------------
//THE ACTUAL MOVEMENT + BOUNDARIES
function playerMovement(){
//------------------------------
//CHECK PLAYER X AND Y IN TILE INDEXES
heroX = Math.abs(updateX - player.x); //current hero X position starting from beginning of tilemap(outside of visible part)
heroY = Math.abs(updateY - player.y); //current hero Y position starting from beginning of tilemap(outside of visible part)
heroIndexX = heroX/64; // X index of hero to chech in which tile is currently located
heroIndexY = heroY/64; // Y index of hero to chech in which tile is currently located
heroIndexXnew = Math.ceil(heroIndexX); //index positioned on the right of the heroes index
heroIndexYnew = Math.ceil(heroIndexY) -2; //index positioned on the left of the heroes index
if(rightPressed) {
if (isPathTile(mapArray, heroIndexXnew, heroIndexYnew)){ // Nothing happens because you hit a tile
}else {
moveRight(); // if you are not at the wall, you go right
}
}
//------------------------------
else if(leftPressed) {
if (isPathTile(mapArray, heroIndexXnew - 2, heroIndexYnew)){ // Nothing happens because you hit a tile
}else {
moveLeft(); // if you are not at the wall, you go left
}
}
//------------------------------
if(downPressed) {
if(player.y>updateY+834){} // Nothing happens because you hit the bottom wall
else {
moveDown(); // if you are not at the wall, you go down
}
}
//------------------------------
else if(upPressed) {
if(player.y<updateY+64){} // Nothing happens because you hit the top wall
else {
moveUp(); // if you are not at the wall, you go up
}
}
}
//-----------------------------------------------------------------------
//------------------------------------------------------------------------------------------------------
//CAMERA BOUNDARIES
function moveRight(){
if(player.x<820){
player.x=player.x+4.1; //If you are at this position, move the player
}
else if(player.x>820){
updateX=updateX-4.1; //If you go over this position, move the background
}
}
function moveLeft(){
if(player.x>100){
player.x=player.x-4.1; //If you are at this position, move the player
}
else if(player.x<100){
updateX=updateX+4.1; //If you go over this position, move the background
}
}
function moveUp(){
if(player.y>80){
player.y=player.y-4.1; //If you are at this position, move the player
}
else if(player.y<80){
updateY=updateY+4.1; //If you go over this position, move the background
}
}
function moveDown(){
if(player.y<500){
player.y=player.y+4.1; //If you are at this position, move the player
}
else if(player.y>500){
updateY=updateY-4.1; //If you go over this position, move the background
}
}
//-----------------------------------------------------------------------
//------------------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------
//------------------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------
//------------------------------------------------------------------------------------------------------
// MOVEMENT BOUNDARIES WITH TILES
function isPathTile(mapArray, x, y) {
return (mapArray[x][y] === 0); // Because 0 is the path tile
}
//-----------------------------------------------------------------------
//------------------------------------------------------------------------------------------------------
//-----------------------------------------------------------------------
//------------------------------------------------------------------------------------------------------
// THE GAME LOOP
function gameLoop(){
console.log("index X =" + heroIndexXnew);
console.log("index Y =" + heroIndexYnew);
playerMovement(); //Check for movements
drawMap(); //Draw the map and the player
requestAnimationFrame(gameLoop);
}
//-----------------------------------------------------------------------
//------------------------------------------------------------------------------------------------------
gameLoop(); // start the gameLoop
#canvas{
border: 1px solid black;
}
<canvas id="canvas" height="650px" width="1000px"></canvas>
All the code has some vars, the tilemap array, drawing the tilemap in only the visible part of the canvas , the player of course with it for every time it draws, then we have the movement and where I believe something is not set correctly. There is a function isPathTile to see if the index next to the current player location is 0 and if it is, it does nothing (when right pressed, so the player does not move). I think that this is where I got it wrong. Much appreciated if anyone can take can a look at this.
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<style>
body {
background-color: black;
}
canvas {
position: absolute;
margin: auto;
left: 0;
right: 0;
border: solid 1px white;
}
</style>
</head>
<body>
<canvas id="canvas"></canvas>
<script type="application/javascript">
// IIFE
// https://developer.mozilla.org/en-US/docs/Glossary/IIFE
void function() {
// Enforce strict mode inside the IIFE
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Strict_mode
"use strict";
// Var declaration
var canvasWidth = 320;
var canvasHeight = 320;
var canvas = null;
var ctx = null;
var player = {
// Position
x: 35.0,
y: 35.0,
// Velocity
dx: 0.0,
dy: 0.0,
// Size
width: 20,
height: 20,
// Input
up: false,
down: false,
left: false,
right: false
};
// Defined this way the map will need to be indexed as
// map[y][x]
// 0 = not solid
// 1 = solid
var mapTileSize = 32; // size for each tile in pixels
var map = [
[1,1,1,1,1,1,1,1,1,1],
[1,0,1,0,0,0,0,0,1,1],
[1,0,0,1,1,1,0,1,0,1],
[1,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,1],
[1,0,1,1,1,1,0,1,0,1],
[1,0,0,0,0,0,0,1,0,1],
[1,0,0,0,0,0,0,0,0,1],
[1,1,1,1,1,1,1,1,1,1]
];
// Runs after the page has finished loading
window.onload = function() {
canvas = document.getElementById("canvas");
canvas.width = canvasWidth;
canvas.height = canvasHeight;
ctx = canvas.getContext("2d");
loop();
}
// Key Input
window.onkeydown = function(e) {
switch(e.key) {
case "w": player.up = true; break;
case "s": player.down = true; break;
case "a": player.left = true; break;
case "d": player.right = true; break;
}
}
window.onkeyup = function(e) {
switch(e.key) {
case "w": player.up = false; break;
case "s": player.down = false; break;
case "a": player.left = false; break;
case "d": player.right = false; break;
}
}
function loop() {
// Tick
// Player movement
if (player.up) {
player.dy = -2;
}
if (player.down) {
player.dy = +2;
}
if (!player.up && !player.down) {
player.dy = 0;
}
if (player.left) {
player.dx = -2;
}
if (player.right) {
player.dx = +2;
}
if (!player.left && !player.right) {
player.dx = 0;
}
// Collision detection & resolution
// Only perform collision detection in either axis
// if the player is actually moving on that axis
// Map grid coordinates at the corners of the player's bounding box
/*
-> *-----* <-
| |
| |
| |
-> *-----* <-
*/
var invMapTileSize = 1.0 / mapTileSize;
var nextX = player.x + player.dx;
var nextY = player.y + player.dy;
// Current position
var currentMinX = (player.x * invMapTileSize) | 0;
var currentMaxX = ((player.x + player.width) * invMapTileSize) | 0;
var currentMinY = (player.y * invMapTileSize) | 0;
var currentMaxY = ((player.y + player.height) * invMapTileSize) | 0;
// Next position
var nextMinX = (nextX * invMapTileSize) | 0;
var nextMaxX = ((nextX + player.width) * invMapTileSize) | 0;
var nextMinY = (nextY * invMapTileSize) | 0;
var nextMaxY = ((nextY + player.height) * invMapTileSize) | 0;
/*
Collision checks are performed down along each axis of the player's
collision box, this way it won't matter if the player is larger
or smaller then the map tiles.
*/
// X axis collision
if (player.dx !== 0.0) {
for (var x = nextMinX; x <= nextMaxX; ++x) {
for (var y = currentMinY; y <= currentMaxY; ++y) {
if (map[y][x]) {
player.dx = 0.0;
break;
}
}
}
}
// Y axis collision
if (player.dy !== 0.0) {
for (var y = nextMinY; y <= nextMaxY; ++y) {
for (var x = currentMinX; x <= currentMaxX; ++x) {
if (map[y][x]) {
player.dy = 0.0;
break;
}
}
}
}
// Update player position
player.x = player.x + player.dx;
player.y = player.y + player.dy;
// render
ctx.fillStyle = "gray";
ctx.fillRect(0,0,canvasWidth,canvasHeight);
// draw map
ctx.fillStyle = "darkred";
ctx.beginPath();
for (var y = 0; y < map.length; ++y) {
for (var x = 0; x < map[0].length; ++x) {
if (map[y][x]) {
ctx.rect(
x * mapTileSize,
y * mapTileSize,
mapTileSize,
mapTileSize
);
}
}
}
ctx.fill();
// draw player
ctx.fillStyle = "darkblue";
ctx.fillRect(
player.x,
player.y,
player.width,
player.height
);
//
requestAnimationFrame(loop);
}
}();
</script>
</body>
</html>
After about a week was giving up on this one :D and finally figured it out. I was switching the places of my X and Y indexes and that is why it was not acting as it should be. Showing up the fix here if anyone is interested (only the Player movement has to be updated):
function playerMovement(){
//------------------------------
//CHECK PLAYER X AND Y IN TILE INDEXES
heroX = -updateX + player.x;
heroY = -updateY + player.y;
heroIndexX = heroX/64; // get the X index
heroIndexY = heroY/64; // get the Y index
heroIndexXnew = Math.ceil(heroIndexX);
heroIndexYnew = Math.ceil(heroIndexY);
if(rightPressed) {
player_image.src = './images/horseright1.png';
if(player.x>updateX+1258){ // Nothing happens because you hit the right wall
}else if (isPathTile(mapArray, heroIndexYnew, heroIndexXnew)){ // Nothing happens because you hit a tile
}else {
moveRight(); // if you are not at the wall, you go right
}
}
//------------------------------
else if(leftPressed) {
player_image.src = './images/horseleft1.png';
if(player.x<updateX+128){ // Nothing happens because you hit the left wall
}else if (isPathTile(mapArray, heroIndexYnew, heroIndexXnew - 1)){ // Nothing happens because you hit a tile
}else {
moveLeft(); // if you are not at the wall, you go left
}
}
//------------------------------
if(downPressed) {
if(player.y>updateY+834){ // Nothing happens because you hit the bottom wall
}else if (isPathTile(mapArray, heroIndexYnew, heroIndexXnew)){ // Nothing happens because you hit a tile
}else {
moveDown(); // if you are not at the wall, you go down
}
}
//------------------------------
else if(upPressed) {
if(player.y<updateY+64){ // Nothing happens because you hit the top wall
}else if (isPathTile(mapArray, heroIndexYnew - 1, heroIndexXnew)){ // Nothing happens because you hit a tile
}else {
moveUp(); // if you are not at the wall, you go up
}
}
}
A simple mistake and took me one hell of a time for debugging, though the logic is good and simple. Needs a bit of a touch on how it collides exactly as there are few things to be updated, but overall it works great!

Categories

Resources