Giới thiệu
Sau khoảng 20 tuần (8–10 giờ mỗi tuần), học viên tự làm được một game xây dựng thuộc địa 3D chạy trên trình duyệt, 2–4 người chơi cùng lúc qua mạng, có lưu game và có bản chạy thật cho bạn bè chơi.
Giáo trình đi theo đúng cách Thương Cảng 1800 (bản làm lại Anno 1800 nhiều người chơi) được làm: một mô phỏng tất định chạy y hệt trên server và mọi máy, Three.js để vẽ, React cho giao diện, kiểm thử tự động ở mọi tầng.
Dành cho ai: người đã biết lập trình cơ bản (biến, hàm, vòng lặp, mảng, đối tượng) bằng một ngôn ngữ bất kỳ. Không cần biết trước đồ hoạ 3D, lập trình mạng hay làm game.
Học xong làm được:
- Viết mô phỏng tất định: cùng chuỗi lệnh vào thì mọi máy ra cùng trạng thái, tới từng bit.
- Thiết kế luật kinh tế xây dựng (chuỗi sản xuất, dân, nhu cầu, thuế) và cân bằng nó bằng người chơi giả lập.
- Vẽ thế giới 3D hàng trăm công trình vẫn mượt, kể cả trên điện thoại.
- Dựng server nhiều người chơi kiểu lockstep, phát hiện và tự sửa khi các máy lệch nhau.
- Nâng cấp định dạng save mà không làm mất thế giới của người chơi.
- Kiểm thử, phát hành, sao lưu và quay lại bản cũ khi có sự cố.
Cách học: cả khoá xây một game nhỏ xuyên suốt tên Bến Nhỏ: một đảo, một tàu, 6–8 loại công trình, chuỗi gỗ → ván → nhà. Mỗi phần kết thúc bằng một mốc chạy được của Bến Nhỏ. Mục "Trong Thương Cảng 1800" ở mỗi phần cho thấy bản đầy đủ làm cùng việc đó ra sao; nên chơi thử game này vài giờ trước khi bắt đầu.
Mỗi phần gồm: mục tiêu, kiến thức cần học, bài thực hành (mốc của Bến Nhỏ), bẫy thường gặp.
Lộ trình tổng quan
Khoá học kéo dài 20 tuần; mỗi phần kết thúc bằng một mốc chạy được của Bến Nhỏ, còn kiểm thử và làm việc cùng AI đi xuyên suốt từ tuần 3.
Vuốt ngang để xem hết sơ đồ →
Phần 0 — Nền tảng tuần 1–2
Mục tiêu: dựng một repo gồm 4 gói, chạy một lệnh là thấy trang web hiện số tick và server trả lời qua WebSocket. Kiến trúc đặt đúng từ tuần 1 rẻ hơn nhiều so với tách lại sau.
Kiến thức:
- TypeScript ở chế độ
strict: kiểu, union,readonly, generic cơ bản. Game lớn sống nhờ trình biên dịch bắt lỗi trước người chơi. - Node.js, ES module, pnpm workspace (nhiều gói trong một repo, dùng chung mã).
- Vite: máy chủ dev, build, proxy WebSocket sang server.
- Git: nhánh, commit nhỏ, tag cho mỗi bản phát hành.
Cấu trúc dựng ngay từ đầu:
| Gói | Vai trò | Chạy ở đâu |
|---|---|---|
sim | Luật chơi; không biết gì về màn hình hay mạng | Server và mọi client |
protocol | Kiểu tin nhắn, kiểm tra dữ liệu từ client | Server và client |
server | Phòng chơi, xếp thứ tự lệnh, lưu save, phục vụ file | Node.js |
client | Vẽ 3D, giao diện, nhập liệu | Trình duyệt |
Quy tắc vàng: sim không import từ client hay server, không đụng DOM, Date hay Math.random.
Thực hành — mốc 0:
- Tạo monorepo pnpm với 4 gói trên.
simcó hàmstep(state)tăngtick, kèm một test vitest.client(Vite + React) hiện số tick;server(thư việnws) trả "pong".pnpm typecheck && pnpm testchạy xanh; từ nay mọi commit đều qua hai lệnh này.
Phần 1 — Mô phỏng tất định tuần 3–5
Cùng trạng thái đầu và cùng chuỗi lệnh phải luôn cho ra cùng trạng thái sau, trên mọi máy. Khi đạt được điều này, mạng chỉ cần gửi lệnh chứ không gửi cả thế giới. Đây là phần quan trọng nhất; mọi phần sau dựa vào nó.
Mục tiêu: sim của Bến Nhỏ chạy không cần màn hình, nhận lệnh, tiến theo tick 100 ms, có snapshot(), load() và hash(). Hai bản chạy song song luôn cho cùng hash.
Kiến thức:
- Vòng lặp theo tick cố định: luật chạy 10 tick/giây, hình vẽ 60 khung/giây, nội suy giữa hai tick.
- Lệnh là cách duy nhất đổi trạng thái:
step(cmds). Lệnh là dữ liệu JSON thuần, không phải hàm. - ECS: entity là một id chuỗi (
b12), component là bản ghi dữ liệu, system là hàm chạy mỗi tick. Dùng thư viện kho (atom, component,system,scope) hoặc tự viết bản tối giản trước để hiểu. - Tất định: chỉ số nguyên (tỉ lệ tính bằng phần nghìn ‰); không
Math.random,Date.now,Math.sin/costrong tick; duyệt Map/Set theo thứ tự chèn, sort khoá khi cần. - Ngẫu nhiên tất định: băm (seed, tick, id, loại) ra số nguyên, thay vì một bộ sinh số có trạng thái.
- Snapshot và hash: serializer tường minh, thứ tự field cố định; hash dùng chính serializer đó.
// Cùng đầu vào → cùng kết quả trên mọi máy
const roll = hashU32(seed, tick, n, KIND_FISH) % 1000; // 0…999
if (roll < chancePerMille) catchFish();
const out = Math.floor((stock * productivity) / 1000); // productivity tính bằng ‰
Thực hành — mốc 1:
- Trạng thái: lưới 64×64 (nước/đất), công trình, kho hàng, vàng.
- Lệnh
place {kind, x, y, rot}vàdemolish {id}; system sản xuất: tiều phu ra 1 gỗ mỗi N tick. snapshot()ra JSON,load(json),hash().- Test "live vs loaded": game A chạy 500 tick với lệnh ngẫu nhiên (seed cố định); giữa chừng nạp snapshot của A vào game B; chạy tiếp cả hai cùng lệnh; hash phải bằng nhau sau 1 và sau 100 tick.
Phần 2 — Luật chơi xây dựng và cân bằng tuần 6–8
Một game xây dựng hay nhờ vòng lặp rõ ràng: xây → sản xuất → dân được đáp ứng → thuế → xây tiếp. Phần này dạy viết vòng lặp đó thành dữ liệu và kiểm tra nó bằng người chơi giả lập, trước khi có hình vẽ nào.
Mục tiêu: Bến Nhỏ chơi được — bằng bot, trong terminal. Một người chơi giả lập đạt 50 dân trong 10–15 phút game và không bao giờ âm tiền.
Kiến thức:
- Định nghĩa bằng dữ liệu: bảng
GOODS,BUILDINGS(kích thước, chi phí, duy trì, đầu vào/đầu ra, chu kỳ),TIERS(nhu cầu, thuế). Thêm nội dung = thêm một dòng, không thêm code. - Đặt công trình trên lưới: xoay, ô bị chiếm, luật địa hình (ven biển, trên mỏ). Một hàm kiểm tra trả về lý do (
notOwned,needsCoast) để giao diện có chữ giải thích. - Đường và kết nối: BFS từ kho cảng; công trình không nối đường thì không chạy.
- Chuỗi sản xuất: bộ đệm vào/ra nhỏ, xe hàng chở về kho theo chu kỳ; lý do ngừng có thứ tự cố định (thiếu đường → thiếu đầu vào → kho đầy).
- Dân và nhu cầu: nhà lớn dần khi được đáp ứng; mức đáp ứng tính bằng ‰; thuế tính bằng milli-vàng để không mất phần lẻ.
- Cân bằng: đặt cửa sổ mục tiêu ("100 dân ở phút 8–14") rồi đo bằng bot, không cân bằng bằng cảm giác.
Thực hành — mốc 2:
- Viết
defs/cho 6–8 công trình: kho cảng, nhà, tiều phu, xưởng cưa, ngư trại, chợ, đường. - Viết
checkPlacementtrả lý do và test từng lý do. - Viết bot
newcomerchỉ gửi lệnh thường, mỗi 5 giây game một thao tác. - In bảng theo phút: vàng, thu/chi, dân, kho, công trình nhàn rỗi. Chỉnh
defs/tới khi bot lọt cửa sổ mục tiêu, rồi biến cửa sổ đó thành test.
Phần 3 — Đồ hoạ 3D với Three.js tuần 9–11
Hình vẽ chỉ đọc trạng thái của sim và gửi lệnh; nó không bao giờ tự sửa thế giới. Giữ được ranh giới này thì đồ hoạ có thể đổi thoải mái mà không làm lệch mạng.
Mục tiêu: thấy đảo của Bến Nhỏ trong 3D, đặt công trình bằng chuột, 500 công trình vẫn giữ 60 khung/giây.
Kiến thức:
- Cơ bản Three.js: scene, camera, renderer, ánh sáng, bóng đổ, vật liệu.
- Camera kiểu game chiến thuật: kéo để di chuyển, cuộn để zoom, xoay quanh một điểm, giới hạn góc nghiêng.
- Địa hình từ lưới: dựng mesh từ mảng ô; làm mượt bờ biển nhưng tâm mỗi ô nước vẫn phải là nước đúng như sim.
- Model GLB: tải bằng
GLTFLoader, nén meshopt, nguồn CC0 (Kenney, Quaternius); ghi công tác giả ngay khi thêm. - Vẽ nhiều vật:
InstancedMesh/BatchedMeshđể hàng trăm công trình chỉ tốn vài chục draw call. - Chọn vật (picking): từ chuột ra tia, giao với mặt phẳng đất rồi đổi ra toạ độ ô; bóng ma xanh/đỏ dùng chính hàm kiểm tra của sim.
- Nội suy: tàu và xe hàng di chuyển mượt giữa hai tick.
- Đo đạc: draw call, số tam giác, thời gian khung (
renderer.info, DevTools Performance).
Thực hành — mốc 3:
- Render system đọc trạng thái sim mỗi khung, không giữ bản sao riêng.
- Đảo từ lưới 64×64, nước có màu theo độ sâu.
- Bóng ma công trình theo chuột, bấm để gửi lệnh
place, phím R để xoay. - Cảnh thử 500 công trình: ghi lại draw call và thời gian khung trước và sau khi dùng instancing.
Phần 4 — Giao diện và nhập liệu tuần 12–13
Giao diện (HUD) là nơi người chơi hiểu luật: vì sao xưởng đứng, thiếu gì, bấm đâu. Chuột, cảm ứng và tay cầm đều phải đi qua một bộ hành động chung, nếu không mỗi thiết bị sẽ lệch luật một kiểu.
Mục tiêu: HUD của Bến Nhỏ có thanh vàng/dân/hàng, menu xây dựng, bảng thông tin công trình; chơi được bằng chuột và bằng điện thoại.
Kiến thức:
- React: component, state, hook; tách store giao diện (phòng, công cụ đang chọn) khỏi store game (tạo lại mỗi lần nạp snapshot).
- Đọc trạng thái game có tiết chế (throttle), không render lại React 10 lần/giây.
- Đa ngôn ngữ: mọi chữ qua
t(); file tiếng Việt là chuẩn, file tiếng Anh bị TypeScript ép cùng cấu trúc. - HUD ưu tiên icon: con số = icon + số, nhãn nằm trong tooltip và chữ ẩn cho trình đọc màn hình.
- Tầng nhập liệu: hàm
click,context,drag,canceldùng chung; chuột, cảm ứng (kéo, chụm, nhấn giữ) và tay cầm (Gamepad API) chỉ là lớp chuyển đổi. - Điện thoại là một "vỏ" riêng: thanh dưới, một bảng trượt (sheet) mỗi lúc, nút ≥ 44 px, đặt nhà phải bấm ✓ xác nhận.
Thực hành — mốc 4:
- Thanh trên, menu xây dựng (phím số), bảng công trình hiện lý do ngừng bằng icon.
- Phím tắt: R xoay, Esc huỷ, Delete phá dỡ; hộp thoại chặn phím tắt khi mở.
- Cảm ứng: kéo bản đồ, chụm zoom, chạm chọn, ✓ để đặt.
- Thử trên 3 cỡ màn hình (390×844, 844×390, 1280×760): không chồng, không tràn.
Phần 5 — Nhiều người chơi kiểu lockstep tuần 14–16
Trong lockstep có host, server giữ thứ tự lệnh chứ không tính hộ ai. Mỗi máy tự chạy sim; server cũng chạy một bản để lưu game và làm chuẩn khi so hash.
Vuốt ngang để xem hết sơ đồ →
Mục tiêu: 2–4 người chơi chung một thế giới qua Internet; người vào giữa ván nhận snapshot; mất mạng thì tự nối lại; máy lệch thì tự đồng bộ lại.
Kiến thức:
- Ba mô hình mạng: gửi trạng thái, lockstep, client-server có dự đoán. Game xây dựng hợp lockstep vì thế giới lớn, lệnh ít, trễ 200 ms vẫn chơi được.
- Vòng lặp: client gửi
cmd→ server gom lệnh, mỗi 100 ms chạystep(cmds)→ phátticks {from, n, c}→ mọi client chạy y hệt. - Phát hiện lệch: server gửi hash định kỳ; client khác hash thì xin
resyncvà nạp lại snapshot. - Vào giữa ván:
welcomechứa snapshot và tick hiện tại. - Không tin client: kiểm tra kiểu, khoảng giá trị và quyền của mọi lệnh; giới hạn số lệnh mỗi tick theo loại; token bucket mỗi kết nối; ngắt client để bộ đệm gửi phình to.
- Phiên bản: client gửi dấu vân tay của mã sim; khác server thì tải lại trang lấy bản mới.
- Khởi động lại êm: server nhận SIGTERM thì lưu mọi phòng rồi thoát; client tự nối lại, không bị đá về sảnh.
Thực hành — mốc 5:
- Server
ws: phòng,hello/welcome, hàng đợi lệnh, vòng tick 100 ms. - Client gửi lệnh qua socket thay vì gọi
steptrực tiếp. - Hash mỗi 50 tick; cố ý sửa sim ở một client để gây lệch, xem resync hoạt động.
- Bộ lọc lệnh (sanitizer) và test với dữ liệu rác: số âm,
NaN, chuỗi 1 MB, id không tồn tại. - Mở hai tab, ngắt mạng một tab 30 giây rồi nối lại.
Phần 6 — Lưu game và nâng cấp định dạng save tuần 17
Khi đã có người chơi thật, save của họ quan trọng hơn code của bạn. Mọi thay đổi luật về sau phải đọc được save cũ và biến nó thành thế giới hợp lệ theo luật mới.
Mục tiêu: Bến Nhỏ có SNAPSHOT_VERSION, nâng một save v1 lên v2 có test, và có sao lưu trước khi nâng.
Kiến thức:
- Loader phủ dữ liệu lưu lên giá trị mặc định: thêm field hoặc loại hàng mới không làm hỏng save cũ.
- Bảng
GOODS/BUILDINGSchỉ được thêm vào cuối, vì chỉ số của chúng nằm trong save. - Thay đổi phá vỡ định dạng: tăng version, viết các bước di trú đánh số, idempotent (chạy hai lần vẫn ra cùng kết quả).
- Fixture: sinh save mẫu bằng code cũ trước khi sửa, rồi không bao giờ sinh lại.
- Nén: lưới ô mã hoá RLE thay vì mảng số dài.
- Ghi file an toàn: ghi ra file tạm rồi đổi tên, không ghi đè trực tiếp.
Thực hành — mốc 6:
- Sinh fixture
world.v1.jsontừ code hiện tại. - Đổi luật: kho hàng từ "mỗi người một kho" sang "mỗi đảo một kho". Tăng version lên 2.
- Viết bước di trú v1 → v2 và test: nạp fixture, chạy 100 tick, không lỗi, tổng hàng không mất.
- Server chép
<phòng>.pre-v2-<giờ>.jsontrước khi ghi bản đã nâng; người chơi thấy một dòng chat giải thích thay đổi.
Phần 7 — Người chơi mới: hướng dẫn chơi tuần 18
Game xây dựng mất người chơi ở 10 phút đầu. Hướng dẫn tốt là một kịch bản dữ liệu, được kiểm bằng một "người học giả lập" trên nhiều bản đồ, không phải bằng cảm giác của người làm game.
Mục tiêu: hướng dẫn 6 bước cho Bến Nhỏ (lập kho → đường → nhà → gỗ → ván → 50 dân); bot người học qua hết trên 5 bản đồ, lập kho dưới 3 phút.
Kiến thức:
- Kịch bản thuần: mỗi bước có
done,progress,guidechỉ đọc trạng thái sim, không đụng DOM, nên bot chạy không cần trình duyệt cũng import được. - Chỉ đếm công trình/dân của chính người chơi; bước đã đạt thì tự qua.
- Giao diện mở dần: phần HUD chưa giới thiệu không có trong DOM; mỗi bước mở thêm một phần kèm nhãn "Mới".
- Chỉ chỗ trên bản đồ: khung chỗ đặt, đường nối có điểm đầu/cuối; nhãn đứng cạnh đích, không đè lên đích; bấm vào nhãn là làm luôn.
- Gỡ kẹt: cùng một bước quá 45 giây thì hiện "Làm giúp"; chỉ dẫn tự đổi khi người chơi lạc (hết ván, hết cây).
- Telemetry ẩn danh, chỉ khi người chơi đồng ý: thời gian mỗi bước, chỗ bỏ cuộc.
Thực hành — mốc 7:
- Viết kịch bản 6 bước dạng dữ liệu, chữ qua
t(). - Hàm
planGuidethuần: tìm chỗ đặt hợp lệ gần kho cảng và đường nối ngắn nhất. - Bot người học chỉ làm đúng điều bước đang chỉ, mỗi 5 giây game một thao tác; in thời gian từng bước và chỗ kẹt.
- Nhờ một người chưa chơi bao giờ thử; ghi lại chỗ họ dừng lại quá 10 giây.
Phần 8 — Kiểm thử tuần 19, và suốt khoá
Test là thứ cho phép sửa một game đang có người chơi mà không sợ. Tuần 19 dành để bổ sung tầng còn thiếu, nhưng từ mốc 1 trở đi mỗi tính năng đều phải có test đi kèm.
Mục tiêu: Bến Nhỏ có đủ năm tầng test dưới đây và một lệnh "cổng" phải xanh trước mỗi lần phát hành.
| Tầng | Kiểm gì | Công cụ | Khi nào chạy |
|---|---|---|---|
| Luật chơi | Từng luật, từng lý do từ chối, di trú save | vitest | Mọi commit |
| Lockstep | Game chạy liên tục và game nạp snapshot giữa chừng có cùng hash | vitest, lệnh ngẫu nhiên seed cố định | Mọi commit |
| Cân bằng | Bot đạt cửa sổ mục tiêu trong 60 phút game | vitest, cấu hình riêng (chậm) | Khi đổi defs/ hay luật kinh tế |
| Server | Sao lưu, khôi phục, mật khẩu, giới hạn lạm dụng | node:test | Mọi commit phần server |
| E2E | Người thật bấm chuột, chạm, tay cầm; chụp ảnh | Playwright, Chromium dùng GPU | Trước khi phát hành |
Kiến thức:
- E2E chạy trên bản build tĩnh và một server mới, cổng riêng, thư mục save mới mỗi lần; không bao giờ chạm server thật.
- Hook kiểm thử
window.__gamechỉ có trong bản dev hoặc bản build debug: test hỏi "ô này ở đâu trên màn hình" rồi bấm chuột thật vào đó. - Cảnh dựng sẵn: script tạo save 300 công trình, hoặc thế giới dừng ngay trước một bước hướng dẫn.
- Lỗi người chơi báo → giữ save làm fixture → viết test tái hiện trước khi sửa.
- WebGL headless: có GPU thì nhanh hơn khoảng 30 lần so với SwiftShader; in tên renderer để biết đang dùng gì.
Thực hành — mốc 8:
- Test lockstep với 3 người chơi, người thứ ba vào giữa ván.
- Suite Playwright "play": lập kho, kéo đường, đặt nhà, phá dỡ — chỉ bằng chuột thật.
- Suite "phone" giả lập điện thoại: đặt nhà bằng chạm và ✓, kiểm không nút nào nhỏ hơn 44 px.
- Script
gate:typecheck && test && e2e.
Phần 9 — Vận hành và phát hành cho bạn bè tuần 20
Game chỉ thật sự tồn tại khi có người chơi. Phát hành từng phần nhỏ ngay khi xong, nhưng mỗi lần phải có đường lùi và bản sao lưu.
Mục tiêu: Bến Nhỏ chạy trên một tên miền thật, có server thử nghiệm riêng, sao lưu hằng ngày, nút báo lỗi, và đã diễn tập quay lại bản cũ một lần.
Kiến thức:
- Một cổng duy nhất: server Node phục vụ cả file tĩnh (ETag, nén brotli/gzip, file có hash thì cache vĩnh viễn) lẫn WebSocket.
- Giám sát tiến trình: script tự khởi động lại khi server chết; ghi PID và log ra file.
- Git worktree: nhánh
mainđể làm việc, nhánhreleasechạy production, mỗi bản phát hành một tag. - Server thử nghiệm: cổng khác, thư mục save riêng, không bao giờ trỏ vào save thật.
- Sao lưu: mỗi ngày chép mọi save sang ổ khác, giữ 7 ngày; công cụ khôi phục kiểm save có nạp được không rồi mới đặt vào.
- Báo lỗi trong game: một phím gửi mô tả, ảnh chụp màn hình và trạng thái; có giới hạn dung lượng và số lần mỗi IP.
- Thế giới có mật khẩu: băm bằng scrypt, giới hạn số lần nhập sai.
Thực hành — mốc 9:
- Script
serve.sh: build client, dừng bản cũ bằng SIGTERM, chạy bản mới dưới giám sát. - Viết runbook một trang: triển khai, quay lại tag trước, khôi phục save từ bản sao lưu.
- Diễn tập: triển khai bản có nâng save lên server thử nghiệm (chạy trên bản sao save thật), rồi quay lại theo đúng runbook.
- Mời 3 người bạn chơi một buổi tối; đọc mọi báo lỗi hôm sau.
Phần 10 — Làm việc cùng AI suốt khoá, từ tuần 3
Thương Cảng 1800 được làm chủ yếu bằng cách giao việc cho trợ lý lập trình AI (Claude Code); người làm game thiết kế, giao việc, kiểm tra và chơi thử. AI làm nhanh, nhưng chỉ an toàn khi dự án có tài liệu tốt và cổng test tự động.
Mục tiêu: học viên giao được một tính năng trọn vẹn cho AI và nhận về code mình hiểu, có test, không phá tính năng cũ.
Kiến thức:
CLAUDE.mdở gốc repo: cấu trúc, lệnh, quy ước, bẫy đã gặp. Mỗi lần AI vấp một bẫy mới, ghi thêm một dòng.- Thiết kế trước, code sau: mỗi tính năng lớn có tài liệu thiết kế (mục tiêu, luật, con số, câu hỏi mở), chia thành gói việc nhỏ, mỗi gói có tiêu chí xong.
- Cổng kiểm tra: AI chỉ commit khi
typecheck && testxanh; tính năng giao diện phải có E2E và ảnh chụp để người xem lại. - Dùng AI để hiểu, không chỉ để viết: nhờ giải thích một đoạn code, so sánh hai cách, tìm nguyên nhân lỗi từ save người chơi gửi.
- Đọc lại diff, nhất là trong
sim: một dòng sai ở đó làm lệch mọi máy. - Giới hạn: AI không thay bạn cảm nhận game có vui không, nhịp có đúng không, chữ có dễ hiểu không. Phải tự chơi và nhờ người khác chơi.
Thực hành (áp dụng xuyên các mốc):
- Từ tuần 3, viết
CLAUDE.mdcho Bến Nhỏ; cập nhật mỗi tuần. - Ở Phần 4 hoặc 5, viết một tài liệu thiết kế (ví dụ "Tàu và lập thuộc địa") rồi giao AI làm từng gói.
- So sánh một tính năng tự làm tay với một tính năng giao AI: thời gian, số lỗi, chỗ phải làm lại.
Đồ án cuối khoá và tiêu chí đánh giá
Đồ án: tự thiết kế và thêm một tính năng vào Bến Nhỏ đi qua mọi tầng, rồi tổ chức một buổi chơi thật với ít nhất 3 người trong 45 phút. Gợi ý tính năng: tầng dân thứ hai, tuyến tàu chở hàng giữa hai đảo, hoặc buôn bán giữa hai người chơi.
Nộp: repo, tài liệu thiết kế của tính năng, link chơi được, và báo cáo một trang sau buổi chơi (bao nhiêu người, lỗi gặp, đã sửa gì).
| Tiêu chí | Đạt | Tốt |
|---|---|---|
| Tất định | Test lockstep xanh, có lệnh mới trong bộ sinh lệnh ngẫu nhiên | Không có lần resync nào trong buổi chơi 45 phút (đọc log server) |
| Luật và cân bằng | Có cửa sổ mục tiêu, bot đạt | Hai chiến lược bot; mỗi con số có lý do trong tài liệu thiết kế |
| Save | Save trước tính năng vẫn nạp được | Fixture cũ, test di trú, bản sao trước khi nâng |
| Đồ hoạ | 60 khung/giây với 300 công trình trên máy tầm trung | Đo cả trên điện thoại; số đo được ghi lại |
| Giao diện | Dùng được bằng chuột và phím | Cả cảm ứng; không chồng, không tràn ở 3 cỡ màn hình |
| Người mới | Có bước hướng dẫn cho tính năng mới | Bot người học qua trên 5 bản đồ; một người lạ chơi qua không cần hỏi |
| Kiểm thử | typecheck và unit test xanh | E2E bấm chuột thật cho tính năng mới |
| Vận hành | Chạy trên tên miền thật | Có runbook, đã diễn tập quay lại bản cũ |
Hoàn thành khoá khi mọi tiêu chí ở mức "Đạt" và ít nhất ba tiêu chí ở mức "Tốt".
Tài liệu tham khảo
Đọc theo đúng phần đang học, không cần đọc hết trước. Tài liệu tiếng Anh; phần đánh dấu "bắt buộc" nên đọc kỹ.
| Tài liệu | Phần | Đọc gì |
|---|---|---|
| TypeScript Handbook | 0 | Toàn bộ phần cơ bản |
| pnpm workspaces | 0 | Cách các gói dùng chung mã |
| Game Programming Patterns (Robert Nystrom) | 1, 2 | Bắt buộc: Game Loop, Update Method, Component, Command |
| Fix Your Timestep! (Glenn Fiedler) | 1 | Bắt buộc: tick cố định và nội suy |
| kho | 1, 4 | README: atom, effect, ECS, system, dùng với React |
| Introduction to the A* Algorithm (Red Blob Games) | 2 | Tìm đường cho tàu và xe hàng; cả trang web về lưới ô |
| three.js manual | 3 | Fundamentals, Optimizing Lots of Objects, Picking |
| Discover three.js | 3 | Giáo trình Three.js từ đầu, dễ hơn manual |
| React — Learn | 4 | Component, state, hook |
| Deterministic Lockstep (Glenn Fiedler) | 5 | Bắt buộc |
| 1500 Archers on a 28.8: Network Programming in Age of Empires and Beyond | 5 | Bắt buộc: lockstep trong một game chiến thuật thật, cách họ tìm lỗi lệch |
| Playwright | 8 | Getting started, Mouse, Touchscreen, Screenshots |
| Kenney · Quaternius · game-icons.net | 3, 4 | Model CC0 và icon CC BY 3.0 — nhớ ghi công |
Chơi thêm Anno 1800 vài giờ với câu hỏi "vì sao bước này dễ hiểu?" sẽ giúp Phần 2, 4 và 7 nhiều hơn mọi tài liệu trên.