สวัสดี (โลก)
หน้าแรกของ Google เป็นสภาพแวดล้อมที่น่าทึ่งในการเขียนโค้ด การสร้างประสบการณ์การใช้งานที่ยอดเยี่ยมนั้นมีข้อจํากัดที่ท้าทายมากมาย เช่น ต้องมุ่งเน้นที่ความเร็วและการตอบสนอง รองรับเบราว์เซอร์ทุกประเภท และทํางานได้ในสถานการณ์ต่างๆ และที่สำคัญคือต้องสร้างความประหลาดใจและความพึงพอใจ
เราหมายถึง Google Doodle ซึ่งเป็นภาพพิเศษที่แสดงแทนโลโก้ของเราในบางครั้ง และแม้ว่าความสัมพันธ์ระหว่างฉันกับปากกาและพู่กันจะมีกลิ่นอายของคำสั่งห้ามไม่ให้เข้าใกล้มาอย่างยาวนาน แต่ฉันก็มักจะมีส่วนร่วมในผลงานแบบอินเทอร์แอกทีฟ
Doodle แบบอินเทอร์แอกทีฟทุกรายการที่ผมเขียนโค้ด (Pac-Man, Jules Verne, World’s Fair) และอีกหลายรายการที่ผมช่วยเขียนล้วนแล้วแต่เป็นทั้งล้ำสมัยและล้าสมัยในขณะเดียวกัน นั่นคือเป็นโอกาสอันยอดเยี่ยมสำหรับแอปพลิเคชันที่เป็นไปไม่ได้ของฟีเจอร์สุดล้ำบนเว็บ และการใช้งานจริงที่เต็มไปด้วยข้อจำกัดของความสามารถในการทำงานร่วมกันข้ามเบราว์เซอร์
เราเรียนรู้สิ่งต่างๆ มากมายจากแต่ละ Doodle แบบอินเทอร์แอกทีฟ และมินิกเกม Stanisław Lem ล่าสุดก็เช่นกัน โดย Doodle นี้ใช้โค้ด JavaScript 17,000 บรรทัด และลองทำสิ่งต่างๆ เป็นครั้งแรกในประวัติศาสตร์ของ Doodle วันนี้ฉันอยากแชร์โค้ดนั้นกับคุณ เผื่อว่าคุณจะพบสิ่งที่น่าสนใจหรือชี้ให้เห็นข้อผิดพลาดของฉัน และพูดคุยกันสักเล็กน้อย
ดูโค้ด Doodle ของ Stanisław Lem »
สิ่งที่ควรคำนึงถึงคือหน้าแรกของ Google ไม่ใช่ที่สำหรับสาธิตเทคโนโลยี เราต้องการเฉลิมฉลองบุคคลและเหตุการณ์สำคัญผ่านภาพวาด Doodle และต้องการนำเสนอด้วยงานศิลปะและเทคโนโลยีที่ดีที่สุดที่เรามี แต่จะไม่เฉลิมฉลองเทคโนโลยีเพียงเพื่อเทคโนโลยี ซึ่งหมายความว่าเราต้องพิจารณาอย่างละเอียดว่าส่วนใดของ HTML5 ที่เข้าใจกันโดยทั่วไปใช้งานได้บ้าง และส่วนนั้นจะช่วยให้เราทำให้ Doodle ดีขึ้นได้หรือไม่โดยไม่ทำให้ Doodle เสียสมาธิหรือบดบัง Doodle
มาดูเทคโนโลยีเว็บสมัยใหม่บางส่วนที่ปรากฏใน Doodle ของ Stanisław Lem และบางส่วนที่ไม่ได้ปรากฏกัน
กราฟิกผ่าน DOM และ Canvas
Canvas เป็นเครื่องมือที่มีประสิทธิภาพและสร้างขึ้นเพื่อสิ่งที่เราต้องการวาดในภาพวาดนี้โดยเฉพาะ อย่างไรก็ตาม เบราว์เซอร์รุ่นเก่าบางรุ่นที่เราให้ความสำคัญไม่ได้รองรับฟีเจอร์นี้ และแม้ว่าเราจะแชร์สำนักงานกับบุคคลที่รวม excanvas ที่ยอดเยี่ยมเข้าด้วยกัน แต่เราก็เลือกวิธีอื่น
เราสร้างเครื่องมือกราฟิกแบบนามธรรมที่แยกกราฟิกพื้นฐานที่เรียกว่า "Rect" ออก แล้วแสดงผลโดยใช้ Canvas หรือ DOM หาก Canvas ไม่พร้อมใช้งาน
แนวทางนี้มาพร้อมกับความท้าทายที่น่าสนใจ เช่น การย้ายหรือเปลี่ยนออบเจ็กต์ใน DOM จะมีผลทันที ส่วนใน Canvas จะมีช่วงเวลาที่วาดทุกอย่างพร้อมกัน (ฉันตัดสินใจใช้ภาพพิมพ์แคนวาสเพียงภาพเดียว แล้วล้างภาพพิมพ์แคนวาสนั้นและวาดใหม่ตั้งแต่ต้นสำหรับทุกเฟรม ในแง่หนึ่ง ชิ้นส่วนที่เคลื่อนไหวมีจำนวนมากเกินไป และอีกด้านหนึ่ง ชิ้นส่วนเหล่านั้นมีความซับซ้อนไม่มากพอที่จะแยกออกเป็นผืนผ้าใบที่ซ้อนทับกันหลายผืนและอัปเดตทีละผืน)
แต่การเปลี่ยนไปใช้ Canvas นั้นไม่ง่ายเหมือนการมิเรอร์พื้นหลัง CSS ด้วย drawImage()
เนื่องจากคุณจะสูญเสียสิ่งต่างๆ บางอย่างไป ซึ่งได้มาแบบไม่มีค่าใช้จ่ายเมื่อประกอบสิ่งต่างๆ เข้าด้วยกันผ่าน DOM โดยเฉพาะการวางซ้อนด้วย z-index และเหตุการณ์เมาส์
เราได้แยกแยะ z-index ออกแล้วโดยใช้แนวคิดที่เรียกว่า "ระนาบ" ภาพวาดดังกล่าวกำหนดระนาบจำนวนหนึ่ง ตั้งแต่ท้องฟ้าที่อยู่ด้านหลังไกลๆ ไปจนถึงเคอร์เซอร์เมาส์ที่อยู่ด้านหน้าทุกสิ่ง และองค์ประกอบทั้งหมดในภาพวาดต้องตัดสินใจว่าอยู่ระนาบใด (การแก้ไขเล็กๆ น้อยๆ ในระนาบหนึ่งๆ ทำได้โดยใช้ planeCorrection
)
เมื่อแสดงผลผ่าน DOM ระบบจะแปลระนาบเป็น z-index แต่หากแสดงผลผ่าน Canvas เราจะต้องจัดเรียงสี่เหลี่ยมผืนผ้าตามระนาบก่อนวาด เนื่องจากการดำเนินการนี้ทุกครั้งมีค่าใช้จ่ายสูง ระบบจะคำนวณลำดับใหม่เฉพาะเมื่อมีการเพิ่มผู้แสดงหรือเมื่อผู้แสดงย้ายไปยังระนาบอื่นเท่านั้น
สำหรับเหตุการณ์เมาส์ เราได้แยกส่วนเหตุการณ์นั้นด้วยเหมือนกัน สำหรับทั้ง DOM และ Canvas เราใช้องค์ประกอบ DOM ที่ลอยอยู่แบบโปร่งใสทั้งหมดเพิ่มเติมซึ่งมี z-index สูง ซึ่งมีหน้าที่เพียงตอบสนองต่อเมาส์ที่เลื่อนเข้า/ออก การคลิก และการแตะ
สิ่งหนึ่งที่เราอยากลองทำกับภาพวาดนี้คือการทำลายด่านที่ 4 เครื่องมือข้างต้นช่วยให้เรารวมเอนทิตีที่อิงตาม Canvas เข้ากับเอนทิตีที่อิงตาม DOM ได้ ตัวอย่างเช่น ระเบิดในฉากสุดท้ายมีทั้งใน Canvas สําหรับวัตถุในจักรวาลและใน DOM สําหรับส่วนที่เหลือของหน้าแรกของ Google นกซึ่งปกติจะบินไปรอบๆ และถูกตัดด้วยหน้ากากขรุขระของเราเหมือนนักแสดงคนอื่นๆ ตัดสินใจที่จะไม่เข้าไปพัวพันกับปัญหาระหว่างระดับการถ่ายทำ และนั่งอยู่บนปุ่ม "ฉันโชคดี" วิธีการคือนกจะออกจาก Canvas และกลายเป็นองค์ประกอบ DOM (และในทางกลับกันภายหลัง) ซึ่งเราหวังว่าจะมีความโปร่งใสต่อผู้เข้าชมโดยสมบูรณ์
อัตราเฟรม
การทราบอัตราเฟรมปัจจุบันและการตอบสนองเมื่ออัตราเฟรมช้าเกินไป (และเร็วเกินไป) เป็นส่วนสำคัญของเครื่องยนต์ เนื่องจากเบราว์เซอร์ไม่ได้รายงานอัตราเฟรมกลับมา เราจึงต้องคำนวณอัตราเฟรมด้วยตนเอง
เราเริ่มต้นด้วยการใช้ requestAnimationFrame
requestAnimationFrame
ช่วยประหยัด CPU อย่างชาญฉลาดในบางสถานการณ์ แม้ว่าเราจะดำเนินการบางอย่างด้วยตนเองตามที่อธิบายไว้ด้านล่าง แต่ก็ยังช่วยให้เราได้รับอัตราเฟรมที่สูงกว่า setTimeout
การคำนวณอัตราเฟรมปัจจุบันนั้นง่าย แต่อาจเปลี่ยนแปลงอย่างฉับพลัน เช่น อาจลดลงอย่างรวดเร็วเมื่อแอปพลิเคชันอื่นใช้ทรัพยากรคอมพิวเตอร์เป็นเวลานาน ดังนั้น เราจะคำนวณอัตราเฟรม "แบบต่อเนื่อง" (ค่าเฉลี่ย) เฉพาะใน 100 ทิกทางกายภาพเท่านั้น และตัดสินใจตามข้อมูลดังกล่าว
การตัดสินใจประเภทใด
หากอัตราเฟรมสูงกว่า 60 FPS เราจะจำกัดอัตราเฟรม ปัจจุบัน
requestAnimationFrame
ใน Firefox บางเวอร์ชันไม่มีขีดจำกัดบนของอัตราเฟรม และไม่มีเหตุผลที่จะสิ้นเปลือง CPU โปรดทราบว่าอัตราเฟรมสูงสุดที่เรากำหนดคือ 65 FPS เนื่องจากข้อผิดพลาดในการปัดเศษที่ทำให้อัตราเฟรมสูงกว่า 60 FPS เล็กน้อยในเบราว์เซอร์อื่นๆ และเราไม่ต้องการให้เริ่มจำกัดอัตราเฟรมโดยไม่ได้ตั้งใจหากอัตราเฟรมต่ำกว่า 10 FPS เราจะเพียงลดความเร็วของเครื่องยนต์แทนการลดเฟรม นี่เป็นทางเลือกที่เสียทั้งสองฝ่าย แต่เรารู้สึกว่าการข้ามเฟรมมากเกินไปจะทำให้สับสนมากกว่าการเล่นเกมที่ช้าลง (แต่ยังคงสอดคล้องกัน) ผลข้างเคียงอีกอย่างหนึ่งที่น่าสนใจคือ หากระบบทำงานช้าลงชั่วคราว ผู้ใช้จะไม่พบการข้ามไปข้างหน้าอย่างผิดปกติขณะที่เครื่องมือพยายามทำงานให้ทัน (ฉันทำ Pac-Man แตกต่างออกไปเล็กน้อย แต่อัตราเฟรมขั้นต่ำเป็นแนวทางที่ดีกว่า)
สุดท้าย เราอาจลดรายละเอียดของกราฟิกเมื่อเฟรมเรตต่ำจนเป็นอันตราย เราไม่ได้ทำเช่นนั้นกับ Doodle ของ Lem ยกเว้นเคอร์เซอร์เมาส์ (ดูข้อมูลเพิ่มเติมด้านล่าง) แต่เราอาจลดภาพเคลื่อนไหวที่ไม่จำเป็นบางส่วนเพื่อให้ Doodle ทำงานได้อย่างราบรื่นแม้ในคอมพิวเตอร์ที่ช้า
นอกจากนี้ เรายังมีแนวคิดเกี่ยวกับเครื่องหมายเวลาจริงและเครื่องหมายเวลาเชิงตรรกะ ค่าแรกมาจาก requestAnimationFrame
/setTimeout
อัตราส่วนในการเล่นเกมปกติคือ 1:1 แต่สำหรับการกรอไปข้างหน้า เราจะเพิ่มการนับเวลาแบบตรรกะต่อการนับเวลาจริง (สูงสุด 1:5) วิธีนี้ช่วยให้เราทําการคํานวณที่จําเป็นทั้งหมดสําหรับการนับเวลาแบบตรรกะทุกครั้ง แต่กําหนดให้เฉพาะการนับครั้งล่าสุดเป็นอัปเดตข้อมูลบนหน้าจอ
การเปรียบเทียบ
เราอาจคาดการณ์ (และก็คาดการณ์มาตั้งแต่เนิ่นๆ) ว่า Canvas จะเร็วกว่า DOM ทุกครั้งที่พร้อมใช้งาน ข้อมูลนี้อาจไม่ถูกต้องเสมอไป ระหว่างการทดสอบ เราพบว่า Opera 10.0–10.1 ใน Mac และ Firefox ใน Linux ทำงานได้เร็วกว่าเมื่อย้ายองค์ประกอบ DOM
ในโลกที่สมบูรณ์แบบ การวาดภาพจะเปรียบเทียบเทคนิคกราฟิกต่างๆ อย่างเงียบๆ เช่น องค์ประกอบ DOM ที่ย้ายโดยใช้ style.left
และ style.top
การวาดบนผืนผ้าใบ และอาจรวมถึงองค์ประกอบ DOM ที่ย้ายโดยใช้การเปลี่ยนรูปแบบ CSS3
จากนั้นเปลี่ยนไปใช้การตั้งค่าที่ให้อัตราเฟรมสูงสุด เราเริ่มเขียนโค้ดสําหรับการทดสอบนั้น แต่พบว่าวิธีการเปรียบเทียบของเราไม่น่าเชื่อถือและใช้เวลานาน เวลาที่เราไม่มีอยู่มากนักในหน้าแรก เนื่องจากเราให้ความสำคัญกับความเร็วเป็นอย่างมากและต้องการให้ Doodle ปรากฏขึ้นทันที รวมถึงเกมเพลย์จะเริ่มขึ้นทันทีที่คุณคลิกหรือแตะ
ท้ายที่สุดแล้ว การพัฒนาเว็บบางครั้งก็ขึ้นอยู่กับว่าคุณต้องทําอะไรบ้าง ฉันมองไปรอบๆ เพื่อดูว่าไม่มีใครอยู่ตรงนั้น จากนั้นก็เขียนโค้ด Opera 10 และ Firefox ออกมาจาก Canvas ชาติหน้าเราจะกลับมาเป็นแท็ก<marquee>
การประหยัด CPU
คุณรู้จักเพื่อนที่เข้ามาบ้านคุณ ดูตอนสุดท้ายของซีซัน Breaking Bad บอกตอนจบให้คุณฟัง แล้วลบตอนนั้นออกจากเครื่องบันทึกวิดีโอใช่ไหม คุณคงไม่อยากให้ตัวเองเป็นคนแบบนั้นใช่ไหม
นี่เป็นตัวอย่างที่แย่ที่สุดเท่าที่เคยมีมา แต่เราก็ไม่ต้องการให้ภาพวาดของเราเป็นอย่างนั้นเช่นกัน การที่เราได้เข้าไปอยู่ในแท็บเบราว์เซอร์ของผู้อื่นถือเป็นอภิสิทธิ์ การแย่งชิงรอบการทำงานของ CPU หรือทำให้ผู้ใช้เสียสมาธิจะทำให้เรากลายเป็นผู้มาเยือนที่ไม่พึงประสงค์ ดังนั้น หากไม่มีใครเล่นวาดเขียน (ไม่มีการแตะ การคลิกเมาส์ การเคลื่อนไหวเมาส์ หรือการกดแป้นพิมพ์) เราต้องการให้แอปเข้าสู่โหมดสลีปในที่สุด
เมื่อไร
- หลังจากผ่านไป 18 วินาทีในหน้าแรก (เกมอาร์เคดเรียกช่วงนี้ว่าโหมดดึงดูด)
- หลังจากผ่านไป 180 วินาทีหากแท็บมีโฟกัส
- หลังจากผ่านไป 30 วินาทีหากแท็บไม่มีโฟกัส (เช่น ผู้ใช้เปลี่ยนไปใช้หน้าต่างอื่น แต่อาจยังดูภาพวาดในแท็บที่ไม่ได้ใช้งานอยู่)
- ทันทีหากแท็บมองไม่เห็น (เช่น ผู้ใช้เปลี่ยนไปใช้แท็บอื่นในหน้าต่างเดียวกัน เราไม่ควรจะเสียเวลาหากแท็บมองไม่เห็น)
เราจะรู้ได้อย่างไรว่าขณะนี้แท็บมีโฟกัส เราแนบไปกับ window.focus
และ window.blur
เราจะรู้ได้อย่างไรว่าแท็บนั้นมองเห็นได้ เราใช้ Page Visibility API ใหม่และตอบสนองต่อเหตุการณ์ที่เหมาะสม
เราให้เวลาพักข้างต้นนานกว่าปกติ เราปรับให้เข้ากับภาพวาดนี้ซึ่งมีภาพเคลื่อนไหวรอบๆ มากมาย (ส่วนใหญ่คือท้องฟ้าและนก) โดยหลักการแล้ว การหมดเวลาควรกำหนดตามการโต้ตอบในเกม เช่น หลังจากลงจอดแล้ว นกจะรายงานกลับไปที่ Doodle ว่าตอนนี้สามารถเข้าสู่โหมดสลีปได้แล้ว แต่สุดท้ายแล้วเราไม่ได้ติดตั้งใช้งาน
เนื่องจากท้องฟ้าเคลื่อนไหวอยู่เสมอ เมื่อคุณหลับไปและตื่นขึ้นมา รูปวาดจะไม่หยุดหรือเริ่มวาดทันที แต่ระบบจะค่อยๆ ช้าลงก่อนที่จะหยุดชั่วคราว และในทางกลับกันเมื่อกลับมาวาดต่อ ระบบจะเพิ่มหรือลดจำนวนการนับเวลาเชิงตรรกะต่อการนับเวลาจริงตามที่จำเป็น
ทรานซิชัน การเปลี่ยนรูปแบบ เหตุการณ์
ความสามารถอย่างหนึ่งของ HTML คือการที่คุณปรับปรุงให้ดีขึ้นได้ด้วยตนเองเสมอ หากบางสิ่งยังไม่ดีพอในพอร์ตโฟลิโอปกติของ HTML และ CSS คุณก็ใช้ JavaScript เพื่อขยายความสามารถของสิ่งนั้น แต่บางครั้งก็อาจต้องเริ่มต้นใหม่ทั้งหมด การเปลี่ยน CSS3 นั้นยอดเยี่ยม แต่คุณจะเพิ่มการเปลี่ยนประเภทใหม่หรือใช้การเปลี่ยนเพื่อดำเนินการอย่างอื่นนอกเหนือจากการจัดรูปแบบองค์ประกอบไม่ได้ อีกตัวอย่างหนึ่งคือ การเปลี่ยนรูปแบบ CSS3 เหมาะสําหรับ DOM แต่เมื่อเปลี่ยนไปใช้ Canvas คุณจะต้องดําเนินการด้วยตนเอง
ปัญหาเหล่านี้และอื่นๆ อีกมากมายเป็นเหตุผลที่ Lem doodle มีเครื่องมือเปลี่ยนรูปแบบและเปลี่ยนเฟรมของตัวเอง เราทราบดีว่ายุค 2000 เรียกหาเราแล้ว ความสามารถที่เราสร้างขึ้นนั้นไม่มีประสิทธิภาพเท่ากับ CSS3 แต่ไม่ว่าจะทำอะไร เครื่องมือก็จะทําอย่างสม่ำเสมอและให้เราควบคุมได้มากขึ้น
เราเริ่มต้นด้วยระบบการดำเนินการ (เหตุการณ์) แบบง่าย ซึ่งเป็นไทม์ไลน์ที่เรียกเหตุการณ์ในอนาคตให้แสดงโดยไม่ต้องใช้ setTimeout
เนื่องจากเวลาวาดภาพแต่ละจุดอาจไม่ตรงกับเวลาจริงเมื่อวาดภาพเร็วขึ้น (กรอไปข้างหน้า) ช้าลง (อัตราเฟรมต่ำหรือระบบหยุดทำงานเพื่อประหยัด CPU) หรือหยุดทำงานไปเลย (รอให้รูปภาพโหลดเสร็จ)
ทรานซิชันเป็นเพียงการดำเนินการอีกประเภทหนึ่ง นอกจากการเคลื่อนไหวและการหมุนพื้นฐานแล้ว เรายังรองรับการเคลื่อนไหวแบบสัมพัทธ์ (เช่น ย้ายวัตถุไปทางขวา 10 พิกเซล) การเคลื่อนไหวที่กำหนดเอง เช่น การสั่น และภาพเคลื่อนไหวของคีย์เฟรมด้วย
เราได้พูดถึงการหมุนแล้ว ซึ่งก็ทำได้ด้วยตนเองเช่นกัน เรามีสไปรต์สำหรับมุมต่างๆ ของออบเจ็กต์ที่ต้องหมุน เหตุผลหลักคือทั้ง CSS3 และการหมุนภาพพิมพ์แคนวาสทำให้เกิดข้อบกพร่องที่มองเห็นได้ซึ่งเราไม่ยอมรับ และข้อบกพร่องเหล่านั้นยังแตกต่างกันไปตามแพลตฟอร์ม
เนื่องจากวัตถุบางอย่างที่หมุนจะยึดอยู่กับวัตถุอื่นๆ ที่หมุนด้วย เช่น มือของหุ่นยนต์ที่เชื่อมต่อกับส่วนแขนล่าง ซึ่งยึดอยู่กับส่วนแขนบนที่หมุนได้ หมายความว่าฉันต้องสร้าง transform-origin จำลองในรูปแบบของจุดหมุนด้วย
ทั้งหมดนี้เป็นงานที่หนักหนาสาหัสซึ่งท้ายที่สุดแล้วครอบคลุมถึงสิ่งที่ HTML5 ดูแลอยู่แล้ว แต่บางครั้งการรองรับแบบเนทีฟก็ยังไม่เพียงพอและถึงเวลาที่ต้องคิดค้นสิ่งใหม่ๆ
การจัดการกับรูปภาพและสไปรต์
เครื่องมือนี้ไม่ได้มีไว้เพื่อเรียกใช้ Doodle เท่านั้น แต่ยังใช้เพื่อแก้ไข Doodle ได้ด้วย เราได้แชร์พารามิเตอร์การแก้ไขข้อบกพร่องบางส่วนไว้ด้านบนแล้ว คุณดูพารามิเตอร์ที่เหลือได้ใน engine.readDebugParams
Spriting
เป็นเทคนิคที่รู้จักกันดีซึ่งเราใช้กับภาพวาดหมึกเช่นกัน ซึ่งช่วยให้เราประหยัดไบต์และลดเวลาในการโหลด รวมถึงทำให้การโหลดล่วงหน้าง่ายขึ้น
แต่วิธีนี้ยังทําให้การพัฒนายากขึ้นด้วย เนื่องจากการเปลี่ยนแปลงภาพทุกครั้งจะต้องมีการแยกภาพใหม่ (ส่วนใหญ่เป็นแบบอัตโนมัติ แต่ก็ยังคงยุ่งยากอยู่) ดังนั้น เครื่องมือนี้จึงรองรับการทำงานบนรูปภาพดิบสําหรับการพัฒนา รวมถึงสไปรต์สําหรับเวอร์ชันที่ใช้งานจริงผ่าน engine.useSprites
โดยทั้ง 2 รูปแบบจะรวมอยู่ในซอร์สโค้ด

นอกจากนี้ เรายังรองรับการโหลดรูปภาพล่วงหน้าขณะวาดภาพ และหยุดการวาดหากรูปภาพไม่โหลดทันเวลา พร้อมแถบความคืบหน้าจำลอง (เสมือนจริงเนื่องจากแม้แต่ HTML5 ก็ยังบอกไม่ได้ว่าโหลดไฟล์ภาพไปมากน้อยเพียงใดแล้ว)

สำหรับบางฉาก เราใช้สไปรต์มากกว่า 1 รายการเพื่อเร่งความเร็วในการโหลดโดยใช้การเชื่อมต่อแบบขนาน แต่เนื่องจากข้อจำกัด 3/5 ล้านพิกเซลสำหรับรูปภาพใน iOS
HTML5 เข้ามามีบทบาทอย่างไรในกระบวนการนี้ ข้อมูลข้างต้นมีไม่มากนัก แต่เครื่องมือที่เราเขียนขึ้นสำหรับการแยกภาพ/ครอบตัดเป็นเทคโนโลยีเว็บใหม่ทั้งหมด ได้แก่ Canvas, Blob และ a[download] สิ่งที่น่าตื่นเต้นอย่างหนึ่งเกี่ยวกับ HTML คือการที่ HTML ค่อยๆ ดูดกลืนสิ่งที่ก่อนหน้านี้ต้องทำนอกเบราว์เซอร์ ส่วนเดียวที่เราต้องทำในเบราว์เซอร์คือการเพิ่มประสิทธิภาพไฟล์ PNG
บันทึกสถานะระหว่างเกม
โลกของ Lem มักจะให้ความรู้สึกยิ่งใหญ่ มีชีวิตชีวา และสมจริง เรื่องราวของเขามักจะเริ่มต้นโดยไม่มีการอธิบายมากนัก หน้าแรกจะเริ่มต้นจากกลางเรื่อง โดยผู้อ่านต้องหาทางไปเอง
Cyberiad ก็เช่นกัน และเราต้องการสื่อความรู้สึกนั้นในภาพวาด Doodle เราเริ่มต้นด้วยการพยายามไม่อธิบายเรื่องราวมากเกินไป อีกส่วนสำคัญคือการสุ่ม ซึ่งเรารู้สึกว่าเหมาะกับลักษณะเชิงกลไกของจักรวาลหนังสือ เราใช้ฟังก์ชันตัวช่วยจำนวนมากที่จัดการกับการสุ่มในหลายๆ ที่
นอกจากนี้ เรายังต้องการเพิ่มความสามารถในการเล่นซ้ำด้วยวิธีอื่นๆ ด้วยเหตุนี้ เราจึงต้องทราบจำนวนครั้งที่มีการวาดภาพวาดเสร็จแล้วก่อนหน้านี้ โซลูชันทางเทคโนโลยีที่ถูกต้องตามประวัติศาสตร์สำหรับปัญหานี้ก็คือคุกกี้ แต่วิธีนี้ใช้ไม่ได้กับหน้าแรกของ Google เนื่องจากคุกกี้ทุกรายการจะเพิ่มเพย์โหลดของทุกหน้า และเราให้ความสำคัญกับความเร็วและเวลาในการตอบสนองเป็นอย่างมาก
แต่โชคดีที่ HTML5 มีพื้นที่เก็บข้อมูลเว็บ ซึ่งใช้งานได้ง่ายมาก ซึ่งช่วยให้เราบันทึกและเรียกดูจำนวนการเล่นทั่วไปและฉากสุดท้ายที่ผู้ใช้เล่นได้สะดวกกว่ามากเมื่อเทียบกับคุกกี้
เราใช้ข้อมูลนี้อย่างไร
- เราจะแสดงปุ่มกรอไปข้างหน้า ซึ่งช่วยให้ข้ามฉากตัดที่ผู้ใช้เคยดูแล้วได้
- เราแสดงรายการ N รายการที่แตกต่างกันในช่วงสุดท้าย
- เราเพิ่มความยากของระดับการถ่ายภาพขึ้นเล็กน้อย
- เราจะแสดงมังกรแห่งความน่าจะเป็นซึ่งเป็นไข่อีสเตอร์เล็กๆ จากเรื่องราวอื่นในการเล่นครั้งที่ 3 และครั้งต่อๆ ไป
พารามิเตอร์การแก้ไขข้อบกพร่องที่ควบคุมข้อมูลนี้ ได้แก่
?doodle-debug&doodle-first-run
– สมมติว่าเป็นการเรียกใช้ครั้งแรก?doodle-debug&doodle-second-run
– สมมติว่าเป็นการเรียกใช้ครั้งที่ 2?doodle-debug&doodle-old-run
– สมมติว่าเป็นการเรียกใช้ครั้งเก่า
อุปกรณ์ระบบสัมผัส
เราต้องการให้ผู้ใช้รู้สึกสบายใจเมื่อเล่นวาดเขียนบนอุปกรณ์แบบสัมผัส เนื่องจากอุปกรณ์ที่ทันสมัยที่สุดมีความสามารถเพียงพอที่จะทำให้วาดเขียนทำงานได้อย่างราบรื่น และประสบการณ์การเล่นเกมผ่านการแตะก็สนุกกว่าการคลิกมาก
จำเป็นต้องทำการเปลี่ยนแปลงบางอย่างกับประสบการณ์ของผู้ใช้ตั้งแต่ต้น เดิมที เคอร์เซอร์เมาส์เป็นสิ่งเดียวที่สื่อสารว่ากำลังมีฉากตัด/ส่วนที่โต้ตอบไม่ได้เกิดขึ้น ต่อมาเราได้เพิ่มตัวบ่งชี้เล็กๆ ที่มุมล่างขวาเพื่อที่เราจะได้ไม่ต้องใช้เคอร์เซอร์เมาส์เพียงอย่างเดียว (เนื่องจากไม่มีเคอร์เซอร์เมาส์ในอุปกรณ์แบบสัมผัส)
ปกติ | ไม่ว่าง | คลิกได้ | เคยคลิก | |
---|---|---|---|---|
อยู่ระหว่างดำเนินการ | ![]() |
![]() |
![]() |
![]() |
รอบชิงชนะเลิศ | ![]() |
![]() |
![]() |
![]() |
ทุกอย่างใช้งานได้ทันที อย่างไรก็ตาม การทดสอบความสามารถในการใช้งานแบบฉับพลันของประสบการณ์การสัมผัสของเราพบปัญหา 2 ข้อ ได้แก่ เป้าหมายบางรายการกดยากเกินไป และระบบไม่สนใจการแตะอย่างรวดเร็วเนื่องจากเราเพิ่งลบล้างเหตุการณ์การคลิกเมาส์
การมีองค์ประกอบ DOM แบบโปร่งใสที่คลิกได้แยกต่างหากช่วยได้มากในเรื่องนี้ เนื่องจากฉันสามารถปรับขนาดองค์ประกอบเหล่านั้นให้อิสระจากภาพ เราเพิ่มระยะห่างจากขอบ 15 พิกเซลสำหรับอุปกรณ์แบบสัมผัส และใช้ระยะนี้ทุกครั้งที่สร้างองค์ประกอบที่คลิกได้ (เราเพิ่มระยะห่างจากขอบ 5 พิกเซลสำหรับสภาพแวดล้อมเมาส์ด้วย เพื่อทำให้ Mr. Fitts พอใจ)
สำหรับปัญหาอื่นๆ เราได้ตรวจสอบว่าได้แนบและทดสอบแฮนเดิลการเริ่มต้นและการสิ้นสุดการแตะที่เหมาะสมแล้ว แทนที่จะใช้การคลิกเมาส์
นอกจากนี้ เรายังใช้พร็อพเพอร์ตี้สไตล์ที่ทันสมัยมากขึ้นเพื่อนำฟีเจอร์การแตะบางอย่างที่เบราว์เซอร์ WebKit เพิ่มโดยค่าเริ่มต้นออก (การไฮไลต์ด้วยการแตะ ข้อความไฮไลต์ด้วยการแตะ)
และเราจะตรวจจับได้อย่างไรว่าอุปกรณ์ที่ใช้งาน Doodle รองรับการแตะหรือไม่ สบายๆ แทนที่จะคิดหาคำตอบล่วงหน้า เราใช้ความสามารถทางปัญญาที่รวมกันเพื่ออนุมานว่าอุปกรณ์รองรับการสัมผัสหลังจากที่เราได้รับเหตุการณ์การเริ่มการสัมผัสครั้งแรก
การปรับแต่งเคอร์เซอร์เมาส์
แต่ไม่ใช่ทุกอย่างที่ต้องใช้การสัมผัส หนึ่งในหลักการที่เรายึดถือคือใส่สิ่งต่างๆ ให้ได้มากที่สุดภายในจักรวาลของ Doodle UI ของแถบด้านข้างเล็กๆ (กรอไปข้างหน้า เครื่องหมายคำถาม) เคล็ดลับเครื่องมือ และแม้แต่เคอร์เซอร์ของเมาส์
วิธีปรับแต่งเคอร์เซอร์เมาส์ เบราว์เซอร์บางตัวอนุญาตให้เปลี่ยนเคอร์เซอร์ของเมาส์โดยลิงก์กับไฟล์รูปภาพที่ออกแบบเอง อย่างไรก็ตาม ฟีเจอร์นี้ยังไม่รองรับอย่างเต็มรูปแบบและค่อนข้างจํากัด
หากไม่ใช่กรณีนี้ จะเป็นกรณีใด เหตุใดจึงไม่ทำให้เคอร์เซอร์เมาส์เป็นเพียงตัวละครอีกตัวในภาพวาด วิธีนี้ได้ผล แต่มีข้อจำกัดหลายประการ โดยข้อจำกัดที่สำคัญที่สุดมีดังนี้
- คุณต้องนำเคอร์เซอร์เมาส์ของอุปกรณ์ออกได้
- คุณต้องทำได้ดีในการทำให้เคอร์เซอร์เมาส์ซิงค์กับเคอร์เซอร์ "จริง"
กรณีแรกนั้นค่อนข้างซับซ้อน CSS3 รองรับ cursor: none
แต่เบราว์เซอร์บางรุ่นก็ไม่รองรับเช่นกัน เราจึงต้องใช้วิธีแก้ปัญหาชั่วคราวบางอย่าง เช่น ใช้.cur
ไฟล์เปล่าเป็นไฟล์สำรอง ระบุลักษณะการทำงานที่ชัดเจนสำหรับเบราว์เซอร์บางรุ่น และแม้แต่การเขียนโค้ดแบบฮาร์ดโค้ดสำหรับเบราว์เซอร์อื่นๆ ไม่ให้แสดงในประสบการณ์การใช้งาน
อีกข้อหนึ่งดูเหมือนจะไม่ค่อยสำคัญ แต่เนื่องจากเคอร์เซอร์เมาส์เป็นเพียงส่วนหนึ่งของจักรวาลของภาพวาด ปัญหาทั้งหมดของภาพวาดก็จะมากับเคอร์เซอร์ด้วย รายการที่ใหญ่ที่สุดใช่ไหม หากอัตราเฟรมของภาพวาดขยุกขยิกต่ำ อัตราเฟรมของเมาส์พอยเตอร์ก็จะต่ำด้วย ซึ่งจะส่งผลเสียร้ายแรงเนื่องจากเมาส์พอยเตอร์เป็นส่วนที่ต่อมาจากมือของคุณ จึงต้องตอบสนองได้ไม่ว่าจะเกิดอะไรขึ้น (ตอนนี้ผู้ที่เคยใช้ Commodore Amiga ต่างพยักหน้ารัวเร็ว)
วิธีแก้ปัญหาที่ค่อนข้างซับซ้อนวิธีหนึ่งคือ การแยกเมาส์ชี้ออกจากลูปการอัปเดตปกติ เราทําเช่นนั้นแล้วในจักรวาลคู่ขนานที่ฉันไม่ต้องนอนหลับ มีวิธีแก้ปัญหาที่ง่ายกว่านี้ไหม เพียงเปลี่ยนกลับไปใช้เคอร์เซอร์เมาส์ของอุปกรณ์หากอัตราเฟรมที่แสดงลดลงต่ำกว่า 20 FPS (อัตราเฟรมแบบเลื่อนมีประโยชน์ในกรณีนี้ หากเราตอบสนองต่ออัตราเฟรมปัจจุบัน และหากอัตราเฟรมดังกล่าวสั่นอยู่ในช่วงประมาณ 20 fps ผู้ใช้จะเห็นเคอร์เซอร์เมาส์ที่กำหนดเองซ่อนและแสดงอยู่ตลอดเวลา) มาถึงส่วนนี้
ช่วงอัตราเฟรม | ลักษณะการทำงาน |
---|---|
มากกว่า 10 FPS | เล่นเกมช้าลงเพื่อไม่ให้เฟรมตกมากขึ้น |
10–20fps | ใช้เคอร์เซอร์เมาส์ของอุปกรณ์แทนเคอร์เซอร์ที่กำหนดเอง |
20–60fps | การดำเนินการตามปกติ |
>60 FPS | จำกัดเพื่อให้อัตราเฟรมไม่เกินค่านี้ |
และเคอร์เซอร์เมาส์จะเป็นสีเข้มใน Mac แต่จะเป็นสีขาวใน PC เหตุผล เพราะสงครามแพลตฟอร์มต้องมีเชื้อเพลิงแม้ในจักรวาลสมมติ
บทสรุป
เครื่องมือนี้ไม่ใช่เครื่องมือที่สมบูรณ์แบบ แต่ก็ไม่ได้พยายามที่จะเป็นแบบนั้น เราได้พัฒนาแอปนี้ควบคู่ไปกับ Doodle ของ Lem โดยเฉพาะ ไม่เป็นไร "การเพิ่มประสิทธิภาพก่อนเวลาอันควรคือต้นเหตุของปัญหาทั้งหมด" ดังที่ Don Knuth กล่าวไว้ และเราไม่เชื่อว่าการเขียนโปรแกรมโดยแยกส่วนก่อน แล้วค่อยนำมาใช้ภายหลังนั้นสมเหตุสมผล การปฏิบัติจริงช่วยให้ทราบทฤษฎีได้เช่นเดียวกับที่ทฤษฎีช่วยให้ทราบการปฏิบัติจริง ในกรณีของฉัน มีการทิ้งโค้ด เขียนบางส่วนซ้ำๆ หลายครั้ง และชิ้นส่วนทั่วไปหลายชิ้นที่สังเกตเห็นโพสต์ ไม่ใช่ก่อนเกิดเหตุการณ์ แต่สุดท้ายแล้ว สิ่งที่เรามีก็ทำให้เราทำในสิ่งที่ต้องการได้ ซึ่งก็คือการเฉลิมฉลองอาชีพของ Stanisław Lem และภาพวาดของ Daniel Mróz ในแบบที่เราคิดว่าดีที่สุด
เราหวังว่าข้อมูลข้างต้นจะช่วยอธิบายถึงทางเลือกในการออกแบบและข้อเสียที่ต้องแลกมาบางส่วน รวมถึงวิธีที่เราใช้ HTML5 ในสถานการณ์จริงที่เฉพาะเจาะจง ตอนนี้ลองใช้ซอร์สโค้ด ทดลองใช้ แล้วบอกให้เราทราบถึงสิ่งที่คุณคิด
เราเป็นคนทำเอง วิดีโอด้านล่างนี้เผยแพร่ในช่วงไม่กี่วันที่ผ่านมาเพื่อนับถอยหลังจนถึงช่วงเช้าของวันที่ 23 พฤศจิกายน 2011 ในรัสเซีย ซึ่งเป็นเขตเวลาแรกที่มี Doodle ของ Lem ฟังดูตลกๆ หน่อย แต่เช่นเดียวกับการวาดรูปเรขาคณิต บางครั้งสิ่งที่ดูเหมือนไม่สำคัญก็อาจมีความหมายที่ลึกซึ้งกว่านั้น เครื่องมือนับนี้ถือเป็น "การทดสอบความเครียด" ที่ดีสำหรับเครื่องยนต์

และนี่คือวิธีหนึ่งในการมองชีวิตของ Google Doodle นั่นคือการทำงานเป็นเวลาหลายเดือน การทดสอบเป็นเวลาหลายสัปดาห์ การทดสอบเวอร์ชันที่เสร็จสมบูรณ์เป็นเวลา 48 ชั่วโมง ทั้งหมดนี้เพื่อสิ่งที่ผู้ใช้เล่นเพียง 5 นาที บรรทัด JavaScript หลายพันบรรทัดเหล่านั้นหวังว่า 5 นาทีนั้นจะคุ้มค่า