Saya mencoba belajar JavaScript, membuat game pertama saya. Bagaimana saya bisa membuat semua gambar onload dalam satu function dan kemudian menggambarnya di kanvas sehingga membuat kode saya lebih pendek?

Bagaimana saya bisa memasukkan banyak gambar ke dalam array dan kemudian kami memasukkannya ke dalam suatu fungsi.

Ini adalah hari ketiga saya belajar JavaScript.

Terima kasih sebelumnya.

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();
1
Votech 23 Oktober 2019, 19:35

1 menjawab

Jawaban Terbaik

Ini dapat dilakukan dengan Promise.all . Kami akan membuat janji baru untuk setiap gambar yang ingin kami muat, menyelesaikan saat onload dipanggil. Setelah Promise.all diselesaikan, kita dapat memanggil fungsi initialize kita dan melanjutkan dengan sisa logika kita. Ini menghindari kondisi balapan di mana requestAnimationFrame loop game utama dipanggil dari bird.onload, tetapi ada kemungkinan bahwa entitas pipa dan sebagainya belum dimuat.

Berikut ini contoh minimal dan lengkap:

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 = [
  "http://placekitten.com/90/100",
  "http://placekitten.com/90/130",
  "http://placekitten.com/90/160",      
  "http://placekitten.com/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);

Perhatikan bahwa saya menggunakan array pada contoh di atas untuk menyimpan gambar. Masalah yang dipecahkan ini adalah bahwa

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

Pola sangat sulit untuk dikelola dan diukur. Jika Anda memutuskan untuk menambahkan hal lain ke dalam game, maka kode tersebut perlu ditulis ulang untuk memperhitungkannya dan logika game menjadi sangat basah. Bug menjadi sulit dikenali dan dihilangkan. Juga, jika kita menginginkan gambar tertentu, kita lebih suka mengaksesnya seperti images.bird daripada images[1], mempertahankan semantik dari masing-masing variabel, tetapi memberi kita kekuatan untuk mengulang objek dan memanggil fungsi render setiap entitas, misalnya.

Semua ini memotivasi objek untuk menggabungkan entitas game. Beberapa informasi yang ingin kami miliki per entitas dapat mencakup, misalnya, posisi entitas saat ini, status mati/hidup, fungsi untuk memindahkan dan merendernya, dll.

Ini juga merupakan ide yang bagus untuk memiliki semacam objek data mentah terpisah yang berisi semua status permainan awal (ini biasanya berupa file JSON eksternal).

Jelas, ini dapat berubah menjadi refactor yang signifikan, tetapi ini adalah langkah yang diperlukan ketika game berkembang menjadi lebih kecil (dan kami dapat secara bertahap mengadopsi ide-ide desain ini). Biasanya ide yang baik untuk menggigit peluru di depan.

Berikut adalah bukti konsep yang menggambarkan beberapa renungan di atas. Semoga ini menawarkan beberapa ide tentang bagaimana Anda dapat mengelola status dan logika permainan.

const entityData = [
  {
    name: "foo", 
    path: "http://placekitten.com/80/80",
    x: 0,
    y: 0
  },
  {
    name: "baz", 
    path: "http://placekitten.com/80/150",
    x: 0,
    y: 90
  },
  {
    name: "quux", 
    path: "http://placekitten.com/100/130",
    x: 90,
    y: 110
  },
  {
    name: "corge", 
    path: "http://placekitten.com/200/240",
    x: 200,
    y: 0
  },
  {
    name: "bar",
    path: "http://placekitten.com/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))
;
1
ggorlen 22 Desember 2020, 03:17