Sprite और text इफ़ेक्ट
2D sprite और text पर Shadow, outline, glow और blur, हर एक की क़ीमत, किसी चलते हुए sprite पर इसका असर, और वह हाथ से बनाई रेसिपी जिसे यह बदल देता है।
यह किसलिए है#
अब तक कोई 2D sprite एक tint और एक image रख सकता था, और बाक़ी कुछ नहीं। किसी कैरेक्टर को उसके बैकग्राउंड से उभारने के लिए आपको इफ़ेक्ट हाथ से बनाना पड़ता था: एक दूसरा sprite बनाएँ, उसे काला tint करें, उसे offset करें, उसे पीछे रखें, और हर एक फ़्रेम में उसे पहले वाले के साथ क़दम मिलाकर रखें। यह काम करता है। लेकिन यह हर कैरेक्टर के लिए बहीखाते की चार अतिरिक्त लाइनें भी हैं, और जिस दिन आप इनमें से एक भूल जाएँ, shadow अपने मालिक से पीछे रह जाता है।
चार कमांड यह काम आपके लिए कर देते हैं, sprite पर और text पर:
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
बाक़ी कुछ भी maintain नहीं करना। sprite को मूव करें, स्केल करें, फ़्लिप करें, इसकी animation चलाएँ: इफ़ेक्ट साथ चलते हैं।
चार इफ़ेक्ट#
Shadow#
SpriteShadow(spriteID, offsetX, offsetY, softness, opacity)
SpriteShadowColor(spriteID, red, green, blue)
offsetX और offsetY आपकी अपनी screen units में हैं, SpritePosition
जैसे ही गिने गए: positive Y नीचे है। softness shadow को फैलाता है;
opacity 0 से 255 तक चलता है। जब तक आप कुछ और न कहें, रंग काला होता है।
SpriteShadow(hero, 3, 5, 4, 110)
SpriteShadowColor(hero, 20, 0, 40) ' a cold shadow, not a grey one
opacity 0 वाला shadow कोई shadow नहीं है। इसे बंद करने का यही तरीक़ा है।
Outline#
SpriteOutline(spriteID, thickness, red, green, blue)
Outline sprite के उस रेक्टेंगल का नहीं, बल्कि उसकी silhouette का अनुसरण करती है जिसमें वह रहता है: किसी transparent PNG को ड्रॉइंग के चारों ओर outline मिलती है, फ़ाइल के चारों ओर नहीं। Thickness screen units में है, और 1 से 3 उपयोगी दायरा है। इससे ज़्यादा पर वे आठ दिशाएँ, जिनसे outline बनी है, आठ lobe के रूप में दिखने लगती हैं।
SpriteOutline(hero, 2, 255, 255, 255) ' the readable-on-anything outline
SpriteOutline(hero, 0, 0, 0, 0) ' off
Glow#
SpriteGlow(spriteID, red, green, blue, size)
एक रंगीन halo, जो silhouette से size units आगे तक फैलता है। यह sprite
के पीछे और shadow के आगे बैठता है, और यही आपको दोनों साथ इस्तेमाल करने
देता है।
SpriteGlow(pickup, 255, 210, 0, 10) ' this one is worth walking to
Blur#
SpriteBlur(spriteID, radius)
Blur बाक़ी तीनों से अलग है। बाक़ी तीन sprite के चारों ओर ड्रॉ होते हैं; blur sprite की अपनी image को उसकी एक धुंधली कॉपी से बदल देता है। इसका मतलब दो बातें हैं जो जानने लायक हैं:
- इसकी हर फ़्रेम कोई क़ीमत नहीं है (धुंधली image एक ही बार गिनी जाती है), और
- blur image के किनारे पर clip हो जाता है। कोई ड्रॉइंग जो अपने PNG के किनारे को छूती है, अपने halo का वह हिस्सा खो देती है जो बाहर पड़ता। अगर आप इसे blur करने की सोच रहे हैं तो फ़ाइल में transparent pixel का थोड़ा margin छोड़ दें।
किसी धुंधले sprite पर SpriteColor काम करता रहता है।
सब कुछ बंद, और फिर वापस चालू करना#
SpriteEffects(spriteID, 0) ' all four off
SpriteEffects(spriteID, 1) ' all four back, exactly as they were
SpriteEffects आपकी सेटिंग्स को मिटाता नहीं। यह एक switch है, कोई reset
नहीं, इसलिए कोई कैरेक्टर बाद में अपना shadow दोबारा declare किए बिना
flash कर सकता है।
Text पर वही चार#
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)
Signature ठीक sprite वालों से मेल खाते हैं, इसलिए सीखने के लिए कुछ नया नहीं है। व्यवहार में दो फ़र्क़:
- कोई glow shadow की softness पर भारी पड़ता है। दोनों एक ही मैकेनिज़्म से ड्रॉ होते हैं, और बिना softness वाला glow अदृश्य होता है जबकि बिना softness वाला shadow फिर भी एक shadow रहता है। जब आप दोनों माँगते हैं, तो softness glow को मिलती है।
- ये vector text पर लागू होते हैं, bitmap-font text पर नहीं।
TextFontImageसे बनाया गया text, sprite का एक कॉम्पोज़िशन होता है; इस पर कमांड चुपचाप नज़रअंदाज़ हो जाते हैं। ऐसे में sprite वाले इफ़ेक्ट, sprite पर इस्तेमाल करें।
एक हल किया हुआ उदाहरण: कहीं भी पढ़ने लायक#
ये कमांड असल में जिस समस्या को हल करते हैं वह है ऐसा contrast जिस पर आपका कोई नियंत्रण नहीं। कोई सफ़ेद score बर्फ़ पर अदृश्य है; कोई काला रात में अदृश्य है। एक outline इसे एक बार में हल कर देती है, हर उस बैकग्राउंड के लिए जिसे आप कभी भी ड्रॉ करेंगे।
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
किसी इफ़ेक्ट को वापस पढ़ना#
आप जो भी पैरामीटर लिखते हैं उसका एक reader होता है, ठीक वैसे ही जैसे
SpriteColor का SpriteColorRed है। यही डायलेक्ट का नियम है, और ये
कमांड इसी का पालन करते हैं।
IF SpriteEffectsEnabled(hero) = 1
SpriteEffects(hero, 0)
ENDIF
alpha = SpriteShadowAlpha(hero) ' 0 to 255
size = SpriteGlowSize(hero) ' 0 means no glow
पूरा सेट, हर family के लिए: SpriteShadowOffsetX, SpriteShadowOffsetY,
SpriteShadowBlur, SpriteShadowAlpha, SpriteShadowColorRed,
SpriteShadowColorGreen, SpriteShadowColorBlue, SpriteGlowRed,
SpriteGlowGreen, SpriteGlowBlue, SpriteGlowSize,
SpriteOutlineThickness, SpriteOutlineRed, SpriteOutlineGreen,
SpriteOutlineBlue, SpriteBlurRadius, SpriteEffectsEnabled, साथ ही
यही सत्रह Text prefix के साथ।
जानने लायक दो नियम:
- जिस sprite को कभी कोई इफ़ेक्ट नहीं दिया गया, वह ख़ुद को ON बताता है। यही डिफ़ॉल्ट स्थिति है; 0 का जवाब देने से किसी प्रोग्राम को यह लगेगा कि उसके इफ़ेक्ट किसी को सेट करने से पहले ही कट चुके हैं।
- किसी ऐसे sprite के बारे में पूछने पर 0 जवाब मिलता है, इससे प्रोग्राम
रुकता नहीं। डायलेक्ट हर जगह सवालों को इसी तरह लेता है: जब कुछ भी
छुआ नहीं जाता तो
SpriteHit0 जवाब देता है, और प्रोग्राम बिना जाँचे उस 0 को पढ़ लेते हैं।
इसकी क़ीमत क्या है#
Shadow, outline और glow ड्रॉ होते हैं, इसलिए इनकी draw call में क़ीमत लगती है: shadow के लिए एक (नरम होने पर तीन), glow के लिए चार, outline के लिए आठ। दो सौ outlined sprite वाली कोई स्क्रीन अठारह सौ quad ड्रॉ करने वाली स्क्रीन है, और यह दिखेगा। ये उन मुट्ठी भर चीज़ों के लिए हैं जिन्हें player को देखना है: कैरेक्टर, pickup, चुनी हुई यूनिट।
Blur की हर फ़्रेम कोई क़ीमत नहीं है।
एक व्यावहारिक नियम: इफ़ेक्ट उस पर जो चलता और मायने रखता है, बैकग्राउंड पर कोई नहीं।
एक्सपोर्ट किए गए गेम में क्या पार होता है#
| Target | Shadow, outline, glow | Blur | Text इफ़ेक्ट |
|---|---|---|---|
| Editor | हाँ | हाँ | हाँ |
| HTML5 export | हाँ | हाँ | हाँ |
| Native और wasm (Bevy) | हाँ | नहीं | नहीं |
Shadow, outline और glow सामान्य sprite से बने होते हैं, इसलिए ये वहीं जाते हैं जहाँ sprite जाते हैं। Blur और text इफ़ेक्ट को एक ऐसा bridge चाहिए जो Bevy targets के पास अभी नहीं है: export की conversion report इन्हें चुपचाप छोड़ने के बजाय नाम से बताती है, ताकि कोई build आपको बता सके कि वह क्या नहीं ले जा सका।
जहाँ ये इफ़ेक्ट नहीं हैं#
कोई SpriteEffect(id, "glow", ...) नहीं है जो इफ़ेक्ट का नाम किसी
string के रूप में ले। हर इफ़ेक्ट अपना ख़ुद का कमांड है ताकि इसके
पैरामीटर नाम दिए जा सकें, डॉक्यूमेंट किए जा सकें, और टाइप करते समय पूरे
किए जा सकें। इन चार से आगे किसी भी चीज़ के लिए, दो और कमांड संभाल लेते
हैं: additive या multiplied blending के लिए (कोई आग, कोई लेज़र)
SpriteBlendModes(id, src, dst), और किसी sprite पर LoadSpriteShader
से कंपाइल किया गया shader लगाने के लिए SpriteShader(id, shaderID)।
दोनों लंबे समय से कैटलॉग में बिना किसी implementation के declare थे,
और इन्हें बुलाने पर एक error आता था; अब ये काम करते हैं।