Uživatelské nástroje

Nástroje pro tento web


vyuka:tahani_objektu_-_startdrag_a_stopdrag

"Tahání" objektů - startDrag a stopDrag

Flash nám jednoduše umožňuje „táhnout“ objekt myší za pomoci dvou funkcí startDrag() a stopDrag() - jak jejich název napovídá, první z nich zahajuje tahání objektu, zatímco druhá ho ukončuje. Zkusme si vzít nějaký jednoduchý grafický symbol, pojmenujme ho např. placacka a vytvořme pro něj dvě událostní procedury - první při stisknutí tlačítka myši na symbolu zahájí jeho „tažení“ a druhá při puštění tlačítka tahání ukončí:

var placacka:MovieClip;
placacka.addEventListener(MouseEvent.MOUSE_DOWN, function(e) {placacka.startDrag();})
placacka.addEventListener(MouseEvent.MOUSE_UP, function(e) {placacka.stopDrag();})

Výše uvedený skript bude dobře použitelný s jedním nebo několika málo pojmenovanými symboly; kdybychom měli mnoho instancí jednoho symbolu a všechny by měly být „tahatelné“, bylo by jednodušší dát událostní procedury pro zahájení i ukončení tahání dovnitř symbolu (podobně jako jsme dávali událostní procedury dovnitř tlačítek kalkulačky). Jméno instance nahradíme uvnitř symbolu odkazem this, ale dáme si pozor, že pokud použijeme v událostní proceduře nepojmenovanou funkci, pak funkcím startDrag a stopDrag nesmí předcházet this - v tomto případě totiž this ukazuje na „globální objekt“ (který lze použít např. ke sdílení proměnných mezi funkcemi). Máme asi 3 možnosti, jak tedy událostní procedury uvnitř symbolu zapsat:

  • Za použití pojmenovaných funkcí (pak se this chová jak by se očekávalo):
this.addEventListener(MouseEvent.MOUSE_DOWN, tahni)
this.addEventListener(MouseEvent.MOUSE_UP, pust)
function tahni(e) {this.startDrag();}
function pust(e) {this.stopDrag();}
  • Za použití nepojmenované funkce (vynecháme this před startDrag a stopDrag):
this.addEventListener(MouseEvent.MOUSE_DOWN, function (e) {startDrag();})
this.addEventListener(MouseEvent.MOUSE_UP, function (e) {stopDrag();})
  • Za použití nepojmenované funkce a e.currentTarget namísto this:
this.addEventListener(MouseEvent.MOUSE_DOWN, function (e) {e.currentTarget.startDrag();})
this.addEventListener(MouseEvent.MOUSE_UP, function (e) {e.currentTarget.stopDrag();})

Všechny 3 varianty naleznete v tomto souboru - drag-multiple.zip.

Nahrazení kurzoru taženým symbolem

Pokud chceme symbolem nahradit kurzor myši, můžeme funkci startDrag použít i bez událostní procedury, ale budeme muset nastavit první parametr funkce (nazvaný „lockCenter“) na true, aby se symbol tahal za svůj registrační bod („střed“) - pokud tento paramter nenastavíte (nebo zadáte výchozí hodnotu false), kurzor myši a symbol od sebe budou vzdáleny. Šipku kurzoru myši můžeme navíc schovat příkazem Mouse.hide():

placacka.startDrag(true);
Mouse.hide();

Další užitečnou možností funkce startDrag je omezení plochy, po které lze objekt tahat - tu lze vymezit obdélníkem, který se předá jako druhý parametr funkce (nazvaný „bounds“ - omezení). Obdélník (ActionScript má pro něj vlastní datový typ (správněji třídu) Rectangle) se definuje x- a y- souřadnicemi levého horního rohu, šířkou (w) a výškou (h) - takže např. omezení tahání po čtverci začínajícím na souřadnici (100,100) a širokém i vysokém 100 bodů by se zapsalo jako:

var obdelnik:Rectangle = new Rectangle(100,100,100,100) //definice omezujiciho obdelniku (x, y, w, h)
placacka.startDrag(true, obdelnik);

Pokud bychom chtěli omezit pohyb tahaného objektu na celou plochu „plátna“ (aby nám objekt neutíkal ven když okno Flashe např. maximalizujeme), nemusíme zadávat přesný rozměr plochy, ale levý horní roh zadáme jako (0,0), šířku a výšku si můžeme zjistit příkazy stage.stageWidth a stage.stageHeight a omezující obdélník vytvoříme jako:

var obdelnik:Rectangle = new Rectangle(0, 0, stage.stageWidth, stage.stageHeight);

Objekt stage („plátno“) má ještě jiné zajímavé vlastnosti kromě stageWidth a stageHeight - umožňuje např. zjistit aktuální souřadnice kurzoru myši pomocí stage.mouseX a stage.mouseY (a nebo i pouze mouseX a mouseY). Pokud bychom měli na ploše 2 textová pole (nazvaná např. x_txt a y_txt, mohli bychom aktuální pozici kurzoru průbežně zobrazovat pomocí událostní procedury na událost Event.ENTER_FRAME, která se generuje podle snímkové frekvence Flashe (tzn. standartně 24x za sekundu) - vzhledem k tomu, že všechny časové osy ve Flashi běží stejně rychle, není důležité, na který objekt posluchače události ENTER_FRAME přidáme - můžeme ho přidat např. hlavní časové ose, na kterou se odkážeme pomocí this:

this.addEventListener(Event.ENTER_FRAME, function (e) {
	x_txt.text = String(stage.mouseX);
	y_txt.text = String(stage.mouseY);
})

Všimněte si, že pro zobrazení hodnouty x- a y- souřadnice v textovém poli musíme použít „přetypování“ hodnoty na „textový“ typ String (protože souřadnice sama o sobě je „číselného“ typu Number. Příklad s omezujícím obdélníkem a zobrazením souřadnic najdete zde - drag-souradnice.zip.

Využití podmínky k omezení pohybu taženého objektu

Vzpomeňme si na předchozí lekci, kde jsme u kalkulačky využívali vyhodnocování podmínky pomocí příkazu if k výběru matematické operace. Abychom si podmínky lépe procvičili, pojďme zkusit naprogramovat chování „omezujícího obdélníku“ u funkce startDrag jako v příkladu výše pouze pomocí podmínek. Logika bude jednoduchá - pokud aktuální pozice kurzoru myši bude mimo rozměry plochy, zavoláme funkci stopDrag, která tažení ukončí a tím se objekt zastaví na hranici plochy. Pokud se kurzor vrátí do rozměrů plochy, zavoláme startDrag a objekt začne opět sledovat kurzor. V reálu na toto budeme potřebovat 4 podmínky - 2 kontroly x-ové souřadnice (je x větší než šířka plochy nebo menší než 0?) a rovněž 2 kontroly y-ové souřadnice (je y větší než výška plochy nebo menší než 0?). Pokud rozepíšeme podmínky jednotlivě, vypdaly by takto:

mouseX>stage.stageWidth
mouseX<0
mouseY>stage.stageHeight
mouseY<0

Mohli bysme vyhodnocovat podmínky jednotlivě a mít tak 4 příkazy if, ale vzhledem k tomu, že k zastavení tahání stačí, aby byla splněná jediná z podmínek, můžeme je zkombinovat dohromady pomocí logické funkce OR (anglicky „nebo“) - ta se chová tak, že je-li splněna jedna (či více) z podmínek spojených OR, pak je splněna celá podmínka. OR se v ActionScriptu zapíše jako || a spojení 4 podmínek bude vypadat takto (každá jednotlivá podmínka musí být v závorkách a stejně tak celá 4-kombinace musí být v závorkách):

if ((mouseX>stage.stageWidth) || (mouseX<0) || (mouseY>stage.stageHeight) || (mouseY<0))

Mohli bysme na podmínku také nahlížet opačně, a to tak, že x musí být vždy menší (nebo rovno) než šířka plochy a větší (nebo rovno) než 0 a stejně tak y musí být menší (nebo rovno) výšce plochy a větší (nebo rovno) než 0 - při této formulaci musí být všechny 4 podmínky splněny zároveň a to odpovídá spojení logickou funkcí AND („a současně“) - ta se chová tak, že podmínka jako celek je splněna pouze tehdy, pokud jsou zároveň splněny všechny jednotlivé podmínky. Operátor AND se v ActionScriptu zapíše && a podmínka by vypadala takto:

if ((mouseX<=stage.stageWidth) && (mouseX>=0) && (mouseY<=stage.stageHeight) && (mouseY>=0))

Pokračujme dál s podmínkou OR (ActionScript s ní bude mít o trochu méně práce) - abychom zajistili, že podmímka bude vyhodnocována průběžně, vložíme ji dovnitř událostní procedury na ENTER_FRAME a uděláme ještě jednu malou úpravu - uložíme si hodnoty stageWidth a stageHeight do číselných proměnných (typu int - integer, celé číslo) hned na začátku programu (v momentě, kdy např. maximalizujete okno Flashe, se toiž hodnoty stageWidth a stageHeight změní):

var w:int=stage.stageWidth;
var h:int=stage.stageHeight;

V podmínce tedy místo šířky plátna dosadíme pouze proměnnou w a místo výšky h. V případě, že podmínka bude splněna (tj. kurzor opustil výchozí plochu Flashe v kterémkoliv směru - vlevo, nahoru, vpravo nebo dolů), tahání objektu se zastaví funkcí stopDrag - v opačném případě (nacházíme se uvnitř plochy), se vykoná část else, v níž se zavolá funkce startDrag - tj. objekt sleduje kurzor myši:

this.addEventListener(Event.ENTER_FRAME, function (e) {
	if ((mouseX>w) || (mouseY>h) || (mouseX<0) || (mouseY<0))	//jsme mimo plochu?
		{petiuhelnik.stopDrag();}					//pokud ano, prestan tahat 
	else
		{petiuhelnik.startDrag(true);}				//pokud ne, tahej za stred
})

Poznámka - stage.stageWidth a stage.stageHeight nevracejí vždy přesné rozměry plochy (kromě toho, že se změní, pokud jsme roztáhli okno Flashe). Zdá se, že přesnou hodnotu vrátí příkazy loaderInfo.width a loaderInfo.height, ale ty jsou problematické zas z toho důvodu, že movie klip musí být plně nahrán, dřív než se začnem ptát na jejich hodnotu. Funkční příklad je uložen zde - drag-podminky.zip.

Příklad s mouchou a plácačkou

Na závěř si pojďme zkusit detekovat kliknutí tahaným objektem na nějaký jiný pohybující se objekt - předpokládejme, že náš tahaný objekt je plácačka na mouchy a máme nějakou jednoduchou animaci letu mouchy v podobě tweenu po dráze. Moucha samotná je movie-clipem, který má v časové ose 2 „stavy“ označené pojmenovanými snímky - např. „klid“ a „krev“ (které odrážejí podobu mouchy v klidu a při zásahu plácačkou).

Na začátku nahradíme kurzor symbolem plácačky a zastavíme mouchu na snímku „klid“:

placacka.startDrag(true); //tahej za stred
Mouse.hide(); //schovej kurzor
let.moucha.gotoAndStop("klid"); //klidova podoba mouchy

Povšimneme si, že symbol mouchy je vložen v tweenu, který je instancí symbolu pojmenovanou „let“ - chceme-li tedy adresovat časovou osu mouchy, musíme uvést i jejího „rodiče“, aby gotoAndStop zastavilo mouchu na správném snímku (kdyby ovšem moucha měla např. animovaný pohyb křídel, pak bysme tuto stopku nepotřebovali).

Stejným způsobem přidáme mouše posluchače na kliknutí:

let.moucha.addEventListener(MouseEvent.CLICK, zabijMouchu)

A v událostní proceduře zastavíme jak tween (let), tak přesuneme mouchu na snímek s její destrukcí:

function zabijMouchu(e) {
	let.stop(); //zastav tween
	let.moucha.gotoAndStop("krev"); //ukaz snimek krev
}

Kdyby byla destrukce animovaná, použili bychom samozřejmě gotoAndPlay místo gotoAndStop.

Zde je funkční příklad - placacka-moucha.zip.

vyuka/tahani_objektu_-_startdrag_a_stopdrag.txt · Poslední úprava: 2010/12/06 00:17 autor: kripi