如何将我的代码重构为游戏循环?

How to refactor my code to a game loop?

现在我有了一个没有主游戏循环的简单代码。我正在使用 Loader 构造函数及其 image.onload 函数在 canvas 上渲染精灵(因为没有 image.onload 我将看不到任何精灵)现在我想为我的精灵制作动画为此,我需要创建一个绘制循环。不幸的是,这是我的知识结束的地方。我尝试创建渲染函数并只是复制粘贴我的 ship.drawimage(boat, boatPosX, boatPosY, 50, 50); 方法,但它不起作用,因为我需要 Loader 中的 image.onload 函数。而且我不能将 Loader 构造函数放入我的 render() 函数,因为那样 var background = new Loader("ground.png"); var boat = new Loader("ship.png"); 就无法访问构造函数变量来初始化新对象。

所以在这一点上我很迷茫我应该如何更好地重构我的代码?

完整代码如下:

var canvas = document.getElementById("canvas");
var context = canvas.getContext("2d");

var mapArray = [
  [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
  [0, 0, 0, 0, 0, 0, 0, 2, 2, 0],
  [0, 0, 1, 1, 1, 0, 0, 2, 0, 0],
  [0, 0, 1, 1, 1, 0, 0, 0, 0, 0],
  [0, 0, 0, 1, 1, 0, 0, 0, 0, 0],
  [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
  [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
  [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
  [0, 0, 0, 0, 1, 1, 0, 0, 0, 0],
  [0, 0, 0, 0, 1, 1, 0, 0, 0, 0],
  [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
]


var StyleSheet = function(image, width, height) {
  this.image = image;
  this.width = width;
  this.height = height;


  this.draw = function(image, sx, sy, swidth, sheight, x, y, width, height) {
      context.drawImage(image, sx, sy, swidth, sheight,x, y, width, height);
  }
  this.drawimage = function(image, x, y, width, height) {
    context.drawImage(image, x, y, width, height);
  }
}

/* Initial Sprite Position */

var boatPosX = 230;
var boatPosY = 200;

var Loader = function(src) {
  this.image = new Image();
  this.image.src = src;
  this.image.onload = function() {
  var sprite = new StyleSheet(background, 36, 36);
  var ship = new StyleSheet(boat, 90, 100);
  for (let i = 0; i < mapArray.length; i++) {
    for (let j = 0; j < mapArray[i].length; j++) {
      if (mapArray[i][j] == 0) {
        sprite.draw(background, 190, 230, 26, 26, i * sprite.width, j * sprite.height, sprite.width, sprite.height);
      }
      if (mapArray[i][j] == 1) {
        sprite.draw(background, 30, 30, 26, 26, i * sprite.width, j * sprite.height, sprite.width, sprite.height);
      }
      if (mapArray[i][j] == 2) {
        sprite.draw(background, 200, 20, 26, 26, i * sprite.width, j * sprite.height, sprite.width, sprite.height);
      }
    }
  }
  ship.drawimage(boat, boatPosX, boatPosY, 50, 50);
}
  return this.image;
}

function render() {

}

setInterval(render, 10);

/* Sprite controls */

function move(e) {
  if (e.keyCode == 39) {
    boatPosX += 2;
    console.log("works");

  }
  if (e.keyCode == 37) {
    boatPosX -= 2;
  }
}

  document.onkeydown = move;

var background = new Loader("ground.png");
var boat = new Loader("ship.png");

console.log(background);

更新:

所以根据我的老问题,我决定对我的代码做一些更改,这样我就可以为我的 onload 函数调用 requestAnimationFrame 并在 [=40 上绘制精灵=]不断。为此,我通过将 onload 放入一个新函数并将该函数分配给 Loader 原型来分离 Loader 构造函数和我的方法 onload。然后我执行 var background = new Loader("ground.png");background.render(); 但我得到 Uncaught TypeError: background.render is not a function 错误。不确定我做错了什么?

var canvas = document.getElementById("canvas");
var context = canvas.getContext("2d");

var mapArray = [
  [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
  [0, 0, 0, 0, 0, 0, 0, 2, 2, 0],
  [0, 0, 1, 1, 1, 0, 0, 2, 0, 0],
  [0, 0, 1, 1, 1, 0, 0, 0, 0, 0],
  [0, 0, 0, 1, 1, 0, 0, 0, 0, 0],
  [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
  [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
  [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
  [0, 0, 0, 0, 1, 1, 0, 0, 0, 0],
  [0, 0, 0, 0, 1, 1, 0, 0, 0, 0],
  [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
]


var StyleSheet = function(image, width, height) {
  this.image = image;
  this.width = width;
  this.height = height;


  this.draw = function(image, sx, sy, swidth, sheight, x, y, width, height) {
      context.drawImage(image, sx, sy, swidth, sheight,x, y, width, height);
  }
  this.drawimage = function(image, x, y, width, height) {
    context.drawImage(image, x, y, width, height);

  }
}

/* Initial Sprite Position */

var boatPosX = 230;
var boatPosY = 200;

var Loader = function(src) {
  this.image = new Image();
  this.image.src = src;
  return this.image;
}

Loader.prototype.render = function() {
  this.image.onload = function() {
  var sprite = new StyleSheet(background, 36, 36);
  var ship = new StyleSheet(boat, 90, 100);
  for (let i = 0; i < mapArray.length; i++) {
    for (let j = 0; j < mapArray[i].length; j++) {
      if (mapArray[i][j] == 0) {
        sprite.draw(background, 190, 230, 26, 26, i * sprite.width, j * sprite.height, sprite.width, sprite.height);
      }
      if (mapArray[i][j] == 1) {
        sprite.draw(background, 30, 30, 26, 26, i * sprite.width, j * sprite.height, sprite.width, sprite.height);
      }
      if (mapArray[i][j] == 2) {
        sprite.draw(background, 200, 20, 26, 26, i * sprite.width, j * sprite.height, sprite.width, sprite.height);
      }
    }
  }
  ship.drawimage(boat, boatPosX, boatPosY, 50, 50);
}
}



/* Sprite controls */

function move(e) {
  if (e.keyCode == 39) {
    boatPosX += 2;
    console.log("works");

  }
  if (e.keyCode == 37) {
    boatPosX -= 2;
  }
}

  document.onkeydown = move;

var background = new Loader("ground.png");
var boat = new Loader("ship.png");
background.render();
console.log(background);

Codepen 示例:https://codepen.io/Limpuls/pen/dejVpR

我对你的 Pen 进行了分叉并重构了你的代码。现在你有一个使用 requestAnimationFrame 的游戏循环:https://codepen.io/DonKarlssonSan/pen/rvrGvL/

编辑,添加我更改的内容:

  • 我删除了 Loader,而是只使用纯图像和 img.src = url,然后我将其作为参数传递给 StyleSheet 的构造函数。

  • 我将 mapArray 上的循环提取到渲染方法中,该方法也用作主 ("game") 循环。

代码:

var canvas = document.getElementById("canvas");
var context = canvas.getContext("2d");

var mapArray = [
  [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
  [0, 0, 0, 0, 0, 0, 0, 2, 2, 0],
  [0, 0, 1, 1, 1, 0, 0, 2, 0, 0],
  [0, 0, 1, 1, 1, 0, 0, 0, 0, 0],
  [0, 0, 0, 1, 1, 0, 0, 0, 0, 0],
  [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
  [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
  [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
  [0, 0, 0, 0, 1, 1, 0, 0, 0, 0],
  [0, 0, 0, 0, 1, 1, 0, 0, 0, 0],
  [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
];

var StyleSheet = function(image, width, height) {
  this.image = image;
  this.width = width;
  this.height = height;

  this.draw = function(image, sx, sy, swidth, sheight, x, y, width, height) {
    context.drawImage(image, sx, sy, swidth, sheight, x, y, width, height);
  };
  this.drawimage = function(image, x, y, width, height) {
    context.drawImage(image, x, y, width, height);
  };
};

/* Initial Sprite Position */

var boatPosX = 230;
var boatPosY = 200;

function render() {
  requestAnimationFrame(render);

  for (let i = 0; i < mapArray.length; i++) {
    for (let j = 0; j < mapArray[i].length; j++) {
      if (mapArray[i][j] == 0) {
        this.sprite.draw(
          background,
          190,
          230,
          26,
          26,
          i * this.sprite.width,
          j * this.sprite.height,
          this.sprite.width,
          this.sprite.height
        );
      }
      if (mapArray[i][j] == 1) {
        this.sprite.draw(
          background,
          30,
          30,
          26,
          26,
          i * this.sprite.width,
          j * this.sprite.height,
          this.sprite.width,
          this.sprite.height
        );
      }
      if (mapArray[i][j] == 2) {
        this.sprite.draw(
          background,
          200,
          20,
          26,
          26,
          i * this.sprite.width,
          j * this.sprite.height,
          this.sprite.width,
          this.sprite.height
        );
      }
    }
  }
  this.ship.drawimage(boat, boatPosX, boatPosY, 50, 50);
};

function move(e) {
  if (e.keyCode == 39) {
    boatPosX += 2;
    console.log("right");
  }
  if (e.keyCode == 37) {
    boatPosX -= 2;
    console.log("left");
  }
}

document.onkeydown = move;

var background = new Image();
background.src = "http://i67.tinypic.com/35lx8y0.png";
var sprite = new StyleSheet(background, 36, 36);

var boat = new Image();
boat.src = "http://i66.tinypic.com/b7b9tc.png";
var ship = new StyleSheet(boat, 90, 100);

render();