You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Web-Dev-For-Beginners/translations/vi/6-space-game/2-drawing-to-canvas/README.md

230 lines
9.7 KiB

<!--
CO_OP_TRANSLATOR_METADATA:
{
"original_hash": "41be8d35e7f30aa9dad10773c35e89c4",
"translation_date": "2025-08-27T22:39:25+00:00",
"source_file": "6-space-game/2-drawing-to-canvas/README.md",
"language_code": "vi"
}
-->
# Xây dựng trò chơi không gian Phần 2: Vẽ nhân vật chính và quái vật lên Canvas
## Câu hỏi trước bài giảng
[Câu hỏi trước bài giảng](https://ff-quizzes.netlify.app/web/quiz/31)
## Canvas
Canvas là một phần tử HTML mặc định không có nội dung; nó giống như một tấm bảng trắng. Bạn cần thêm nội dung bằng cách vẽ lên nó.
✅ Đọc [thêm về Canvas API](https://developer.mozilla.org/docs/Web/API/Canvas_API) trên MDN.
Dưới đây là cách nó thường được khai báo, như một phần của phần thân trang:
```html
<canvas id="myCanvas" width="200" height="100"></canvas>
```
Ở trên, chúng ta đang thiết lập `id`, `width``height`.
- `id`: thiết lập để bạn có thể lấy tham chiếu khi cần tương tác với nó.
- `width`: đây là chiều rộng của phần tử.
- `height`: đây là chiều cao của phần tử.
## Vẽ hình học đơn giản
Canvas sử dụng hệ tọa độ Cartesian để vẽ các đối tượng. Do đó, nó sử dụng trục x và trục y để biểu thị vị trí của một đối tượng. Vị trí `0,0` là góc trên bên trái và góc dưới bên phải là giá trị WIDTH và HEIGHT mà bạn đã thiết lập cho canvas.
![lưới của canvas](../../../../translated_images/canvas_grid.5f209da785ded492a01ece440e3032afe51efa500cc2308e5ea4252487ceaf0b.vi.png)
> Hình ảnh từ [MDN](https://developer.mozilla.org/docs/Web/API/Canvas_API/Tutorial/Drawing_shapes)
Để vẽ lên phần tử canvas, bạn cần thực hiện các bước sau:
1. **Lấy tham chiếu** đến phần tử Canvas.
2. **Lấy tham chiếu** đến phần tử Context nằm trên phần tử Canvas.
3. **Thực hiện thao tác vẽ** bằng cách sử dụng phần tử Context.
Mã cho các bước trên thường trông như sau:
```javascript
// draws a red rectangle
//1. get the canvas reference
canvas = document.getElementById("myCanvas");
//2. set the context to 2D to draw basic shapes
ctx = canvas.getContext("2d");
//3. fill it with the color red
ctx.fillStyle = 'red';
//4. and draw a rectangle with these parameters, setting location and size
ctx.fillRect(0,0, 200, 200) // x,y,width, height
```
✅ Canvas API chủ yếu tập trung vào các hình dạng 2D, nhưng bạn cũng có thể vẽ các đối tượng 3D lên trang web; để làm điều này, bạn có thể sử dụng [WebGL API](https://developer.mozilla.org/docs/Web/API/WebGL_API).
Bạn có thể vẽ nhiều thứ với Canvas API như:
- **Hình dạng hình học**, chúng ta đã chỉ cách vẽ một hình chữ nhật, nhưng còn nhiều thứ khác bạn có thể vẽ.
- **Văn bản**, bạn có thể vẽ văn bản với bất kỳ phông chữ và màu sắc nào bạn muốn.
- **Hình ảnh**, bạn có thể vẽ hình ảnh từ một tài sản hình ảnh như .jpg hoặc .png chẳng hạn.
✅ Thử ngay! Bạn đã biết cách vẽ một hình chữ nhật, liệu bạn có thể vẽ một hình tròn lên trang không? Hãy xem một số bản vẽ Canvas thú vị trên CodePen. Đây là một [ví dụ đặc biệt ấn tượng](https://codepen.io/dissimulate/pen/KrAwx).
## Tải và vẽ tài sản hình ảnh
Bạn tải một tài sản hình ảnh bằng cách tạo một đối tượng `Image` và thiết lập thuộc tính `src` của nó. Sau đó, bạn lắng nghe sự kiện `load` để biết khi nào nó sẵn sàng được sử dụng. Mã trông như sau:
### Tải tài sản
```javascript
const img = new Image();
img.src = 'path/to/my/image.png';
img.onload = () => {
// image loaded and ready to be used
}
```
### Mẫu tải tài sản
Nên gói gọn đoạn mã trên trong một cấu trúc như sau để dễ sử dụng và chỉ cố gắng thao tác khi nó đã được tải đầy đủ:
```javascript
function loadAsset(path) {
return new Promise((resolve) => {
const img = new Image();
img.src = path;
img.onload = () => {
// image loaded and ready to be used
resolve(img);
}
})
}
// use like so
async function run() {
const heroImg = await loadAsset('hero.png')
const monsterImg = await loadAsset('monster.png')
}
```
Để vẽ các tài sản trò chơi lên màn hình, mã của bạn sẽ trông như sau:
```javascript
async function run() {
const heroImg = await loadAsset('hero.png')
const monsterImg = await loadAsset('monster.png')
canvas = document.getElementById("myCanvas");
ctx = canvas.getContext("2d");
ctx.drawImage(heroImg, canvas.width/2,canvas.height/2);
ctx.drawImage(monsterImg, 0,0);
}
```
## Bây giờ là lúc bắt đầu xây dựng trò chơi của bạn
### Những gì cần xây dựng
Bạn sẽ xây dựng một trang web với một phần tử Canvas. Nó sẽ hiển thị một màn hình đen `1024*768`. Chúng tôi đã cung cấp cho bạn hai hình ảnh:
- Tàu của nhân vật chính
![Tàu của nhân vật chính](../../../../translated_images/player.dd24c1afa8c71e9b82b2958946d4bad13308681392d4b5ddcc61a0e818ef8088.vi.png)
- Tàu quái vật 5*5
![Tàu quái vật](../../../../translated_images/enemyShip.5df2a822c16650c2fb3c06652e8ec8120cdb9122a6de46b9a1a56d54db22657f.vi.png)
### Các bước khuyến nghị để bắt đầu phát triển
Tìm các tệp đã được tạo cho bạn trong thư mục con `your-work`. Nó sẽ chứa các tệp sau:
```bash
-| assets
-| enemyShip.png
-| player.png
-| index.html
-| app.js
-| package.json
```
Mở bản sao của thư mục này trong Visual Studio Code. Bạn cần thiết lập môi trường phát triển cục bộ, tốt nhất là với Visual Studio Code cùng NPM và Node đã được cài đặt. Nếu bạn chưa thiết lập `npm` trên máy tính của mình, [đây là cách thực hiện](https://www.npmjs.com/get-npm).
Bắt đầu dự án của bạn bằng cách điều hướng đến thư mục `your_work`:
```bash
cd your-work
npm start
```
Lệnh trên sẽ khởi động một HTTP Server tại địa chỉ `http://localhost:5000`. Mở trình duyệt và nhập địa chỉ đó. Hiện tại trang vẫn trống, nhưng điều đó sẽ thay đổi.
> Lưu ý: để xem các thay đổi trên màn hình, hãy làm mới trình duyệt của bạn.
### Thêm mã
Thêm mã cần thiết vào `your-work/app.js` để giải quyết các yêu cầu dưới đây:
1. **Vẽ** một canvas với nền đen
> gợi ý: thêm hai dòng dưới TODO thích hợp trong `/app.js`, thiết lập phần tử `ctx` có màu đen và tọa độ trên/trái ở 0,0, chiều cao và chiều rộng bằng với canvas.
2. **Tải** các texture
> gợi ý: thêm hình ảnh nhân vật chính và quái vật bằng cách sử dụng `await loadTexture` và truyền vào đường dẫn hình ảnh. Bạn sẽ chưa thấy chúng trên màn hình!
3. **Vẽ** nhân vật chính ở giữa màn hình trong nửa dưới
> gợi ý: sử dụng API `drawImage` để vẽ heroImg lên màn hình, thiết lập `canvas.width / 2 - 45` và `canvas.height - canvas.height / 4)`.
4. **Vẽ** 5*5 quái vật
> gợi ý: Bây giờ bạn có thể bỏ chú thích mã để vẽ quái vật lên màn hình. Tiếp theo, đi đến hàm `createEnemies` và xây dựng nó.
Đầu tiên, thiết lập một số hằng số:
```javascript
const MONSTER_TOTAL = 5;
const MONSTER_WIDTH = MONSTER_TOTAL * 98;
const START_X = (canvas.width - MONSTER_WIDTH) / 2;
const STOP_X = START_X + MONSTER_WIDTH;
```
sau đó, tạo một vòng lặp để vẽ mảng quái vật lên màn hình:
```javascript
for (let x = START_X; x < STOP_X; x += 98) {
for (let y = 0; y < 50 * 5; y += 50) {
ctx.drawImage(enemyImg, x, y);
}
}
```
## Kết quả
Kết qu hoàn chnh s trông như sau:
![Màn hình đen với nhân vật chính và 5*5 quái vật](../../../../translated_images/partI-solution.36c53b48c9ffae2a5e15496b23b604ba5393433e4bf91608a7a0a020eb7a2691.vi.png)
## Giải pháp
Hãy th t gii quyết trước, nhưng nếu bn gp khó khăn, hãy xem [giải pháp](../../../../6-space-game/2-drawing-to-canvas/solution/app.js).
---
## 🚀 Thử thách
Bn đã hc v v vi Canvas API tp trung vào 2D; hãy xem [WebGL API](https://developer.mozilla.org/docs/Web/API/WebGL_API) và th v mt đối tượng 3D.
## Câu hỏi sau bài giảng
[Câu hỏi sau bài giảng](https://ff-quizzes.netlify.app/web/quiz/32)
## Ôn tập & Tự học
Tìm hiu thêm v Canvas API bng cách [đọc về nó](https://developer.mozilla.org/docs/Web/API/Canvas_API).
## Bài tập
[Thử nghiệm với Canvas API](assignment.md)
---
**Tuyên bố miễn trừ trách nhiệm**:
Tài liu này đã được dch bng dch v dch thut AI [Co-op Translator](https://github.com/Azure/co-op-translator). Mc dù chúng tôi c gng đảm bo độ chính xác, xin lưu ý rng các bn dch t động có th cha li hoc không chính xác. Tài liu gc bng ngôn ng bn địa nên được coi là ngun thông tin chính thc. Đối vi các thông tin quan trng, khuyến ngh s dng dch v dch thut chuyên nghip bi con người. Chúng tôi không chu trách nhim cho bt k s hiu lm hoc din gii sai nào phát sinh t vic s dng bn dch này.