Autor Zpráva
petr
Profil *
Dobrý den, mám takový problém. Potřeboval bych otočit s rodičovským divem (transform: rotate(xxdeg)), ale zároveň, aby byl vnořený div skrytý v rodičovském divu. Myslel jsem si, že to udělám nějak takhle:
...
<style>
.rodDiv {
  position: absolute;
  transform: rotate(20deg);
  ...
}
.vnorenyDiv {
  position: relative;
  background-color: #00AA00;
  z-index: -1;
  ...
}
</style>
<div class="rodDiv">
    <div class="vnorenyDiv"></div>
</div>
Hodnota transform: rotate může být klidně i 0deg, z-index to stejně zruší. Stačí ale jen zakomentovat řádku transform a nastane napůl očekávaný výsledek.
Živá ukázka: Živá ukázka

Očekávaný výsledek:


Předem děkuji za odpověď.

Moderátor Chamurappi: Doplnil jsem do titulku později řešené nepříliš související téma a přemýšlím, že bych vlákno mohl rozdělit na dvě…
sitole
Profil
petr:
Ahoj, jde pravda, že jsem řešení celkem upravil, ale výsledek je stejný jako tvůj předpokládaný.
Tady tedy posílám kod. A zde jak stránka tak obrázek.
petr
Profil *
S tím přichází další problém. Já s rodičovským divem potřebuji točit libovolně (pomocí JavaScriptu), a jestliže se 2. div nenachází v 1., potřebuji buď:
• zjistit vztah mezi velikostmi otočení prvního a druhého divu pro jakékoliv hodnoty (přijde mi to hodně krkolomné a složité)
• nechat 2. div vnořený v prvním a vymyslet to jinak
Je mi jedno, jak se to vyřeší, ale chci, aby 2. div zůstal vždy veprostřed prvního (alespoň přibližně):

Věděl by někdo, jak na to?
sitole
Profil
petr:
Co zabalit celou rodinu do dalšího divu a otačet ním? Poté zústanou hodnoty stejné a budeš otáčet obojím.. :)
Případně sem prosím dej "otáčecí" script a já něco vykoumám.

Takovej rychlej komol, ale funguje :)
petr
Profil *
Není to nic moc složitého:
/* Dělám to pomocí jQuery: vrací CSS transform nějak takhle (pro 30°): "matrix(0.8660254037844387, 0.49999999999999994, -0.49999999999999994, 0.8660254037844387, 0, 0);" - funkce convertMatrix tedy převede tyto šílenosti na stupně :)*/
function convertMatrix(csstransform) {
  var values = csstransform.split('(')[1].split(')')[0].split(',');
  var angle = Math.round(Math.atan2(values[1], values[0]) * (180/Math.PI));
  return angle;
}
function otoc() {
  var uhel = convertMatrix($(".rodDiv").css("transform"));
  var newrotate = "rotate(" + ((uhel + 5) + "deg)";
  $("#rodDiv").css("transform", newrotate);
}

sitole:
Takovej rychlej komol, ale funguje :)
Ten tvůj „komol“ není tak špatný, ale už by možná stačilo jen přesunout bod otáčení. (možná pomocí transform-origin, ale nemám s tím žádné zkušenosti)


Děkuji mockrát za tvojí trpělivost. Už jsem na to přišel. Upravil jsem tvůj „komol“ a vzniklo z toho přesně to, co jsem si představoval: http://kod.djpw.cz/tsnb
Já si nad tím lámal hlavu nejméně 5 hodin, takže jsem moc rád, že jsi mi pomohl.
Chamurappi
Profil
Reaguji na petra:
funkce convertMatrix tedy převede tyto šílenosti na stupně :)
Brr. Proč jsi vůbec potřeboval číst hodnoty z CSS? Vždyť tam je jen to, co jsi tam sám nastavil, ne? Tak proč ji zase zpátky složitě zjišťovat, když ji můžeš mít trvale uloženou v nějaké proměnné.

vzniklo z toho přesně to, co jsem si představoval
Pokud prohodíš pořadí vnitřních <div>ů, nemusíš vůbec nastavovat z-index.
petr
Profil *
Chamurappi:
Proč jsi vůbec potřeboval číst hodnoty z CSS?
Až sem jsem se dostat nechtěl, ale pro vysvětlení tohoto dotazu jsem musel. Myslím si totiž, že na tohle bych měl založit nové téma (porušuji totiž tuhle větu: „Název diskuse prosím volte tak, aby vyjadřoval podstatu dotazu.“)
Je to ještě z jiného důvodu. Tohle celé potřebuji na takovou „hru“ s tankem, který se bude pohybovat pomocí kláves. Bude se moci otáčet celým tankem i hlavní. Tank tedy logicky musí jet „dopředu“ přesně po přímce, kam je natočen tank (na obrázku je tank natočen o 30°):

Neuvedl jsem tady poslední verzi své funkce convertMatrix, protože jsem se chtěl vyhnout složitému vysvětlování: (ale jak vidím, tak mě to neminulo :D)
function convertMatrix(csstransform) {
  var values = csstransform.split('(')[1].split(')')[0].split(',');
  var angle = Math.round(Math.atan2(values[1], values[0]) * (180/Math.PI));
  return { 
    uhel : angle,
    a : values[0],
    b : values[2]
  }
}
Přišel jsem na to, že 0. hodnota z toho matrixu(convertMatrix(csstransform).a) se vždy rovná tomu, co musím přičíst k poloze tanku na souřadnici x (prakticky k css vlastnosti left), a 2. hodnota(convertMatrix(csstransform).a) se rovná tomu, co musím přičíst k poloze na souřadnici y (k css vlastnosti bottom).

Dva příklady, kde je to jasné jako facka:

0° = "matrix(1, 0, 0, 1, 0, 0)" => a = 1; b = 0; => x += 1; y += 0;
Tohle je logické: přičítá se přece jen k souřadnici x => tank se pohybuje jen doprava
------------------------------------------------
90° = "matrix(0, 1, -1, 0, 0, 0)" => a = 0; b = -1; => x += 0; y += -1;
Zde se jen odečítá ze souřadnice y => tank se pohybuje jen svisle dolů

Jistěže by to šlo ještě tisíci způsoby, ale dokud ta můj způsob funguje, tak mi je tu nemusíte vypisovat.
Chamurappi:
Pokud prohodíš pořadí vnitřních <div>ů, nemusíš vůbec nastavovat z-index.
Ano, to vím také, ale původně byl „vnitřní“ jen jeden, tak jsem na to prostě zapomněl (a zabalit celou rodinu do dalšího divu mě nenapadlo). Uznej, že tohle prohodit nešlo (teoreticky ano, ale dělalo by to úplně něco jiného):
<!-- 1. div --><div class="rodDiv">
    <!-- 2. div --><div class="vnorenyDiv"></div>
</div>
Ještě nějaké připomínky (inteligentní, prosím :D)? Klidně pište, alespoň se něco dozvím. Celá hra: http://kod.djpw.cz/gtnb(ještě nemám vyřešené střílení, tak se nezlobte)
Chamurappi
Profil
Reaguji na petra:
Přišel jsem na to, že 0. hodnota z toho matrixu(convertMatrix(csstransform).a) se vždy rovná tomu, co musím přičíst k poloze tanku na souřadnici x
To bude kosinus úhlu.

a 2. hodnota(convertMatrix(csstransform).a) se rovná tomu, co musím přičíst k poloze na souřadnici y
To bude záporný sinus úhlu.

Smekám před tímto vynalézavým přístupem, ale skutečně je mnohem efektivnější a snazší pamatovat si úhel v proměnné a pak použít trochu té goniometrie. Poslal jsem tvoji ukázku jednomu známému a nefungovala mu, nejspíš proto, že jeho prohlížeč při getComputedStyle nevrací hodnotu transformu v takové podobě, jakou tvůj convertMatrix očekává. Tvé řešení je zbytečně křehké.

Celá hra
Jé, to je hezké :-)

1) Na posun tanku můžeš použít translate v transformu, mělo by to být pro prohlížeč snazší, než měnit left a top (nebo bottom, když máš zatím ten sinus záporný).
2) Nemusel bys zjišťovat $("#playground").width() a $("#tank1").width() při skoro každém pohybu, lze předpokládat, že to budou neměnné hodnoty.
3) tanks.pressedKeys nepotřebuje být pole, použil bych {} místo [].
4) Jak plánuješ řešit kolize při střílení? Nedoporučuji k tomu zneužívat HTML DOM (ve smyslu že by ses prohlížeče ptal, jaký element je na daném pixelu).
petr
Profil *
Chamurappi:
To bude kosinus úhlu.“, „To bude záporný sinus úhlu.
Pardon za mé hrůzostrašné technické názvosloví, ale člověk si nějak poradit musí :D

skutečně je mnohem efektivnější a snazší pamatovat si úhel v proměnné
Když jsem dělal jakousi fotogalerii (s obrázky pojmenovánými „x.png“), hádejte, jak mě napadlo zjistit aktuální snímek? No přece načíst si celou cestu obrázku (C://bla/bla/bla/bla/x.png), použít regulérní výraz na vyhledávání číslic a vypsat je. A když by cesta obsahovala nežádoucí číslice, tak je tam prostě zahrne. (C://123/456/789/21.png => 12345678921. obrázek) Teprve až pak mě napadlo, co si to takhle uložit do proměnné?

Tvé řešení je zbytečně křehké.
Omlouvám se, ale opravdu nevím, jak to vylepšit. Zase tolik zkušeností nemám (tohle je vlastně má první hra), ale budu rád za každou radu.

Na posun tanku můžeš použít translate v transformu
Ještě jsem o tom moc nečetl, ale napravím to.

Nemusel bys zjišťovat $("#playground").width() a $("#tank1").width()
To je pravda, jsem trochu blbej, no.

tanks.pressedKeys nepotřebuje být pole, použil bych {} místo [].
To mě vůbec nenapadlo, děkuji.

Jak plánuješ řešit kolize při střílení? Nedoporučuji k tomu zneužívat HTML DOM
Takhle daleko ještě nejsem, ale určitě bych HTML DOM použil (to už si můžeš všimnout, jak řeším to, aby se nevyjelo z herního pole :D). Opravdu nevím, jak to jinak udělat.

Každopádně moc děkuji za připomínky.
Chamurappi
Profil
Reaguji na petra:
Upravil jsem tvoji ukázku.
Kdybych se v tom šťoural déle, výsledek by se mi líbil více, ale asi bys mu pak hůř porozuměl. Takhle v tom snad aspoň zůstaly náznaky tvých postupů.

1) Zrušil jsem convertMatrix, hodnotu z transformu nikdy zpětně nečteme.
2) Úhel si budeme pamatovat v proměnné a na případné výpočet posunu při pohybu vpřed použijeme Math.sin a Math.cos (tyto funkce přijímají úhel v radiánech, takže pokud zůstáváme u stupňů, musíme dělat přepočet / 180 * Math.PI).
3) Při posunu tanku vpřed a vzad i při jeho otáčení nastavujeme transform na kombinaci translate + rotate, tato jedna vlastnost vyřeší umístění i otočení, absolutní pozicování nevyužíváme.
4) Velikost hracího pole se ukládá do objektu playground jednorázově na začátku.
5) Při posunu tanku vpřed či vzad se cílové souřadnice zaráží o okraje playgroundu – to mi přijde lepší, než při překročení stornovat pohyb úplně.

Takhle daleko ještě nejsem, ale určitě bych HTML DOM použil (to už si můžeš všimnout, jak řeším to, aby se nevyjelo z herního pole :D). Opravdu nevím, jak to jinak udělat.
Úplně nejjednodušší řešení by bylo představit si všechny objekty v hracím poli jako kruhy a střelu jako bod. Pak si spočítáš vzdálenost bodu od středu (každého) kruhu Pythagorovou větou a tím zjistíš, jestli je střela uvnitř objektu.
petr
Profil *
Tvá verze ukázky se mi moc líbí.

Chamurappi:
se cílové souřadnice zaráží o okraje playgroundu – to mi přijde lepší, než při překročení stornovat pohyb úplně.
Mám úplně stejný názor. A děláš to vlastně jednodušeji, než já. Zkrátka v jednoduchosti je krása.

na případné výpočet posunu při pohybu vpřed použijeme Math.sin a Math.cos
Tyto funkce jsem bohužel neznal, takže jsem to dělal jako blbec z nějakého matrixu :D

Kolize: „Úplně nejjednodušší řešení by bylo představit si všechny objekty v hracím poli jako kruhy a střelu jako bod. Pak si spočítáš vzdálenost bodu od středu (každého) kruhu Pythagorovou větou a tím zjistíš, jestli je střela uvnitř objektu.
Pochopil jsem to takhle, jestli jsi to tak myslel:

Udělal jsem to jen pro jeden objekt, ale jde mi jen o princip.
Takže vzdálenost mám vypočítat Pythagorovou větou, tedy

b = √c2-a2

Javascript:

var b = Math.sqrt(Math.pow(c, 2) - Math.pow(a, 2));

Jestliže bude b (vzdálenost) menší než r (poloměr objektu), tak se vyvolá akce „bum“ :D
Pochopil jsem to správně?

Jinak díky a oceňuji, že jsi se v tom vůbec „šťoural“.
Radek9
Profil
petr:
var b = Math.sqrt(Math.pow(c, 2) - Math.pow(a, 2));
Jestli mám správně v paměti Pythagorovu větu, tak by tam mělo být plus, ne minus. Možná jsi to popletl vzhledem k tomu, že právě přepona (u tebe b) bývá nejčastěji označována jako c.
Chamurappi
Profil
Reaguji na petra:
Pochopil jsem to správně?
Ano. Akorát Radek9 má samozřejmě pravdu s tím plusem, toho jsem si sám vůbec nevšiml :-)

Místo Math.pow(a, 2) bych napsal a * a, je to rychlejší na napsání i na vykonání.
A odmocňováním se také nemusíš zdržovat, pokud budeš místo s poloměrem pracovat rovnou s druhou mocninou poloměru. Tzn. když bys měl ve hře věž s poloměrem 20, budeš mít rovnou uloženo, že její velikost je 400 a pak budeš porovnávat tuto velikost s dx * dx + dy * dy (kde dx je rozdíl iksových souřadnic a dy rozdíl ypsilonových).
Keeehi
Profil
Další výhoda neodmocňování je ta, že počítače mají "problém"* s desetinnými čísly. Když budeš pracovat s celými čísly tak to bude o hodně jednodušší.

* ne že by počítače při měli problém s počítáním s desetinnými čísly avšak reprezentace desetinných čísel v binární soustavě v počítači není až tak jednoduchá jako reprezentace čísel celých. Dochází ke ztrátám přesnosti a to pak programátorům přináší problémy které musí řešit.
petr
Profil *
Už to zkouším zabudovat do hry, ale je tam takových chyb, že už nevím, např.:

1. Když je tank natočen mezi určitými stupni, střela letí za tank (a ne před tank).
2. Ke kolizím buď dochází moc brzy, nebo k nim nedochází vůbec.

Tomu prvnímu nerozumím, CSS translate by měl být závislý na #otochlav1, ne?
U toho druhého tuším, že ten program vidí můj objekt podle souřadnic zřejmě úplně jinde, než je.
Poradíte mi, prosím, jak dál?
Kryvosa
Profil *
Rozhodně bych <div> s class "bullet" při každém "výstřelu" vytvořil, a po nárazu do stěny (nebo do jiného tanku) odstranil. (Tuším přes document.createElement().) Jinak bys mohl mít jen jednu střelu. Taky by neměla být pod divem tanku, ale jen v playgroundu.

Být tebou, tak bych si asi vyrobil funkci createVector(), která by zařizovala pohyb nějakého DOM objektu. Její volání si představuji nějak takto:
//  createVector(DOM Objekt, rychlost px/s, azimut)
createVector(document.getElementsByClassName("bullet")[0], 20, 90)
sitole
Profil
petr:
Doporučuji také nastavit "výstřel" na pevné místo, kde byla vystřelena, protože poté se hýbe s tankem. :)
petr
Profil *
Kryvosa:
Taky by neměla být pod divem tanku
To mě taky napadlo, jenže přijde mi, že by to bylo moc komplikované. Když jsem například zkoušel držet střelu a hlaveň úplně odděleně a oběma přičítat stejné hodnoty transform: rotate, nedopadlo to moc dobře, protože mi v některých úhlech lezla střela mimo hlaveň. Jednak by se k transform: rotate muselo přičítat o trochu víc než k otočení hlavně, ale také by se muselo trochu „hýbat“ střelou absolutním pozicováním.

sitole:
Doporučuji také nastavit "výstřel" na pevné místo, kde byla vystřelena, protože poté se hýbe s tankem. :)
Kdyby byla střela jen v playgroundu, byl by tento problém vyřešen, ale už jsem zmínil, proč se do toho moc nevrhám po hlavě. :D

Děkuji za tyto připomínky, ale především chci vyřešit tu kolizi.
Kryvosa
Profil *
Ty mne neposloucháš :D
Vtip je v tom, že žádný div nebudeš mít předvytvořený, ale vždy si ho při výstřelu vytvoříš pomocí JS (To je ten createElement(), googlovat umíš :)). Takže si nikdo nevšimne, když vyletí o pixel vedle.
Krom toho by střela měla mít menší z-index, než celý tank.

Nejsem si jistý, pořádně tam ten tvůj výmysl nechápu, ale podle mne je chyba buď v tom, že uloženě souřadnice tvého kolizního divu nejsou správné, a nebo se vzdálenost střely počítá od tanku.
Kryvosa
Profil *
Nějak takhle si to představuji:
function fire(tank){
        var shot=document.createElement("div");
        shot.className="bullet"
        shot.style["webkitTransform"||"transform"]="translate("+(tank.x+20)+"px,"+(tank.y+13)+"px)";
        document.getElementById("playground").appendChild(shot);
}
Ps: Uprav si to, dělám to samé co ty, jen tak z legrace, a řeším to už předem pro několik tanků. Tady je moje verze :)
Chamurappi
Profil
Reaguji na Kryvosu:
shot.style["webkitTransform"||"transform"]=
Nevím, co si slibuješ od tohoto zvláštního zápisu. Řetězec "webkitTransform" je vždy pravdivý, proto nikdy žádný prohlížeč nepoužije "transform" – tímhle rozhodně netestuješ podporu CSS vlastnosti. Tvoje ukázka tím pádem funguje jen ve webkitech (a v mobilním Exploreru 11, ale tam stejně nejde tank ovládat).
Kryvosa
Profil *
Jejda, to mě nenapadlo, a nijak jsem to netestoval...
Má cenu zjišťovat podmínku, zdali prefix existuje, nebo je lepší nastylovat jak pro webkit, tak normálně?
petr
Profil *
Tvoje řešení jsem si upravil, ale pořád mám stejný problém jako předtím. Někdy kolize nefunguje vůbec, někdy funguje moc pozdě.
Kryvosa
Profil *
Mám aktualizaci i s kolizí: Tady mi to funguje normálně (řádek 87), akorát nemám vymyšlenou možnost více cílů. Asi bych to udělal přes smyčku for, která je bude procházet jeden po druhém.
petr
Profil *
Ta tvoje aktualizace bohužel funguje jen tak „na oko“. Když se podíváme zblízka, tak už to tak slavné není:

Kolize funguje jen v jedné čtvrtině. Cokoliv jinam nevyvolá kolizi.


EDIT: Promiň, trochu mě zmátly ty tvoje magická čísla. Funguje to dobře. Děkuju.

Vaše odpověď

Mohlo by se hodit

Neumíte-li správně určit příčinu chyby, vkládejte odkazy na živé ukázky.
Užíváte-li nějakou cizí knihovnu, ukažte odpovídajícím, kde jste ji vzali.

Užitečné odkazy:

Odkud se sem odkazuje


Prosím používejte diakritiku a interpunkci.

Ochrana proti spamu. Napište prosím číslo dvě-sta čtyřicet-sedm:

0