Tích hợp bản đồ Tiled với Phaser 3: Hướng dẫn thực hành từ cơ bản đến nâng cao

Tiled và Phaser 3 là hai công cụ phổ biến trong phát triển trò chơi 2D dựa trên web. Việc kết nối chúng một cách hiệu quả giúp xây dựng bản đồ động, hỗ trợ va chạm, tương tác đối tượng và mở rộng quy mô game mà không cần viết lại logic render.

Khởi tạo bản đồ trong Tiled

Để bắt đầu, tạo một bản đồ mới với cấu hình phù hợp cho môi trường Phaser:

  • Chọn kiểu Orthogonal (không dùng Isometric trừ khi có xử lý đặc biệt)
  • Đặt kích thước ô (tile size) là 32x32 hoặc 64x64, đảm bảo khớp với kích thước ảnh tileset
  • Đặt chiều rộng/cao theo đơn vị ô — ví dụ: 50x30 cho bản đồ vừa phải

Nhập và cấu hình tileset

Sau khi tạo bản đồ, thêm tileset qua menu Map → New Tileset:

  • Chọn file ảnh chứa các ô (PNG, WebP), đảm bảo không bị nén mất cạnh
  • Thiết lập Margin = 0, Spacing = 0 để tránh khe hở khi render
  • Gán thuộc tính tùy chỉnh như collides: true, type: "lava", hoặc script: "teleport_to_cave" vào từng ô trong tab Tile Properties

Xuất bản đồ sang định dạng JSON tương thích với Phaser

Trong Tiled, chọn File → Export As… rồi lưu dưới dạng .json. Để tối ưu:

  • Với dự án nhỏ: tích chọn Embed tilesets để gộp dữ liệu vào một file duy nhất
  • Với dự án lớn: giữ tileset ở dạng tệp riêng (desert.png) và chỉ lưu đường dẫn trong JSON

Tải và render bản đồ trong Phaser 3

Dưới đây là đoạn mã khởi tạo bản đồ đầy đủ, bao gồm xử lý va chạm và phân lớp:

function preload() {
  this.load.tilemapTiledJSON('levelOne', 'maps/forest-level.json');
  this.load.image('forestTiles', 'assets/tiles/forest-pack.png');
}

function create() {
  // Tạo tilemap từ JSON
  const worldMap = this.make.tilemap({ key: 'levelOne' });
  
  // Liên kết tileset với map
  const tilesetRef = worldMap.addTilesetImage('forest-tiles', 'forestTiles');

  // Tạo từng lớp theo tên trong Tiled
  const bgLayer = worldMap.createLayer('Background', tilesetRef, 0, 0);
  const terrainLayer = worldMap.createLayer('Terrain', tilesetRef, 0, 0);
  const obstacleLayer = worldMap.createLayer('Walls', tilesetRef, 0, 0);

  // Kích hoạt va chạm cho các ô có thuộc tính 'collides'
  obstacleLayer.setCollisionByProperty({ collides: true });

  // Gắn hệ thống va chạm với arcade physics
  this.physics.world.enable(obstacleLayer);
}

Sử dụng Object Layer để quản lý tương tác

Các lớp đối tượng (Object Layer) trong Tiled được chuyển thành Phaser.GameObjects.Image hoặc Phaser.GameObjects.Sprite trong Phaser:

// Lấy tất cả object từ lớp 'Entities'
const entityObjects = worldMap.objects.Entities || [];

entityObjects.forEach(obj => {
  if (obj.type === 'player_spawn') {
    this.player = this.physics.add.sprite(obj.x, obj.y, 'hero');
  } else if (obj.type === 'chest') {
    const chest = this.physics.add.sprite(obj.x, obj.y, 'chest-closed');
    chest.setData('id', obj.id);
    chest.setData('reward', obj.properties.reward || 'gold_50');
  }
});

Tối ưu hóa bằng kỹ thuật chia bản đồ (chunking)

Với bản đồ lớn, nên chia thành các khối (chunks) và tải động theo vùng nhìn:

  • Tạo nhiều bản đồ con trong Tiled, mỗi bản đồ đại diện một chunk
  • Trong Phaser, sử dụng this.cameras.main.scrollX/Y để xác định chunk nào cần hiển thị
  • Load/unload layer động bằng layer.setVisible()layer.setActive()

Tài nguyên tham khảo

Thẻ: tiled phaser3 game-development 2d-game html5-game

Đăng vào ngày 25 tháng 6 lúc 11:34