Edit in JSFiddle

class Game {
  constructor(opt) {
    this._canvas = opt.canvas;
    this._ctx = this._canvas.getContext('2d');
    
    this._assets = opt.assets;
    this._loadedAssets = {};
    
    this._fps = opt.fps || 30;
    this._timer;
    this._items = [];
    this._keyboard = '';
    this._setEventListener();

    // 当たり判定用リスト
    this.hitTests = [];
  }

  /**
   * 当たり判定を追加する
   * @param {Object} opt オプション
   * @param {Object} opt.self 主のオブジェクト
   * @param {Object} opt.target 当たり判定の対象
   * @param {Function} opt.onhit 衝突検知したときの処理
   */
  addHitTest(opt) {
    this.hitTests.push(opt);
  }
  /**
   * 当たり判定を削除する
   * @param {Object} opt オプション
   * @param {Object} opt.self 主のオブジェクト
   * @param {Object} opt.target 当たり判定の対象
   * @param {Function} opt.onhit 衝突検知したときの処理
   */
  removeHitTest(opt) {
    const index = this.hitTests.findIndex(a => a === opt);
    this.hitTests.splice(index, 1);
  }
  /**
   * 当たり判定を行う
   * @param {Object} self メイン
   * @param {Object} target ターゲット
   * @return {boolean} 衝突検知したらtrue
   */
  _hitTest(self, target) {
    const myTop = self.y;
    const myBottom = self.y + self.h;
    const myLeft = self.x;
    const myRight = self.x + self.w;

    const targetTop = target.y;
    const targetBottom = target.y + target.h;
    const targetLeft = target.x;
    const targetRight = target.x + target.w;

    return (myTop < targetBottom && targetTop < myBottom) && (myLeft < targetRight && targetLeft < myRight);
  }

  //以下の詳細は参照→ http://kuroeveryday.blogspot.jp/2017/10/canvas-how-to-move-object-with-keyboard.html
  // _renderのみ修正
  async start() {
    await this._loadAssets();
    this._timer = setInterval(() => {
      this._render();
    }, 1000 / this._fps);
  }
  stop() {
    clearInterval(this._timer);
  }
  async _loadAssets() {
    const promises = Object.keys(this._assets).map(asset => {
      return new Promise((resolve, reject) => {
        const img = new Image();
        img.onload = () => { resolve(); }
        img.onerror = err => { reject(err); }
        img.src = this._assets[asset];
        this._loadedAssets[asset] = img;
      });
    });

    return Promise.all(promises);
  }
  _render() {
    this._ctx.clearRect(0, 0, this._canvas.clientWidth, this._canvas.clientHeight);
    this._items.forEach(a => {
      a.update(this._keyboard);
      a.draw(this._ctx, this._loadedAssets);

      // 当たり判定
      this.hitTests
        // 自分に関係する当たり判定のみ取得
        .filter(test => test.self === a)
        .forEach(test => {
          if (this._hitTest(test.self, test.target)) {
            // 当たったときの処理
            test.onhit();
            // 不要な当たり判定を削除
            this.removeHitTest(test);
          }
        });
    })
  }
  _setEventListener() {
    window.addEventListener('keydown', e => { this._keyboard = e.key });
    window.addEventListener('keyup', e => { this._keyboard = '' });
  }
  add(item) {
    this._items.push(item);
  }
  remove(item) {
    const idx = this._items.find(a => a === item);
    this._items.splice(idx, 1);
  }
}

class Player {
  constructor(opt = {}) {
    this.x = opt.x || 0;
    this.y = opt.y || 0;
    this.w = opt.w || 64;
    this.h = opt.h || 64;
    this.src = opt.src;
  }
  draw(ctx, assets) {
    if (assets[this.src]) {
      ctx.drawImage(assets[this.src], this.x, this.y, this.w, this.h);
    } else {
      ctx.fillRect(this.x, this.y, this.w, this.h);
    }
  }
  update(keyboard) {
    // ここで動作を定義する
    switch (keyboard) {
      case 'ArrowUp':
        this.y -= 5;
        break;
      case 'ArrowDown':
        this.y += 5;
        break;
      case 'ArrowLeft':
        this.x -= 5;
        break;
      case 'ArrowRight':
        this.x += 5;
        break;
    }
  }
}

class ObjectItem {
  constructor(opt = {}) {
    this.x = opt.x || 0;
    this.y = opt.y || 0;
    this.w = opt.w || 64;
    this.h = opt.h || 64;
    this.color = 'black';
  }
  draw(ctx, assets) {
    ctx.fillStyle = this.color;
  	ctx.fillRect(this.x, this.y, this.w, this.h);
  }
  update(keyboard) {
    /* nop */
  }
}

function main() {
  const assets = {
    player: 'https://avatars3.githubusercontent.com/u/5305599'
  };
  const game = new Game({
    canvas: document.getElementById('app'),
    assets: assets,
    fps: 30
  });
  
  const player = new Player({
    src: 'player'
  });
  game.add(player);
  
 for (let i = 0; i < 10; i++) {
    const x = Math.floor(Math.random() * (580 - 60 + 1) ) + 60;
    const y = Math.floor(Math.random() * (300 - 60 + 1) ) + 60;
    const item = new ObjectItem({
      x: x,
      y: y
    });

    game.addHitTest({
      self: item,
      target: player,
      onhit: () => {
        item.color = 'red';
      }
    });
    game.add(item);
 }
  
  document.getElementById('start').addEventListener('click', () => game.start());
  document.getElementById('stop').addEventListener('click', () => game.stop());
}
main();
<div>
  <canvas id="app" width="640" height="360"></canvas>
</div>
<button id="start">start</button>
<button id="stop">stop</button>