Nghiên cứu điển hình - Xây dựng hình tượng trưng trên Google của Stanisław Lem

Marcin Wichary
Marcin Wichary

Xin chào, một thế giới (kỳ lạ)

Trang chủ Google là một môi trường hấp dẫn để bạn lập trình. Trò chơi này đi kèm với nhiều hạn chế thách thức: đặc biệt chú trọng vào tốc độ và độ trễ, phải phục vụ mọi loại trình duyệt và hoạt động trong nhiều tình huống. Vân vậy, thật bất ngờ và thích thú.

Tôi đang nói về Google doodle, các hình minh họa đặc biệt đôi khi thay thế biểu trưng của chúng tôi. Và mặc dù mối quan hệ của tôi với bút và bút đã từ lâu có đặc điểm riêng của lệnh cấm, tôi thường đóng góp cho những hành vi tương tác.

Mọi hình tượng trưng tương tác mà tôi đã lập trình (Pac-Man, Jules Verne, World’s Fair) – và nhiều hình tượng trưng mà tôi đã trợ giúp – đều có tính tương lai và lỗi thời: cơ hội tuyệt vời để ứng dụng các tính năng web tiên tiến... và tính thực dụng nghiêm túc của khả năng tương thích giữa nhiều trình duyệt.

Chúng ta học được rất nhiều điều từ mỗi hình tượng trưng tương tác và trò chơi nhỏ Stanis ưuaw Lem gần đây cũng không ngoại lệ, với 17.000 dòng mã JavaScript đã thử nhiều thứ lần đầu tiên trong lịch sử hình tượng trưng. Hôm nay, tôi muốn chia sẻ mã đó với bạn – có thể bạn sẽ tìm thấy điều gì đó thú vị ở đó hoặc chỉ ra những lỗi của tôi – và nói một chút về nó.

Xem mã hình tượng trưng Stanis ưuaw Lem »

Một điều đáng lưu ý là trang chủ của Google không phải là nơi dành cho các bản minh hoạ công nghệ. Với hình tượng trưng, chúng tôi muốn tôn vinh những người và sự kiện cụ thể. Chúng tôi muốn làm điều đó bằng cách sử dụng nghệ thuật và công nghệ tốt nhất mà chúng tôi có thể áp dụng, nhưng không bao giờ ca ngợi công nghệ vì lợi ích của công nghệ. Điều này có nghĩa là xem xét kỹ bất kỳ phần nào của HTML5 mà mọi người có thể hiểu được, và liệu phần tử này có giúp chúng tôi cải thiện hình tượng trưng mà không bị sao lãng hoặc làm lu mờ hình tượng trưng hay không.

Vì vậy, hãy cùng điểm qua một số công nghệ Web hiện đại đã tìm thấy vị trí của chúng – và một số công nghệ thì không – trong hình tượng trưng Stanis ánh Lem.

Đồ hoạ qua DOM và canvas

Canvas là một công cụ mạnh mẽ và được tạo ra để thực hiện chính xác những việc chúng tôi muốn thực hiện trong hình tượng trưng này. Tuy nhiên, một số trình duyệt cũ mà chúng tôi quan tâm lại không hỗ trợ tính năng này – và mặc dù tôi thực sự đang chia sẻ văn phòng với người đã tạo ra một excanvas tuyệt vời, nhưng tôi vẫn quyết định chọn một cách khác.

Tôi đã kết hợp một công cụ đồ hoạ giúp loại bỏ các ảnh gốc đồ hoạ gốc được gọi là "hình chữ nhật", rồi kết xuất chúng bằng canvas, DOM nếu không có canvas.

Phương pháp này đi kèm với một số thách thức thú vị – ví dụ: việc di chuyển hoặc thay đổi một đối tượng trong DOM sẽ mang lại những kết quả ngay lập tức, trong khi đối với canvas, có một thời điểm cụ thể khi mọi thứ được vẽ cùng một lúc. (Tôi quyết định chỉ có một canvas, sau đó xoá và vẽ từ vết xước ở mọi khung hình. Có quá nhiều phần (theo nghĩa đen) chuyển động một mặt – và mặt khác là không đủ phức tạp để đảm bảo việc chia thành nhiều canvas chồng chéo và cập nhật chúng một cách có chọn lọc.)

Thật không may, việc chuyển sang canvas không đơn giản như việc phản chiếu nền CSS bằng drawImage(): bạn mất một số nội dung miễn phí khi kết hợp các mục với nhau thông qua DOM – quan trọng nhất là xếp lớp với chỉ mục z và sự kiện chuột.

Tôi đã tóm tắt chỉ mục z bằng khái niệm "máy bay". Hình tượng trưng này xác định một số mặt phẳng – từ bầu trời phía xa phía sau, con trỏ chuột ở phía trước mọi vật – và mọi diễn viên trong hình tượng trưng đều phải quyết định xem nó thuộc về mặt nào (có thể có các chỉnh sửa dấu cộng/trừ nhỏ trong một mặt phẳng bằng cách sử dụng planeCorrection).

Kết xuất thông qua DOM, các mặt phẳng chỉ được chuyển đổi sang chỉ mục z. Nhưng nếu kết xuất qua canvas, chúng ta cần sắp xếp các kích cỡ khuôn hình chữ nhật dựa trên mặt phẳng trước khi vẽ. Vì việc thực hiện việc này rất tốn kém, nên thứ tự chỉ được tính toán lại khi một diễn viên được thêm vào hoặc khi đối tượng đó di chuyển sang một mặt phẳng khác.

Đối với các sự kiện liên quan đến chuột, tôi cũng đã tóm tắt về điều đó... đại loại. Đối với cả DOM và canvas, tôi sử dụng thêm các phần tử DOM nổi hoàn toàn trong suốt có chỉ mục z cao, có chức năng chỉ phản ứng với các thao tác di chuột qua/ra, nhấp và nhấn.

Một trong những điều chúng tôi muốn thử với hình tượng trưng này là phá vỡ bức tường thứ tư. Công cụ trên cho phép chúng tôi kết hợp các đối tượng trên canvas với các đối tượng dựa trên DOM. Ví dụ: các vụ nổ trong trận chung kết đều xuất hiện trong canvas đối với các vật thể trong vũ trụ và trong DOM đối với phần còn lại của trang chủ Google. Con chim, thường bay quanh và bị cắt bởi chiếc mặt nạ lởm chởm như bất kỳ diễn viên nào khác, quyết định tránh né rắc rối trong khi quay và ngồi vào nút Xem trang đầu tiên tìm được. Cách thực hiện là để chim rời khỏi canvas và trở thành một thành phần DOM (và ngược lại sau này), mà tôi hy vọng sẽ minh bạch hoàn toàn cho khách truy cập.

Tốc độ khung hình

Việc biết được tốc độ khung hình hiện tại và phản ứng với thời điểm quá chậm (và quá nhanh!) là một phần quan trọng trong công cụ của chúng tôi. Vì trình duyệt không báo cáo lại tốc độ khung hình, nên chúng tôi phải tự tính toán.

Tôi đã bắt đầu bằng việc sử dụng requestAnimationFrame, quay lại sử dụng setTimeout lỗi thời nếu không có sẵn. requestAnimationFrame khéo léo tiết kiệm CPU trong một số trường hợp – mặc dù chúng tôi đang tự làm một số việc đó, như sẽ được giải thích dưới đây, nhưng cũng chỉ đơn giản là cho phép chúng ta có được tốc độ khung hình cao hơn setTimeout.

Việc tính tốc độ khung hình hiện tại rất đơn giản nhưng có thể thay đổi đáng kể – ví dụ: tốc độ này có thể giảm nhanh khi một ứng dụng khác sử dụng máy tính trong một thời gian. Do đó, chúng tôi chỉ tính toán tốc độ khung hình "lộn" (trung bình) trên mỗi 100 kim đánh dấu nhịp độ khung hình vật lý và đưa ra quyết định dựa trên điều đó.

Loại quyết định nào?

  • Nếu tốc độ khung hình cao hơn 60 khung hình/giây, chúng tôi sẽ điều tiết tốc độ đó. Hiện tại, requestAnimationFrame trên một số phiên bản Firefox không có giới hạn cao hơn về tốc độ khung hình và không có lý do gì để lãng phí CPU. Xin lưu ý rằng chúng tôi thực sự giới hạn ở 65 khung hình/giây, vì các lỗi làm tròn khiến tốc độ khung hình chỉ cao hơn một chút so với 60 khung hình/giây trên các trình duyệt khác – chúng tôi không muốn bắt đầu điều tiết do nhầm lẫn.

  • Nếu tốc độ khung hình thấp hơn 10 khung hình/giây, chúng tôi chỉ cần giảm tốc độ động cơ thay vì giảm khung hình. Đó là một tuyên bố thua cuộc, nhưng tôi cảm thấy rằng việc bỏ qua khung hình quá mức sẽ gây nhầm lẫn hơn là chỉ chơi một trò chơi chậm hơn (nhưng vẫn nhất quán). Việc này còn có một tác dụng phụ khá thú vị nữa – nếu hệ thống tạm thời bị chậm, người dùng sẽ không gặp phải tình trạng "nhảy" kỳ lạ vì công cụ bắt kịp tốc độ. (Tôi đã làm hơi khác với Pac-Man, nhưng tốc độ khung hình tối thiểu là phương pháp tốt hơn.)

  • Cuối cùng, chúng ta có thể xem xét việc đơn giản hoá đồ hoạ khi tốc độ khung hình bị thấp một cách nguy hiểm. Chúng tôi sẽ không làm điều đó cho hình tượng trưng Lem ngoại trừ con trỏ chuột (tìm hiểu thêm về nội dung này bên dưới), nhưng giả thuyết chúng tôi có thể mất một số ảnh động không liên quan chỉ để hình tượng trưng trông linh hoạt ngay cả trên các máy tính chậm hơn.

Chúng ta cũng có khái niệm về kim đánh dấu nhịp độ khung hình và kim đánh dấu nhịp độ logic. Dữ liệu đầu tiên đến từ requestAnimationFrame/setTimeout. Tỷ lệ trong lối chơi thông thường là 1:1, nhưng để tua đi, chúng ta chỉ cần thêm nhiều dấu tích hợp lý hơn trên mỗi dấu tích vật lý (tối đa 1:5). Điều này cho phép chúng tôi thực hiện mọi phép tính cần thiết cho mọi kim đánh dấu nhịp độ khung hình logic, nhưng chỉ chỉ định công cụ cuối cùng là giá trị cập nhật nội dung trên màn hình.

Đo điểm chuẩn

Có một giả định (và thực sự, ngay từ sớm) đã được đưa ra rằng canvas sẽ nhanh hơn DOM bất cứ khi nào có sẵn. Không phải lúc nào điều này cũng đúng. Trong khi thử nghiệm, chúng tôi nhận thấy rằng Opera 10.0–10.1 trên máy Mac và Firefox trên Linux thực sự nhanh hơn khi di chuyển các phần tử DOM.

Trong thế giới hoàn hảo, hình tượng trưng sẽ ngầm điểm chuẩn các kỹ thuật đồ hoạ khác nhau – các thành phần DOM di chuyển bằng cách sử dụng style.leftstyle.top, vẽ trên canvas và thậm chí có thể là các thành phần DOM di chuyển bằng cách biến đổi CSS3

– rồi chuyển sang bất kỳ định dạng nào có tốc độ khung hình cao nhất. Tôi đã bắt đầu viết mã cho chương trình đó, nhưng nhận thấy rằng ít nhất cách đo điểm chuẩn của tôi khá không đáng tin cậy và cần nhiều thời gian. Thời gian mà chúng tôi chưa có trên trang chủ của mình – chúng tôi quan tâm rất nhiều đến tốc độ và chúng tôi muốn hình tượng trưng hiển thị ngay lập tức và lối chơi bắt đầu ngay khi bạn nhấp hoặc nhấn.

Cuối cùng, đôi khi việc phát triển web chỉ cần làm những gì bạn phải làm. Tôi nhìn sau vai để đảm bảo không có ai nhìn, sau đó tôi mã hóa cứng Opera 10 và Firefox trên canvas. Trong lần tới, tôi sẽ sử dụng lại dưới dạng thẻ <marquee>.

Tiết kiệm CPU

Bạn có biết một người bạn đến nhà bạn, xem tập cuối của bộ phim Break Bad, phá hoại và sau đó xoá nội dung đó khỏi DVR không? Em không muốn trở thành người đó, đúng không?

Vâng, sự tương đồng tệ nhất từ trước đến nay. Nhưng chúng tôi cũng không muốn hình tượng trưng của mình là như vậy – việc chúng tôi được phép xuất hiện trên thẻ trình duyệt của ai đó là một đặc quyền và việc tích trữ chu kỳ CPU hoặc làm mất tập trung người dùng sẽ khiến chúng tôi trở thành một vị khách khó chịu. Do đó, nếu không có ai đang chơi với hình tượng trưng (không nhấn, nhấp chuột, di chuyển chuột hoặc nhấn phím), chúng ta muốn hình tượng trưng đó chuyển sang chế độ ngủ.

Khoảng thời gian đó là khi nào?

  • sau 18 giây trên trang chủ (trò chơi trò chơi gọi là chế độ thu hút)
  • sau 180 giây nếu thẻ có tiêu điểm
  • sau 30 giây nếu tab không có tiêu điểm (ví dụ: người dùng chuyển sang cửa sổ khác, nhưng có lẽ vẫn đang xem hình tượng trưng hiện tại trong một thẻ không hoạt động)
  • ngay lập tức nếu thẻ không hiển thị (ví dụ: người dùng chuyển sang một thẻ khác trong cùng một cửa sổ – sẽ không có thời điểm lãng phí chu kỳ nếu chúng tôi không thể nhìn thấy)

Làm cách nào để biết thẻ hiện có tiêu điểm? Chúng ta tự đính kèm vào window.focuswindow.blur. Làm cách nào để biết thẻ này có hiển thị? Chúng tôi đang sử dụng Page Visibility API mới và phản ứng với sự kiện thích hợp.

Thời gian ngừng hoạt động nêu trên dễ khiến chúng tôi bỏ qua hơn bình thường. Tôi đã điều chỉnh chúng cho phù hợp với hình tượng trưng cụ thể này, có rất nhiều ảnh động xung quanh (chủ yếu là bầu trời và chim). Lý tưởng nhất là phải giới hạn thời gian tương tác trong trò chơi – ví dụ: ngay sau khi hạ cánh, chú chim có thể báo cáo lại với hình tượng trưng rằng nó có thể đi ngủ – nhưng cuối cùng tôi đã không thực hiện việc đó.

Do bầu trời luôn chuyển động, nên khi chìm vào giấc ngủ và đánh thức hình tượng trưng không chỉ dừng lại hay bắt đầu lại – nó sẽ chậm lại trước khi tạm dừng và ngược lại để tiếp tục, tăng hoặc giảm số kim đánh dấu nhịp độ khung hình trên mỗi kim đánh dấu vật lý (nếu cần).

Chuyển cảnh, biến đổi, sự kiện

Một trong những sức mạnh của HTML luôn là thực tế là bạn có thể tự cải thiện: nếu có thứ gì không đủ tốt trong danh mục HTML và CSS thông thường, bạn có thể lôi kéo JavaScript vào việc mở rộng nó. Thật không may, đôi khi việc này có nghĩa là phải bắt đầu lại từ đầu. Hiệu ứng chuyển đổi CSS3 rất hiệu quả, nhưng bạn không thể thêm loại chuyển đổi mới hoặc sử dụng hiệu ứng chuyển đổi để làm bất cứ điều gì khác ngoài các phần tử định kiểu. Một ví dụ khác: Phép biến đổi CSS3 rất hiệu quả đối với DOM, nhưng khi chuyển sang canvas, bạn sẽ đột nhiên tự di chuyển mình.

Những vấn đề này và nhiều vấn đề khác là lý do tại sao Lem doodle có công cụ chuyển đổi và biến đổi riêng. Vâng, tôi biết, những năm 2000 đã được gọi, v.v. – các tính năng tôi tích hợp không mạnh bằng CSS3, nhưng bất kể công cụ có làm gì, nó vẫn nhất quán và cho chúng tôi nhiều quyền kiểm soát hơn.

Tôi đã bắt đầu bằng một hệ thống hành động (event) đơn giản – dòng thời gian kích hoạt các sự kiện trong tương lai mà không sử dụng setTimeout, vì tại một thời điểm cụ thể, thời gian vẽ hình tượng trưng có thể tách khỏi thời gian thực khi tải nhanh hơn, chậm hơn (tốc độ khung hình thấp hoặc chìm vào giấc ngủ để tiết kiệm CPU) hoặc dừng hoàn toàn (chờ hình ảnh tải xong).

Chuyển đổi chỉ là một loại hành động khác. Ngoài các chuyển động và xoay cơ bản, chúng tôi cũng hỗ trợ chuyển động tương đối (ví dụ: di chuyển 10 pixel sang phải), những tuỳ chỉnh như rung lắc và cả ảnh động hình ảnh trên khung hình chính.

Tôi đã đề cập đến việc xoay và việc xoay cũng được thực hiện theo cách thủ công: chúng tôi có các sprite cho các góc khác nhau cho các đối tượng cần được xoay. Lý do chính là cả chế độ xoay CSS3 và canvas đều giới thiệu các cấu phần phần mềm trực quan mà chúng tôi không chấp nhận được – và hơn nữa, những cấu phần phần mềm đó lại thay đổi tuỳ theo nền tảng.

Do một số đối tượng xoay được gắn vào các đối tượng xoay khác – ví dụ như bàn tay của robot được nối với cánh tay dưới, vốn được gắn vào cánh tay trên xoay – điều này có nghĩa là tôi cũng phải tạo nguồn gốc biến đổi của một người đàn ông kém dưới dạng trục.

Tất cả đây là một khối lượng công việc vững chắc cuối cùng bao quát nền tảng mà HTML5 đã xử lý – nhưng đôi khi dịch vụ hỗ trợ gốc chưa đủ tốt và đã đến lúc chúng tôi phát minh lại những gì cần thiết.

Xử lý hình ảnh và sprite

Công cụ không chỉ dùng để chạy hình tượng trưng, mà còn dùng để xử lý hình tượng trưng. Tôi đã chia sẻ một số thông số gỡ lỗi ở trên: bạn có thể tìm thấy phần còn lại trong engine.readDebugParams.

Tạo hình vẽ là một kỹ thuật phổ biến mà chúng tôi cũng sử dụng cho các hình tượng trưng. API này cho phép chúng ta tiết kiệm byte và giảm thời gian tải, đồng thời giúp tải trước dễ dàng hơn. Tuy nhiên, điều này cũng khiến việc phát triển khó khăn hơn – mọi thay đổi đối với hình ảnh sẽ yêu cầu phải tái tạo (phần lớn được tự động hoá nhưng vẫn rườm rà). Do đó, công cụ này hỗ trợ chạy trên các hình ảnh thô để phát triển cũng như các sprite để sản xuất thông qua engine.useSprites – cả hai đều được đi kèm với mã nguồn.

Hình tượng trưng của Pac-Man
Sprit được sử dụng trong hình tượng trưng của Pac-Man.

Chúng tôi cũng hỗ trợ tải trước hình ảnh khi tiếp tục và tạm dừng hình tượng trưng nếu hình ảnh không tải kịp thời – hoàn thiện với thanh tiến trình giả! (Giả mạo vì rất tiếc, ngay cả HTML5 cũng không thể cho chúng tôi biết tệp hình ảnh đã được tải bao nhiêu.)

Ảnh chụp màn hình về quá trình tải đồ hoạ với thanh tiến trình được quản lý.
Ảnh chụp màn hình quá trình tải đồ hoạ với thanh tiến trình được kiểm soát.

Đối với một số cảnh, chúng tôi sử dụng nhiều sprite không nhiều để tăng tốc độ tải bằng các kết nối song song, mà chỉ đơn giản là vì giới hạn 3/5 triệu pixel đối với hình ảnh trên iOS.

HTML5 phù hợp với tất cả những yếu tố này ở đâu? Chưa có nhiều chủ đề ở trên, nhưng công cụ mà tôi viết cho tính năng phân nhánh/cắt lại hoàn toàn là Công nghệ web mới: canvas, blobs, a[tải xuống]. Một trong những điều thú vị về HTML là phần phụ trợ chậm những việc trước đây phải thực hiện bên ngoài trình duyệt; phần duy nhất chúng tôi cần làm là tối ưu hoá tệp PNG.

Lưu trạng thái giữa các trò chơi

Thế giới của Lem luôn rộng lớn, sống động và chân thực. Những câu chuyện của ông thường bắt đầu mà không có nhiều lời giải thích, trang đầu tiên bắt đầu bằng nội dung truyền thông, trong đó người đọc phải tìm ra bản thân mình hoặc tìm ra cách riêng.

Cyberiad cũng không phải là ngoại lệ và chúng tôi muốn lặp lại cảm giác đó đối với hình tượng trưng. Chúng tôi bắt đầu với việc cố gắng không giải thích quá mức câu chuyện. Một vấn đề lớn khác là việc sắp xếp ngẫu nhiên mà chúng tôi cho rằng tính chất cơ học của vũ trụ của cuốn sách là phù hợp; chúng tôi có một số chức năng trợ giúp xử lý tính ngẫu nhiên mà chúng tôi sử dụng ở nhiều nơi.

Chúng tôi cũng muốn tăng khả năng phát lại theo những cách khác. Để làm được điều đó, chúng tôi cần biết hình tượng trưng trước đó bao nhiêu lần đã hoàn thành. Giải pháp công nghệ chính xác trước đây là một cookie, nhưng không phù hợp với trang chủ của Google – mọi cookie đều tăng tải trọng của mỗi trang, và một lần nữa, chúng tôi quan tâm nhiều đến tốc độ và độ trễ.

May mắn thay, HTML5 cung cấp cho chúng tôi Bộ nhớ trên web, một cách đơn giản để sử dụng, cho phép chúng tôi lưu và truy lại số lượt phát chung và cảnh người dùng chơi gần đây nhất – với nhiều nội dung hơn so với những gì mà cookie cho phép.

Chúng tôi làm gì với thông tin này?

  • chúng tôi sẽ hiển thị một nút tua đi, cho phép cuộn qua các đoạn phim cắt cảnh mà người dùng đã xem trước đó
  • chúng tôi sẽ cho khán giả xem N mục khác nhau trong đêm chung kết
  • chúng tôi tăng độ khó của cấp độ bắn một chút
  • chúng tôi sẽ chiếu một con rồng có xác suất của trứng phục sinh từ một câu chuyện khác trong các lượt chơi thứ ba và tiếp theo của bạn

Có một số thông số gỡ lỗi kiểm soát việc này:

  • ?doodle-debug&doodle-first-run – giả sử đó là lần chạy đầu tiên
  • ?doodle-debug&doodle-second-run – giả sử đó là lần chạy thứ hai
  • ?doodle-debug&doodle-old-run – hãy giả vờ như đó là một phiên bản cũ

Thiết bị cảm ứng

Chúng tôi muốn hình tượng trưng cảm thấy ngay tại nhà trên các thiết bị cảm ứng – các hình tượng trưng hiện đại nhất đủ mạnh mẽ để hình tượng trưng chạy thực sự tốt và việc trải nghiệm trò chơi thông qua thao tác nhấn sẽ thú vị hơn nhiều so với nhấp chuột.

Một số thay đổi trước đối với trải nghiệm người dùng cần được thực hiện. Ban đầu, con trỏ chuột là nơi duy nhất diễn ra phần cắt cảnh/không tương tác. Sau đó, chúng tôi đã thêm một chỉ báo nhỏ ở góc dưới bên phải, vì vậy, chúng tôi không phải chỉ dựa vào con trỏ chuột (vì những chỉ báo đó không tồn tại trên thiết bị cảm ứng).

Bình thường Bận Nhấp vào được Đã nhấp
Đang tiến hành
Con trỏ thông thường đang tiến hành
Con trỏ bận đang tiến hành
Con trỏ có thể nhấp đang tiến hành
Con trỏ đã nhấp đang tiến hành
Cuối cùng
Con trỏ thường cuối cùngv
Con trỏ bận cuối cùng
Con trỏ có thể nhấp cuối cùng
Con trỏ được nhấp cuối cùng
Con trỏ chuột trong quá trình phát triển và các thành phần tương đương cuối cùng.

Hầu hết mọi thứ đều hoạt động hiệu quả. Tuy nhiên, các bài kiểm tra khả năng hữu dụng nhanh trong trải nghiệm chạm của chúng tôi cho thấy hai vấn đề: một số mục tiêu quá khó nhấn, còn thao tác nhấn nhanh đã bị bỏ qua vì chúng tôi chỉ ghi đè các sự kiện nhấp chuột.

Việc có các phần tử DOM trong suốt riêng biệt có thể nhấp vào đã giúp ích rất nhiều ở đây, vì tôi có thể đổi kích thước các phần tử đó một cách độc lập với hình ảnh. Tôi đã ra mắt khoảng đệm bổ sung 15 pixel cho các thiết bị cảm ứng và sử dụng khoảng đệm này bất cứ khi nào các phần tử có thể nhấp được tạo. (Tôi cũng đã thêm khoảng đệm 5 pixel cho môi trường chuột, chỉ để làm cho anh Fitts hài lòng.)

Đối với vấn đề còn lại, tôi chỉ đảm bảo sẽ đính kèm và kiểm thử trình xử lý kết thúc và khởi động thao tác chạm phù hợp, thay vì dựa vào thao tác nhấp chuột.

Chúng tôi cũng sử dụng các thuộc tính kiểu hiện đại hơn để loại bỏ một số tính năng cảm ứng mà trình duyệt WebKit thêm theo mặc định (nhấn vào làm nổi bật, nhấn vào chú thích).

Và làm cách nào để chúng ta phát hiện xem một thiết bị cụ thể đang chạy hình tượng trưng có hỗ trợ thao tác chạm hay không? lười biếng. Thay vì tìm hiểu mức độ ưu tiên, chúng tôi chỉ sử dụng các bài IQ kết hợp để suy ra việc thiết bị hỗ trợ thao tác chạm... sau khi nhận được sự kiện bắt đầu chạm đầu tiên.

Tuỳ chỉnh con trỏ chuột

Tuy nhiên, không phải mọi thứ đều dựa trên thao tác chạm. Một trong những nguyên tắc định hướng của chúng tôi là đưa nhiều nội dung nhất có thể vào trong vũ trụ của hình tượng trưng. Giao diện người dùng nhỏ ở thanh bên (Tua đi, dấu chấm hỏi), chú giải công cụ và thậm chí là cả con trỏ chuột.

Cách tuỳ chỉnh con trỏ chuột? Một số trình duyệt cho phép thay đổi con trỏ chuột bằng cách liên kết đến một tệp hình ảnh đặt trước. Tuy nhiên, cách này không được hỗ trợ hiệu quả và cũng có phần hạn chế.

Nếu không phải cái này thì sao? Chà, tại sao không làm con trỏ chuột chỉ là một diễn viên khác trong hình tượng trưng? Cách này hiệu quả, nhưng chủ yếu đi kèm một số điều cần lưu ý:

  • bạn cần xoá được con trỏ chuột gốc
  • bạn cần phải khá giỏi trong việc giữ con trỏ chuột đồng bộ với con trỏ "thực"

Bước đầu tiên khá phức tạp. CSS3 cho phép cursor: none, nhưng một số trình duyệt không hỗ trợ thuộc tính này. Chúng tôi cần phải dùng đến một số môn thể dục dụng cụ: dùng tệp .cur trống làm phương án dự phòng, chỉ định hành vi cụ thể cho một số trình duyệt và thậm chí là mã hoá cứng những trình duyệt khác ra khỏi trải nghiệm.

Hình tượng trưng còn lại tương đối nhỏ, nhưng con trỏ chuột chỉ là một phần khác của vũ trụ của hình tượng trưng, nó cũng sẽ kế thừa tất cả vấn đề. Sự kiện lớn nhất? Nếu tốc độ khung hình của hình tượng trưng thấp, thì tốc độ khung hình của con trỏ chuột cũng sẽ thấp – và điều này gây ra những hậu quả nghiêm trọng vì con trỏ chuột (là một phần mở rộng tự nhiên của bàn tay) cần phải phản hồi nhanh cho dù có xảy ra điều gì. (Những người đã sử dụng Commodore Amiga trước đây giờ đây đều gật gù một cách mạnh mẽ.)

Một giải pháp hơi phức tạp cho vấn đề đó là tách con trỏ chuột khỏi vòng lặp cập nhật thông thường. Chúng tôi đã làm được điều đó – trong một vũ trụ thay thế nơi tôi không cần ngủ. Giải pháp đơn giản hơn cho vấn đề này? Chỉ cần quay lại con trỏ chuột gốc nếu tốc độ khung hình đổ xúc xắc giảm xuống dưới 20 khung hình/giây. (Đây là lúc tốc độ khung hình cuộn phát huy tác dụng. Nếu chúng tôi phản ứng với tốc độ khung hình hiện tại và nếu tốc độ đó dao động khoảng 20 khung hình/giây, thì người dùng sẽ thấy con trỏ chuột tuỳ chỉnh ẩn và luôn hiện.) Điều này đưa chúng tôi đến:

Phạm vi tốc độ khung hình Hành vi
>10 khung hình/giây Giảm tốc độ trò chơi để không giảm nhiều khung hình hơn.
10 – 20 khung hình/giây Sử dụng con trỏ chuột gốc thay vì con trỏ tuỳ chỉnh.
20 – 60 khung hình/giây Hoạt động bình thường.
>60 khung hình/giây Điều chỉnh để tốc độ khung hình không vượt quá giá trị này.
Tóm tắt về hành vi phụ thuộc vào tốc độ khung hình.

Ồ, con trỏ chuột trên máy Mac thì tối, nhưng lại có màu trắng trên máy tính. Vì sao lại như vậy? Bởi vì các cuộc chiến trên nền tảng cần nhiên liệu ngay cả trong vũ trụ hư cấu.

Kết luận

Đây không phải là một công cụ hoàn hảo, nhưng cũng không thể trở thành một công cụ như vậy. Biểu tượng này được phát triển cùng với hình tượng trưng Lem và rất đặc trưng. Không sao cả. "Tối ưu hoá sớm là gốc rễ của mọi cái ác", như Don Knuth nổi tiếng. Và tôi không tin rằng trước tiên việc viết một công cụ một cách riêng biệt mà sau đó chỉ áp dụng nó mới hợp lý – thực hành cung cấp cho lý thuyết nhiều như lý thuyết cũng như để áp dụng cho thực tiễn. Trong trường hợp của tôi, mã bị loại bỏ, một số phần được viết lại nhiều lần và nhiều phần phổ biến được ghi nhận sau khi đăng, thay vì thực tế. Nhưng cuối cùng, những gì chúng tôi có ở đây đã cho phép chúng tôi làm điều mình muốn – hãy tôn vinh sự nghiệp của Stanis ưuaw Lem và các bức vẽ của Daniel Mróz theo cách tốt nhất mà chúng tôi có thể nghĩ đến.

Tôi hy vọng những điều trên đã làm sáng tỏ một số lựa chọn và lựa chọn đánh đổi về thiết kế mà chúng tôi cần thực hiện – cũng như cách chúng tôi sử dụng HTML5 trong tình huống thực tế cụ thể. Bây giờ, hãy thử với mã nguồn, dùng thử và cho chúng tôi biết suy nghĩ của bạn.

Tôi đã tự làm điều đó – sự kiện dưới đây đã diễn ra vào những ngày cuối cùng, đếm ngược đến đầu giờ sáng ngày 23 tháng 11 năm 2011 ở Nga, là múi giờ đầu tiên thấy hình tượng trưng Lem. Có lẽ là một điều ngốc nghếch, nhưng cũng giống như hình tượng trưng, những thứ trông có vẻ không đáng kể đôi khi lại có ý nghĩa sâu sắc hơn – bộ đếm này thực sự là một "bài kiểm tra căng thẳng" tuyệt vời cho công cụ.

Ảnh chụp màn hình đồng hồ đếm ngược trong vũ trụ Lem doodle.
Ảnh chụp màn hình đồng hồ đếm ngược trong vũ trụ Lem doodle.

Đó là một cách để thấy được cuộc sống của hình tượng trưng của Google – nhiều tháng làm việc, nhiều tuần thử nghiệm, 48 giờ làm việc, tất cả đều dành cho một trò chơi mà mọi người chơi trong 5 phút. Mỗi một trong số hàng nghìn dòng JavaScript đó đều hy vọng 5 phút đó sẽ giúp bạn sử dụng hiệu quả. Chúc bạn có những phút giây giải trí vui vẻ.