Here is the code, how would i go on about making the bullets fired (size 6x6 pixels) collide with the blocks currently on the map? I've looked at all sort of collision code but I can't seem to apply it to this particular code because of how the map is setup i'm guessing.
Desperately need a solution!
// inner variables
var canvas, context; // canvas and context objects
var imgBrick, imgSteel, imgWater, imgForest, imgTank; // images
var aMap; // map array
var oTank; // tank object
var bullets = [];
var iCellSize = 24; // cell wide
var iXCnt = 26; // amount of X cells
var iYCnt = 26; // amount of Y cells
// objects :
function Tank(x, y, w, h, image) {
this.x = x;
this.y = y;
this.w = w;
this.h = h;
this.i = 0;
this.image = image;
}
function Bullet(dir, bullX, bullY, bulltype) {
this.direct = dir;
this.bullX = bullX;
this.bullY = bullY;
this.bulltype = bulltype;
}
// functions
function clear() { // clear canvas function
context.clearRect(0, 0, canvas.width, canvas.height);
}
// Firing bullets and directions
function movebullets()
{
for (var i = 0; i < bullets.length; i++) {
if (bullets[i].direct==2)
{
bullets[i].bullY-=10;
}
else if (bullets[i].direct==3)
{
bullets[i].bullY+=10;
}
else if (bullets[i].direct==0)
{
bullets[i].bullX+=10;
}
else if (bullets[i].direct==1)
{
bullets[i].bullX-=10;
}
}
}
/*
function bulletCollision(){
var remove = false;
for(var i = 0; i < bullets.length; i++){
for(var j = 0; j < asteroids.length; j++){
if(bullets[i].y <= (asteroids[j].y + enemies[j].h) && bullets[i].x >= enemies[j].x && bullets[i].x <= (enemies[j].x + enemies[j].w)){
remove = true;
enemies[j].dead = true;
//score++;
//explosions.push(new Explosion((asteroids[j].x + (asteroids[j].w / 2)), (asteroids[j].y + (asteroids[j].h / 2 )), asteroids[j].w));
enemies.splice(j,1);
}
}
*/
function drawScene() { // main drawScene function
clear(); // clear canvas
// fill background
context.fillStyle = '#111';
context.fillRect(0, 0, canvas.width, canvas.height);
// save current context
context.save();
// walk through our array
for (var y = 0; y < iYCnt; y++) {
for (var x = 0; x < iXCnt; x++) {
switch (aMap[y][x]) {
case 0: // skip
break;
case 1: // draw brick block
context.drawImage(imgBrick, 0, 0, iCellSize, iCellSize, x*iCellSize, y*iCellSize, iCellSize, iCellSize);
break;
case 2: // draw steel block
context.drawImage(imgSteel, 0, 0, iCellSize, iCellSize, x*iCellSize, y*iCellSize, iCellSize, iCellSize);
break;
case 3: // draw forest block
context.drawImage(imgForest, 0, 0, iCellSize, iCellSize, x*iCellSize, y*iCellSize, iCellSize, iCellSize);
break;
case 4: // draw water block
context.drawImage(imgWater, 0, 0, iCellSize, iCellSize, x*iCellSize, y*iCellSize, iCellSize, iCellSize);
break;
}
}
}
// restore current context
context.restore();
// draw tank + bullets
context.drawImage(oTank.image, oTank.i*oTank.w, 0, oTank.w, oTank.h, oTank.x, oTank.y, oTank.w, oTank.h);
for (var i = 0; i < bullets.length; i++) {
context.drawImage(imgBullet, bullets[i].bullX, bullets[i].bullY);
}
}
// -------------------------------------------------------------
// initialization
$(function(){
canvas = document.getElementById('scene');
canvas.width = iXCnt * iCellSize;
canvas.height = iYCnt * iCellSize;
context = canvas.getContext('2d');
// main scene Map array
aMap = ([
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 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, 0, 0],
[0, 0, 1, 1, 2, 2, 2, 2, 0, 0, 2, 2, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 1, 1, 2, 2, 2, 2, 0, 0, 2, 2, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 4, 4, 4, 4, 1, 1, 3, 3, 3, 3, 3, 3, 4, 4, 1, 1, 0, 0, 2, 2, 0, 0],
[0, 0, 0, 0, 4, 4, 4, 4, 1, 1, 3, 3, 3, 3, 3, 3, 4, 4, 1, 1, 0, 0, 2, 2, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 4, 4, 1, 1, 1, 1, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 4, 4, 1, 1, 1, 1, 0, 0, 0, 0],
[0, 0, 2, 2, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 2, 2, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[3, 3, 3, 3, 1, 1, 0, 0, 4, 4, 4, 4, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0],
[3, 3, 3, 3, 1, 1, 0, 0, 4, 4, 4, 4, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0],
[3, 3, 3, 3, 3, 3, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 3, 3],
[3, 3, 3, 3, 3, 3, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 3, 3],
[0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[2, 2, 0, 0, 0, 0, 0, 0, 3, 3, 0, 0, 2, 2, 0, 0, 3, 3, 4, 4, 0, 0, 1, 1, 0, 0],
[2, 2, 0, 0, 0, 0, 0, 0, 3, 3, 0, 0, 2, 2, 0, 0, 3, 3, 4, 4, 0, 0, 1, 1, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 0, 0, 2, 2, 0, 0, 3, 3, 4, 4, 0, 0, 2, 3, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 0, 0, 2, 2, 0, 0, 3, 3, 4, 4, 0, 0, 2, 3, 0, 0],
[0, 0, 0, 0, 0, 0, 2, 2, 3, 3, 0, 0, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 2, 3, 0, 0],
[0, 0, 0, 0, 0, 0, 2, 2, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 3, 0, 0],
[0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0]
]);
// load images
imgBrick = new Image();
imgBrick.src = 'images/brick.png';
imgSteel = new Image();
imgSteel.src = 'images/steel.png';
imgWater = new Image();
imgWater.src = 'images/water.png';
imgForest = new Image();
imgForest.src = 'images/forest.png';
imgBullet = new Image();
imgBullet.src = 'images/bullet.png';
imgTank = new Image();
imgTank.src = 'images/tank.png';
oTank = new Tank(iCellSize*9, iCellSize*24, 48, 48, imgTank);
document.addEventListener('mousedown', function (event) {
bullets.push(new Bullet(oTank.i, oTank.x+24, oTank.y+24, 1));
(function(){
var sound = new Audio('bullet_shot.ogg');
sound.volume = 0.9;
sound.addEventListener('ended', function() { // loop the sound
}, false);
sound.play();
})();
});
$(window).keydown(function(event){ // keyboard alerts
switch (event.keyCode) {
case 87: // W key
oTank.i = 2;
// checking collisions
var iCurCelX = (2 * oTank.x) / 48;
var iCurCelY = (2 * oTank.y) / 48;
if (iCurCelY) {
var iTest1 = aMap[iCurCelY-1][iCurCelX];
var iTest2 = aMap[iCurCelY-1][iCurCelX+1];
if ((iTest1 == 0 || iTest1 == 3) && (iTest2 == 0 || iTest2 == 3)) {
oTank.y-=24;
if (oTank.y < 0) {
oTank.y = 0;
}
}
}
break;
case 83: // S key
oTank.i = 3;
// checking collisions
var iCurCelX = (2 * oTank.x) / 48;
var iCurCelY = (2 * oTank.y) / 48;
if (iCurCelY+2 < iYCnt) {
var iTest1 = aMap[iCurCelY+2][iCurCelX];
var iTest2 = aMap[iCurCelY+2][iCurCelX+1];
if ((iTest1 == 0 || iTest1 == 3) && (iTest2 == 0 || iTest2 == 3)) {
oTank.y+=24;
if (oTank.y > 576) { //iCellSize * (iYCnt-2)
oTank.y = 576;
}
}
}
break;
case 65: // A key
oTank.i = 1;
// checking collisions
var iCurCelX = (2 * oTank.x) / 48;
var iCurCelY = (2 * oTank.y) / 48;
var iTest1 = aMap[iCurCelY][iCurCelX-1];
var iTest2 = aMap[iCurCelY+1][iCurCelX-1];
if ((iTest1 == 0 || iTest1 == 3) && (iTest2 == 0 || iTest2 == 3)) {
oTank.x-=24;
if (oTank.x < 0) {
oTank.x = 0;
}
}
break;
case 68: // D key
oTank.i = 0;
// checking collisions
var iCurCelX = (2 * oTank.x) / 48;
var iCurCelY = (2 * oTank.y) / 48;
var iTest1 = aMap[iCurCelY][iCurCelX+2];
var iTest2 = aMap[iCurCelY+1][iCurCelX+2];
if ((iTest1 == 0 || iTest1 == 3) && (iTest2 == 0 || iTest2 == 3)) {
oTank.x+=24;
if (oTank.x > 576) { //iCellSize * (iXCnt-2)
oTank.x = 576;
}
}
break;
}
});
setInterval(drawScene, 40); // loop drawScene
setInterval(movebullets, 40);
});
you need to set the bullet size like this inside the for
for (var i = 0; i < bullets.length; i++) {
//6px width and height
context.drawImage(imgBullet, bullets[i].bullX, bullets[i].bullY,6,6);
}
and inside movebullets() you can call bulletCollision like this
function movebullets()
{
for (var i = 0; i < bullets.length; i++) {
if (bullets[i].direct==2)
{
bullets[i].bullY-=10;
}
else if (bullets[i].direct==3)
{
bullets[i].bullY+=10;
}
else if (bullets[i].direct==0)
{
bullets[i].bullX+=10;
}
else if (bullets[i].direct==1)
{
bullets[i].bullX-=10;
}
bulletCollision(i);
}
}
function bulletCollision(i){
//if the aMap value in the bullet position is not 0
if(aMap[parseInt(bullets[i].bullY/iCellSize)][parseInt(bullets[i].bullX/iCellSize)]!=0){
alert("Collision");//do something
bullets.splice(i, 1);//remove the current bullet
}
}
Related
Im writing a Tomb of the Mask game clone in Canvas for an assignment, and I wanted to create a small animation so that when my character "Snaps" to the next wall, it doesnt just "teleport" like it does now.
See here for a live review: https://codepen.io/SkylerSpark/pen/GRpdzBZ
Currently I have a big keydown event and a switch case that detects for any of the 4 arrow keys, this is an example of one of the case statements:
case "ArrowLeft":
if (map[playerCoords[1]][playerCoords[0] - 1] != 1) {
while (map[playerCoords[1]][playerCoords[0] - 1] != 1) {
playerCoords[0]--;
}
}
Ill split up those map statements for a better understanding:
map[playerCoords[1]][playerCoords[0] - 1] != 1
map[] - Main Map Data (1s and 0s that determine the game layout)
playerCoords[0 / 1] - Location of the Player
map[ pc[1] ] (going to get the sub array of map[playerCoords[1]]) > [pc[0] - 1] (-1 to look for the block to the left of the player)
then Im selecting all of that into one statement and detecting if its equal to 1 (1 is a brick block) to see if the player should MOVE or NOT MOVE.
Anyways, I have an animationFrame running on my player location at ALL TIMES so that if any adjustments are made, it will show them.
The while loops I use to send the player to the opposite wall (rather than just moving 1 block to the left or right, it needs to work JUST like TotM) are just immediately sending the results. I want it to quickly move all those blocks 1 by 1 but barely noticable...
Is it possible I can add some kind of "delay" inside the while loops so it can move 1 block, then wait 10 milliseconds, and then the next, so on so fourth?
Full Game and Code:
View in FULL PAGE or it wont work correctly..
const cvs = document.querySelector(".bastione"),
ctx = cvs.getContext("2d");
const cvs2 = document.querySelector(".basPlayer"),
ctx2 = cvs2.getContext("2d");
ctx.imageSmoothingEnabled = ctx.mozImageSmoothingEnabled = ctx.webkitImageSmoothingEnabled = false;
ctx2.imageSmoothingEnabled = ctx2.mozImageSmoothingEnabled = ctx2.webkitImageSmoothingEnabled = false;
function loadImage(src, callback) {
var img = new Image();
img.onload = callback;
img.setAttribute("crossorigin", "anonymous");
img.src = src;
return img;
}
function ran(min, max) {
return Math.floor(Math.random() * (max - min + 1) + min);
}
const map = [
[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, 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, 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, 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, 1],
[1, 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, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
[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, 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, 1, 1],
[1, 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, 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, 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, 1],
[1, 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, 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, 3, 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]
];
const drawEnvironment = {
init: () => {
drawEnvironment.renderBack();
},
renderBack: () => {
let cx = 0, cy = 0;
map.forEach(e => {
for (var i = 0; i < e.length; i++) {
if (e[i] == 1) {
let v = ran(0, 10);
if (v > 0 && v < 8) {
ctx.drawImage(spriteImage, 0, 0, 32, 32, cx, cy, 32, 32);
} else {
ctx.drawImage(spriteImage, 32, 0, 32, 32, cx, cy, 32, 32);
}
cx += 32;
} else if (e[i] == 2 || e[i] == 3) {
ctx.drawImage(spriteImage, 64, 64, 32, 32, cx, cy, 32, 32);
cx += 32;
} else {
let v = ran(0, 10);
if (v > 0 && v < 5) {
ctx.drawImage(spriteImage, 128, 64, 32, 32, cx, cy, 32, 32);
if (v == 10) {
ctx.drawImage(spriteImage, 128, 32, 32, 32, cx, cy, 32, 32);
}
} else {
ctx.drawImage(spriteImage, 128, 32, 32, 32, cx, cy, 32, 32);
}
cx += 32;
}
}
cx = 0;
cy += 32;
});
ctx.drawImage(spriteImage, 0, 0, 32, 32, 0, 0, 32, 32);
}
};
let playerCoords = [1, 1];
const drawPlayer = {
init: () => {
drawPlayer.playerLoc();
drawPlayer.playerMove();
},
playerLoc: () => {
ctx2.drawImage(spriteImage, 0, 64, 32, 32, playerCoords[0] * 32, playerCoords[1] * 32, 32, 32);
window.requestAnimationFrame(drawPlayer.playerLoc);
},
playerMove: () => {
document.addEventListener("keydown", function(event) {
ctx2.clearRect(0, 0, cvs2.width, cvs2.height);
event.preventDefault();
const key = event.key;
switch (key) {
case "ArrowLeft":
if (map[playerCoords[1]][playerCoords[0] - 1] != 1) {
while (map[playerCoords[1]][playerCoords[0] - 1] != 1) {
playerCoords[0]--;
}
}
break;
case "ArrowRight":
if (map[playerCoords[1]][playerCoords[0] + 1] != 1) {
while (map[playerCoords[1]][playerCoords[0] + 1] != 1) {
playerCoords[0]++;
}
}
break;
case "ArrowUp":
if (map[playerCoords[1] - 1][playerCoords[0]] != 1) {
while (map[playerCoords[1] - 1][playerCoords[0]] != 1) {
playerCoords[1]--;
}
}
break;
case "ArrowDown":
if (map[playerCoords[1] + 1][playerCoords[0]] != 1) {
while (map[playerCoords[1] + 1][playerCoords[0]] != 1) {
playerCoords[1]++;
}
}
break;
}
});
}
}
const spriteImage = loadImage(
"https://cdn.jsdelivr.net/gh/FunctFlow/Bastione-Game#1d0514c968a737061916ae5e160b20eaf3a6b8b4/Sprites/Bastione_Sprites.png",
() => {
drawEnvironment.init();
drawPlayer.init();
}
);
* {
box-sizing: border-box;
overflow: hidden;
}
body {
text-align: center;
background: black;
}
canvas {
display: inline-block;
}
.basPlayer {
position: absolute;
margin-left: -1024px;
}
<canvas class=bastione width=1024 height=512></canvas>
<canvas class=basPlayer width=1024 height=512></canvas>
View in FULL PAGE or it wont work correctly..
You can use setInterval to create a loop which runs at a specific frequency.
case "ArrowLeft":
if (map[playerCoords[1]][playerCoords[0] - 1] != 1) {
let interval = setInterval(() => {
if (map[playerCoords[1]][playerCoords[0] - 1] != 1) {
// Stop the interval, and do nothing.
clearInterval(interval)
return
}
playerCoords[0]--;
}, 100) // <- 100 here is delay in milliseconds
}
This code is now running asynchronously. This means that while we are waiting for the delay, other code can run. If we are not careful, this can introduce bugs. For example: You need to think about what would happen if the player presses arrowRight while the arrowLeft is still being processed. If you do not fix that case, the character will move both left and right at the same time, which would mean that he would never hit a wall and you would be stuck in an endless loop.
This is BIG TOPIC
The normal thing to do would be for each thing (player, monster, etc..) to give them some kind of update function
const allTheThings = [];
function loop() {
for (const thing of things) {
thing.update();
}
requestAnimationFrame(loop);
}
In each of those update functions you would do whatever is appropriate for that thing doing only what is need at this moment. So for example the player might have a update function like this
class Player() {
constructor() {
this.coords = [1, 1];
this.delta = [0, 0];
}
update() {
if (this.waiting) {
this.waiting -= 1;
} else if (this.moving) {
this.coords[0] = this.delta[0];
this.coords[1] = this.delta[1];
this.waiting = 10;
} else {
// check the keys
// and set this.delta and moving appropriately
}
}
}
Then you can make a player and add it to this array of allTheThings
const player = new Player();
allTheThings.push(player);
Note that is way over simplified. Most games don't directly update in an object like that. Instead, just like allTheThings calls update for each thing, a thing itself might have a list of subthings (components) each of which also has an update function. A thing, or a GameThing, is a collection of these components.
Further, there are all kinds of ways to help organize what those update functions do. In the example above there were 2 flags moving and waiting but as the game gets more and more complicated there get to be too many flags so people have come up with things like Finite State Machines and Coroutines and may other techniques to help make that stuff simpler.
Maybe not useful but here is an article that uses some of these techniques.
Thanks to ViktorW, gman and VLAZ for the help and answers, I came up with a solution though:
so if you put a "run object" into the project, and have 4 sub variables with true/false, and change them depending on which key you press, you can make it work perfectly.
I followed ViktorW's answer and applied this idea, plus I just made a simple interval instead of the logic Viktor used:
so outside of my movement function, I have the run variable
let run = {
l: true,
r: true,
u: true,
d: true
}
theres variables for the 4 directions (Left Right Up Down)
Then just add the logic into the movement function + the interval and ITS logic:
case "ArrowLeft":
if (map[playerCoords[1]][playerCoords[0] - 1] != 1) {
if (run.l == true) { // Detect for direction
var lInterval = setInterval(() => {
if (map[playerCoords[1]][playerCoords[0] - 1] != 1) {
playerCoords[0]--;
run.r = run.u = run.d = false; // Set all other directions false
} else {
clearInterval(lInterval);
run.r = run.u = run.d = true; // Set all other directions true when done moving
}
}, 10);
}
}
break;
This PERFECTLY prevents the opposing movement of of the block if you use an interval to achieve the animation.
Check it out live here, use arrow keys to control: Tomb of the Mask Clone
var gameMap = [ [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
[1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1],
[1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1,0,1,0,1],
[1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1],
[1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1,0,1,1,1],
[1,1,1,0,1,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,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,1],
[1,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,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,1],
[1,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,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,1],
[1,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,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,1],
[1,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] ]
var can = document.getElementById('gc')
var c = can.getContext('2d')
var di = null
var start = [0,0]
var end = [5,5]
document.addEventListener('keydown',keydown)
document.addEventListener('keyup',keyup)
function update() {
c.clearRect(0,0,can.width,can.height)
switch(di) {
case 'left':
start[0] -= 1
end[0] -= 1
break;
case 'up':
start[1] -= 1
end[1] -= 1
break;
case 'right':
start[0] += 1
end[0] += 1
break;
case 'down':
start[1] += 1
end[1] += 1
break;
}
if(start[0]<0) {
start[0] = 0;
}if(start[1]<0) {
start[1] = 0
}if(end[0]>20) {
end[0] = 20
}if(end[1]>20) {
end[1] = 20
}
can.style.border = '1px black solid'
map()
requestAnimationFrame(update)
}
requestAnimationFrame(update)
function keydown(evt) {
switch(evt.keyCode) {
case 37:
di = 'left'
break;
case 38:
di = 'up'
break;
case 39:
di = 'right'
break;
case 40:
di = 'down'
break;
}
}
function keyup() {
di = null
}
function map() {
var mapx = 0
var mapy = 0
for(var i = start[1]; i<end[1]; i++) {
for(var j = start[0]; j<end[0]; j++) {
switch(gameMap[i][j]) {
case 1:
c.fillRect(mapx,mapy,30,30)
break;
case 0:
break;
}
mapx+=30
}
mapy+=30
mapx = 0
}
}
<!doctype html>
<html>
<canvas id='gc' width=200 height=200></canvas>
</html>
We have a tile map
We have a start and an end
And a draw map function.
When the 'di' (direction) goes above the array, the screen will become white.
So I tried to prevent it by making sure that the start[0], start[1], end[0], end[1] does not exceed the array.
However, the drawing was reduced (try to go out of the array in the snippet)
Why is this so?
You need some adjustmets if the pane goes out of range.
The adjustment bases on the pane width or height and the data array size.
I suggest to call requestAnimationFrame first on run time and then after an event.
Mabe you combine map and update actually it is not clear, what they are for, especially because both handles canvas operations.
function update() {
can.style.border = '1px black solid';
map();
}
function keydown(evt) {
di = { 37: 'left', 38: 'up', 39: 'right', 40: 'down' }[evt.keyCode];
switch (di) {
case 'left':
start[0]--;
end[0]--;
break;
case 'up':
start[1]--;
end[1]--;
break;
case 'right':
start[0]++;
end[0]++;
break;
case 'down':
start[1]++;
end[1]++;
break;
}
if (start[0] < 0) {
start[0] = 0;
end[0] = paneWidth;
}
if (start[1] < 0) {
start[1] = 0;
end[1] = paneHeight;
}
if (end[0] > gameMap[0].length) {
start[0] = gameMap[0].length - paneWidth;
end[0] = gameMap[0].length;
}
if (end[1] > gameMap.length) {
start[1] = gameMap.length - paneHeight;
end[1] = gameMap.length;
}
requestAnimationFrame(update);
}
function keyup() {
di = null;
}
function map() {
var mapx = 0,
mapy = 0;
c.clearRect(0, 0, can.width, can.height);
for (var i = start[1]; i < end[1]; i++) {
for (var j = start[0]; j < end[0]; j++) {
switch (gameMap[i][j]) {
case 1:
c.fillRect(mapx, mapy, 30, 30);
break;
case 0:
break;
}
mapx += 30;
}
mapy += 30;
mapx = 0;
}
}
var gameMap = [
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
[1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1],
[1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1],
[1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1],
[1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1],
[1, 1, 1, 0, 1, 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, 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, 1],
[1, 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, 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, 1],
[1, 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, 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, 1],
[1, 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, 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, 1],
[1, 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]
],
can = document.getElementById('gc'),
c = can.getContext('2d'),
di = null,
paneWidth = 6,
paneHeight = 6,
start = [0, 0],
end = [paneWidth, paneHeight];
document.addEventListener('keydown', keydown);
document.addEventListener('keyup', keyup);
requestAnimationFrame(update);
<canvas id="gc" width="180" height="180"></canvas>
You have 8 constraints to enforce and are only enforcing 4.
Eg. your code ensures that start[0] >= 0 but it doesn't ensure start[0] < 20.
I am developing a game where the character has to move through the bricks(hurdles) which comes randomly in the screen.
FACING CHALLENGE
I want to get the co-ordinates of the character in order to find out whether the character has hit the brick
Here is my code
gamer = (function () {
//global function
var c = document.getElementById("canvas");
var ctx = c.getContext("2d");
var blocks = c.getContext('2d');
var marioArray = [
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0],
[0, 0, 0, 3, 3, 3, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0],
[0, 0, 3, 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0],
[0, 0, 3, 1, 3, 3, 1, 1, 1, 1, 3, 1, 1, 1, 0, 0, 0],
[0, 0, 3, 3, 1, 1, 1, 1, 1, 3, 3, 3, 3, 0, 0, 0, 0],
[0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0],
[0, 0, 2, 2, 2, 4, 2, 2, 4, 2, 0, 0, 0, 0, 0, 0, 0],
[0, 2, 2, 2, 2, 4, 2, 2, 4, 2, 2, 2, 0, 0, 0, 0, 0],
[2, 2, 2, 2, 2, 4, 4, 4, 4, 2, 2, 2, 2, 0, 0, 0, 0],
[1, 1, 1, 2, 4, 1, 4, 4, 1, 4, 2, 1, 1, 0, 0, 0, 0],
[1, 1, 1, 1, 4, 4, 4, 4, 4, 4, 1, 1, 1, 0, 0, 0, 0],
[1, 1, 1, 4, 4, 4, 4, 4, 4, 4, 4, 1, 1, 0, 0, 0, 0],
[0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0],
[0, 0, 4, 4, 4, 4, 4, 0, 4, 4, 4, 4, 0, 0, 0, 0, 0],
[0, 4, 4, 4, 4, 4, 4, 0, 4, 4, 4, 4, 4, 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]
];
var width = 3;
var height = 3;
var motion = 5;
var globalX = 0;
var globalY = 0;
this.canvasWidth = c.width;
this.canvasHeight = c.height;
this.structureHeight = height * marioArray.length;
this.structureWidth = width * marioArray.length;
var flightStrength = 40;
drawMario = (x, y) => {
this.xPos = x;
this.yPos = y;
globalX = x;
globalY = y;
// starting position
ctx.clearRect(0, 0, canvasWidth, canvasHeight);
for (var i = 0; i < marioArray.length; i++) {
for (var r = 0; r < marioArray[i].length; r++) {
ctx.fillRect(xPos, yPos, width, height);
//black
if (marioArray[i][r] === 0) {
ctx.fillStyle = "#000000";
}
//flesh
if (marioArray[i][r] === 1) {
ctx.fillStyle = "#FFCC66";
}
//red
if (marioArray[i][r] === 2) {
ctx.fillStyle = "#FF0000";
}
//brown
if (marioArray[i][r] === 3) {
ctx.fillStyle = "#663300";
}
//blue
if (marioArray[i][r] === 4) {
ctx.fillStyle = "#66CCFF";
}
//move over 32px
xPos += width;
}//end internal for loop
//once ctx reaches end on canvas reset xPos to 0
xPos = x;
//move down 32px
yPos += height;
}//end for loop
// ctx.drawImage(image, 0, 0, 10, 10, 10, 10);
};
keyPressEvent = () => {
document.onkeydown = function (e) {
switch (e.keyCode) {
case 37:
//left
if (globalX <= 0)
return false;
globalX -= motion;
drawMario(globalX, globalY);
break;
case 38:
//up
if (globalY < (c.height - (structureHeight + flightStrength))) {
bringDown();
} else {
globalY -= motion;
drawMario(globalX, globalY);
}
break;
case 39:
//right
if (globalX >= (canvasWidth - structureWidth))
return false;
globalX += motion;
drawMario(globalX, globalY);
break;
case 40:
alert('down');
break;
}
};
bringDown = () => {
var interval = setInterval(function () {
if (globalY <= (this.canvasHeight - this.structureHeight)) {
drawMario(globalX, globalY);
globalY += motion;
} else {
globalY = (this.canvasHeight - this.structureHeight);
clearInterval(interval);
}
}, 80)
};
document.onkeyup = function (e) {
switch (e.keyCode) {
case 38:
bringDown();
break;
}
}
};
return {
mario: drawMario,
key: keyPressEvent
}
})();
gamer.mario(0, (this.canvasHeight - this.structureHeight));
gamer.key();
In the above code, i am creating a new context
var blocks = c.getContext('2d');
and will be placing somewhere in the canvas, i want to find out whether my character has hit the object, how can i find the co-ordinate
So, I am making a maze, in javascript. I do not know how to display an array (such as 1's and 0's) graphically. The best way is to show you the code:
var maze= [
[0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,0,1,0,0,0],
[0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,0,1,0,0,1],
[0,0,1,1,1,0,0,1,1,0,0,1,0,0,0,0,1,0,0,1],
[0,0,1,0,1,0,0,1,1,0,0,1,0,0,0,0,1,0,0,1],
[0,0,1,0,1,1,0,1,0,0,0,1,1,1,0,0,1,0,0,0],
[0,0,1,1,0,1,1,0,0,0,0,0,0,1,0,0,1,1,1,1],
[0,0,0,1,1,0,1,1,1,1,1,1,0,0,0,0,0,1,0,1],
[0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,1],
];
With the 0's representing walls, and the 1's representing empty space, and 2 meaning the end of the maze, how can I display this as a maze using only javascript? Shall I make each 0 an individual rectangle? How can I do this?
Please do not make fun as I am just starting out.
Here is the code for reference (this is on "coding with chrome", as it was the easiest to use, as I did not have to import anything).
//PART 1 : THE CHARACTER
//Where is the character???
charX=10;
charY=10;
//Draw char
function drawChar(){
draw.circle(charX, charY, 5, "black");
}
//Loop happens at 40 milliseconds
setInterval (loop, 40);
//loop that clears screen
function loop(){
draw.rectangle(0,0, window.innerWidth, window.innerHeight,"white");
drawChar();
}
//Move Character
document.addEventListener("keydown", moveChar);
function moveChar (e) {
if(e.keyCode ==37){
//Left arrow
charX=charX-50;
}
if(e.keyCode== 38){
//Up arrow
charY=charY-50;
}
if(e.keyCode == 39){
//right arrow
charX=charX+50;
}
if(e.keyCode == 40){
//down arrow
charY=charY +50;
}
//PART 1 DONE :-)
//PART 2: Walls
//map of maze
var maze= [
[0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,0,1,0,0,0],
[0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,0,1,0,0,1],
[0,0,1,1,1,0,0,1,1,0,0,1,0,0,0,0,1,0,0,1],
[0,0,1,0,1,0,0,1,1,0,0,1,0,0,0,0,1,0,0,1],
[0,0,1,0,1,1,0,1,0,0,0,1,1,1,0,0,1,0,0,0],
[0,0,1,1,0,1,1,0,0,0,0,0,0,1,0,0,1,1,1,1],
[0,0,0,1,1,0,1,1,1,1,1,1,0,0,0,0,0,1,0,1],
[0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,1],
];
//How can we display this graphically, with the 0 being a wall, and 1 being an empty space?
span {
white-space: pre;
display: inline-block;
width: 24px;
}
<script>
var maze = [
[0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0],
[0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1],
[0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1],
[0, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1],
[0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0],
[0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1],
[0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 1],
[0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 1],
];
maze.forEach(function(arr, index) {
arr.forEach(function(path, i) {
var span = document.createElement("span");
if (path === 0) {
span.textContent = " ";
span.style.backgroundColor = "#000";
}
if (path === 1) {
span.textContent = " ";
span.style.backgroundColor = "yellow";
}
if (path === 2) {
span.textContent = "end";
span.style.backgroundColor = "green";
span.style.color = "gold";
}
document.body.appendChild(span)
});
document.body.appendChild(document.createElement("br"))
})
</script>
I'm making a platformer game in HTML5 Canvas and I have run into some collision problems. I've been experimenting with numerous collision algorithms but I can't seem to get any to work.
My question:
How can I get the blocks/darker grey squares to stop my ball from passing through it?
Some info about my code:
The map is dynamically generated
I have tried collision algorithms many times
Collision handling is done in the canMoveHere function and returns true or false to the moveAll function, where it is determined if the ball can move to the next square
My code on jsfiddle.net
My code download from Google Drive
My full code:
<html>
<head>
<canvas id ="gameCanvas" width = "500" height = "500" style = "border:1px solid black;"></canvas>
<script>
var canvas, canvasContext;
var framesPerSecond = 30;
var gravity = .2;
var leftKey = false;
var rightKey = false;
const TILE_H = 25;
const TILE_W = 25;
var map = [
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
[1, 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, 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, 1],
[1, 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, 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, 1],
[1, 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, 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, 1],
[1, 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, 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, 1],
[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1],
[1, 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, 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, 1],
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
];
var ball = {
`x:250`,
`y:250`,
`radius:10`,
color:"#ff9966",
`velocityX:5`,
`velocityY:1`,
`terminalVel:8`,
draw:function()
{
canvasContext.beginPath();
canvasContext.fillStyle = this.color;
canvasContext.arc(this.x, `this.y`, this.radius, 0, Math.PI * 2, false);
canvasContext.fill();
canvasContext.closePath();
}
};
document.addEventListener("keydown", function(evt)
{
if(evt.keyCode == 37)
{
leftKey = true;
}
if(evt.keyCode == 39)
{
rightKey = true;
}
});
document.addEventListener("keyup", function(evt)
{
if(evt.keyCode == 37)
{
leftKey = false;
}
if(evt.keyCode == 39)
{
rightKey = false;
}
});
window.onload = function()
{
canvas = document.getElementById("gameCanvas");
canvasContext = canvas.getContext("2d");
setInterval(function()
{
drawAll();
moveAll();
}, 1000/framesPerSecond);
}
var renderMap = function()
{
for(var eachRow=0; eachRow<20; eachRow++)
{
for(var eachCol=0; eachCol<20; eachCol++)
{
if(map[eachRow][eachCol] == 0)
{
canvasContext.fillStyle = "#a6a6a6";
canvasContext.fillRect(TILE_W*eachCol, TILE_H*eachRow, TILE_W, TILE_H);
}
if(map[eachRow][eachCol] == 1)
{
canvasContext.fillStyle = "#666666";
canvasContext.fillRect(TILE_W*eachCol, TILE_H*eachRow, TILE_W, TILE_H);
}
}
}
}
var drawAll = function()
{
canvasContext.clearRect(0, 0, canvas.width, canvas.height);
renderMap();
ball.draw();
}
var canMoveHere = function(col, row)
{
if(map[row][col] == 1)
{
return false;
}
else
{
return true;
}
}
var moveAll = function()
{
nextBallX = `ball.x` + ball.velocityX;
nextBallY = `ball.y` + ball.velocityY;
nextBallCol = Math.floor(nextBallX / TILE_W);
nextBallRow = Math.floor(nextBallY / TILE_H);
var canMove = canMoveHere(nextBallCol, nextBallRow);
ball.velocityY += gravity;
`ball.y` += ball.velocityY;
if(ball.velocityY >= ball.terminalVel)
{
ball.velocityY = ball.terminalVel;
}
if(canMove === false)
{
ball.velocityY *= -1;
}
if(leftKey)
{
`ball.x` -= ball.velocityX;
}
if(rightKey)
{
`ball.x` += ball.velocityX;
}
}
</script>
</head>
<body>
</body>
</html>
You can't just say "if the ball can or cannot move over certain tile", you have to tell the game how to respond when an obstacle is hit and that depends on two factors: current ball direction and shape of the obstacle.
I modified your canMoveHere function to evaluate that:
var directionChange = function(nextCol, nextRow)
{
var currentRow = Math.floor(ball.y / TILE_H);
var currentCol = Math.floor(ball.x / TILE_W);
var resultDirection = { x: 1, y: 1 };
if (map[nextRow][nextCol] == 1) {
if (map[nextRow][currentCol] == 1 &&
map[currentRow][nextCol] == 0) {
// horizontal obstacle
resultDirection.x = 1;
resultDirection.y = -1;
} else if (map[nextRow][currentCol] == 0 &&
map[currentRow][nextCol] == 1) {
// vertical obstacle
resultDirection.x = -1;
resultDirection.y = 1;
} else {
// corner obstacle
resultDirection.x = -1;
resultDirection.y = -1;
}
}
return resultDirection;
}
at this point we also modify the moveAll function accordingly
var moveAll = function()
{
nextBallX = ball.x + ball.velocityX;
nextBallY = ball.y + ball.velocityY;
nextBallCol = Math.floor(nextBallX / TILE_W);
nextBallRow = Math.floor(nextBallY / TILE_H);
let dir = directionChange(nextBallCol, nextBallRow);
ball.velocityY *= dir.y;
ball.velocityX *= dir.x;
ball.velocityY += gravity;
if(ball.velocityY >= ball.terminalVel)
{
ball.velocityY = ball.terminalVel;
}
ball.y += ball.velocityY;
if(leftKey) {
ball.x -= ball.velocityX;
}
if(rightKey) {
ball.x += ball.velocityX;
}
}
Now you just have to find a way to let the keys drive the ball smoothly, because changing the velocity using positive/negative values has an effect to the actual direction of the ball, because it will go to the opposite direction of the pressed key when values are negatives;
I tried using absolute values
if(leftKey) {
ball.x -= Math.abs(ball.velocityX);
}
if(rightKey) {
ball.x += Math.abs(ball.velocityX);
}
but as soon as the ball hits an obstacle, the pressed key will keep pushing the ball against the obstacle changing again the velocity and - for how it is built now - the ball will go through the walls.
Even though this isn't a bug-free solution, I hope this can help you on solving the main problem.