TL; DR Tôi cần trợ giúp trong việc xác định các kỹ thuật để đơn giản hóa kiểm tra đơn vị tự động khi làm việc trong khuôn khổ trạng thái.
Lý lịch:
Tôi hiện đang viết một trò chơi trong TypeScript và khung Phaser . Phaser mô tả chính nó như một khung trò chơi HTML5 cố gắng ít nhất có thể để hạn chế cấu trúc mã của bạn. Điều này đi kèm với một vài sự đánh đổi, cụ thể là tồn tại Phaser.Game-object cho phép bạn truy cập mọi thứ: bộ nhớ cache, vật lý, trạng thái trò chơi, v.v.
Tính trạng thái này làm cho việc kiểm tra rất nhiều chức năng, chẳng hạn như Tilemap của tôi. Hãy xem một ví dụ:
Ở đây tôi đang kiểm tra xem các lớp gạch của mình có chính xác hay không và tôi có thể xác định các bức tường và sinh vật trong Tilemap của mình:
export class TilemapTest extends tsUnit.TestClass {
constructor() {
super();
this.map = this.mapLoader.load("maze", this.manifest, this.mazeMapDefinition);
this.parameterizeUnitTest(this.isWall,
[
[{ x: 0, y: 0 }, true],
[{ x: 1, y: 1 }, false],
[{ x: 1, y: 0 }, true],
[{ x: 0, y: 1 }, true],
[{ x: 2, y: 0 }, false],
[{ x: 1, y: 3 }, false],
[{ x: 6, y: 3 }, false]
]);
this.parameterizeUnitTest(this.isCreature,
[
[{ x: 0, y: 0 }, false],
[{ x: 2, y: 0 }, false],
[{ x: 1, y: 3 }, true],
[{ x: 4, y: 1 }, false],
[{ x: 8, y: 1 }, true],
[{ x: 11, y: 2 }, false],
[{ x: 6, y: 3 }, false]
]);
Bất kể tôi làm gì, ngay khi tôi cố gắng tạo bản đồ, Phaser sẽ gọi bộ nhớ cache trong bộ nhớ cache, nó chỉ được điền trong thời gian chạy.
Tôi không thể gọi thử nghiệm này mà không tải toàn bộ trò chơi.
Một giải pháp phức tạp có thể là viết Adaptor hoặc Proxy chỉ xây dựng bản đồ khi chúng ta cần hiển thị trên màn hình. Hoặc tôi có thể tự điền vào trò chơi bằng cách chỉ tải thủ công các tài sản tôi cần và sau đó chỉ sử dụng nó cho lớp thử nghiệm hoặc mô-đun cụ thể.
Tôi đã chọn những gì tôi cảm thấy là một giải pháp thực tế hơn, nhưng nước ngoài cho điều này. Giữa việc tải trò chơi của tôi và chơi trò chơi thực tế, tôi đã bắt đầu một cuộc TestState
chạy thử nghiệm với tất cả các tài sản và dữ liệu được lưu trong bộ nhớ cache.
Điều này thật tuyệt, bởi vì tôi có thể kiểm tra tất cả các chức năng mà tôi muốn, nhưng cũng không phải vì nó là một bài kiểm tra tích hợp và người ta tự hỏi liệu tôi không thể chỉ nhìn vào màn hình và xem liệu kẻ thù có được hiển thị hay không. Trên thực tế, không, chúng có thể đã được xác định nhầm là Vật phẩm (đã xảy ra một lần rồi) hoặc - sau đó trong các thử nghiệm - chúng có thể không được đưa ra các sự kiện gắn liền với cái chết của chúng.
Câu hỏi của tôi - Là mờ trong trạng thái thử nghiệm như thế này phổ biến? Có cách tiếp cận nào tốt hơn, đặc biệt là trong môi trường JavaScript mà tôi không biết?
Một vi dụ khac:
Được rồi, đây là một ví dụ cụ thể hơn để giúp giải thích những gì đang xảy ra:
export class Tilemap extends Phaser.Tilemap {
// layers is already defined in Phaser.Tilemap, so we use tilemapLayers instead.
private tilemapLayers: TilemapLayers = {};
// A TileMap can have any number of layers, but
// we're only concerned about the existence of two.
// The collidables layer has the information about where
// a Player or Enemy can move to, and where he cannot.
private CollidablesLayer = "Collidables";
// Triggers are map events, anything from loading
// an item, enemy, or object, to triggers that are activated
// when the player moves toward it.
private TriggersLayer = "Triggers";
private items: Array<Phaser.Sprite> = [];
private creatures: Array<Phaser.Sprite> = [];
private interactables: Array<ActivatableObject> = [];
private triggers: Array<Trigger> = [];
constructor(json: TilemapData) {
// First
super(json.game, json.key);
// Second
json.tilesets.forEach((tileset) => this.addTilesetImage(tileset.name, tileset.key), this);
json.tileLayers.forEach((layer) => {
this.tilemapLayers[layer.name] = this.createLayer(layer.name);
}, this);
// Third
this.identifyTriggers();
this.tilemapLayers[this.CollidablesLayer].resizeWorld();
this.setCollisionBetween(1, 2, true, this.CollidablesLayer);
}
Tôi xây dựng Tilemap của mình từ ba phần:
- Bản đồ
key
- Bản đồ
manifest
chi tiết tất cả các tài sản (gạch lát và spritesheets) theo yêu cầu của bản đồ - Một
mapDefinition
mô tả cấu trúc và các lớp của tilemap.
Đầu tiên, tôi phải gọi siêu để xây dựng Tilemap trong Phaser. Đây là phần gọi tất cả các lệnh gọi tới bộ đệm khi nó cố gắng tra cứu các tài sản thực tế và không chỉ các khóa được xác định trong manifest
.
Thứ hai, tôi liên kết các ô xếp và các lớp gạch với Tilemap. Bây giờ nó có thể hiển thị bản đồ.
Thứ ba, tôi lặp qua lớp của tôi và tìm thấy bất kỳ đối tượng đặc biệt mà tôi muốn extrude từ bản đồ: Creatures
, Items
, Interactables
và vân vân. Tôi tạo và lưu trữ các đối tượng này để sử dụng sau.
Hiện tại tôi vẫn có một API tương đối đơn giản cho phép tôi tìm, xóa, cập nhật các thực thể này:
wallAt(at: TileCoordinates) {
var tile = this.getTile(at.x, at.y, this.CollidablesLayer);
return tile && tile.index != 0;
}
itemAt(at: TileCoordinates) {
return _.find(this.items, (item: Phaser.Sprite) => _.isEqual(this.toTileCoordinates(item), at));
}
interactableAt(at: TileCoordinates) {
return _.find(this.interactables, (object: ActivatableObject) => _.isEqual(this.toTileCoordinates(object), at));
}
creatureAt(at: TileCoordinates) {
return _.find(this.creatures, (creature: Phaser.Sprite) => _.isEqual(this.toTileCoordinates(creature), at));
}
triggerAt(at: TileCoordinates) {
return _.find(this.triggers, (trigger: Trigger) => _.isEqual(this.toTileCoordinates(trigger), at));
}
getTrigger(name: string) {
return _.find(this.triggers, { name: name });
}
Đây là chức năng tôi muốn kiểm tra. Nếu tôi không thêm Lớp Ngói hoặc Ngói, bản đồ sẽ không hiển thị, nhưng tôi có thể kiểm tra nó. Tuy nhiên, ngay cả việc gọi siêu (...) cũng gọi logic cụ thể theo ngữ cảnh hoặc trạng thái mà tôi không thể tách rời trong các thử nghiệm của mình.
new Tilemap(...)
Phaser bắt đầu đào sâu vào bộ đệm của nó. Tôi phải trì hoãn điều đó, nhưng điều đó có nghĩa là Tilemap của tôi ở hai trạng thái, một trạng thái không thể hiển thị chính xác và trạng thái được xây dựng đầy đủ.