1

I'm trying to make a very simple mini-game where a character moves with keys. Multiple obstacles come at you from the right and you have to avoid them.

The problem is that the obstacles in the myObstacles array appear behind the background image. Why is it doing that and is there an easy fix that I'm missing?

Let me know if anything is unclear or I left out information. First time posting a question on here :)

var myGamePiece;
var myObstacles = [];
var myBackground;

function startGame() { 
    myGamePiece = new component(50, 50, "still.png", 10, 120, "image");
    myBackground = new component(1600, 400, "gamebkg.png", 0, 0, "background");
    myGameArea.start();
}


//board
var myGameArea = {
    canvas : document.createElement("canvas"),
    start : function() {
        this.canvas.width = 600;
        this.canvas.height = 600;
        this.context = this.canvas.getContext("2d");
        this.context.translate(0.5, 0.5);
        this.context.imageSmoothingQuality = "high";
        document.body.insertBefore(this.canvas, document.body.childNodes[0]);
        this.frameNo = 0;
        this.interval = setInterval(updateGameArea, 20);
        //keys to move
        window.addEventListener('keydown', function (e) {
        myGameArea.key = e.keyCode;
        })
        window.addEventListener('keyup', function (e) {
        myGameArea.key = false;
        })
    },
    clear : function() {
        this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
    },
    stop : function() {
        clearInterval(this.interval);
    }
}



function component(width, height, color, x, y, type) {
    this.type = type;
    if (type == "image" || type == "background") {
        this.image = new Image();
        this.image.src = color;
    }
    this.width = width;
    this.height = height;
    this.speedX = 0;
    this.speedY = 0;    
    this.x = x;
    this.y = y;    
    this.update = function() {
        ctx = myGameArea.context;
        if (type == "image" || type == "background") {
            ctx.drawImage(this.image, 
                this.x, 
                this.y,
                this.width, this.height);
        if (type == "background") {
            ctx.drawImage(this.image, 
                this.x + this.width, 
                this.y,
                this.width, this.height);
        }
        } else {
            ctx.fillStyle = color;
            ctx.fillRect(this.x, this.y, this.width, this.height);
        }
    }
    this.newPos = function() {
        this.x += this.speedX;
        this.y += this.speedY;
        if (this.type == "background") {
            if (this.x == -(this.width)) {
                this.x = 0;
            }
        }
    }    
    this.crashWith = function(otherobj) {
        var myleft = this.x;
        var myright = this.x + (this.width);
        var mytop = this.y;
        var mybottom = this.y + (this.height);
        var otherleft = otherobj.x;
        var otherright = otherobj.x + (otherobj.width);
        var othertop = otherobj.y;
        var otherbottom = otherobj.y + (otherobj.height);
        var crash = true;
    if ((mybottom < othertop) ||
        (mytop > otherbottom) ||
        (myright < otherleft) ||
        (myleft > otherright)) {
        crash = false;
    }
    return crash;
  }
}

function updateGameArea() {
   var x, y;
   for (i = 0; i < myObstacles.length; i += 1) {
        if (myGamePiece.crashWith(myObstacles[i])) {
            myGameArea.stop();
            return;
        }
    }

    myGameArea.clear();
    myGameArea.frameNo += 1;

    if (myGameArea.frameNo == 1 || everyinterval(150)) {
        x = myGameArea.canvas.width;
        y = myGameArea.canvas.height - 500;
        myObstacles.push(new component(30, 30, "feesh.png", x, y, "image"))
    }

    for (i = 0; i < myObstacles.length; i += 1) {
        myObstacles[i].x += -1;
        myObstacles[i].update();
    }

    myGamePiece.speedX = 0;
    myGamePiece.speedY = 0;
        if (myGameArea.key && myGameArea.key == 37) {myGamePiece.speedX = -5; }
        if (myGameArea.key && myGameArea.key == 39) {myGamePiece.speedX = 5; }
        if (myGameArea.key && myGameArea.key == 38) {myGamePiece.speedY = -5; }
        if (myGameArea.key && myGameArea.key == 40) {myGamePiece.speedY = 5; }
    myBackground.speedX = -1;
    myBackground.newPos();    
    myBackground.update();
    
    myGamePiece.newPos();    
    myGamePiece.update();
  
}

function everyinterval(n) {
    if ((myGameArea.frameNo / n) % 1 == 0) {return true;}
    return false;
}
pcmila
  • 23
  • 5
  • have you tried using a positive `z-index` to move them further to the top (layer-wise) already? – tacoshy Mar 03 '21 at 04:30
  • @tacoshy I was under the impression that you can't really use z-index in canvas? – pcmila Mar 03 '21 at 04:40
  • 1
    As everything seems to be on a canvas you need to be careful about the order in which things are drawn. Make sure background is drawn first. Canvas is just a flat thing, there is no concept of z positioning. – A Haworth Mar 03 '21 at 06:01
  • Not in a singl canvas. But by using multiple canvas and layering them on top of each other. There are plenty topics on SO about it: https://stackoverflow.com/questions/9165766/html5-canvas-set-z-index/26064753 – tacoshy Mar 03 '21 at 07:49

1 Answers1

0

Building on the comment from @AHaworth:

you need to be careful about the order in which things are drawn!

The problem I see in your code is on function updateGameArea() the background should be at the top of the stuff you do, see my fix below.

var myGamePiece;
var myObstacles = [];
var myBackground;

function startGame() {
  myGamePiece = new component(50, 50, "red", 10, 60, "rect");
  myBackground = new component(1600, 400, "blue", 0, 0, "rect");
  myGameArea.start();
}

function updateGameArea() {
  myGameArea.clear();
  myGameArea.frameNo += 1;

  myBackground.speedX = -1;
  myBackground.newPos();
  myBackground.update();

  if (myGameArea.frameNo == 1 || everyinterval(150)) {    
    myObstacles.push(new component(30, 30, "pink", myGameArea.canvas.width, 50, "rect"))
  }
  for (i = 0; i < myObstacles.length; i += 1) {
    myObstacles[i].x += -0.5;
    myObstacles[i].update();
  }

  myGamePiece.speedX = 0;
  myGamePiece.speedY = 0;
  myGamePiece.newPos();
  myGamePiece.update();
}

//board
var myGameArea = {
  canvas: document.createElement("canvas"),
  start: function() {
    this.canvas.width = 400;
    this.canvas.height = 150;
    this.context = this.canvas.getContext("2d");
    document.body.insertBefore(this.canvas, document.body.childNodes[0]);
    this.frameNo = 0;
    this.interval = setInterval(updateGameArea, 20);    
  },
  clear: function() {
    this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
  }
}

function component(width, height, color, x, y, type) {
  this.width = width;
  this.height = height;
  this.speedX = 0;
  this.speedY = 0;
  this.x = x;
  this.y = y;
  this.update = function() {
    ctx = myGameArea.context;
    ctx.fillStyle = color;
    ctx.fillRect(this.x, this.y, this.width, this.height);
  }
  this.newPos = function() {
    this.x += this.speedX;
    this.y += this.speedY;   
  }
}

function everyinterval(n) {
  return ((myGameArea.frameNo / n) % 1 == 0)
}

startGame()

I reduced a lot of your code to get a working snippet, you should do the same when posting question, that helps you focus on the error 90% of the time you will fix it before you post a question and also helps other debug your code.

If you are serious about it use a game engine, there a lot of good Open Source ones: https://github.com/collections/javascript-game-engines

Helder Sepulveda
  • 15,500
  • 4
  • 29
  • 56