Hướng dẫn dùng p-play JavaScript

Trong bài viết trước, chúng ta đã tìm hiểu về việc cấu hình môi trường cho dự án làm game đơn giản bằng Javascript.

Hôm nay, chúng ta cùng nhau cài đặt P5js vào trong dự án game Plinko bằng javascript này nhé.

Các bạn có thể kết hợp bài viết với xem nội dung sau

  • 1. Khởi tạo P5js
  • 2. Cấu trúc thư mục dự án làm game bằng javascript
  • 3. Khởi tạo P5Wrapper.ts – class đại diện cho khởi tạo P5
  • 4. File cấu hình game App.ts
  • 5. Class Loader – thực thi việc tải tài nguyên hình ảnh cho game plinko
  • File index.ts của game plinko javascript
  • Chạy thử game demo

1. Khởi tạo P5js

Thư viện P5js đã được cài đặc thông qua lệnh npm, do vậy chúng ta có thể dễ dàng sử dụng trong dự án. Khi làm việc với P5js các bạn cần lưu ý các hàm đặc biệt như sau:

  • Hàm preload: hàm này được khởi tạo đầu tiên, thông thường được sử dụng cho mục đích load các tài nguyên của ứng dụng như là ảnh, âm thanh, font chữ…
  • Hàm setup: Hàm preload sau khi chạy xong sẽ gọi đến hàm setup. Hàm setup với múc đích để cài đặt các thông số ban đầu cho p5js ví dụ như là khởi tạo canvas…
  • Hàm draw: là hàm vẽ (render) nội dung cho canvas. Chú ý rằng tùy thuộc vào thông số máy tính bạn sử dụng mà sẽ có Frame Per Rate là bao nhiêu? Ví dụ với máy tính mình đang sử dụng FPS tối đa là 60. Các bạn chú ý tới con số này để tối ưu code và tạo trải nghiệm tốt nhất cho người dùng.
    Hàm draw còn được hiểu là vòng lặp chính của game. Trước đây các dự án Game có thể sử dụng Setinterval để liên tục làm mới hình ảnh game. Tuy nhiên sau này cơ chế chạy đó được thay đổi bằng requestAnimationFrame(). Các bạn có thể tìm hiểu thêm điều này trên google. Về cơ bản, đây là cơ chế được khuyến nghị hạn chế tiêu tốn tài nguyên của máy tính trong trường hợp tab trình duyệt inactive.Một ghi chú nhỏ các bạn rằng, chính cơ chế này của trình duyệt mà hàm setInterval sẽ chạy không chính xác nếu như tab trình duyệt của bạn ở chế độ inactive. Phần này Code Tu Tam sẽ trình bày trong một bài viết khác.

Mặc định P5js có hai phương thức chạy:

  • Phương thức 1 là chạy mặc định với các hàm bên trên sẽ là hàm dạng global của window.
  • Phương thức thứ 2 là chạy dưới dạng đối tượng

Trong seri hướng dẫn này để thuận tiện cho quản lý và mở rộng dự án, chúng ta sẽ quản lý dưới dạng đối tượng.

Chú ý rằng thông thường các ví dụ trên trang p5js.org thường thực thi theo phương thức 1.

2. Cấu trúc thư mục dự án làm game bằng javascript

Hướng dẫn dùng p-play JavaScript
Cấu trúc thư mục game Plinko Javascript

Sơ lược về thông tin cấu trúc thư mục như sau. Tất cả các mã nguồn game javascript sẽ được đặt trong thư mục src.

Các file thông tin cấu hình như package.json, webpack.config.js, tsconfig.json hay file index.html thì như đã trình bày ở bài trước

Trong bài viết này, chúng ta cùng nhau tìm hiểu thêm các file: config/app.ts, Loader.ts, P5Wrapper.ts

Trong đó, file app.ts chứa thông tin cấu hình của game Plinko js này. File Loader thực hiện nhiệm vụ tải các tài nguyên (cụ thể là hình ảnh) trong dự án. File P5Wrapper.ts chính là file thực hiện wrapper lại P5. Đây cũng chính là vòng lặp chính của game.

3. Khởi tạo P5Wrapper.ts – class đại diện cho khởi tạo P5

Nội dung file P5Wrapper.js có nội dung như sau:

import AppConfig from "./configs/app";
import Loader from "./Loader";

export default class P5Wrapper {
    private options: any = {
        parent: "game",
    };
    private P5: any;
    private mCanvas: any;
    private loader: Loader;
    constructor(P5: any, options: any = {}) {
        this.P5 = P5;
        this.options = { ...this.options, ...options };
        this.loader = new Loader(P5);
    }
    preload() {
        this.loader.loadImages();
    }
    setup() {
        this.mCanvas = this.P5.createCanvas(
            AppConfig.APP.WIDTH,
            AppConfig.APP.HEIGHT
        );
        this.mCanvas.parent(this.options.parent);
    }
    draw() {
        let background = Loader.getImage("bg");
        if (background) this.P5.background(background);
    }
}

Trong file này các bạn sẽ cần chú ý tới:

Export default class P5Wrapper, với lệnh này chúng ta export P5Wrapper để các file khác có thể dễ dàng import và sử dụng

Với class này chúng ta sẽ có 1 số thuộc tính

  • Options: chứa cấu hình cho p5js, như trong hình chỉ có 1 config là parent với giá trị là game. Đây chính là config chỉ div chứa canvas mà p5js tạo ra
  • Tham số P5, chính là biến P5 được truyền vào phục vụ các hoạt động của dự án

Trong hàm khởi tạo, chúng ta merge config truyền vào và config mặc định.

Trong hàm setup, chúng ta khởi tạo 1 canvas mới với độ rộng và cao được cấu hình trong hệ thống

Trong hàm draw, chúng ta sẽ lấy hình nền và vẽ hình nền này.

Trong hàm preload, chúng ta thực hiện việc tải toàn bộ hình ảnh của game. Các hình ảnh này sẽ được render trong hàm draw của game Plinko.

4. File cấu hình game App.ts

Như các bạn nói bên trên, file app.ts sẽ chứa toàn bộ cấu hình của Game Plinko js này.

export default class AppConfig {
    public static APP: any = {
        WIDTH: 550,
        HEIGHT: 580,
        TOPBUFFER: 50,
    };
}

Trong file này, Code Tu Tam định nghĩa 1 đối tượng APP với các thuộc tính:

WIDTH: độ rộng của canvas game

HEIGHT: chiều cao của canvas game

TOPBUFFER: Khoảng cách từ mép trên cảu canvas tới điểm thả bóng. Nói cách khác đây là tọa độ theo chiều y của nơi sẽ thả quả bóng.

5. Class Loader – thực thi việc tải tài nguyên hình ảnh cho game plinko

Như đã thấy trong P5Wrapper, chúng ta có sử dụng file Loader để thực hiện tải các nội dung ảnh.

Nội dung của file như sau:

export default class Loader {
    export default class Loader {
    private _images: any = {
        ball_black: "assets/images/ball_black.png",
        ball_green: "assets/images/ball_xanh.png",
        ball: "assets/images/ball1.png",
        light: "assets/images/light.png",
        bg: "assets/images/bg.jpg",
        hole: "assets/images/hole.png",
        panel: "assets/images/panel.png",
    };

    private static images: any = {};

    private P5: any;
    constructor(P5: any) {
        this.P5 = P5;
    }

    public loadImages() {
                       for (const [key, value] of Object.entries(this._images)) {
            let tmp = this.P5.loadImage(value);
            Loader.images[key] = tmp;
        }
    }

    public static getImage(key: any) {
        return Loader.images[key];
    }
}

Như các bạn đã thấy trong file này.

Chúng ta có 1 đối tượng định nghĩa danh sách các hình ảnh cần sử dụng. Loader có hàm tĩnh getImage để lấy image đã load ra.

Tất cả hình ảnh đã tải chúng ta sẽ lưu vào 1 biến tĩnh image, việc nảy giúp việc truy vấn vào các hình ảnh đã tải 1 cách nhanh chóng hơn.

Với dự án game này, số lượng tài nguyên không lớn nên được để trực tiếp trong code. Còn trên thực tế chúng ta có thể dụng các file config được gửi từ server để chuẩn bị dữ iệu trước khi khởi tạo game.

File index.ts của game plinko javascript

Tiếp đến chúng ta sẽ cập nhật code cho file index.ts của game plinko. Đây là file main của dự án chúng ta đang thực hiện.

import * as p5 from "p5";
import P5Wrapper from "./P5Wrapper";

function makeGame() {
    const tmp = function (p: any) {
        let p5w = new P5Wrapper(p);
        p.preload = function () {
            p5w.preload();
        };
        p.setup = function () {
            p5w.setup();
        };
        p.draw = function () {
            p5w.draw();
        };
    };
    return new p5(tmp);
}
makeGame();

Trong này chúng ta thực hiện 1 hàm makeGame, trong đó đã wrapper lại các hàm ban đầu của P5.

Và cuối cùng là gọi game makeGame, để đảm bảo chương trình chạy ngay khi trang web được tải trang.

Chạy thử game demo

Nếu bạn đang sử visual studio code giống như Code Tu Tam, bạn có thể nhanh chóng mở termial bằng phím tắt ctrl + shift+ `

Sau khi terminal mở lên, bạn gõ lệnh sau: npm run wpw

Lệnh này như đã trình bày trong bài trước, là lệnh chạy webpack giúp build ra file js cuối cùng

Tiếp đến chúng ta sẽ sử dụng Live Server để xem thành quả của game Plinko javascript chúng ta đang làm nhé.

Hướng dẫn dùng p-play JavaScript
Hình ảnh demo game Plinko

Như hình ảnh demo, chúng ta đã thực hiện load được ảnh nền của game. Các bạn thấy thế nào? Thực quá đơn giản phải không?

Bài tiếp theo chúng ta sẽ hiển thị 1 số thông tin debug của game, kèm theo đó là khởi tạo các đối tượng trong game plinko.

Nếu có bất kì thắc mắc và cần trợ giúp hãy để lại comment để Code Tu Tam hỗ trợ bạn nhé!