Přejít k navigační liště

Zdroják » JavaScript » Dart StageXL – Jak napsat flashovku bez Flashe (a námahy)

Dart StageXL – Jak napsat flashovku bez Flashe (a námahy)

Články JavaScript

Dart je vynikající jazyk a StageXL je vynikající knihovna. Umožní vám nad HTML canvas naprogramovat hru, kterou si pustíte i na Androidu nebo iOS. Pochopitelně v prohlížeči, bez rozšíření a pluginů.

Nálepky:

Výstupem článku je jednoduchá interaktivní blbůstka á la Rorschachův test, kterou si můžete online prohlédnout na we.are.hiring.cz (Chrome prosím, ale ne kvůli StageXL, ale kvůli Polymeru, o tom ovšem jindy).

Co budete potřebovat

Postačí vám DartEditor a základní znalost Dart-u, žádné pokročilé techniky nám nehrozí.
Zdrojáky tutoriálu jsou na GitHub, takže si je stáhněte, otevřete v DartEditoru a jdeme na to.

pubspec.yaml

V závislostech vidíte, že toho moc nevidíte:

name: devfest_2014_stageXL
author: +TomasZverina
description: Workshop o StageXL
dependencies:
  browser: any
  stagexl: any

StageXL je poměrně stabilní, takže “any” nám tu nijak zvlášť nevadí, ale pokud se bojíte, specifikujte si verzi přesně.

Krok 0: Inicizalizace StageXL

StageXL je technologie pro web. Obvykle svůj projekt pomocí “pub” kompilujete do JavaScriptu a nasazujete na web server. Celkem logicky je tedy základem html dokument.
Kromě běžné inicializace Dart-u pak potřebujete jen:

<canvas id="stage" width="500" height="400" style="border: 1px solid black;"></canvas>

Nad tímhle canvasem bude StageXL operovat. Takhle ho nastartujeme …

var canvas = html.querySelector('#stage');
_stage = new Stage(canvas);
var renderLoop = new RenderLoop();
renderLoop.addStage(_stage);

… a takhle do něj přidáme první objekt:

var shape = new Shape();
shape.graphics.rect(0, 0, 50, 50);
shape.graphics.fillColor(Color.Red);
shape.x = 100;
shape.y = 100;
_stage.addChild(shape);

Asi je jasné co to dělá – na souřadnice 100×100 dej červený čtverec 50×50.

Shape je objekt z knihovny StageXL, který se dědí z DisplayObject. DisplayObject je bázová třída pro všechno, co se ve StageXL renderuje a obsahuje všechno, co tak můžete potřebovat pro 2D grafiku:

num x = 0.0; // souřadnice objektu v rodiči
num y = 0.0; // souřadnice objektu v rodiči
num pivotX = 0.0; // referenční bod [0,0], ke kterému vztahuji svoje ...
num pivotY = 0.0; //      souřadnice. Moje "těžiště", střed rotace atd.
num scaleX = 1.0; // natažení v ose X
num scaleY = 1.0; // natažení v ose Y
num skewX = 0.0; // zkosení
num skewY = 0.0;
num rotation = 0.0; // rotace

num alpha = 1.0; // průhlednost (1=plný, 0=zcela průhledný)
bool visible = true; // je viditelný?

Jestli je můj objekt Shape, Bitmap nebo skupina více objektů nastrkaná do jednoho Sprite – to už je jedno.

A rovnou si ukážeme, jak objekty animovat. Náš Shape necháme, aby se během 100 vteřin (konstanta REPEAT) 100x otočil o 380°.

Tween t = new Tween(shape, REPEAT * 1, TransitionFunction.linear);
t.animate.rotation.to(REPEAT * math.PI);
_stage.renderLoop.juggler.add(t);

Animace se dělají tak, že vytvoříte Tween, řeknete co a jak dlouho se má animovat a přidáte Tween do “juggleru” – správce animací.

Když se teď ohlédnete na to málo, co jsme zatím vytvořili, zjistíte, že už nám vlastně skoro nic nechybí. Teď už můžeme napsat v podstatě cokoliv:

  • umíme si připravit HTML a zinicializovat prostředí
  • umíme přidávat a pozicovat objekty
  • umíme je animovat

Zatím neumíme pracovat s obrázky (bitmapami) a neumíme přijímat události (myš, touch).

Krok 1: ResourceManager

Stáhnout si obrázky, zvuky apod. zdroje nějakou dobu trvá. Bylo by užitečné mít možnost si vypsat seznam věcí, které budeme potřebovat, zobrazit “loading” screen a až se zdroje stáhnou, tak abychom mohli náš “stage” spustit. K tomu slouží ResourceManager.

void main() {
  _Rorschach r = new _Rorschach();
  r.initGame();
}

class _Rorschach {

  ResourceManager _resourceManager = new ResourceManager();

  initGame() {
    _resourceManager
      ..addBitmapData("bg", "bg.jpg")
      ..addBitmapData("stain", "stain.png");
    _resourceManager.load().then(_runGame);
  }

  _runGame(_) {
    // muzeme to spustit
  }
}

Vytvoříme instanci ResourceManager, zaregistrujeme zdroje, které budeme potřebovat, a spustíme load(). Load() vrací Future<ResourceManager>, tzn. až bude staženo (then), zavolá se naše metoda _runGame, která ResourceManager bere jako argument. V tomhle případě ale argument ignoruji, ResourceManager mám uložený jako vlastnost mojí třídy _Rorschach.

Stažené bitmapy pak můžeme použít ve stage:

var bgBitmap = new Bitmap(_resourceManager.getBitmapData("bg"));
_stage.addChild(bgBitmap);

Bitmap je opět DisplayObject, takže ji můžeme pozicovat, otáčet, animovat, …

Krok 2: Responzivita

V tomto kroce si upravíme HTML do finální podoby a ukážeme si, jak StageXL nastavit, aby dobře fungovala bez ohledu na velikost obrazovky.

<html>
  <head>
    <meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=1, user-scalable=no">
    <script async type="application/dart" src="step01.dart"></script>
    <script async src="packages/browser/dart.js"></script>
    <style type="text/css">
      body { margin: 0; padding: 0; overflow: hidden; }
      #stage { position: absolute; width: 100%; height: 100%; }
    </style>
  </head>
  <body>
    <canvas id="stage"></canvas>
  </body>
</html>

Canvas si nastylujeme na celou obrazovku a meta tagem viewport vysvětlíme prohlížeči, jak má s naším dokumentem zacházet. V tomto případě vytváříme spíš aplikaci než WWW stránku, takže si můžeme dovolit takové neslušnosti jako user-scalable=no.

Teď je potřeba StageXL naučit, jak s dostupným prostorem pracovat.

var bgBitmap = new Bitmap(_resourceManager.getBitmapData("bg"));
var canvas = html.querySelector('#stage');
_stage = new Stage(canvas, width: bgBitmap.bitmapData.width, height: bgBitmap.bitmapData.height);
_stage.scaleMode = StageScaleMode.NO_BORDER;
_stage.align = StageAlign.NONE;

V konstruktoru Stage předáme rozměry, na které ji optimalizujeme – v našem případě šířku a výšku Bitmapy, kterou máme na pozadí.

Režimem StageScaleMode.NO_BORDER jí říkáme: “Vyplň dostupné místo tak, aby kolem tebe nebyl žádný prázdný prostor, ale nedeformuj se”.

Režim StageAlign.NONE zařídí, aby se Stage centrovala uprostřed dostupného viewportu. Pusťte si hotový krok 5 a zahýbejte velikostí okna, myslím, že to bude jasné.

Kromě toho si v kroce připravíme pole skvrn, které budeme později zobrazovat.

for (int a = 0; a < 2 * STAINS_COUNT; a++) {
  Bitmap stain = new Bitmap(stainData);
  stain.visible = false;
  stain.pivotX = stainPx;
  stain.pivotY = stainPy;

  if (a % 2 == 1) {
    // zrcadlove prevracene skrvrny na druhe strane události myši
    stain.scaleX = -1;
  }

  STAINS.add(stain);
  _stage.addChild(stain);
}

Krok 3: Umísťování skvrn na stage

  • html – se nezměnilo
  • dart

Teď už to začne být zajímavější. Napojíme se na stream událostí myši nad stage a budeme kreslit.

int _stainPointer = 0;

...

_stage.onMouseMove.listen(_placeStain);

...

void _placeStain(MouseEvent event) {

  double rotation = _randomGenerator.nextDouble() * PI;
  double x = event.stageX;
  double y = event.stageY;

  STAINS[_stainPointer].x = x;
  STAINS[_stainPointer].y = y;
  STAINS[_stainPointer].rotation = rotation;
  STAINS[_stainPointer].visible = true;

  // a presunem ukazatel na dalsi
  _stainPointer = (_stainPointer + 1) % STAINS_COUNT;

}

Mimochodem – proč vůbec mám nějaké pole těch skvrn a řeším tu složitosti se _stainPointer? Inu tak – rád recykluju. Mohl bych pokaždé vytvořit novou Bitmap a staré Bitmapy zahazovat, ale garbage collector je taky jenom člověk, tak proč ho trápit.

Krok 4: Zrcadlení skvrn

  • html – se nezměnilo
  • dart

V dalším kroce zařídím, aby se skvrny zobrazovaly nejen pod myší, ale i zrcadlově na druhé straně “papíru”. To už je jen nudná 2D geometrie, tak se jen lehce mrkněte do zdrojáků, co se
změnilo.

Krok 5: Filtr událostí

No a jsme na konci! Teď už nám to dělá co chceme, snad jen že se skvrny objevují zbytečně často. K tomu, abych jejich četnost omezil, použiju API Dart streamů, konkrétně metodu “where”:

_stage.onMouseMove.where(_timeToPlaceFilter).listen(_placeStain);

...

bool _timeToPlaceFilter(Event event) {
  _nowTime = new DateTime.now().millisecondsSinceEpoch;
  return (_nowTime - _lastEventTime > MINIMUM_DELAY);
}

void _placeStain(Event event) {
  ...
  _lastEventTime = _nowTime;
}

Kudy dál

StageXL je velmi silný nástroj. Pokud se vám líbí Dart, není v podstatě o čem přemýšlet. Kdekoliv, kde funguje Dart (resp.
Dartem vygenerovaný JavaScript), bude fungovat i StageXL.

Pokračujte pochopitelně na stránkách StageXL. Pravdou je, že dokumentace knihovny není úplně košatá, ale je tam alespoň spousta komentovaných a názorných příkladů, které si můžete nastudovat.

Kromě toho co jsem vám tu ukázal, umí StageXL masky, filtry, WebGL akceleraci, přehrávání zvuků a spoustu dalších libůstek.

P.S.: RIP, Flash. Chybět nám nebudeš, muahahaha!

Komentáře

Odebírat
Upozornit na
guest
0 Komentářů
Nejstarší
Nejnovější Most Voted
Inline Feedbacks
Zobrazit všechny komentáře

Přístupnost není jen o splnění norem: nový pohled na inkluzivní design

Přístupnost a inkluze možná nepatří mezi nejžhavější témata digitálního světa – dokud o nich nezačne mluvit Vitaly Friedman. Na WebExpo 2024 předvedl, že inkluzivní design není jen o splněných checkboxech, ale hlavně o lidech. S energií sobě vlastní obrátil zažité přístupy naruby a ukázal, že skutečně přístupný web je nejen možný, ale i nezbytný.

Efektivnější vývoj UI nebo API: Co si odnést z WebExpo 2025?

Různé
Komentáře: 0
Jak snadno implementovat moderní uživatelské rozhraní? Které funkce brzdí rychlost vašeho webu? A kdy raději sami přibrzdit, abychom využitím AI nepřekročili etické principy? Debatu aktuálních dev témat rozdmýchá sedmnáctý ročník technologické konference WebExpo, která proběhne v Praze od 28. do 30. května. Který talk či workshop si rozhodně nenechat ujít? Toto je náš redakční výběr z vývojářských hroznů.

Zapřáhněte AI jako nikdy předtím. Květnová konference WebExpo přivítá hvězdy technologického světa

Od 28. do 30. května 2025 promění pražský Palác Lucerna na tři dny technologická konference WebExpo. Na programu je více než 80 přednášek a workshopů od expertů z celého světa. WebExpo tradičně propojuje vývojáře, designéry, marketéry i byznysové lídry a nabízí praktické dovednosti, strategické myšlení a přináší nejnovější trendy nejen v oblasti AI.