You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Web-Dev-For-Beginners/translations/hr/6-space-game/3-moving-elements-around/README.md

24 KiB

Izgradnja svemirske igre, dio 3: Dodavanje kretanja

Razmislite o svojim omiljenim igrama ono što ih čini privlačnima nisu samo lijepe grafike, već način na koji se sve kreće i reagira na vaše akcije. Trenutno je vaša svemirska igra poput prekrasne slike, ali uskoro ćemo dodati kretanje koje će je oživjeti.

Kada su NASA-ini inženjeri programirali računalo za navođenje Apollo misija, suočili su se sa sličnim izazovom: kako učiniti da svemirska letjelica reagira na unos pilota, a istovremeno automatski održava korekcije kursa? Principi koje ćemo danas naučiti odražavaju te iste koncepte upravljanje kretanjem koje kontrolira igrač uz automatsko ponašanje sustava.

U ovoj lekciji naučit ćete kako učiniti da svemirski brodovi klize po ekranu, reagiraju na naredbe igrača i stvaraju glatke uzorke kretanja. Sve ćemo razložiti na razumljive koncepte koji se prirodno nadovezuju jedan na drugi.

Na kraju, igrači će moći upravljati svojim herojskim brodom po ekranu dok neprijateljski brodovi patroliraju iznad. Još važnije, razumjet ćete osnovne principe koji pokreću sustave kretanja u igrama.

Kviz prije predavanja

Pre-lecture quiz

Razumijevanje kretanja u igrama

Igre oživljavaju kada se stvari počnu kretati, a postoje dva osnovna načina na koja se to događa:

  • Kretanje kontrolirano od strane igrača: Kada pritisnete tipku ili kliknete mišem, nešto se pomakne. Ovo je izravna veza između vas i svijeta igre.
  • Automatsko kretanje: Kada sama igra odluči pomaknuti stvari poput onih neprijateljskih brodova koji trebaju patrolirati ekranom bez obzira na vaše radnje.

Pomicanje objekata na ekranu računala jednostavnije je nego što mislite. Sjećate li se onih x i y koordinata iz matematike? Upravo s njima radimo ovdje. Kada je Galileo 1610. pratio Jupiterove mjesece, u biti je radio isto bilježio je položaje tijekom vremena kako bi razumio uzorke kretanja.

Pomicanje stvari na ekranu je poput stvaranja animacije u obliku flipbooka trebate slijediti ova tri jednostavna koraka:

  1. Ažurirajte položaj Promijenite gdje bi vaš objekt trebao biti (možda ga pomaknite 5 piksela udesno)
  2. Izbrišite stari okvir Očistite ekran kako ne biste vidjeli sablasne tragove posvuda
  3. Nacrtajte novi okvir Postavite svoj objekt na njegovo novo mjesto

Ako to radite dovoljno brzo, bum! Dobivate glatko kretanje koje se igračima čini prirodnim.

Evo kako to može izgledati u kodu:

// Set the hero's location
hero.x += 5;
// Clear the rectangle that hosts the hero
ctx.clearRect(0, 0, canvas.width, canvas.height);
// Redraw the game background and hero
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = "black";
ctx.drawImage(heroImg, hero.x, hero.y);

Što ovaj kod radi:

  • Ažurira x-koordinatu heroja za 5 piksela kako bi se pomaknuo vodoravno
  • Briše cijelo područje platna kako bi uklonio prethodni okvir
  • Ispunjava platno crnom bojom pozadine
  • Ponovno crta sliku heroja na njegovom novom položaju

Možete li smisliti razlog zašto ponovno crtanje vašeg heroja mnogo puta u sekundi može uzrokovati troškove performansi? Pročitajte o alternativama ovom obrascu.

Rukovanje događajima na tipkovnici

Ovdje povezujemo unos igrača s akcijom u igri. Kada netko pritisne razmaknicu za ispaljivanje lasera ili pritisne strelicu za izbjegavanje asteroida, vaša igra mora otkriti i reagirati na taj unos.

Događaji na tipkovnici događaju se na razini prozora, što znači da cijeli prozor vašeg preglednika sluša te pritiske tipki. Klikovi mišem, s druge strane, mogu se vezati za određene elemente (poput klikanja na gumb). Za našu svemirsku igru, fokusirat ćemo se na kontrole tipkovnice jer one igračima daju taj klasični arkadni osjećaj.

Ovo me podsjeća na to kako su telegrafisti u 1800-ima morali prevoditi unos Morseove abecede u smislene poruke radimo nešto slično, prevodimo pritiske tipki u naredbe igre.

Za rukovanje događajem trebate koristiti metodu addEventListener() prozora i pružiti joj dva ulazna parametra. Prvi parametar je naziv događaja, na primjer keyup. Drugi parametar je funkcija koja bi se trebala pozvati kao rezultat događaja.

Evo primjera:

window.addEventListener('keyup', (evt) => {
  // evt.key = string representation of the key
  if (evt.key === 'ArrowUp') {
    // do something
  }
});

Razlaganje onoga što se ovdje događa:

  • Sluša događaje na tipkovnici na cijelom prozoru
  • Hvata objekt događaja koji sadrži informacije o tome koja je tipka pritisnuta
  • Provjerava odgovara li pritisnuta tipka određenoj tipki (u ovom slučaju, strelici gore)
  • Izvršava kod kada je uvjet ispunjen

Za događaje na tipkama postoje dva svojstva na događaju koja možete koristiti za provjeru koja je tipka pritisnuta:

  • key - ovo je tekstualni prikaz pritisnute tipke, na primjer 'ArrowUp'
  • keyCode - ovo je brojčani prikaz, na primjer 37, što odgovara ArrowLeft

Manipulacija događajima na tipkama korisna je i izvan razvoja igara. Koje druge primjene možete zamisliti za ovu tehniku?

Posebne tipke: upozorenje!

Neke tipke imaju ugrađene funkcije preglednika koje mogu ometati vašu igru. Strelice pomiču stranicu, a razmaknica skrolira prema dolje ponašanja koja ne želite kada netko pokušava upravljati svojim svemirskim brodom.

Možemo spriječiti ova zadana ponašanja i dopustiti našoj igri da upravlja unosom. Ovo je slično tome kako su rani računalni programeri morali nadjačati sistemske prekide kako bi stvorili prilagođena ponašanja mi to radimo na razini preglednika. Evo kako:

const onKeyDown = function (e) {
  console.log(e.keyCode);
  switch (e.keyCode) {
    case 37:
    case 39:
    case 38:
    case 40: // Arrow keys
    case 32:
      e.preventDefault();
      break; // Space
    default:
      break; // do not block other keys
  }
};

window.addEventListener('keydown', onKeyDown);

Razumijevanje ovog koda za sprječavanje:

  • Provjerava specifične kodove tipki koji bi mogli uzrokovati neželjeno ponašanje preglednika
  • Sprječava zadanu akciju preglednika za strelice i razmaknicu
  • Dopušta ostalim tipkama da normalno funkcioniraju
  • Koristi e.preventDefault() za zaustavljanje ugrađenog ponašanja preglednika

Kretanje inducirano igrom

Sada ćemo razgovarati o objektima koji se kreću bez unosa igrača. Razmislite o neprijateljskim brodovima koji krstare ekranom, mecima koji lete ravno ili oblacima koji lebde u pozadini. Ovo autonomno kretanje čini vaš svijet igre živim čak i kada nitko ne dodiruje kontrole.

Koristimo ugrađene JavaScript timere za ažuriranje položaja u redovitim intervalima. Ovaj koncept je sličan načinu na koji rade klatna u satovima redoviti mehanizam koji pokreće dosljedne, vremenski određene radnje. Evo kako to može izgledati:

const id = setInterval(() => {
  // Move the enemy on the y axis
  enemy.y += 10;
}, 100);

Što ovaj kod za kretanje radi:

  • Stvara timer koji se pokreće svakih 100 milisekundi
  • Ažurira y-koordinatu neprijatelja za 10 piksela svaki put
  • Pohranjuje ID intervala kako bismo ga kasnije mogli zaustaviti ako je potrebno
  • Pomiče neprijatelja prema dolje na ekranu automatski

Petlja igre

Evo koncepta koji sve povezuje petlja igre. Ako je vaša igra film, petlja igre bila bi projektor filma, prikazujući kadar za kadrom tako brzo da se sve čini kao glatko kretanje.

Svaka igra ima jednu od ovih petlji koja radi u pozadini. To je funkcija koja ažurira sve objekte igre, ponovno crta ekran i kontinuirano ponavlja ovaj proces. Ovo prati vašeg heroja, sve neprijatelje, sve lasere koji lete okolo cijelo stanje igre.

Ovaj koncept me podsjeća na to kako su rani animatori poput Walta Disneya morali ponovno crtati likove kadar po kadar kako bi stvorili iluziju kretanja. Mi radimo isto, samo s kodom umjesto olovaka.

Evo kako tipična petlja igre može izgledati, izražena u kodu:

const gameLoopId = setInterval(() => {
  function gameLoop() {
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    ctx.fillStyle = "black";
    ctx.fillRect(0, 0, canvas.width, canvas.height);
    drawHero();
    drawEnemies();
    drawStaticObjects();
  }
  gameLoop();
}, 200);

Razumijevanje strukture petlje igre:

  • Briše cijelo platno kako bi uklonila prethodni okvir
  • Ispunjava pozadinu čvrstom bojom
  • Crta sve objekte igre na njihovim trenutnim položajima
  • Ponavlja ovaj proces svakih 200 milisekundi kako bi stvorila glatku animaciju
  • Upravlja brzinom kadrova kontroliranjem intervalnog vremena

Nastavak svemirske igre

Sada ćemo dodati kretanje u statičnu scenu koju ste prethodno izgradili. Pretvorit ćemo je iz snimke zaslona u interaktivno iskustvo. Proći ćemo kroz ovo korak po korak kako bismo osigurali da se svaki dio nadovezuje na prethodni.

Preuzmite kod odakle smo stali u prethodnoj lekciji (ili započnite s kodom u Part II- starter mapi ako trebate svježi početak).

Evo što danas gradimo:

  • Kontrole heroja: Strelice će upravljati vašim svemirskim brodom po ekranu
  • Kretanje neprijatelja: Ti vanzemaljski brodovi će započeti svoj napad

Krenimo s implementacijom ovih značajki.

Preporučeni koraci

Pronađite datoteke koje su stvorene za vas u podmapi your-work. Trebale bi sadržavati sljedeće:

-| assets
  -| enemyShip.png
  -| player.png
-| index.html
-| app.js
-| package.json

Svoj projekt započnite u mapi your-work upisivanjem:

cd your-work
npm start

Što ova naredba radi:

  • Navigira do direktorija vašeg projekta
  • Pokreće HTTP poslužitelj na adresi http://localhost:5000
  • Poslužuje datoteke vaše igre kako biste ih mogli testirati u pregledniku

Gore navedeno će pokrenuti HTTP poslužitelj na adresi http://localhost:5000. Otvorite preglednik i unesite tu adresu, trenutno bi trebao prikazati heroja i sve neprijatelje; ništa se još ne miče!

Dodavanje koda

  1. Dodajte namjenske objekte za heroja, neprijatelja i objekt igre, oni bi trebali imati svojstva x i y. (Sjetite se dijela o Nasljeđivanju ili kompoziciji).

    SAVJET objekt igre trebao bi biti onaj s x i y te sposobnošću da se nacrta na platnu.

    Savjet: Započnite dodavanjem nove klase GameObject s konstruktorom definiranim kao dolje, a zatim ga nacrtajte na platnu:

    class GameObject {
      constructor(x, y) {
        this.x = x;
        this.y = y;
        this.dead = false;
        this.type = "";
        this.width = 0;
        this.height = 0;
        this.img = undefined;
      }
    
      draw(ctx) {
        ctx.drawImage(this.img, this.x, this.y, this.width, this.height);
      }
    }
    

    Razumijevanje ove osnovne klase:

    • Definira zajednička svojstva koja dijele svi objekti igre (položaj, veličina, slika)
    • Uključuje zastavicu dead za praćenje treba li objekt biti uklonjen
    • Pruža metodu draw() koja prikazuje objekt na platnu
    • Postavlja zadane vrijednosti za sva svojstva koja podklase mogu nadjačati

    Sada proširite ovaj GameObject kako biste stvorili Hero i Enemy:

    class Hero extends GameObject {
      constructor(x, y) {
        super(x, y);
        this.width = 98;
        this.height = 75;
        this.type = "Hero";
        this.speed = 5;
      }
    }
    
    class Enemy extends GameObject {
      constructor(x, y) {
        super(x, y);
        this.width = 98;
        this.height = 50;
        this.type = "Enemy";
        const id = setInterval(() => {
          if (this.y < canvas.height - this.height) {
            this.y += 5;
          } else {
            console.log('Stopped at', this.y);
            clearInterval(id);
          }
        }, 300);
      }
    }
    

    Ključni koncepti u ovim klasama:

    • Nasljeđuje od GameObject koristeći ključnu riječ extends
    • Poziva konstruktor roditelja s super(x, y)
    • Postavlja specifične dimenzije i svojstva za svaku vrstu objekta
    • Implementira automatsko kretanje za neprijatelje koristeći setInterval()
  2. Dodajte rukovatelje događajima na tipkama za upravljanje navigacijom (pomicanje heroja gore/dolje lijevo/desno)

    ZAPAMTITE to je kartezijanski sustav, gornji lijevi kut je 0,0. Također zapamtite dodati kod za zaustavljanje zadanog ponašanja

    Savjet: Kreirajte svoju funkciju onKeyDown i povežite je s prozorom:

    const onKeyDown = function (e) {
      console.log(e.keyCode);
      // Add the code from the lesson above to stop default behavior
      switch (e.keyCode) {
        case 37:
        case 39:
        case 38:
        case 40: // Arrow keys
        case 32:
          e.preventDefault();
          break; // Space
        default:
          break; // do not block other keys
      }
    };
    
    window.addEventListener("keydown", onKeyDown);
    

    Što ovaj rukovatelj događajima radi:

    • Sluša događaje pritiska tipki na cijelom prozoru
    • Bilježi kod tipke kako bi vam pomogao u otkrivanju koje se tipke pritišću
    • Sprječava zadano ponašanje preglednika za strelice i razmaknicu
    • Dopušta ostalim tipkama da normalno funkcioniraju

    Provjerite konzolu preglednika u ovom trenutku i pratite pritiske tipki koji se bilježe.

  3. Implementirajte Pub sub pattern, ovo će održati vaš kod čistim dok slijedite preostale dijelove.

    Obrazac Publish-Subscribe pomaže organizirati vaš kod razdvajanjem otkrivanja događaja od rukovanja događajima. Ovo čini vaš kod modularnijim i lakšim za održavanje.

    Za ovaj posljednji dio možete:

    1. Dodati slušatelja događaja na prozor:

      window.addEventListener("keyup", (evt) => {
        if (evt.key === "ArrowUp") {
          eventEmitter.emit(Messages.KEY_EVENT_UP);
        } else if (evt.key === "ArrowDown") {
          eventEmitter.emit(Messages.KEY_EVENT_DOWN);
        } else if (evt.key === "ArrowLeft") {
          eventEmitter.emit(Messages.KEY_EVENT_LEFT);
        } else if (evt.key === "ArrowRight") {
          eventEmitter.emit(Messages.KEY_EVENT_RIGHT);
        }
      });
      

    Što ovaj sustav događaja radi:

    • Otkriva unos s tipkovnice i pretvara ga u prilagođene događaje igre
    • Razdvaja otkrivanje unosa od logike igre
    • Omogućuje jednostavnu promjenu kontrola kasnije bez utjecaja na kod igre
    • Dopušta više sustava da reagiraju na isti unos
    1. Kreirajte klasu EventEmitter za objavljivanje i pretplatu na poruke:

      class EventEmitter {
        constructor() {
          this.listeners = {};
        }
      
        on(message, listener) {
          if (!this.listeners[message]) {
            this.listeners[message] = [];
          }
          this.listeners[message].push(listener);
        }
      
      
    2. Dodajte konstante i postavite EventEmitter:

      const Messages = {
        KEY_EVENT_UP: "KEY_EVENT_UP",
        KEY_EVENT_DOWN: "KEY_EVENT_DOWN",
        KEY_EVENT_LEFT: "KEY_EVENT_LEFT",
        KEY_EVENT_RIGHT: "KEY_EVENT_RIGHT",
      };
      
      let heroImg, 
          enemyImg, 
          laserImg,
          canvas, ctx, 
          gameObjects = [], 
          hero, 
          eventEmitter = new EventEmitter();
      

    Razumijevanje postavke:

    • Definira konstante poruka kako bi se izbjegle pogreške u pisanju i olakšalo refaktoriranje
    • Deklarira varijable za slike, kontekst platna i stanje igre
    • Stvara globalni event emitter za sustav pub-sub
    • Inicijalizira niz za pohranu svih objekata igre
    1. Inicijalizirajte igru

      function initGame() {
        gameObjects = [];
        createEnemies();
        createHero();
      
        eventEmitter.on(Messages.KEY_EVENT_UP, () => {
          hero.y -= 5;
        });
      
        eventEmitter.on(Messages.KEY_EVENT_DOWN, () => {
          hero.y += 5;
        });
      
        eventEmitter.on(Messages.KEY_EVENT_LEFT, () => {
          hero.x -= 5;
        });
      
      
  4. Postavite petlju igre

    Refaktorirajte funkciju window.onload kako biste inicijalizirali igru i postavili petlju igre na dobar interval. Također ćete dodati laserski zrak:

    window.onload = async () => {
      canvas = document.getElementById("canvas");
      ctx = canvas.getContext("2d");
      heroImg = await loadTexture("assets/player.png");
      enemyImg = await loadTexture("assets/enemyShip.png");
      laserImg = await loadTexture("assets/laserRed.png");
    
      initGame();
      const gameLoopId = setInterval(() => {
        ctx.clearRect(0, 0, canvas.width, canvas.height);
        ctx.fillStyle = "black";
        ctx.fillRect(0, 0, canvas.width, canvas.height);
        drawGameObjects(ctx);
      }, 100);
    };
    

    Razumijevanje postavke igre:

    • Čeka da se stranica potpuno učita prije početka
    • Dohvaća element platna i njegov 2D kontekst za crtanje
    • Učitava sve slikovne resurse asinkrono koristeći await
    • Pokreće petlju igre koja radi u intervalima od 100 ms (10 FPS)
    • Briše i ponovno crta cijeli ekran svaki kadar
  5. Dodajte kod za pomicanje neprijatelja u određenim intervalima

    Refaktorirajte funkciju createEnemies() kako biste stvorili neprijatelje i dodali ih u novu klasu gameObjects:

    function createEnemies() {
      const MONSTER_TOTAL = 5;
      const MONSTER_WIDTH = MONSTER_TOTAL * 98;
      const START_X = (canvas.width - MONSTER_WIDTH) / 2;
      const STOP_X = START_X + MONSTER_WIDTH;
    
      for (let x = START_X; x < STOP_X; x += 98) {
        for (let y = 0; y < 50 * 5; y += 50) {
          const enemy = new Enemy(x, y);
          enemy.img = enemyImg;
          gameObjects.push(enemy);
        }
      }
    }
    

    Što radi stvaranje neprijatelja:

    • Izračunava položaje za centriranje neprijatelja na ekranu
  • Stvara mrežu neprijatelja koristeći ugniježđene petlje
  • Dodjeljuje sliku neprijatelja svakom objektu neprijatelja
  • Dodaje svakog neprijatelja u globalni niz objekata igre

i dodajte funkciju createHero() koja će obaviti sličan proces za heroja.

```javascript
function createHero() {
  hero = new Hero(
    canvas.width / 2 - 45,
    canvas.height - canvas.height / 4
  );
  hero.img = heroImg;
  gameObjects.push(hero);
}
```

Što radi kreacija heroja:

  • Pozicionira heroja na dno, u sredinu ekrana
  • Dodjeljuje sliku heroja objektu heroja
  • Dodaje heroja u niz objekata igre za prikaz

i na kraju, dodajte funkciju drawGameObjects() za početak crtanja:

```javascript
function drawGameObjects(ctx) {
  gameObjects.forEach(go => go.draw(ctx));
}
```

Razumijevanje funkcije crtanja:

  • Iterira kroz sve objekte igre u nizu
  • Poziva metodu draw() na svakom objektu
  • Prosljeđuje kontekst platna kako bi se objekti mogli sami prikazati

Vaši neprijatelji trebali bi početi napredovati prema vašem svemirskom brodu heroja!
}
}
```

and add a `createHero()` function to do a similar process for the hero.

```javascript
function createHero() {
  hero = new Hero(
    canvas.width / 2 - 45,
    canvas.height - canvas.height / 4
  );
  hero.img = heroImg;
  gameObjects.push(hero);
}
```

i na kraju, dodajte funkciju drawGameObjects() za početak crtanja:

```javascript
function drawGameObjects(ctx) {
  gameObjects.forEach(go => go.draw(ctx));
}
```

Vaši neprijatelji trebali bi početi napredovati prema vašem svemirskom brodu heroja!


Izazov GitHub Copilot Agent 🚀

Evo izazova koji će poboljšati završnu obradu vaše igre: dodavanje granica i glatkih kontrola. Trenutno vaš heroj može odletjeti izvan ekrana, a kretanje može djelovati trzavo.

Vaša misija: Učinite da vaš svemirski brod djeluje realističnije implementacijom granica ekrana i fluidnog kretanja. To je slično načinu na koji NASA-ini sustavi za kontrolu leta sprječavaju svemirske letjelice da prekorače sigurne operativne parametre.

Što treba izgraditi: Stvorite sustav koji drži svemirski brod heroja na ekranu i učinite da kontrole djeluju glatko. Kada igrači drže pritisnutu tipku sa strelicom, brod bi trebao kliziti kontinuirano, umjesto da se kreće u diskretnim koracima. Razmislite o dodavanju vizualne povratne informacije kada brod dosegne granice ekrana možda suptilni efekt koji označava rub područja igre.

Saznajte više o agent modu ovdje.

🚀 Izazov

Organizacija koda postaje sve važnija kako projekti rastu. Možda ste primijetili da vaš dokument postaje pretrpan funkcijama, varijablama i klasama koje su sve izmiješane. To me podsjeća na način na koji su inženjeri organizirali kod za misiju Apollo, stvarajući jasne, održive sustave na kojima su istovremeno mogle raditi različite ekipe.

Vaša misija:
Razmišljajte kao softverski arhitekt. Kako biste organizirali svoj kod tako da ga za šest mjeseci vi (ili vaš kolega) možete razumjeti? Čak i ako sve ostane u jednoj datoteci za sada, možete stvoriti bolju organizaciju:

  • Grupiranje povezanih funkcija zajedno s jasnim zaglavljima komentara
  • Razdvajanje odgovornosti - odvojite logiku igre od prikaza
  • Korištenje dosljednih konvencija imenovanja za varijable i funkcije
  • Stvaranje modula ili prostora imena za organizaciju različitih aspekata vaše igre
  • Dodavanje dokumentacije koja objašnjava svrhu svakog glavnog dijela

Pitanja za razmišljanje:

  • Koji su dijelovi vašeg koda najteži za razumjeti kada se vratite na njih?
  • Kako biste mogli organizirati svoj kod da ga drugi lakše razumiju i doprinesu?
  • Što bi se dogodilo ako biste željeli dodati nove značajke poput pojačanja ili različitih vrsta neprijatelja?

Kviz nakon predavanja

Kviz nakon predavanja

Pregled i samostalno učenje

Sve gradimo od nule, što je fantastično za učenje, ali evo male tajne postoje nevjerojatni JavaScript okviri koji mogu obaviti velik dio posla za vas. Kada se osjećate ugodno s osnovama koje smo obradili, vrijedi istražiti što je dostupno.

Razmislite o okvirima kao o dobro opremljenoj kutiji s alatima, umjesto da svaki alat izrađujete ručno. Oni mogu riješiti mnoge od onih izazova organizacije koda o kojima smo govorili, plus ponuditi značajke koje bi vam inače trebale tjedni da ih sami izradite.

Stvari koje vrijedi istražiti:

  • Kako game engine-i organiziraju kod bit ćete zadivljeni pametnim obrascima koje koriste
  • Trikovi za performanse kako bi igre na platnu radile glatko kao maslac
  • Moderne značajke JavaScripta koje mogu učiniti vaš kod čišćim i lakšim za održavanje
  • Različiti pristupi upravljanju objektima igre i njihovim odnosima

Zadatak

Komentirajte svoj kod


Izjava o odricanju odgovornosti:
Ovaj dokument je preveden pomoću AI usluge za prevođenje Co-op Translator. Iako nastojimo osigurati točnost, imajte na umu da automatski prijevodi mogu sadržavati pogreške ili netočnosti. Izvorni dokument na izvornom jeziku treba smatrati autoritativnim izvorom. Za ključne informacije preporučuje se profesionalni prijevod od strane čovjeka. Ne preuzimamo odgovornost za nesporazume ili pogrešna tumačenja koja proizlaze iz korištenja ovog prijevoda.