Sprite- en teksteffecten
Schaduw, contour, gloed en vervaging op 2D-sprites en op tekst, met wat elk kost, wat het doet met een bewegende sprite, en het handgebouwde recept dat het vervangt.
Waar dit voor dient#
Tot nu toe kon een 2D-sprite een tint en een afbeelding dragen, en verder niets. Om een personage van zijn achtergrond te laten loskomen, moest u het effect met de hand bouwen: een tweede sprite maken, hem zwart tinten, hem verschuiven, hem erachter zetten, en hem elke afzonderlijke frame in de pas houden met de eerste. Het werkt. Het is ook vier extra regels boekhouding per personage, en de dag dat u er één vergeet, sleept de schaduw achter zijn eigenaar aan.
Vier commando's doen dat voor u, op sprites en op tekst:
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
Verder niets te onderhouden. Verplaats de sprite, schaal hem, spiegel hem, speel zijn animatie af: de effecten volgen mee.
De vier effecten#
Schaduw#
SpriteShadow(spriteID, offsetX, offsetY, softness, opacity)
SpriteShadowColor(spriteID, red, green, blue)
offsetX en offsetY staan in uw eigen schermeenheden, geteld op
dezelfde manier als SpritePosition: positieve Y is omlaag.
softness verspreidt de schaduw; opacity loopt van 0 tot 255. De kleur
is zwart tenzij u anders zegt.
SpriteShadow(hero, 3, 5, 4, 110)
SpriteShadowColor(hero, 20, 0, 40) ' a cold shadow, not a grey one
Een schaduw met dekking 0 is geen schaduw. Zo schakelt u hem uit.
Contour#
SpriteOutline(spriteID, thickness, red, green, blue)
De contour volgt het silhouet van de sprite, niet de rechthoek waarin hij leeft: een transparante PNG krijgt een contour rond de tekening, niet rond het bestand. Dikte staat in schermeenheden, en 1 tot 3 is het bruikbare bereik. Erboven beginnen de acht richtingen waaruit de contour is opgebouwd zich te tonen als acht kwabben.
SpriteOutline(hero, 2, 255, 255, 255) ' the readable-on-anything outline
SpriteOutline(hero, 0, 0, 0, 0) ' off
Gloed#
SpriteGlow(spriteID, red, green, blue, size)
Een gekleurde halo, die zich size eenheden voorbij het silhouet
verspreidt. Ze zit achter de sprite en voor de schaduw, wat het mogelijk
maakt allebei te gebruiken.
SpriteGlow(pickup, 255, 210, 0, 10) ' this one is worth walking to
Vervaging#
SpriteBlur(spriteID, radius)
Vervaging is de uitzondering. De andere drie worden rond de sprite getekend; vervaging vervangt de eigen afbeelding van de sprite door een vervaagde kopie ervan. Dat betekent twee dingen die het weten waard zijn:
- ze kost niets per frame (de vervaagde afbeelding wordt eenmalig berekend), en
- de vervaging wordt afgesneden aan de rand van de afbeelding. Een tekening die de rand van zijn PNG raakt, verliest het deel van zijn halo dat buiten zou vallen. Laat een paar transparante pixels marge in het bestand als u van plan bent het te vervagen.
SpriteColor blijft werken op een vervaagde sprite.
Alles uit- en weer aanzetten#
SpriteEffects(spriteID, 0) ' all four off
SpriteEffects(spriteID, 1) ' all four back, exactly as they were
SpriteEffects wist uw instellingen niet. Het is een schakelaar, geen
reset, zodat een personage kan opflitsen zonder dat u zijn schaduw
achteraf opnieuw hoeft te declareren.
Dezelfde vier op tekst#
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)
De signaturen komen exact overeen met die van de sprites, dus er is niets nieuws te leren. Twee verschillen in gedrag:
- Een gloed wint van de zachtheid van een schaduw. Beide worden door hetzelfde mechanisme getekend, en een gloed zonder zachtheid is onzichtbaar, terwijl een schaduw zonder zachtheid nog altijd een schaduw is. Als u om allebei vraagt, krijgt de gloed de zachtheid.
- Deze gelden voor vectortekst, niet voor bitmap-lettertype-tekst.
Tekst getekend met
TextFontImageis een compositie van sprites; de commando's worden er stilzwijgend op genegeerd. Gebruik in dat geval de spriteeffecten op de sprites.
Een uitgewerkt voorbeeld: leesbaar op alles#
Het probleem dat deze commando's echt oplossen, is contrast dat u niet controleert. Een witte score is onzichtbaar op sneeuw; een zwarte is onzichtbaar in de nacht. Een contour lost het eenmalig op, voor elke achtergrond die u ooit zult tekenen.
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
Een effect teruglezen#
Elke parameter die u schrijft, heeft een lezer, zoals SpriteColor
SpriteColorRed heeft. Dat is de regel van het dialect, en deze
commando's volgen ze.
IF SpriteEffectsEnabled(hero) = 1
SpriteEffects(hero, 0)
ENDIF
alpha = SpriteShadowAlpha(hero) ' 0 to 255
size = SpriteGlowSize(hero) ' 0 means no glow
De volledige set, per familie: SpriteShadowOffsetX, SpriteShadowOffsetY,
SpriteShadowBlur, SpriteShadowAlpha, SpriteShadowColorRed,
SpriteShadowColorGreen, SpriteShadowColorBlue, SpriteGlowRed,
SpriteGlowGreen, SpriteGlowBlue, SpriteGlowSize,
SpriteOutlineThickness, SpriteOutlineRed, SpriteOutlineGreen,
SpriteOutlineBlue, SpriteBlurRadius, SpriteEffectsEnabled, plus
dezelfde zeventien met een Text-voorvoegsel.
Twee regels die het weten waard zijn:
- Een sprite die nooit een effect heeft gekregen, meldt zichzelf als AAN. Dat is de standaardstatus; 0 antwoorden zou een programma vertellen dat zijn effecten uitgeschakeld zijn voordat het er ook maar één heeft ingesteld.
- Vragen naar een sprite die niet bestaat, antwoordt 0, het stopt het
programma niet. Zo behandelt het dialect vragen overal:
SpriteHitantwoordt 0 wanneer niets wordt geraakt, en programma's lezen die 0 zonder ze te testen.
Wat het kost#
Schaduw, contour en gloed worden getekend, dus ze kosten draw calls: één voor de schaduw (drie wanneer ze zacht is), vier voor een gloed, acht voor een contour. Een scherm met tweehonderd omlijnde sprites is een scherm dat achttienhonderd quads tekent, en dat zal te zien zijn. Ze zijn bedoeld voor het handjevol dingen waar de speler naar zou moeten kijken: het personage, het oppakbare voorwerp, de geselecteerde eenheid.
Vervaging kost niets per frame.
Een praktische regel: effecten op wat beweegt en ertoe doet, geen op de achtergrond.
Wat een geëxporteerde game overleeft#
| Doel | Schaduw, contour, gloed | Vervaging | Teksteffecten |
|---|---|---|---|
| De editor | ja | ja | ja |
| HTML5-export | ja | ja | ja |
| Native en wasm (Bevy) | ja | nee | nee |
Schaduw, contour en gloed zijn opgebouwd uit gewone sprites, dus ze reizen overal waar sprites reizen. Vervaging en de teksteffecten hebben een brug nodig die de Bevy-doelen nog niet hebben: het exportconversierapport noemt ze bij naam in plaats van ze stilzwijgend te laten vallen, zodat een build u vertelt wat het niet kon meedragen.
Waar de effecten niet zijn#
Er is geen SpriteEffect(id, "glow", ...) die de effectnaam als string
aanneemt. Elk effect is zijn eigen commando, zodat de parameters ervan
benoemd, gedocumenteerd en aangevuld kunnen worden terwijl u typt. Voor
alles voorbij deze vier nemen twee andere commando's het over:
SpriteBlendModes(id, src, dst) voor additieve of vermenigvuldigde
blending (een vuur, een laser), en SpriteShader(id, shaderID) om een
shader gecompileerd door LoadSpriteShader op een sprite te plaatsen.
Beide werden lange tijd in de catalogus vermeld zonder implementatie, en
ze aanroepen gaf een fout; nu werken ze.