Thành phố trong chai – hệ thống raycasting 256 byte
(frankforce.com)City In A Bottle – hệ thống raycasting 256 byte
-
Giới thiệu
- Hôm nay giới thiệu một engine raycasting nhỏ và trình tạo thành phố được gói trong một tệp HTML 256 byte.
- Có thể hiểu chương trình này như giải một câu đố, nơi nhiều khái niệm được nén vào một không gian cực nhỏ.
- Các thành phần chính gồm mã HTML, vòng lặp cập nhật khung hình, hệ thống render, engine raycasting và bản thân thành phố.
-
Toàn bộ mã
- Đây không chỉ là một snippet JavaScript đơn giản mà là một chương trình HTML hoàn chỉnh.
-
<canvas style=width:99% id=c onclick=setInterval('for(c.width=w=99,++t,i=6e3;i--;c.getContext`2d`.fillRect(i%w,i/w|0,1-d*Z/w+s,1))for(a=i%w/50-1,s=b=1-i/4e3,X=t,Y=Z=d=1;++Z<w&(Y<6-(32<Z&27<X%w&&X/9^Z/8)*8%46||d|(s=(X&Y&Z)%3/Z,a=b=1,d=Z/w));Y-=b)X+=a',t=9)>
Mã HTML
- Mã HTML
- Phần HTML gồm một phần tử canvas đơn giản và sự kiện onclick.
-
<canvas style=width:99% id=c onclick=setInterval('',t=9)> - Phần tử canvas có id là 'c' để có thể được truy cập từ JavaScript.
- Sự kiện onclick khởi động chương trình và tạo vòng lặp cập nhật thông qua lời gọi setInterval.
Mã JavaScript
-
Mã JavaScript
- Đoạn mã JavaScript dài 199 byte được thực thi khi canvas được nhấp.
-
for(c.width=w=99,++t,i=6e3;i--;c.getContext`2d`.fillRect(i%w,i/w|0,1-d*Z/w+s,1))for(a=i%w/50-1,s=b=1-i/4e3,X=t,Y=Z=d=1;++Z<w&(Y<6-(32<Z&27<X%w&&X/9^Z/8)*8%46||d|(s=(X&Y&Z)%3/Z,a=b=1,d=Z/w));Y-=b)X+=a
-
Phân tích mã
- Mã được tách ra để dễ đọc hơn.
-
c.width = w = 99 ++t for (i = 6e3; i--;){ a = i%w/50 - 1 s = b = 1 - i/4e3 X = t Y = Z = d = 1 for(; ++Z<w & (Y < 6 - (32<Z & 27<X%w && X/9^Z/8)*8%46 || d | (s = (X&Y&Z)%3/Z, a = b = 1, d = Z/w));) { X += a Y -= b } c.getContext`2d`.fillRect(i%w, i/w|0, 1 - d*Z/w + s, 1) }
-
Giải thích mã theo từng bước
c.width = w = 99: khởi tạo canvas và đặt chiều rộng thành 99 pixel.++t: tăng biến thời gian để tạo hoạt ảnh.for (i = 6e3; i--;){}: dùng vòng lặp để quyết định độ sáng của từng pixel.a = i % w / 50 - 1: tính thành phần ngang của vector camera.b = s = 1 - i / 4e3: tính thành phần dọc của vector camera.X = t: dùng giá trị thời gian làm vị trí X ban đầu.Y = Z = d = 1: khởi tạo các giá trị Y, Z và d.for(; ++Z<w & ...;): hệ thống raycasting lặp cho đến khi phát hiện va chạm.c.getContext2d.fillRect(i%w, i/w|0, 1 - d*Z/w + s, 1): vẽ từng pixel để tạo ra hình ảnh cuối cùng.
Học thêm
- Học thêm
- Bản demo này đã được gửi tới demoparty Revision 2022 và có thể xem trên Pouet.
- Có thể xem phiên bản mở rộng thành shader 256 byte trên Shadertoy.
- Công cụ tương tác do Daniel Darabos tạo ra cho phép thao tác nhiều khía cạnh khác nhau của chương trình theo thời gian thực.
Ý kiến của GN⁺
-
Điểm thú vị
- Chương trình này cho thấy cách tạo ra đồ họa phức tạp bằng lượng mã cực nhỏ.
- Chỉ sử dụng những phép toán cơ bản nên ngay cả kỹ sư phần mềm mới vào nghề cũng dễ hiểu.
- Đây là ví dụ tốt về tối ưu hóa mã và chủ nghĩa tối giản, hữu ích trong các cuộc thi như code golf.
-
Góc nhìn phê bình
- Mã được nén rất mạnh nên có thể khó đọc.
- Phù hợp hơn cho mục đích nghệ thuật và thử nghiệm hơn là ứng dụng thực tế.
-
Công nghệ liên quan
- Với các dự án tương tự, có thể xem nhiều ví dụ shader khác nhau trên Shadertoy.
- Cũng có thể khám phá các ví dụ mã nhỏ khác trên những nền tảng như Dwitter.
-
Các điểm cần cân nhắc khi áp dụng công nghệ
- Khi áp dụng kỹ thuật này, cần cân nhắc khả năng đọc và bảo trì của mã.
- Cần nhận thức được những khó khăn về tối ưu hiệu năng và debug khi hiện thực chức năng phức tạp bằng lượng mã nhỏ.
1 bình luận
Ý kiến trên Hacker News
Tóm tắt các bình luận trên Hacker News
Trò chơi pinball 1K bằng JavaScript:
Sinh thủ tục và lazy evaluation:
Ý kiến khác: