I już połowa maja minęła, czas biegnie nieubłaganie, a ja akurat mam teraz milion rzeczy na głowie. Broni jednak nie składam i pokażę dziś jak zbudowałem sobie tarczę i jak rozwiązałem problem punktacji.
Do tej pory moim celem była encja kuli zawieszona w przestrzeni, animująca się z lewej do prawej i na odwrót. Animacje chciałbym zachować, natomiast kule muszę zastąpić jakimś sensownym obiektem, który chociaż trochę będzie przypominał normalną tarczę strzelniczą. Cel będzie grupą encji i będzie się składał z następujących elementów:
- Belka służąca jako „taśma” po której będzie poruszała się tarcza
- Belka „zwisająca” z taśmy, służąca do trzymania tarczy
- Białe płótno w postaci cienkiego prostopadłościanu imitujące ciało
- Białe płótno w postaci okręgu imitujące głowę
- Pierścienie z różnych kolorów szarości imitujące wartości na tarczy i umiejscowione na płótnach
I teraz w kolejności powyższe elementy będą w kodzie wyglądały następująco:
1. Taśma:
<Entity primitive="a-box" color="#575757" depth="1" height="0.5" width="25" position="0 4.75 -8"> </Entity>
Belka górna to po prostu prostopadłościan zbudowany z pomocą encji <a-box>. Oprócz swojej wizualnej funkcji, będzie również spełniał rolę kontenera dla pozostałych encji. Pozycjonowanie elementów wewnętrznych odbywać się zatem będzie względem pozycji tej belki, nie względem środka sceny.
2. Encja animacyjna i belka dla tarczy:
<Entity position="10 -1.6 0" animation={{
property: "position",
dir: "alternate",
dur: 4000,
easing: "easeInOutCubic",
loop: true,
to: "-10 -1.6 0"
}}></Entity>Powyższa encja nie ma żadnej geometrii poza pozycją, wyróżnia ją jednak komponent animacyjny. To właśnie ta encja przejmie animację po starym prototypie tarczy i również będzie grupą dla wewnętrznych obiektów. Dzięki temu będą się one poruszały wszystkie razem, nie trzeba będzie animować ich osobno (to nawet brzmi absurdalnie). Belka pionowa to z kolei taki prosty obiekt:
<Entity primitive="a-box" color="#333333" depth="0.1" height="2.5" width="0.2"></Entity> <Entity primitive="a-sphere" radius="0.4" color="#333333" position="0 1.5 0"></Entity>
Oprócz obiektu typu a-box, pojawia się tu też a-sphere, która „symuluje” uchwyt belki pionowej do poziomej. Taki tam smaczek graficzny ha!
3. Płótno główne tarczy:
<Entity primitive="a-box" color="#fafafa" depth="0.02" height="1.66" width="1.38" position="0 -0.9 0.08"></Entity>
I kolejny a-box. Tym razem będzie to właściwy element tarczy i przy okazji grupa dla pierścieni punktacyjnych.
4. Płótno imitujące głowę sylwetki na tarczy:
<Entity primitive="a-circle" radius="0.4" color="#fafafa" position="0 1.15 0"> </Entity>
Tym razem użyłem encji <a-circle>, rysuje ona proste dwuwymiarowe koło na scenie. Encja ta została umieszczona wewnątrz encji sylwetki.
5. Pierścienie punktacyjne:
<Entity events={{
click: () => {
console.log("25");
}
}} primitive="a-ring" color="#666" radius-inner="0.19" radius-outer="0.3" position="0 0 0.04"></Entity>
<Entity events={{
click: () => {
console.log("50");
}
}} primitive="a-circle" radius="0.08" color="#222" position="0 0 0.04"></Entity>Powyższe dwie encje umieszczone zostały w elemencie głowy. Pierścień zewnętrzny zbudowany z pomocą <a-ring>, który wypisuje na konsoli 25 przy kliknięciu w niego, oraz koło, które po kliknięciu wypisuje 50. Te liczby to oczywiście punktacja. Podobną rzecz wykonuję dla encji sylwetki:
<Entity primitive="a-circle" radius="0.6" color="#ccc" position="0 0 0.04">
<Entity events={{
click: () => {
console.log("5");
}
}} primitive="a-ring" color="#666" radius-inner="0.36" radius-outer="0.46" position="0 0 0.04"></Entity>
<Entity events={{
click: () => {
console.log("15");
}
}} primitive="a-ring" color="#444" radius-inner="0.19" radius-outer="0.26" position="0 0 0.04"></Entity>
<Entity events={{
click: () => {
console.log("30");
}
}} primitive="a-circle" radius="0.1" color="#222" position="0 0 0.04"></Entity>
</Entity>W powyższym przykładzie znajdują się dwa pierścienie z punktami 5 i 15, oraz środek sylwetki: koło z 30 punktami za strzał. I to by było na tyle jeżeli chodzi o tarczę! No dobrze, może nie do końca, bo przecież nikt nie chce patrzeć w konsole czy trafił. Zarządzaniem punktacją zajmę się w kolejnym wpisie.
Można się zastanawiać jak długo wybierałem wartości dla chociażby pozycji elementów. Otóż z A-Frame jest to bardzo proste, ponieważ dysponuje on wbudowanym A-Frame inspectorem. Za pomocą tego narzędzia można wizualnie przenosić obiekty encji w trzech płaszczyznach, zmieniać właściwości obiektów, a nawet dogrywać komponenty z A-Frame register. O to jak prezentuje się kawałek mojej sceny w A-Frame inspectorze:
A tak prezentuje się cały kod elementu tarczy:
import { Entity } from "aframe-react";
import React from "react";
const TargetComponent = () => (
<Entity primitive="a-box" color="#575757" depth="1" height="0.5" width="25" position="0 4.75 -8">
<Entity position="10 -1.6 0" animation={{
property: "position",
dir: "alternate",
dur: 4000,
easing: "easeInOutCubic",
loop: true,
to: "-10 -1.6 0"
}}>
<Entity primitive="a-box" color="#333333" depth="0.1" height="2.5" width="0.2"></Entity>
<Entity primitive="a-sphere" radius="0.4" color="#333333" position="0 1.5 0"></Entity>
<Entity primitive="a-box" color="#fafafa" depth="0.02" height="1.66" width="1.38" position="0 -0.9 0.08">
<Entity primitive="a-circle" radius="0.4" color="#fafafa" position="0 1.15 0">
<Entity events={{
click: () => {
console.log("25");
}
}} primitive="a-ring" color="#666" radius-inner="0.19" radius-outer="0.3" position="0 0 0.04"></Entity>
<Entity events={{
click: () => {
console.log("50");
}
}} primitive="a-circle" radius="0.08" color="#222" position="0 0 0.04"></Entity>
</Entity>
<Entity primitive="a-circle" radius="0.6" color="#ccc" position="0 0 0.04">
<Entity events={{
click: () => {
console.log("5");
}
}} primitive="a-ring" color="#666" radius-inner="0.36" radius-outer="0.46" position="0 0 0.04"></Entity>
<Entity events={{
click: () => {
console.log("15");
}
}} primitive="a-ring" color="#444" radius-inner="0.19" radius-outer="0.26" position="0 0 0.04"></Entity>
<Entity events={{
click: () => {
console.log("30");
}
}} primitive="a-circle" radius="0.1" color="#222" position="0 0 0.04"></Entity>
</Entity>
</Entity>
</Entity>
</Entity>
);
export default TargetComponent;Podsumowanie
Wpis nieco skromniejszy niż zwykle, ale mam już najważniejszy element na scenie. W kolejnym kroku zajmę się stanem gry i uzupełnieniem sceny o dodatkowe elementy.