2

I'm working on a custom Pacman game using Javascript canvas. I have different classes, one for the player, another one for the enemies and another one for the walls in the board. Inside my wall class I have the following code:

class Wall {
constructor(x, y, width, height, color, gate){
    this.x = x;
    this.y = y;
    this.width = width;
    this.height = height;
    this.color = color;
    this.gate = gate;
};
draw(){
    ctx.lineWidth = 3;
    ctx.strokeStyle = this.color;
    ctx.strokeRect(this.x, this.y, this.width, this.height);
};

Inside my enemy class I have the following code:

class Enemy {
constructor(img, x, y){
    this.img = img;
    this.x = x;
    this.y = y;
    this.width = 36;
    this.height = 36;
    this.speedX = 0.5;
    this.speedY = 0.5;
    this.dx = 0;
    this.dy = 0;
    this.distance = 0;
    this.angle = 0;
};
draw(){
    ctx.drawImage(this.img, this.x, this.y, this.width, this.height);
};
checkcollision(object) {
    return (
      this.x < object.x + object.width &&
      this.x + this.width > object.x &&
      this.y < object.y + object.height &&
      this.y + this.height > object.y
    );
};
moveRight(objects) {
    this.x += this.speedX;
    objects.forEach(object => {
        if (this.checkcollision(object)) {
            this.x -= this.speedX;
        } else if (this.x >= 976){
            this.x = 0;
        };
    });
  };
moveLeft(objects) {
    this.x -= this.speedX;
    objects.forEach(object => {
        if (this.checkcollision(object)) {
            this.x += this.speedX;
        } else if (this.x <= 0){
            this.x = 975;
        };
    });
};
moveUp(objects) {
    this.y -= this.speedY;
    objects.forEach(object => {
        if (this.checkcollision(object)) {
            this.y += this.speedY;
        };
    });
};
moveDown(objects) {
    this.y += this.speedY;
    objects.forEach(object => {
        if (this.checkcollision(object)) {
            this.y -= this.speedY;
        };
    });
};
updateAngleX(player, objects){
    this.dx = player.x - this.x;
    this.dy = player.y - this.y;
    this.distance = Math.sqrt((this.dx*this.dx) + (this.dy*this.dy));
    this.angle = Math.atan2(this.dy,this.dx);
    this.x += Math.cos(this.angle) * this.speedX;
    objects.forEach(object => {
        if (this.dead === false || object.gate === false){
            if (this.checkcollision(object)) {
                if (this.dy > 0){
                    this.y += this.speedY;
                    this.x -= Math.cos(this.angle) * this.speedX;
                    if (this.checkcollision(object)){
                        this.y -= this.speedY;
                    };
                } else if (this.dy < 0){
                    this.y -= this.speedY;
                    this.x -= Math.cos(this.angle) * this.speedX;
                    if (this.checkcollision(object)){
                        this.y += this.speedY;
                    };
                };
            };
        };
    });
};
updateAngleY(player, objects){
    this.dx = player.x - this.x;
    this.dy = player.y - this.y;
    this.distance = Math.sqrt((this.dx*this.dx) + (this.dy*this.dy));
    this.angle = Math.atan2(this.dy,this.dx);
    this.y += Math.sin(this.angle) * this.speedY;
    objects.forEach(object => {
        if (this.dead === false || object.gate === false){
            if (this.checkcollision(object)) {
                if (this.dx > 0){
                    this.x += this.speedX;
                    this.y -= Math.sin(this.angle) * this.speedY;
                    if (this.checkcollision(object)){
                        this.x -= this.speedX;
                    };
                } else if (this.dx < 0){
                    this.x -= this.speedX;
                    this.y -= Math.sin(this.angle) * this.speedY;
                    if (this.checkcollision(object)){
                        this.x += this.speedX;
                    };
                };
            };
        };
    });
};

};

But I have some problems because the enemies are stuck when they find a corner like in the following image:

enter image description here

Like the enemy should follow the top or right path to continue the persecution but it gets stuck in the corner. How can I change my functions so they find the correct path to the player? Thank you.

Added the whole code to codepen to check it here: https://codepen.io/SpaSniper/pen/bGooKrP

Raúl
  • 159
  • 1
  • 10
  • We need more information about the problem you're trying to solve. – Vektor Dec 22 '21 at 22:05
  • @Vektor I added the class Wall, what more information would you need? – Raúl Dec 22 '21 at 22:17
  • Can you better clarify "enemies are stuck when they find a corner"? – Vektor Dec 22 '21 at 22:19
  • @Vektor I added an image explaining it in the post. – Raúl Dec 22 '21 at 22:43
  • compare your code with an example: https://codepen.io/hellokatili/pen/xwKRmo – Lawrence Cherone Dec 22 '21 at 22:47
  • We still need more information. Maybe embed the code through JSFiddle or use CodePen. Problems like these require debugging. – Vektor Dec 22 '21 at 23:33
  • @Vektor I added the code in CodePen at the end of the post. – Raúl Dec 23 '21 at 12:42
  • Are your enemies simply trying to minimise the distance between them and the player? – Johnny Dec 23 '21 at 14:11
  • Yes they are doing that @Johnny, that's what I want to change. Because when there's an obstacle they get stuck, but I don't know how to do code it. – Raúl Dec 23 '21 at 14:30
  • 1
    Make the game tile-based, temporarily remove the walls, then attempt to advance towards the player using the Dijkstra algorithm as @Johnny mentioned. Try to get the basic things working before adding more complexity to the code. – Vektor Dec 23 '21 at 19:44

1 Answers1

1

Stop what you're currently doing. Keep it super simple. You know where you can go and you know how big you are.

Let's say your enemy character is 36x36. A nice square. Now flood the map (the parts that you can actually go) with squares 36x36 or 40x40. You end up having a lot of squares one beside the other all over the map.

Now you can run something like Dijkstra to find the path between the enemy and the player (actually between the closest square to the enemy and the closest square to the player). You get back a list of squares (their centres actually) so you minimise the distance between the enemy and the next closest square in the list.

Do not run this every frame, just every 2 or 3 seconds or so.

Dijkstra on such a small amount of positions will be blazing fast but it is not necessary to keep on running it otherwise you risk your enemy to jitter too much.

This is not the only or the best solution, but you'll learn some nice techniques.

Johnny
  • 1,063
  • 1
  • 11
  • 23
  • Thank you so much for your answer, and sorry for the late response. But is there any way to do this using the existing rectangles drawn in Canvas? – Raúl Dec 29 '21 at 17:47