Home > Mobile >  How to go through JavaScript Code step by step, similar to a draw() function
How to go through JavaScript Code step by step, similar to a draw() function

Time:10-19

I am making a 'code your own adventure' type game, and I have a module set up so then I can do things like character.move() to move a character forward, but the problem is, is that if I have multiple of these set up, ie

character.move()
character.move()
character.turnLeft()
character.move()

It will immediately go through every single one, and appear all the way at the end, though I want it to go line by line, a little bit slower.

If I do

setInterval(() => {character.move()}, 400)

It gets an effect similar to what I want, but if I add anything else it still just goes through it instantly.

I just want to know if there is anything similar to a draw() function, that goes line by line, instead of just immedeately, or if there are any work arounds.

FWI, the snippet below is the exact code, so no other text entry other than in javascript underneath bob.initiate()

    class HTMLGrid {
      constructor(w, h) {
        this.w = w;
        this.h = h;
        this.gridArray = this.create();
        this.painterPosition = null;
        this.obstacleArray = [];
      }

      create() {
        let tempArr = []
        for (let i = 0; i < this.w; i  ) {
          for (let j = 0; j < this.h; j  ) {
            tempArr.push([i, j]);
          }
        }
        return tempArr;
      } //Creates an array that contains coordinates in the form [[x1, y2], [x2, y2],...]

      initiate() {
        for (let i = 0; i < this.gridArray.length; i  ) {
          if (!document.getElementById(this.gridArray[i][0])) {
            let row = document.createElement('tr');
            row.id = 'row'   this.gridArray[i][0];
            document.getElementById('holder').appendChild(row);
          }
          let cell = document.createElement('td');
          cell.id = 'cell'   this.gridArray[i];
          document.getElementById('row'   this.gridArray[i][0]).appendChild(cell);
        }
      }
      /* Uses the created array from create() to make HTML Elements for each square
                creates a row with the id of 'row0' 'row1' ..., and cells with the id of 
            'cell x1y1, cell x2y2'*/

      changeColorAtIndex(x, y, color) {
        document.getElementById('cell'   [x, y]).style.backgroundColor = color;
        if (color == 'black') {
          document.getElementById('cell'   [x, y]).style.color = 'white';
        } else document.getElementById('cell'   [x, y]).style.color = 'black';
      } //Changes the color at specified index

      returnColorIndex(x, y) {
        return document.getElementById('cell'   [x, y]).style.backgroundColor;
      } //return the color of the index
      placePainter(x, y, sprite) {
        if (!document.getElementById('cell'   [x, y])) {
          console.log('Painter Cannot Move Out of Bounds');
        } else if (this.painterPosition === null) {
          document.getElementById('cell'   [x, y]).innerHTML = sprite;
          this.painterPosition = [x, y];
        } else {
          document.getElementById('cell'   this.painterPosition).innerText = '';
          document.getElementById('cell'   [x, y]).innerHTML = sprite;
          this.painterPosition = [x, y];
        }
      } //places the painter and removes the other one

      returnPainterPosition() {
        return this.painterPosition;
      } //gives you the painters xy

      changeSprite(x, y, sprite) {
        document.getElementById('cell'   [x, y]).innerHTML = sprite;
      } //changes the sprites allowing for rotation

      isValidSquare(x, y) {
        if (this.obstacleArray.length === 0)
          return this.gridArray.flat().includes(x, y)
        else {
          if (this.gridArray.join('|').indexOf([x, y]   '|') == -1) {
            return this.gridArray.join('|').indexOf([x, y]   '|') !== -1
          } else {
            return !this.obstacleArray.flat().includes(x, y)
          }
        }
      } //lets you see if a square is valid to move onto 

      createObstacle(x, y) {
        document.getElementById('cell'   [x, y]).innerHTML = '&#8420;';
        this.obstacleArray.push([x, y])
      } //creates an obstacle that can prevent movement
    }
    /* create with new HTMLGrid(int width, int height) as the dimensiosn of the grid
     use HTMLGrid.initiate() to place the grid on the screen*/


    class Painter {
      constructor(gridToPlaceOn) {
        this.x = 0;
        this.y = 0;
        this.grid = gridToPlaceOn;
        this.direction = null;
        this.sprite = '&rarr;';
        this.spriteArr = {
          0: '&uarr;',
          1: '&rarr;',
          2: '&darr;',
          3: '&larr;'
        };
      }

      initiate() {
        this.grid.placePainter(this.x, this.y, this.sprite);
        this.direction = 1;
        this.sprite = '&rarr;';
      } //places the sprite on 0,0 with the rotation to the right\

      directionToMove() {
        let tempX = this.x,
          tempY = this.y;
        if (this.direction == 0) tempX -= 1;
        else if (this.direction == 1) tempY  = 1;
        else if (this.direction == 2) tempX  = 1;
        else tempY -= 1;

        return [tempX, tempY]
      } //Uses direction to set x and y values to desired location

      move() {
        let moveTo = this.directionToMove();
        this.grid.placePainter(moveTo[0], moveTo[1], this.sprite);
        this.x = moveTo[0];
        this.y = moveTo[1];
      } //Allows a piece to move forward

      canMove() {
        let direction = this.directionToMove()
        return this.grid.isValidSquare(direction[0], direction[1])
      } //Checks if you can move in desired location, returns false if cannot including for obstacles

      turnRight() {
        this.direction  = 1;
        if (this.direction == 4) this.direction = 0;
        this.sprite = this.spriteArr[this.direction];
        this.grid.changeSprite(this.x, this.y, this.sprite);
      } //Iterates on direction, loopin if at end of the loop, then changes the sprite

      turnLeft() {
        this.turnRight();
        this.turnRight();
        this.turnRight();
      }

      turnAround() {
        this.turnRight();
        this.turnRight();
      }

      paint(color) {
        this.grid.changeColorAtIndex(this.x, this.y, color);
      }

      scrapePaint() {
        this.grid.changeColorAtIndex(this.x, this.y, '#808080');
      }

      isOnPaint() {
        return this.grid.returnColorIndex(this.x, this.y) != '#808080';
      }

      getColor() {
        return this.grid.returnColorIndex(this.x, this.y) == '' ? '#808080' : this.grid.returnColorIndex(this.x, this.y);
      }

      getX() {
        return this.x;
      }
      getY() {
        return this.y;
      }

      isFacingNorth() {
        return this.direction == 0;
      }
      isFacingSouth() {
        return this.direction == 2;
      }
      isFacingEast() {
        return this.direction == 1;
      }
      isFacingWest() {
        return this.direction == 3;
      }

      getDirection() {
        if (this.isFacingNorth()) return 'north';
        else if (this.isFacingSouth()) return 'south';
        else if (this.isFacingEast()) return 'east';
        else return 'west';
      } // returns direction as a cardinal direction string
    } /* create with new Painter(gridToPlaceOn) as the grid that will be changing
   use Painter.initiate() to place it on the grid*/

    let grid = new HTMLGrid(8, 8);
    let bob = new Painter(grid);

    grid.initiate();
    bob.initiate();
    bob.move();
    bob.move();
    bob.move(); // This is where the problem is, instantly jumping through everything
  
table {
  border-collapse: collapse;
}
td {
  height: 40px;
  width: 40px;
  text-align: center;
  border: 1px solid white;
  border-radius: 5px;
  border-color: white;
  background-color: #808080;
}
<table id = 'holder'></table>

CodePudding user response:

Here is how to implement async/await in your code. I only edited the move() function as an example.

First write a delay function

function delay(millis) {
    return new Promise((resolve, reject) => setTimeout(resolve, millis));
}

Then make the move() function async and put a delay in it

    async move() {
        await delay(400);
        let moveTo = this.directionToMove();
        this.grid.placePainter(moveTo[0], moveTo[1], this.sprite);
        this.x = moveTo[0];
        this.y = moveTo[1];
    } //Allows a piece to move forward

Finally, call the move function and await for it, within an async function

(async () => {
    await bob.move();
    await bob.move();
    await bob.move();
})();

function delay(millis) {
    return new Promise((resolve, reject) => setTimeout(resolve, millis));
}

class HTMLGrid {
    constructor(w, h) {
        this.w = w;
        this.h = h;
        this.gridArray = this.create();
        this.painterPosition = null;
        this.obstacleArray = [];
    }

    create() {
        let tempArr = []
        for (let i = 0; i < this.w; i  ) {
            for (let j = 0; j < this.h; j  ) {
                tempArr.push([i, j]);
            }
        }
        return tempArr;
    } //Creates an array that contains coordinates in the form [[x1, y2], [x2, y2],...]

    initiate() {
        for (let i = 0; i < this.gridArray.length; i  ) {
            if (!document.getElementById(this.gridArray[i][0])) {
                let row = document.createElement('tr');
                row.id = 'row'   this.gridArray[i][0];
                document.getElementById('holder').appendChild(row);
            }
            let cell = document.createElement('td');
            cell.id = 'cell'   this.gridArray[i];
            document.getElementById('row'   this.gridArray[i][0]).appendChild(cell);
        }
    }
    /* Uses the created array from create() to make HTML Elements for each square
              creates a row with the id of 'row0' 'row1' ..., and cells with the id of 
          'cell x1y1, cell x2y2'*/

    changeColorAtIndex(x, y, color) {
        document.getElementById('cell'   [x, y]).style.backgroundColor = color;
        if (color == 'black') {
            document.getElementById('cell'   [x, y]).style.color = 'white';
        } else document.getElementById('cell'   [x, y]).style.color = 'black';
    } //Changes the color at specified index

    returnColorIndex(x, y) {
        return document.getElementById('cell'   [x, y]).style.backgroundColor;
    } //return the color of the index
    placePainter(x, y, sprite) {
        if (!document.getElementById('cell'   [x, y])) {
            console.log('Painter Cannot Move Out of Bounds');
        } else if (this.painterPosition === null) {
            document.getElementById('cell'   [x, y]).innerHTML = sprite;
            this.painterPosition = [x, y];
        } else {
            document.getElementById('cell'   this.painterPosition).innerText = '';
            document.getElementById('cell'   [x, y]).innerHTML = sprite;
            this.painterPosition = [x, y];
        }
    } //places the painter and removes the other one

    returnPainterPosition() {
        return this.painterPosition;
    } //gives you the painters xy

    changeSprite(x, y, sprite) {
        document.getElementById('cell'   [x, y]).innerHTML = sprite;
    } //changes the sprites allowing for rotation

    isValidSquare(x, y) {
        if (this.obstacleArray.length === 0)
            return this.gridArray.flat().includes(x, y)
        else {
            if (this.gridArray.join('|').indexOf([x, y]   '|') == -1) {
                return this.gridArray.join('|').indexOf([x, y]   '|') !== -1
            } else {
                return !this.obstacleArray.flat().includes(x, y)
            }
        }
    } //lets you see if a square is valid to move onto 

    createObstacle(x, y) {
        document.getElementById('cell'   [x, y]).innerHTML = '&#8420;';
        this.obstacleArray.push([x, y])
    } //creates an obstacle that can prevent movement
}
/* create with new HTMLGrid(int width, int height) as the dimensiosn of the grid
 use HTMLGrid.initiate() to place the grid on the screen*/


class Painter {
    constructor(gridToPlaceOn) {
        this.x = 0;
        this.y = 0;
        this.grid = gridToPlaceOn;
        this.direction = null;
        this.sprite = '&rarr;';
        this.spriteArr = {
            0: '&uarr;',
            1: '&rarr;',
            2: '&darr;',
            3: '&larr;'
        };
    }

    initiate() {
        this.grid.placePainter(this.x, this.y, this.sprite);
        this.direction = 1;
        this.sprite = '&rarr;';
    } //places the sprite on 0,0 with the rotation to the right\

    directionToMove() {
        let tempX = this.x,
            tempY = this.y;
        if (this.direction == 0) tempX -= 1;
        else if (this.direction == 1) tempY  = 1;
        else if (this.direction == 2) tempX  = 1;
        else tempY -= 1;

        return [tempX, tempY]
    } //Uses direction to set x and y values to desired location

    async move() {
        await delay(400);
        let moveTo = this.directionToMove();
        this.grid.placePainter(moveTo[0], moveTo[1], this.sprite);
        this.x = moveTo[0];
        this.y = moveTo[1];
    } //Allows a piece to move forward

    canMove() {
        let direction = this.directionToMove()
        return this.grid.isValidSquare(direction[0], direction[1])
    } //Checks if you can move in desired location, returns false if cannot including for obstacles

    turnRight() {
        this.direction  = 1;
        if (this.direction == 4) this.direction = 0;
        this.sprite = this.spriteArr[this.direction];
        this.grid.changeSprite(this.x, this.y, this.sprite);
    } //Iterates on direction, loopin if at end of the loop, then changes the sprite

    turnLeft() {
        this.turnRight();
        this.turnRight();
        this.turnRight();
    }

    turnAround() {
        this.turnRight();
        this.turnRight();
    }

    paint(color) {
        this.grid.changeColorAtIndex(this.x, this.y, color);
    }

    scrapePaint() {
        this.grid.changeColorAtIndex(this.x, this.y, '#808080');
    }

    isOnPaint() {
        return this.grid.returnColorIndex(this.x, this.y) != '#808080';
    }

    getColor() {
        return this.grid.returnColorIndex(this.x, this.y) == '' ? '#808080' : this.grid.returnColorIndex(this.x, this.y);
    }

    getX() {
        return this.x;
    }
    getY() {
        return this.y;
    }

    isFacingNorth() {
        return this.direction == 0;
    }
    isFacingSouth() {
        return this.direction == 2;
    }
    isFacingEast() {
        return this.direction == 1;
    }
    isFacingWest() {
        return this.direction == 3;
    }

    getDirection() {
        if (this.isFacingNorth()) return 'north';
        else if (this.isFacingSouth()) return 'south';
        else if (this.isFacingEast()) return 'east';
        else return 'west';
    } // returns direction as a cardinal direction string
} /* create with new Painter(gridToPlaceOn) as the grid that will be changing
   use Painter.initiate() to place it on the grid*/

let grid = new HTMLGrid(8, 8);
let bob = new Painter(grid);

grid.initiate();
bob.initiate();
(async () => {
    await bob.move();
    await bob.move();
    await bob.move();
})();
table {
  border-collapse: collapse;
}
td {
  height: 40px;
  width: 40px;
  text-align: center;
  border: 1px solid white;
  border-radius: 5px;
  border-color: white;
  background-color: #808080;
}
<table id = 'holder'></table>

Another approach so that no await is needed by user: Use an array to queue up the operation. Use a timer to dequeue one operation in regular interval.

    let operations = [];
    setInterval(()=>{
      if(operations.length > 0)
      {
        operations.shift()();
      }
    },400);

        move() {
            operations.push(()=>{
              let moveTo = this.directionToMove();
              this.grid.placePainter(moveTo[0], moveTo[1], this.sprite);
              this.x = moveTo[0];
              this.y = moveTo[1];
            });
        } //Allows a piece to move forward

let operations = [];
setInterval(()=>{
  if(operations.length > 0)
  {
    operations.shift()();
  }
},400);

class HTMLGrid {
    constructor(w, h) {
        this.w = w;
        this.h = h;
        this.gridArray = this.create();
        this.painterPosition = null;
        this.obstacleArray = [];
    }

    create() {
        let tempArr = []
        for (let i = 0; i < this.w; i  ) {
            for (let j = 0; j < this.h; j  ) {
                tempArr.push([i, j]);
            }
        }
        return tempArr;
    } //Creates an array that contains coordinates in the form [[x1, y2], [x2, y2],...]

    initiate() {
        for (let i = 0; i < this.gridArray.length; i  ) {
            if (!document.getElementById(this.gridArray[i][0])) {
                let row = document.createElement('tr');
                row.id = 'row'   this.gridArray[i][0];
                document.getElementById('holder').appendChild(row);
            }
            let cell = document.createElement('td');
            cell.id = 'cell'   this.gridArray[i];
            document.getElementById('row'   this.gridArray[i][0]).appendChild(cell);
        }
    }
    /* Uses the created array from create() to make HTML Elements for each square
              creates a row with the id of 'row0' 'row1' ..., and cells with the id of 
          'cell x1y1, cell x2y2'*/

    changeColorAtIndex(x, y, color) {
        document.getElementById('cell'   [x, y]).style.backgroundColor = color;
        if (color == 'black') {
            document.getElementById('cell'   [x, y]).style.color = 'white';
        } else document.getElementById('cell'   [x, y]).style.color = 'black';
    } //Changes the color at specified index

    returnColorIndex(x, y) {
        return document.getElementById('cell'   [x, y]).style.backgroundColor;
    } //return the color of the index
    placePainter(x, y, sprite) {
        if (!document.getElementById('cell'   [x, y])) {
            console.log('Painter Cannot Move Out of Bounds');
        } else if (this.painterPosition === null) {
            document.getElementById('cell'   [x, y]).innerHTML = sprite;
            this.painterPosition = [x, y];
        } else {
            document.getElementById('cell'   this.painterPosition).innerText = '';
            document.getElementById('cell'   [x, y]).innerHTML = sprite;
            this.painterPosition = [x, y];
        }
    } //places the painter and removes the other one

    returnPainterPosition() {
        return this.painterPosition;
    } //gives you the painters xy

    changeSprite(x, y, sprite) {
        document.getElementById('cell'   [x, y]).innerHTML = sprite;
    } //changes the sprites allowing for rotation

    isValidSquare(x, y) {
        if (this.obstacleArray.length === 0)
            return this.gridArray.flat().includes(x, y)
        else {
            if (this.gridArray.join('|').indexOf([x, y]   '|') == -1) {
                return this.gridArray.join('|').indexOf([x, y]   '|') !== -1
            } else {
                return !this.obstacleArray.flat().includes(x, y)
            }
        }
    } //lets you see if a square is valid to move onto 

    createObstacle(x, y) {
        document.getElementById('cell'   [x, y]).innerHTML = '&#8420;';
        this.obstacleArray.push([x, y])
    } //creates an obstacle that can prevent movement
}
/* create with new HTMLGrid(int width, int height) as the dimensiosn of the grid
 use HTMLGrid.initiate() to place the grid on the screen*/


class Painter {
    constructor(gridToPlaceOn) {
        this.x = 0;
        this.y = 0;
        this.grid = gridToPlaceOn;
        this.direction = null;
        this.sprite = '&rarr;';
        this.spriteArr = {
            0: '&uarr;',
            1: '&rarr;',
            2: '&darr;',
            3: '&larr;'
        };
    }

    initiate() {
        this.grid.placePainter(this.x, this.y, this.sprite);
        this.direction = 1;
        this.sprite = '&rarr;';
    } //places the sprite on 0,0 with the rotation to the right\

    directionToMove() {
        let tempX = this.x,
            tempY = this.y;
        if (this.direction == 0) tempX -= 1;
        else if (this.direction == 1) tempY  = 1;
        else if (this.direction == 2) tempX  = 1;
        else tempY -= 1;

        return [tempX, tempY]
    } //Uses direction to set x and y values to desired location

    move() {
        operations.push(()=>{
          let moveTo = this.directionToMove();
          this.grid.placePainter(moveTo[0], moveTo[1], this.sprite);
          this.x = moveTo[0];
          this.y = moveTo[1];
        });
    } //Allows a piece to move forward

    canMove() {
        let direction = this.directionToMove()
        return this.grid.isValidSquare(direction[0], direction[1])
    } //Checks if you can move in desired location, returns false if cannot including for obstacles

    turnRight() {
        this.direction  = 1;
        if (this.direction == 4) this.direction = 0;
        this.sprite = this.spriteArr[this.direction];
        this.grid.changeSprite(this.x, this.y, this.sprite);
    } //Iterates on direction, loopin if at end of the loop, then changes the sprite

    turnLeft() {
        this.turnRight();
        this.turnRight();
        this.turnRight();
    }

    turnAround() {
        this.turnRight();
        this.turnRight();
    }

    paint(color) {
        this.grid.changeColorAtIndex(this.x, this.y, color);
    }

    scrapePaint() {
        this.grid.changeColorAtIndex(this.x, this.y, '#808080');
    }

    isOnPaint() {
        return this.grid.returnColorIndex(this.x, this.y) != '#808080';
    }

    getColor() {
        return this.grid.returnColorIndex(this.x, this.y) == '' ? '#808080' : this.grid.returnColorIndex(this.x, this.y);
    }

    getX() {
        return this.x;
    }
    getY() {
        return this.y;
    }

    isFacingNorth() {
        return this.direction == 0;
    }
    isFacingSouth() {
        return this.direction == 2;
    }
    isFacingEast() {
        return this.direction == 1;
    }
    isFacingWest() {
        return this.direction == 3;
    }

    getDirection() {
        if (this.isFacingNorth()) return 'north';
        else if (this.isFacingSouth()) return 'south';
        else if (this.isFacingEast()) return 'east';
        else return 'west';
    } // returns direction as a cardinal direction string
} /* create with new Painter(gridToPlaceOn) as the grid that will be changing
   use Painter.initiate() to place it on the grid*/

let grid = new HTMLGrid(8, 8);
let bob = new Painter(grid);

grid.initiate();
bob.initiate();

bob.move();
bob.move();
bob.move();
table {
  border-collapse: collapse;
}
td {
  height: 40px;
  width: 40px;
  text-align: center;
  border: 1px solid white;
  border-radius: 5px;
  border-color: white;
  background-color: #808080;
}
<table id = 'holder'></table>

  • Related