Kattints ide a teljes képernyős verzió lejátszásához

Idle aranybánya

Az "Idle" (tétlen) vagy "klikkalapú" játékok 2013 környékén váltak rendkívül népszerűvé, így egy kicsit lemaradtunk a buliról, de azért még szórakozhatunk egy ilyennek a létrehozásával.

Ezeknek a játékoknak az ötlete az, hogy a játékos jutalmat kapjon egy egyszerű műveletért (például egy kattintásért). Vannak, akik élvezik ezeket a játékokat, mások nem szívesen pazarolják rájuk az értékes idejüket. Én nem ítélkezem.
A mi esetünkben a játékos egy aranybányát fog üzemeltetni, és a kattintásért járó jutalma egy új, voxel-stílusú munkás lesz. Ez a "jutalom" 5 dollárba fog kerülni.
Minden munkás fáradhatatlanul ássa az aranyrögöket és szállítja azokat a ládákhoz, ahol egy automatizált lift felveszi és egy másik, felszíni ládába viszi őket.
Onnan egy másik csapat a raktárba szállítja a rögöket, és a játékos minden egyes darabért 1 dollárt kap (úgy tűnik, az aranypiac jelenleg nem túl forró).
Mindössze 20 dollárért nyithatsz egy új aknát.
A játék, akárcsak az emberi kapzsiság, sosem ér véget, de elég hamar unalmassá válik: megnyitod az összes aknát és megtöltöd őket munkásokkal. Ezen a ponton már csak tétlenül nézheted, ahogy a vagyonod nő, vagy megnézheted az alábbi oktatóanyagok egyikét.

Íme, hogyan működik (teljes kód alább):

[1-7] A HTML5 vászon (canvas) és a betűtípusának beállítása.
[8-27] Képek
[29-30] Akna méretei
[32] 5$ egy új munkás felvételéhez
[33] max 3 munkás aknánként
[34] 20$ egy új akna megnyitása (micsoda alku!)
[35] 10 akna maximum - ennyi fér el a vásznunkon
[36-37] a képek méretei
[38] minden animációs szekvencia 20 képkockából áll
[39] a vászon vízszintes és függőleges nyújtásának aránya, hogy illeszkedjen az eszköz képernyőjéhez
[40] a pontszám az aktuális készpénzed
[41] az aknák tömbjének inicializálása
[42] az aktuális animációs képkocka (0-val kezdődik)

[43-81] a lift objektum:
[44] kezdeti sebesség
[45-59] Amikor a lift megérkezik egy aknához:
[47-52] ha a föld alatt van, mozgasd az aranyat (ha van) a ládából a liftbe, ürítsd ki az akna ládáját, indítsd el a rakodási számlálót
[54-58] különben mozgasd az aranyat a liftből az akna ládájába
[60-67] A lift mozgatása:
[61] az y koordináta megváltoztatása
[63-64] ha a lift megérkezett egy aknához, hajtsd végre a megfelelő függvényt
[65-66] ha elérte a tetejét vagy az alját, fordítsd meg a sebességet
[68-80] A lift rajzolása és frissítése:
[69] A bittérkép rajzolása
[70] A láda tartalmának megjelenítése
[71-75] Ha a rakodási számláló be van kapcsolva, rajzold a nyilat az aktuális irányba
[76] és csökkentsd a számlálót
[77-78] különben mozgasd a liftet.

[83-100] Az akna
[84] munkások nélkül indul
[85] és üres ládával
[86] alapértelmezés szerint zárva (később nyitjuk meg)
[87-93] Az akna rajzolása:
[88-92] Ha van hely több munkásnak, mutasd a "munkás felvétele" gombot (aktív vagy inaktív, attól függően, hogy van-e elég pénzed)
[94-98] Új akna megnyitása:
[95] váltás "nyitva" állapotra
[96] a nyitott aknák számlálójának növelése
[97] az első munkás automatikus felvétele
[98] és kifizetése.

[102-154] Munkások
[103] véletlenszerűen kezdenek valahol a lift közelében
[104] jobbra nézve
[107-153] Munkás logika:
[110-117] Ha ás:
[111] Növeld az ásási számlálót
[112] használd a spritesheet 5. sorát:


[113] Ha már 100 képkocka óta ás, fejezze be az ásást és menjen a lifthez.
[118-130] Ha jobbra megy:
[119] használd a spritesheet 1. (felső) sorát
[120] mozgás jobbra
[121] ha közel van a jobb oldalhoz, kezdjen el ásni, vagy (ha a felszínen van) helyezze el a szállítmányt a raktárban és menjen vissza a lifthez
[131-146] Ha balra megy:
[132] Használd a spritesheet 2. sorát
[133] mozgás balra
[134-144] ha közel van a ládához:
[135] forduljon meg
[136-7] adja az aranyat a ládához, ha a föld alatt van
[138-143] ha van arany a ládában, vegye el
[147-148] Ha a felszínen van, menjen le két sort a spritesheeten (hogy megfordítsa az irányt, amerre néz). A felszínen balra haladva cipeli a rögöt, jobbra haladva pedig üres kézzel megy. A föld alatt ez fordítva van.
[149-150] Ha a felszínen van és üres a keze, használja az 1. sort.
[152] a képkocka kirajzolása a spritesheetről.
[156-169] A képernyő rajzolása:
[157] a háttérkép kirajzolása a nyitott aknákhoz
[158] a pontszám mutatása
[159-162] a nyitott aknák kirajzolása
[165-168] az aktív/inaktív "új akna" gomb kirajzolása

[171-183] Fő animációs ciklus
[173-177] minden munkás frissítése
[179-181] A képkocka-számláló növelése és szükség esetén visszaállítása.
[182] Várakozás a következő animációs képkockára.
[185-203] A változók kezdeti értékei.
[205-214] Ha az ablakot átméretezik (pl. a mobil eszközt elforgatják), változtasd meg a vászon stílusának méreteit, hogy kitöltse az egész képernyőt, és számítsd ki a frissített x/y arányokat.

[216-230] Kattintás kezelése
[217-218] a koordináták újraszámítása az arányok figyelembevételével
[219] Melyik akna gombjára kattintottak?
[221-224] ha egy "munkás felvétele" gombra kattintottak, adj hozzá egy munkást és fizesd ki
[225-227] különben nyiss meg egy új aknát

[232-242] Amikor az ablak először betöltődik:
[233-238] hozd létre az aknákat és állítsd be a munkások maximális számát
[235-236] a felszínen 5-ször több munkás lehet, mint az aknákban.


<html>
<body>
<canvas id='canvaswidth='600height='600style='position:absoluteleft:0top:0'></canvas>
<script>
const canvas = document.getElementById('canvas');
const context = canvas.getContext('2d');
context.font = 'bold 16px sans-serif';
const backgroundImg = new Image();
backgroundImg.src = 'background.png';
const liftImg = new Image();
liftImg.src = 'lift.png';
const arrowLeftImg = new Image();
arrowLeftImg.src = 'arrow.png';
const arrowRightImg = new Image();
arrowRightImg.src = 'arrow_right.png';
const spritesheetImg = new Image();
spritesheetImg.src = 'spritesheet.png';
const closeImg = new Image();
closeImg.src = 'close.png';
const workerActiveButtonsImg = new Image();
workerActiveButtonsImg.src = 'worker_active.png';
const workerInactiveButtonsImg = new Image();
workerInactiveButtonsImg.src = 'worker_inactive.png';
const shaftActiveButtonsImg = new Image();
shaftActiveButtonsImg.src = 'shaft_active.png';
const shaftInactiveButtonsImg = new Image();
shaftInactiveButtonsImg.src = 'shaft_inactive.png';
 
const shaftHeight = 60,
  shaftWidth = 450,
  liftWidth = 40,
  workerCost = 5,
  max_workers = 3,
  shaftCost = 20,
  max_shafts = 10,
  buttonWidth = 150,
  spriteSize = 60,
  max_frames = 19;
let aspectXaspectY;
let scoreshaftsOpen;
let shafts = [];
let frame = 0;
let lift = {
  speed: .5,
  arrivedAtShaftfunction(shaftNumber) {
    let shaft = shafts[shaftNumber];
    if (shaftNumber > 0) {
      if (shaft.chest > 0) {
        this.chest = this.chest + shaft.chest;
        shaft.chest = 0;
        this.loadingCounter = 100;
      }
    } else {
      if (this.chest > 0)
        this.loadingCounter = 100;
      shaft.chest = shaft.chest + this.chest;
      this.chest = 0;
    }
  },
  movefunction() {
    this.y = this.y + this.speed;
    let currentShaft = this.y / shaftHeight;
    if (currentShaft == Math.floor(currentShaft))
      this.arrivedAtShaft(currentShaft);
    if (this.y >= (shaftsOpen - 1) * shaftHeight || this.y <= 0)
      this.speed = -this.speed;
  },
  updatefunction() {
    context.drawImage(liftImg0this.y);
    context.fillText(this.chest10this.y + 25);
    if (this.loadingCounter) {
      if (this.y > 0)
        context.drawImage(arrowLeftImgliftWidth * .5this.y);
      else
        context.drawImage(arrowRightImgliftWidth * .5this.y);
      this.loadingCounter--;
    } else {
      this.move();
    }
  },
};
 
function Shaft() {
  this.workers = [];
  this.chest = 0;
  this.closed = true;
  this.draw = function(shaftNumber) {
    if (shafts[shaftNumber].workers.length < shafts[shaftNumber].max_workers)
      if (score >= workerCost)
        context.drawImage(workerActiveButtonsImgshaftWidthshaftHeight * shaftNumber);
      else
        context.drawImage(workerInactiveButtonsImgshaftWidthshaftHeight * shaftNumber);
  };
  this.open = function() {
    this.closed = false;
    shaftsOpen++;
    this.workers.push(new Worker());
    score = score - shaftCost;
  };
}
 
function Worker() {
  this.x = Math.floor(Math.random() * liftWidth);
  this.mode = 'goRight';
  this.counter = 0;
  this.load = 0;
  this.update = function(shaftNumber) {
    let row;
    switch (this.mode) {
      case 'dig':
        this.counter++;
        row = 4;
        if (this.counter > 100) {
          this.counter = 0;
          this.mode = 'goLeft';
        }
        break;
      case 'goRight':
        row = 0;
        this.x++;
        if (this.x >= shaftWidth - spriteSize * 1.5 + Math.random() * spriteSize) {
          if (shaftNumber > 0)
            this.mode = 'dig';
          else {
            score = score + this.load;
            this.load = 0;
            this.mode = 'goLeft';
          }
        }
        break;
      case 'goLeft':
        row = 1;
        this.x--;
        if (this.x <= 2 * liftWidth) {
          this.mode = 'goRight';
          if (shaftNumber > 0) {
            shafts[shaftNumber].chest = shafts[shaftNumber].chest + 1;
          } else {
            if (shafts[0].chest > 0) {
              this.load = 1;
              shafts[0].chest = shafts[0].chest - 1;
            }
          }
        }
        break;
    }
    if (shaftNumber == 0) {
      row = row + 2;
      if (this.load == 0 && this.mode == 'goRight')
        row = 0;
    }
    context.drawImage(spritesheetImgframe * spriteSizerow * spriteSizespriteSizespriteSizethis.xshaftNumber * shaftHeightspriteSizespriteSize);
  };
}
 
function drawScreen() {
  context.drawImage(backgroundImg00shaftWidth + buttonWidthshaftHeight * shaftsOpen00shaftWidth + buttonWidthshaftHeight * shaftsOpen);
  context.fillText(score30015);
  shafts.forEach((shaftshaftNumber) => {
    if (!shaft.closed) {
      context.fillText(shaft.chestliftWidth + 15shaftNumber * shaftHeight + 25);
      shaft.draw(shaftNumber);
    }
  });
  if (score >= shaftCost)
    context.drawImage(shaftActiveButtonsImgshaftWidthshaftHeight * (shaftsOpen));
  else
    context.drawImage(shaftInactiveButtonsImgshaftWidthshaftHeight * (shaftsOpen));
}
 
function animate() {
  drawScreen();
  shafts.forEach((shaftshaftNumber) => {
    shaft.workers.forEach((worker) => {
      worker.update(shaftNumber);
    });
  });
  lift.update();
  frame++;
  if (frame > max_frames)
    frame = 0;
  window.requestAnimationFrame(animate);
}
 
function reset() {
  shaftsOpen = 0;
  score = 70;
  lift.y = 0;
  lift.chest = 0;
  lift.loadingCounter = 0;
  shafts.forEach((shaft) => {
    shaft.closed = true;
    shaft.workers = [];
  });
  shafts[0].open();
  shafts[1].open();
  for (let i = shaftsOpeni < max_shaftsi++) {
    shafts[i].closed = true;
    shafts[i].workers = [];
    context.drawImage(closeImg0i * shaftHeight);
  }
  animate();
}
 
function resize() {
  let picSizeX = window.innerWidth;
  let picSizeY = window.innerHeight;
  canvas.style.width = window.innerWidth;
  canvas.style.height = window.innerHeight;
  aspectX = picSizeX / 600;
  aspectY = picSizeY / 600;
}
 
window.onresize = resize;
 
window.onpointerdown = function(event) {
  let x = event.offsetX / aspectX;
  let y = event.offsetY / aspectY;
  let shaftNumber = Math.floor(y / shaftHeight);
  let shaft = shafts[shaftNumber];
  if (x > shaftWidth)
    if (shaftNumber < shaftsOpen && score >= workerCost && shaft.workers.length <= shaft.max_workers) {
      shaft.workers.push(new Worker());
      score = score - workerCost;
    } else {
      if (shaftNumber == shaftsOpen && score >= shaftCost) {
        shaft.open();
      }
    }
};
 
window.onload = function() {
  for (let i = 0i < max_shaftsi++) {
    shafts[i] = new Shaft();
    if (i == 0)
      shafts[i].max_workers = max_workers * 5;
    else
      shafts[i].max_workers = max_workers;
  }
  reset();
  resize();
};
</script>
</body>
</html>


További JavaScript oktatóanyagok:

Buborékrendezés vizualizációja

Tűzijáték animáció

Stick Champ játék