เอฟเฟกต์สไปรต์และข้อความ
เงา เส้นขอบ เรืองแสง และเบลอ บนสไปรต์ 2D และบนข้อความ พร้อมต้นทุนของแต่ละอย่าง ผลที่มีต่อสไปรต์ที่กำลังเคลื่อนไหว และสูตรที่มันมาแทนที่
สิ่งนี้มีไว้เพื่ออะไร#
จนถึงตอนนี้สไปรต์ 2D สามารถมีสีและภาพเท่านั้น ไม่มีอะไรอื่นอีก การทำให้ตัวละคร ดูโดดเด่นจากพื้นหลังต้องสร้างเอฟเฟกต์ด้วยมือ: สร้างสไปรต์ตัวที่สอง ทำให้เป็นสีดำ เลื่อนตำแหน่ง วางไว้ด้านหลัง และให้มันตามสไปรต์แรกทุกเฟรม มันได้ผล แต่ก็เป็น งานบัญชีเพิ่มอีกสี่บรรทัดต่อตัวละคร และวันที่คุณลืมบรรทัดใดบรรทัดหนึ่ง เงาก็จะ ตามหลังเจ้าของมันไม่ทัน
สี่คำสั่งทำสิ่งนี้ให้คุณ บนสไปรต์และบนข้อความ:
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
ไม่มีอะไรอื่นให้ต้องดูแลรักษา ย้ายสไปรต์ ปรับขนาด พลิกมัน เล่นแอนิเมชันของมัน: เอฟเฟกต์จะตามไปเอง
สี่เอฟเฟกต์#
Shadow#
SpriteShadow(spriteID, offsetX, offsetY, softness, opacity)
SpriteShadowColor(spriteID, red, green, blue)
offsetX และ offsetY เป็นหน่วยหน้าจอของคุณเอง นับแบบเดียวกับ
SpritePosition: ค่า Y เป็นบวกคือ ลง softness กระจายเงาออก opacity
มีค่าตั้งแต่ 0 ถึง 255 สีเป็นสีดำเว้นแต่คุณจะระบุอย่างอื่น
SpriteShadow(hero, 3, 5, 4, 110)
SpriteShadowColor(hero, 20, 0, 40) ' a cold shadow, not a grey one
เงาที่มี opacity เป็น 0 คือไม่มีเงา นั่นคือวิธีปิดมัน
Outline#
SpriteOutline(spriteID, thickness, red, green, blue)
เส้นขอบตาม ซิลูเอตต์ ของสไปรต์ ไม่ใช่ตามกรอบสี่เหลี่ยมที่มันอาศัยอยู่: PNG แบบโปร่งใสจะได้เส้นขอบรอบรูปวาด ไม่ใช่รอบไฟล์ ความหนาเป็นหน่วยหน้าจอ และ 1 ถึง 3 คือช่วงที่ใช้งานได้จริง เกินกว่านั้นแปดทิศทางที่เส้นขอบถูกสร้างขึ้นจะเริ่มเห็นเป็น แปดพู
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)
รัศมีที่มีสี กระจายออกไป size หน่วยเลยจากซิลูเอตต์ มันอยู่หลังสไปรต์และหน้าเงา
ซึ่งเป็นสิ่งที่ทำให้คุณใช้ทั้งสองอย่างพร้อมกันได้
SpriteGlow(pickup, 255, 210, 0, 10) ' this one is worth walking to
Blur#
SpriteBlur(spriteID, radius)
Blur คือตัวที่แตกต่างออกไป อีกสามตัวถูกวาด รอบ สไปรต์ ส่วน blur แทนที่ภาพ ของสไปรต์เองด้วยสำเนาที่เบลอแล้ว นั่นหมายความว่ามีสองสิ่งที่ควรรู้:
- มันไม่มีต้นทุนต่อเฟรม (ภาพที่เบลอถูกคำนวณเพียงครั้งเดียว) และ
- การเบลอถูกตัดที่ขอบของภาพ ภาพวาดที่แตะขอบไฟล์ PNG ของมันจะเสียส่วนของรัศมี ที่ควรจะล้นออกไปนอกไฟล์ เว้นระยะขอบโปร่งใสไว้สักสองสามพิกเซลในไฟล์ ถ้าคุณ วางแผนจะเบลอมัน
SpriteColor ยังคงทำงานได้กับสไปรต์ที่เบลอแล้ว
ปิดทุกอย่าง แล้วเปิดกลับมา#
SpriteEffects(spriteID, 0) ' all four off
SpriteEffects(spriteID, 1) ' all four back, exactly as they were
SpriteEffects ไม่ลบการตั้งค่าของคุณ มันคือสวิตช์ ไม่ใช่การรีเซ็ต ดังนั้นตัวละคร
สามารถกะพริบได้โดยที่คุณไม่ต้องประกาศเงาของมันใหม่ทีหลัง
สี่อย่างเดียวกันนี้บนข้อความ#
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)
ลายเซ็นตรงกับของสไปรต์ทุกประการ จึงไม่มีอะไรใหม่ต้องเรียนรู้ มีสองข้อแตกต่างด้าน พฤติกรรม:
- glow ชนะ softness ของ shadow ทั้งสองถูกวาดด้วยกลไกเดียวกัน และ glow ที่ไม่มี softness จะมองไม่เห็น ในขณะที่ shadow ที่ไม่มี softness ก็ยังคงเป็นเงา อยู่ เมื่อคุณขอทั้งสองอย่าง glow จะได้ softness ไป
- สิ่งเหล่านี้ใช้ได้กับข้อความแบบเวกเตอร์เท่านั้น ไม่ใช่ข้อความแบบ bitmap-font
ข้อความที่วาดด้วย
TextFontImageคือการประกอบกันของสไปรต์ คำสั่งเหล่านี้จะถูก เพิกเฉยอย่างเงียบ ๆ กับมัน ให้ใช้เอฟเฟกต์ของสไปรต์กับสไปรต์เหล่านั้นแทนในกรณีนั้น
ตัวอย่างที่ใช้งานได้จริง: อ่านได้บนพื้นหลังทุกแบบ#
ปัญหาที่คำสั่งเหล่านี้แก้จริง ๆ คือความคมชัดที่คุณควบคุมไม่ได้ คะแนนสีขาวจะมองไม่เห็น บนหิมะ คะแนนสีดำจะมองไม่เห็นตอนกลางคืน เส้นขอบแก้ปัญหานี้ได้ครั้งเดียว สำหรับ ทุกพื้นหลังที่คุณจะเคยวาด
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
การอ่านค่าเอฟเฟกต์กลับมา#
พารามิเตอร์ทุกตัวที่คุณเขียนมีตัวอ่านค่า เหมือนที่ SpriteColor มี
SpriteColorRed นั่นคือกฎของภาษาถิ่นนี้ และคำสั่งเหล่านี้ก็ทำตามกฎเดียวกัน
IF SpriteEffectsEnabled(hero) = 1
SpriteEffects(hero, 0)
ENDIF
alpha = SpriteShadowAlpha(hero) ' 0 to 255
size = SpriteGlowSize(hero) ' 0 means no glow
ชุดเต็มทั้งหมด ต่อกลุ่ม: SpriteShadowOffsetX, SpriteShadowOffsetY,
SpriteShadowBlur, SpriteShadowAlpha, SpriteShadowColorRed,
SpriteShadowColorGreen, SpriteShadowColorBlue, SpriteGlowRed,
SpriteGlowGreen, SpriteGlowBlue, SpriteGlowSize,
SpriteOutlineThickness, SpriteOutlineRed, SpriteOutlineGreen,
SpriteOutlineBlue, SpriteBlurRadius, SpriteEffectsEnabled บวกกับสิบเจ็ด
ตัวเดียวกันที่มีคำนำหน้า Text
สองกฎที่ควรรู้:
- สไปรต์ที่ไม่เคยถูกกำหนดเอฟเฟกต์เลยจะรายงานตัวว่าเปิดอยู่ นั่นคือสถานะ เริ่มต้น การตอบ 0 จะบอกโปรแกรมว่าเอฟเฟกต์ของมันถูกตัดออกไปแล้ว ก่อนที่จะมีการ ตั้งค่าใด ๆ เลย
- การถามถึงสไปรต์ที่ไม่มีอยู่จริงจะตอบ 0 ไม่ใช่หยุดโปรแกรม นั่นคือวิธีที่
ภาษาถิ่นนี้ปฏิบัติต่อคำถามทุกแห่ง:
SpriteHitตอบ 0 เมื่อไม่มีอะไรแตะกัน และ โปรแกรมอ่านค่า 0 นั้นโดยไม่ต้องทดสอบมัน
ต้นทุนของมัน#
Shadow, outline และ glow ถูก วาด ดังนั้นมันมีต้นทุนเป็น draw call: หนึ่งครั้ง สำหรับเงา (สามครั้งเมื่อเป็นเงานุ่ม) สี่ครั้งสำหรับ glow แปดครั้งสำหรับ outline หน้าจอที่มีสไปรต์แบบมีเส้นขอบสองร้อยตัวคือหน้าจอที่วาดสี่เหลี่ยมหนึ่งพันแปดร้อยชิ้น และมันจะแสดงผลชัดเจน สิ่งเหล่านี้มีไว้สำหรับสิ่งไม่กี่อย่างที่ผู้เล่นควรมองไปที่: ตัวละคร ไอเทม หน่วยที่ถูกเลือก
Blur ไม่มีต้นทุนต่อเฟรม
กฎที่ใช้ได้จริง: ใส่เอฟเฟกต์กับสิ่งที่เคลื่อนไหวและสำคัญ ไม่ใส่กับพื้นหลัง
สิ่งที่ข้ามไปยังเกมที่ส่งออกแล้ว#
| เป้าหมาย | Shadow, outline, glow | Blur | เอฟเฟกต์ข้อความ |
|---|---|---|---|
| ตัวแก้ไข | ใช่ | ใช่ | ใช่ |
| ส่งออก HTML5 | ใช่ | ใช่ | ใช่ |
| Native และ wasm (Bevy) | ใช่ | ไม่ | ไม่ |
Shadow, outline และ glow ถูกสร้างจากสไปรต์ธรรมดา จึงเดินทางไปได้ทุกที่ที่สไปรต์ ไปได้ Blur และเอฟเฟกต์ข้อความต้องการสะพานที่เป้าหมาย Bevy ยังไม่มี: รายงานการ แปลง (conversion report) ระบุชื่อมันไว้ แทนที่จะทิ้งมันไปเงียบ ๆ ดังนั้นการบิลด์ จะบอกคุณว่ามันพกพาอะไรไปด้วยไม่ได้
จุดที่เอฟเฟกต์ไม่มี#
ไม่มี SpriteEffect(id, "glow", ...) ที่รับชื่อเอฟเฟกต์เป็นสตริง แต่ละเอฟเฟกต์เป็น
คำสั่งของตัวเอง เพื่อให้พารามิเตอร์ของมันมีชื่อ มีเอกสาร และเติมคำอัตโนมัติได้ขณะพิมพ์
สำหรับสิ่งที่เกินกว่าสี่อย่างนี้ มีอีกสองคำสั่งที่รับช่วงต่อ:
SpriteBlendModes(id, src, dst) สำหรับการผสมแบบบวกหรือคูณ (ไฟ เลเซอร์) และ
SpriteShader(id, shaderID) เพื่อใส่ shader ที่คอมไพล์โดย LoadSpriteShader
ลงบนสไปรต์ ทั้งคู่ถูกประกาศไว้ในแคตตาล็อกมาเป็นเวลานานโดยไม่มีการใช้งานจริง และ
การเรียกใช้มันเคยแจ้งข้อผิดพลาด แต่ตอนนี้มันทำงานได้แล้ว