dfasdfas

🧩 Syntax:
class Level {
  constructor() {
    this.tiles = [
      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,1,1,1,1,1,1,1,1,1,1,1,1,1,
      1,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,
      1,0,0,0,0,0,0,1,1,1,0,1,1,1,1,1,1,1,1,1,
      1,1,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,
      1,1,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
      1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
      1,1,1,1,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,
      1,1,1,1,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,
    ];
    this.lenX = 20;
    this.lenY = 10;
  }
  tileAt(x,y) {
    if (x<0 || x>=this.lenX || y<0 || y>=this.lenY) return 1;
    return this.tiles[y*this.lenX + x];
  }
}

class Actor {
  constructor(x,y,image) {
    this.x = x;
    this.y = y;
    this.image = image;
  }
}

class Camera {
  constructor(x,y) {
    this.x = x;
    this.y = y;
  }
}
////////////////////////////////////////////////////////
class ComMove {
  /**
   * @param {Actor} actor 移動させたいアクター
   * @param {number} dx 何マス移動するか
   * @param {number} dy 何マス移動するか
   */
  constructor(actor, dx, dy) {
    let t = this;
    t.actor = actor;
    t.dx = dx;
    t.dy = dy;
    t.beginX = -1;
    t.beginY = -1;
    t.endX = -1;
    t.endY = -1;
    /** 実行したフレーム数 */
    t.f = 0;
  }
  /**
   * コマンドを1フレーム実行する
   */
  exec() {
    let t = this;
    if (t.done) return t.done; //終了しているコマンドは実行しない
    t.f++;
    if (t.f === 1) {
      // 開始地点と終了地点の座標を計算
      t.beginX = t.actor.x;
      t.beginY = t.actor.y;
      t.endX = t.actor.x + t.dx;
      t.endY = t.actor.y + t.dy;
      
      if (game.level.tileAt(t.endX, t.endY) === 1) {
        t.f = 20;
        return t.done;
      }
    }
    // ↑で計算した座標の間を移動する
    t.actor.x = t.beginX + t.f*t.dx/20;
    t.actor.y = t.beginY + t.f*t.dy/20;

    return t.done;
  }
  /**
   * @returns {boolean} コマンドが終了していればtrue, 実行中ならfalse
   */
  get done() {
    return this.f >= 20;
  }
}
////////////////////////////////////////////////////////
class Game {
  constructor() {
    this.level = new Level();
    this.player = null;
    this.actors = [];
    this.camera = new Camera(0,0);
    this.commands = [];
  }
}

let game;

function setup() {
  game = new Game();
  
  let player = new Actor(4,2,'🐤');
  game.player = player;
  game.actors = [player];
  
  createCanvas(480, 480);
}

function draw() {
  let w = 60;
  
////////////////////////////////////////////////////////
  // プレイヤーの入力を受け付ける
  if (keyIsPressed && game.commands.length === 0) {
    let dxy = {37:[-1,0], 38:[0,-1], 39:[1,0], 40:[0,1]}[keyCode];
    if (dxy !== undefined) {
      game.commands.push(new ComMove(game.player, dxy[0], dxy[1]));

      // 仮に、敵を移動させてみる
      //game.commands.push(new ComMove(game.actors[1], 0, 1));
    }
  }

  // コマンドをすべて1フレーム分実行する
  for(let c of game.commands) {
    c.exec();
  }
  // 実行し終わったコマンドを消す
  game.commands = game.commands.filter(c => !c.done);
////////////////////////////////////////////////////////
  
  let p = game.player;
  let c = game.camera;
  c.x = p.x - 7/2;
  c.y = p.y - 7/2;
  let cx = w * c.x;
  let cy = w * c.y;
  
  background('Bisque');
  
  textAlign(LEFT, TOP);
  textSize(w * 7/8);
  for(let y=0; y<10; y++){
    for(let x=0; x<20; x++){
      let t = game.level.tileAt(x,y);
      if(t === 1){
        text('🌳', w*x-cx, w*y-cy);
      } 
    }
  }
  
  for(let a of game.actors) {
    text(a.image, w*a.x-cx, w*a.y-cy);
  }
}