Umíme ve Flashi – 19. díl – detekce kolize objektů

Dnešním dílem začínáme další z miniseriálů, na jehož konci bude akční hra, umožňující ukládání výsledků všech zúčastněných hráčů. Dnes se zaměříme na nejdůležitější funkci, která se týká detekce kolize jednotlivých objektů.

O čem hra bude?

Až společně projdeme všechny díly tohoto miniseriálu, budeme mít před sebou hru, kde budeme ovládat pohyb figurky po ploše. Tato figurka bude umět skákat, chodit, běhat, sbírat objekty, střílet a samozřejmě že se bude muset vypořádat s nejrůznějšími nástrahami.

Prakticky všechny funkce, které budeme k tvorbě potřebovat, jsme si alespoň v základní formě již dříve představili. Jedna z funkcí nás ale bude provázet téměř neustále, proto se na ní v prvních dvou dílech zaměříme podrobněji.

Detekce kolize dvou objektů

Pokud chceme vytvořit hru, musíme bezpodmínečně zvládnout detekci kolize dvou objektů. Detekci kolize dvou objektů jsme si představili v dílech, kdy jsme tvořili závodní autíčko (díly 26. a 27. úvodní části). Ovšem v naší hře budeme detekci kolize potřebovat v mnohem propracovanější podobě.

Samotný pohyb figurky je neustálé testování, zda se nedotýká některé s částí prostředí hry. Už jen pouhá chůze po rovině znamená zjišťování kolize figurky a podlahy, protože musíme mít zajištěno, že nám figurka během pohybu „nepropadne„ podlahou. Co by to ale bylo za hru, kdybychom chodili pouze po rovině a nemuseli přeskakovat či jinak překonávat různé nástrahy. Taková hra by nás a naše uživatele brzy přestala bavit.

Do cesty proto postavíme objekty, které budeme muset figurkou překonávat. Opět se zde musíme zaměřit na detekci kolize dvou objektů. Výsledkem setkání figurky a překážky musí být zastavení chůze. A další objekty hře? Určitě budeme chtít umístit alespoň jednoho soupeře, který bude naší figurku ohrožovat život beroucími střelami, nebo i jednotlivé objekty, které budou pro figurku sami o sobě nebezpečné. Zase zde budeme muset zjišťovat kolizi vystřeleného projektilu, nebezpečných objektů apod.

Jak je zřejmé, detekce kolize bude stěžejní a velmi potřebná funkce. Dnes si ukážeme možnosti detekce kolize na jednoduchém příkladu, který v dalším díle upravíme a zobecníme pro univerzální použití na dva objekty ve scéně.

Metoda HitTest()

Toto je metoda, pomocí které budeme detekci kolize provádět. Pro zjištění kolize existuje i mnoho jiných řešení, kde mezi nejlepší patří řešení s využitím BitmapData třídy (viz zde). Ovšem i toto řešení není stoprocentní, a proto se pustíme do vlastního, které bude vyhovovat našemu účelu.

Pomocí metody HitTest() můžeme zjistit, zda se dva objekty protínají. Existují dvě základní varianty této metody, kde v prvním případě testujeme dva celé objekty a jejich průnik, v druhém případě testujeme kolizi souřadnice a objektu.

My se podíváme na druhou možnost, testování průniku souřadnice a objektu. Protože jednou ze základních funkcí bude chůze figurky po ploše, na jednoduchém příkladě si vyzkoušíme vytvořit objekt, chodící po podlaze a zastavující se o různé překážky.

Otevřeme si nový dokument a na scénu vložíme objekt, kterým budeme chtít pohybovat a na panelu vlastností jej pojmenujeme „obj“. Dále si vytvoříme podlahu s překážkami a převedeme ji na MC.

Dotyky s podlahou

Během pohybu se náš objekt může setkat s podlahou ve třech různých situacích (nebudeme dnes uvažovat horní dotyky o strop). Základní situací je spodní dotyk o podlahu. Další možnou situací je dotyk z levé a z pravé strany, kde může náš objekt narazit na překážky, bránící v dalším pohybu.

Jakmile s objektem narazíme na nějakou překážku, musíme určit, o jaký dotyk se jedná a podle toho zareagovat a zastavit další postup. Klikneme proto na objekt s podlahou a na panelu akcí mu přiřadíme tento skript:

onClipEvent (load) {
 posuv = 2;
 dotykSpodni = function () {
  spodek = false;
  for (i=1; i<_root.obj._width; i++) {
   if (this.hitTest(sour_x+i, sour_y+sour_h, true)) {
    trace("dotyk spodní");
    spodek = true;
   }
  }
  return spodek;
 };
 dotykLevy = function () {
  leva = false;
  for (i=1; i<_root.obj._height; i++) {
   if (this.hitTest(sour_x, sour_y+i, true)) {
    trace("dotyk levý");
    leva = true;
   }
  }
  return leva;
 };
 dotykPravy = function () {
  prava = false;
  for (i=1; i<_root.obj._height; i++) {
   if (this.hitTest(sour_x+sour_w, sour_y+i, true)) {
    trace("dotyk pravý");
    prava = true;
   }
  }
  return prava;
 };
}

Nejdříve proměnnou „posuv“ určíme vzdálenost, o kterou se objekt při stisknutí klávesy pohne. Následují tři funkce, pomocí kterých zjistíme, kterou částí jsme se objektem dotkli podlahy. Protože jsme se rozhodli pro testování bodu vůči podlaze, musíme vzít vždy několik bodů (cyklus FOR) hrany objektu, abychom získali co nejpřesnější výsledek. V ideálním případě bychom měli testovat podrobnější souřadnice, ale pro naše účely zatím stačí testování souřadnic s krokem „1“.

Další část skriptu, který umístíme na objekt podlahy, vypadá následovně:

onClipEvent (enterFrame) {
 sour_w = _root.obj._width;
 sour_h = _root.obj._height;
 if (Key.isDown(Key.LEFT) && Key.isDown(Key.DOWN)) {
  sour_y = _root.obj._y+posuv;
  sour_x = _root.obj._x-posuv;
  resA = dotykSpodni();
  resB = dotykLevy();
  if (!resA && !resB) {
   _root.obj._x -= posuv;
   _root.obj._y += posuv;
  }
 } else if (Key.isDown(Key.LEFT) && Key.isDown(Key.UP)) {
  sour_y = _root.obj._y-posuv;
  sour_x = _root.obj._x-posuv;
  resA = dotykLevy();
  if (!resA) {
   _root.obj._x -= posuv;
   _root.obj._y -= posuv;
  }
 } else if (Key.isDown(Key.RIGHT) && Key.isDown(Key.DOWN)) {
  sour_y = _root.obj._y+posuv;
  sour_x = _root.obj._x+posuv;
  resA = dotykSpodni();
  resB = dotykPravy();
  if (!resA && !resB) {
   _root.obj._x += posuv;
   _root.obj._y += posuv;
  }
 } else if (Key.isDown(Key.RIGHT) && Key.isDown(Key.UP)) {
  sour_y = _root.obj._y-posuv;
  sour_x = _root.obj._x+posuv;
  resA = dotykPravy();
  if (!resA) {
   _root.obj._x += posuv;
   _root.obj._y -= posuv;
  }
 } else if (Key.isDown(Key.RIGHT)) {
  sour_y = _root.obj._y;
  sour_x = _root.obj._x+posuv;
  resA = dotykPravy();
  if (!resA) {
   _root.obj._x += posuv;
  }
 } else if (Key.isDown(Key.LEFT)) {
  sour_y = _root.obj._y;
  sour_x = _root.obj._x-posuv;
  resA = dotykLevy();
  if (!resA) {
   _root.obj._x -= posuv;
  }
 } else if (Key.isDown(Key.UP)) {
  _root.obj._y -= posuv;
 } else {
  sour_y = _root.obj._y+posuv;
  sour_x = _root.obj._x;
  resA = dotykSpodni();
  if (!resA) {
   _root.obj._y += posuv;
  }
 }
}

V onEnterFrame události zjišťujeme, jaké tlačítko je právě stisknuté. Hlídáme kurzorové šipky, které budou ovládat pohyb objektu po scéně. Trochu netradičně se teď podíváme až na úplný konec, kde z předchozích podmínek plyne, že pokud není stisknutá ani jedna ze šipek, objekt pomalu padá dolů, dokud se nedotkne podlahy. Dotek podlahy zjistíme proměnnou „resA“, do které vložíme výsledek z funkce pro detekci spodní kolize. Pokud jsme se zatím podlahy nedotkli, pohybujeme objektem dolů. Pokud jsme se podlahy dotkli, nic se neprovede.

Ve stejném duchu se odehrávají podmínky na začátku, kde nejdříve testujeme možné kombinace dvou kláves, které vedou v šikmý pohyb po scéně, a ve zbylé části zjišťujeme už pouze jednotlivé klávesy. Vždy, než provedeme posuv objektu, vložíme do proměnné „sour_y“ a „sour_x“ další možné umístění objektu, které ihned otestujeme. Pokud zjistíme, že pomocné proměnné „resA“ a „resB“ jsou hodnoty logická „NE“, můžeme objekt posunout na další pozici. Pokud se tak nestane, víme, že se objekt na dalším umístění dotkne podlahy, a proto s ním dále nehýbeme.

Výsledek ovládání pohybu si můžeme prohlédnout zde.

V příštím díle se zaměříme na reálnější ztvárnění pohybu objektu a na zobecnění použitých funkcí detekce kolize, pro širší použití.

Zdrojový soubor dnešní ukázky je ke stažení zde.

Určitě si přečtěte

Články odjinud