Sprite- és szöveghatások

Árnyék, körvonal, izzás és elmosás 2D sprite-okon és szövegen, azzal, hogy mindegyik mennyibe kerül, mit tesz egy mozgó sprite-tal, és milyen kézzel összerakott receptet vált ki.

Mire ez való#

Eddig egy 2D sprite hordozhatott egy színezést és egy képet, és semmi mást. Ahhoz, hogy egy karaktert leemelj a hátteréről, kézzel kellett felépíteni a hatást: létrehozni egy második sprite-ot, feketére színezni, eltolni, mögé tenni, és minden egyes képkockán lépést tartani vele az elsővel. Működik. Ez emellett négy extra sor könyvelés karakterenként, és aznap, amikor elfelejted az egyiket, az árnyék a gazdája mögött vánszorog.

Négy parancs elvégzi ezt helyetted, sprite-okon és szövegen:

hero = LoadSprite("hero.png")
SpritePosition(hero, 160, 120)

SpriteShadow(hero, 4, 4, 6, 128)        ' offset x, offset y, softness, opacity
SpriteOutline(hero, 2, 255, 255, 255)   ' thickness, colour
SpriteGlow(hero, 0, 240, 255, 8)        ' colour, size

DO
  Sync()
LOOP

Semmi mást nem kell karbantartani. Mozgasd a sprite-ot, méretezd, tükrözd, játszd le az animációját: a hatások követik.

A négy hatás#

Árnyék#

SpriteShadow(spriteID, offsetX, offsetY, softness, opacity)
SpriteShadowColor(spriteID, red, green, blue)

Az offsetX és az offsetY a saját képernyőegységeidben van, ugyanúgy számolva, mint a SpritePosition: a pozitív Y lefelé van. A softness szétteríti az árnyékot; az opacity 0-tól 255-ig fut. A szín fekete, hacsak mást nem mondasz.

SpriteShadow(hero, 3, 5, 4, 110)
SpriteShadowColor(hero, 20, 0, 40)      ' a cold shadow, not a grey one

Egy 0 átlátszatlanságú árnyék nem árnyék. Így kapcsolod ki.

Körvonal#

SpriteOutline(spriteID, thickness, red, green, blue)

A körvonal a sprite sziluettjét követi, nem a téglalapot, amelyben él: egy átlátszó PNG körvonalat kap a rajz körül, nem a fájl körül. A vastagság képernyőegységben van, és 1 és 3 között van a hasznos tartomány. Efölött az a nyolc irány, amelyekből a körvonal épül, nyolc lebenyként kezd látszani.

SpriteOutline(hero, 2, 255, 255, 255)   ' the readable-on-anything outline
SpriteOutline(hero, 0, 0, 0, 0)         ' off

Izzás#

SpriteGlow(spriteID, red, green, blue, size)

Egy színes glória, amely size egységgel terjed túl a sziluetten. A sprite mögött és az árnyék előtt ül, ami lehetővé teszi, hogy mindkettőt használd.

SpriteGlow(pickup, 255, 210, 0, 10)     ' this one is worth walking to

Elmosás#

SpriteBlur(spriteID, radius)

Az elmosás a kakukktojás. A másik három a sprite körül rajzolódik; az elmosás a sprite saját képét cseréli le annak elmosott másolatára. Ez két dolgot jelent, amit érdemes tudni:

  • semmibe nem kerül képkockánként (az elmosott kép egyszer számolódik ki), és
  • az elmosás a kép szélénél levágódik. Egy rajz, amely hozzáér a saját PNG-je széléhez, elveszíti a glóriájának azt a részét, amely a képen kívülre esne. Hagyj néhány átlátszó pixel margót a fájlban, ha elmosásra tervezed.

A SpriteColor tovább működik egy elmosott sprite-on.

Minden kikapcsolása, és visszakapcsolása#

SpriteEffects(spriteID, 0)   ' all four off
SpriteEffects(spriteID, 1)   ' all four back, exactly as they were

A SpriteEffects nem törli a beállításaidat. Ez egy kapcsoló, nem egy visszaállítás, így egy karakter felvillanhat anélkül, hogy utána újra meg kellene adnod az árnyékát.

Ugyanaz a négy szövegen#

score = CreateText("SCORE 0")
TextPositionSet(score, 10, 10)
TextSizeSet(score, 6)

TextOutline(score, 3, 0, 0, 0)          ' readable on any background
TextShadow(score, 2, 2, 4, 160)
TextGlow(score, 255, 80, 0, 6)
TextBlur(score, 0)
TextEffects(score, 1)

A szignatúrák pontosan megegyeznek a sprite-osokkal, így nincs semmi új tanulnivaló. Két viselkedésbeli különbség:

  • Egy izzás felülír egy árnyék lágyságát. Mindkettőt ugyanaz a gépezet rajzolja, és egy izzás lágyság nélkül láthatatlan, míg egy árnyék lágyság nélkül még mindig árnyék. Ha mindkettőt kéred, az izzás kapja a lágyságot.
  • Ezek vektoros szövegre vonatkoznak, nem bitmap-betűtípusú szövegre. Egy TextFontImage-dzsel rajzolt szöveg sprite-ok összeállítása; a parancsok csendben figyelmen kívül maradnak rajta. Ilyenkor használd a sprite-hatásokat a benne lévő sprite-okon.

Egy kidolgozott példa: olvasható bármin#

Az a probléma, amit ezek a parancsok valójában megoldanak, az a kontraszt, amit nem irányítasz. Egy fehér pontszám láthatatlan a havon; egy fekete láthatatlan éjjel. Egy körvonal egyszer és mindenkorra megoldja, minden háttérre, amit valaha rajzolni fogsz.

CreateText(1, "SCORE 0")
TextPositionSet(1, 10, 10)
TextSizeSet(1, 8)
TextColorSet(1, 255, 255, 255, 255)
TextOutline(1, 3, 0, 0, 0)

hero = LoadSprite("hero.png")
SpriteName(hero, "hero")
SpriteShadow(hero, 4, 6, 5, 120)
SpriteOutline(hero, 2, 255, 255, 255)

points = 0
DO
  points = points + 1
  TextString(1, "SCORE " + Str(points))
  Sync()
LOOP

Egy hatás visszaolvasása#

Minden paraméternek, amit írsz, van egy olvasója, ahogy a SpriteColor-nak van SpriteColorRed-je. Ez a nyelvjárás szabálya, és ezek a parancsok követik.

IF SpriteEffectsEnabled(hero) = 1
  SpriteEffects(hero, 0)
ENDIF

alpha = SpriteShadowAlpha(hero)      ' 0 to 255
size  = SpriteGlowSize(hero)         ' 0 means no glow

A teljes készlet, családonként: SpriteShadowOffsetX, SpriteShadowOffsetY, SpriteShadowBlur, SpriteShadowAlpha, SpriteShadowColorRed, SpriteShadowColorGreen, SpriteShadowColorBlue, SpriteGlowRed, SpriteGlowGreen, SpriteGlowBlue, SpriteGlowSize, SpriteOutlineThickness, SpriteOutlineRed, SpriteOutlineGreen, SpriteOutlineBlue, SpriteBlurRadius, SpriteEffectsEnabled, plusz ugyanez a tizenhét, Text előtaggal.

Két szabály, amit érdemes tudni:

  • Egy sprite, amely sosem kapott hatást, magát BE-ként jelenti. Ez az alapállapot; a 0 válasz azt mondaná egy programnak, hogy a hatásai le vannak tiltva, mielőtt egyet is beállított volna.
  • Egy nem létező sprite-ról kérdezni 0-t válaszol, nem állítja meg a programot. Így kezeli a nyelvjárás a kérdéseket mindenhol: a SpriteHit 0-t válaszol, amikor semmi nem érintkezik, és a programok olvassák azt a 0-t anélkül, hogy tesztelnék.

Mibe kerül#

Az árnyék, a körvonal és az izzás rajzolva van, így draw call-okba kerül: egy az árnyékhoz (három, amikor lágy), négy egy izzáshoz, nyolc egy körvonalhoz. Egy képernyő kétszáz körvonalazott sprite-tal ezernyolcszáz quadot rajzol, és ez látszani fog. Azoknak a maroknyi dolognak valók, amit a játékosnak nézni kell: a karakter, a felszedhető tárgy, a kijelölt egység.

Az elmosás semmibe nem kerül képkockánként.

Egy gyakorlati szabály: hatások arra, ami mozog és számít, semmi a háttérre.

Ami átkerül egy exportált játékba#

CélÁrnyék, körvonal, izzásElmosásSzöveghatások
A szerkesztőigenigenigen
HTML5 exportigenigenigen
Natív és wasm (Bevy)igennemnem

Az árnyék, a körvonal és az izzás közönséges sprite-okból épül fel, így mindenhová eljutnak, ahová a sprite-ok. Az elmosásnak és a szöveghatásoknak egy hídra van szükségük, amivel a Bevy célok még nem rendelkeznek: az export konverziós jelentése megnevezi őket, ahelyett hogy csendben elhagyná őket, így egy build megmondja, mit nem tudott magával vinni.

Ahol a hatások nincsenek#

Nincs SpriteEffect(id, "glow", ...), amely a hatás nevét stringként venné át. Minden hatás a saját parancsa, hogy a paraméterei elnevezhetők, dokumentálhatók és gépelés közben kiegészíthetők legyenek. Bármi ezen a négyen túl, két másik parancs veszi át a helyet: SpriteBlendModes(id, src, dst) az additív vagy szorzott keveréshez (egy tűz, egy lézer), és SpriteShader(id, shaderID), hogy a LoadSpriteShader által fordított shadert tegyen egy sprite-ra. Mindkettő sokáig szerepelt a katalógusban implementáció nélkül, és a meghívásuk hibát okozott; most már működnek.