在一个函数中加载图像

问题描述 投票:0回答:1

我正在尝试学习 JavaScript,制作我的第一个游戏。如何将所有图像

onload
制作在一张
function
中,然后将其绘制在画布上,从而使我的代码更短?

如何将大量图像放入数组中,然后在函数中使用它。

这是我学习 JavaScript 的第三天。

提前致谢。

var cvs = document.getElementById('canvas');
var ctx = cvs.getContext('2d');

//load images

var bird = new Image();
var bg = new Image();
var fg = new Image();
var pipeNorth = new Image();
var pipeSouth = new Image();

//images directions 
bg.src = "assets/bg.png";
bird.src = "assets/bird.png";
fg.src = "assets/fg.png";
pipeNorth.src = "assets/pipeNorth.png";
pipeSouth.src = "assets/pipeSouth.png";

var heightnum = 80;
var myHeight = pipeSouth.height+heightnum;
var bX = 10;
var bY = 150;
var gravity = 0.5;

// Key Control :D
 document.addEventListener("keydown",moveUP)
function moveUP(){
bY -= 20;
}
//pipe coordinates

var pipe = [];

pipe[0] = {
  x : cvs.width,
  y : 0
}
//draw images 


//Background img
  bg.onload = function back(){
    ctx.drawImage(bg,0,0);

  }
  //pipe north
  pipeNorth.onload = function tubo(){

    for(var i = 0; i < pipe.length; i++){

    ctx.drawImage(pipeNorth,pipe[i].x,pipe[i].y);
    pipe[i].x--;
    }
  }

  pipeSouth.onload = function tuba(){
    ctx.drawImage(pipeSouth,pipe[i].x,pipe[i].y+myHeight);

  }



  bird.onload = function pajaro(){
    ctx.drawImage(bird,bX,bY);
    bY += gravity;

    requestAnimationFrame(pajaro);  
  } 


  fg.onload = function flor(){
    ctx.drawImage(fg,0,cvs.height - fg.height);

  }




moveUP();
   back();
   tuba();
   pajaro();
   flor();
javascript html arrays canvas onload-event
1个回答
1
投票

这可以通过

Promise.all
来完成。我们将为要加载的每个图像做出新的承诺,并在调用
onload
时解决。一旦
Promise.all
解析,我们就可以调用
initialize
函数并继续其余的逻辑。这避免了从
requestAnimationFrame
调用主游戏循环的
bird.onload
的竞争条件,但管道实体等可能尚未加载。

这是一个最小的完整示例:

const initialize = images => {

  // images are loaded here and we can go about our business
  
  const canvas = document.createElement("canvas");
  document.body.appendChild(canvas);
  canvas.width = 400;
  canvas.height = 200;
  const ctx = canvas.getContext("2d");

  Object.values(images).forEach((e, i) =>
    ctx.drawImage(e, i * 100, 0)
  );
};

const imageUrls = [
  "https://picsum.photos/90/100",
  "https://picsum.photos/90/130",
  "https://picsum.photos/90/160",      
  "https://picsum.photos/90/190",
];

Promise.all(imageUrls.map(e =>
  new Promise((resolve, reject) => {
    const img = new Image();
    img.onload = () => resolve(img);
    img.onerror = reject;
    img.src = e;
  })
)).then(initialize);

请注意,我在上面的示例中使用了数组来存储图像。这解决的问题是

var foo = ...
var bar = ...
var baz = ...
var qux = ...
foo.src = ...
bar.src = ...
baz.src = ...
qux.src = ...
foo.onload = ...
bar.onload = ...
baz.onload = ...
qux.onload = ...

模式极难管理和扩展。如果您决定在游戏中添加其他内容,则需要重新编写代码来解释它,并且游戏逻辑变得非常湿。错误变得难以发现和消除。另外,如果我们想要一个特定的图像,我们更愿意像

images.bird
而不是
images[1]
那样访问它,保留各个变量的语义,但让我们能够循环遍历对象并调用每个实体的
render 
函数,例如。

所有这些都会激励对象聚合游戏实体。我们希望每个实体获得的一些信息可能包括,例如,实体的当前位置、死/活状态、移动和渲染它的功能等。

拥有某种包含所有初始游戏状态的单独原始数据对象(通常是外部 JSON 文件)也是一个好主意。

显然,这可能会变成一个重要的重构,但当游戏变得越来越小时,这是必要的一步(我们可以逐步采用这些设计思想)。一般来说,预先咬紧牙关是个好主意。

这是一个概念验证,说明了上面的一些想法。希望这能为您如何管理游戏状态和逻辑提供一些想法。

const entityData = [
  {
    name: "foo", 
    path: "https://picsum.photos/80/80",
    x: 0,
    y: 0
  },
  {
    name: "baz", 
    path: "https://picsum.photos/80/150",
    x: 0,
    y: 90
  },
  {
    name: "quux", 
    path: "https://picsum.photos/100/130",
    x: 90,
    y: 110
  },
  {
    name: "corge", 
    path: "https://picsum.photos/200/240",
    x: 200,
    y: 0
  },
  {
    name: "bar",
    path: "https://picsum.photos/100/100",
    x: 90,
    y: 0
  }
  /* you can add more properties and functions 
     (movement, etc) to each entity
     ... try adding more entities ...
  */
];

const entities = entityData.reduce((a, e) => {
  a[e.name] = {...e, image: new Image(), path: e.path};
  return a;
}, {});

const initialize = () => {
  const canvas = document.createElement("canvas");
  document.body.appendChild(canvas);
  canvas.width = innerWidth;
  canvas.height = innerHeight;
  const ctx = canvas.getContext("2d");

  for (const key of Object.keys(entities)) {
    entities[key].alpha = Math.random();
  }
  
  (function render () {
    ctx.clearRect(0, 0, canvas.width, canvas.height);
  
    Object.values(entities).forEach(e => {
      ctx.globalAlpha = Math.abs(Math.sin(e.alpha += 0.005));
      ctx.drawImage(e.image, e.x, e.y);
      ctx.globalAlpha = 1;
    });
    
    requestAnimationFrame(render);
  })();
};

Promise.all(Object.values(entities).map(e =>
    new Promise((resolve, reject) => {
      e.image.onload = () => resolve(e.image);
      e.image.onerror = () => 
        reject(`${e.path} failed to load`)
      ;
      e.image.src = e.path;
    })
  ))
  .then(initialize)
  .catch(err => console.error(err))
;

© www.soinside.com 2019 - 2024. All rights reserved.