Help! - Pixel Hunt: A game in progress

Hello everyone, my name is Matt. I got into Javascript and Phaser3 about four days ago. I’ve been off work for about a week and half now because I contracted the coronavirus. I have a game idea that i’ve been tumbling around in my head for quite a while and have been trying to bring it to life. Slowly, but surely, I am making progress but I need help.

The concept is as follows. You fly a little ship around on a two-dimensional plane. At the beginning this is a single gray pixel. Throughout the map there are green, red, and blue pixels. Each pixel represents a significant element.

  • Gray is your ship.
  • Red is Energy, used for firepower for your ship.
  • Blue is Water, used as fuel for your ship.
  • Green is Food, used a health for your ship.

It took me a while to realize the camera can be unhinged from the game frame itself. So even though it says 800x600. The camera transcends those bounds.

Question number 1: How do I set the actual map boundaries?

My current input handling is as follows:

this.input.keyboard.on("keydown", this.handleKey, this);

handleKey(e){
  switch(e.code){
    case "KeyW":
      player.y-=1;
      break;
    case "KeyS":
      player.y+=1;
      break;
    case "KeyA":
      player.x-=1;
      break;
    case "KeyD":
      player.x+=1;
      break;
    case "KeyQ":
      zoomLevel += 1;
      this.cameras.main.setZoom(zoomLevel);
      //console.log(zoomLevel);
      break;
    case "KeyE":
      zoomLevel -= 1;
      this.cameras.main.setZoom(zoomLevel);
      //console.log(zoomLevel);
    }
}

Question 2: Which function should this be located in my game scene? It currently resides in the create() method. I am confused that it updates regularly though. I assumed recursive functions would need to be in the update() method?

I use a for loop in conjunction with random points to place the pixels throughout the game screen 800x600. Then I zoom the camera in by 30 and set the camera to follow the players ship.

Question 3: Is there a better way to group all of these pixels so that they can be searched and I can check them against the location of my ship to know if they are colliding?

As you gather pixels, your camera will zoom back out and the sprite of your ship will evolve into a more advanced model.

Question 4: How can I rotate the ship image to accommodate four directions of travel?

Question 5: Inevitably I want to use physics for this game. There will be NPC creatures and ships that move throughout the world. Which physics engine type would be best for this?

I am sorry that I have so many questions. Learning can be difficult without direction.

Here is the game code so far:

 var game;
    var player;
    var pixels = [];
    var controls;
    var zoomLevel = 30;
    window.onload = function() {
      var config = {
        type: Phaser.Auto,
        width: 800,
        height: 600,
        backgroundColor: 0x000000,
        pixelArt: true,
        scene: [
          bootGame,
          playGame
        ]
      }
      game = new Phaser.Game(config);
      window.focus();
    }

    class bootGame extends Phaser.Scene{
        constructor(){
            super("BootGame");
        }
        preload(){
            this.load.image("ship1", "assets/ship1.png");
            this.load.image("redP", "assets/red.png");
            this.load.image("blueP", "assets/blue.png");
            this.load.image("greenP", "assets/green.png");
            //this.load.spritesheet("tiles", "assets/sprites/tiles.png", {
                //frameWidth: gameOptions.tileSize,
                //frameHeight: gameOptions.tileSize
            //});
        }
        create(){
            this.scene.start("PlayGame");
        }
    }

    class playGame extends Phaser.Scene{
        constructor(){
          super("PlayGame");
        }
        create(){
          this.input.keyboard.on("keydown", this.handleKey, this);
          player = this.add.image(game.config.width/2, game.config.height/2, "ship1");
          this.cameras.main.setBounds(0,0,800,600);
          this.cameras.main.startFollow(player, true, 0.9, 0.9);
          this.cameras.main.setZoom(zoomLevel);
          this.createPixels(600,'red');
          this.createPixels(300, 'blue');
          this.createPixels(100, 'green');
          console.log(player);

        }
        update(){

        }
        handleKey(e){
          switch(e.code){
            case "KeyW":
              player.y-=1;
              break;
            case "KeyS":
              player.y+=1;
              break;
            case "KeyA":
              player.x-=1;
              break;
            case "KeyD":
              player.x+=1;
              break;
            case "KeyQ":
              zoomLevel += 1;
              this.cameras.main.setZoom(zoomLevel);
              //console.log(zoomLevel);
              break;
            case "KeyE":
              zoomLevel -= 1;
              this.cameras.main.setZoom(zoomLevel);
              //console.log(zoomLevel);
            }
        }
        createPixels(num, color){
          for(var i = 0; i < num; i++)
          {
            var valueX = Phaser.Math.Between(0, game.config.width);
            var valueY = Phaser.Math.Between(0, game.config.height);
            if(color == 'red'){
              this.add.image(valueX, valueY, "redP");
            }
            if(color == 'blue'){
              this.add.image(valueX, valueY, "blueP");
            }
            if(color == 'green'){
              this.add.image(valueX, valueY, "greenP");
            }
          }
        }
      }

I’ve made it much further into development. These questions still remain however they are not important. Right now I cannot understand why my AI tends to always move -y, if anyone has insight please help. I’ve added a link to show this behavior in the video as well as the creature class and methods. The method I keep questions is the move() methods. However this could have something to do with the way I am managing each individual creatures local map known as this.map = [].

Phaser3 Pixel Hunt AI Issue

function queryActorsCord(x,y){
  for(var i = 0; i < actors.length; i++){
    if(actors[i].x == x && actors[i].y  == y){
      return actors[i];
    }
  }
}

class Creature {
  constructor(pX,pY,pHealth,pFuel,pFire,pThis){
    this.x = pX;
    this.y = pY;
    this.health = pHealth;
    this.fuel = pFuel;
    this.fire = pFire;
    this.view = [];
    this.map = [];
    this.map.push(new Phaser.Math.Vector2(0,0));
    this.mImage = pThis.add.image(pX,pY,"orangeP");
    this.x = 0;
    this.y = 0;
    return this;
  }
  collision(){
    for(var i = 0; i < actors.length; i++){
      if(actors[i].x == this.mImage.x && actors[i].y  == this.mImage.y){
        if(actors[i].texture.key == 'blueP'){
          this.fuel += 100;
          actors[i].destroy();
          actors.splice(i,1);
          break;
        }
        if(actors[i].texture.key == 'redP'){
          this.fire += 1;
          actors[i].destroy();
          actors.splice(i,1);
          break;
        }
        if(actors[i].texture.key == 'greenP'){
        this.health += 1;
          actors[i].destroy();
          actors.splice(i,1);
          break;
        }
      }
    }
  }
  look(){
    this.view = []
    this.view.push(queryActorsCord(this.mImage.x, this.mImage.y-1)); //north
    this.view.push(queryActorsCord(this.mImage.x+1, this.mImage.y)); //east
    this.view.push(queryActorsCord(this.mImage.x, this.mImage.y+1)); //south
    this.view.push(queryActorsCord(this.mImage.x-1, this.mImage.y)); //west
  }
  move(){
    //console.log("N:" + direction[0] + " E: " + direction[1] + " S: " + direction[2] + " W: " + direction[3])
    if(this.map.length > 50){
      this.map = [];
    }
    if(this.fuel > 0){
      this.fuel--;
      var moveDirection = Phaser.Math.Between(1,4);
      //console.log(moveDirection);
      var tempView = [];
      var tempSwitch = 0;
      for(var i = 0; i < this.view.length; i++){
        if(this.view[i] != undefined){
          tempView.push(i);
          //console.log("logging tempview", tempView);
        }
      }
      if(tempView.length > 0){
        //console.log("tempview is loaded ");
        tempSwitch = Phaser.Math.Between(0,tempView.length);
        //console.log("tempswitch: " + tempSwitch);
        switch(tempView[tempSwitch]){
          case 0:
            this.mImage.y -=1;
            this.y -=1;
            this.map.push(new Phaser.Math.Vector2(this.x, this.y));
            break;
          case 1:
            this.mImage.x +=1;
            this.x +=1;
            break;
          case 2:
            this.mImage.y +=1;
            this.y +=1;
            this.map.push(new Phaser.Math.Vector2(this.x, this.y));
            break;
          case 3:
            this.mImage.x -=1;
            this.x -=1;
            this.map.push(new Phaser.Math.Vector2(this.x, this.y));
            break;
        }
      }
      else{
        switch(moveDirection){
          case 1:
            var tempY1 = this.y -1;
            for(var i = 0; i < this.map.length; i++){
              if(this.map[i].x == this.x && this.map.y == tempY1){
                return;
              }
            }
            //console.log("N succeded");
            direction[0]+=1;
            this.mImage.y -=1;
            this.y -=1;
            this.map.push(new Phaser.Math.Vector2(this.x, this.y));
            break;
          case 2:
            var tempX1 = this.x + 1;
            for(var i = 0; i < this.map.length; i++){
              if(this.map[i].x == tempX1 && this.map[i].y == this.y){
                return;
              }
            }
            //console.log("E succeded");
            direction[1]+=1;
            this.mImage.x +=1;
            this.x +=1;
            this.map.push(new Phaser.Math.Vector2(this.x, this.y));
            break;
          case 3:
            var tempY2 = this.y + 1;
            for(var i = 0; i < this.map.length; i++){
              if(this.map[i].x == this.x && this.map[i].y == tempY2){
                return;
              }
            }
            //console.log("S succeded");
            direction[2]+=1;
            this.mImage.y +=1;
            this.y +=1;
            this.map.push(new Phaser.Math.Vector2(this.x, this.y));
            break;
          case 4:
            var tempX2 = this.x -1;
            for(var i = 0; i < this.map.length; i++){
              if(this.map[i].x == tempX2 && this.map[i].y == this.y){
                return;
              }
            }
            //console.log("W succeded");
            direction[3]+=1;
            this.mImage.x -=1;
            this.x -=1;
            this.map.push(new Phaser.Math.Vector2(this.x, this.y));
            break;
          }
      }
    }
  }
  die(){

  }
  spawn(){
    if(this.fire > 5){
      var spawnProfile = [this.mImage.x, this.mImage.y + 1, 0, 1000, 0];
      spawns.push(spawnProfile);
      console.log("spawn");
      this.fire -= 5;
    }
  }
  do(){
    this.look();
    this.move();
    this.spawn();
    this.collision();
  }
}

I have decided that the move() method was getting swamped with code and becoming unbearable. So move() takes one argument now.

move(direction){
        switch(direction){
          case 0:
            this.mImage.y -=1;
            this.y -=1;
            break;
          case 1:
            this.mImage.x +=1;
            this.x +=1;
            break;
          case 2:
            this.mImage.y +=1;
            this.y +=1;
            break;
          case 3:
            this.mImage.x -=1;
            this.x -=1;
            break;
      }
  }

This will be used in conjunction with a movementQueue = []